@sonicjs-cms/core 2.14.0 → 2.15.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/admin-layout-catalyst.template-HFD37TY5.cjs +17 -0
- package/dist/admin-layout-catalyst.template-HFD37TY5.cjs.map +1 -0
- package/dist/admin-layout-catalyst.template-UMTIN66R.js +7 -0
- package/dist/admin-layout-catalyst.template-UMTIN66R.js.map +1 -0
- package/dist/{chunk-DRWSHIFG.cjs → chunk-26HYU7MX.cjs} +228 -658
- package/dist/chunk-26HYU7MX.cjs.map +1 -0
- package/dist/{chunk-AFGOH2F6.js → chunk-2BL2A62D.js} +4 -4
- package/dist/{chunk-AFGOH2F6.js.map → chunk-2BL2A62D.js.map} +1 -1
- package/dist/{chunk-I6FFGQIT.cjs → chunk-43AB4EH4.cjs} +723 -211
- package/dist/chunk-43AB4EH4.cjs.map +1 -0
- package/dist/{chunk-3QCEYJLK.cjs → chunk-4ZSNJDLS.cjs} +9 -9
- package/dist/{chunk-3QCEYJLK.cjs.map → chunk-4ZSNJDLS.cjs.map} +1 -1
- package/dist/chunk-55RDMDOP.js +684 -0
- package/dist/chunk-55RDMDOP.js.map +1 -0
- package/dist/{chunk-JKNKO6LA.js → chunk-5SOFMH66.js} +2 -2
- package/dist/{chunk-JKNKO6LA.js.map → chunk-5SOFMH66.js.map} +1 -1
- package/dist/{chunk-6FHNRRJ3.cjs → chunk-635JAMSE.cjs} +76 -17
- package/dist/chunk-635JAMSE.cjs.map +1 -0
- package/dist/{chunk-23DP6TO5.js → chunk-7MMD5WMK.js} +44 -474
- package/dist/chunk-7MMD5WMK.js.map +1 -0
- package/dist/{chunk-56GUBLJE.cjs → chunk-ABB34XUS.cjs} +13 -13
- package/dist/{chunk-56GUBLJE.cjs.map → chunk-ABB34XUS.cjs.map} +1 -1
- package/dist/{chunk-GAVTTYMC.js → chunk-EWXV2KG2.js} +3 -3
- package/dist/{chunk-GAVTTYMC.js.map → chunk-EWXV2KG2.js.map} +1 -1
- package/dist/{chunk-J5WGMRSU.js → chunk-EXNEW5US.js} +76 -17
- package/dist/chunk-EXNEW5US.js.map +1 -0
- package/dist/{chunk-H3XXBAMO.js → chunk-G7XSN72O.js} +722 -212
- package/dist/chunk-G7XSN72O.js.map +1 -0
- package/dist/{chunk-QP3OHHON.cjs → chunk-OHYBNCVL.cjs} +18 -696
- package/dist/chunk-OHYBNCVL.cjs.map +1 -0
- package/dist/{chunk-CB7ONLGB.js → chunk-ON5ZMSU4.js} +3 -3
- package/dist/{chunk-CB7ONLGB.js.map → chunk-ON5ZMSU4.js.map} +1 -1
- package/dist/{chunk-KZ2MFGET.cjs → chunk-RVD7PLMU.cjs} +2 -2
- package/dist/{chunk-KZ2MFGET.cjs.map → chunk-RVD7PLMU.cjs.map} +1 -1
- package/dist/{chunk-2MXF4RYZ.js → chunk-TFNTM3OA.js} +3 -3
- package/dist/{chunk-2MXF4RYZ.js.map → chunk-TFNTM3OA.js.map} +1 -1
- package/dist/{chunk-YYMPHM3I.cjs → chunk-UFPT5KCQ.cjs} +8 -8
- package/dist/{chunk-YYMPHM3I.cjs.map → chunk-UFPT5KCQ.cjs.map} +1 -1
- package/dist/chunk-UYJ6TJHX.cjs +691 -0
- package/dist/chunk-UYJ6TJHX.cjs.map +1 -0
- package/dist/{chunk-YULUPQZV.cjs → chunk-VUISYUHY.cjs} +3 -3
- package/dist/{chunk-YULUPQZV.cjs.map → chunk-VUISYUHY.cjs.map} +1 -1
- package/dist/{chunk-JTUCC6WZ.js → chunk-XWIA3HVX.js} +9 -683
- package/dist/chunk-XWIA3HVX.js.map +1 -0
- package/dist/index.cjs +910 -233
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +765 -88
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +29 -29
- package/dist/middleware.js +3 -3
- package/dist/migrations-APFGYCB6.cjs +13 -0
- package/dist/{migrations-F7KVA74T.cjs.map → migrations-APFGYCB6.cjs.map} +1 -1
- package/dist/migrations-YB52SLW7.js +4 -0
- package/dist/{migrations-WKONKRN7.js.map → migrations-YB52SLW7.js.map} +1 -1
- package/dist/{plugin-bootstrap-BGwBraaN.d.cts → plugin-bootstrap-DfVerYV4.d.cts} +2 -1
- package/dist/{plugin-bootstrap-Drns7X9w.d.ts → plugin-bootstrap-P_ciLp_C.d.ts} +2 -1
- package/dist/plugins.cjs +11 -11
- package/dist/plugins.js +2 -2
- package/dist/routes.cjs +31 -30
- package/dist/routes.js +8 -7
- package/dist/services.cjs +23 -23
- package/dist/services.js +2 -2
- package/dist/templates.cjs +26 -25
- package/dist/templates.js +3 -2
- package/dist/utils.cjs +11 -11
- package/dist/utils.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-23DP6TO5.js.map +0 -1
- package/dist/chunk-6FHNRRJ3.cjs.map +0 -1
- package/dist/chunk-DRWSHIFG.cjs.map +0 -1
- package/dist/chunk-H3XXBAMO.js.map +0 -1
- package/dist/chunk-I6FFGQIT.cjs.map +0 -1
- package/dist/chunk-J5WGMRSU.js.map +0 -1
- package/dist/chunk-JTUCC6WZ.js.map +0 -1
- package/dist/chunk-QP3OHHON.cjs.map +0 -1
- package/dist/migrations-F7KVA74T.cjs +0 -13
- package/dist/migrations-WKONKRN7.js +0 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { syncCollections, syncAllFormCollections, PluginBootstrapService } from './chunk-
|
|
2
|
-
import { MigrationService } from './chunk-
|
|
1
|
+
import { syncCollections, syncAllFormCollections, PluginBootstrapService } from './chunk-G7XSN72O.js';
|
|
2
|
+
import { MigrationService } from './chunk-5SOFMH66.js';
|
|
3
3
|
import { metricsTracker } from './chunk-FICTAGD4.js';
|
|
4
4
|
import { sign, verify } from 'hono/jwt';
|
|
5
5
|
import { setCookie, getCookie } from 'hono/cookie';
|
|
@@ -543,5 +543,5 @@ var getActivePlugins = () => [];
|
|
|
543
543
|
var isPluginActive = () => false;
|
|
544
544
|
|
|
545
545
|
export { AuthManager, PermissionManager, bootstrapMiddleware, cacheHeaders, compressionMiddleware, csrfProtection, detailedLoggingMiddleware, generateCsrfToken, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, metricsMiddleware, optionalAuth, performanceLoggingMiddleware, rateLimit, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeadersMiddleware, securityLoggingMiddleware, validateCsrfToken, verifySecurityConfig };
|
|
546
|
-
//# sourceMappingURL=chunk-
|
|
547
|
-
//# sourceMappingURL=chunk-
|
|
546
|
+
//# sourceMappingURL=chunk-2BL2A62D.js.map
|
|
547
|
+
//# sourceMappingURL=chunk-2BL2A62D.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/middleware/bootstrap.ts","../src/middleware/auth.ts","../src/middleware/metrics.ts","../src/middleware/csrf.ts","../src/middleware/rate-limit.ts","../src/middleware/security-headers.ts","../src/middleware/index.ts"],"names":["result","JWT_SECRET_FALLBACK","getCookie","setCookie"],"mappings":"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","file":"chunk-AFGOH2F6.js","sourcesContent":["import { Context, Next } from \"hono\";\nimport { syncCollections } from \"../services/collection-sync\";\nimport { syncAllFormCollections } from \"../services/form-collection-sync\";\nimport { MigrationService } from \"../services/migrations\";\nimport { PluginBootstrapService } from \"../services/plugin-bootstrap\";\nimport type { SonicJSConfig } from \"../app\";\n\ntype Bindings = {\n DB: D1Database;\n KV: KVNamespace;\n JWT_SECRET?: string;\n CORS_ORIGINS?: string;\n ENVIRONMENT?: string;\n};\n\n// Track if bootstrap has been run in this worker instance\nlet bootstrapComplete = false;\n\n/**\n * Verify security-critical environment configuration at startup.\n * Logs warnings in development, throws in production to prevent\n * insecure deployments from silently running.\n */\nexport function verifySecurityConfig(env: Bindings): void {\n const warnings: string[] = [];\n\n // Check JWT secret\n if (!env.JWT_SECRET) {\n warnings.push(\n \"JWT_SECRET is not set — using hardcoded fallback. Set via `wrangler secret put JWT_SECRET`\"\n );\n } else if (env.JWT_SECRET.includes(\"change-in-production\")) {\n warnings.push(\n \"JWT_SECRET contains the default value — tokens are forgeable. Generate a strong random secret\"\n );\n }\n\n // Check CORS origins\n if (!env.CORS_ORIGINS) {\n warnings.push(\n \"CORS_ORIGINS is not set — all cross-origin API requests will be rejected\"\n );\n }\n\n // Check environment designation\n if (!env.ENVIRONMENT) {\n warnings.push(\n \"ENVIRONMENT is not set — HSTS header will not be applied. Set to \\\"production\\\" or \\\"development\\\"\"\n );\n }\n\n if (warnings.length === 0) {\n return;\n }\n\n const isProduction = env.ENVIRONMENT === \"production\";\n\n for (const warning of warnings) {\n console.warn(`[SonicJS Security] ${warning}`);\n }\n\n if (isProduction) {\n // In production, a missing or default JWT_SECRET is a hard failure —\n // every token issued would be forgeable by anyone reading the source code.\n const hasCritical =\n !env.JWT_SECRET || env.JWT_SECRET.includes(\"change-in-production\");\n if (hasCritical) {\n throw new Error(\n \"[SonicJS Security] CRITICAL: Production deployment is missing a secure JWT_SECRET. \" +\n \"Set it via `wrangler secret put JWT_SECRET` before deploying.\"\n );\n }\n }\n}\n\n/**\n * Bootstrap middleware that ensures system initialization\n * Runs once per worker instance\n */\nexport function bootstrapMiddleware(config: SonicJSConfig = {}) {\n return async (c: Context<{ Bindings: Bindings }>, next: Next) => {\n // Skip if already bootstrapped in this worker instance\n if (bootstrapComplete) {\n return next();\n }\n\n // Skip bootstrap for static assets and health checks\n const path = c.req.path;\n if (\n path.startsWith(\"/images/\") ||\n path.startsWith(\"/assets/\") ||\n path === \"/health\" ||\n path.endsWith(\".js\") ||\n path.endsWith(\".css\") ||\n path.endsWith(\".png\") ||\n path.endsWith(\".jpg\") ||\n path.endsWith(\".ico\")\n ) {\n return next();\n }\n\n try {\n console.log(\"[Bootstrap] Starting system initialization...\");\n\n // 1. Run database migrations first\n console.log(\"[Bootstrap] Running database migrations...\");\n const migrationService = new MigrationService(c.env.DB);\n await migrationService.runPendingMigrations();\n\n // 2. Sync collection configurations\n console.log(\"[Bootstrap] Syncing collection configurations...\");\n try {\n await syncCollections(c.env.DB);\n } catch (error) {\n console.error(\"[Bootstrap] Error syncing collections:\", error);\n // Continue bootstrap even if collection sync fails\n }\n\n // 2b. Sync form-derived shadow collections\n console.log(\"[Bootstrap] Syncing form collections...\");\n try {\n await syncAllFormCollections(c.env.DB);\n } catch (error) {\n console.error(\"[Bootstrap] Error syncing form collections:\", error);\n }\n\n // 3. Bootstrap core plugins (unless disableAll is set)\n if (!config.plugins?.disableAll) {\n console.log(\"[Bootstrap] Bootstrapping core plugins...\");\n const bootstrapService = new PluginBootstrapService(c.env.DB);\n\n // Check if bootstrap is needed\n const needsBootstrap = await bootstrapService.isBootstrapNeeded();\n if (needsBootstrap) {\n await bootstrapService.bootstrapCorePlugins();\n }\n } else {\n console.log(\"[Bootstrap] Plugin bootstrap skipped (disableAll is true)\");\n }\n\n // Mark bootstrap as complete for this worker instance\n bootstrapComplete = true;\n console.log(\"[Bootstrap] System initialization completed\");\n } catch (error) {\n console.error(\"[Bootstrap] Error during system initialization:\", error);\n // Don't prevent the app from starting, but log the error\n }\n\n // 4. Verify security configuration (outside try/catch so critical\n // errors in production propagate and prevent insecure deployments)\n verifySecurityConfig(c.env as Bindings);\n\n return next();\n };\n}\n\n/**\n * Reset bootstrap flag (useful for testing)\n */\nexport function resetBootstrap() {\n bootstrapComplete = false;\n}\n","import { sign, verify } from 'hono/jwt'\nimport { Context, Next } from 'hono'\nimport { getCookie, setCookie } from 'hono/cookie'\n\ntype JWTPayload = {\n userId: string\n email: string\n role: string\n exp: number\n iat: number\n}\n\n// Fallback JWT secret for local development only (no wrangler secret set)\nconst JWT_SECRET_FALLBACK = 'your-super-secret-jwt-key-change-in-production'\n\nexport class AuthManager {\n static async generateToken(userId: string, email: string, role: string, secret?: string): Promise<string> {\n const payload: JWTPayload = {\n userId,\n email,\n role,\n exp: Math.floor(Date.now() / 1000) + (60 * 60 * 24), // 24 hours\n iat: Math.floor(Date.now() / 1000)\n }\n\n return await sign(payload, secret || JWT_SECRET_FALLBACK, 'HS256')\n }\n\n static async verifyToken(token: string, secret?: string): Promise<JWTPayload | null> {\n try {\n const payload = await verify(token, secret || JWT_SECRET_FALLBACK, 'HS256') as JWTPayload\n \n // Check if token is expired\n if (payload.exp < Math.floor(Date.now() / 1000)) {\n return null\n }\n \n return payload\n } catch (error) {\n console.error('Token verification failed:', error)\n return null\n }\n }\n\n static async hashPassword(password: string): Promise<string> {\n const iterations = 100000\n const salt = new Uint8Array(16)\n crypto.getRandomValues(salt)\n\n const encoder = new TextEncoder()\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(password),\n 'PBKDF2',\n false,\n ['deriveBits']\n )\n\n const hashBuffer = await crypto.subtle.deriveBits(\n {\n name: 'PBKDF2',\n salt,\n iterations,\n hash: 'SHA-256'\n },\n keyMaterial,\n 256\n )\n\n const saltHex = Array.from(salt).map(b => b.toString(16).padStart(2, '0')).join('')\n const hashHex = Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('')\n\n return `pbkdf2:${iterations}:${saltHex}:${hashHex}`\n }\n\n static async hashPasswordLegacy(password: string): Promise<string> {\n const encoder = new TextEncoder()\n const data = encoder.encode(password + 'salt-change-in-production')\n const hashBuffer = await crypto.subtle.digest('SHA-256', data)\n const hashArray = Array.from(new Uint8Array(hashBuffer))\n return hashArray.map(b => b.toString(16).padStart(2, '0')).join('')\n }\n\n static async verifyPassword(password: string, storedHash: string): Promise<boolean> {\n if (storedHash.startsWith('pbkdf2:')) {\n // PBKDF2 format: pbkdf2:<iterations>:<salt_hex>:<hash_hex>\n const parts = storedHash.split(':')\n if (parts.length !== 4) return false\n\n const iterationsStr = parts[1]!\n const saltHex = parts[2]!\n const expectedHashHex = parts[3]!\n const iterations = parseInt(iterationsStr, 10)\n\n const saltBytes = saltHex.match(/.{2}/g)\n if (!saltBytes) return false\n const salt = new Uint8Array(saltBytes.map(byte => parseInt(byte, 16)))\n\n const encoder = new TextEncoder()\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(password),\n 'PBKDF2',\n false,\n ['deriveBits']\n )\n\n const hashBuffer = await crypto.subtle.deriveBits(\n {\n name: 'PBKDF2',\n salt,\n iterations,\n hash: 'SHA-256'\n },\n keyMaterial,\n 256\n )\n\n const actualHashHex = Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('')\n\n // Constant-time comparison\n if (actualHashHex.length !== expectedHashHex.length) return false\n let result = 0\n for (let i = 0; i < actualHashHex.length; i++) {\n result |= actualHashHex.charCodeAt(i) ^ expectedHashHex.charCodeAt(i)\n }\n return result === 0\n }\n\n // Legacy SHA-256 format (no colons in hash)\n const legacyHash = await this.hashPasswordLegacy(password)\n // Constant-time comparison for legacy too\n if (legacyHash.length !== storedHash.length) return false\n let result = 0\n for (let i = 0; i < legacyHash.length; i++) {\n result |= legacyHash.charCodeAt(i) ^ storedHash.charCodeAt(i)\n }\n return result === 0\n }\n\n static isLegacyHash(storedHash: string): boolean {\n return !storedHash.startsWith('pbkdf2:')\n }\n\n /**\n * Set authentication cookie - useful for plugins implementing alternative auth methods\n * @param c - Hono context\n * @param token - JWT token to set in cookie\n * @param options - Optional cookie configuration\n */\n static setAuthCookie(c: Context, token: string, options?: {\n maxAge?: number\n secure?: boolean\n httpOnly?: boolean\n sameSite?: 'Strict' | 'Lax' | 'None'\n }): void {\n setCookie(c, 'auth_token', token, {\n httpOnly: options?.httpOnly ?? true,\n secure: options?.secure ?? true,\n sameSite: options?.sameSite ?? 'Strict',\n maxAge: options?.maxAge ?? (60 * 60 * 24) // 24 hours default\n })\n }\n}\n\n// Middleware to require authentication\nexport const requireAuth = () => {\n return async (c: Context, next: Next) => {\n try {\n // Try to get token from Authorization header\n let token = c.req.header('Authorization')?.replace('Bearer ', '')\n\n // If no header token, try cookie\n if (!token) {\n token = getCookie(c, 'auth_token')\n }\n\n if (!token) {\n // Check if this is a browser request (HTML accept header)\n const acceptHeader = c.req.header('Accept') || ''\n if (acceptHeader.includes('text/html')) {\n return c.redirect('/auth/login?error=Please login to access the admin area')\n }\n return c.json({ error: 'Authentication required' }, 401)\n }\n\n // Try to get cached token verification from KV\n const kv = c.env?.KV\n let payload: JWTPayload | null = null\n\n if (kv) {\n const cacheKey = `auth:${token.substring(0, 20)}` // Use token prefix as key\n const cached = await kv.get(cacheKey, 'json')\n if (cached) {\n payload = cached as JWTPayload\n }\n }\n\n // If not cached, verify token\n if (!payload) {\n const jwtSecret = (c.env as any)?.JWT_SECRET\n payload = await AuthManager.verifyToken(token, jwtSecret)\n\n // Cache the verified payload for 5 minutes\n if (payload && kv) {\n const cacheKey = `auth:${token.substring(0, 20)}`\n await kv.put(cacheKey, JSON.stringify(payload), { expirationTtl: 300 })\n }\n }\n\n if (!payload) {\n // Check if this is a browser request (HTML accept header)\n const acceptHeader = c.req.header('Accept') || ''\n if (acceptHeader.includes('text/html')) {\n return c.redirect('/auth/login?error=Your session has expired, please login again')\n }\n return c.json({ error: 'Invalid or expired token' }, 401)\n }\n\n // Add user info to context\n c.set('user', payload)\n\n return await next()\n } catch (error) {\n console.error('Auth middleware error:', error)\n // Check if this is a browser request (HTML accept header)\n const acceptHeader = c.req.header('Accept') || ''\n if (acceptHeader.includes('text/html')) {\n return c.redirect('/auth/login?error=Authentication failed, please login again')\n }\n return c.json({ error: 'Authentication failed' }, 401)\n }\n }\n}\n\n// Middleware to require specific role\nexport const requireRole = (requiredRole: string | string[]) => {\n return async (c: Context, next: Next) => {\n const user = c.get('user') as JWTPayload\n \n if (!user) {\n // Check if this is a browser request (HTML accept header)\n const acceptHeader = c.req.header('Accept') || ''\n if (acceptHeader.includes('text/html')) {\n return c.redirect('/auth/login?error=Please login to access the admin area')\n }\n return c.json({ error: 'Authentication required' }, 401)\n }\n \n const roles = Array.isArray(requiredRole) ? requiredRole : [requiredRole]\n \n if (!roles.includes(user.role)) {\n // Check if this is a browser request (HTML accept header)\n const acceptHeader = c.req.header('Accept') || ''\n if (acceptHeader.includes('text/html')) {\n return c.redirect('/auth/login?error=You do not have permission to access this area')\n }\n return c.json({ error: 'Insufficient permissions' }, 403)\n }\n \n return await next()\n }\n}\n\n// Optional auth middleware (doesn't block if no token)\nexport const optionalAuth = () => {\n return async (c: Context, next: Next) => {\n try {\n let token = c.req.header('Authorization')?.replace('Bearer ', '')\n \n if (!token) {\n token = getCookie(c, 'auth_token')\n }\n \n if (token) {\n const jwtSecret = (c.env as any)?.JWT_SECRET\n const payload = await AuthManager.verifyToken(token, jwtSecret)\n if (payload) {\n c.set('user', payload)\n }\n }\n \n return await next()\n } catch (error) {\n // Don't block on auth errors in optional auth\n console.error('Optional auth error:', error)\n return await next()\n }\n }\n}\n","import { MiddlewareHandler } from 'hono'\nimport { metricsTracker } from '../utils/metrics'\n\n/**\n * Middleware to track all HTTP requests for real-time analytics\n * Excludes the metrics endpoint itself to avoid inflating the count\n */\nexport const metricsMiddleware = (): MiddlewareHandler => {\n return async (c, next) => {\n const path = new URL(c.req.url).pathname\n\n // Don't track the metrics endpoint itself to avoid self-inflating counts\n if (path !== '/admin/dashboard/api/metrics') {\n metricsTracker.recordRequest()\n }\n\n // Continue with the request\n await next()\n }\n}\n","/**\n * CSRF Protection Middleware — Signed Double-Submit Cookie\n *\n * Stateless CSRF protection for Cloudflare Workers (no session store needed).\n * Token format: `<nonce>.<hmac>` where HMAC-SHA256 is keyed with JWT_SECRET.\n *\n * Flow:\n * GET — ensureCsrfCookie(): reuse existing valid cookie or set a new one\n * POST/PUT/DELETE/PATCH — validate X-CSRF-Token header === csrf_token cookie, HMAC valid\n *\n * Exempt:\n * - Safe methods (GET, HEAD, OPTIONS)\n * - Auth routes that create sessions (/auth/login*, /auth/register*, etc.)\n * - Public form submissions (/forms/*, /api/forms/*) — NOT /admin/forms/*\n * - Requests with no auth_token cookie (Bearer-only or API-key-only)\n */\n\nimport type { Context, Next } from 'hono'\nimport { getCookie, setCookie } from 'hono/cookie'\n\n// Fallback secret — mirrors auth.ts behavior for local dev without wrangler secret\nconst JWT_SECRET_FALLBACK = 'your-super-secret-jwt-key-change-in-production'\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Convert ArrayBuffer to URL-safe base64 (no padding). */\nexport function arrayBufferToBase64Url(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n let binary = ''\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]!)\n }\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\n/** Import a string key for HMAC-SHA256. */\nasync function getHmacKey(secret: string): Promise<CryptoKey> {\n const encoder = new TextEncoder()\n return crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify']\n )\n}\n\n// ============================================================================\n// Token Generation & Validation\n// ============================================================================\n\n/**\n * Generate a signed CSRF token: `<nonce>.<hmac_signature>`\n * - nonce = 32 random bytes, base64url-encoded\n * - signature = HMAC-SHA256(nonce, secret), base64url-encoded\n */\nexport async function generateCsrfToken(secret: string): Promise<string> {\n const nonceBytes = new Uint8Array(32)\n crypto.getRandomValues(nonceBytes)\n const nonce = arrayBufferToBase64Url(nonceBytes.buffer)\n\n const key = await getHmacKey(secret)\n const encoder = new TextEncoder()\n const signatureBuffer = await crypto.subtle.sign('HMAC', key, encoder.encode(nonce))\n const signature = arrayBufferToBase64Url(signatureBuffer)\n\n return `${nonce}.${signature}`\n}\n\n/**\n * Validate a signed CSRF token.\n *\n * Checks that the token has the correct `<nonce>.<signature>` format and that\n * the HMAC signature is valid for the given secret. Uses crypto.subtle.verify\n * which provides constant-time comparison.\n *\n * NOTE: No expiry check here — by design. The security property of signed\n * double-submit comes from the unpredictability of the nonce + the\n * secret-bound HMAC, not from time-bounding. The cookie's maxAge (86400s)\n * handles expiry at the browser level.\n */\nexport async function validateCsrfToken(token: string, secret: string): Promise<boolean> {\n if (!token || typeof token !== 'string') return false\n\n const dotIndex = token.indexOf('.')\n if (dotIndex === -1) return false\n\n const nonce = token.substring(0, dotIndex)\n const signature = token.substring(dotIndex + 1)\n\n if (!nonce || !signature) return false\n\n try {\n const key = await getHmacKey(secret)\n const encoder = new TextEncoder()\n\n // Decode the signature from base64url\n const sigPadded = signature.replace(/-/g, '+').replace(/_/g, '/')\n const sigBinary = atob(sigPadded)\n const sigBytes = new Uint8Array(sigBinary.length)\n for (let i = 0; i < sigBinary.length; i++) {\n sigBytes[i] = sigBinary.charCodeAt(i)\n }\n\n // crypto.subtle.verify is constant-time\n return await crypto.subtle.verify('HMAC', key, sigBytes.buffer, encoder.encode(nonce))\n } catch {\n return false\n }\n}\n\n// ============================================================================\n// Default Exempt Paths\n// ============================================================================\n\nconst DEFAULT_EXEMPT_PATHS = [\n '/auth/login',\n '/auth/register',\n '/auth/seed-admin',\n '/auth/accept-invitation',\n '/auth/reset-password',\n '/auth/request-password-reset',\n]\n\n/**\n * Check whether a request path is exempt from CSRF validation.\n * - Exact match or startsWith for auth routes (e.g. /auth/login/form)\n * - /forms/* and /api/forms/* are exempt (public submissions)\n * - /api/search* is exempt (read-only POST for complex query params)\n * - /admin/forms/* is NOT exempt\n */\nfunction isExemptPath(path: string, extraExemptPaths: string[] = []): boolean {\n // Public form routes — NOT /admin/forms/*\n if (path.startsWith('/forms/') || path.startsWith('/api/forms/') || path === '/forms' || path === '/api/forms') {\n return true\n }\n\n // Search API — read-only POST (includes /api/search/click, /api/search/facet-click)\n if (path.startsWith('/api/search')) {\n return true\n }\n\n const allExempt = [...DEFAULT_EXEMPT_PATHS, ...extraExemptPaths]\n for (const exempt of allExempt) {\n if (path === exempt || path.startsWith(exempt + '/')) {\n return true\n }\n }\n\n return false\n}\n\n// ============================================================================\n// Middleware\n// ============================================================================\n\nexport interface CsrfOptions {\n /** Additional paths to exempt from CSRF validation. */\n exemptPaths?: string[]\n}\n\n/**\n * CSRF protection middleware (Signed Double-Submit Cookie).\n *\n * - GET/HEAD/OPTIONS: ensure a valid csrf_token cookie exists\n * - POST/PUT/DELETE/PATCH: validate X-CSRF-Token header matches cookie, HMAC valid\n * - Exempt: auth routes, public /forms/*, Bearer-only, API-key-only\n */\nexport function csrfProtection(options: CsrfOptions = {}) {\n return async (c: Context, next: Next): Promise<Response | void> => {\n const method = c.req.method.toUpperCase()\n const path = new URL(c.req.url).pathname\n const secret = c.env?.JWT_SECRET || JWT_SECRET_FALLBACK\n\n // Warn if using fallback secret in production\n if (c.env?.ENVIRONMENT === 'production' && !c.env?.JWT_SECRET) {\n console.warn(\n '[CSRF] WARNING: JWT_SECRET is not set in production. ' +\n 'CSRF tokens are signed with the fallback key, which is insecure.'\n )\n }\n\n // Safe methods — just ensure cookie, then pass through\n if (method === 'GET' || method === 'HEAD' || method === 'OPTIONS') {\n await ensureCsrfCookie(c, secret)\n await next()\n return\n }\n\n // Exempt paths — pass through without validation\n if (isExemptPath(path, options.exemptPaths)) {\n await next()\n return\n }\n\n // Bearer-only or API-key-only requests (no auth_token cookie) — exempt\n const authCookie = getCookie(c, 'auth_token')\n if (!authCookie) {\n await next()\n return\n }\n\n // State-changing request with cookie auth — validate CSRF\n const cookieToken = getCookie(c, 'csrf_token')\n let headerToken = c.req.header('X-CSRF-Token')\n\n // Fallback: check _csrf field in form-encoded body (regular HTML form submissions)\n if (!headerToken) {\n const contentType = c.req.header('Content-Type') || ''\n if (contentType.includes('application/x-www-form-urlencoded') || contentType.includes('multipart/form-data')) {\n try {\n const body = await c.req.parseBody()\n headerToken = body['_csrf'] as string | undefined\n } catch {\n // Body not parseable — leave headerToken undefined\n }\n }\n }\n\n if (!cookieToken || !headerToken) {\n return csrfError(c, 'CSRF token missing')\n }\n\n if (cookieToken !== headerToken) {\n return csrfError(c, 'CSRF token mismatch')\n }\n\n const isValid = await validateCsrfToken(cookieToken, secret)\n if (!isValid) {\n return csrfError(c, 'CSRF token invalid')\n }\n\n await next()\n }\n}\n\n/**\n * Ensure a valid CSRF cookie exists. Check-then-reuse: if the existing cookie\n * has a valid HMAC signature, reuse it (no new Set-Cookie header). Only\n * generate a fresh token when the cookie is missing or has an invalid signature.\n */\nasync function ensureCsrfCookie(c: Context, secret: string): Promise<void> {\n const existing = getCookie(c, 'csrf_token')\n\n if (existing) {\n const isValid = await validateCsrfToken(existing, secret)\n if (isValid) {\n // Reuse existing valid token — no Set-Cookie needed\n c.set('csrfToken', existing)\n return\n }\n }\n\n // Generate fresh token\n const token = await generateCsrfToken(secret)\n c.set('csrfToken', token)\n\n const isDev = c.env?.ENVIRONMENT === 'development' || !c.env?.ENVIRONMENT\n setCookie(c, 'csrf_token', token, {\n httpOnly: false, // JS must read this cookie\n secure: !isDev,\n sameSite: 'Strict',\n path: '/',\n maxAge: 86400, // 24 hours — browser-side expiry\n })\n}\n\n/** Return a 403 CSRF error — HTML for browser requests, JSON for API. */\nfunction csrfError(c: Context, message: string): Response {\n const accept = c.req.header('Accept') || ''\n if (accept.includes('text/html')) {\n return c.html(\n `<!DOCTYPE html><html><head><title>403 Forbidden</title></head>` +\n `<body><h1>403 Forbidden</h1><p>${message}</p></body></html>`,\n 403\n )\n }\n return c.json({ error: message, status: 403 }, 403)\n}\n","import { Context, Next } from 'hono'\n\ninterface RateLimitOptions {\n max: number\n windowMs: number\n keyPrefix: string\n}\n\ninterface RateLimitEntry {\n count: number\n resetAt: number\n}\n\n/**\n * KV-based sliding window rate limiter middleware.\n * Gracefully skips if CACHE_KV binding is not available.\n */\nexport function rateLimit(options: RateLimitOptions) {\n const { max, windowMs, keyPrefix } = options\n\n return async (c: Context, next: Next) => {\n const kv = (c.env as any)?.CACHE_KV\n if (!kv) {\n // No KV binding available — skip rate limiting\n return await next()\n }\n\n const ip = c.req.header('cf-connecting-ip') || c.req.header('x-forwarded-for') || 'unknown'\n const key = `ratelimit:${keyPrefix}:${ip}`\n\n try {\n const now = Date.now()\n const stored = await kv.get(key, 'json') as RateLimitEntry | null\n\n let entry: RateLimitEntry\n if (stored && stored.resetAt > now) {\n entry = stored\n } else {\n entry = { count: 0, resetAt: now + windowMs }\n }\n\n entry.count++\n\n // Calculate TTL in seconds (KV expiration)\n const ttlSeconds = Math.ceil((entry.resetAt - now) / 1000)\n\n if (entry.count > max) {\n // Store the updated count even when rejecting\n await kv.put(key, JSON.stringify(entry), { expirationTtl: Math.max(ttlSeconds, 60) })\n\n const retryAfter = Math.ceil((entry.resetAt - now) / 1000)\n c.header('Retry-After', String(retryAfter))\n c.header('X-RateLimit-Limit', String(max))\n c.header('X-RateLimit-Remaining', '0')\n c.header('X-RateLimit-Reset', String(Math.ceil(entry.resetAt / 1000)))\n return c.json({ error: 'Too many requests. Please try again later.' }, 429)\n }\n\n await kv.put(key, JSON.stringify(entry), { expirationTtl: Math.max(ttlSeconds, 60) })\n\n c.header('X-RateLimit-Limit', String(max))\n c.header('X-RateLimit-Remaining', String(max - entry.count))\n c.header('X-RateLimit-Reset', String(Math.ceil(entry.resetAt / 1000)))\n\n return await next()\n } catch (error) {\n // Rate limiting should never break the app\n console.error('Rate limiter error (non-fatal):', error)\n return await next()\n }\n }\n}\n","import { Context, Next } from 'hono'\n\n/**\n * Security headers middleware.\n * Sets standard security headers on every response.\n * Skips HSTS in development to avoid local dev issues.\n */\nexport const securityHeadersMiddleware = () => {\n return async (c: Context, next: Next) => {\n await next()\n\n c.header('X-Content-Type-Options', 'nosniff')\n c.header('X-Frame-Options', 'SAMEORIGIN')\n c.header('Referrer-Policy', 'strict-origin-when-cross-origin')\n c.header('Permissions-Policy', 'camera=(), microphone=(), geolocation=()')\n\n // Only set HSTS in non-development environments\n const environment = (c.env as any)?.ENVIRONMENT\n if (environment !== 'development') {\n c.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains')\n }\n }\n}\n","/**\n * Middleware Module Exports\n *\n * Request processing middleware for SonicJS\n *\n * Note: Most middleware is currently in the monolith and will be migrated later.\n * For now, we only export the bootstrap middleware which is used for system initialization.\n */\n\n// Bootstrap middleware\nexport { bootstrapMiddleware, verifySecurityConfig } from './bootstrap'\n\n// Auth middleware\nexport { AuthManager, requireAuth, requireRole, optionalAuth } from './auth'\n\n// Metrics middleware\nexport { metricsMiddleware } from './metrics'\n\n// CSRF protection middleware\nexport { csrfProtection, generateCsrfToken, validateCsrfToken } from './csrf'\n\n// Rate limiting middleware\nexport { rateLimit } from './rate-limit'\n\n// Re-export types and functions that are referenced but implemented in monolith\n// These are placeholder exports to maintain API compatibility\nexport type Permission = string\nexport type UserPermissions = {\n userId: string\n permissions: Permission[]\n}\n\n// Middleware stubs - these return pass-through middleware that call next()\nexport const loggingMiddleware: any = () => async (_c: any, next: any) => await next()\nexport const detailedLoggingMiddleware: any = () => async (_c: any, next: any) => await next()\nexport const securityLoggingMiddleware: any = () => async (_c: any, next: any) => await next()\nexport const performanceLoggingMiddleware: any = () => async (_c: any, next: any) => await next()\nexport const cacheHeaders: any = () => async (_c: any, next: any) => await next()\nexport const compressionMiddleware: any = async (_c: any, next: any) => await next()\nexport { securityHeadersMiddleware as securityHeaders } from './security-headers'\n\n// Other stubs\nexport const PermissionManager: any = {}\nexport const requirePermission: any = () => async (_c: any, next: any) => await next()\nexport const requireAnyPermission: any = () => async (_c: any, next: any) => await next()\nexport const logActivity: any = () => {}\nexport const requireActivePlugin: any = () => async (_c: any, next: any) => await next()\nexport const requireActivePlugins: any = () => async (_c: any, next: any) => await next()\nexport const getActivePlugins: any = () => []\nexport const isPluginActive: any = () => false\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/middleware/bootstrap.ts","../src/middleware/auth.ts","../src/middleware/metrics.ts","../src/middleware/csrf.ts","../src/middleware/rate-limit.ts","../src/middleware/security-headers.ts","../src/middleware/index.ts"],"names":["result","JWT_SECRET_FALLBACK","getCookie","setCookie"],"mappings":"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","file":"chunk-2BL2A62D.js","sourcesContent":["import { Context, Next } from \"hono\";\nimport { syncCollections } from \"../services/collection-sync\";\nimport { syncAllFormCollections } from \"../services/form-collection-sync\";\nimport { MigrationService } from \"../services/migrations\";\nimport { PluginBootstrapService } from \"../services/plugin-bootstrap\";\nimport type { SonicJSConfig } from \"../app\";\n\ntype Bindings = {\n DB: D1Database;\n KV: KVNamespace;\n JWT_SECRET?: string;\n CORS_ORIGINS?: string;\n ENVIRONMENT?: string;\n};\n\n// Track if bootstrap has been run in this worker instance\nlet bootstrapComplete = false;\n\n/**\n * Verify security-critical environment configuration at startup.\n * Logs warnings in development, throws in production to prevent\n * insecure deployments from silently running.\n */\nexport function verifySecurityConfig(env: Bindings): void {\n const warnings: string[] = [];\n\n // Check JWT secret\n if (!env.JWT_SECRET) {\n warnings.push(\n \"JWT_SECRET is not set — using hardcoded fallback. Set via `wrangler secret put JWT_SECRET`\"\n );\n } else if (env.JWT_SECRET.includes(\"change-in-production\")) {\n warnings.push(\n \"JWT_SECRET contains the default value — tokens are forgeable. Generate a strong random secret\"\n );\n }\n\n // Check CORS origins\n if (!env.CORS_ORIGINS) {\n warnings.push(\n \"CORS_ORIGINS is not set — all cross-origin API requests will be rejected\"\n );\n }\n\n // Check environment designation\n if (!env.ENVIRONMENT) {\n warnings.push(\n \"ENVIRONMENT is not set — HSTS header will not be applied. Set to \\\"production\\\" or \\\"development\\\"\"\n );\n }\n\n if (warnings.length === 0) {\n return;\n }\n\n const isProduction = env.ENVIRONMENT === \"production\";\n\n for (const warning of warnings) {\n console.warn(`[SonicJS Security] ${warning}`);\n }\n\n if (isProduction) {\n // In production, a missing or default JWT_SECRET is a hard failure —\n // every token issued would be forgeable by anyone reading the source code.\n const hasCritical =\n !env.JWT_SECRET || env.JWT_SECRET.includes(\"change-in-production\");\n if (hasCritical) {\n throw new Error(\n \"[SonicJS Security] CRITICAL: Production deployment is missing a secure JWT_SECRET. \" +\n \"Set it via `wrangler secret put JWT_SECRET` before deploying.\"\n );\n }\n }\n}\n\n/**\n * Bootstrap middleware that ensures system initialization\n * Runs once per worker instance\n */\nexport function bootstrapMiddleware(config: SonicJSConfig = {}) {\n return async (c: Context<{ Bindings: Bindings }>, next: Next) => {\n // Skip if already bootstrapped in this worker instance\n if (bootstrapComplete) {\n return next();\n }\n\n // Skip bootstrap for static assets and health checks\n const path = c.req.path;\n if (\n path.startsWith(\"/images/\") ||\n path.startsWith(\"/assets/\") ||\n path === \"/health\" ||\n path.endsWith(\".js\") ||\n path.endsWith(\".css\") ||\n path.endsWith(\".png\") ||\n path.endsWith(\".jpg\") ||\n path.endsWith(\".ico\")\n ) {\n return next();\n }\n\n try {\n console.log(\"[Bootstrap] Starting system initialization...\");\n\n // 1. Run database migrations first\n console.log(\"[Bootstrap] Running database migrations...\");\n const migrationService = new MigrationService(c.env.DB);\n await migrationService.runPendingMigrations();\n\n // 2. Sync collection configurations\n console.log(\"[Bootstrap] Syncing collection configurations...\");\n try {\n await syncCollections(c.env.DB);\n } catch (error) {\n console.error(\"[Bootstrap] Error syncing collections:\", error);\n // Continue bootstrap even if collection sync fails\n }\n\n // 2b. Sync form-derived shadow collections\n console.log(\"[Bootstrap] Syncing form collections...\");\n try {\n await syncAllFormCollections(c.env.DB);\n } catch (error) {\n console.error(\"[Bootstrap] Error syncing form collections:\", error);\n }\n\n // 3. Bootstrap core plugins (unless disableAll is set)\n if (!config.plugins?.disableAll) {\n console.log(\"[Bootstrap] Bootstrapping core plugins...\");\n const bootstrapService = new PluginBootstrapService(c.env.DB);\n\n // Check if bootstrap is needed\n const needsBootstrap = await bootstrapService.isBootstrapNeeded();\n if (needsBootstrap) {\n await bootstrapService.bootstrapCorePlugins();\n }\n } else {\n console.log(\"[Bootstrap] Plugin bootstrap skipped (disableAll is true)\");\n }\n\n // Mark bootstrap as complete for this worker instance\n bootstrapComplete = true;\n console.log(\"[Bootstrap] System initialization completed\");\n } catch (error) {\n console.error(\"[Bootstrap] Error during system initialization:\", error);\n // Don't prevent the app from starting, but log the error\n }\n\n // 4. Verify security configuration (outside try/catch so critical\n // errors in production propagate and prevent insecure deployments)\n verifySecurityConfig(c.env as Bindings);\n\n return next();\n };\n}\n\n/**\n * Reset bootstrap flag (useful for testing)\n */\nexport function resetBootstrap() {\n bootstrapComplete = false;\n}\n","import { sign, verify } from 'hono/jwt'\nimport { Context, Next } from 'hono'\nimport { getCookie, setCookie } from 'hono/cookie'\n\ntype JWTPayload = {\n userId: string\n email: string\n role: string\n exp: number\n iat: number\n}\n\n// Fallback JWT secret for local development only (no wrangler secret set)\nconst JWT_SECRET_FALLBACK = 'your-super-secret-jwt-key-change-in-production'\n\nexport class AuthManager {\n static async generateToken(userId: string, email: string, role: string, secret?: string): Promise<string> {\n const payload: JWTPayload = {\n userId,\n email,\n role,\n exp: Math.floor(Date.now() / 1000) + (60 * 60 * 24), // 24 hours\n iat: Math.floor(Date.now() / 1000)\n }\n\n return await sign(payload, secret || JWT_SECRET_FALLBACK, 'HS256')\n }\n\n static async verifyToken(token: string, secret?: string): Promise<JWTPayload | null> {\n try {\n const payload = await verify(token, secret || JWT_SECRET_FALLBACK, 'HS256') as JWTPayload\n \n // Check if token is expired\n if (payload.exp < Math.floor(Date.now() / 1000)) {\n return null\n }\n \n return payload\n } catch (error) {\n console.error('Token verification failed:', error)\n return null\n }\n }\n\n static async hashPassword(password: string): Promise<string> {\n const iterations = 100000\n const salt = new Uint8Array(16)\n crypto.getRandomValues(salt)\n\n const encoder = new TextEncoder()\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(password),\n 'PBKDF2',\n false,\n ['deriveBits']\n )\n\n const hashBuffer = await crypto.subtle.deriveBits(\n {\n name: 'PBKDF2',\n salt,\n iterations,\n hash: 'SHA-256'\n },\n keyMaterial,\n 256\n )\n\n const saltHex = Array.from(salt).map(b => b.toString(16).padStart(2, '0')).join('')\n const hashHex = Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('')\n\n return `pbkdf2:${iterations}:${saltHex}:${hashHex}`\n }\n\n static async hashPasswordLegacy(password: string): Promise<string> {\n const encoder = new TextEncoder()\n const data = encoder.encode(password + 'salt-change-in-production')\n const hashBuffer = await crypto.subtle.digest('SHA-256', data)\n const hashArray = Array.from(new Uint8Array(hashBuffer))\n return hashArray.map(b => b.toString(16).padStart(2, '0')).join('')\n }\n\n static async verifyPassword(password: string, storedHash: string): Promise<boolean> {\n if (storedHash.startsWith('pbkdf2:')) {\n // PBKDF2 format: pbkdf2:<iterations>:<salt_hex>:<hash_hex>\n const parts = storedHash.split(':')\n if (parts.length !== 4) return false\n\n const iterationsStr = parts[1]!\n const saltHex = parts[2]!\n const expectedHashHex = parts[3]!\n const iterations = parseInt(iterationsStr, 10)\n\n const saltBytes = saltHex.match(/.{2}/g)\n if (!saltBytes) return false\n const salt = new Uint8Array(saltBytes.map(byte => parseInt(byte, 16)))\n\n const encoder = new TextEncoder()\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(password),\n 'PBKDF2',\n false,\n ['deriveBits']\n )\n\n const hashBuffer = await crypto.subtle.deriveBits(\n {\n name: 'PBKDF2',\n salt,\n iterations,\n hash: 'SHA-256'\n },\n keyMaterial,\n 256\n )\n\n const actualHashHex = Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('')\n\n // Constant-time comparison\n if (actualHashHex.length !== expectedHashHex.length) return false\n let result = 0\n for (let i = 0; i < actualHashHex.length; i++) {\n result |= actualHashHex.charCodeAt(i) ^ expectedHashHex.charCodeAt(i)\n }\n return result === 0\n }\n\n // Legacy SHA-256 format (no colons in hash)\n const legacyHash = await this.hashPasswordLegacy(password)\n // Constant-time comparison for legacy too\n if (legacyHash.length !== storedHash.length) return false\n let result = 0\n for (let i = 0; i < legacyHash.length; i++) {\n result |= legacyHash.charCodeAt(i) ^ storedHash.charCodeAt(i)\n }\n return result === 0\n }\n\n static isLegacyHash(storedHash: string): boolean {\n return !storedHash.startsWith('pbkdf2:')\n }\n\n /**\n * Set authentication cookie - useful for plugins implementing alternative auth methods\n * @param c - Hono context\n * @param token - JWT token to set in cookie\n * @param options - Optional cookie configuration\n */\n static setAuthCookie(c: Context, token: string, options?: {\n maxAge?: number\n secure?: boolean\n httpOnly?: boolean\n sameSite?: 'Strict' | 'Lax' | 'None'\n }): void {\n setCookie(c, 'auth_token', token, {\n httpOnly: options?.httpOnly ?? true,\n secure: options?.secure ?? true,\n sameSite: options?.sameSite ?? 'Strict',\n maxAge: options?.maxAge ?? (60 * 60 * 24) // 24 hours default\n })\n }\n}\n\n// Middleware to require authentication\nexport const requireAuth = () => {\n return async (c: Context, next: Next) => {\n try {\n // Try to get token from Authorization header\n let token = c.req.header('Authorization')?.replace('Bearer ', '')\n\n // If no header token, try cookie\n if (!token) {\n token = getCookie(c, 'auth_token')\n }\n\n if (!token) {\n // Check if this is a browser request (HTML accept header)\n const acceptHeader = c.req.header('Accept') || ''\n if (acceptHeader.includes('text/html')) {\n return c.redirect('/auth/login?error=Please login to access the admin area')\n }\n return c.json({ error: 'Authentication required' }, 401)\n }\n\n // Try to get cached token verification from KV\n const kv = c.env?.KV\n let payload: JWTPayload | null = null\n\n if (kv) {\n const cacheKey = `auth:${token.substring(0, 20)}` // Use token prefix as key\n const cached = await kv.get(cacheKey, 'json')\n if (cached) {\n payload = cached as JWTPayload\n }\n }\n\n // If not cached, verify token\n if (!payload) {\n const jwtSecret = (c.env as any)?.JWT_SECRET\n payload = await AuthManager.verifyToken(token, jwtSecret)\n\n // Cache the verified payload for 5 minutes\n if (payload && kv) {\n const cacheKey = `auth:${token.substring(0, 20)}`\n await kv.put(cacheKey, JSON.stringify(payload), { expirationTtl: 300 })\n }\n }\n\n if (!payload) {\n // Check if this is a browser request (HTML accept header)\n const acceptHeader = c.req.header('Accept') || ''\n if (acceptHeader.includes('text/html')) {\n return c.redirect('/auth/login?error=Your session has expired, please login again')\n }\n return c.json({ error: 'Invalid or expired token' }, 401)\n }\n\n // Add user info to context\n c.set('user', payload)\n\n return await next()\n } catch (error) {\n console.error('Auth middleware error:', error)\n // Check if this is a browser request (HTML accept header)\n const acceptHeader = c.req.header('Accept') || ''\n if (acceptHeader.includes('text/html')) {\n return c.redirect('/auth/login?error=Authentication failed, please login again')\n }\n return c.json({ error: 'Authentication failed' }, 401)\n }\n }\n}\n\n// Middleware to require specific role\nexport const requireRole = (requiredRole: string | string[]) => {\n return async (c: Context, next: Next) => {\n const user = c.get('user') as JWTPayload\n \n if (!user) {\n // Check if this is a browser request (HTML accept header)\n const acceptHeader = c.req.header('Accept') || ''\n if (acceptHeader.includes('text/html')) {\n return c.redirect('/auth/login?error=Please login to access the admin area')\n }\n return c.json({ error: 'Authentication required' }, 401)\n }\n \n const roles = Array.isArray(requiredRole) ? requiredRole : [requiredRole]\n \n if (!roles.includes(user.role)) {\n // Check if this is a browser request (HTML accept header)\n const acceptHeader = c.req.header('Accept') || ''\n if (acceptHeader.includes('text/html')) {\n return c.redirect('/auth/login?error=You do not have permission to access this area')\n }\n return c.json({ error: 'Insufficient permissions' }, 403)\n }\n \n return await next()\n }\n}\n\n// Optional auth middleware (doesn't block if no token)\nexport const optionalAuth = () => {\n return async (c: Context, next: Next) => {\n try {\n let token = c.req.header('Authorization')?.replace('Bearer ', '')\n \n if (!token) {\n token = getCookie(c, 'auth_token')\n }\n \n if (token) {\n const jwtSecret = (c.env as any)?.JWT_SECRET\n const payload = await AuthManager.verifyToken(token, jwtSecret)\n if (payload) {\n c.set('user', payload)\n }\n }\n \n return await next()\n } catch (error) {\n // Don't block on auth errors in optional auth\n console.error('Optional auth error:', error)\n return await next()\n }\n }\n}\n","import { MiddlewareHandler } from 'hono'\nimport { metricsTracker } from '../utils/metrics'\n\n/**\n * Middleware to track all HTTP requests for real-time analytics\n * Excludes the metrics endpoint itself to avoid inflating the count\n */\nexport const metricsMiddleware = (): MiddlewareHandler => {\n return async (c, next) => {\n const path = new URL(c.req.url).pathname\n\n // Don't track the metrics endpoint itself to avoid self-inflating counts\n if (path !== '/admin/dashboard/api/metrics') {\n metricsTracker.recordRequest()\n }\n\n // Continue with the request\n await next()\n }\n}\n","/**\n * CSRF Protection Middleware — Signed Double-Submit Cookie\n *\n * Stateless CSRF protection for Cloudflare Workers (no session store needed).\n * Token format: `<nonce>.<hmac>` where HMAC-SHA256 is keyed with JWT_SECRET.\n *\n * Flow:\n * GET — ensureCsrfCookie(): reuse existing valid cookie or set a new one\n * POST/PUT/DELETE/PATCH — validate X-CSRF-Token header === csrf_token cookie, HMAC valid\n *\n * Exempt:\n * - Safe methods (GET, HEAD, OPTIONS)\n * - Auth routes that create sessions (/auth/login*, /auth/register*, etc.)\n * - Public form submissions (/forms/*, /api/forms/*) — NOT /admin/forms/*\n * - Requests with no auth_token cookie (Bearer-only or API-key-only)\n */\n\nimport type { Context, Next } from 'hono'\nimport { getCookie, setCookie } from 'hono/cookie'\n\n// Fallback secret — mirrors auth.ts behavior for local dev without wrangler secret\nconst JWT_SECRET_FALLBACK = 'your-super-secret-jwt-key-change-in-production'\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Convert ArrayBuffer to URL-safe base64 (no padding). */\nexport function arrayBufferToBase64Url(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n let binary = ''\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]!)\n }\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\n/** Import a string key for HMAC-SHA256. */\nasync function getHmacKey(secret: string): Promise<CryptoKey> {\n const encoder = new TextEncoder()\n return crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify']\n )\n}\n\n// ============================================================================\n// Token Generation & Validation\n// ============================================================================\n\n/**\n * Generate a signed CSRF token: `<nonce>.<hmac_signature>`\n * - nonce = 32 random bytes, base64url-encoded\n * - signature = HMAC-SHA256(nonce, secret), base64url-encoded\n */\nexport async function generateCsrfToken(secret: string): Promise<string> {\n const nonceBytes = new Uint8Array(32)\n crypto.getRandomValues(nonceBytes)\n const nonce = arrayBufferToBase64Url(nonceBytes.buffer)\n\n const key = await getHmacKey(secret)\n const encoder = new TextEncoder()\n const signatureBuffer = await crypto.subtle.sign('HMAC', key, encoder.encode(nonce))\n const signature = arrayBufferToBase64Url(signatureBuffer)\n\n return `${nonce}.${signature}`\n}\n\n/**\n * Validate a signed CSRF token.\n *\n * Checks that the token has the correct `<nonce>.<signature>` format and that\n * the HMAC signature is valid for the given secret. Uses crypto.subtle.verify\n * which provides constant-time comparison.\n *\n * NOTE: No expiry check here — by design. The security property of signed\n * double-submit comes from the unpredictability of the nonce + the\n * secret-bound HMAC, not from time-bounding. The cookie's maxAge (86400s)\n * handles expiry at the browser level.\n */\nexport async function validateCsrfToken(token: string, secret: string): Promise<boolean> {\n if (!token || typeof token !== 'string') return false\n\n const dotIndex = token.indexOf('.')\n if (dotIndex === -1) return false\n\n const nonce = token.substring(0, dotIndex)\n const signature = token.substring(dotIndex + 1)\n\n if (!nonce || !signature) return false\n\n try {\n const key = await getHmacKey(secret)\n const encoder = new TextEncoder()\n\n // Decode the signature from base64url\n const sigPadded = signature.replace(/-/g, '+').replace(/_/g, '/')\n const sigBinary = atob(sigPadded)\n const sigBytes = new Uint8Array(sigBinary.length)\n for (let i = 0; i < sigBinary.length; i++) {\n sigBytes[i] = sigBinary.charCodeAt(i)\n }\n\n // crypto.subtle.verify is constant-time\n return await crypto.subtle.verify('HMAC', key, sigBytes.buffer, encoder.encode(nonce))\n } catch {\n return false\n }\n}\n\n// ============================================================================\n// Default Exempt Paths\n// ============================================================================\n\nconst DEFAULT_EXEMPT_PATHS = [\n '/auth/login',\n '/auth/register',\n '/auth/seed-admin',\n '/auth/accept-invitation',\n '/auth/reset-password',\n '/auth/request-password-reset',\n]\n\n/**\n * Check whether a request path is exempt from CSRF validation.\n * - Exact match or startsWith for auth routes (e.g. /auth/login/form)\n * - /forms/* and /api/forms/* are exempt (public submissions)\n * - /api/search* is exempt (read-only POST for complex query params)\n * - /admin/forms/* is NOT exempt\n */\nfunction isExemptPath(path: string, extraExemptPaths: string[] = []): boolean {\n // Public form routes — NOT /admin/forms/*\n if (path.startsWith('/forms/') || path.startsWith('/api/forms/') || path === '/forms' || path === '/api/forms') {\n return true\n }\n\n // Search API — read-only POST (includes /api/search/click, /api/search/facet-click)\n if (path.startsWith('/api/search')) {\n return true\n }\n\n const allExempt = [...DEFAULT_EXEMPT_PATHS, ...extraExemptPaths]\n for (const exempt of allExempt) {\n if (path === exempt || path.startsWith(exempt + '/')) {\n return true\n }\n }\n\n return false\n}\n\n// ============================================================================\n// Middleware\n// ============================================================================\n\nexport interface CsrfOptions {\n /** Additional paths to exempt from CSRF validation. */\n exemptPaths?: string[]\n}\n\n/**\n * CSRF protection middleware (Signed Double-Submit Cookie).\n *\n * - GET/HEAD/OPTIONS: ensure a valid csrf_token cookie exists\n * - POST/PUT/DELETE/PATCH: validate X-CSRF-Token header matches cookie, HMAC valid\n * - Exempt: auth routes, public /forms/*, Bearer-only, API-key-only\n */\nexport function csrfProtection(options: CsrfOptions = {}) {\n return async (c: Context, next: Next): Promise<Response | void> => {\n const method = c.req.method.toUpperCase()\n const path = new URL(c.req.url).pathname\n const secret = c.env?.JWT_SECRET || JWT_SECRET_FALLBACK\n\n // Warn if using fallback secret in production\n if (c.env?.ENVIRONMENT === 'production' && !c.env?.JWT_SECRET) {\n console.warn(\n '[CSRF] WARNING: JWT_SECRET is not set in production. ' +\n 'CSRF tokens are signed with the fallback key, which is insecure.'\n )\n }\n\n // Safe methods — just ensure cookie, then pass through\n if (method === 'GET' || method === 'HEAD' || method === 'OPTIONS') {\n await ensureCsrfCookie(c, secret)\n await next()\n return\n }\n\n // Exempt paths — pass through without validation\n if (isExemptPath(path, options.exemptPaths)) {\n await next()\n return\n }\n\n // Bearer-only or API-key-only requests (no auth_token cookie) — exempt\n const authCookie = getCookie(c, 'auth_token')\n if (!authCookie) {\n await next()\n return\n }\n\n // State-changing request with cookie auth — validate CSRF\n const cookieToken = getCookie(c, 'csrf_token')\n let headerToken = c.req.header('X-CSRF-Token')\n\n // Fallback: check _csrf field in form-encoded body (regular HTML form submissions)\n if (!headerToken) {\n const contentType = c.req.header('Content-Type') || ''\n if (contentType.includes('application/x-www-form-urlencoded') || contentType.includes('multipart/form-data')) {\n try {\n const body = await c.req.parseBody()\n headerToken = body['_csrf'] as string | undefined\n } catch {\n // Body not parseable — leave headerToken undefined\n }\n }\n }\n\n if (!cookieToken || !headerToken) {\n return csrfError(c, 'CSRF token missing')\n }\n\n if (cookieToken !== headerToken) {\n return csrfError(c, 'CSRF token mismatch')\n }\n\n const isValid = await validateCsrfToken(cookieToken, secret)\n if (!isValid) {\n return csrfError(c, 'CSRF token invalid')\n }\n\n await next()\n }\n}\n\n/**\n * Ensure a valid CSRF cookie exists. Check-then-reuse: if the existing cookie\n * has a valid HMAC signature, reuse it (no new Set-Cookie header). Only\n * generate a fresh token when the cookie is missing or has an invalid signature.\n */\nasync function ensureCsrfCookie(c: Context, secret: string): Promise<void> {\n const existing = getCookie(c, 'csrf_token')\n\n if (existing) {\n const isValid = await validateCsrfToken(existing, secret)\n if (isValid) {\n // Reuse existing valid token — no Set-Cookie needed\n c.set('csrfToken', existing)\n return\n }\n }\n\n // Generate fresh token\n const token = await generateCsrfToken(secret)\n c.set('csrfToken', token)\n\n const isDev = c.env?.ENVIRONMENT === 'development' || !c.env?.ENVIRONMENT\n setCookie(c, 'csrf_token', token, {\n httpOnly: false, // JS must read this cookie\n secure: !isDev,\n sameSite: 'Strict',\n path: '/',\n maxAge: 86400, // 24 hours — browser-side expiry\n })\n}\n\n/** Return a 403 CSRF error — HTML for browser requests, JSON for API. */\nfunction csrfError(c: Context, message: string): Response {\n const accept = c.req.header('Accept') || ''\n if (accept.includes('text/html')) {\n return c.html(\n `<!DOCTYPE html><html><head><title>403 Forbidden</title></head>` +\n `<body><h1>403 Forbidden</h1><p>${message}</p></body></html>`,\n 403\n )\n }\n return c.json({ error: message, status: 403 }, 403)\n}\n","import { Context, Next } from 'hono'\n\ninterface RateLimitOptions {\n max: number\n windowMs: number\n keyPrefix: string\n}\n\ninterface RateLimitEntry {\n count: number\n resetAt: number\n}\n\n/**\n * KV-based sliding window rate limiter middleware.\n * Gracefully skips if CACHE_KV binding is not available.\n */\nexport function rateLimit(options: RateLimitOptions) {\n const { max, windowMs, keyPrefix } = options\n\n return async (c: Context, next: Next) => {\n const kv = (c.env as any)?.CACHE_KV\n if (!kv) {\n // No KV binding available — skip rate limiting\n return await next()\n }\n\n const ip = c.req.header('cf-connecting-ip') || c.req.header('x-forwarded-for') || 'unknown'\n const key = `ratelimit:${keyPrefix}:${ip}`\n\n try {\n const now = Date.now()\n const stored = await kv.get(key, 'json') as RateLimitEntry | null\n\n let entry: RateLimitEntry\n if (stored && stored.resetAt > now) {\n entry = stored\n } else {\n entry = { count: 0, resetAt: now + windowMs }\n }\n\n entry.count++\n\n // Calculate TTL in seconds (KV expiration)\n const ttlSeconds = Math.ceil((entry.resetAt - now) / 1000)\n\n if (entry.count > max) {\n // Store the updated count even when rejecting\n await kv.put(key, JSON.stringify(entry), { expirationTtl: Math.max(ttlSeconds, 60) })\n\n const retryAfter = Math.ceil((entry.resetAt - now) / 1000)\n c.header('Retry-After', String(retryAfter))\n c.header('X-RateLimit-Limit', String(max))\n c.header('X-RateLimit-Remaining', '0')\n c.header('X-RateLimit-Reset', String(Math.ceil(entry.resetAt / 1000)))\n return c.json({ error: 'Too many requests. Please try again later.' }, 429)\n }\n\n await kv.put(key, JSON.stringify(entry), { expirationTtl: Math.max(ttlSeconds, 60) })\n\n c.header('X-RateLimit-Limit', String(max))\n c.header('X-RateLimit-Remaining', String(max - entry.count))\n c.header('X-RateLimit-Reset', String(Math.ceil(entry.resetAt / 1000)))\n\n return await next()\n } catch (error) {\n // Rate limiting should never break the app\n console.error('Rate limiter error (non-fatal):', error)\n return await next()\n }\n }\n}\n","import { Context, Next } from 'hono'\n\n/**\n * Security headers middleware.\n * Sets standard security headers on every response.\n * Skips HSTS in development to avoid local dev issues.\n */\nexport const securityHeadersMiddleware = () => {\n return async (c: Context, next: Next) => {\n await next()\n\n c.header('X-Content-Type-Options', 'nosniff')\n c.header('X-Frame-Options', 'SAMEORIGIN')\n c.header('Referrer-Policy', 'strict-origin-when-cross-origin')\n c.header('Permissions-Policy', 'camera=(), microphone=(), geolocation=()')\n\n // Only set HSTS in non-development environments\n const environment = (c.env as any)?.ENVIRONMENT\n if (environment !== 'development') {\n c.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains')\n }\n }\n}\n","/**\n * Middleware Module Exports\n *\n * Request processing middleware for SonicJS\n *\n * Note: Most middleware is currently in the monolith and will be migrated later.\n * For now, we only export the bootstrap middleware which is used for system initialization.\n */\n\n// Bootstrap middleware\nexport { bootstrapMiddleware, verifySecurityConfig } from './bootstrap'\n\n// Auth middleware\nexport { AuthManager, requireAuth, requireRole, optionalAuth } from './auth'\n\n// Metrics middleware\nexport { metricsMiddleware } from './metrics'\n\n// CSRF protection middleware\nexport { csrfProtection, generateCsrfToken, validateCsrfToken } from './csrf'\n\n// Rate limiting middleware\nexport { rateLimit } from './rate-limit'\n\n// Re-export types and functions that are referenced but implemented in monolith\n// These are placeholder exports to maintain API compatibility\nexport type Permission = string\nexport type UserPermissions = {\n userId: string\n permissions: Permission[]\n}\n\n// Middleware stubs - these return pass-through middleware that call next()\nexport const loggingMiddleware: any = () => async (_c: any, next: any) => await next()\nexport const detailedLoggingMiddleware: any = () => async (_c: any, next: any) => await next()\nexport const securityLoggingMiddleware: any = () => async (_c: any, next: any) => await next()\nexport const performanceLoggingMiddleware: any = () => async (_c: any, next: any) => await next()\nexport const cacheHeaders: any = () => async (_c: any, next: any) => await next()\nexport const compressionMiddleware: any = async (_c: any, next: any) => await next()\nexport { securityHeadersMiddleware as securityHeaders } from './security-headers'\n\n// Other stubs\nexport const PermissionManager: any = {}\nexport const requirePermission: any = () => async (_c: any, next: any) => await next()\nexport const requireAnyPermission: any = () => async (_c: any, next: any) => await next()\nexport const logActivity: any = () => {}\nexport const requireActivePlugin: any = () => async (_c: any, next: any) => await next()\nexport const requireActivePlugins: any = () => async (_c: any, next: any) => await next()\nexport const getActivePlugins: any = () => []\nexport const isPluginActive: any = () => false\n"]}
|