@sigil-security/runtime 0.0.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.
Files changed (48) hide show
  1. package/LICENSE +201 -0
  2. package/dist/adapters/elysia.cjs +307 -0
  3. package/dist/adapters/elysia.cjs.map +1 -0
  4. package/dist/adapters/elysia.d.cts +41 -0
  5. package/dist/adapters/elysia.d.ts +41 -0
  6. package/dist/adapters/elysia.js +98 -0
  7. package/dist/adapters/elysia.js.map +1 -0
  8. package/dist/adapters/express.cjs +286 -0
  9. package/dist/adapters/express.cjs.map +1 -0
  10. package/dist/adapters/express.d.cts +59 -0
  11. package/dist/adapters/express.d.ts +59 -0
  12. package/dist/adapters/express.js +77 -0
  13. package/dist/adapters/express.js.map +1 -0
  14. package/dist/adapters/fastify.cjs +308 -0
  15. package/dist/adapters/fastify.cjs.map +1 -0
  16. package/dist/adapters/fastify.d.cts +54 -0
  17. package/dist/adapters/fastify.d.ts +54 -0
  18. package/dist/adapters/fastify.js +99 -0
  19. package/dist/adapters/fastify.js.map +1 -0
  20. package/dist/adapters/fetch.cjs +359 -0
  21. package/dist/adapters/fetch.cjs.map +1 -0
  22. package/dist/adapters/fetch.d.cts +46 -0
  23. package/dist/adapters/fetch.d.ts +46 -0
  24. package/dist/adapters/fetch.js +149 -0
  25. package/dist/adapters/fetch.js.map +1 -0
  26. package/dist/adapters/hono.cjs +300 -0
  27. package/dist/adapters/hono.cjs.map +1 -0
  28. package/dist/adapters/hono.d.cts +41 -0
  29. package/dist/adapters/hono.d.ts +41 -0
  30. package/dist/adapters/hono.js +91 -0
  31. package/dist/adapters/hono.js.map +1 -0
  32. package/dist/adapters/oak.cjs +318 -0
  33. package/dist/adapters/oak.cjs.map +1 -0
  34. package/dist/adapters/oak.d.cts +48 -0
  35. package/dist/adapters/oak.d.ts +48 -0
  36. package/dist/adapters/oak.js +109 -0
  37. package/dist/adapters/oak.js.map +1 -0
  38. package/dist/chunk-JPT5I5W5.js +225 -0
  39. package/dist/chunk-JPT5I5W5.js.map +1 -0
  40. package/dist/index.cjs +486 -0
  41. package/dist/index.cjs.map +1 -0
  42. package/dist/index.d.cts +201 -0
  43. package/dist/index.d.ts +201 -0
  44. package/dist/index.js +284 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/types-DySgT8rA.d.cts +184 -0
  47. package/dist/types-DySgT8rA.d.ts +184 -0
  48. package/package.json +141 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sigil.ts"],"sourcesContent":["// @sigil-security/runtime — Core Sigil instance (orchestration layer)\n// Reference: SPECIFICATION.md Sections 3, 5, 8\n\nimport {\n WebCryptoCryptoProvider,\n createKeyring,\n rotateKey,\n getActiveKey,\n generateToken as coreGenerateToken,\n validateToken as coreValidateToken,\n computeContext,\n generateOneShotToken as coreGenerateOneShotToken,\n validateOneShotToken as coreValidateOneShotToken,\n createNonceCache,\n DEFAULT_TOKEN_TTL_MS,\n DEFAULT_GRACE_WINDOW_MS,\n DEFAULT_ONESHOT_TTL_MS,\n} from '@sigil-security/core'\nimport type { CryptoProvider, Keyring, NonceCache, ValidationResult } from '@sigil-security/core'\nimport {\n createFetchMetadataPolicy,\n createOriginPolicy,\n createMethodPolicy,\n createContentTypePolicy,\n detectClientMode,\n isProtectedMethod,\n evaluatePolicyChain,\n DEFAULT_HEADER_NAME,\n DEFAULT_ONESHOT_HEADER_NAME,\n DEFAULT_PROTECTED_METHODS,\n} from '@sigil-security/policy'\nimport type { PolicyValidator, RequestMetadata, PolicyChainResult } from '@sigil-security/policy'\nimport type {\n SigilConfig,\n SigilInstance,\n ResolvedSigilConfig,\n TokenGenerationResponse,\n TokenValidationResponse,\n ProtectResult,\n} from './types.js'\n\n// ============================================================\n// Master Secret Normalization\n// ============================================================\n\n/** Minimum master secret length in bytes for adequate security */\nconst MIN_MASTER_SECRET_BYTES = 32\n\n/**\n * Converts a string master secret to ArrayBuffer.\n * If already an ArrayBuffer, returns as-is.\n *\n * **Security (L1 fix):** Validates that the master secret is at least 32 bytes.\n * HKDF handles short inputs correctly, but effective security is bounded by\n * the input entropy. A weak master secret undermines the entire key hierarchy.\n *\n * @throws {Error} If the master secret is shorter than 32 bytes\n */\nfunction normalizeMasterSecret(secret: ArrayBuffer | string): ArrayBuffer {\n if (typeof secret !== 'string') {\n if (secret.byteLength < MIN_MASTER_SECRET_BYTES) {\n throw new Error(\n `Master secret must be at least ${String(MIN_MASTER_SECRET_BYTES)} bytes, ` +\n `got ${String(secret.byteLength)} bytes. Use a cryptographically strong secret.`,\n )\n }\n return secret\n }\n const encoder = new TextEncoder()\n const bytes = encoder.encode(secret)\n if (bytes.byteLength < MIN_MASTER_SECRET_BYTES) {\n throw new Error(\n `Master secret must be at least ${String(MIN_MASTER_SECRET_BYTES)} bytes when UTF-8 encoded, ` +\n `got ${String(bytes.byteLength)} bytes. Use a cryptographically strong secret.`,\n )\n }\n // Create a clean ArrayBuffer (not a view into a shared buffer)\n const buffer = new ArrayBuffer(bytes.byteLength)\n new Uint8Array(buffer).set(bytes)\n return buffer\n}\n\n// ============================================================\n// Configuration Resolution\n// ============================================================\n\n/**\n * Resolves user config with defaults applied.\n */\nfunction resolveConfig(config: SigilConfig): ResolvedSigilConfig {\n return {\n tokenTTL: config.tokenTTL ?? DEFAULT_TOKEN_TTL_MS,\n graceWindow: config.graceWindow ?? DEFAULT_GRACE_WINDOW_MS,\n allowedOrigins: config.allowedOrigins,\n legacyBrowserMode: config.legacyBrowserMode ?? 'degraded',\n allowApiMode: config.allowApiMode ?? true,\n protectedMethods: config.protectedMethods ?? DEFAULT_PROTECTED_METHODS,\n contextBinding: config.contextBinding,\n oneShotEnabled: config.oneShotEnabled ?? false,\n oneShotTTL: config.oneShotTTL ?? DEFAULT_ONESHOT_TTL_MS,\n headerName: config.headerName ?? DEFAULT_HEADER_NAME,\n oneShotHeaderName: config.oneShotHeaderName ?? DEFAULT_ONESHOT_HEADER_NAME,\n disableClientModeOverride: config.disableClientModeOverride ?? false,\n }\n}\n\n// ============================================================\n// One-Shot Keyring Validation Helper\n// ============================================================\n\n/**\n * Validates a one-shot token against all keys in a keyring.\n *\n * One-shot tokens do NOT embed a kid, so we must try all keys.\n * The nonce is only consumed on the first successful validation.\n *\n * @returns The first successful result, or the last failure\n */\nasync function validateOneShotWithKeyring(\n cryptoProvider: CryptoProvider,\n keyring: Keyring,\n tokenString: string,\n expectedAction: string,\n nonceCache: NonceCache,\n expectedContext: Uint8Array | undefined,\n ttlMs: number,\n): Promise<ValidationResult> {\n let lastResult: ValidationResult = { valid: false, reason: 'no_keys' }\n\n for (const key of keyring.keys) {\n const result = await coreValidateOneShotToken(\n cryptoProvider,\n key,\n tokenString,\n expectedAction,\n nonceCache,\n expectedContext,\n ttlMs,\n )\n if (result.valid) return result\n lastResult = result\n }\n\n return lastResult\n}\n\n// ============================================================\n// Sigil Instance Factory\n// ============================================================\n\n/**\n * Creates a Sigil runtime instance.\n *\n * This is the main entry point for Sigil. It initializes keyrings,\n * sets up policy chains, and returns an orchestration instance\n * that adapters use for token generation, validation, and request protection.\n *\n * @param config - Sigil configuration\n * @returns Initialized SigilInstance\n *\n * @example\n * ```typescript\n * const sigil = await createSigil({\n * masterSecret: process.env.CSRF_SECRET!,\n * allowedOrigins: ['https://example.com'],\n * })\n *\n * // Generate a token\n * const result = await sigil.generateToken()\n *\n * // Protect a request\n * const protection = await sigil.protect(metadata)\n * ```\n */\nexport async function createSigil(config: SigilConfig): Promise<SigilInstance> {\n const resolved = resolveConfig(config)\n const cryptoProvider: CryptoProvider = config.cryptoProvider ?? new WebCryptoCryptoProvider()\n const masterSecret = normalizeMasterSecret(config.masterSecret)\n\n // Instance-scoped kid counter (avoids global state)\n let kidCounter = 0\n function nextKid(): number {\n kidCounter = (kidCounter + 1) & 0xff // 8-bit wrap\n return kidCounter\n }\n\n // Initialize CSRF keyring\n const initialKid = nextKid()\n let csrfKeyring = await createKeyring(cryptoProvider, masterSecret, initialKid, 'csrf')\n\n // Initialize one-shot keyring and nonce cache (if enabled)\n let oneShotKeyring: Keyring | null = null\n let nonceCache: NonceCache | null = null\n if (resolved.oneShotEnabled) {\n oneShotKeyring = await createKeyring(cryptoProvider, masterSecret, initialKid, 'oneshot')\n nonceCache = createNonceCache()\n }\n\n // Build policy chains\n const browserPolicies: PolicyValidator[] = [\n createMethodPolicy({ protectedMethods: [...resolved.protectedMethods] }),\n createFetchMetadataPolicy({ legacyBrowserMode: resolved.legacyBrowserMode }),\n createOriginPolicy({ allowedOrigins: [...resolved.allowedOrigins] }),\n createContentTypePolicy(),\n ]\n\n const apiPolicies: PolicyValidator[] = [\n createMethodPolicy({ protectedMethods: [...resolved.protectedMethods] }),\n createContentTypePolicy(),\n ]\n\n // ============================================================\n // Instance Methods\n // ============================================================\n\n const instance: SigilInstance = {\n config: resolved,\n\n async generateToken(\n context?: readonly string[],\n ): Promise<TokenGenerationResponse> {\n const activeKey = getActiveKey(csrfKeyring)\n if (activeKey === undefined) {\n return { success: false, reason: 'no_active_key' }\n }\n\n let contextBytes: Uint8Array | undefined\n if (context !== undefined && context.length > 0) {\n contextBytes = await computeContext(cryptoProvider, ...context)\n }\n\n return coreGenerateToken(cryptoProvider, activeKey, contextBytes, resolved.tokenTTL)\n },\n\n async validateToken(\n tokenString: string,\n expectedContext?: readonly string[],\n ): Promise<TokenValidationResponse> {\n let contextBytes: Uint8Array | undefined\n if (expectedContext !== undefined && expectedContext.length > 0) {\n contextBytes = await computeContext(cryptoProvider, ...expectedContext)\n }\n\n return coreValidateToken(\n cryptoProvider,\n csrfKeyring,\n tokenString,\n contextBytes,\n resolved.tokenTTL,\n resolved.graceWindow,\n )\n },\n\n async generateOneShotToken(\n action: string,\n context?: readonly string[],\n ): Promise<TokenGenerationResponse> {\n if (!resolved.oneShotEnabled || oneShotKeyring === null) {\n return { success: false, reason: 'oneshot_not_enabled' }\n }\n\n const activeKey = getActiveKey(oneShotKeyring)\n if (activeKey === undefined) {\n return { success: false, reason: 'no_active_key' }\n }\n\n let contextBytes: Uint8Array | undefined\n if (context !== undefined && context.length > 0) {\n contextBytes = await computeContext(cryptoProvider, ...context)\n }\n\n return coreGenerateOneShotToken(\n cryptoProvider,\n activeKey,\n action,\n contextBytes,\n resolved.oneShotTTL,\n )\n },\n\n async validateOneShotToken(\n tokenString: string,\n expectedAction: string,\n expectedContext?: readonly string[],\n ): Promise<TokenValidationResponse> {\n if (!resolved.oneShotEnabled || oneShotKeyring === null || nonceCache === null) {\n return { valid: false, reason: 'oneshot_not_enabled' }\n }\n\n let contextBytes: Uint8Array | undefined\n if (expectedContext !== undefined && expectedContext.length > 0) {\n contextBytes = await computeContext(cryptoProvider, ...expectedContext)\n }\n\n // One-shot tokens have no kid — try all keys in the keyring\n return validateOneShotWithKeyring(\n cryptoProvider,\n oneShotKeyring,\n tokenString,\n expectedAction,\n nonceCache,\n contextBytes,\n resolved.oneShotTTL,\n )\n },\n\n async rotateKeys(): Promise<void> {\n const newKid = nextKid()\n csrfKeyring = await rotateKey(csrfKeyring, cryptoProvider, masterSecret, newKid)\n\n if (oneShotKeyring !== null) {\n oneShotKeyring = await rotateKey(oneShotKeyring, cryptoProvider, masterSecret, newKid)\n }\n },\n\n async protect(\n metadata: RequestMetadata,\n contextBindings?: readonly string[],\n ): Promise<ProtectResult> {\n // Step 1: Safe methods don't need protection\n if (!isProtectedMethod(metadata.method, [...resolved.protectedMethods])) {\n return {\n allowed: true,\n tokenValid: false,\n policyResult: { allowed: true, evaluated: [], failures: [] },\n }\n }\n\n // Step 2: Detect client mode\n const mode = detectClientMode(metadata, {\n disableClientModeOverride: resolved.disableClientModeOverride,\n })\n\n // Step 3: API mode check\n if (mode === 'api' && !resolved.allowApiMode) {\n return {\n allowed: false,\n reason: 'api_mode_not_allowed',\n expired: false,\n policyResult: null,\n }\n }\n\n // Step 4: Run policy chain based on detected mode\n const policies = mode === 'browser' ? browserPolicies : apiPolicies\n const policyResult: PolicyChainResult = evaluatePolicyChain(policies, metadata)\n\n if (!policyResult.allowed) {\n return {\n allowed: false,\n reason: policyResult.reason,\n expired: false,\n policyResult,\n }\n }\n\n // Step 5: Token must be present\n if (metadata.tokenSource.from === 'none') {\n return {\n allowed: false,\n reason: 'no_token_present',\n expired: false,\n policyResult,\n }\n }\n\n // Step 6: Compute context binding (if provided)\n let contextBytes: Uint8Array | undefined\n if (contextBindings !== undefined && contextBindings.length > 0) {\n contextBytes = await computeContext(cryptoProvider, ...contextBindings)\n }\n\n // Step 7: Validate CSRF token\n const tokenResult = await coreValidateToken(\n cryptoProvider,\n csrfKeyring,\n metadata.tokenSource.value,\n contextBytes,\n resolved.tokenTTL,\n resolved.graceWindow,\n )\n\n if (!tokenResult.valid) {\n return {\n allowed: false,\n reason: tokenResult.reason,\n expired: tokenResult.reason === 'expired',\n policyResult,\n }\n }\n\n return {\n allowed: true,\n tokenValid: true,\n policyResult,\n }\n },\n }\n\n return instance\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,184 @@
