@c9up/warden 0.1.3 → 0.1.4

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 (134) hide show
  1. package/dist/AuthManager.d.ts +98 -0
  2. package/dist/AuthManager.d.ts.map +1 -0
  3. package/dist/AuthManager.js +147 -0
  4. package/dist/AuthManager.js.map +1 -0
  5. package/dist/AuthRateLimiter.d.ts +29 -0
  6. package/dist/AuthRateLimiter.d.ts.map +1 -0
  7. package/dist/AuthRateLimiter.js +88 -0
  8. package/dist/AuthRateLimiter.js.map +1 -0
  9. package/dist/Guard.d.ts +26 -0
  10. package/dist/Guard.d.ts.map +1 -0
  11. package/dist/Guard.js +52 -0
  12. package/dist/Guard.js.map +1 -0
  13. package/dist/RefreshTokenStore.d.ts +34 -0
  14. package/dist/RefreshTokenStore.d.ts.map +1 -0
  15. package/dist/RefreshTokenStore.js +48 -0
  16. package/dist/RefreshTokenStore.js.map +1 -0
  17. package/dist/TokenBlacklist.d.ts +30 -0
  18. package/dist/TokenBlacklist.d.ts.map +1 -0
  19. package/dist/TokenBlacklist.js +50 -0
  20. package/dist/TokenBlacklist.js.map +1 -0
  21. package/dist/WardenProvider.d.ts +19 -0
  22. package/dist/WardenProvider.d.ts.map +1 -0
  23. package/dist/WardenProvider.js +61 -0
  24. package/dist/WardenProvider.js.map +1 -0
  25. package/dist/bouncer/AuthorizationResponse.d.ts +25 -0
  26. package/dist/bouncer/AuthorizationResponse.d.ts.map +1 -0
  27. package/dist/bouncer/AuthorizationResponse.js +31 -0
  28. package/dist/bouncer/AuthorizationResponse.js.map +1 -0
  29. package/dist/bouncer/BasePolicy.d.ts +47 -0
  30. package/dist/bouncer/BasePolicy.d.ts.map +1 -0
  31. package/dist/bouncer/BasePolicy.js +36 -0
  32. package/dist/bouncer/BasePolicy.js.map +1 -0
  33. package/dist/bouncer/Bouncer.d.ts +47 -0
  34. package/dist/bouncer/Bouncer.d.ts.map +1 -0
  35. package/dist/bouncer/Bouncer.js +134 -0
  36. package/dist/bouncer/Bouncer.js.map +1 -0
  37. package/dist/bouncer/PolicyAuthorizer.d.ts +24 -0
  38. package/dist/bouncer/PolicyAuthorizer.d.ts.map +1 -0
  39. package/dist/bouncer/PolicyAuthorizer.js +92 -0
  40. package/dist/bouncer/PolicyAuthorizer.js.map +1 -0
  41. package/dist/bouncer/decorators.d.ts +25 -0
  42. package/dist/bouncer/decorators.d.ts.map +1 -0
  43. package/dist/bouncer/decorators.js +36 -0
  44. package/dist/bouncer/decorators.js.map +1 -0
  45. package/dist/bouncer/evaluate.d.ts +36 -0
  46. package/dist/bouncer/evaluate.d.ts.map +1 -0
  47. package/dist/bouncer/evaluate.js +64 -0
  48. package/dist/bouncer/evaluate.js.map +1 -0
  49. package/dist/bouncer/policyContext.d.ts +29 -0
  50. package/dist/bouncer/policyContext.d.ts.map +1 -0
  51. package/dist/bouncer/policyContext.js +36 -0
  52. package/dist/bouncer/policyContext.js.map +1 -0
  53. package/dist/bouncer/types.d.ts +52 -0
  54. package/dist/bouncer/types.d.ts.map +1 -0
  55. package/dist/bouncer/types.js +9 -0
  56. package/dist/bouncer/types.js.map +1 -0
  57. package/dist/config.d.ts +42 -0
  58. package/dist/config.d.ts.map +1 -0
  59. package/dist/config.js +21 -0
  60. package/dist/config.js.map +1 -0
  61. package/dist/configure.d.ts +10 -0
  62. package/dist/configure.d.ts.map +1 -0
  63. package/dist/configure.js +44 -0
  64. package/dist/configure.js.map +1 -0
  65. package/dist/errors.d.ts +18 -0
  66. package/dist/errors.d.ts.map +1 -0
  67. package/dist/errors.js +21 -0
  68. package/dist/errors.js.map +1 -0
  69. package/dist/firstcontact/FirstContactManager.d.ts +25 -0
  70. package/dist/firstcontact/FirstContactManager.d.ts.map +1 -0
  71. package/dist/firstcontact/FirstContactManager.js +38 -0
  72. package/dist/firstcontact/FirstContactManager.js.map +1 -0
  73. package/dist/firstcontact/drivers/GitHubDriver.d.ts +14 -0
  74. package/dist/firstcontact/drivers/GitHubDriver.d.ts.map +1 -0
  75. package/dist/firstcontact/drivers/GitHubDriver.js +61 -0
  76. package/dist/firstcontact/drivers/GitHubDriver.js.map +1 -0
  77. package/dist/firstcontact/drivers/GoogleDriver.d.ts +14 -0
  78. package/dist/firstcontact/drivers/GoogleDriver.d.ts.map +1 -0
  79. package/dist/firstcontact/drivers/GoogleDriver.js +64 -0
  80. package/dist/firstcontact/drivers/GoogleDriver.js.map +1 -0
  81. package/dist/firstcontact/types.d.ts +34 -0
  82. package/dist/firstcontact/types.d.ts.map +1 -0
  83. package/dist/firstcontact/types.js +5 -0
  84. package/dist/firstcontact/types.js.map +1 -0
  85. package/dist/index.d.ts +38 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +27 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/middleware.d.ts +51 -0
  90. package/dist/middleware.d.ts.map +1 -0
  91. package/dist/middleware.js +201 -0
  92. package/dist/middleware.js.map +1 -0
  93. package/dist/native.d.ts +14 -0
  94. package/dist/native.d.ts.map +1 -0
  95. package/dist/native.js +39 -0
  96. package/dist/native.js.map +1 -0
  97. package/dist/rights/MemoryRightsStore.d.ts +29 -0
  98. package/dist/rights/MemoryRightsStore.d.ts.map +1 -0
  99. package/dist/rights/MemoryRightsStore.js +70 -0
  100. package/dist/rights/MemoryRightsStore.js.map +1 -0
  101. package/dist/rights/RightsResolver.d.ts +29 -0
  102. package/dist/rights/RightsResolver.d.ts.map +1 -0
  103. package/dist/rights/RightsResolver.js +73 -0
  104. package/dist/rights/RightsResolver.js.map +1 -0
  105. package/dist/rights/types.d.ts +55 -0
  106. package/dist/rights/types.d.ts.map +1 -0
  107. package/dist/rights/types.js +18 -0
  108. package/dist/rights/types.js.map +1 -0
  109. package/dist/services/main.d.ts +19 -0
  110. package/dist/services/main.d.ts.map +1 -0
  111. package/dist/services/main.js +32 -0
  112. package/dist/services/main.js.map +1 -0
  113. package/dist/standalone.d.ts +37 -0
  114. package/dist/standalone.d.ts.map +1 -0
  115. package/dist/standalone.js +92 -0
  116. package/dist/standalone.js.map +1 -0
  117. package/dist/strategies/ApiKeyStrategy.d.ts +28 -0
  118. package/dist/strategies/ApiKeyStrategy.d.ts.map +1 -0
  119. package/dist/strategies/ApiKeyStrategy.js +36 -0
  120. package/dist/strategies/ApiKeyStrategy.js.map +1 -0
  121. package/dist/strategies/JwtStrategy.d.ts +51 -0
  122. package/dist/strategies/JwtStrategy.d.ts.map +1 -0
  123. package/dist/strategies/JwtStrategy.js +150 -0
  124. package/dist/strategies/JwtStrategy.js.map +1 -0
  125. package/dist/strategies/SessionStrategy.d.ts +58 -0
  126. package/dist/strategies/SessionStrategy.d.ts.map +1 -0
  127. package/dist/strategies/SessionStrategy.js +70 -0
  128. package/dist/strategies/SessionStrategy.js.map +1 -0
  129. package/index.darwin-arm64.node +0 -0
  130. package/index.darwin-x64.node +0 -0
  131. package/index.linux-arm64-gnu.node +0 -0
  132. package/index.linux-x64-gnu.node +0 -0
  133. package/index.win32-x64-msvc.node +0 -0
  134. package/package.json +1 -1
