|
@@ -21,7 +21,12 @@ async function fixture() {
|
|
|
},
|
|
},
|
|
|
};
|
|
};
|
|
|
const config = {
|
|
const config = {
|
|
|
- corsAllowedOrigins: ['http://localhost:4200'],
|
|
|
|
|
|
|
+ corsAllowedOrigins: [
|
|
|
|
|
+ 'https://www.yuban.co',
|
|
|
|
|
+ 'https://yuban.co',
|
|
|
|
|
+ 'http://localhost:4200',
|
|
|
|
|
+ 'http://127.0.0.1:4200',
|
|
|
|
|
+ ],
|
|
|
allowedAudioHosts: ['file.yuban.co'],
|
|
allowedAudioHosts: ['file.yuban.co'],
|
|
|
jobRetentionMs: 86_400_000,
|
|
jobRetentionMs: 86_400_000,
|
|
|
maxActiveJobsPerUser: 2,
|
|
maxActiveJobsPerUser: 2,
|
|
@@ -63,6 +68,43 @@ test('健康检查不要求认证', async t => {
|
|
|
assert.equal(body.service, 'yuban-server');
|
|
assert.equal(body.service, 'yuban-server');
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
+test('仅允许配置的网页来源通过 CORS 预检', async t => {
|
|
|
|
|
+ const app = await fixture();
|
|
|
|
|
+ t.after(() => app.close());
|
|
|
|
|
+
|
|
|
|
|
+ for (const origin of [
|
|
|
|
|
+ 'https://www.yuban.co',
|
|
|
|
|
+ 'https://yuban.co',
|
|
|
|
|
+ 'http://localhost:4200',
|
|
|
|
|
+ 'http://127.0.0.1:4200',
|
|
|
|
|
+ ]) {
|
|
|
|
|
+ const response = await fetch(`${app.baseUrl}/recording-transcription/jobs`, {
|
|
|
|
|
+ method: 'OPTIONS',
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ Origin: origin,
|
|
|
|
|
+ 'Access-Control-Request-Method': 'POST',
|
|
|
|
|
+ 'Access-Control-Request-Headers': 'Authorization, Content-Type, Idempotency-Key',
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ assert.equal(response.status, 204, origin);
|
|
|
|
|
+ assert.equal(response.headers.get('access-control-allow-origin'), origin);
|
|
|
|
|
+ assert.match(response.headers.get('vary') || '', /Origin/i);
|
|
|
|
|
+ assert.match(response.headers.get('access-control-allow-methods') || '', /POST/);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const rejected = await fetch(`${app.baseUrl}/recording-transcription/jobs`, {
|
|
|
|
|
+ method: 'OPTIONS',
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ Origin: 'https://untrusted.example.com',
|
|
|
|
|
+ 'Access-Control-Request-Method': 'POST',
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ assert.equal(rejected.status, 403);
|
|
|
|
|
+ const body = await rejected.json();
|
|
|
|
|
+ assert.equal(body.error.code, 'ORIGIN_NOT_ALLOWED');
|
|
|
|
|
+ assert.equal(rejected.headers.has('access-control-allow-origin'), false);
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
test('创建任务立即返回 202,查询不会暴露音频地址或所有者', async t => {
|
|
test('创建任务立即返回 202,查询不会暴露音频地址或所有者', async t => {
|
|
|
const app = await fixture();
|
|
const app = await fixture();
|
|
|
t.after(() => app.close());
|
|
t.after(() => app.close());
|