1
+ import { CryptoProvider } from '@sigil-security/core';
2
+ import { RequestMetadata, PolicyChainResult, LegacyBrowserMode, ContextBindingConfig } from '@sigil-security/policy';
3
+
4
+ /**
5
+ * Main configuration for Sigil runtime.
6
+ *
7
+ * This is the single entry point for configuring CSRF protection.
8
+ * The runtime layer orchestrates all interactions between core and policy.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const sigil = await createSigil({
13
+ * masterSecret: process.env.CSRF_SECRET,
14
+ * allowedOrigins: ['https://example.com'],
15
+ * })
16
+ * ```
17
+ */
18
+ interface SigilConfig {
19
+ /** Master secret for HKDF key derivation (minimum 32 bytes recommended) */
20
+ readonly masterSecret: ArrayBuffer | string;
21
+ /** Token TTL in milliseconds (default: 20 minutes = 1_200_000ms) */
22
+ readonly tokenTTL?: number | undefined;
23
+ /** Grace window after TTL expiry for in-flight requests (default: 60s = 60_000ms) */
24
+ readonly graceWindow?: number | undefined;
25
+ /** List of allowed origins (e.g., ['https://example.com']) */
26
+ readonly allowedOrigins: readonly string[];
27
+ /** How to handle legacy browsers without Fetch Metadata (default: 'degraded') */
28
+ readonly legacyBrowserMode?: LegacyBrowserMode | undefined;
29
+ /** Allow API mode (non-browser clients with token-only validation) (default: true) */
30
+ readonly allowApiMode?: boolean | undefined;
31
+ /** HTTP methods that require CSRF protection (default: ['POST','PUT','PATCH','DELETE']) */
32
+ readonly protectedMethods?: readonly string[] | undefined;
33
+ /** Context binding configuration (risk tier model) */
34
+ readonly contextBinding?: ContextBindingConfig | undefined;
35
+ /** Enable one-shot token support (default: false) */
36
+ readonly oneShotEnabled?: boolean | undefined;
37
+ /** One-shot token TTL in milliseconds (default: 5 minutes = 300_000ms) */
38
+ readonly oneShotTTL?: number | undefined;
39
+ /** Custom header name for CSRF tokens (default: 'x-csrf-token') */
40
+ readonly headerName?: string | undefined;
41
+ /** Custom header name for one-shot tokens (default: 'x-csrf-one-shot-token') */
42
+ readonly oneShotHeaderName?: string | undefined;
43
+ /**
44
+ * Disable X-Client-Type header override for mode detection.
45
+ * When true, clients cannot self-declare as API mode to bypass
46
+ * Fetch Metadata and Origin validation policies.
47
+ *
48
+ * Enable this if CORS configuration cannot be tightly controlled.
49
+ * Default: false
50
+ */
51
+ readonly disableClientModeOverride?: boolean | undefined;
52
+ /** Custom CryptoProvider implementation (default: WebCryptoCryptoProvider) */
53
+ readonly cryptoProvider?: CryptoProvider | undefined;
54
+ }
55
+ /**
56
+ * Fully resolved configuration with all defaults applied.
57
+ * Exposed as `sigil.config` on a SigilInstance.
58
+ */
59
+ interface ResolvedSigilConfig {
60
+ readonly tokenTTL: number;
61
+ readonly graceWindow: number;
62
+ readonly allowedOrigins: readonly string[];
63
+ readonly legacyBrowserMode: LegacyBrowserMode;
64
+ readonly allowApiMode: boolean;
65
+ readonly protectedMethods: readonly string[];
66
+ readonly contextBinding: ContextBindingConfig | undefined;
67
+ readonly oneShotEnabled: boolean;
68
+ readonly oneShotTTL: number;
69
+ readonly headerName: string;
70
+ readonly oneShotHeaderName: string;
71
+ readonly disableClientModeOverride: boolean;
72
+ }
73
+ /**
74
+ * The Sigil runtime instance.
75
+ *
76
+ * Created by `createSigil(config)`. Holds the keyring, nonce cache,
77
+ * and provides token generation / validation / protection methods.
78
+ */
79
+ interface SigilInstance {
80
+ /** Generate a new CSRF token */
81
+ generateToken(context?: readonly string[]): Promise<TokenGenerationResponse>;
82
+ /** Validate a CSRF token */
83
+ validateToken(tokenString: string, expectedContext?: readonly string[]): Promise<TokenValidationResponse>;
84
+ /** Generate a one-shot token (requires `oneShotEnabled: true`) */
85
+ generateOneShotToken(action: string, context?: readonly string[]): Promise<TokenGenerationResponse>;
86
+ /** Validate a one-shot token (tries all keys in the oneshot keyring) */
87
+ validateOneShotToken(tokenString: string, expectedAction: string, expectedContext?: readonly string[]): Promise<TokenValidationResponse>;
88
+ /** Rotate keyrings — new key becomes active, oldest dropped */
89
+ rotateKeys(): Promise<void>;
90
+ /**
91
+ * Full request protection: policy chain + token validation.
92
+ *
93
+ * 1. Checks if the method needs protection
94
+ * 2. Detects client mode (browser vs API)
95
+ * 3. Runs appropriate policy chain
96
+ * 4. Validates CSRF token
97
+ *
98
+ * @param metadata - Normalized request metadata (extracted by adapter)
99
+ * @param contextBindings - Optional context bindings for token validation
100
+ */
101
+ protect(metadata: RequestMetadata, contextBindings?: readonly string[]): Promise<ProtectResult>;
102
+ /** Resolved configuration (readonly) */
103
+ readonly config: ResolvedSigilConfig;
104
+ }
105
+ /** Token generation response */
106
+ type TokenGenerationResponse = {
107
+ readonly success: true;
108
+ readonly token: string;
109
+ readonly expiresAt: number;
110
+ } | {
111
+ readonly success: false;
112
+ readonly reason: string;
113
+ };
114
+ /** Token validation response */
115
+ type TokenValidationResponse = {
116
+ readonly valid: true;
117
+ } | {
118
+ readonly valid: false;
119
+ readonly reason: string;
120
+ };
121
+ /**
122
+ * Result of full request protection (policy chain + token validation).
123
+ *
124
+ * - `allowed: true` → request passed all checks
125
+ * - `allowed: false` → request blocked, `reason` is for internal logging only
126
+ */
127
+ type ProtectResult = {
128
+ readonly allowed: true;
129
+ readonly tokenValid: boolean;
130
+ readonly policyResult: PolicyChainResult;
131
+ } | {
132
+ readonly allowed: false;
133
+ readonly reason: string;
134
+ readonly expired: boolean;
135
+ readonly policyResult: PolicyChainResult | null;
136
+ };
137
+ /**
138
+ * Extracts normalized `RequestMetadata` from a framework-specific request object.
139
+ *
140
+ * Each framework adapter implements this for its own request type.
141
+ * This bridges framework HTTP objects to the policy layer.
142
+ */
143
+ type MetadataExtractor<TRequest> = (req: TRequest) => RequestMetadata;
144
+ /** Minimal request shape for the token endpoint handler */
145
+ interface TokenEndpointRequest {
146
+ readonly method: string;
147
+ readonly path: string;
148
+ readonly body?: Record<string, unknown> | undefined;
149
+ }
150
+ /** Token endpoint response (returned by `handleTokenEndpoint`) */
151
+ interface TokenEndpointResult {
152
+ readonly handled: boolean;
153
+ readonly status: number;
154
+ readonly body: Record<string, unknown>;
155
+ readonly headers: Record<string, string>;
156
+ }
157
+ /** One-shot token request body */
158
+ interface OneShotTokenRequestBody {
159
+ readonly action: string;
160
+ readonly context?: readonly string[] | undefined;
161
+ }
162
+ /** Uniform error response body — NEVER differentiates error types to client */
163
+ interface ErrorResponseBody {
164
+ readonly error: string;
165
+ }
166
+ /**
167
+ * Options for framework middleware adapters.
168
+ *
169
+ * Controls path exclusion, token endpoint paths, and context binding extraction.
170
+ */
171
+ interface MiddlewareOptions {
172
+ /** Paths to exclude from protection (exact match) */
173
+ readonly excludePaths?: readonly string[] | undefined;
174
+ /** Token generation endpoint path (default: '/api/csrf/token') */
175
+ readonly tokenEndpointPath?: string | undefined;
176
+ /** One-shot token endpoint path (default: '/api/csrf/one-shot') */
177
+ readonly oneShotEndpointPath?: string | undefined;
178
+ }
179
+ /** Default token generation endpoint path */
180
+ declare const DEFAULT_TOKEN_ENDPOINT_PATH = "/api/csrf/token";
181
+ /** Default one-shot token endpoint path */
182
+ declare const DEFAULT_ONESHOT_ENDPOINT_PATH = "/api/csrf/one-shot";
183
+
184
+ export { DEFAULT_ONESHOT_ENDPOINT_PATH as D, type ErrorResponseBody as E, type MetadataExtractor as M, type OneShotTokenRequestBody as O, type ProtectResult as P, type ResolvedSigilConfig as R, type SigilConfig as S, type TokenEndpointResult as T, type SigilInstance as a, DEFAULT_TOKEN_ENDPOINT_PATH as b, type MiddlewareOptions as c, type TokenEndpointRequest as d, type TokenGenerationResponse as e, type TokenValidationResponse as f };
@@ -0,0 +1,184 @@
1
+ import { CryptoProvider } from '@sigil-security/core';
2
+ import { RequestMetadata, PolicyChainResult, LegacyBrowserMode, ContextBindingConfig } from '@sigil-security/policy';
3
+
4
+ /**
5
+ * Main configuration for Sigil runtime.
6
+ *
7
+ * This is the single entry point for configuring CSRF protection.
8
+ * The runtime layer orchestrates all interactions between core and policy.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const sigil = await createSigil({
13
+ * masterSecret: process.env.CSRF_SECRET,
14
+ * allowedOrigins: ['https://example.com'],
15
+ * })
16
+ * ```
17
+ */
18
+ interface SigilConfig {
19
+ /** Master secret for HKDF key derivation (minimum 32 bytes recommended) */
20
+ readonly masterSecret: ArrayBuffer | string;
21
+ /** Token TTL in milliseconds (default: 20 minutes = 1_200_000ms) */
22
+ readonly tokenTTL?: number | undefined;
23
+ /** Grace window after TTL expiry for in-flight requests (default: 60s = 60_000ms) */
24
+ readonly graceWindow?: number | undefined;
25
+ /** List of allowed origins (e.g., ['https://example.com']) */
26
+ readonly allowedOrigins: readonly string[];
27
+ /** How to handle legacy browsers without Fetch Metadata (default: 'degraded') */
28
+ readonly legacyBrowserMode?: LegacyBrowserMode | undefined;
29
+ /** Allow API mode (non-browser clients with token-only validation) (default: true) */
30
+ readonly allowApiMode?: boolean | undefined;
31
+ /** HTTP methods that require CSRF protection (default: ['POST','PUT','PATCH','DELETE']) */
32
+ readonly protectedMethods?: readonly string[] | undefined;
33
+ /** Context binding configuration (risk tier model) */
34
+ readonly contextBinding?: ContextBindingConfig | undefined;
35
+ /** Enable one-shot token support (default: false) */
36
+ readonly oneShotEnabled?: boolean | undefined;
37
+ /** One-shot token TTL in milliseconds (default: 5 minutes = 300_000ms) */
38
+ readonly oneShotTTL?: number | undefined;
39
+ /** Custom header name for CSRF tokens (default: 'x-csrf-token') */
40
+ readonly headerName?: string | undefined;
41
+ /** Custom header name for one-shot tokens (default: 'x-csrf-one-shot-token') */
42
+ readonly oneShotHeaderName?: string | undefined;
43
+ /**
44
+ * Disable X-Client-Type header override for mode detection.
45
+ * When true, clients cannot self-declare as API mode to bypass
46
+ * Fetch Metadata and Origin validation policies.
47
+ *
48
+ * Enable this if CORS configuration cannot be tightly controlled.
49
+ * Default: false
50
+ */
51
+ readonly disableClientModeOverride?: boolean | undefined;
52
+ /** Custom CryptoProvider implementation (default: WebCryptoCryptoProvider) */
53
+ readonly cryptoProvider?: CryptoProvider | undefined;
54
+ }
55
+ /**
56
+ * Fully resolved configuration with all defaults applied.
57
+ * Exposed as `sigil.config` on a SigilInstance.
58
+ */
59
+ interface ResolvedSigilConfig {
60
+ readonly tokenTTL: number;
61
+ readonly graceWindow: number;
62
+ readonly allowedOrigins: readonly string[];
63
+ readonly legacyBrowserMode: LegacyBrowserMode;
64
+ readonly allowApiMode: boolean;
65
+ readonly protectedMethods: readonly string[];
66
+ readonly contextBinding: ContextBindingConfig | undefined;
67
+ readonly oneShotEnabled: boolean;
68
+ readonly oneShotTTL: number;
69
+ readonly headerName: string;
70
+ readonly oneShotHeaderName: string;
71
+ readonly disableClientModeOverride: boolean;
72
+ }
73
+ /**
74
+ * The Sigil runtime instance.
75
+ *
76
+ * Created by `createSigil(config)`. Holds the keyring, nonce cache,
77
+ * and provides token generation / validation / protection methods.
78
+ */
79
+ interface SigilInstance {
80
+ /** Generate a new CSRF token */
81
+ generateToken(context?: readonly string[]): Promise<TokenGenerationResponse>;
82
+ /** Validate a CSRF token */
83
+ validateToken(tokenString: string, expectedContext?: readonly string[]): Promise<TokenValidationResponse>;
84
+ /** Generate a one-shot token (requires `oneShotEnabled: true`) */
85
+ generateOneShotToken(action: string, context?: readonly string[]): Promise<TokenGenerationResponse>;
86
+ /** Validate a one-shot token (tries all keys in the oneshot keyring) */
87
+ validateOneShotToken(tokenString: string, expectedAction: string, expectedContext?: readonly string[]): Promise<TokenValidationResponse>;
88
+ /** Rotate keyrings — new key becomes active, oldest dropped */
89
+ rotateKeys(): Promise<void>;
90
+ /**
91
+ * Full request protection: policy chain + token validation.
92
+ *
93
+ * 1. Checks if the method needs protection
94
+ * 2. Detects client mode (browser vs API)
95
+ * 3. Runs appropriate policy chain
96
+ * 4. Validates CSRF token
97
+ *
98
+ * @param metadata - Normalized request metadata (extracted by adapter)
99
+ * @param contextBindings - Optional context bindings for token validation
100
+ */
101
+ protect(metadata: RequestMetadata, contextBindings?: readonly string[]): Promise<ProtectResult>;
102
+ /** Resolved configuration (readonly) */
103
+ readonly config: ResolvedSigilConfig;
104
+ }
105
+ /** Token generation response */
106
+ type TokenGenerationResponse = {
107
+ readonly success: true;
108
+ readonly token: string;
109
+ readonly expiresAt: number;
110
+ } | {
111
+ readonly success: false;
112
+ readonly reason: string;
113
+ };
114
+ /** Token validation response */
115
+ type TokenValidationResponse = {
116
+ readonly valid: true;
117
+ } | {
118
+ readonly valid: false;
119
+ readonly reason: string;
120
+ };
121
+ /**
122
+ * Result of full request protection (policy chain + token validation).
123
+ *
124
+ * - `allowed: true` → request passed all checks
125
+ * - `allowed: false` → request blocked, `reason` is for internal logging only
126
+ */
127
+ type ProtectResult = {
128
+ readonly allowed: true;
129
+ readonly tokenValid: boolean;
130
+ readonly policyResult: PolicyChainResult;
131
+ } | {
132
+ readonly allowed: false;
133
+ readonly reason: string;
134
+ readonly expired: boolean;
135
+ readonly policyResult: PolicyChainResult | null;
136
+ };
137
+ /**
138
+ * Extracts normalized `RequestMetadata` from a framework-specific request object.
139
+ *
140
+ * Each framework adapter implements this for its own request type.
141
+ * This bridges framework HTTP objects to the policy layer.
142
+ */
143
+ type MetadataExtractor<TRequest> = (req: TRequest) => RequestMetadata;
144
+ /** Minimal request shape for the token endpoint handler */
145
+ interface TokenEndpointRequest {
146
+ readonly method: string;
147
+ readonly path: string;
148
+ readonly body?: Record<string, unknown> | undefined;
149
+ }
150
+ /** Token endpoint response (returned by `handleTokenEndpoint`) */
151
+ interface TokenEndpointResult {
152
+ readonly handled: boolean;
153
+ readonly status: number;
154
+ readonly body: Record<string, unknown>;
155
+ readonly headers: Record<string, string>;
156
+ }
157
+ /** One-shot token request body */
158
+ interface OneShotTokenRequestBody {
159
+ readonly action: string;
160
+ readonly context?: readonly string[] | undefined;
161
+ }
162
+ /** Uniform error response body — NEVER differentiates error types to client */
163
+ interface ErrorResponseBody {
164
+ readonly error: string;
165
+ }
166
+ /**
167
+ * Options for framework middleware adapters.
168
+ *
169
+ * Controls path exclusion, token endpoint paths, and context binding extraction.
170
+ */
171
+ interface MiddlewareOptions {
172
+ /** Paths to exclude from protection (exact match) */
173
+ readonly excludePaths?: readonly string[] | undefined;
174
+ /** Token generation endpoint path (default: '/api/csrf/token') */
175
+ readonly tokenEndpointPath?: string | undefined;
176
+ /** One-shot token endpoint path (default: '/api/csrf/one-shot') */
177
+ readonly oneShotEndpointPath?: string | undefined;
178
+ }
179
+ /** Default token generation endpoint path */
180
+ declare const DEFAULT_TOKEN_ENDPOINT_PATH = "/api/csrf/token";
181
+ /** Default one-shot token endpoint path */
182
+ declare const DEFAULT_ONESHOT_ENDPOINT_PATH = "/api/csrf/one-shot";
183
+
184
+ export { DEFAULT_ONESHOT_ENDPOINT_PATH as D, type ErrorResponseBody as E, type MetadataExtractor as M, type OneShotTokenRequestBody as O, type ProtectResult as P, type ResolvedSigilConfig as R, type SigilConfig as S, type TokenEndpointResult as T, type SigilInstance as a, DEFAULT_TOKEN_ENDPOINT_PATH as b, type MiddlewareOptions as c, type TokenEndpointRequest as d, type TokenGenerationResponse as e, type TokenValidationResponse as f };
package/package.json ADDED
@@ -0,0 +1,141 @@
1
+ {
2
+ "name": "@sigil-security/runtime",
3
+ "version": "0.0.0",
4
+ "description": "Framework adapters — Express, Fastify, Hono, Oak, Elysia, native fetch",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "import": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "require": {
13
+ "types": "./dist/index.d.cts",
14
+ "default": "./dist/index.cjs"
15
+ }
16
+ },
17
+ "./express": {
18
+ "import": {
19
+ "types": "./dist/adapters/express.d.ts",
20
+ "default": "./dist/adapters/express.js"
21
+ },
22
+ "require": {
23
+ "types": "./dist/adapters/express.d.cts",
24
+ "default": "./dist/adapters/express.cjs"
25
+ }
26
+ },
27
+ "./fastify": {
28
+ "import": {
29
+ "types": "./dist/adapters/fastify.d.ts",
30
+ "default": "./dist/adapters/fastify.js"
31
+ },
32
+ "require": {
33
+ "types": "./dist/adapters/fastify.d.cts",
34
+ "default": "./dist/adapters/fastify.cjs"
35
+ }
36
+ },
37
+ "./hono": {
38
+ "import": {
39
+ "types": "./dist/adapters/hono.d.ts",
40
+ "default": "./dist/adapters/hono.js"
41
+ },
42
+ "require": {
43
+ "types": "./dist/adapters/hono.d.cts",
44
+ "default": "./dist/adapters/hono.cjs"
45
+ }
46
+ },
47
+ "./oak": {
48
+ "import": {
49
+ "types": "./dist/adapters/oak.d.ts",
50
+ "default": "./dist/adapters/oak.js"
51
+ },
52
+ "require": {
53
+ "types": "./dist/adapters/oak.d.cts",
54
+ "default": "./dist/adapters/oak.cjs"
55
+ }
56
+ },
57
+ "./elysia": {
58
+ "import": {
59
+ "types": "./dist/adapters/elysia.d.ts",
60
+ "default": "./dist/adapters/elysia.js"
61
+ },
62
+ "require": {
63
+ "types": "./dist/adapters/elysia.d.cts",
64
+ "default": "./dist/adapters/elysia.cjs"
65
+ }
66
+ },
67
+ "./fetch": {
68
+ "import": {
69
+ "types": "./dist/adapters/fetch.d.ts",
70
+ "default": "./dist/adapters/fetch.js"
71
+ },
72
+ "require": {
73
+ "types": "./dist/adapters/fetch.d.cts",
74
+ "default": "./dist/adapters/fetch.cjs"
75
+ }
76
+ }
77
+ },
78
+ "main": "./dist/index.cjs",
79
+ "module": "./dist/index.js",
80
+ "types": "./dist/index.d.ts",
81
+ "files": [
82
+ "dist"
83
+ ],
84
+ "keywords": [
85
+ "csrf",
86
+ "security",
87
+ "middleware",
88
+ "express",
89
+ "fastify",
90
+ "hono",
91
+ "oak",
92
+ "elysia",
93
+ "fetch",
94
+ "edge"
95
+ ],
96
+ "license": "Apache-2.0",
97
+ "repository": {
98
+ "type": "git",
99
+ "url": "https://github.com/laphilosophia/sigil-security.git",
100
+ "directory": "packages/runtime"
101
+ },
102
+ "dependencies": {
103
+ "@sigil-security/core": "0.0.0",
104
+ "@sigil-security/policy": "0.0.0"
105
+ },
106
+ "devDependencies": {
107
+ "tsup": "^8.0.0",
108
+ "typescript": "^5.7.0"
109
+ },
110
+ "peerDependencies": {
111
+ "express": ">=4.0.0",
112
+ "fastify": ">=4.0.0",
113
+ "hono": ">=4.0.0",
114
+ "@oakserver/oak": ">=12.0.0",
115
+ "elysia": ">=1.0.0"
116
+ },
117
+ "peerDependenciesMeta": {
118
+ "express": {
119
+ "optional": true
120
+ },
121
+ "fastify": {
122
+ "optional": true
123
+ },
124
+ "hono": {
125
+ "optional": true
126
+ },
127
+ "@oakserver/oak": {
128
+ "optional": true
129
+ },
130
+ "elysia": {
131
+ "optional": true
132
+ }
133
+ },
134
+ "publishConfig": {
135
+ "access": "public"
136
+ },
137
+ "scripts": {
138
+ "build": "tsup",
139
+ "typecheck": "tsc --noEmit"
140
+ }
141
+ }