@shware/http 2.11.3 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.cjs +13 -0
- package/dist/_virtual/_rolldown/runtime.mjs +13 -0
- package/dist/cache/index.cjs +5 -30
- package/dist/cache/index.cjs.map +1 -1
- package/dist/cache/index.d.cts +7 -5
- package/dist/cache/index.d.cts.map +1 -0
- package/dist/cache/index.d.mts +11 -0
- package/dist/cache/index.d.mts.map +1 -0
- package/dist/cache/index.mjs +5 -6
- package/dist/cache/index.mjs.map +1 -1
- package/dist/error/detail.cjs +100 -90
- package/dist/error/detail.cjs.map +1 -1
- package/dist/error/detail.d.cts +77 -78
- package/dist/error/detail.d.cts.map +1 -0
- package/dist/error/detail.d.mts +108 -0
- package/dist/error/detail.d.mts.map +1 -0
- package/dist/error/detail.mjs +99 -65
- package/dist/error/detail.mjs.map +1 -1
- package/dist/error/i18n/en-us.cjs +5 -29
- package/dist/error/i18n/en-us.cjs.map +1 -1
- package/dist/error/i18n/en-us.d.cts +3 -1
- package/dist/error/i18n/en-us.d.cts.map +1 -0
- package/dist/error/i18n/en-us.d.mts +5 -0
- package/dist/error/i18n/en-us.d.mts.map +1 -0
- package/dist/error/i18n/en-us.mjs +5 -5
- package/dist/error/i18n/en-us.mjs.map +1 -1
- package/dist/error/index.cjs +29 -56
- package/dist/error/index.cjs.map +1 -1
- package/dist/error/index.d.cts +12 -10
- package/dist/error/index.d.cts.map +1 -0
- package/dist/error/index.d.mts +21 -0
- package/dist/error/index.d.mts.map +1 -0
- package/dist/error/index.mjs +25 -28
- package/dist/error/index.mjs.map +1 -1
- package/dist/error/parse.cjs +63 -61
- package/dist/error/parse.cjs.map +1 -1
- package/dist/error/parse.d.cts +8 -7
- package/dist/error/parse.d.cts.map +1 -0
- package/dist/error/{parse.d.ts → parse.d.mts} +8 -7
- package/dist/error/parse.d.mts.map +1 -0
- package/dist/error/parse.mjs +59 -33
- package/dist/error/parse.mjs.map +1 -1
- package/dist/error/reason.cjs +0 -19
- package/dist/error/reason.d.cts +5 -4
- package/dist/error/reason.d.cts.map +1 -0
- package/dist/error/reason.d.mts +6 -0
- package/dist/error/reason.d.mts.map +1 -0
- package/dist/error/reason.mjs +1 -1
- package/dist/error/status.cjs +103 -256
- package/dist/error/status.cjs.map +1 -1
- package/dist/error/status.d.cts +58 -58
- package/dist/error/status.d.cts.map +1 -0
- package/dist/error/status.d.mts +69 -0
- package/dist/error/status.d.mts.map +1 -0
- package/dist/error/status.mjs +98 -227
- package/dist/error/status.mjs.map +1 -1
- package/dist/google-one-tap/index.cjs +135 -138
- package/dist/google-one-tap/index.cjs.map +1 -1
- package/dist/google-one-tap/index.d.cts +49 -48
- package/dist/google-one-tap/index.d.cts.map +1 -0
- package/dist/google-one-tap/index.d.mts +82 -0
- package/dist/google-one-tap/index.d.mts.map +1 -0
- package/dist/google-one-tap/index.mjs +133 -112
- package/dist/google-one-tap/index.mjs.map +1 -1
- package/dist/google-one-tap/types.cjs +0 -19
- package/dist/google-one-tap/types.d.cts +124 -122
- package/dist/google-one-tap/types.d.cts.map +1 -0
- package/dist/google-one-tap/types.d.mts +157 -0
- package/dist/google-one-tap/types.d.mts.map +1 -0
- package/dist/google-one-tap/types.mjs +1 -1
- package/dist/hono/authorizer.cjs +28 -65
- package/dist/hono/authorizer.cjs.map +1 -1
- package/dist/hono/authorizer.d.cts +12 -11
- package/dist/hono/authorizer.d.cts.map +1 -0
- package/dist/hono/authorizer.d.mts +19 -0
- package/dist/hono/authorizer.d.mts.map +1 -0
- package/dist/hono/authorizer.mjs +23 -36
- package/dist/hono/authorizer.mjs.map +1 -1
- package/dist/hono/csrf.cjs +81 -92
- package/dist/hono/csrf.cjs.map +1 -1
- package/dist/hono/csrf.d.cts +46 -45
- package/dist/hono/csrf.d.cts.map +1 -0
- package/dist/hono/csrf.d.mts +76 -0
- package/dist/hono/csrf.d.mts.map +1 -0
- package/dist/hono/csrf.mjs +76 -63
- package/dist/hono/csrf.mjs.map +1 -1
- package/dist/hono/geolocation.cjs +10 -34
- package/dist/hono/geolocation.cjs.map +1 -1
- package/dist/hono/geolocation.d.cts +5 -4
- package/dist/hono/geolocation.d.cts.map +1 -0
- package/dist/hono/geolocation.d.mts +7 -0
- package/dist/hono/geolocation.d.mts.map +1 -0
- package/dist/hono/geolocation.mjs +8 -12
- package/dist/hono/geolocation.mjs.map +1 -1
- package/dist/hono/handler.cjs +37 -61
- package/dist/hono/handler.cjs.map +1 -1
- package/dist/hono/handler.d.cts +26 -25
- package/dist/hono/handler.d.cts.map +1 -0
- package/dist/hono/handler.d.mts +32 -0
- package/dist/hono/handler.d.mts.map +1 -0
- package/dist/hono/handler.mjs +34 -34
- package/dist/hono/handler.mjs.map +1 -1
- package/dist/hono/index.cjs +14 -48
- package/dist/hono/index.d.cts +7 -15
- package/dist/hono/index.d.mts +7 -0
- package/dist/hono/index.mjs +4 -14
- package/dist/hono/rate-limit.cjs +65 -110
- package/dist/hono/rate-limit.cjs.map +1 -1
- package/dist/hono/rate-limit.d.cts +27 -26
- package/dist/hono/rate-limit.d.cts.map +1 -0
- package/dist/hono/rate-limit.d.mts +36 -0
- package/dist/hono/rate-limit.d.mts.map +1 -0
- package/dist/hono/rate-limit.mjs +60 -81
- package/dist/hono/rate-limit.mjs.map +1 -1
- package/dist/hono/validator.cjs +47 -66
- package/dist/hono/validator.cjs.map +1 -1
- package/dist/hono/validator.d.cts +25 -30
- package/dist/hono/validator.d.cts.map +1 -0
- package/dist/hono/validator.d.mts +26 -0
- package/dist/hono/validator.d.mts.map +1 -0
- package/dist/hono/validator.mjs +43 -43
- package/dist/hono/validator.mjs.map +1 -1
- package/dist/index.cjs +39 -95
- package/dist/index.d.cts +12 -14
- package/dist/index.d.mts +12 -0
- package/dist/index.mjs +5 -48
- package/dist/iso/iso_3601_1.cjs +1512 -290
- package/dist/iso/iso_3601_1.cjs.map +1 -1
- package/dist/iso/iso_3601_1.d.cts +8 -6
- package/dist/iso/iso_3601_1.d.cts.map +1 -0
- package/dist/iso/iso_3601_1.d.mts +11 -0
- package/dist/iso/iso_3601_1.d.mts.map +1 -0
- package/dist/iso/iso_3601_1.mjs +1511 -265
- package/dist/iso/iso_3601_1.mjs.map +1 -1
- package/dist/max-length/index.cjs +158 -91
- package/dist/max-length/index.cjs.map +1 -1
- package/dist/max-length/index.d.cts +110 -1
- package/dist/max-length/index.d.cts.map +1 -0
- package/dist/{index-BhgdyigB.d.ts → max-length/index.d.mts} +9 -28
- package/dist/max-length/index.d.mts.map +1 -0
- package/dist/max-length/index.mjs +133 -47
- package/dist/max-length/index.mjs.map +1 -1
- package/dist/message.cjs +5 -30
- package/dist/message.cjs.map +1 -1
- package/dist/message.d.cts +3 -1
- package/dist/message.d.cts.map +1 -0
- package/dist/{message.d.ts → message.d.mts} +3 -1
- package/dist/message.d.mts.map +1 -0
- package/dist/message.mjs +5 -6
- package/dist/message.mjs.map +1 -1
- package/dist/polyfills/index.cjs +4 -4
- package/dist/polyfills/index.cjs.map +1 -1
- package/dist/polyfills/index.d.cts +1 -2
- package/dist/polyfills/index.d.mts +1 -0
- package/dist/polyfills/index.mjs +5 -2
- package/dist/polyfills/index.mjs.map +1 -1
- package/dist/response.cjs +191 -208
- package/dist/response.cjs.map +1 -1
- package/dist/response.d.cts +53 -54
- package/dist/response.d.cts.map +1 -0
- package/dist/response.d.mts +82 -0
- package/dist/response.d.mts.map +1 -0
- package/dist/response.mjs +182 -175
- package/dist/response.mjs.map +1 -1
- package/dist/snowflake.cjs +48 -70
- package/dist/snowflake.cjs.map +1 -1
- package/dist/snowflake.d.cts +16 -14
- package/dist/snowflake.d.cts.map +1 -0
- package/dist/snowflake.d.mts +31 -0
- package/dist/snowflake.d.mts.map +1 -0
- package/dist/snowflake.mjs +46 -44
- package/dist/snowflake.mjs.map +1 -1
- package/dist/utils/geolocation.cjs +51 -75
- package/dist/utils/geolocation.cjs.map +1 -1
- package/dist/utils/geolocation.d.cts +14 -12
- package/dist/utils/geolocation.d.cts.map +1 -0
- package/dist/utils/{geolocation.d.ts → geolocation.d.mts} +14 -12
- package/dist/utils/geolocation.d.mts.map +1 -0
- package/dist/utils/geolocation.mjs +47 -47
- package/dist/utils/geolocation.mjs.map +1 -1
- package/dist/utils/google-tag-gateway.cjs +35 -56
- package/dist/utils/google-tag-gateway.cjs.map +1 -1
- package/dist/utils/google-tag-gateway.d.cts +3 -1
- package/dist/utils/google-tag-gateway.d.cts.map +1 -0
- package/dist/utils/{google-tag-gateway.d.ts → google-tag-gateway.d.mts} +3 -1
- package/dist/utils/google-tag-gateway.d.mts.map +1 -0
- package/dist/utils/google-tag-gateway.mjs +33 -30
- package/dist/utils/google-tag-gateway.mjs.map +1 -1
- package/dist/utils/timing.cjs +50 -71
- package/dist/utils/timing.cjs.map +1 -1
- package/dist/utils/timing.d.cts +11 -9
- package/dist/utils/timing.d.cts.map +1 -0
- package/dist/utils/timing.d.mts +15 -0
- package/dist/utils/timing.d.mts.map +1 -0
- package/dist/utils/timing.mjs +49 -46
- package/dist/utils/timing.mjs.map +1 -1
- package/dist/webhook/index.cjs +43 -72
- package/dist/webhook/index.cjs.map +1 -1
- package/dist/webhook/index.d.cts +3 -1
- package/dist/webhook/index.d.cts.map +1 -0
- package/dist/webhook/{index.d.ts → index.d.mts} +3 -1
- package/dist/webhook/index.d.mts.map +1 -0
- package/dist/webhook/index.mjs +41 -46
- package/dist/webhook/index.mjs.map +1 -1
- package/package.json +50 -25
- package/dist/cache/index.d.ts +0 -9
- package/dist/error/detail.d.ts +0 -109
- package/dist/error/i18n/en-us.d.ts +0 -3
- package/dist/error/index.d.ts +0 -19
- package/dist/error/reason.cjs.map +0 -1
- package/dist/error/reason.d.ts +0 -5
- package/dist/error/reason.mjs.map +0 -1
- package/dist/error/status.d.ts +0 -69
- package/dist/google-one-tap/index.d.ts +0 -81
- package/dist/google-one-tap/types.cjs.map +0 -1
- package/dist/google-one-tap/types.d.ts +0 -155
- package/dist/google-one-tap/types.mjs.map +0 -1
- package/dist/hono/authorizer.d.ts +0 -18
- package/dist/hono/csrf.d.ts +0 -75
- package/dist/hono/geolocation.d.ts +0 -6
- package/dist/hono/handler.d.ts +0 -31
- package/dist/hono/index.cjs.map +0 -1
- package/dist/hono/index.d.ts +0 -15
- package/dist/hono/index.mjs.map +0 -1
- package/dist/hono/rate-limit.d.ts +0 -35
- package/dist/hono/validator.d.ts +0 -31
- package/dist/index-BhgdyigB.d.cts +0 -129
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.ts +0 -14
- package/dist/index.mjs.map +0 -1
- package/dist/iso/iso_3601_1.d.ts +0 -9
- package/dist/max-length/index.d.ts +0 -1
- package/dist/polyfills/index.d.ts +0 -2
- package/dist/response.d.ts +0 -83
- package/dist/snowflake.d.ts +0 -29
- package/dist/utils/timing.d.ts +0 -13
package/dist/hono/csrf.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hono/csrf.ts"],"sourcesContent":["import { timingSafeEqual } from 'crypto';\nimport type { MiddlewareHandler } from 'hono';\nimport { getCookie } from 'hono/cookie';\nimport { METHOD_NAME_ALL } from 'hono/router';\nimport { RegExpRouter } from 'hono/router/reg-exp-router';\nimport { SmartRouter } from 'hono/router/smart-router';\nimport { TrieRouter } from 'hono/router/trie-router';\nimport { Status } from '../error/status';\n\ntype HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';\n\nexport type CSRFIgnoreRule = string | { path: string; methods?: [HTTPMethod, ...HTTPMethod[]] };\n\nexport interface CSRFConfig {\n /**\n * Cookie name for CSRF token\n * @default 'XSRF-TOKEN'\n */\n cookieName?: string;\n\n /**\n * Header name for CSRF token\n * @default 'X-XSRF-TOKEN'\n */\n headerName?: string;\n\n /**\n * Ignore rules for specific paths and methods\n * @example\n * [\n * { path: '/api/webhook/*', methods: ['POST'] },\n * { path: '/auth/apple/callback' }, // ignores all methods\n * ]\n */\n ignores?: CSRFIgnoreRule[];\n\n /**\n * Skip CSRF check for these methods\n * @default ['GET', 'HEAD', 'OPTIONS']\n */\n safeMethods?: HTTPMethod[];\n\n /**\n * Origin allowed to bypass CSRF check\n * @default undefined\n */\n origin?: string[];\n\n /**\n * Sec-Fetch-Site allowed to bypass CSRF check\n * @default undefined\n */\n secFetchSite?: Array<'same-origin' | 'same-site' | 'none' | 'cross-origin'>;\n\n /**\n * Custom error message\n * @default 'CSRF token validation failed'\n */\n errorMessage?: string;\n}\n\n/** use timing safe compare to prevent timing attack */\nfunction safeCompare(a: string, b: string): boolean {\n if (typeof a !== 'string' || typeof b !== 'string') return false;\n if (a.length === 0 || b.length === 0) return false;\n\n const bufferA = Buffer.from(a, 'utf-8');\n const bufferB = Buffer.from(b, 'utf-8');\n if (bufferA.length !== bufferB.length) return false;\n return timingSafeEqual(bufferA, bufferB);\n}\n\n/**\n * Create CSRF protection middleware\n *\n * @example\n * ```ts\n * import { Hono } from 'hono';\n * import { csrf } from '@shware/http/hono';\n *\n * const app = new Hono();\n *\n * // basic usage\n * app.use(csrf());\n *\n * // with configuration\n * app.use(csrf({\n * cookieName: 'csrf-token',\n * headerName: 'X-CSRF-Token',\n * ignores: [\n * { path: '/api/webhook/*', methods: ['POST'] },\n * { path: '/auth/apple/callback' },\n * ]\n * }));\n * ```\n */\nexport function csrf(config: CSRFConfig = {}): MiddlewareHandler {\n const cookieName = config.cookieName ?? 'XSRF-TOKEN';\n const headerName = config.headerName ?? 'X-XSRF-TOKEN';\n const safeMethods = new Set(config.safeMethods ?? ['GET', 'HEAD', 'OPTIONS']);\n const errorMessage = config.errorMessage ?? 'CSRF token validation failed';\n\n // initialize router for matching ignore rules\n const router = new SmartRouter<boolean>({\n routers: [new RegExpRouter(), new TrieRouter()],\n });\n\n // register ignore rules\n if (config.ignores) {\n for (const rule of config.ignores) {\n if (typeof rule === 'string') {\n router.add(METHOD_NAME_ALL, rule, true);\n } else if (rule.methods && rule.methods.length > 0) {\n for (const method of rule.methods) {\n router.add(method, rule.path, true);\n }\n } else {\n // if no methods are specified, ignore all methods\n router.add(METHOD_NAME_ALL, rule.path, true);\n }\n }\n }\n\n // return middleware\n return async (c, next) => {\n const method = c.req.method;\n const path = c.req.path;\n\n // check if the request should be ignored\n // 1. ignore safe methods\n if (safeMethods.has(method)) {\n await next();\n return;\n }\n\n // 2. ignore configured origin\n if (config.origin && config.origin.includes(c.req.header('origin') ?? '')) {\n await next();\n return;\n }\n\n // 3. ignore configured secFetchSite\n if (\n config.secFetchSite &&\n config.secFetchSite.includes((c.req.header('sec-fetch-site') ?? '') as never)\n ) {\n await next();\n return;\n }\n\n // 4. ignore configured ignore rules\n const [matched] = router.match(method, path);\n if (matched.length > 0) {\n await next();\n return;\n }\n\n const cookieToken = getCookie(c, cookieName);\n const headerToken = c.req.header(headerName);\n\n if (!cookieToken || !headerToken) {\n throw Status.permissionDenied(errorMessage).error();\n }\n\n if (!safeCompare(cookieToken, headerToken)) {\n throw Status.permissionDenied(errorMessage).error();\n }\n\n await next();\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"csrf.cjs","names":["SmartRouter","RegExpRouter","TrieRouter","METHOD_NAME_ALL","Status"],"sources":["../../src/hono/csrf.ts"],"sourcesContent":["import { timingSafeEqual } from 'node:crypto';\nimport type { MiddlewareHandler } from 'hono';\nimport { getCookie } from 'hono/cookie';\nimport { METHOD_NAME_ALL } from 'hono/router';\nimport { RegExpRouter } from 'hono/router/reg-exp-router';\nimport { SmartRouter } from 'hono/router/smart-router';\nimport { TrieRouter } from 'hono/router/trie-router';\nimport { Status } from '../error/status';\n\ntype HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';\n\nexport type CSRFIgnoreRule = string | { path: string; methods?: [HTTPMethod, ...HTTPMethod[]] };\n\nexport interface CSRFConfig {\n /**\n * Cookie name for CSRF token\n * @default 'XSRF-TOKEN'\n */\n cookieName?: string;\n\n /**\n * Header name for CSRF token\n * @default 'X-XSRF-TOKEN'\n */\n headerName?: string;\n\n /**\n * Ignore rules for specific paths and methods\n * @example\n * [\n * { path: '/api/webhook/*', methods: ['POST'] },\n * { path: '/auth/apple/callback' }, // ignores all methods\n * ]\n */\n ignores?: CSRFIgnoreRule[];\n\n /**\n * Skip CSRF check for these methods\n * @default ['GET', 'HEAD', 'OPTIONS']\n */\n safeMethods?: HTTPMethod[];\n\n /**\n * Origin allowed to bypass CSRF check\n * @default undefined\n */\n origin?: string[];\n\n /**\n * Sec-Fetch-Site allowed to bypass CSRF check\n * @default undefined\n */\n secFetchSite?: Array<'same-origin' | 'same-site' | 'none' | 'cross-origin'>;\n\n /**\n * Custom error message\n * @default 'CSRF token validation failed'\n */\n errorMessage?: string;\n}\n\n/** use timing safe compare to prevent timing attack */\nfunction safeCompare(a: string, b: string): boolean {\n if (typeof a !== 'string' || typeof b !== 'string') return false;\n if (a.length === 0 || b.length === 0) return false;\n\n const bufferA = Buffer.from(a, 'utf-8');\n const bufferB = Buffer.from(b, 'utf-8');\n if (bufferA.length !== bufferB.length) return false;\n return timingSafeEqual(bufferA, bufferB);\n}\n\n/**\n * Create CSRF protection middleware\n *\n * @example\n * ```ts\n * import { Hono } from 'hono';\n * import { csrf } from '@shware/http/hono';\n *\n * const app = new Hono();\n *\n * // basic usage\n * app.use(csrf());\n *\n * // with configuration\n * app.use(csrf({\n * cookieName: 'csrf-token',\n * headerName: 'X-CSRF-Token',\n * ignores: [\n * { path: '/api/webhook/*', methods: ['POST'] },\n * { path: '/auth/apple/callback' },\n * ]\n * }));\n * ```\n */\nexport function csrf(config: CSRFConfig = {}): MiddlewareHandler {\n const cookieName = config.cookieName ?? 'XSRF-TOKEN';\n const headerName = config.headerName ?? 'X-XSRF-TOKEN';\n const safeMethods = new Set(config.safeMethods ?? ['GET', 'HEAD', 'OPTIONS']);\n const errorMessage = config.errorMessage ?? 'CSRF token validation failed';\n\n // initialize router for matching ignore rules\n const router = new SmartRouter<boolean>({\n routers: [new RegExpRouter(), new TrieRouter()],\n });\n\n // register ignore rules\n if (config.ignores) {\n for (const rule of config.ignores) {\n if (typeof rule === 'string') {\n router.add(METHOD_NAME_ALL, rule, true);\n } else if (rule.methods && rule.methods.length > 0) {\n for (const method of rule.methods) {\n router.add(method, rule.path, true);\n }\n } else {\n // if no methods are specified, ignore all methods\n router.add(METHOD_NAME_ALL, rule.path, true);\n }\n }\n }\n\n // return middleware\n return async (c, next) => {\n const method = c.req.method;\n const path = c.req.path;\n\n // check if the request should be ignored\n // 1. ignore safe methods\n if (safeMethods.has(method)) {\n await next();\n return;\n }\n\n // 2. ignore configured origin\n if (config.origin && config.origin.includes(c.req.header('origin') ?? '')) {\n await next();\n return;\n }\n\n // 3. ignore configured secFetchSite\n if (\n config.secFetchSite &&\n config.secFetchSite.includes((c.req.header('sec-fetch-site') ?? '') as never)\n ) {\n await next();\n return;\n }\n\n // 4. ignore configured ignore rules\n const [matched] = router.match(method, path);\n if (matched.length > 0) {\n await next();\n return;\n }\n\n const cookieToken = getCookie(c, cookieName);\n const headerToken = c.req.header(headerName);\n\n if (!cookieToken || !headerToken) {\n throw Status.permissionDenied(errorMessage).error();\n }\n\n if (!safeCompare(cookieToken, headerToken)) {\n throw Status.permissionDenied(errorMessage).error();\n }\n\n await next();\n };\n}\n"],"mappings":";;;;;;;;;;AA8DA,SAAS,YAAY,GAAW,GAAoB;CAClD,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU,OAAO;CAC3D,IAAI,EAAE,WAAW,KAAK,EAAE,WAAW,GAAG,OAAO;CAE7C,MAAM,UAAU,OAAO,KAAK,GAAG,OAAO;CACtC,MAAM,UAAU,OAAO,KAAK,GAAG,OAAO;CACtC,IAAI,QAAQ,WAAW,QAAQ,QAAQ,OAAO;CAC9C,QAAA,GAAA,YAAA,gBAAA,CAAuB,SAAS,OAAO;AACzC;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,KAAK,SAAqB,CAAC,GAAsB;CAC/D,MAAM,aAAa,OAAO,cAAc;CACxC,MAAM,aAAa,OAAO,cAAc;CACxC,MAAM,cAAc,IAAI,IAAI,OAAO,eAAe;EAAC;EAAO;EAAQ;CAAS,CAAC;CAC5E,MAAM,eAAe,OAAO,gBAAgB;CAG5C,MAAM,SAAS,IAAIA,yBAAAA,YAAqB,EACtC,SAAS,CAAC,IAAIC,2BAAAA,aAAa,GAAG,IAAIC,wBAAAA,WAAW,CAAC,EAChD,CAAC;CAGD,IAAI,OAAO,SACT,KAAK,MAAM,QAAQ,OAAO,SACxB,IAAI,OAAO,SAAS,UAClB,OAAO,IAAIC,YAAAA,iBAAiB,MAAM,IAAI;MACjC,IAAI,KAAK,WAAW,KAAK,QAAQ,SAAS,GAC/C,KAAK,MAAM,UAAU,KAAK,SACxB,OAAO,IAAI,QAAQ,KAAK,MAAM,IAAI;MAIpC,OAAO,IAAIA,YAAAA,iBAAiB,KAAK,MAAM,IAAI;CAMjD,OAAO,OAAO,GAAG,SAAS;EACxB,MAAM,SAAS,EAAE,IAAI;EACrB,MAAM,OAAO,EAAE,IAAI;EAInB,IAAI,YAAY,IAAI,MAAM,GAAG;GAC3B,MAAM,KAAK;GACX;EACF;EAGA,IAAI,OAAO,UAAU,OAAO,OAAO,SAAS,EAAE,IAAI,OAAO,QAAQ,KAAK,EAAE,GAAG;GACzE,MAAM,KAAK;GACX;EACF;EAGA,IACE,OAAO,gBACP,OAAO,aAAa,SAAU,EAAE,IAAI,OAAO,gBAAgB,KAAK,EAAY,GAC5E;GACA,MAAM,KAAK;GACX;EACF;EAGA,MAAM,CAAC,WAAW,OAAO,MAAM,QAAQ,IAAI;EAC3C,IAAI,QAAQ,SAAS,GAAG;GACtB,MAAM,KAAK;GACX;EACF;EAEA,MAAM,eAAA,GAAA,YAAA,UAAA,CAAwB,GAAG,UAAU;EAC3C,MAAM,cAAc,EAAE,IAAI,OAAO,UAAU;EAE3C,IAAI,CAAC,eAAe,CAAC,aACnB,MAAMC,qBAAAA,OAAO,iBAAiB,YAAY,CAAC,CAAC,MAAM;EAGpD,IAAI,CAAC,YAAY,aAAa,WAAW,GACvC,MAAMA,qBAAAA,OAAO,iBAAiB,YAAY,CAAC,CAAC,MAAM;EAGpD,MAAM,KAAK;CACb;AACF"}
|
package/dist/hono/csrf.d.cts
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import { MiddlewareHandler } from
|
|
2
|
-
|
|
1
|
+
import { MiddlewareHandler } from "hono";
|
|
2
|
+
//#region src/hono/csrf.d.ts
|
|
3
3
|
type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
|
|
4
4
|
type CSRFIgnoreRule = string | {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
path: string;
|
|
6
|
+
methods?: [HTTPMethod, ...HTTPMethod[]];
|
|
7
7
|
};
|
|
8
8
|
interface CSRFConfig {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Cookie name for CSRF token
|
|
11
|
+
* @default 'XSRF-TOKEN'
|
|
12
|
+
*/
|
|
13
|
+
cookieName?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Header name for CSRF token
|
|
16
|
+
* @default 'X-XSRF-TOKEN'
|
|
17
|
+
*/
|
|
18
|
+
headerName?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Ignore rules for specific paths and methods
|
|
21
|
+
* @example
|
|
22
|
+
* [
|
|
23
|
+
* { path: '/api/webhook/*', methods: ['POST'] },
|
|
24
|
+
* { path: '/auth/apple/callback' }, // ignores all methods
|
|
25
|
+
* ]
|
|
26
|
+
*/
|
|
27
|
+
ignores?: CSRFIgnoreRule[];
|
|
28
|
+
/**
|
|
29
|
+
* Skip CSRF check for these methods
|
|
30
|
+
* @default ['GET', 'HEAD', 'OPTIONS']
|
|
31
|
+
*/
|
|
32
|
+
safeMethods?: HTTPMethod[];
|
|
33
|
+
/**
|
|
34
|
+
* Origin allowed to bypass CSRF check
|
|
35
|
+
* @default undefined
|
|
36
|
+
*/
|
|
37
|
+
origin?: string[];
|
|
38
|
+
/**
|
|
39
|
+
* Sec-Fetch-Site allowed to bypass CSRF check
|
|
40
|
+
* @default undefined
|
|
41
|
+
*/
|
|
42
|
+
secFetchSite?: Array<'same-origin' | 'same-site' | 'none' | 'cross-origin'>;
|
|
43
|
+
/**
|
|
44
|
+
* Custom error message
|
|
45
|
+
* @default 'CSRF token validation failed'
|
|
46
|
+
*/
|
|
47
|
+
errorMessage?: string;
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Create CSRF protection middleware
|
|
@@ -71,5 +71,6 @@ interface CSRFConfig {
|
|
|
71
71
|
* ```
|
|
72
72
|
*/
|
|
73
73
|
declare function csrf(config?: CSRFConfig): MiddlewareHandler;
|
|
74
|
-
|
|
75
|
-
export {
|
|
74
|
+
//#endregion
|
|
75
|
+
export { CSRFConfig, CSRFIgnoreRule, csrf };
|
|
76
|
+
//# sourceMappingURL=csrf.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.d.cts","names":[],"sources":["../../src/hono/csrf.ts"],"mappings":";;KASK;KAEO;EAA4B;EAAc,WAAW,eAAe;;UAE/D;;;;;EAKf;;;;;EAMA;;;;;;;;;EAUA,UAAU;;;;;EAMV,cAAc;;;;;EAMd;;;;;EAMA,eAAe;;;;;EAMf;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsCc,KAAK,SAAQ,aAAkB"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { MiddlewareHandler } from "hono";
|
|
2
|
+
//#region src/hono/csrf.d.ts
|
|
3
|
+
type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
|
|
4
|
+
type CSRFIgnoreRule = string | {
|
|
5
|
+
path: string;
|
|
6
|
+
methods?: [HTTPMethod, ...HTTPMethod[]];
|
|
7
|
+
};
|
|
8
|
+
interface CSRFConfig {
|
|
9
|
+
/**
|
|
10
|
+
* Cookie name for CSRF token
|
|
11
|
+
* @default 'XSRF-TOKEN'
|
|
12
|
+
*/
|
|
13
|
+
cookieName?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Header name for CSRF token
|
|
16
|
+
* @default 'X-XSRF-TOKEN'
|
|
17
|
+
*/
|
|
18
|
+
headerName?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Ignore rules for specific paths and methods
|
|
21
|
+
* @example
|
|
22
|
+
* [
|
|
23
|
+
* { path: '/api/webhook/*', methods: ['POST'] },
|
|
24
|
+
* { path: '/auth/apple/callback' }, // ignores all methods
|
|
25
|
+
* ]
|
|
26
|
+
*/
|
|
27
|
+
ignores?: CSRFIgnoreRule[];
|
|
28
|
+
/**
|
|
29
|
+
* Skip CSRF check for these methods
|
|
30
|
+
* @default ['GET', 'HEAD', 'OPTIONS']
|
|
31
|
+
*/
|
|
32
|
+
safeMethods?: HTTPMethod[];
|
|
33
|
+
/**
|
|
34
|
+
* Origin allowed to bypass CSRF check
|
|
35
|
+
* @default undefined
|
|
36
|
+
*/
|
|
37
|
+
origin?: string[];
|
|
38
|
+
/**
|
|
39
|
+
* Sec-Fetch-Site allowed to bypass CSRF check
|
|
40
|
+
* @default undefined
|
|
41
|
+
*/
|
|
42
|
+
secFetchSite?: Array<'same-origin' | 'same-site' | 'none' | 'cross-origin'>;
|
|
43
|
+
/**
|
|
44
|
+
* Custom error message
|
|
45
|
+
* @default 'CSRF token validation failed'
|
|
46
|
+
*/
|
|
47
|
+
errorMessage?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create CSRF protection middleware
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { Hono } from 'hono';
|
|
55
|
+
* import { csrf } from '@shware/http/hono';
|
|
56
|
+
*
|
|
57
|
+
* const app = new Hono();
|
|
58
|
+
*
|
|
59
|
+
* // basic usage
|
|
60
|
+
* app.use(csrf());
|
|
61
|
+
*
|
|
62
|
+
* // with configuration
|
|
63
|
+
* app.use(csrf({
|
|
64
|
+
* cookieName: 'csrf-token',
|
|
65
|
+
* headerName: 'X-CSRF-Token',
|
|
66
|
+
* ignores: [
|
|
67
|
+
* { path: '/api/webhook/*', methods: ['POST'] },
|
|
68
|
+
* { path: '/auth/apple/callback' },
|
|
69
|
+
* ]
|
|
70
|
+
* }));
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
declare function csrf(config?: CSRFConfig): MiddlewareHandler;
|
|
74
|
+
//#endregion
|
|
75
|
+
export { CSRFConfig, CSRFIgnoreRule, csrf };
|
|
76
|
+
//# sourceMappingURL=csrf.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.d.mts","names":[],"sources":["../../src/hono/csrf.ts"],"mappings":";;KASK;KAEO;EAA4B;EAAc,WAAW,eAAe;;UAE/D;;;;;EAKf;;;;;EAMA;;;;;;;;;EAUA,UAAU;;;;;EAMV,cAAc;;;;;EAMd;;;;;EAMA,eAAe;;;;;EAMf;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsCc,KAAK,SAAQ,aAAkB"}
|
package/dist/hono/csrf.mjs
CHANGED
|
@@ -1,72 +1,85 @@
|
|
|
1
|
-
|
|
2
|
-
import { timingSafeEqual } from "crypto";
|
|
3
|
-
import { getCookie } from "hono/cookie";
|
|
1
|
+
import { Status } from "../error/status.mjs";
|
|
4
2
|
import { METHOD_NAME_ALL } from "hono/router";
|
|
5
3
|
import { RegExpRouter } from "hono/router/reg-exp-router";
|
|
6
4
|
import { SmartRouter } from "hono/router/smart-router";
|
|
7
5
|
import { TrieRouter } from "hono/router/trie-router";
|
|
8
|
-
import {
|
|
6
|
+
import { timingSafeEqual } from "node:crypto";
|
|
7
|
+
import { getCookie } from "hono/cookie";
|
|
8
|
+
//#region src/hono/csrf.ts
|
|
9
|
+
/** use timing safe compare to prevent timing attack */
|
|
9
10
|
function safeCompare(a, b) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
if (typeof a !== "string" || typeof b !== "string") return false;
|
|
12
|
+
if (a.length === 0 || b.length === 0) return false;
|
|
13
|
+
const bufferA = Buffer.from(a, "utf-8");
|
|
14
|
+
const bufferB = Buffer.from(b, "utf-8");
|
|
15
|
+
if (bufferA.length !== bufferB.length) return false;
|
|
16
|
+
return timingSafeEqual(bufferA, bufferB);
|
|
16
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Create CSRF protection middleware
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { Hono } from 'hono';
|
|
24
|
+
* import { csrf } from '@shware/http/hono';
|
|
25
|
+
*
|
|
26
|
+
* const app = new Hono();
|
|
27
|
+
*
|
|
28
|
+
* // basic usage
|
|
29
|
+
* app.use(csrf());
|
|
30
|
+
*
|
|
31
|
+
* // with configuration
|
|
32
|
+
* app.use(csrf({
|
|
33
|
+
* cookieName: 'csrf-token',
|
|
34
|
+
* headerName: 'X-CSRF-Token',
|
|
35
|
+
* ignores: [
|
|
36
|
+
* { path: '/api/webhook/*', methods: ['POST'] },
|
|
37
|
+
* { path: '/auth/apple/callback' },
|
|
38
|
+
* ]
|
|
39
|
+
* }));
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
17
42
|
function csrf(config = {}) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const cookieToken = getCookie(c, cookieName);
|
|
59
|
-
const headerToken = c.req.header(headerName);
|
|
60
|
-
if (!cookieToken || !headerToken) {
|
|
61
|
-
throw Status.permissionDenied(errorMessage).error();
|
|
62
|
-
}
|
|
63
|
-
if (!safeCompare(cookieToken, headerToken)) {
|
|
64
|
-
throw Status.permissionDenied(errorMessage).error();
|
|
65
|
-
}
|
|
66
|
-
await next();
|
|
67
|
-
};
|
|
43
|
+
const cookieName = config.cookieName ?? "XSRF-TOKEN";
|
|
44
|
+
const headerName = config.headerName ?? "X-XSRF-TOKEN";
|
|
45
|
+
const safeMethods = new Set(config.safeMethods ?? [
|
|
46
|
+
"GET",
|
|
47
|
+
"HEAD",
|
|
48
|
+
"OPTIONS"
|
|
49
|
+
]);
|
|
50
|
+
const errorMessage = config.errorMessage ?? "CSRF token validation failed";
|
|
51
|
+
const router = new SmartRouter({ routers: [new RegExpRouter(), new TrieRouter()] });
|
|
52
|
+
if (config.ignores) for (const rule of config.ignores) if (typeof rule === "string") router.add(METHOD_NAME_ALL, rule, true);
|
|
53
|
+
else if (rule.methods && rule.methods.length > 0) for (const method of rule.methods) router.add(method, rule.path, true);
|
|
54
|
+
else router.add(METHOD_NAME_ALL, rule.path, true);
|
|
55
|
+
return async (c, next) => {
|
|
56
|
+
const method = c.req.method;
|
|
57
|
+
const path = c.req.path;
|
|
58
|
+
if (safeMethods.has(method)) {
|
|
59
|
+
await next();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (config.origin && config.origin.includes(c.req.header("origin") ?? "")) {
|
|
63
|
+
await next();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (config.secFetchSite && config.secFetchSite.includes(c.req.header("sec-fetch-site") ?? "")) {
|
|
67
|
+
await next();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const [matched] = router.match(method, path);
|
|
71
|
+
if (matched.length > 0) {
|
|
72
|
+
await next();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const cookieToken = getCookie(c, cookieName);
|
|
76
|
+
const headerToken = c.req.header(headerName);
|
|
77
|
+
if (!cookieToken || !headerToken) throw Status.permissionDenied(errorMessage).error();
|
|
78
|
+
if (!safeCompare(cookieToken, headerToken)) throw Status.permissionDenied(errorMessage).error();
|
|
79
|
+
await next();
|
|
80
|
+
};
|
|
68
81
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
//#endregion
|
|
83
|
+
export { csrf };
|
|
84
|
+
|
|
72
85
|
//# sourceMappingURL=csrf.mjs.map
|
package/dist/hono/csrf.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hono/csrf.ts"],"sourcesContent":["import { timingSafeEqual } from 'crypto';\nimport type { MiddlewareHandler } from 'hono';\nimport { getCookie } from 'hono/cookie';\nimport { METHOD_NAME_ALL } from 'hono/router';\nimport { RegExpRouter } from 'hono/router/reg-exp-router';\nimport { SmartRouter } from 'hono/router/smart-router';\nimport { TrieRouter } from 'hono/router/trie-router';\nimport { Status } from '../error/status';\n\ntype HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';\n\nexport type CSRFIgnoreRule = string | { path: string; methods?: [HTTPMethod, ...HTTPMethod[]] };\n\nexport interface CSRFConfig {\n /**\n * Cookie name for CSRF token\n * @default 'XSRF-TOKEN'\n */\n cookieName?: string;\n\n /**\n * Header name for CSRF token\n * @default 'X-XSRF-TOKEN'\n */\n headerName?: string;\n\n /**\n * Ignore rules for specific paths and methods\n * @example\n * [\n * { path: '/api/webhook/*', methods: ['POST'] },\n * { path: '/auth/apple/callback' }, // ignores all methods\n * ]\n */\n ignores?: CSRFIgnoreRule[];\n\n /**\n * Skip CSRF check for these methods\n * @default ['GET', 'HEAD', 'OPTIONS']\n */\n safeMethods?: HTTPMethod[];\n\n /**\n * Origin allowed to bypass CSRF check\n * @default undefined\n */\n origin?: string[];\n\n /**\n * Sec-Fetch-Site allowed to bypass CSRF check\n * @default undefined\n */\n secFetchSite?: Array<'same-origin' | 'same-site' | 'none' | 'cross-origin'>;\n\n /**\n * Custom error message\n * @default 'CSRF token validation failed'\n */\n errorMessage?: string;\n}\n\n/** use timing safe compare to prevent timing attack */\nfunction safeCompare(a: string, b: string): boolean {\n if (typeof a !== 'string' || typeof b !== 'string') return false;\n if (a.length === 0 || b.length === 0) return false;\n\n const bufferA = Buffer.from(a, 'utf-8');\n const bufferB = Buffer.from(b, 'utf-8');\n if (bufferA.length !== bufferB.length) return false;\n return timingSafeEqual(bufferA, bufferB);\n}\n\n/**\n * Create CSRF protection middleware\n *\n * @example\n * ```ts\n * import { Hono } from 'hono';\n * import { csrf } from '@shware/http/hono';\n *\n * const app = new Hono();\n *\n * // basic usage\n * app.use(csrf());\n *\n * // with configuration\n * app.use(csrf({\n * cookieName: 'csrf-token',\n * headerName: 'X-CSRF-Token',\n * ignores: [\n * { path: '/api/webhook/*', methods: ['POST'] },\n * { path: '/auth/apple/callback' },\n * ]\n * }));\n * ```\n */\nexport function csrf(config: CSRFConfig = {}): MiddlewareHandler {\n const cookieName = config.cookieName ?? 'XSRF-TOKEN';\n const headerName = config.headerName ?? 'X-XSRF-TOKEN';\n const safeMethods = new Set(config.safeMethods ?? ['GET', 'HEAD', 'OPTIONS']);\n const errorMessage = config.errorMessage ?? 'CSRF token validation failed';\n\n // initialize router for matching ignore rules\n const router = new SmartRouter<boolean>({\n routers: [new RegExpRouter(), new TrieRouter()],\n });\n\n // register ignore rules\n if (config.ignores) {\n for (const rule of config.ignores) {\n if (typeof rule === 'string') {\n router.add(METHOD_NAME_ALL, rule, true);\n } else if (rule.methods && rule.methods.length > 0) {\n for (const method of rule.methods) {\n router.add(method, rule.path, true);\n }\n } else {\n // if no methods are specified, ignore all methods\n router.add(METHOD_NAME_ALL, rule.path, true);\n }\n }\n }\n\n // return middleware\n return async (c, next) => {\n const method = c.req.method;\n const path = c.req.path;\n\n // check if the request should be ignored\n // 1. ignore safe methods\n if (safeMethods.has(method)) {\n await next();\n return;\n }\n\n // 2. ignore configured origin\n if (config.origin && config.origin.includes(c.req.header('origin') ?? '')) {\n await next();\n return;\n }\n\n // 3. ignore configured secFetchSite\n if (\n config.secFetchSite &&\n config.secFetchSite.includes((c.req.header('sec-fetch-site') ?? '') as never)\n ) {\n await next();\n return;\n }\n\n // 4. ignore configured ignore rules\n const [matched] = router.match(method, path);\n if (matched.length > 0) {\n await next();\n return;\n }\n\n const cookieToken = getCookie(c, cookieName);\n const headerToken = c.req.header(headerName);\n\n if (!cookieToken || !headerToken) {\n throw Status.permissionDenied(errorMessage).error();\n }\n\n if (!safeCompare(cookieToken, headerToken)) {\n throw Status.permissionDenied(errorMessage).error();\n }\n\n await next();\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"csrf.mjs","names":[],"sources":["../../src/hono/csrf.ts"],"sourcesContent":["import { timingSafeEqual } from 'node:crypto';\nimport type { MiddlewareHandler } from 'hono';\nimport { getCookie } from 'hono/cookie';\nimport { METHOD_NAME_ALL } from 'hono/router';\nimport { RegExpRouter } from 'hono/router/reg-exp-router';\nimport { SmartRouter } from 'hono/router/smart-router';\nimport { TrieRouter } from 'hono/router/trie-router';\nimport { Status } from '../error/status';\n\ntype HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';\n\nexport type CSRFIgnoreRule = string | { path: string; methods?: [HTTPMethod, ...HTTPMethod[]] };\n\nexport interface CSRFConfig {\n /**\n * Cookie name for CSRF token\n * @default 'XSRF-TOKEN'\n */\n cookieName?: string;\n\n /**\n * Header name for CSRF token\n * @default 'X-XSRF-TOKEN'\n */\n headerName?: string;\n\n /**\n * Ignore rules for specific paths and methods\n * @example\n * [\n * { path: '/api/webhook/*', methods: ['POST'] },\n * { path: '/auth/apple/callback' }, // ignores all methods\n * ]\n */\n ignores?: CSRFIgnoreRule[];\n\n /**\n * Skip CSRF check for these methods\n * @default ['GET', 'HEAD', 'OPTIONS']\n */\n safeMethods?: HTTPMethod[];\n\n /**\n * Origin allowed to bypass CSRF check\n * @default undefined\n */\n origin?: string[];\n\n /**\n * Sec-Fetch-Site allowed to bypass CSRF check\n * @default undefined\n */\n secFetchSite?: Array<'same-origin' | 'same-site' | 'none' | 'cross-origin'>;\n\n /**\n * Custom error message\n * @default 'CSRF token validation failed'\n */\n errorMessage?: string;\n}\n\n/** use timing safe compare to prevent timing attack */\nfunction safeCompare(a: string, b: string): boolean {\n if (typeof a !== 'string' || typeof b !== 'string') return false;\n if (a.length === 0 || b.length === 0) return false;\n\n const bufferA = Buffer.from(a, 'utf-8');\n const bufferB = Buffer.from(b, 'utf-8');\n if (bufferA.length !== bufferB.length) return false;\n return timingSafeEqual(bufferA, bufferB);\n}\n\n/**\n * Create CSRF protection middleware\n *\n * @example\n * ```ts\n * import { Hono } from 'hono';\n * import { csrf } from '@shware/http/hono';\n *\n * const app = new Hono();\n *\n * // basic usage\n * app.use(csrf());\n *\n * // with configuration\n * app.use(csrf({\n * cookieName: 'csrf-token',\n * headerName: 'X-CSRF-Token',\n * ignores: [\n * { path: '/api/webhook/*', methods: ['POST'] },\n * { path: '/auth/apple/callback' },\n * ]\n * }));\n * ```\n */\nexport function csrf(config: CSRFConfig = {}): MiddlewareHandler {\n const cookieName = config.cookieName ?? 'XSRF-TOKEN';\n const headerName = config.headerName ?? 'X-XSRF-TOKEN';\n const safeMethods = new Set(config.safeMethods ?? ['GET', 'HEAD', 'OPTIONS']);\n const errorMessage = config.errorMessage ?? 'CSRF token validation failed';\n\n // initialize router for matching ignore rules\n const router = new SmartRouter<boolean>({\n routers: [new RegExpRouter(), new TrieRouter()],\n });\n\n // register ignore rules\n if (config.ignores) {\n for (const rule of config.ignores) {\n if (typeof rule === 'string') {\n router.add(METHOD_NAME_ALL, rule, true);\n } else if (rule.methods && rule.methods.length > 0) {\n for (const method of rule.methods) {\n router.add(method, rule.path, true);\n }\n } else {\n // if no methods are specified, ignore all methods\n router.add(METHOD_NAME_ALL, rule.path, true);\n }\n }\n }\n\n // return middleware\n return async (c, next) => {\n const method = c.req.method;\n const path = c.req.path;\n\n // check if the request should be ignored\n // 1. ignore safe methods\n if (safeMethods.has(method)) {\n await next();\n return;\n }\n\n // 2. ignore configured origin\n if (config.origin && config.origin.includes(c.req.header('origin') ?? '')) {\n await next();\n return;\n }\n\n // 3. ignore configured secFetchSite\n if (\n config.secFetchSite &&\n config.secFetchSite.includes((c.req.header('sec-fetch-site') ?? '') as never)\n ) {\n await next();\n return;\n }\n\n // 4. ignore configured ignore rules\n const [matched] = router.match(method, path);\n if (matched.length > 0) {\n await next();\n return;\n }\n\n const cookieToken = getCookie(c, cookieName);\n const headerToken = c.req.header(headerName);\n\n if (!cookieToken || !headerToken) {\n throw Status.permissionDenied(errorMessage).error();\n }\n\n if (!safeCompare(cookieToken, headerToken)) {\n throw Status.permissionDenied(errorMessage).error();\n }\n\n await next();\n };\n}\n"],"mappings":";;;;;;;;;AA8DA,SAAS,YAAY,GAAW,GAAoB;CAClD,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU,OAAO;CAC3D,IAAI,EAAE,WAAW,KAAK,EAAE,WAAW,GAAG,OAAO;CAE7C,MAAM,UAAU,OAAO,KAAK,GAAG,OAAO;CACtC,MAAM,UAAU,OAAO,KAAK,GAAG,OAAO;CACtC,IAAI,QAAQ,WAAW,QAAQ,QAAQ,OAAO;CAC9C,OAAO,gBAAgB,SAAS,OAAO;AACzC;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,KAAK,SAAqB,CAAC,GAAsB;CAC/D,MAAM,aAAa,OAAO,cAAc;CACxC,MAAM,aAAa,OAAO,cAAc;CACxC,MAAM,cAAc,IAAI,IAAI,OAAO,eAAe;EAAC;EAAO;EAAQ;CAAS,CAAC;CAC5E,MAAM,eAAe,OAAO,gBAAgB;CAG5C,MAAM,SAAS,IAAI,YAAqB,EACtC,SAAS,CAAC,IAAI,aAAa,GAAG,IAAI,WAAW,CAAC,EAChD,CAAC;CAGD,IAAI,OAAO,SACT,KAAK,MAAM,QAAQ,OAAO,SACxB,IAAI,OAAO,SAAS,UAClB,OAAO,IAAI,iBAAiB,MAAM,IAAI;MACjC,IAAI,KAAK,WAAW,KAAK,QAAQ,SAAS,GAC/C,KAAK,MAAM,UAAU,KAAK,SACxB,OAAO,IAAI,QAAQ,KAAK,MAAM,IAAI;MAIpC,OAAO,IAAI,iBAAiB,KAAK,MAAM,IAAI;CAMjD,OAAO,OAAO,GAAG,SAAS;EACxB,MAAM,SAAS,EAAE,IAAI;EACrB,MAAM,OAAO,EAAE,IAAI;EAInB,IAAI,YAAY,IAAI,MAAM,GAAG;GAC3B,MAAM,KAAK;GACX;EACF;EAGA,IAAI,OAAO,UAAU,OAAO,OAAO,SAAS,EAAE,IAAI,OAAO,QAAQ,KAAK,EAAE,GAAG;GACzE,MAAM,KAAK;GACX;EACF;EAGA,IACE,OAAO,gBACP,OAAO,aAAa,SAAU,EAAE,IAAI,OAAO,gBAAgB,KAAK,EAAY,GAC5E;GACA,MAAM,KAAK;GACX;EACF;EAGA,MAAM,CAAC,WAAW,OAAO,MAAM,QAAQ,IAAI;EAC3C,IAAI,QAAQ,SAAS,GAAG;GACtB,MAAM,KAAK;GACX;EACF;EAEA,MAAM,cAAc,UAAU,GAAG,UAAU;EAC3C,MAAM,cAAc,EAAE,IAAI,OAAO,UAAU;EAE3C,IAAI,CAAC,eAAe,CAAC,aACnB,MAAM,OAAO,iBAAiB,YAAY,CAAC,CAAC,MAAM;EAGpD,IAAI,CAAC,YAAY,aAAa,WAAW,GACvC,MAAM,OAAO,iBAAiB,YAAY,CAAC,CAAC,MAAM;EAGpD,MAAM,KAAK;CACb;AACF"}
|
|
@@ -1,37 +1,13 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/hono/geolocation.ts
|
|
21
|
-
var geolocation_exports = {};
|
|
22
|
-
__export(geolocation_exports, {
|
|
23
|
-
geolocation: () => geolocation
|
|
24
|
-
});
|
|
25
|
-
module.exports = __toCommonJS(geolocation_exports);
|
|
26
|
-
var import_adapter = require("hono/adapter");
|
|
27
|
-
var import_geolocation = require("../utils/geolocation.cjs");
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_utils_geolocation = require("../utils/geolocation.cjs");
|
|
3
|
+
let hono_adapter = require("hono/adapter");
|
|
4
|
+
//#region src/hono/geolocation.ts
|
|
28
5
|
function geolocation(c) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
6
|
+
if ((0, hono_adapter.getRuntimeKey)() === "workerd") return require_utils_geolocation.getGeolocationFromCloudflare(c.req.raw);
|
|
7
|
+
if (c.req.header("x-vercel-id")) return require_utils_geolocation.getGeolocationFromVercel(c.req.raw);
|
|
8
|
+
return require_utils_geolocation.getGeolocationFromCloudfront(c.req.raw);
|
|
32
9
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
10
|
+
//#endregion
|
|
11
|
+
exports.geolocation = geolocation;
|
|
12
|
+
|
|
37
13
|
//# sourceMappingURL=geolocation.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hono/geolocation.ts"],"sourcesContent":["import type { Context } from 'hono';\nimport { getRuntimeKey } from 'hono/adapter';\nimport {\n type Geolocation,\n getGeolocationFromCloudflare,\n getGeolocationFromCloudfront,\n getGeolocationFromVercel,\n} from '../utils/geolocation';\n\nexport function geolocation(c: Context): Geolocation {\n if (getRuntimeKey() === 'workerd') return getGeolocationFromCloudflare(c.req.raw);\n if (c.req.header('x-vercel-id')) return getGeolocationFromVercel(c.req.raw);\n return getGeolocationFromCloudfront(c.req.raw);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"geolocation.cjs","names":["getGeolocationFromCloudflare","getGeolocationFromVercel","getGeolocationFromCloudfront"],"sources":["../../src/hono/geolocation.ts"],"sourcesContent":["import type { Context } from 'hono';\nimport { getRuntimeKey } from 'hono/adapter';\nimport {\n type Geolocation,\n getGeolocationFromCloudflare,\n getGeolocationFromCloudfront,\n getGeolocationFromVercel,\n} from '../utils/geolocation';\n\nexport function geolocation(c: Context): Geolocation {\n if (getRuntimeKey() === 'workerd') return getGeolocationFromCloudflare(c.req.raw);\n if (c.req.header('x-vercel-id')) return getGeolocationFromVercel(c.req.raw);\n return getGeolocationFromCloudfront(c.req.raw);\n}\n"],"mappings":";;;;AASA,SAAgB,YAAY,GAAyB;CACnD,KAAA,GAAA,aAAA,cAAA,CAAkB,MAAM,WAAW,OAAOA,0BAAAA,6BAA6B,EAAE,IAAI,GAAG;CAChF,IAAI,EAAE,IAAI,OAAO,aAAa,GAAG,OAAOC,0BAAAA,yBAAyB,EAAE,IAAI,GAAG;CAC1E,OAAOC,0BAAAA,6BAA6B,EAAE,IAAI,GAAG;AAC/C"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { Geolocation } from "../utils/geolocation.cjs";
|
|
2
|
+
import { Context } from "hono";
|
|
3
|
+
//#region src/hono/geolocation.d.ts
|
|
4
4
|
declare function geolocation(c: Context): Geolocation;
|
|
5
|
-
|
|
5
|
+
//#endregion
|
|
6
6
|
export { geolocation };
|
|
7
|
+
//# sourceMappingURL=geolocation.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geolocation.d.cts","names":[],"sources":["../../src/hono/geolocation.ts"],"mappings":";;;iBASgB,YAAY,GAAG,UAAU"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Geolocation } from "../utils/geolocation.mjs";
|
|
2
|
+
import { Context } from "hono";
|
|
3
|
+
//#region src/hono/geolocation.d.ts
|
|
4
|
+
declare function geolocation(c: Context): Geolocation;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { geolocation };
|
|
7
|
+
//# sourceMappingURL=geolocation.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geolocation.d.mts","names":[],"sources":["../../src/hono/geolocation.ts"],"mappings":";;;iBASgB,YAAY,GAAG,UAAU"}
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { getGeolocationFromCloudflare, getGeolocationFromCloudfront, getGeolocationFromVercel } from "../utils/geolocation.mjs";
|
|
2
2
|
import { getRuntimeKey } from "hono/adapter";
|
|
3
|
-
|
|
4
|
-
getGeolocationFromCloudflare,
|
|
5
|
-
getGeolocationFromCloudfront,
|
|
6
|
-
getGeolocationFromVercel
|
|
7
|
-
} from "../utils/geolocation.mjs";
|
|
3
|
+
//#region src/hono/geolocation.ts
|
|
8
4
|
function geolocation(c) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
if (getRuntimeKey() === "workerd") return getGeolocationFromCloudflare(c.req.raw);
|
|
6
|
+
if (c.req.header("x-vercel-id")) return getGeolocationFromVercel(c.req.raw);
|
|
7
|
+
return getGeolocationFromCloudfront(c.req.raw);
|
|
12
8
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
//#endregion
|
|
10
|
+
export { geolocation };
|
|
11
|
+
|
|
16
12
|
//# sourceMappingURL=geolocation.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hono/geolocation.ts"],"sourcesContent":["import type { Context } from 'hono';\nimport { getRuntimeKey } from 'hono/adapter';\nimport {\n type Geolocation,\n getGeolocationFromCloudflare,\n getGeolocationFromCloudfront,\n getGeolocationFromVercel,\n} from '../utils/geolocation';\n\nexport function geolocation(c: Context): Geolocation {\n if (getRuntimeKey() === 'workerd') return getGeolocationFromCloudflare(c.req.raw);\n if (c.req.header('x-vercel-id')) return getGeolocationFromVercel(c.req.raw);\n return getGeolocationFromCloudfront(c.req.raw);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"geolocation.mjs","names":[],"sources":["../../src/hono/geolocation.ts"],"sourcesContent":["import type { Context } from 'hono';\nimport { getRuntimeKey } from 'hono/adapter';\nimport {\n type Geolocation,\n getGeolocationFromCloudflare,\n getGeolocationFromCloudfront,\n getGeolocationFromVercel,\n} from '../utils/geolocation';\n\nexport function geolocation(c: Context): Geolocation {\n if (getRuntimeKey() === 'workerd') return getGeolocationFromCloudflare(c.req.raw);\n if (c.req.header('x-vercel-id')) return getGeolocationFromVercel(c.req.raw);\n return getGeolocationFromCloudfront(c.req.raw);\n}\n"],"mappings":";;;AASA,SAAgB,YAAY,GAAyB;CACnD,IAAI,cAAc,MAAM,WAAW,OAAO,6BAA6B,EAAE,IAAI,GAAG;CAChF,IAAI,EAAE,IAAI,OAAO,aAAa,GAAG,OAAO,yBAAyB,EAAE,IAAI,GAAG;CAC1E,OAAO,6BAA6B,EAAE,IAAI,GAAG;AAC/C"}
|