@opensyber/tokenforge 0.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 (94) hide show
  1. package/README.md +137 -0
  2. package/dist/adapters/express.d.ts +48 -0
  3. package/dist/adapters/express.d.ts.map +1 -0
  4. package/dist/adapters/express.js +73 -0
  5. package/dist/adapters/express.js.map +1 -0
  6. package/dist/adapters/fastify.d.ts +44 -0
  7. package/dist/adapters/fastify.d.ts.map +1 -0
  8. package/dist/adapters/fastify.js +69 -0
  9. package/dist/adapters/fastify.js.map +1 -0
  10. package/dist/adapters/hono.d.ts +8 -0
  11. package/dist/adapters/hono.d.ts.map +1 -0
  12. package/dist/adapters/hono.js +8 -0
  13. package/dist/adapters/hono.js.map +1 -0
  14. package/dist/adapters/index.d.ts +5 -0
  15. package/dist/adapters/index.d.ts.map +1 -0
  16. package/dist/adapters/index.js +5 -0
  17. package/dist/adapters/index.js.map +1 -0
  18. package/dist/adapters/nextjs.d.ts +51 -0
  19. package/dist/adapters/nextjs.d.ts.map +1 -0
  20. package/dist/adapters/nextjs.js +101 -0
  21. package/dist/adapters/nextjs.js.map +1 -0
  22. package/dist/client/binding.d.ts +14 -0
  23. package/dist/client/binding.d.ts.map +1 -0
  24. package/dist/client/binding.js +49 -0
  25. package/dist/client/binding.js.map +1 -0
  26. package/dist/client/crypto.d.ts +16 -0
  27. package/dist/client/crypto.d.ts.map +1 -0
  28. package/dist/client/crypto.js +22 -0
  29. package/dist/client/crypto.js.map +1 -0
  30. package/dist/client/index.d.ts +38 -0
  31. package/dist/client/index.d.ts.map +1 -0
  32. package/dist/client/index.js +108 -0
  33. package/dist/client/index.js.map +1 -0
  34. package/dist/client/interceptor.d.ts +13 -0
  35. package/dist/client/interceptor.d.ts.map +1 -0
  36. package/dist/client/interceptor.js +85 -0
  37. package/dist/client/interceptor.js.map +1 -0
  38. package/dist/client/signer.d.ts +15 -0
  39. package/dist/client/signer.d.ts.map +1 -0
  40. package/dist/client/signer.js +31 -0
  41. package/dist/client/signer.js.map +1 -0
  42. package/dist/client/storage.d.ts +17 -0
  43. package/dist/client/storage.d.ts.map +1 -0
  44. package/dist/client/storage.js +58 -0
  45. package/dist/client/storage.js.map +1 -0
  46. package/dist/react/index.d.ts +2 -0
  47. package/dist/react/index.d.ts.map +1 -0
  48. package/dist/react/index.js +2 -0
  49. package/dist/react/index.js.map +1 -0
  50. package/dist/react/provider.d.ts +30 -0
  51. package/dist/react/provider.d.ts.map +1 -0
  52. package/dist/react/provider.js +59 -0
  53. package/dist/react/provider.js.map +1 -0
  54. package/dist/server/binding.d.ts +19 -0
  55. package/dist/server/binding.d.ts.map +1 -0
  56. package/dist/server/binding.js +87 -0
  57. package/dist/server/binding.js.map +1 -0
  58. package/dist/server/index.d.ts +7 -0
  59. package/dist/server/index.d.ts.map +1 -0
  60. package/dist/server/index.js +6 -0
  61. package/dist/server/index.js.map +1 -0
  62. package/dist/server/middleware.d.ts +30 -0
  63. package/dist/server/middleware.d.ts.map +1 -0
  64. package/dist/server/middleware.js +107 -0
  65. package/dist/server/middleware.js.map +1 -0
  66. package/dist/server/step-up.d.ts +19 -0
  67. package/dist/server/step-up.d.ts.map +1 -0
  68. package/dist/server/step-up.js +139 -0
  69. package/dist/server/step-up.js.map +1 -0
  70. package/dist/server/storage/index.d.ts +3 -0
  71. package/dist/server/storage/index.d.ts.map +1 -0
  72. package/dist/server/storage/index.js +2 -0
  73. package/dist/server/storage/index.js.map +1 -0
  74. package/dist/server/storage/interface.d.ts +61 -0
  75. package/dist/server/storage/interface.d.ts.map +1 -0
  76. package/dist/server/storage/interface.js +2 -0
  77. package/dist/server/storage/interface.js.map +1 -0
  78. package/dist/server/storage/memory.d.ts +40 -0
  79. package/dist/server/storage/memory.d.ts.map +1 -0
  80. package/dist/server/storage/memory.js +107 -0
  81. package/dist/server/storage/memory.js.map +1 -0
  82. package/dist/server/totp.d.ts +53 -0
  83. package/dist/server/totp.d.ts.map +1 -0
  84. package/dist/server/totp.js +114 -0
  85. package/dist/server/totp.js.map +1 -0
  86. package/dist/shared/types-internal.d.ts +66 -0
  87. package/dist/shared/types-internal.d.ts.map +1 -0
  88. package/dist/shared/types-internal.js +4 -0
  89. package/dist/shared/types-internal.js.map +1 -0
  90. package/dist/shared/types.d.ts +148 -0
  91. package/dist/shared/types.d.ts.map +1 -0
  92. package/dist/shared/types.js +9 -0
  93. package/dist/shared/types.js.map +1 -0
  94. package/package.json +118 -0
