Skip to content

Commit 669a16e

Browse files
committed
feat: enhance CORS middleware to improve origin matching and logging
1 parent dd99242 commit 669a16e

1 file changed

Lines changed: 39 additions & 7 deletions

File tree

apps/api/src/middleware/cors.ts

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,51 @@
11
import { Context } from 'hono';
22
import { Env } from '../utils';
33

4+
function matchOrigin(origin: string, allowed: string[]): boolean {
5+
for (const rule of allowed) {
6+
if (rule === '*') return true;
7+
if (rule.includes('*')) {
8+
const pattern = '^' + rule
9+
.replace(/[.+?^${}()|[\]\\]/g, '\\$&')
10+
.replace(/\\\*/g, '.*') + '$';
11+
const re = new RegExp(pattern);
12+
if (re.test(origin)) return true;
13+
} else if (rule === origin) {
14+
return true;
15+
}
16+
}
17+
return false;
18+
}
19+
420
export async function corsMiddleware(c: Context<{ Bindings: Env }>, next: () => Promise<void>) {
5-
const origin = c.req.header('Origin');
21+
const origin = c.req.header('Origin') || '';
622
const allowedOriginsEnv = c.env.ALLOWED_ORIGINS || '*';
723

8-
// 許可されたオリジンのリストを取得
924
const allowedOrigins = allowedOriginsEnv === '*'
1025
? ['*']
11-
: allowedOriginsEnv.split(',').map((o: string) => o.trim());
26+
: allowedOriginsEnv.split(',').map((o: string) => o.trim()).filter(Boolean);
1227

13-
// オリジンが許可されているかチェック
1428
let allowedOrigin = '*';
1529
if (origin && allowedOrigins[0] !== '*') {
16-
if (allowedOrigins.includes(origin)) {
30+
if (matchOrigin(origin, allowedOrigins)) {
1731
allowedOrigin = origin;
1832
} else {
19-
// オリジンが許可されていない場合はCORSヘッダーを返さない
33+
// Not allowed origin: log details for troubleshooting
34+
try {
35+
const url = new URL(c.req.url);
36+
console.warn('[CORS] Blocked request', {
37+
method: c.req.method,
38+
path: url.pathname,
39+
origin,
40+
allowedOrigins,
41+
});
42+
} catch (_) {
43+
console.warn('[CORS] Blocked request', {
44+
method: c.req.method,
45+
origin,
46+
allowedOrigins,
47+
});
48+
}
2049
if (c.req.method === 'OPTIONS') {
2150
return c.text('Forbidden', 403);
2251
}
@@ -25,9 +54,12 @@ export async function corsMiddleware(c: Context<{ Bindings: Env }>, next: () =>
2554
}
2655
}
2756

57+
const reqAllowedHeaders = c.req.header('Access-Control-Request-Headers');
58+
2859
c.header('Access-Control-Allow-Origin', allowedOrigin);
60+
c.header('Vary', 'Origin, Access-Control-Request-Headers');
2961
c.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
30-
c.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
62+
c.header('Access-Control-Allow-Headers', reqAllowedHeaders || 'Content-Type, Authorization');
3163
c.header('Access-Control-Max-Age', '86400');
3264

3365
if (c.req.method === 'OPTIONS') {

0 commit comments

Comments
 (0)