@opensyber/tokenforge 1.0.0 → 1.1.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 (162) hide show
  1. package/README.md +130 -11
  2. package/dist/adapters/astro.d.ts +9 -0
  3. package/dist/adapters/astro.d.ts.map +1 -1
  4. package/dist/adapters/astro.js +13 -0
  5. package/dist/adapters/astro.js.map +1 -1
  6. package/dist/adapters/cloud-v2-bridge.d.ts +8 -0
  7. package/dist/adapters/cloud-v2-bridge.d.ts.map +1 -0
  8. package/dist/adapters/cloud-v2-bridge.js +24 -0
  9. package/dist/adapters/cloud-v2-bridge.js.map +1 -0
  10. package/dist/adapters/express.d.ts +15 -2
  11. package/dist/adapters/express.d.ts.map +1 -1
  12. package/dist/adapters/express.js +38 -0
  13. package/dist/adapters/express.js.map +1 -1
  14. package/dist/adapters/fastify.d.ts +15 -6
  15. package/dist/adapters/fastify.d.ts.map +1 -1
  16. package/dist/adapters/fastify.js +38 -0
  17. package/dist/adapters/fastify.js.map +1 -1
  18. package/dist/adapters/hono.d.ts +12 -0
  19. package/dist/adapters/hono.d.ts.map +1 -1
  20. package/dist/adapters/hono.js +13 -0
  21. package/dist/adapters/hono.js.map +1 -1
  22. package/dist/adapters/index.d.ts.map +1 -1
  23. package/dist/adapters/index.js.map +1 -1
  24. package/dist/adapters/nextjs.d.ts +15 -0
  25. package/dist/adapters/nextjs.d.ts.map +1 -1
  26. package/dist/adapters/nextjs.js +57 -30
  27. package/dist/adapters/nextjs.js.map +1 -1
  28. package/dist/adapters/sveltekit.d.ts +9 -0
  29. package/dist/adapters/sveltekit.d.ts.map +1 -1
  30. package/dist/adapters/sveltekit.js +13 -0
  31. package/dist/adapters/sveltekit.js.map +1 -1
  32. package/dist/client/action-signer.d.ts.map +1 -1
  33. package/dist/client/action-signer.js.map +1 -1
  34. package/dist/client/binding.d.ts.map +1 -1
  35. package/dist/client/binding.js.map +1 -1
  36. package/dist/client/cloud-device.d.ts +54 -0
  37. package/dist/client/cloud-device.d.ts.map +1 -0
  38. package/dist/client/cloud-device.js +301 -0
  39. package/dist/client/cloud-device.js.map +1 -0
  40. package/dist/client/crypto.d.ts.map +1 -1
  41. package/dist/client/crypto.js.map +1 -1
  42. package/dist/client/index.d.ts +1 -0
  43. package/dist/client/index.d.ts.map +1 -1
  44. package/dist/client/index.js +3 -1
  45. package/dist/client/index.js.map +1 -1
  46. package/dist/client/interceptor.d.ts.map +1 -1
  47. package/dist/client/interceptor.js +27 -3
  48. package/dist/client/interceptor.js.map +1 -1
  49. package/dist/client/signer.d.ts +23 -3
  50. package/dist/client/signer.d.ts.map +1 -1
  51. package/dist/client/signer.js +33 -5
  52. package/dist/client/signer.js.map +1 -1
  53. package/dist/client/storage.d.ts.map +1 -1
  54. package/dist/client/storage.js.map +1 -1
  55. package/dist/client/webauthn.d.ts.map +1 -1
  56. package/dist/client/webauthn.js.map +1 -1
  57. package/dist/protocol/v2.d.ts +23 -0
  58. package/dist/protocol/v2.d.ts.map +1 -0
  59. package/dist/protocol/v2.js +157 -0
  60. package/dist/protocol/v2.js.map +1 -0
  61. package/dist/react/index.d.ts.map +1 -1
  62. package/dist/react/index.js.map +1 -1
  63. package/dist/react/provider.d.ts.map +1 -1
  64. package/dist/react/provider.js.map +1 -1
  65. package/dist/server/action-verify.d.ts.map +1 -1
  66. package/dist/server/action-verify.js +1 -1
  67. package/dist/server/action-verify.js.map +1 -1
  68. package/dist/server/activity-histogram.d.ts +47 -0
  69. package/dist/server/activity-histogram.d.ts.map +1 -0
  70. package/dist/server/activity-histogram.js +76 -0
  71. package/dist/server/activity-histogram.js.map +1 -0
  72. package/dist/server/aitm-heuristics.d.ts.map +1 -1
  73. package/dist/server/aitm-heuristics.js.map +1 -1
  74. package/dist/server/bind-with-id-token.d.ts +55 -0
  75. package/dist/server/bind-with-id-token.d.ts.map +1 -0
  76. package/dist/server/bind-with-id-token.js +70 -0
  77. package/dist/server/bind-with-id-token.js.map +1 -0
  78. package/dist/server/bound-cookie.d.ts.map +1 -1
  79. package/dist/server/bound-cookie.js.map +1 -1
  80. package/dist/server/cbor.d.ts.map +1 -1
  81. package/dist/server/cbor.js.map +1 -1
  82. package/dist/server/cloud-bind.d.ts +42 -0
  83. package/dist/server/cloud-bind.d.ts.map +1 -0
  84. package/dist/server/cloud-bind.js +387 -0
  85. package/dist/server/cloud-bind.js.map +1 -0
  86. package/dist/server/cloud-middleware.d.ts +46 -0
  87. package/dist/server/cloud-middleware.d.ts.map +1 -0
  88. package/dist/server/cloud-middleware.js +344 -0
  89. package/dist/server/cloud-middleware.js.map +1 -0
  90. package/dist/server/cloud-verify.d.ts +30 -0
  91. package/dist/server/cloud-verify.d.ts.map +1 -0
  92. package/dist/server/cloud-verify.js +206 -0
  93. package/dist/server/cloud-verify.js.map +1 -0
  94. package/dist/server/dbsc-challenge.d.ts.map +1 -1
  95. package/dist/server/dbsc-challenge.js.map +1 -1
  96. package/dist/server/dbsc-endpoint.d.ts +20 -0
  97. package/dist/server/dbsc-endpoint.d.ts.map +1 -0
  98. package/dist/server/dbsc-endpoint.js +85 -0
  99. package/dist/server/dbsc-endpoint.js.map +1 -0
  100. package/dist/server/dbsc-verify.d.ts +32 -0
  101. package/dist/server/dbsc-verify.d.ts.map +1 -0
  102. package/dist/server/dbsc-verify.js +65 -0
  103. package/dist/server/dbsc-verify.js.map +1 -0
  104. package/dist/server/identity-profile.d.ts +18 -0
  105. package/dist/server/identity-profile.d.ts.map +1 -0
  106. package/dist/server/identity-profile.js +113 -0
  107. package/dist/server/identity-profile.js.map +1 -0
  108. package/dist/server/index.d.ts +10 -0
  109. package/dist/server/index.d.ts.map +1 -1
  110. package/dist/server/index.js +5 -0
  111. package/dist/server/index.js.map +1 -1
  112. package/dist/server/jws-verify.d.ts.map +1 -1
  113. package/dist/server/jws-verify.js.map +1 -1
  114. package/dist/server/middleware.d.ts +9 -0
  115. package/dist/server/middleware.d.ts.map +1 -1
  116. package/dist/server/middleware.js +60 -20
  117. package/dist/server/middleware.js.map +1 -1
  118. package/dist/server/oidc-verify.d.ts +16 -1
  119. package/dist/server/oidc-verify.d.ts.map +1 -1
  120. package/dist/server/oidc-verify.js +9 -1
  121. package/dist/server/oidc-verify.js.map +1 -1
  122. package/dist/server/policy.d.ts.map +1 -1
  123. package/dist/server/policy.js.map +1 -1
  124. package/dist/server/step-up-policy.d.ts.map +1 -1
  125. package/dist/server/step-up-policy.js.map +1 -1
  126. package/dist/server/storage/index.d.ts +3 -0
  127. package/dist/server/storage/index.d.ts.map +1 -0
  128. package/dist/server/storage/index.js +2 -0
  129. package/dist/server/storage/index.js.map +1 -0
  130. package/dist/server/storage/interface.d.ts +73 -0
  131. package/dist/server/storage/interface.d.ts.map +1 -0
  132. package/dist/server/storage/interface.js +2 -0
  133. package/dist/server/storage/interface.js.map +1 -0
  134. package/dist/server/storage/memory.d.ts +50 -0
  135. package/dist/server/storage/memory.d.ts.map +1 -0
  136. package/dist/server/storage/memory.js +121 -0
  137. package/dist/server/storage/memory.js.map +1 -0
  138. package/dist/server/webauthn-verify.d.ts.map +1 -1
  139. package/dist/server/webauthn-verify.js.map +1 -1
  140. package/dist/server/webhooks.d.ts.map +1 -1
  141. package/dist/server/webhooks.js.map +1 -1
  142. package/dist/shared/action-hash.d.ts.map +1 -1
  143. package/dist/shared/action-hash.js.map +1 -1
  144. package/dist/shared/identity.d.ts +45 -0
  145. package/dist/shared/identity.d.ts.map +1 -0
  146. package/dist/shared/identity.js +176 -0
  147. package/dist/shared/identity.js.map +1 -0
  148. package/dist/shared/types-internal.d.ts.map +1 -1
  149. package/dist/shared/types-internal.js.map +1 -1
  150. package/dist/shared/types.d.ts +47 -2
  151. package/dist/shared/types.d.ts.map +1 -1
  152. package/dist/shared/types.js +1 -0
  153. package/dist/shared/types.js.map +1 -1
  154. package/package.json +9 -47
  155. package/dist/server/trust-score-fixtures.d.ts +0 -9
  156. package/dist/server/trust-score-fixtures.d.ts.map +0 -1
  157. package/dist/server/trust-score-fixtures.js +0 -23
  158. package/dist/server/trust-score-fixtures.js.map +0 -1
  159. package/dist/server/webauthn-verify.test-helpers.d.ts +0 -8
  160. package/dist/server/webauthn-verify.test-helpers.d.ts.map +0 -1
  161. package/dist/server/webauthn-verify.test-helpers.js +0 -39
  162. package/dist/server/webauthn-verify.test-helpers.js.map +0 -1
