0
0
mirror of https://github.com/honojs/hono.git synced 2024-11-29 17:46:30 +01:00
hono/deno_dist/middleware/csrf/index.ts
Taku Amano b143c4ed8b
feat(middleware/csrf): Introduce CSRF middleware (#1823)
* feat(middleware/csrf): Introduce CSRF middleware

* test(middleware/csrf): Add tests for CSRF middleware

* chore: denoify

* fix(middleware/csrf): fix typo.
2023-12-27 06:58:20 +09:00

49 lines
1.5 KiB
TypeScript

import type { Context } from '../../context.ts'
import { HTTPException } from '../../http-exception.ts'
import type { MiddlewareHandler } from '../../types.ts'
type IsAllowedOriginHandler = (origin: string, context: Context) => boolean
interface CSRFOptions {
origin?: string | string[] | IsAllowedOriginHandler
}
const isSafeMethodRe = /^(GET|HEAD)$/
const isRequestedByFormElementRe =
/^\b(application\/x-www-form-urlencoded|multipart\/form-data|text\/plain)\b/
export const csrf = (options?: CSRFOptions): MiddlewareHandler => {
const handler: IsAllowedOriginHandler = ((optsOrigin) => {
if (!optsOrigin) {
return (origin, c) => origin === new URL(c.req.url).origin
} else if (typeof optsOrigin === 'string') {
return (origin) => origin === optsOrigin
} else if (typeof optsOrigin === 'function') {
return optsOrigin
} else {
return (origin) => optsOrigin.includes(origin)
}
})(options?.origin)
const isAllowedOrigin = (origin: string | undefined, c: Context) => {
if (origin === undefined) {
// denied always when origin header is not present
return false
}
return handler(origin, c)
}
return async function cors(c, next) {
if (
!isSafeMethodRe.test(c.req.method) &&
isRequestedByFormElementRe.test(c.req.header('content-type') || '') &&
!isAllowedOrigin(c.req.header('origin'), c)
) {
const res = new Response('Forbidden', {
status: 403,
})
throw new HTTPException(403, { res })
}
await next()
}
}