@@ -0,0 +1,19 @@
1
+ import { Hono } from 'hono';
2
+ import type { TokenForgeServerOptions } from '../shared/types.js';
3
+ interface Variables {
4
+ userId: string;
5
+ sessionId: string;
6
+ }
7
+ /**
8
+ * TokenForge binding and session management routes.
9
+ * Mount at /api/tf on the main Hono app.
10
+ * @param options - Server options (storage, thresholds, callbacks).
11
+ * @returns A Hono sub-app with /bind, /sessions, /events, /trust-score routes.
12
+ */
13
+ export declare function createTokenForgeRoutes(options: TokenForgeServerOptions): Hono<{
14
+ Variables: Variables;
15
+ }>;
16
+ /** @deprecated Use createTokenForgeRoutes(options) instead */
17
+ export declare const tokenForgeRoutes: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
18
+ export {};
19
+ //# sourceMappingURL=binding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/server/binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,uBAAuB,EAAiB,MAAM,oBAAoB,CAAC;AAEjF,UAAU,SAAS;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC,CAsFvG;AAED,8DAA8D;AAC9D,eAAO,MAAM,gBAAgB,4EAAa,CAAC"}
@@ -0,0 +1,87 @@
1
+ import { Hono } from 'hono';
2
+ import { hashFingerprint } from './trust-score.js';
3
+ /**
4
+ * TokenForge binding and session management routes.
5
+ * Mount at /api/tf on the main Hono app.
6
+ * @param options - Server options (storage, thresholds, callbacks).
7
+ * @returns A Hono sub-app with /bind, /sessions, /events, /trust-score routes.
8
+ */
9
+ export function createTokenForgeRoutes(options) {
10
+ const tf = new Hono();
11
+ tf.post('/bind', async (c) => {
12
+ const userId = c.get('userId');
13
+ const sessionId = c.get('sessionId');
14
+ if (!userId || !sessionId)
15
+ return c.json({ error: 'unauthorized' }, 401);
16
+ const body = await c.req.json();
17
+ if (body.sessionId !== sessionId)
18
+ return c.json({ error: 'session_mismatch' }, 400);
19
+ if (!body.publicKey?.kty || body.publicKey.kty !== 'EC' || body.publicKey.crv !== 'P-256') {
20
+ return c.json({ error: 'invalid_key_format' }, 400);
21
+ }
22
+ const deviceId = crypto.randomUUID().replace(/-/g, '');
23
+ const fingerprint = hashFingerprint(body.metadata?.userAgent || '');
24
+ const expiresAt = new Date(Date.now() + options.sessionMaxAge * 1000).toISOString();
25
+ const ipAddress = options.getIpAddress?.(c.req.raw) ?? c.req.header('cf-connecting-ip') ?? '';
26
+ const countryCode = options.getCountryCode?.(c.req.raw) ?? c.req.header('cf-ipcountry') ?? '';
27
+ await options.storage.revokeUserSessions(userId);
28
+ const session = {
29
+ id: deviceId, session_id: sessionId, user_id: userId,
30
+ public_key: JSON.stringify(body.publicKey),
31
+ device_fingerprint: fingerprint, ip_address: ipAddress,
32
+ country_code: countryCode, trust_score: 100,
33
+ bound_at: new Date().toISOString(), last_verified_at: new Date().toISOString(),
34
+ expires_at: expiresAt, revoked: 0, revoked_reason: null,
35
+ created_at: new Date().toISOString(),
36
+ };
37
+ await options.storage.createSession(session);
38
+ await options.storage.logEvent({
39
+ id: crypto.randomUUID(), sessionId, userId,
40
+ eventType: 'DEVICE_BOUND', trustScoreBefore: 0, trustScoreAfter: 100,
41
+ ipAddress, countryCode,
42
+ userAgent: options.getUserAgent?.(c.req.raw) ?? c.req.header('user-agent') ?? '',
43
+ metadata: { deviceId, fingerprint, metadata: body.metadata },
44
+ });
45
+ return c.json({ deviceId, expiresAt });
46
+ });
47
+ tf.get('/sessions', async (c) => {
48
+ const userId = c.get('userId');
49
+ if (!userId)
50
+ return c.json({ error: 'unauthorized' }, 401);
51
+ const sessions = await options.storage.listUserSessions(userId, 20);
52
+ return c.json({ sessions });
53
+ });
54
+ tf.delete('/sessions/:id', async (c) => {
55
+ const userId = c.get('userId');
56
+ if (!userId)
57
+ return c.json({ error: 'unauthorized' }, 401);
58
+ await options.storage.revokeSession(c.req.param('id'), 'user_revoked');
59
+ return c.json({ revoked: true });
60
+ });
61
+ tf.get('/events', async (c) => {
62
+ const userId = c.get('userId');
63
+ if (!userId)
64
+ return c.json({ error: 'unauthorized' }, 401);
65
+ const limit = parseInt(c.req.query('limit') || '50', 10);
66
+ const offset = parseInt(c.req.query('offset') || '0', 10);
67
+ const events = await options.storage.listEvents(userId, limit, offset);
68
+ return c.json({ events });
69
+ });
70
+ tf.get('/trust-score', async (c) => {
71
+ const userId = c.get('userId');
72
+ const sessionId = c.get('sessionId');
73
+ const deviceId = c.req.header('X-TF-Device-ID');
74
+ if (!userId)
75
+ return c.json({ error: 'unauthorized' }, 401);
76
+ if (!deviceId || !sessionId)
77
+ return c.json({ trustScore: 0, isBound: false, deviceId: null });
78
+ const session = await options.storage.getSession(sessionId, deviceId);
79
+ if (!session)
80
+ return c.json({ trustScore: 0, isBound: false, deviceId: null });
81
+ return c.json({ trustScore: session.trust_score, isBound: true, deviceId });
82
+ });
83
+ return tf;
84
+ }
85
+ /** @deprecated Use createTokenForgeRoutes(options) instead */
86
+ export const tokenForgeRoutes = new Hono();
87
+ //# sourceMappingURL=binding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding.js","sourceRoot":"","sources":["../../src/server/binding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { tokenForgeMiddleware } from './middleware.js';
2
+ export type { TokenForgeOptions } from './middleware.js';
3
+ export { createTokenForgeRoutes, tokenForgeRoutes } from './binding.js';
4
+ export { createStepUpRoutes, stepUpRoutes } from './step-up.js';
5
+ export { verifyTotp, generateTotp } from './totp.js';
6
+ export type { TokenForgeStorage, StepUpChallengeRecord } from './storage/interface.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAGrD,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,6 @@
1
+ // Public API — shipped in the npm package
2
+ export { tokenForgeMiddleware } from './middleware.js';
3
+ export { createTokenForgeRoutes, tokenForgeRoutes } from './binding.js';
4
+ export { createStepUpRoutes, stepUpRoutes } from './step-up.js';
5
+ export { verifyTotp, generateTotp } from './totp.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { MiddlewareHandler } from 'hono';
2
+ /** Options for the TokenForge API-backed middleware. */
3
+ export interface TokenForgeOptions {
4
+ /** Your TokenForge API key (starts with `tf_`). */
5
+ apiKey: string;
6
+ /** API base URL (defaults to TokenForge cloud). */
7
+ apiBase?: string;
8
+ /** Paths to skip verification (e.g. ['/health', '/public/*']). */
9
+ skipPaths?: string[];
10
+ /** Paths that require elevated trust (>90). */
11
+ sensitiveOps?: string[];
12
+ /** Trust score threshold to allow (default: 80). */
13
+ allowThreshold?: number;
14
+ /** Trust score threshold for step-up (default: 40). */
15
+ stepUpThreshold?: number;
16
+ }
17
+ /**
18
+ * TokenForge Hono middleware — verifies device-bound sessions via the
19
+ * TokenForge cloud API. All verification runs server-side on TokenForge
20
+ * infrastructure.
21
+ *
22
+ * @param options - API key and optional configuration.
23
+ * @returns Hono middleware handler.
24
+ */
25
+ export declare function tokenForgeMiddleware(options: TokenForgeOptions): MiddlewareHandler;
26
+ /** @internal */
27
+ export declare function shouldSkip(path: string, skipPaths?: string[]): boolean;
28
+ /** @internal */
29
+ export declare function isSensitiveOp(path: string, method: string, sensitiveOps?: string[]): boolean;
30
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAI7D,wDAAwD;AACxD,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAcD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,iBAAiB,GACzB,iBAAiB,CAgFnB;AAED,gBAAgB;AAChB,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAMtE;AAED,gBAAgB;AAChB,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EAAE,GACtB,OAAO,CAaT"}
@@ -0,0 +1,107 @@
1
+ const DEFAULT_API_BASE = 'https://tokenforge-api.opensyber.cloud';
2
+ /**
3
+ * TokenForge Hono middleware — verifies device-bound sessions via the
4
+ * TokenForge cloud API. All verification runs server-side on TokenForge
5
+ * infrastructure.
6
+ *
7
+ * @param options - API key and optional configuration.
8
+ * @returns Hono middleware handler.
9
+ */
10
+ export function tokenForgeMiddleware(options) {
11
+ const apiBase = options.apiBase ?? DEFAULT_API_BASE;
12
+ const allowThreshold = options.allowThreshold ?? 80;
13
+ const stepUpThreshold = options.stepUpThreshold ?? 40;
14
+ return async (c, next) => {
15
+ if (shouldSkip(c.req.path, options.skipPaths))
16
+ return next();
17
+ const headers = {
18
+ signature: c.req.header('X-TF-Signature') ?? null,
19
+ nonce: c.req.header('X-TF-Nonce') ?? null,
20
+ timestamp: c.req.header('X-TF-Timestamp') ?? null,
21
+ deviceId: c.req.header('X-TF-Device-ID') ?? null,
22
+ };
23
+ // Call TokenForge API for verification
24
+ const res = await fetch(`${apiBase}/v1/edge/verify`, {
25
+ method: 'POST',
26
+ headers: {
27
+ Authorization: `Bearer ${options.apiKey}`,
28
+ 'Content-Type': 'application/json',
29
+ },
30
+ body: JSON.stringify({
31
+ path: c.req.path,
32
+ method: c.req.method,
33
+ headers,
34
+ ipAddress: c.req.header('cf-connecting-ip')
35
+ ?? c.req.header('x-forwarded-for') ?? '',
36
+ countryCode: c.req.header('cf-ipcountry') ?? '',
37
+ userAgent: c.req.header('user-agent') ?? '',
38
+ }),
39
+ });
40
+ if (!res.ok) {
41
+ // API unreachable — degrade gracefully
42
+ console.error('[TokenForge] API error:', res.status);
43
+ c.set('tf', { bound: false, trustScore: 0, deviceId: null });
44
+ return next();
45
+ }
46
+ const { data } = (await res.json());
47
+ if (data.status === 'block') {
48
+ return c.json({
49
+ error: 'session_blocked',
50
+ reason: data.reason,
51
+ trustScore: data.trustScore,
52
+ }, 401);
53
+ }
54
+ if (data.status === 'step_up') {
55
+ if (isSensitiveOp(c.req.path, c.req.method, options.sensitiveOps)) {
56
+ return c.json({
57
+ error: 'elevated_trust_required',
58
+ action: 'step_up_required',
59
+ trustScore: data.trustScore,
60
+ }, 403);
61
+ }
62
+ // Allow step-up range through for non-sensitive ops
63
+ }
64
+ if (isSensitiveOp(c.req.path, c.req.method, options.sensitiveOps)
65
+ && data.trustScore < 90) {
66
+ return c.json({
67
+ error: 'elevated_trust_required',
68
+ action: 'step_up_required',
69
+ trustScore: data.trustScore,
70
+ }, 403);
71
+ }
72
+ c.set('tf', {
73
+ bound: data.bound,
74
+ trustScore: data.trustScore,
75
+ deviceId: data.deviceId,
76
+ });
77
+ await next();
78
+ };
79
+ }
80
+ /** @internal */
81
+ export function shouldSkip(path, skipPaths) {
82
+ if (!skipPaths)
83
+ return false;
84
+ return skipPaths.some((pattern) => {
85
+ if (pattern.endsWith('*'))
86
+ return path.startsWith(pattern.slice(0, -1));
87
+ return path === pattern;
88
+ });
89
+ }
90
+ /** @internal */
91
+ export function isSensitiveOp(path, method, sensitiveOps) {
92
+ if (!sensitiveOps)
93
+ return false;
94
+ const key = `${method} ${path}`;
95
+ return sensitiveOps.some((op) => {
96
+ if (op.includes('*')) {
97
+ const parts = op.split(' ');
98
+ const opMethod = parts[0];
99
+ const opPath = parts[1];
100
+ if (opMethod !== method || !opPath)
101
+ return false;
102
+ return new RegExp('^' + opPath.replace(/\*/g, '[^/]+') + '$').test(path);
103
+ }
104
+ return key === op;
105
+ });
106
+ }
107
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { Hono } from 'hono';
2
+ import type { TokenForgeServerOptions } from '../shared/types.js';
3
+ interface Variables {
4
+ userId: string;
5
+ sessionId: string;
6
+ }
7
+ /**
8
+ * Step-up authentication routes for TokenForge.
9
+ * Mount at /api/tf/step-up on the main Hono app.
10
+ * @param options - Server options (storage, email sender, passkey verifier).
11
+ * @returns A Hono sub-app with /initiate and /complete routes.
12
+ */
13
+ export declare function createStepUpRoutes(options: TokenForgeServerOptions): Hono<{
14
+ Variables: Variables;
15
+ }>;
16
+ /** @deprecated Use createStepUpRoutes(options) instead */
17
+ export declare const stepUpRoutes: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
18
+ export {};
19
+ //# sourceMappingURL=step-up.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-up.d.ts","sourceRoot":"","sources":["../../src/server/step-up.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAIlE,UAAU,SAAS;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,uBAAuB,GAC/B,IAAI,CAAC;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC,CAiGhC;AA8DD,0DAA0D;AAC1D,eAAO,MAAM,YAAY,4EAAa,CAAC"}
@@ -0,0 +1,139 @@
1
+ import { Hono } from 'hono';
2
+ import { verifyTotp } from './totp.js';
3
+ const MAX_CHALLENGES_PER_WINDOW = 5;
4
+ const CHALLENGE_WINDOW_MINUTES = 15;
5
+ const CHALLENGE_TTL_SECONDS = 300; // 5 minutes
6
+ /**
7
+ * Step-up authentication routes for TokenForge.
8
+ * Mount at /api/tf/step-up on the main Hono app.
9
+ * @param options - Server options (storage, email sender, passkey verifier).
10
+ * @returns A Hono sub-app with /initiate and /complete routes.
11
+ */
12
+ export function createStepUpRoutes(options) {
13
+ const stepUp = new Hono();
14
+ stepUp.post('/initiate', async (c) => {
15
+ const userId = c.get('userId');
16
+ const sessionId = c.get('sessionId');
17
+ if (!userId || !sessionId)
18
+ return c.json({ error: 'unauthorized' }, 401);
19
+ const count = await options.storage.countRecentChallenges(userId, CHALLENGE_WINDOW_MINUTES);
20
+ if (count >= MAX_CHALLENGES_PER_WINDOW) {
21
+ return c.json({ error: 'rate_limited', message: 'Too many step-up attempts. Try again later.' }, 429);
22
+ }
23
+ const { method } = await c.req.json();
24
+ const challengeMethod = (method || 'totp');
25
+ const challengeId = crypto.randomUUID();
26
+ const now = new Date();
27
+ const expiresAt = new Date(now.getTime() + CHALLENGE_TTL_SECONDS * 1000).toISOString();
28
+ const challenge = {
29
+ id: challengeId, sessionId, userId,
30
+ reason: 'trust_score_drop', method: challengeMethod,
31
+ status: 'pending', expiresAt,
32
+ createdAt: now.toISOString(), completedAt: null,
33
+ };
34
+ await options.storage.createChallenge(challenge);
35
+ if (challengeMethod === 'email_otp') {
36
+ const otp = generateOtp();
37
+ await options.storage.storeOtp(challengeId, otp, CHALLENGE_TTL_SECONDS);
38
+ if (options.sendEmail) {
39
+ await options.sendEmail(userId, otp);
40
+ }
41
+ else {
42
+ throw new Error('sendEmail handler not configured — cannot deliver OTP');
43
+ }
44
+ }
45
+ if (challengeMethod === 'passkey') {
46
+ // Generate WebAuthn challenge and return it
47
+ const webauthnChallenge = generateWebAuthnChallenge();
48
+ return c.json({ challengeId, method: challengeMethod, expiresAt, webauthnChallenge });
49
+ }
50
+ return c.json({ challengeId, method: challengeMethod, expiresAt });
51
+ });
52
+ stepUp.post('/complete', async (c) => {
53
+ const userId = c.get('userId');
54
+ if (!userId)
55
+ return c.json({ error: 'unauthorized' }, 401);
56
+ const { challengeId, code, credential } = await c.req.json();
57
+ const challenge = await options.storage.getChallenge(challengeId, userId);
58
+ if (!challenge)
59
+ return c.json({ error: 'invalid_challenge' }, 400);
60
+ if (new Date(challenge.expiresAt) < new Date()) {
61
+ await options.storage.updateChallengeStatus(challengeId, 'expired');
62
+ return c.json({ error: 'challenge_expired' }, 400);
63
+ }
64
+ let verified = false;
65
+ if (challenge.method === 'email_otp') {
66
+ const storedOtp = await options.storage.getOtp(challengeId);
67
+ verified = storedOtp !== null && storedOtp === code;
68
+ if (verified)
69
+ await options.storage.deleteOtp(challengeId);
70
+ }
71
+ else if (challenge.method === 'totp' && code) {
72
+ verified = await verifyTotp(code, userId, options);
73
+ }
74
+ else if (challenge.method === 'passkey' && credential) {
75
+ const storedKey = options.getPasskeyPublicKey
76
+ ? await options.getPasskeyPublicKey(userId, credential.id)
77
+ : null;
78
+ if (storedKey) {
79
+ verified = await verifyPasskeyCredential(credential, storedKey, challengeId);
80
+ }
81
+ }
82
+ if (!verified) {
83
+ await options.storage.updateChallengeStatus(challengeId, 'failed');
84
+ return c.json({ error: 'verification_failed' }, 401);
85
+ }
86
+ await options.storage.updateChallengeStatus(challengeId, 'completed', new Date().toISOString());
87
+ const deviceId = c.req.header('X-TF-Device-ID');
88
+ if (deviceId) {
89
+ await options.storage.restoreTrust(deviceId, userId);
90
+ }
91
+ return c.json({ verified: true, trustScore: 100 });
92
+ });
93
+ return stepUp;
94
+ }
95
+ /** Generate a 6-digit OTP using CSPRNG */
96
+ function generateOtp() {
97
+ const randomBytes = new Uint32Array(1);
98
+ crypto.getRandomValues(randomBytes);
99
+ return ((randomBytes[0] % 900000) + 100000).toString();
100
+ }
101
+ /** Generate a WebAuthn challenge (32 random bytes, base64url encoded) */
102
+ function generateWebAuthnChallenge() {
103
+ const bytes = new Uint8Array(32);
104
+ crypto.getRandomValues(bytes);
105
+ return btoa(String.fromCharCode(...bytes))
106
+ .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
107
+ }
108
+ /**
109
+ * Verify a WebAuthn passkey credential against the stored public key.
110
+ * Uses ECDSA P-256 signature verification via Web Crypto API.
111
+ */
112
+ async function verifyPasskeyCredential(credential, publicKeySpki, expectedChallenge) {
113
+ try {
114
+ if (!credential.id || !credential.response?.signature || !credential.response?.authenticatorData) {
115
+ return false;
116
+ }
117
+ const clientDataJSON = atob(credential.response.clientDataJSON);
118
+ const clientData = JSON.parse(clientDataJSON);
119
+ if (clientData.type !== 'webauthn.get')
120
+ return false;
121
+ const decodedChallenge = atob(clientData.challenge?.replace(/-/g, '+').replace(/_/g, '/') ?? '');
122
+ if (decodedChallenge !== expectedChallenge)
123
+ return false;
124
+ const key = await crypto.subtle.importKey('spki', publicKeySpki, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']);
125
+ const authData = Uint8Array.from(atob(credential.response.authenticatorData), (ch) => ch.charCodeAt(0));
126
+ const clientDataHash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(clientDataJSON));
127
+ const signedData = new Uint8Array(authData.length + clientDataHash.byteLength);
128
+ signedData.set(authData, 0);
129
+ signedData.set(new Uint8Array(clientDataHash), authData.length);
130
+ const sigBytes = Uint8Array.from(atob(credential.response.signature), (ch) => ch.charCodeAt(0));
131
+ return await crypto.subtle.verify({ name: 'ECDSA', hash: 'SHA-256' }, key, sigBytes, signedData);
132
+ }
133
+ catch {
134
+ return false;
135
+ }
136
+ }
137
+ /** @deprecated Use createStepUpRoutes(options) instead */
138
+ export const stepUpRoutes = new Hono();
139
+ //# sourceMappingURL=step-up.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-up.js","sourceRoot":"","sources":["../../src/server/step-up.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export type { TokenForgeStorage, StepUpChallengeRecord } from './interface.js';
2
+ export { MemoryStorage } from './memory.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/storage/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { MemoryStorage } from './memory.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/storage/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,61 @@
1
+ import type { DeviceSession, SecurityEvent } from '../../shared/types.js';
2
+ /**
3
+ * Storage interface for TokenForge server.
4
+ * Implement this to use any database/cache backend.
5
+ */
6
+ export interface TokenForgeStorage {
7
+ /** Find an active (non-revoked) session by sessionId + deviceId */
8
+ getSession(sessionId: string, deviceId: string): Promise<DeviceSession | null>;
9
+ /** Create a new device session */
10
+ createSession(session: DeviceSession): Promise<void>;
11
+ /** Update trust score and last_verified_at for a session */
12
+ updateTrustScore(deviceId: string, trustScore: number): Promise<void>;
13
+ /** Mark a session as revoked */
14
+ revokeSession(deviceId: string, reason: string): Promise<void>;
15
+ /** Revoke all sessions for a user (called before re-binding) */
16
+ revokeUserSessions(userId: string): Promise<void>;
17
+ /** List a user's sessions (most recent first) */
18
+ listUserSessions(userId: string, limit: number): Promise<DeviceSession[]>;
19
+ /** Restore trust score to 100 after step-up */
20
+ restoreTrust(deviceId: string, userId: string): Promise<void>;
21
+ /** Check if nonce has been used */
22
+ hasNonce(nonce: string): Promise<boolean>;
23
+ /** Store a used nonce with TTL in seconds */
24
+ storeNonce(nonce: string, ttlSeconds: number): Promise<void>;
25
+ /** Insert a security event record */
26
+ logEvent(event: SecurityEvent & {
27
+ id: string;
28
+ }): Promise<void>;
29
+ /** List security events for a user (for dashboard) */
30
+ listEvents(userId: string, limit: number, offset: number): Promise<(SecurityEvent & {
31
+ id: string;
32
+ created_at: string;
33
+ })[]>;
34
+ /** Create a step-up challenge */
35
+ createChallenge(challenge: StepUpChallengeRecord): Promise<void>;
36
+ /** Get a pending challenge by ID + userId */
37
+ getChallenge(challengeId: string, userId: string): Promise<StepUpChallengeRecord | null>;
38
+ /** Update challenge status */
39
+ updateChallengeStatus(challengeId: string, status: string, completedAt?: string): Promise<void>;
40
+ /** Count recent challenges for rate limiting */
41
+ countRecentChallenges(userId: string, windowMinutes: number): Promise<number>;
42
+ /** Store OTP code for a challenge with TTL */
43
+ storeOtp(challengeId: string, code: string, ttlSeconds: number): Promise<void>;
44
+ /** Retrieve and consume OTP code */
45
+ getOtp(challengeId: string): Promise<string | null>;
46
+ /** Delete OTP after verification */
47
+ deleteOtp(challengeId: string): Promise<void>;
48
+ }
49
+ /** Step-up challenge stored in database */
50
+ export interface StepUpChallengeRecord {
51
+ id: string;
52
+ sessionId: string;
53
+ userId: string;
54
+ reason: string;
55
+ method: 'totp' | 'email_otp' | 'passkey';
56
+ status: 'pending' | 'completed' | 'expired' | 'failed';
57
+ expiresAt: string;
58
+ createdAt: string;
59
+ completedAt: string | null;
60
+ }
61
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../../src/server/storage/interface.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../../src/server/storage/interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,40 @@
1
+ import type { TokenForgeStorage, StepUpChallengeRecord } from './interface.js';
2
+ import type { DeviceSession, SecurityEvent } from '../../shared/types.js';
3
+ /**
4
+ * In-memory storage for testing and development.
5
+ * Not suitable for production — data is lost on restart.
6
+ */
7
+ export declare class MemoryStorage implements TokenForgeStorage {
8
+ sessions: DeviceSession[];
9
+ events: (SecurityEvent & {
10
+ id: string;
11
+ created_at: string;
12
+ })[];
13
+ challenges: StepUpChallengeRecord[];
14
+ private nonces;
15
+ private otps;
16
+ getSession(sessionId: string, deviceId: string): Promise<DeviceSession | null>;
17
+ createSession(session: DeviceSession): Promise<void>;
18
+ updateTrustScore(deviceId: string, trustScore: number): Promise<void>;
19
+ revokeSession(deviceId: string, reason: string): Promise<void>;
20
+ revokeUserSessions(userId: string): Promise<void>;
21
+ listUserSessions(userId: string, limit: number): Promise<DeviceSession[]>;
22
+ restoreTrust(deviceId: string, userId: string): Promise<void>;
23
+ hasNonce(nonce: string): Promise<boolean>;
24
+ storeNonce(nonce: string, ttlSeconds: number): Promise<void>;
25
+ logEvent(event: SecurityEvent & {
26
+ id: string;
27
+ }): Promise<void>;
28
+ listEvents(userId: string, limit: number, offset: number): Promise<(SecurityEvent & {
29
+ id: string;
30
+ created_at: string;
31
+ })[]>;
32
+ createChallenge(challenge: StepUpChallengeRecord): Promise<void>;
33
+ getChallenge(challengeId: string, userId: string): Promise<StepUpChallengeRecord | null>;
34
+ updateChallengeStatus(challengeId: string, status: string, completedAt?: string): Promise<void>;
35
+ countRecentChallenges(userId: string, windowMinutes: number): Promise<number>;
36
+ storeOtp(challengeId: string, code: string, ttlSeconds: number): Promise<void>;
37
+ getOtp(challengeId: string): Promise<string | null>;
38
+ deleteOtp(challengeId: string): Promise<void>;
39
+ }
40
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/server/storage/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE1E;;;GAGG;AACH,qBAAa,aAAc,YAAW,iBAAiB;IACrD,QAAQ,EAAE,aAAa,EAAE,CAAM;IAC/B,MAAM,EAAE,CAAC,aAAa,GAAG;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAM;IACpE,UAAU,EAAE,qBAAqB,EAAE,CAAM;IACzC,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,IAAI,CAA0D;IAEhE,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAM9E,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrE,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9D,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjD,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAOzE,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUzC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5D,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,aAAa,GAAG;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAO1H,eAAe,CAAC,SAAS,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhE,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAMxF,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/F,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO7E,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9E,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAUnD,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGpD"}