@@ -0,0 +1,387 @@
1
+ import { PROTOCOL_V2, sha256Base64Url, } from '../protocol/v2.js';
2
+ import { validateTokenForgeIdentity, } from '../shared/identity.js';
3
+ const DEFAULT_API_URL = 'https://tokenforge-api.opensyber.cloud';
4
+ const DEFAULT_TIMEOUT_MS = 1_500;
5
+ const DEFAULT_MAX_REQUEST_BYTES = 16 * 1024;
6
+ const DEFAULT_MAX_RESPONSE_BYTES = 64 * 1024;
7
+ const DEVICE_PATTERN = /^[A-Za-z0-9_.:-]{8,256}$/;
8
+ const PROJECT_PATTERN = /^[A-Za-z0-9_-]{8,256}$/;
9
+ const SESSION_PATTERN = /^[A-Za-z0-9_-]{16,256}$/;
10
+ const IDEMPOTENCY_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;
11
+ const BIND_KEYS = new Set(['protocol', 'localDeviceId', 'publicKey']);
12
+ const PUBLIC_JWK_KEYS = new Set(['kty', 'crv', 'x', 'y', 'ext', 'key_ops']);
13
+ class CloudBindRejectedError extends Error {
14
+ status;
15
+ code;
16
+ constructor(status, code) {
17
+ super('TokenForge Cloud rejected the bind');
18
+ this.status = status;
19
+ this.code = code;
20
+ }
21
+ }
22
+ /**
23
+ * Framework-neutral Cloud v2 bind handler. Mount the returned function behind
24
+ * the application's normal authenticated session endpoint.
25
+ */
26
+ export function createTokenForgeCloudBindHandler(options) {
27
+ const mode = normalizeMode(options.mode);
28
+ const apiUrl = normalizeApiUrl(options.apiUrl ?? DEFAULT_API_URL);
29
+ const fetcher = options.fetch ?? globalThis.fetch;
30
+ const timeoutMs = positiveInteger(options.requestTimeoutMs, DEFAULT_TIMEOUT_MS);
31
+ const maxRequestBytes = positiveInteger(options.maxRequestBytes, DEFAULT_MAX_REQUEST_BYTES);
32
+ const maxResponseBytes = positiveInteger(options.maxResponseBytes, DEFAULT_MAX_RESPONSE_BYTES);
33
+ if (!options.bindingStore || typeof options.resolveSession !== 'function') {
34
+ throw new Error('TokenForge Cloud bind requires bindingStore and resolveSession');
35
+ }
36
+ if (typeof fetcher !== 'function') {
37
+ throw new Error('TokenForge Cloud bind requires fetch');
38
+ }
39
+ return async (request) => {
40
+ if (request.method !== 'POST')
41
+ return safeJson(405, { error: 'method_not_allowed' });
42
+ let session;
43
+ try {
44
+ session = await options.resolveSession(request);
45
+ }
46
+ catch {
47
+ return safeJson(401, { error: 'unauthorized' });
48
+ }
49
+ if (!validSession(session))
50
+ return safeJson(401, { error: 'unauthorized' });
51
+ let input;
52
+ try {
53
+ input = await parseBrowserBindRequest(request, maxRequestBytes);
54
+ }
55
+ catch {
56
+ return safeJson(400, { error: 'invalid_bind_request' });
57
+ }
58
+ if (session.localDeviceId && session.localDeviceId !== input.localDeviceId) {
59
+ return safeJson(400, { error: 'device_mismatch' });
60
+ }
61
+ let publicKey;
62
+ try {
63
+ publicKey = await validatePublicJwk(input.publicKey);
64
+ }
65
+ catch {
66
+ return safeJson(400, { error: 'invalid_public_key' });
67
+ }
68
+ if (mode === 'off') {
69
+ return safeJson(200, { data: { protocol: PROTOCOL_V2, mode, bound: false } });
70
+ }
71
+ const publicSessionId = await hashOpaque('session', session.sessionId);
72
+ const correlationId = await hashOpaque('correlation', session.correlationId || session.userId || 'anonymous');
73
+ let currentBinding = null;
74
+ try {
75
+ const existing = await options.bindingStore.getByLocalDeviceId(input.localDeviceId);
76
+ if (existing &&
77
+ existing.sessionId === publicSessionId &&
78
+ existing.publicKeyFingerprint === publicKey.fingerprint &&
79
+ Date.parse(existing.expiresAt) > Date.now()) {
80
+ currentBinding = existing;
81
+ if (!options.resolveIdentity)
82
+ return boundResponse(mode, existing, true);
83
+ }
84
+ }
85
+ catch {
86
+ // Cloud bind remains available when a stale local lookup fails.
87
+ }
88
+ if (!options.apiKey?.trim()) {
89
+ return unavailableOrExisting(mode, currentBinding);
90
+ }
91
+ const idempotencyKey = request.headers.get('Idempotency-Key') ?? '';
92
+ if (idempotencyKey && !IDEMPOTENCY_PATTERN.test(idempotencyKey)) {
93
+ return safeJson(400, { error: 'invalid_idempotency_key' });
94
+ }
95
+ let identity;
96
+ if (options.resolveIdentity) {
97
+ try {
98
+ const resolved = await options.resolveIdentity(request, session);
99
+ if (resolved !== null) {
100
+ try {
101
+ identity = validateTokenForgeIdentity(resolved);
102
+ }
103
+ catch {
104
+ return safeJson(500, { error: 'tokenforge_identity_invalid' });
105
+ }
106
+ }
107
+ }
108
+ catch {
109
+ return unavailableOrExisting(mode, currentBinding);
110
+ }
111
+ }
112
+ let cloudResult;
113
+ try {
114
+ cloudResult = await postCloudBind(fetcher, apiUrl, options.apiKey, idempotencyKey, timeoutMs, maxResponseBytes, {
115
+ publicKey: publicKey.json,
116
+ // A canonical identity is already scoped by the host's project and
117
+ // tenant derivation. Do not add an account-global legacy join key.
118
+ userId: identity?.externalUserRef ?? await hashOpaque('user', session.userId),
119
+ sessionId: publicSessionId,
120
+ fingerprint: publicKey.fingerprint,
121
+ userIdSource: 'declared',
122
+ identity,
123
+ });
124
+ }
125
+ catch (error) {
126
+ if (error instanceof CloudBindRejectedError) {
127
+ return safeJson(error.status, {
128
+ error: 'tokenforge_rejected',
129
+ reason: error.code,
130
+ });
131
+ }
132
+ return unavailableOrExisting(mode, currentBinding);
133
+ }
134
+ const binding = {
135
+ localDeviceId: input.localDeviceId,
136
+ cloudDeviceId: cloudResult.deviceId,
137
+ projectId: cloudResult.projectId,
138
+ sessionId: cloudResult.sessionId,
139
+ correlationId,
140
+ publicKeyFingerprint: publicKey.fingerprint,
141
+ publicKeyJwk: publicKey.json,
142
+ expiresAt: cloudResult.expiresAt,
143
+ };
144
+ try {
145
+ await options.bindingStore.put(binding);
146
+ }
147
+ catch {
148
+ return unavailableOrExisting(mode, currentBinding);
149
+ }
150
+ return boundResponse(mode, binding, cloudResult.idempotent);
151
+ };
152
+ }
153
+ async function postCloudBind(fetcher, apiUrl, apiKey, idempotencyKey, timeoutMs, maxResponseBytes, body) {
154
+ const controller = new AbortController();
155
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
156
+ let response;
157
+ let raw;
158
+ try {
159
+ response = await fetcher(`${apiUrl}/v1/bind`, {
160
+ method: 'POST',
161
+ signal: controller.signal,
162
+ headers: {
163
+ Authorization: `Bearer ${apiKey}`,
164
+ Accept: 'application/json',
165
+ 'Content-Type': 'application/json',
166
+ ...(idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : {}),
167
+ },
168
+ body: JSON.stringify(body),
169
+ });
170
+ raw = await readBoundedResponse(response, maxResponseBytes);
171
+ }
172
+ finally {
173
+ clearTimeout(timeout);
174
+ }
175
+ if (!response.ok) {
176
+ const code = safeCloudErrorCode(raw);
177
+ const authenticationFailure = response.status === 401 && code === 'unauthorized';
178
+ if (response.status >= 400 && response.status < 500 && !authenticationFailure) {
179
+ throw new CloudBindRejectedError(response.status, code);
180
+ }
181
+ throw new Error('TokenForge Cloud bind is unavailable');
182
+ }
183
+ const envelope = requireRecord(JSON.parse(raw), 'TokenForge Cloud response');
184
+ const data = requireRecord(envelope.data, 'TokenForge Cloud response data');
185
+ if (typeof data.projectId !== 'string' || !PROJECT_PATTERN.test(data.projectId) ||
186
+ typeof data.deviceId !== 'string' || !DEVICE_PATTERN.test(data.deviceId) ||
187
+ typeof data.sessionId !== 'string' || !SESSION_PATTERN.test(data.sessionId) ||
188
+ typeof data.expiresAt !== 'string' || !Number.isFinite(Date.parse(data.expiresAt)) ||
189
+ typeof data.idempotent !== 'boolean') {
190
+ throw new Error('TokenForge Cloud bind response is invalid');
191
+ }
192
+ return {
193
+ projectId: data.projectId,
194
+ deviceId: data.deviceId,
195
+ sessionId: data.sessionId,
196
+ expiresAt: data.expiresAt,
197
+ idempotent: data.idempotent,
198
+ };
199
+ }
200
+ async function readBoundedResponse(response, maxBytes) {
201
+ if (!response.body)
202
+ return '';
203
+ const reader = response.body.getReader();
204
+ const chunks = [];
205
+ let total = 0;
206
+ try {
207
+ while (true) {
208
+ const { done, value } = await reader.read();
209
+ if (done)
210
+ break;
211
+ total += value.byteLength;
212
+ if (total > maxBytes) {
213
+ await reader.cancel();
214
+ throw new Error('TokenForge Cloud bind response is too large');
215
+ }
216
+ chunks.push(value);
217
+ }
218
+ }
219
+ finally {
220
+ reader.releaseLock();
221
+ }
222
+ const output = new Uint8Array(total);
223
+ let offset = 0;
224
+ for (const chunk of chunks) {
225
+ output.set(chunk, offset);
226
+ offset += chunk.byteLength;
227
+ }
228
+ return new TextDecoder().decode(output);
229
+ }
230
+ async function parseBrowserBindRequest(request, maxRequestBytes) {
231
+ const raw = await readBoundedRequestBody(request, maxRequestBytes);
232
+ const input = requireRecord(JSON.parse(raw), 'TokenForge bind request');
233
+ rejectUnknownKeys(input, BIND_KEYS);
234
+ if (input.protocol !== PROTOCOL_V2 ||
235
+ typeof input.localDeviceId !== 'string' ||
236
+ !DEVICE_PATTERN.test(input.localDeviceId)) {
237
+ throw new Error('invalid bind request');
238
+ }
239
+ return {
240
+ protocol: PROTOCOL_V2,
241
+ localDeviceId: input.localDeviceId,
242
+ publicKey: requireRecord(input.publicKey, 'TokenForge public key'),
243
+ };
244
+ }
245
+ async function readBoundedRequestBody(request, maxBytes) {
246
+ const declaredLength = Number(request.headers.get('content-length'));
247
+ if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
248
+ throw new Error('request too large');
249
+ }
250
+ if (!request.body)
251
+ return '';
252
+ const reader = request.body.getReader();
253
+ const chunks = [];
254
+ let total = 0;
255
+ try {
256
+ while (true) {
257
+ const { done, value } = await reader.read();
258
+ if (done)
259
+ break;
260
+ total += value.byteLength;
261
+ if (total > maxBytes)
262
+ throw new Error('request too large');
263
+ chunks.push(value);
264
+ }
265
+ }
266
+ finally {
267
+ reader.releaseLock();
268
+ }
269
+ const output = new Uint8Array(total);
270
+ let offset = 0;
271
+ for (const chunk of chunks) {
272
+ output.set(chunk, offset);
273
+ offset += chunk.byteLength;
274
+ }
275
+ return new TextDecoder().decode(output);
276
+ }
277
+ async function validatePublicJwk(input) {
278
+ rejectUnknownKeys(input, PUBLIC_JWK_KEYS);
279
+ if (input.kty !== 'EC' || input.crv !== 'P-256' ||
280
+ typeof input.x !== 'string' || typeof input.y !== 'string' ||
281
+ (input.key_ops && (input.key_ops.length !== 1 || input.key_ops[0] !== 'verify'))) {
282
+ throw new Error('invalid public key');
283
+ }
284
+ const x = decodeBase64Url(input.x);
285
+ const y = decodeBase64Url(input.y);
286
+ if (x.byteLength !== 32 || y.byteLength !== 32)
287
+ throw new Error('invalid public key');
288
+ const canonical = {
289
+ kty: 'EC',
290
+ crv: 'P-256',
291
+ x: input.x,
292
+ y: input.y,
293
+ ext: true,
294
+ key_ops: ['verify'],
295
+ };
296
+ await crypto.subtle.importKey('jwk', canonical, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']);
297
+ const coordinates = new Uint8Array(64);
298
+ coordinates.set(x, 0);
299
+ coordinates.set(y, 32);
300
+ return {
301
+ json: JSON.stringify(canonical),
302
+ fingerprint: await sha256Base64Url(coordinates),
303
+ };
304
+ }
305
+ async function hashOpaque(purpose, value) {
306
+ return sha256Base64Url(new TextEncoder().encode(`tokenforge-v2:${purpose}\0${value}`));
307
+ }
308
+ function unavailableOrExisting(mode, existing) {
309
+ if (mode === 'enforce')
310
+ return safeJson(503, { error: 'tokenforge_unavailable' });
311
+ if (existing)
312
+ return boundResponse(mode, existing, true);
313
+ return safeJson(200, {
314
+ data: { protocol: PROTOCOL_V2, mode: 'monitor', bound: false, status: 'unavailable' },
315
+ });
316
+ }
317
+ function boundResponse(mode, binding, idempotent) {
318
+ return safeJson(200, {
319
+ data: {
320
+ protocol: PROTOCOL_V2,
321
+ mode,
322
+ bound: true,
323
+ projectId: binding.projectId,
324
+ deviceId: binding.cloudDeviceId,
325
+ sessionId: binding.sessionId,
326
+ expiresAt: binding.expiresAt,
327
+ idempotent,
328
+ },
329
+ });
330
+ }
331
+ function safeJson(status, value) {
332
+ return new Response(JSON.stringify(value), {
333
+ status,
334
+ headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' },
335
+ });
336
+ }
337
+ function validSession(session) {
338
+ return !!session &&
339
+ typeof session.sessionId === 'string' && session.sessionId.length > 0 &&
340
+ typeof session.userId === 'string' && session.userId.length > 0;
341
+ }
342
+ function normalizeMode(mode) {
343
+ return mode === 'monitor' || mode === 'enforce' ? mode : 'off';
344
+ }
345
+ function normalizeApiUrl(input) {
346
+ const url = new URL(input);
347
+ if (url.protocol !== 'https:' || !url.hostname || url.username || url.password ||
348
+ url.search || url.hash) {
349
+ throw new Error('TokenForge Cloud API URL is invalid');
350
+ }
351
+ return url.toString().replace(/\/$/, '');
352
+ }
353
+ function positiveInteger(value, fallback) {
354
+ return Number.isSafeInteger(value) && (value ?? 0) > 0 ? value : fallback;
355
+ }
356
+ function requireRecord(input, label) {
357
+ if (typeof input !== 'object' || input === null || Array.isArray(input)) {
358
+ throw new Error(`${label} must be an object`);
359
+ }
360
+ return input;
361
+ }
362
+ function rejectUnknownKeys(input, allowed) {
363
+ for (const key of Object.keys(input)) {
364
+ if (!allowed.has(key))
365
+ throw new Error(`unsupported bind field: ${key}`);
366
+ }
367
+ }
368
+ function safeCloudErrorCode(raw) {
369
+ try {
370
+ const envelope = requireRecord(JSON.parse(raw), 'TokenForge Cloud error');
371
+ const code = envelope.error;
372
+ if (typeof code === 'string' && /^[A-Za-z0-9._:-]{1,96}$/.test(code))
373
+ return code;
374
+ }
375
+ catch {
376
+ // Return a bounded generic reason without exposing a remote response body.
377
+ }
378
+ return 'bind_rejected';
379
+ }
380
+ function decodeBase64Url(value) {
381
+ if (!/^[A-Za-z0-9_-]{43}$/.test(value))
382
+ throw new Error('invalid base64url');
383
+ const padded = value.replace(/-/g, '+').replace(/_/g, '/') + '=';
384
+ const binary = atob(padded);
385
+ return Uint8Array.from(binary, (character) => character.charCodeAt(0));
386
+ }
387
+ //# sourceMappingURL=cloud-bind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-bind.js","sourceRoot":"../src/","sources":["server/cloud-bind.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { PROTOCOL_V2 } from '../protocol/v2.js';
2
+ import type { TokenForgeCloudMode } from './cloud-bind.js';
3
+ import { type CloudVerifyOptions } from './cloud-verify.js';
4
+ export type CloudCircuitState = 'closed' | 'open' | 'half_open';
5
+ export type TokenForgeRequestHandler = (request: Request) => Promise<Response> | Response;
6
+ export interface CloudVerifyDecision {
7
+ status: 'allow' | 'step_up' | 'block';
8
+ bound: boolean;
9
+ trustScore: number;
10
+ deviceId: string;
11
+ reason: string;
12
+ protocol: typeof PROTOCOL_V2;
13
+ }
14
+ export interface CloudTelemetryEvent {
15
+ type: 'attempt' | 'success' | 'would_block' | 'error' | 'timeout' | 'circuit_open' | 'local_cloud_mismatch';
16
+ operation: '/v2/edge/verify';
17
+ mode: TokenForgeCloudMode;
18
+ outcome: string;
19
+ latencyMs: number;
20
+ circuit: CloudCircuitState;
21
+ correlationId?: string;
22
+ }
23
+ export type CloudTelemetryHook = (event: CloudTelemetryEvent) => void;
24
+ export interface TokenForgeCloudMiddlewareOptions {
25
+ mode: TokenForgeCloudMode;
26
+ local: CloudVerifyOptions;
27
+ apiKey?: string;
28
+ apiUrl?: string;
29
+ fetch?: typeof fetch;
30
+ requestTimeoutMs?: number;
31
+ maxResponseBytes?: number;
32
+ failureThreshold?: number;
33
+ openIntervalMs?: number;
34
+ maxOpenIntervalMs?: number;
35
+ /** Exact URL paths that bypass TokenForge proof verification. */
36
+ skipPaths?: readonly string[];
37
+ telemetry?: CloudTelemetryHook;
38
+ now?: () => number;
39
+ }
40
+ /**
41
+ * Compose local verification with TokenForge Cloud verification.
42
+ * Local denial always wins. Monitor observes cloud decisions; enforce requires
43
+ * both local and cloud acceptance.
44
+ */
45
+ export declare function createTokenForgeCloudMiddleware(options: TokenForgeCloudMiddlewareOptions): (next: TokenForgeRequestHandler) => TokenForgeRequestHandler;
46
+ //# sourceMappingURL=cloud-middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-middleware.d.ts","sourceRoot":"../src/","sources":["server/cloud-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAGL,KAAK,kBAAkB,EAGxB,MAAM,mBAAmB,CAAC;AAU3B,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAChE,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;AAE1F,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;IACtC,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,WAAW,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,cAAc,GAAG,sBAAsB,CAAC;IAC5G,SAAS,EAAE,iBAAiB,CAAC;IAC7B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAEtE,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,mBAAmB,CAAC;IAC1B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IACjE,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAaD;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,gCAAgC,GACxC,CAAC,IAAI,EAAE,wBAAwB,KAAK,wBAAwB,CA8H9D"}