Repository: honojs/hono
File: src/middleware/csrf/index.ts (TypeScript)

Code before:
 * }))
 *
 * // Dynamic origin validation
 * app.use('*', csrf({
 *   origin: (origin, c) => {
 *     // Allow same origin
 *     if (origin === new URL(c.req.url).origin) return true
 *     // Allow specific trusted domains
 *     return ['https://app.example.com', 'https://admin.example.com'].includes(origin)
 *   }
 * }))
 * ```
 */
export const csrf = (options?: CSRFOptions): MiddlewareHandler => {
  const originHandler: 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 = async (origin: string | undefined, c: Context): Promise<boolean> => {
    if (origin === undefined) {
      // denied always when origin header is not present
      return false
    }
    return await originHandler(origin, c)
  }

  const secFetchSiteHandler: IsAllowedSecFetchSiteHandler = ((optsSecFetchSite) => {
    if (!optsSecFetchSite) {
      // Default: only allow same-origin
      return (secFetchSite) => secFetchSite === 'same-origin'
    } else if (typeof optsSecFetchSite === 'string') {
      return (secFetchSite) => secFetchSite === optsSecFetchSite
    } else if (typeof optsSecFetchSite === 'function') {
      return optsSecFetchSite
    } else {
      return (secFetchSite) => optsSecFetchSite.includes(secFetchSite)
    }
  })(options?.secFetchSite)
  const isAllowedSecFetchSite = (secFetchSite: string | undefined, c: Context) => {
    if (secFetchSite === undefined) {
      // denied always when sec-fetch-site header is not present
      return false
    }
    // type guard to check if the value is a valid SecFetchSite

Review comment (security):
To make a short code, you can remove the return value annotation and the `await`. Do you think of it?

```diff
diff --git a/src/middleware/csrf/index.ts b/src/middleware/csrf/index.ts
index f57b99e4..24164919 100644
--- a/src/middleware/csrf/index.ts
+++ b/src/middleware/csrf/index.ts
@@ -100,12 +100,12 @@ export const csrf = (options?: CSRFOptions): MiddlewareHandler => {
       return (origin) => optsOrigin.includes(origin)
     }
   })(options?.origin)
-  const isAllowedOrigin = async (origin: string | undefined, c: Context): Promise<boolean> => {
+  const isAllowedOrigin = async (origin: string | undefined, c: Context) => {
     if (origin === undefined) {
       // denied always when origin header is not present
       return false
     }
-    return await originHandler(origin, c)
+    return originHandler(origin, c)
   }

   const secFetchSiteHandler: IsAllowedSecFetchSiteHandler = ((optsSecFetchSite) => {
```

Code after:
 * }))
 *
 * // Dynamic origin validation
 * app.use('*', csrf({
 *   origin: (origin, c) => {
 *     // Allow same origin
 *     if (origin === new URL(c.req.url).origin) return true
 *     // Allow specific trusted domains
 *     return ['https://app.example.com', 'https://admin.example.com'].includes(origin)
 *   }
 * }))
 * ```
 */
export const csrf = (options?: CSRFOptions): MiddlewareHandler => {
  const originHandler: 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 = async (origin: string | undefined, c: Context) => {
    if (origin === undefined) {
      // denied always when origin header is not present
      return false
    }
    return await originHandler(origin, c)
  }

  const secFetchSiteHandler: IsAllowedSecFetchSiteHandler = ((optsSecFetchSite) => {
    if (!optsSecFetchSite) {
      // Default: only allow same-origin
      return (secFetchSite) => secFetchSite === 'same-origin'
    } else if (typeof optsSecFetchSite === 'string') {
      return (secFetchSite) => secFetchSite === optsSecFetchSite
    } else if (typeof optsSecFetchSite === 'function') {
      return optsSecFetchSite
    } else {
      return (secFetchSite) => optsSecFetchSite.includes(secFetchSite)
    }
  })(options?.secFetchSite)
  const isAllowedSecFetchSite = (secFetchSite: string | undefined, c: Context) => {
    if (secFetchSite === undefined) {
      // denied always when sec-fetch-site header is not present
      return false
    }
    // type guard to check if the value is a valid SecFetchSite