@@ -0,0 +1,98 @@
1
+ /**
2
+ * AuthManager — manages multiple authentication strategies.
3
+ *
4
+ * @implements FR48, FR50, FR51
5
+ */
6
+ import { RightsResolver } from "./rights/RightsResolver.js";
7
+ import type { EffectivePermissions, Scope } from "./rights/types.js";
8
+ export interface UserPayload {
9
+ id: string;
10
+ roles?: string[];
11
+ permissions?: string[];
12
+ [key: string]: unknown;
13
+ }
14
+ export interface AuthResult {
15
+ authenticated: boolean;
16
+ user?: UserPayload;
17
+ error?: string;
18
+ /**
19
+ * @internal Set when the strategy's `verify()` / `authenticate()` THREW
20
+ * a generic error (vs returned a deliberate `{ authenticated: false }`
21
+ * rejection). The middleware uses this to distinguish credential
22
+ * failures (→ 401) from strategy crashes (→ 500). Not part of the
23
+ * public consumer-facing API.
24
+ */
25
+ strategyCrash?: true;
26
+ }
27
+ export interface AuthStrategy {
28
+ name: string;
29
+ authenticate(credentials: Record<string, unknown>): Promise<AuthResult>;
30
+ verify(token: string, context?: Record<string, unknown>): Promise<AuthResult>;
31
+ }
32
+ export interface AuthConfig {
33
+ defaultStrategy: string;
34
+ strategies: Record<string, AuthStrategy>;
35
+ /**
36
+ * The rights resolver backing the coarse RBAC helpers (Epic 56). When
37
+ * absent, a default `RightsResolver(new MemoryRightsStore())` is used so
38
+ * `new AuthManager({ defaultStrategy, strategies })` keeps working — with
39
+ * an empty store, payload roles still fold in (D2) and permissions are
40
+ * empty (token `user.permissions` is not an input — D1).
41
+ */
42
+ rights?: RightsResolver;
43
+ }
44
+ /**
45
+ * Manages authentication strategies and provides guard/permission checks.
46
+ */
47
+ export declare class AuthManager {
48
+ private strategies;
49
+ private defaultStrategy;
50
+ private readonly rights;
51
+ constructor(config: AuthConfig);
52
+ /** Authenticate with credentials using a specific or default strategy. */
53
+ authenticate(credentials: Record<string, unknown>, strategyName?: string): Promise<AuthResult>;
54
+ /** Verify a token (JWT, session, API key). */
55
+ verify(token: string, strategyName?: string, context?: Record<string, unknown>): Promise<AuthResult>;
56
+ /**
57
+ * Resolve a user's effective permissions for a scope (Epic 56). The single
58
+ * resolution entry the coarse helpers wrap — `hasRole`/`hasPermission`/
59
+ * `hasAllPermissions` read this set, never the token payload directly. The
60
+ * Bouncer policy path (`this.permissions`, 56.3) consults the SAME resolver,
61
+ * so a coarse question and a policy question return the same answer for the
62
+ * same `(user, scope)` (the single unification point — AC-E3).
63
+ */
64
+ resolvePermissions(user: UserPayload, scope?: Scope): Promise<EffectivePermissions>;
65
+ /**
66
+ * Check if a user has a specific role within a scope (default `"global"`).
67
+ * Reflects payload roles ∪ store roles (D2) — a token-carried role still
68
+ * satisfies it with no store config.
69
+ */
70
+ hasRole(user: UserPayload, role: string, scope?: Scope): Promise<boolean>;
71
+ /**
72
+ * Check if a user has a specific permission within a scope (default
73
+ * `"global"`). Derived from roles + store grants ONLY — token
74
+ * `user.permissions` is NOT read (D1, cerebrum 459).
75
+ */
76
+ hasPermission(user: UserPayload, permission: string, scope?: Scope): Promise<boolean>;
77
+ /**
78
+ * Check if a user has ALL required permissions within a scope (default
79
+ * `"global"`). Empty list ⇒ vacuously true.
80
+ */
81
+ hasAllPermissions(user: UserPayload, permissions: string[], scope?: Scope): Promise<boolean>;
82
+ /** Get a registered strategy by name. */
83
+ getStrategy(name?: string): AuthStrategy;
84
+ /** Register a new strategy at runtime. */
85
+ registerStrategy(name: string, strategy: AuthStrategy): void;
86
+ /** Get all registered strategy names. */
87
+ getStrategyNames(): string[];
88
+ }
89
+ /** Strip dangerous prototype-pollution keys from user payload. */
90
+ /**
91
+ * Strip prototype-pollution keys from a user payload before it's
92
+ * attached to the request. Exported so the middleware can apply it to
93
+ * the session path too — session auth goes through `verifyWithContext`
94
+ * directly (not `AuthManager.verify`), so without this it would skip
95
+ * the guard JWT / api-key users get.
96
+ */
97
+ export declare function sanitizePayload(user: UserPayload): void;
98
+ //# sourceMappingURL=AuthManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthManager.d.ts","sourceRoot":"","sources":["../src/AuthManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAErE,MAAM,WAAW,WAAW;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACxE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC9E;AAED,MAAM,WAAW,UAAU;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACzC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;CACxB;AAED;;GAEG;AACH,qBAAa,WAAW;IACvB,OAAO,CAAC,UAAU,CAAwC;IAC1D,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;gBAE5B,MAAM,EAAE,UAAU;IA0B9B,0EAA0E;IACpE,YAAY,CACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,YAAY,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,UAAU,CAAC;IAmBtB,8CAA8C;IACxC,MAAM,CACX,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,UAAU,CAAC;IAoBtB;;;;;;;OAOG;IACH,kBAAkB,CACjB,IAAI,EAAE,WAAW,EACjB,KAAK,GAAE,KAAgB,GACrB,OAAO,CAAC,oBAAoB,CAAC;IAIhC;;;;OAIG;IACG,OAAO,CACZ,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,KAAgB,GACrB,OAAO,CAAC,OAAO,CAAC;IAInB;;;;OAIG;IACG,aAAa,CAClB,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,KAAgB,GACrB,OAAO,CAAC,OAAO,CAAC;IAInB;;;OAGG;IACG,iBAAiB,CACtB,IAAI,EAAE,WAAW,EACjB,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,GAAE,KAAgB,GACrB,OAAO,CAAC,OAAO,CAAC;IAInB,yCAAyC;IACzC,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,YAAY;IAexC,0CAA0C;IAC1C,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI;IAI5D,yCAAyC;IACzC,gBAAgB,IAAI,MAAM,EAAE;CAG5B;AAED,kEAAkE;AAClE;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAMvD"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * AuthManager — manages multiple authentication strategies.
3
+ *
4
+ * @implements FR48, FR50, FR51
5
+ */
6
+ import { WardenError } from "./errors.js";
7
+ import { MemoryRightsStore } from "./rights/MemoryRightsStore.js";
8
+ import { RightsResolver } from "./rights/RightsResolver.js";
9
+ /**
10
+ * Manages authentication strategies and provides guard/permission checks.
11
+ */
12
+ export class AuthManager {
13
+ strategies = new Map();
14
+ defaultStrategy;
15
+ rights;
16
+ constructor(config) {
17
+ this.defaultStrategy = config.defaultStrategy;
18
+ this.rights = config.rights ?? new RightsResolver(new MemoryRightsStore());
19
+ for (const [name, strategy] of Object.entries(config.strategies)) {
20
+ this.strategies.set(name, strategy);
21
+ }
22
+ // Fail-fast at construction: an AuthManager with zero strategies
23
+ // is a configuration bug. Previously, an empty `strategies: {}`
24
+ // passed the constructor cleanly and the first protected request
25
+ // crashed at runtime when `getStrategy('jwt')` threw — opaque 401
26
+ // or 500 instead of a boot-time INVALID_CONFIG that points the
27
+ // operator at the missing `config.auth.jwt` (or other strategy).
28
+ if (Object.keys(config.strategies).length === 0) {
29
+ throw new WardenError("INVALID_CONFIG", `AuthManager: no authentication strategies registered. Configure at least one strategy (e.g. config.warden.auth.jwt) before booting WardenProvider.`);
30
+ }
31
+ if (!this.strategies.has(config.defaultStrategy)) {
32
+ throw new WardenError("INVALID_CONFIG", `defaultStrategy '${config.defaultStrategy}' is not present in strategies`);
33
+ }
34
+ }
35
+ /** Authenticate with credentials using a specific or default strategy. */
36
+ async authenticate(credentials, strategyName) {
37
+ const strategy = this.getStrategy(strategyName);
38
+ try {
39
+ const result = await strategy.authenticate(credentials);
40
+ if (result.user)
41
+ sanitizePayload(result.user);
42
+ return result;
43
+ }
44
+ catch (err) {
45
+ // Re-throw structured WardenError sentinels (e.g. SessionStrategy's
46
+ // USE_LOGIN throw) so callers see the design-boundary signal instead
47
+ // of a soft `{ authenticated: false }`. Generic errors stay soft.
48
+ if (err instanceof WardenError)
49
+ throw err;
50
+ return {
51
+ authenticated: false,
52
+ error: err instanceof Error ? err.message : "Unknown authentication error",
53
+ };
54
+ }
55
+ }
56
+ /** Verify a token (JWT, session, API key). */
57
+ async verify(token, strategyName, context) {
58
+ const strategy = this.getStrategy(strategyName);
59
+ try {
60
+ const result = await strategy.verify(token, context);
61
+ if (result.user)
62
+ sanitizePayload(result.user);
63
+ return result;
64
+ }
65
+ catch (err) {
66
+ // Mirror authenticate(): rethrow structured WardenError sentinels;
67
+ // soft-fail generic throws but TAG them as strategy crashes so the
68
+ // middleware can flip 401 → 500 when every attempted strategy bombed.
69
+ if (err instanceof WardenError)
70
+ throw err;
71
+ return {
72
+ authenticated: false,
73
+ error: err instanceof Error ? err.message : "Unknown verification error",
74
+ strategyCrash: true,
75
+ };
76
+ }
77
+ }
78
+ /**
79
+ * Resolve a user's effective permissions for a scope (Epic 56). The single
80
+ * resolution entry the coarse helpers wrap — `hasRole`/`hasPermission`/
81
+ * `hasAllPermissions` read this set, never the token payload directly. The
82
+ * Bouncer policy path (`this.permissions`, 56.3) consults the SAME resolver,
83
+ * so a coarse question and a policy question return the same answer for the
84
+ * same `(user, scope)` (the single unification point — AC-E3).
85
+ */
86
+ resolvePermissions(user, scope = "global") {
87
+ return this.rights.resolve(user, scope);
88
+ }
89
+ /**
90
+ * Check if a user has a specific role within a scope (default `"global"`).
91
+ * Reflects payload roles ∪ store roles (D2) — a token-carried role still
92
+ * satisfies it with no store config.
93
+ */
94
+ async hasRole(user, role, scope = "global") {
95
+ return (await this.resolvePermissions(user, scope)).roles.has(role);
96
+ }
97
+ /**
98
+ * Check if a user has a specific permission within a scope (default
99
+ * `"global"`). Derived from roles + store grants ONLY — token
100
+ * `user.permissions` is NOT read (D1, cerebrum 459).
101
+ */
102
+ async hasPermission(user, permission, scope = "global") {
103
+ return (await this.resolvePermissions(user, scope)).has(permission);
104
+ }
105
+ /**
106
+ * Check if a user has ALL required permissions within a scope (default
107
+ * `"global"`). Empty list ⇒ vacuously true.
108
+ */
109
+ async hasAllPermissions(user, permissions, scope = "global") {
110
+ return (await this.resolvePermissions(user, scope)).hasAll(permissions);
111
+ }
112
+ /** Get a registered strategy by name. */
113
+ getStrategy(name) {
114
+ const strategyName = name ?? this.defaultStrategy;
115
+ const strategy = this.strategies.get(strategyName);
116
+ if (!strategy) {
117
+ throw new WardenError("STRATEGY_NOT_FOUND", `Auth strategy '${strategyName}' not registered`, {
118
+ hint: "Call registerStrategy() before using this strategy name.",
119
+ });
120
+ }
121
+ return strategy;
122
+ }
123
+ /** Register a new strategy at runtime. */
124
+ registerStrategy(name, strategy) {
125
+ this.strategies.set(name, strategy);
126
+ }
127
+ /** Get all registered strategy names. */
128
+ getStrategyNames() {
129
+ return [...this.strategies.keys()];
130
+ }
131
+ }
132
+ /** Strip dangerous prototype-pollution keys from user payload. */
133
+ /**
134
+ * Strip prototype-pollution keys from a user payload before it's
135
+ * attached to the request. Exported so the middleware can apply it to
136
+ * the session path too — session auth goes through `verifyWithContext`
137
+ * directly (not `AuthManager.verify`), so without this it would skip
138
+ * the guard JWT / api-key users get.
139
+ */
140
+ export function sanitizePayload(user) {
141
+ for (const key of ["__proto__", "constructor", "prototype"]) {
142
+ if (key in user) {
143
+ delete user[key];
144
+ }
145
+ }
146
+ }
147
+ //# sourceMappingURL=AuthManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthManager.js","sourceRoot":"","sources":["../src/AuthManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * AuthRateLimiter — brute force protection for login endpoints.
3
+ *
4
+ * Dual-key rate limiting: IP + email to prevent distributed attacks.
5
+ *
6
+ * @implements MISS-26
7
+ */
8
+ export interface AuthRateLimiterConfig {
9
+ maxAttempts?: number;
10
+ windowSeconds?: number;
11
+ }
12
+ export declare class AuthRateLimiter {
13
+ private maxAttempts;
14
+ private window;
15
+ private store;
16
+ private maxStoreSize;
17
+ constructor(config?: AuthRateLimiterConfig);
18
+ /** Check if an attempt is allowed. Returns false if rate limited. */
19
+ check(ip: string, identifier: string): boolean;
20
+ /** Record a failed attempt. */
21
+ recordFailure(ip: string, identifier: string): void;
22
+ /** Reset counters on successful login. */
23
+ recordSuccess(ip: string, identifier: string): void;
24
+ /** Get remaining attempts for an identifier. */
25
+ remaining(ip: string, identifier: string): number;
26
+ private checkKey;
27
+ private increment;
28
+ }
29
+ //# sourceMappingURL=AuthRateLimiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthRateLimiter.d.ts","sourceRoot":"","sources":["../src/AuthRateLimiter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,qBAAqB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAOD,qBAAa,eAAe;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAwC;IACrD,OAAO,CAAC,YAAY,CAAW;gBAEnB,MAAM,CAAC,EAAE,qBAAqB;IAO1C,qEAAqE;IACrE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO;IAW9C,+BAA+B;IAC/B,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAQnD,0CAA0C;IAC1C,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAOnD,gDAAgD;IAChD,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;IAcjD,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,SAAS;CAejB"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * AuthRateLimiter — brute force protection for login endpoints.
3
+ *
4
+ * Dual-key rate limiting: IP + email to prevent distributed attacks.
5
+ *
6
+ * @implements MISS-26
7
+ */
8
+ export class AuthRateLimiter {
9
+ maxAttempts;
10
+ window;
11
+ store = new Map();
12
+ maxStoreSize = 100_000;
13
+ constructor(config) {
14
+ this.maxAttempts = config?.maxAttempts ?? 5;
15
+ if (this.maxAttempts <= 0)
16
+ this.maxAttempts = 1;
17
+ this.window = (config?.windowSeconds ?? 900) * 1000;
18
+ if (this.window <= 0)
19
+ this.window = 900_000; // prevent bypass via 0/negative
20
+ }
21
+ /** Check if an attempt is allowed. Returns false if rate limited. */
22
+ check(ip, identifier) {
23
+ const now = Date.now();
24
+ const ipNorm = normalizeIp(ip);
25
+ const identifierNorm = normalizeIdentifier(identifier);
26
+ // Dual key: limit both by IP and by identifier (email)
27
+ const ipKey = `ip:${ipNorm}`;
28
+ const idKey = `id:${identifierNorm}`;
29
+ return this.checkKey(ipKey, now) && this.checkKey(idKey, now);
30
+ }
31
+ /** Record a failed attempt. */
32
+ recordFailure(ip, identifier) {
33
+ const now = Date.now();
34
+ const ipNorm = normalizeIp(ip);
35
+ const identifierNorm = normalizeIdentifier(identifier);
36
+ this.increment(`ip:${ipNorm}`, now);
37
+ this.increment(`id:${identifierNorm}`, now);
38
+ }
39
+ /** Reset counters on successful login. */
40
+ recordSuccess(ip, identifier) {
41
+ const ipNorm = normalizeIp(ip);
42
+ const identifierNorm = normalizeIdentifier(identifier);
43
+ this.store.delete(`ip:${ipNorm}`);
44
+ this.store.delete(`id:${identifierNorm}`);
45
+ }
46
+ /** Get remaining attempts for an identifier. */
47
+ remaining(ip, identifier) {
48
+ const ipNorm = normalizeIp(ip);
49
+ const identifierNorm = normalizeIdentifier(identifier);
50
+ const ipEntry = this.store.get(`ip:${ipNorm}`);
51
+ const idEntry = this.store.get(`id:${identifierNorm}`);
52
+ const ipRemaining = ipEntry
53
+ ? Math.max(0, this.maxAttempts - ipEntry.count)
54
+ : this.maxAttempts;
55
+ const idRemaining = idEntry
56
+ ? Math.max(0, this.maxAttempts - idEntry.count)
57
+ : this.maxAttempts;
58
+ return Math.min(ipRemaining, idRemaining);
59
+ }
60
+ checkKey(key, now) {
61
+ const entry = this.store.get(key);
62
+ if (!entry || entry.resetAt < now)
63
+ return true;
64
+ return entry.count < this.maxAttempts;
65
+ }
66
+ increment(key, now) {
67
+ // Evict expired entries when store grows too large (prevent OOM)
68
+ if (this.store.size > this.maxStoreSize) {
69
+ for (const [k, v] of this.store) {
70
+ if (v.resetAt < now)
71
+ this.store.delete(k);
72
+ }
73
+ }
74
+ let entry = this.store.get(key);
75
+ if (!entry || entry.resetAt < now) {
76
+ entry = { count: 0, resetAt: now + this.window };
77
+ this.store.set(key, entry);
78
+ }
79
+ entry.count++;
80
+ }
81
+ }
82
+ function normalizeIdentifier(identifier) {
83
+ return identifier.trim().toLowerCase();
84
+ }
85
+ function normalizeIp(ip) {
86
+ return ip.trim();
87
+ }
88
+ //# sourceMappingURL=AuthRateLimiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthRateLimiter.js","sourceRoot":"","sources":["../src/AuthRateLimiter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,MAAM,OAAO,eAAe;IACnB,WAAW,CAAS;IACpB,MAAM,CAAS;IACf,KAAK,GAA8B,IAAI,GAAG,EAAE,CAAC;IAC7C,YAAY,GAAG,OAAO,CAAC;IAE/B,YAAY,MAA8B;QACzC,IAAI,CAAC,WAAW,GAAG,MAAM,EAAE,WAAW,IAAI,CAAC,CAAC;QAC5C,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC;YAAE,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QAChD,IAAI,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,aAAa,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC;QACpD,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;YAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC,gCAAgC;IAC9E,CAAC;IAED,qEAAqE;IACrE,KAAK,CAAC,EAAU,EAAE,UAAkB;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;QAC/B,MAAM,cAAc,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;QACvD,uDAAuD;QACvD,MAAM,KAAK,GAAG,MAAM,MAAM,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAC;QAErC,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC/D,CAAC;IAED,+BAA+B;IAC/B,aAAa,CAAC,EAAU,EAAE,UAAkB;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;QAC/B,MAAM,cAAc,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;QACvD,IAAI,CAAC,SAAS,CAAC,MAAM,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,SAAS,CAAC,MAAM,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;IAC7C,CAAC;IAED,0CAA0C;IAC1C,aAAa,CAAC,EAAU,EAAE,UAAkB;QAC3C,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;QAC/B,MAAM,cAAc,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,cAAc,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,gDAAgD;IAChD,SAAS,CAAC,EAAU,EAAE,UAAkB;QACvC,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;QAC/B,MAAM,cAAc,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,cAAc,EAAE,CAAC,CAAC;QACvD,MAAM,WAAW,GAAG,OAAO;YAC1B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC;YAC/C,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;QACpB,MAAM,WAAW,GAAG,OAAO;YAC1B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC;YAC/C,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;QACpB,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC3C,CAAC;IAEO,QAAQ,CAAC,GAAW,EAAE,GAAW;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,GAAG,GAAG;YAAE,OAAO,IAAI,CAAC;QAC/C,OAAO,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC;IACvC,CAAC;IAEO,SAAS,CAAC,GAAW,EAAE,GAAW;QACzC,iEAAiE;QACjE,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YACzC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACjC,IAAI,CAAC,CAAC,OAAO,GAAG,GAAG;oBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC3C,CAAC;QACF,CAAC;QAED,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC;YACnC,KAAK,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACjD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC5B,CAAC;QACD,KAAK,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;CACD;AAED,SAAS,mBAAmB,CAAC,UAAkB;IAC9C,OAAO,UAAU,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACxC,CAAC;AAED,SAAS,WAAW,CAAC,EAAU;IAC9B,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC;AAClB,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @Guard() decorator — protects route handlers with authentication.
3
+ *
4
+ * @implements FR50, FR51
5
+ */
6
+ import "reflect-metadata";
7
+ /**
8
+ * @Guard('jwt') — require authentication via the named strategy.
9
+ * At least one strategy name is required.
10
+ */
11
+ export declare function Guard(first: string, ...rest: string[]): MethodDecorator;
12
+ /**
13
+ * @Permission('orders.create') — require specific permissions.
14
+ */
15
+ export declare function Permission(...permissions: string[]): MethodDecorator;
16
+ /**
17
+ * @Role('admin') — require specific roles.
18
+ */
19
+ export declare function Role(...roles: string[]): MethodDecorator;
20
+ /** Get guard metadata. */
21
+ export declare function getGuardMetadata(target: object, propertyKey: string | symbol): string[];
22
+ /** Get permission metadata. */
23
+ export declare function getPermissionMetadata(target: object, propertyKey: string | symbol): string[];
24
+ /** Get role metadata. */
25
+ export declare function getRoleMetadata(target: object, propertyKey: string | symbol): string[];
26
+ //# sourceMappingURL=Guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Guard.d.ts","sourceRoot":"","sources":["../src/Guard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,kBAAkB,CAAC;AAO1B;;;GAGG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CAKvE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,WAAW,EAAE,MAAM,EAAE,GAAG,eAAe,CAIpE;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,eAAe,CAIxD;AAED,0BAA0B;AAC1B,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,GAC1B,MAAM,EAAE,CAEV;AAED,+BAA+B;AAC/B,wBAAgB,qBAAqB,CACpC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,GAC1B,MAAM,EAAE,CAEV;AAED,yBAAyB;AACzB,wBAAgB,eAAe,CAC9B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,GAC1B,MAAM,EAAE,CAEV"}
package/dist/Guard.js ADDED
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @Guard() decorator — protects route handlers with authentication.
3
+ *
4
+ * @implements FR50, FR51
5
+ */
6
+ // Side-effect import: registers the `Reflect.defineMetadata` / `getOwnMetadata`
7
+ // methods used below. Pulled in here (not transitively via the framework)
8
+ // so warden remains self-sufficient when published / consumed standalone.
9
+ import "reflect-metadata";
10
+ /** Guard decorator metadata key — Symbol.for ensures cross-module accessibility. */
11
+ const GUARD_KEY = Symbol.for("warden:guard");
12
+ const PERMISSION_KEY = Symbol.for("warden:permission");
13
+ const ROLE_KEY = Symbol.for("warden:role");
14
+ /**
15
+ * @Guard('jwt') — require authentication via the named strategy.
16
+ * At least one strategy name is required.
17
+ */
18
+ export function Guard(first, ...rest) {
19
+ const strategies = [first, ...rest];
20
+ return (target, propertyKey) => {
21
+ Reflect.defineMetadata(GUARD_KEY, strategies, target, propertyKey);
22
+ };
23
+ }
24
+ /**
25
+ * @Permission('orders.create') — require specific permissions.
26
+ */
27
+ export function Permission(...permissions) {
28
+ return (target, propertyKey) => {
29
+ Reflect.defineMetadata(PERMISSION_KEY, permissions, target, propertyKey);
30
+ };
31
+ }
32
+ /**
33
+ * @Role('admin') — require specific roles.
34
+ */
35
+ export function Role(...roles) {
36
+ return (target, propertyKey) => {
37
+ Reflect.defineMetadata(ROLE_KEY, roles, target, propertyKey);
38
+ };
39
+ }
40
+ /** Get guard metadata. */
41
+ export function getGuardMetadata(target, propertyKey) {
42
+ return Reflect.getOwnMetadata(GUARD_KEY, target, propertyKey) ?? [];
43
+ }
44
+ /** Get permission metadata. */
45
+ export function getPermissionMetadata(target, propertyKey) {
46
+ return Reflect.getOwnMetadata(PERMISSION_KEY, target, propertyKey) ?? [];
47
+ }
48
+ /** Get role metadata. */
49
+ export function getRoleMetadata(target, propertyKey) {
50
+ return Reflect.getOwnMetadata(ROLE_KEY, target, propertyKey) ?? [];
51
+ }
52
+ //# sourceMappingURL=Guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Guard.js","sourceRoot":"","sources":["../src/Guard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,gFAAgF;AAChF,0EAA0E;AAC1E,0EAA0E;AAC1E,OAAO,kBAAkB,CAAC;AAE1B,oFAAoF;AACpF,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAC7C,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;AACvD,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AAE3C;;;GAGG;AACH,MAAM,UAAU,KAAK,CAAC,KAAa,EAAE,GAAG,IAAc;IACrD,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;IACpC,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;QAC9B,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IACpE,CAAC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,GAAG,WAAqB;IAClD,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;QAC9B,OAAO,CAAC,cAAc,CAAC,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAC1E,CAAC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,IAAI,CAAC,GAAG,KAAe;IACtC,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;QAC9B,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAC9D,CAAC,CAAC;AACH,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,gBAAgB,CAC/B,MAAc,EACd,WAA4B;IAE5B,OAAO,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;AACrE,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,qBAAqB,CACpC,MAAc,EACd,WAA4B;IAE5B,OAAO,OAAO,CAAC,cAAc,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;AAC1E,CAAC;AAED,yBAAyB;AACzB,MAAM,UAAU,eAAe,CAC9B,MAAc,EACd,WAA4B;IAE5B,OAAO,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;AACpE,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * RefreshTokenStore — server-side opaque refresh token management.
3
+ *
4
+ * AdonisJS opaque token pattern:
5
+ * { accessToken, refreshToken, expiresIn }
6
+ * POST /auth/refresh → new pair, old token invalidated
7
+ *
8
+ * @implements MISS-5
9
+ */
10
+ export interface StoredRefreshToken {
11
+ token: string;
12
+ userId: string | number;
13
+ expiresAt: number;
14
+ createdAt: number;
15
+ }
16
+ export interface RefreshTokenDriver {
17
+ store(token: StoredRefreshToken): Promise<void>;
18
+ find(token: string): Promise<StoredRefreshToken | null>;
19
+ revoke(token: string): Promise<void>;
20
+ revokeAllForUser(userId: string | number): Promise<void>;
21
+ cleanup(): Promise<void>;
22
+ }
23
+ /** In-memory driver for development. */
24
+ export declare class MemoryRefreshTokenDriver implements RefreshTokenDriver {
25
+ private tokens;
26
+ store(token: StoredRefreshToken): Promise<void>;
27
+ find(token: string): Promise<StoredRefreshToken | null>;
28
+ revoke(token: string): Promise<void>;
29
+ revokeAllForUser(userId: string | number): Promise<void>;
30
+ cleanup(): Promise<void>;
31
+ }
32
+ /** Generate an opaque refresh token. */
33
+ export declare function generateRefreshToken(): string;
34
+ //# sourceMappingURL=RefreshTokenStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RefreshTokenStore.d.ts","sourceRoot":"","sources":["../src/RefreshTokenStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED,wCAAwC;AACxC,qBAAa,wBAAyB,YAAW,kBAAkB;IAClE,OAAO,CAAC,MAAM,CAA8C;IAEtD,KAAK,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAUvD,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpC,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAM9B;AAED,wCAAwC;AACxC,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * RefreshTokenStore — server-side opaque refresh token management.
3
+ *
4
+ * AdonisJS opaque token pattern:
5
+ * { accessToken, refreshToken, expiresIn }
6
+ * POST /auth/refresh → new pair, old token invalidated
7
+ *
8
+ * @implements MISS-5
9
+ */
10
+ import { randomBytes } from "node:crypto";
11
+ /** In-memory driver for development. */
12
+ export class MemoryRefreshTokenDriver {
13
+ tokens = new Map();
14
+ async store(token) {
15
+ this.tokens.set(token.token, token);
16
+ }
17
+ async find(token) {
18
+ const stored = this.tokens.get(token);
19
+ if (!stored)
20
+ return null;
21
+ if (stored.expiresAt < Date.now()) {
22
+ this.tokens.delete(token);
23
+ return null;
24
+ }
25
+ return stored;
26
+ }
27
+ async revoke(token) {
28
+ this.tokens.delete(token);
29
+ }
30
+ async revokeAllForUser(userId) {
31
+ for (const [key, val] of this.tokens) {
32
+ if (val.userId === userId)
33
+ this.tokens.delete(key);
34
+ }
35
+ }
36
+ async cleanup() {
37
+ const now = Date.now();
38
+ for (const [key, val] of this.tokens) {
39
+ if (val.expiresAt < now)
40
+ this.tokens.delete(key);
41
+ }
42
+ }
43
+ }
44
+ /** Generate an opaque refresh token. */
45
+ export function generateRefreshToken() {
46
+ return randomBytes(48).toString("base64url");
47
+ }
48
+ //# sourceMappingURL=RefreshTokenStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RefreshTokenStore.js","sourceRoot":"","sources":["../src/RefreshTokenStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAiB1C,wCAAwC;AACxC,MAAM,OAAO,wBAAwB;IAC5B,MAAM,GAAoC,IAAI,GAAG,EAAE,CAAC;IAE5D,KAAK,CAAC,KAAK,CAAC,KAAyB;QACpC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAa;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,IAAI,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1B,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACzB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,MAAuB;QAC7C,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACtC,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACpD,CAAC;IACF,CAAC;IAED,KAAK,CAAC,OAAO;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACtC,IAAI,GAAG,CAAC,SAAS,GAAG,GAAG;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAClD,CAAC;IACF,CAAC;CACD;AAED,wCAAwC;AACxC,MAAM,UAAU,oBAAoB;IACnC,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * TokenBlacklist — revoke JWT tokens before expiry.
3
+ *
4
+ * Stores JTI (JWT ID) with expiry. Supports Memory and Redis drivers.
5
+ *
6
+ * @implements MISS-6
7
+ */
8
+ export interface BlacklistDriver {
9
+ add(jti: string, expiresAt: number): Promise<void>;
10
+ has(jti: string): Promise<boolean>;
11
+ cleanup(): Promise<void>;
12
+ }
13
+ /** In-memory blacklist for development. */
14
+ export declare class MemoryBlacklistDriver implements BlacklistDriver {
15
+ private entries;
16
+ add(jti: string, expiresAt: number): Promise<void>;
17
+ has(jti: string): Promise<boolean>;
18
+ cleanup(): Promise<void>;
19
+ }
20
+ export declare class TokenBlacklist {
21
+ private driver;
22
+ constructor(driver: BlacklistDriver);
23
+ /** Revoke a token by its JTI claim. */
24
+ revoke(jti: string, expiresAt: number): Promise<void>;
25
+ /** Check if a token JTI is blacklisted. */
26
+ isRevoked(jti: string): Promise<boolean>;
27
+ /** Remove expired entries. */
28
+ cleanup(): Promise<void>;
29
+ }
30
+ //# sourceMappingURL=TokenBlacklist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenBlacklist.d.ts","sourceRoot":"","sources":["../src/TokenBlacklist.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,eAAe;IAC/B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED,2CAA2C;AAC3C,qBAAa,qBAAsB,YAAW,eAAe;IAC5D,OAAO,CAAC,OAAO,CAAkC;IAE3C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUlC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAM9B;AAED,qBAAa,cAAc;IACd,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,eAAe;IAE3C,uCAAuC;IACjC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D,2CAA2C;IACrC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9C,8BAA8B;IACxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG9B"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * TokenBlacklist — revoke JWT tokens before expiry.
3
+ *
4
+ * Stores JTI (JWT ID) with expiry. Supports Memory and Redis drivers.
5
+ *
6
+ * @implements MISS-6
7
+ */
8
+ /** In-memory blacklist for development. */
9
+ export class MemoryBlacklistDriver {
10
+ entries = new Map();
11
+ async add(jti, expiresAt) {
12
+ this.entries.set(jti, expiresAt);
13
+ }
14
+ async has(jti) {
15
+ const expiresAt = this.entries.get(jti);
16
+ if (expiresAt === undefined)
17
+ return false;
18
+ if (expiresAt < Date.now()) {
19
+ this.entries.delete(jti);
20
+ return false;
21
+ }
22
+ return true;
23
+ }
24
+ async cleanup() {
25
+ const now = Date.now();
26
+ for (const [jti, exp] of this.entries) {
27
+ if (exp < now)
28
+ this.entries.delete(jti);
29
+ }
30
+ }
31
+ }
32
+ export class TokenBlacklist {
33
+ driver;
34
+ constructor(driver) {
35
+ this.driver = driver;
36
+ }
37
+ /** Revoke a token by its JTI claim. */
38
+ async revoke(jti, expiresAt) {
39
+ await this.driver.add(jti, expiresAt);
40
+ }
41
+ /** Check if a token JTI is blacklisted. */
42
+ async isRevoked(jti) {
43
+ return this.driver.has(jti);
44
+ }
45
+ /** Remove expired entries. */
46
+ async cleanup() {
47
+ return this.driver.cleanup();
48
+ }
49
+ }
50
+ //# sourceMappingURL=TokenBlacklist.js.map