server/http/middleware/cors.ts
Rama main · réplica de lectura del repositorio original.
import { forbidden } from '@server/domain/errors'
import type { Context, MiddlewareHandler } from 'hono'
const corsMethods = 'GET,POST,PUT,PATCH,DELETE,OPTIONS'
const corsHeaders = 'authorization,content-type'
interface TrustedOriginCorsOptions {
isOriginExemptPath?: (path: string) => boolean
isPublicPath?: (path: string) => boolean
resolveAllowedOrigins?: (context: { path: string; context: Context }) => Promise<string[]>
}
export function trustedOriginCors(trustedOrigins: string[], options: TrustedOriginCorsOptions = {}): MiddlewareHandler {
const allowedOrigins = new Set(trustedOrigins)
return async (c, next) => {
const origin = c.req.header('origin')
if (!origin || options.isOriginExemptPath?.(c.req.path)) {
await next()
return
}
if (options.isPublicPath?.(c.req.path)) {
const setPublicCorsHeaders = () => {
c.header('Access-Control-Allow-Origin', origin)
c.header('Vary', 'Origin')
}
setPublicCorsHeaders()
if (c.req.method === 'OPTIONS') {
c.header('Access-Control-Allow-Methods', 'GET,OPTIONS')
c.header('Access-Control-Allow-Headers', c.req.header('access-control-request-headers') || corsHeaders)
return c.body(null, 204)
}
await next()
setPublicCorsHeaders()
return
}
const dynamicOrigins = allowedOrigins.has(origin)
? []
: await (options.resolveAllowedOrigins?.({ path: c.req.path, context: c }) ?? [])
if (!allowedOrigins.has(origin) && !dynamicOrigins.includes(origin)) {
throw forbidden('Origin is not trusted for this issuer.')
}
const setCorsHeaders = () => {
c.header('Access-Control-Allow-Origin', origin)
c.header('Access-Control-Allow-Credentials', 'true')
c.header('Vary', 'Origin')
}
setCorsHeaders()
if (c.req.method === 'OPTIONS') {
c.header('Access-Control-Allow-Methods', corsMethods)
c.header('Access-Control-Allow-Headers', c.req.header('access-control-request-headers') || corsHeaders)
return c.body(null, 204)
}
await next()
setCorsHeaders()
}
}