@c9up/warden 0.1.17 → 0.1.19

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 (124) hide show
  1. package/dist/AuthManager.d.ts +86 -1
  2. package/dist/AuthManager.d.ts.map +1 -1
  3. package/dist/AuthManager.js +113 -10
  4. package/dist/AuthManager.js.map +1 -1
  5. package/dist/Authenticator.d.ts +13 -1
  6. package/dist/Authenticator.d.ts.map +1 -1
  7. package/dist/Authenticator.js +37 -3
  8. package/dist/Authenticator.js.map +1 -1
  9. package/dist/RememberMeToken.d.ts +169 -0
  10. package/dist/RememberMeToken.d.ts.map +1 -0
  11. package/dist/RememberMeToken.js +269 -0
  12. package/dist/RememberMeToken.js.map +1 -0
  13. package/dist/ResilientBlacklistDriver.d.ts +15 -9
  14. package/dist/ResilientBlacklistDriver.d.ts.map +1 -1
  15. package/dist/ResilientBlacklistDriver.js +53 -15
  16. package/dist/ResilientBlacklistDriver.js.map +1 -1
  17. package/dist/Secret.d.ts +11 -0
  18. package/dist/Secret.d.ts.map +1 -0
  19. package/dist/Secret.js +36 -0
  20. package/dist/Secret.js.map +1 -0
  21. package/dist/WardenProvider.d.ts +1 -0
  22. package/dist/WardenProvider.d.ts.map +1 -1
  23. package/dist/WardenProvider.js +64 -0
  24. package/dist/WardenProvider.js.map +1 -1
  25. package/dist/bouncer/Bouncer.d.ts +46 -1
  26. package/dist/bouncer/Bouncer.d.ts.map +1 -1
  27. package/dist/bouncer/Bouncer.js +77 -4
  28. package/dist/bouncer/Bouncer.js.map +1 -1
  29. package/dist/bouncer/PolicyAuthorizer.d.ts +9 -1
  30. package/dist/bouncer/PolicyAuthorizer.d.ts.map +1 -1
  31. package/dist/bouncer/PolicyAuthorizer.js +17 -1
  32. package/dist/bouncer/PolicyAuthorizer.js.map +1 -1
  33. package/dist/bouncer/evaluate.d.ts +14 -2
  34. package/dist/bouncer/evaluate.d.ts.map +1 -1
  35. package/dist/bouncer/evaluate.js +16 -5
  36. package/dist/bouncer/evaluate.js.map +1 -1
  37. package/dist/bouncer/types.d.ts +4 -2
  38. package/dist/bouncer/types.d.ts.map +1 -1
  39. package/dist/config.d.ts +3 -0
  40. package/dist/config.d.ts.map +1 -1
  41. package/dist/config.js +5 -0
  42. package/dist/config.js.map +1 -1
  43. package/dist/firstcontact/drivers/GitHubDriver.d.ts.map +1 -1
  44. package/dist/firstcontact/drivers/GitHubDriver.js +2 -3
  45. package/dist/firstcontact/drivers/GitHubDriver.js.map +1 -1
  46. package/dist/firstcontact/drivers/GoogleDriver.d.ts.map +1 -1
  47. package/dist/firstcontact/drivers/GoogleDriver.js +2 -3
  48. package/dist/firstcontact/drivers/GoogleDriver.js.map +1 -1
  49. package/dist/firstcontact/types.d.ts +10 -0
  50. package/dist/firstcontact/types.d.ts.map +1 -1
  51. package/dist/firstcontact/types.js +18 -1
  52. package/dist/firstcontact/types.js.map +1 -1
  53. package/dist/index.d.ts +8 -4
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +6 -3
  56. package/dist/index.js.map +1 -1
  57. package/dist/mfa/MfaManager.d.ts.map +1 -1
  58. package/dist/mfa/MfaManager.js +14 -5
  59. package/dist/mfa/MfaManager.js.map +1 -1
  60. package/dist/mfa/TotpProvider.d.ts +34 -1
  61. package/dist/mfa/TotpProvider.d.ts.map +1 -1
  62. package/dist/mfa/TotpProvider.js +60 -4
  63. package/dist/mfa/TotpProvider.js.map +1 -1
  64. package/dist/mfa/webauthn-codec.d.ts +6 -1
  65. package/dist/mfa/webauthn-codec.d.ts.map +1 -1
  66. package/dist/mfa/webauthn-codec.js +50 -6
  67. package/dist/mfa/webauthn-codec.js.map +1 -1
  68. package/dist/middleware.d.ts.map +1 -1
  69. package/dist/middleware.js +46 -1
  70. package/dist/middleware.js.map +1 -1
  71. package/dist/quasar.d.ts.map +1 -1
  72. package/dist/quasar.js +6 -14
  73. package/dist/quasar.js.map +1 -1
  74. package/dist/sanitize.d.ts +10 -0
  75. package/dist/sanitize.d.ts.map +1 -0
  76. package/dist/sanitize.js +15 -0
  77. package/dist/sanitize.js.map +1 -0
  78. package/dist/strategies/ApiKeyStrategy.d.ts +10 -1
  79. package/dist/strategies/ApiKeyStrategy.d.ts.map +1 -1
  80. package/dist/strategies/ApiKeyStrategy.js +16 -0
  81. package/dist/strategies/ApiKeyStrategy.js.map +1 -1
  82. package/dist/strategies/BasicAuthStrategy.d.ts +59 -0
  83. package/dist/strategies/BasicAuthStrategy.d.ts.map +1 -0
  84. package/dist/strategies/BasicAuthStrategy.js +97 -0
  85. package/dist/strategies/BasicAuthStrategy.js.map +1 -0
  86. package/dist/strategies/JwtStrategy.d.ts +10 -1
  87. package/dist/strategies/JwtStrategy.d.ts.map +1 -1
  88. package/dist/strategies/JwtStrategy.js +11 -0
  89. package/dist/strategies/JwtStrategy.js.map +1 -1
  90. package/dist/strategies/SessionStrategy.d.ts +84 -2
  91. package/dist/strategies/SessionStrategy.d.ts.map +1 -1
  92. package/dist/strategies/SessionStrategy.js +124 -1
  93. package/dist/strategies/SessionStrategy.js.map +1 -1
  94. package/index.darwin-arm64.node +0 -0
  95. package/index.darwin-x64.node +0 -0
  96. package/index.linux-arm64-gnu.node +0 -0
  97. package/index.linux-x64-gnu.node +0 -0
  98. package/index.win32-x64-msvc.node +0 -0
  99. package/package.json +4 -2
  100. package/src/AuthManager.ts +163 -7
  101. package/src/Authenticator.ts +58 -10
  102. package/src/RememberMeToken.ts +357 -0
  103. package/src/ResilientBlacklistDriver.ts +58 -18
  104. package/src/Secret.ts +41 -0
  105. package/src/WardenProvider.ts +90 -0
  106. package/src/bouncer/Bouncer.ts +93 -4
  107. package/src/bouncer/PolicyAuthorizer.ts +20 -1
  108. package/src/bouncer/evaluate.ts +26 -6
  109. package/src/bouncer/types.ts +4 -2
  110. package/src/config.ts +9 -0
  111. package/src/firstcontact/drivers/GitHubDriver.ts +2 -3
  112. package/src/firstcontact/drivers/GoogleDriver.ts +2 -3
  113. package/src/firstcontact/types.ts +24 -0
  114. package/src/index.ts +30 -2
  115. package/src/mfa/MfaManager.ts +15 -8
  116. package/src/mfa/TotpProvider.ts +90 -6
  117. package/src/mfa/webauthn-codec.ts +48 -6
  118. package/src/middleware.ts +55 -2
  119. package/src/quasar.ts +6 -14
  120. package/src/sanitize.ts +17 -0
  121. package/src/strategies/ApiKeyStrategy.ts +23 -1
  122. package/src/strategies/BasicAuthStrategy.ts +127 -0
  123. package/src/strategies/JwtStrategy.ts +18 -1
  124. package/src/strategies/SessionStrategy.ts +167 -2
@@ -1 +1 @@
1
- {"version":3,"file":"JwtStrategy.d.ts","sourceRoot":"","sources":["../../src/strategies/JwtStrategy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,wFAAwF;IACxF,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AA6BD,MAAM,WAAW,iBAAiB;IACjC;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;;OAOG;IACH,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzE,iBAAiB,EAAE,CAClB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,KACZ,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACjC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,qBAAa,WAAY,YAAW,YAAY;;IAC/C,IAAI,SAAS;gBAaD,MAAM,EAAE,iBAAiB;IAgC/B,YAAY,CACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,UAAU,CAAC;IAkBhB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAmChD,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM;IAepC;;;;;;;;OAQG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAa7C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
1
+ {"version":3,"file":"JwtStrategy.d.ts","sourceRoot":"","sources":["../../src/strategies/JwtStrategy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,wFAAwF;IACxF,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AA6BD,MAAM,WAAW,iBAAiB;IACjC;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;;OAOG;IACH,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzE,iBAAiB,EAAE,CAClB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,KACZ,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACjC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,qBAAa,WAAY,YAAW,YAAY;;IAC/C,IAAI,SAAS;gBAaD,MAAM,EAAE,iBAAiB;IAgC/B,YAAY,CACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,UAAU,CAAC;IAkBhB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAmChD,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM;IAepC;;;;;;;;OAQG;IACH;;;;;;;OAOG;IACH,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,kBAAkB;IAIrD,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAa7C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
@@ -133,6 +133,17 @@ export class JwtStrategy {
133
133
  * Returns `true` when the token was added to the blacklist, `false` when
134
134
  * the token is already expired (revocation is unnecessary) or unparseable.
135
135
  */
136
+ /**
137
+ * The header a test client sends to be `user` (AdonisJS
138
+ * `authenticateAsClient`).
139
+ *
140
+ * Signs a real token with the configured secret, so the request travels the
141
+ * SAME verification path as production — a test that forges its own header
142
+ * proves only that the forgery works.
143
+ */
144
+ authenticateAsClient(user) {
145
+ return { headers: { authorization: `Bearer ${this.signToken(user)}` } };
146
+ }
136
147
  async revoke(token) {
137
148
  if (!this.#blacklist) {
138
149
  throw new Error("JwtStrategy.revoke() requires a `blacklist` driver. Pass `{ blacklist: new TokenBlacklist(driver) }` to the constructor.");
@@ -1 +1 @@
1
- {"version":3,"file":"JwtStrategy.js","sourceRoot":"","sources":["../../src/strategies/JwtStrategy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"JwtStrategy.js","sourceRoot":"","sources":["../../src/strategies/JwtStrategy.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,8 @@
6
6
  *
7
7
  * @implements MISS-7
8
8
  */
9
- import type { AuthResult, AuthStrategy, UserPayload } from "../AuthManager.js";
9
+ import type { AuthClientResponse, AuthResult, AuthStrategy, UserPayload } from "../AuthManager.js";
10
+ import { type RememberMeTokenDriver } from "../RememberMeToken.js";
10
11
  export interface SessionStore {
11
12
  get(key: string): unknown;
12
13
  /**
@@ -29,11 +30,79 @@ export interface SessionStore {
29
30
  export interface SessionStrategyConfig {
30
31
  sessionKey?: string;
31
32
  findUser: (id: string | number) => Promise<UserPayload | null>;
33
+ /**
34
+ * Turn on "keep me signed in". Adonis calls the equivalent flag
35
+ * `useRememberMeTokens`; without a driver there is nowhere to persist the
36
+ * token, so passing one IS the opt-in.
37
+ */
38
+ rememberMeTokens?: RememberMeTokenDriver;
39
+ /**
40
+ * How long a remember-me token lives. Adonis defaults to two years, and a
41
+ * number here is SECONDS (`durationToSeconds` semantics).
42
+ */
43
+ rememberMeAge?: number;
44
+ /**
45
+ * Cookie name holding the token. Adonis derives `remember_<guard>`; the
46
+ * default matches the `web` guard an app is most likely migrating.
47
+ */
48
+ rememberMeCookieName?: string;
32
49
  }
33
50
  export declare class SessionStrategy implements AuthStrategy {
34
51
  #private;
35
52
  name: string;
36
53
  constructor(config: SessionStrategyConfig);
54
+ /** The cookie the remember-me token travels in. */
55
+ get rememberMeCookieName(): string;
56
+ /** Whether "keep me signed in" is wired at all. */
57
+ get usesRememberMeTokens(): boolean;
58
+ /**
59
+ * Whether the current user was revived from a remember-me cookie rather
60
+ * than signing in (AdonisJS `viaRemember`).
61
+ *
62
+ * This is the distinction that lets an app demand the password again before
63
+ * something sensitive — changing an email, spending money, deleting an
64
+ * account. Nothing reported it, so a session restored from a cookie looked
65
+ * exactly like one where the user had just typed their password.
66
+ */
67
+ get viaRemember(): boolean;
68
+ /**
69
+ * Whether a remember-me token was even tried on this request (AdonisJS
70
+ * `attemptedViaRemember`) — true whether or not it worked.
71
+ */
72
+ get attemptedViaRemember(): boolean;
73
+ /**
74
+ * Whether `logout()` ran on this guard (AdonisJS `isLoggedOut`).
75
+ *
76
+ * A handler that logs out and then keeps working — clearing a cart, writing
77
+ * an audit line — could not tell that the session was already gone.
78
+ */
79
+ get isLoggedOut(): boolean;
80
+ /** The session key the user id is stored under (AdonisJS `sessionKeyName`). */
81
+ get sessionKeyName(): string;
82
+ /** The cookie key the remember-me token is stored under (AdonisJS `rememberMeKeyName`). */
83
+ get rememberMeKeyName(): string;
84
+ /**
85
+ * Mint a remember-me token for `user` and return the cookie value the caller
86
+ * must set. `null` when the feature is not wired.
87
+ */
88
+ issueRememberMeToken(user: UserPayload): Promise<string | null>;
89
+ /**
90
+ * Authenticate from a remember-me cookie, and RECYCLE it: the returned
91
+ * `cookieValue` must replace the one the browser holds.
92
+ *
93
+ * The user is re-read through `findUser`, never trusted from the token — a
94
+ * token outlives the row it points at, and a deleted or disabled account
95
+ * must not walk back in through a cookie.
96
+ */
97
+ authenticateViaRememberMeToken(cookieValue: unknown): Promise<{
98
+ user: UserPayload;
99
+ cookieValue: string;
100
+ } | null>;
101
+ /**
102
+ * Drop the token behind `cookieValue`. Called on logout so the persistent
103
+ * credential dies with the session — Adonis deletes the row too.
104
+ */
105
+ revokeRememberMeToken(cookieValue: unknown): Promise<void>;
37
106
  /** Authenticate via email/password — stores user ID in session. */
38
107
  authenticate(_credentials: {
39
108
  email: string;
@@ -58,7 +127,20 @@ export declare class SessionStrategy implements AuthStrategy {
58
127
  * path — see `wasRegenerated()` there.
59
128
  */
60
129
  login(user: UserPayload, session: SessionStore): Promise<void>;
61
- /** Logout — remove user ID from session. */
130
+ /**
131
+ * The session entry a test client needs to be `user` (AdonisJS
132
+ * `authenticateAsClient`).
133
+ *
134
+ * Returns the same key `login()` writes, so the request is authenticated by
135
+ * the guard's own logic rather than by the test knowing where the id lives.
136
+ */
137
+ authenticateAsClient(user: UserPayload): AuthClientResponse;
138
+ /**
139
+ * Logout — remove the user id from the session.
140
+ *
141
+ * The remember-me token is revoked separately through
142
+ * {@link revokeRememberMeToken}, because only the caller holds the cookie.
143
+ */
62
144
  logout(session: SessionStore): Promise<void>;
63
145
  }
64
146
  //# sourceMappingURL=SessionStrategy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionStrategy.d.ts","sourceRoot":"","sources":["../../src/strategies/SessionStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAG/E,MAAM,WAAW,YAAY;IAC5B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACvC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;;;OAMG;IACH,UAAU,IAAI,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAC/D;AAED,qBAAa,eAAgB,YAAW,YAAY;;IACnD,IAAI,SAAa;gBAIL,MAAM,EAAE,qBAAqB;IAKzC,mEAAmE;IAC7D,YAAY,CACjB,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EACjD,QAAQ,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,YAAY,CAAA;KAAE,GACnC,OAAO,CAAC,UAAU,CAAC;IAgBtB,8DAA8D;IACxD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAQjD,2EAA2E;IACrE,iBAAiB,CACtB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,YAAY,CAAA;KAAE,GAClC,OAAO,CAAC,UAAU,CAAC;IAWtB;;;;;;;;;OASG;IACG,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpE,4CAA4C;IACtC,MAAM,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAGlD"}
1
+ {"version":3,"file":"SessionStrategy.d.ts","sourceRoot":"","sources":["../../src/strategies/SessionStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAGN,KAAK,qBAAqB,EAE1B,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,YAAY;IAC5B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACvC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;;;OAMG;IACH,UAAU,IAAI,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC/D;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;IACzC;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAKD,qBAAa,eAAgB,YAAW,YAAY;;IACnD,IAAI,SAAa;gBAOL,MAAM,EAAE,qBAAqB;IAKzC,mDAAmD;IACnD,IAAI,oBAAoB,IAAI,MAAM,CAEjC;IAED,mDAAmD;IACnD,IAAI,oBAAoB,IAAI,OAAO,CAElC;IAED;;;;;;;;OAQG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;;OAGG;IACH,IAAI,oBAAoB,IAAI,OAAO,CAElC;IAED;;;;;OAKG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,+EAA+E;IAC/E,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,2FAA2F;IAC3F,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAMD;;;OAGG;IACG,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAQrE;;;;;;;OAOG;IACG,8BAA8B,CACnC,WAAW,EAAE,OAAO,GAClB,OAAO,CAAC;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAmB7D;;;OAGG;IACG,qBAAqB,CAAC,WAAW,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAQhE,mEAAmE;IAC7D,YAAY,CACjB,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EACjD,QAAQ,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,YAAY,CAAA;KAAE,GACnC,OAAO,CAAC,UAAU,CAAC;IAgBtB,8DAA8D;IACxD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAQjD,2EAA2E;IACrE,iBAAiB,CACtB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,YAAY,CAAA;KAAE,GAClC,OAAO,CAAC,UAAU,CAAC;IAWtB;;;;;;;;;OASG;IACG,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAUpE;;;;;;OAMG;IACH,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,kBAAkB;IAI3D;;;;;OAKG;IACG,MAAM,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAMlD"}
@@ -7,14 +7,114 @@
7
7
  * @implements MISS-7
8
8
  */
9
9
  import { WardenError } from "../errors.js";
10
+ import { decodeTokenValue, mintRememberMeToken, verifyAndRecycleRememberMeToken, } from "../RememberMeToken.js";
11
+ /** Two years, Adonis' `rememberMeTokensAge` default. */
12
+ const DEFAULT_REMEMBER_AGE_SECONDS = 63_072_000;
10
13
  export class SessionStrategy {
11
14
  name = "session";
12
15
  #config;
13
16
  #sessionKey;
17
+ #viaRemember = false;
18
+ #loggedOut = false;
19
+ #attemptedViaRemember = false;
14
20
  constructor(config) {
15
21
  this.#config = config;
16
22
  this.#sessionKey = config.sessionKey ?? "auth_user_id";
17
23
  }
24
+ /** The cookie the remember-me token travels in. */
25
+ get rememberMeCookieName() {
26
+ return this.#config.rememberMeCookieName ?? "remember_web";
27
+ }
28
+ /** Whether "keep me signed in" is wired at all. */
29
+ get usesRememberMeTokens() {
30
+ return this.#config.rememberMeTokens !== undefined;
31
+ }
32
+ /**
33
+ * Whether the current user was revived from a remember-me cookie rather
34
+ * than signing in (AdonisJS `viaRemember`).
35
+ *
36
+ * This is the distinction that lets an app demand the password again before
37
+ * something sensitive — changing an email, spending money, deleting an
38
+ * account. Nothing reported it, so a session restored from a cookie looked
39
+ * exactly like one where the user had just typed their password.
40
+ */
41
+ get viaRemember() {
42
+ return this.#viaRemember;
43
+ }
44
+ /**
45
+ * Whether a remember-me token was even tried on this request (AdonisJS
46
+ * `attemptedViaRemember`) — true whether or not it worked.
47
+ */
48
+ get attemptedViaRemember() {
49
+ return this.#attemptedViaRemember;
50
+ }
51
+ /**
52
+ * Whether `logout()` ran on this guard (AdonisJS `isLoggedOut`).
53
+ *
54
+ * A handler that logs out and then keeps working — clearing a cart, writing
55
+ * an audit line — could not tell that the session was already gone.
56
+ */
57
+ get isLoggedOut() {
58
+ return this.#loggedOut;
59
+ }
60
+ /** The session key the user id is stored under (AdonisJS `sessionKeyName`). */
61
+ get sessionKeyName() {
62
+ return this.#sessionKey;
63
+ }
64
+ /** The cookie key the remember-me token is stored under (AdonisJS `rememberMeKeyName`). */
65
+ get rememberMeKeyName() {
66
+ return this.rememberMeCookieName;
67
+ }
68
+ #rememberMeAge() {
69
+ return this.#config.rememberMeAge ?? DEFAULT_REMEMBER_AGE_SECONDS;
70
+ }
71
+ /**
72
+ * Mint a remember-me token for `user` and return the cookie value the caller
73
+ * must set. `null` when the feature is not wired.
74
+ */
75
+ async issueRememberMeToken(user) {
76
+ const driver = this.#config.rememberMeTokens;
77
+ if (!driver)
78
+ return null;
79
+ const minted = mintRememberMeToken(user.id, this.#rememberMeAge());
80
+ await driver.create(minted.stored);
81
+ return minted.value;
82
+ }
83
+ /**
84
+ * Authenticate from a remember-me cookie, and RECYCLE it: the returned
85
+ * `cookieValue` must replace the one the browser holds.
86
+ *
87
+ * The user is re-read through `findUser`, never trusted from the token — a
88
+ * token outlives the row it points at, and a deleted or disabled account
89
+ * must not walk back in through a cookie.
90
+ */
91
+ async authenticateViaRememberMeToken(cookieValue) {
92
+ const driver = this.#config.rememberMeTokens;
93
+ if (!driver)
94
+ return null;
95
+ this.#attemptedViaRemember = true;
96
+ const recycled = await verifyAndRecycleRememberMeToken(driver, cookieValue, this.#rememberMeAge());
97
+ if (!recycled)
98
+ return null;
99
+ const user = await this.#config.findUser(recycled.userId);
100
+ if (!user)
101
+ return null;
102
+ this.#viaRemember = true;
103
+ return { user, cookieValue: recycled.value };
104
+ }
105
+ /**
106
+ * Drop the token behind `cookieValue`. Called on logout so the persistent
107
+ * credential dies with the session — Adonis deletes the row too.
108
+ */
109
+ async revokeRememberMeToken(cookieValue) {
110
+ const driver = this.#config.rememberMeTokens;
111
+ if (!driver)
112
+ return;
113
+ const decoded = decodeTokenValue(cookieValue);
114
+ if (!decoded)
115
+ return;
116
+ await driver.delete(decoded.identifier);
117
+ }
18
118
  /** Authenticate via email/password — stores user ID in session. */
19
119
  async authenticate(_credentials, _context) {
20
120
  // Session strategy doesn't handle password verification — that's done
@@ -61,10 +161,33 @@ export class SessionStrategy {
61
161
  async login(user, session) {
62
162
  session.regenerate();
63
163
  session.put(this.#sessionKey, user.id);
164
+ this.#loggedOut = false;
165
+ // A password was typed: this session is no longer "via remember", even
166
+ // if a cookie was tried earlier in the same request. Without the reset
167
+ // the flag would stay true and a re-auth prompt would never fire.
168
+ this.#viaRemember = false;
169
+ }
170
+ /**
171
+ * The session entry a test client needs to be `user` (AdonisJS
172
+ * `authenticateAsClient`).
173
+ *
174
+ * Returns the same key `login()` writes, so the request is authenticated by
175
+ * the guard's own logic rather than by the test knowing where the id lives.
176
+ */
177
+ authenticateAsClient(user) {
178
+ return { session: { [this.#sessionKey]: user.id } };
64
179
  }
65
- /** Logout — remove user ID from session. */
180
+ /**
181
+ * Logout — remove the user id from the session.
182
+ *
183
+ * The remember-me token is revoked separately through
184
+ * {@link revokeRememberMeToken}, because only the caller holds the cookie.
185
+ */
66
186
  async logout(session) {
67
187
  session.forget(this.#sessionKey);
188
+ this.#viaRemember = false;
189
+ this.#attemptedViaRemember = false;
190
+ this.#loggedOut = true;
68
191
  }
69
192
  }
70
193
  //# sourceMappingURL=SessionStrategy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionStrategy.js","sourceRoot":"","sources":["../../src/strategies/SessionStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AA2B3C,MAAM,OAAO,eAAe;IAC3B,IAAI,GAAG,SAAS,CAAC;IACjB,OAAO,CAAwB;IAC/B,WAAW,CAAS;IAEpB,YAAY,MAA6B;QACxC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,UAAU,IAAI,cAAc,CAAC;IACxD,CAAC;IAED,mEAAmE;IACnE,KAAK,CAAC,YAAY,CACjB,YAAiD,EACjD,QAAqC;QAErC,sEAAsE;QACtE,wEAAwE;QACxE,mEAAmE;QACnE,sEAAsE;QACtE,kEAAkE;QAClE,sCAAsC;QACtC,MAAM,IAAI,WAAW,CACpB,WAAW,EACX,6KAA6K,EAC7K;YACC,IAAI,EAAE,yKAAyK;SAC/K,CACD,CAAC;IACH,CAAC;IAED,8DAA8D;IAC9D,KAAK,CAAC,MAAM,CAAC,MAAc;QAC1B,OAAO;YACN,aAAa,EAAE,KAAK;YACpB,KAAK,EACJ,qEAAqE;SACtE,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,KAAK,CAAC,iBAAiB,CACtB,MAAc,EACd,OAAoC;QAEpC,IAAI,CAAC,OAAO,EAAE,OAAO;YAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;QAC5E,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;QACvE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,KAAK,QAAQ;YAC3D,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;QAChE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;QACpE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACtC,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,KAAK,CAAC,IAAiB,EAAE,OAAqB;QACnD,OAAO,CAAC,UAAU,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,4CAA4C;IAC5C,KAAK,CAAC,MAAM,CAAC,OAAqB;QACjC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAClC,CAAC;CACD"}
1
+ {"version":3,"file":"SessionStrategy.js","sourceRoot":"","sources":["../../src/strategies/SessionStrategy.ts"],"names":[],"mappings":"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"}
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c9up/warden",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "Warden — Authentication & authorization for the Ream framework",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -62,6 +62,7 @@
62
62
  },
63
63
  "devDependencies": {
64
64
  "@biomejs/biome": "^2.4.10",
65
+ "@c9up/quasar": "^0.1.0",
65
66
  "@types/node": "^22.19.15",
66
67
  "reflect-metadata": "^0.2.2",
67
68
  "typescript": "^6.0.2",
@@ -85,6 +86,7 @@
85
86
  "test:rust": "cargo test -p warden-engine",
86
87
  "lint": "biome check src/",
87
88
  "test:coverage": "vitest run --coverage",
88
- "typecheck": "tsc --noEmit"
89
+ "typecheck": "tsc --noEmit",
90
+ "test:integration": "vitest run -c vitest.integration.config.ts"
89
91
  }
90
92
  }
@@ -4,7 +4,13 @@
4
4
  * @implements FR48, FR50, FR51
5
5
  */
6
6
 
7
+ import { Authenticator } from "./Authenticator.js";
7
8
  import { WardenError } from "./errors.js";
9
+ import type { WardenContext } from "./middleware.js";
10
+ import { sanitizePayload } from "./sanitize.js";
11
+
12
+ export { sanitizePayload };
13
+
8
14
  import { MemoryRightsStore } from "./rights/MemoryRightsStore.js";
9
15
  import { RightsResolver } from "./rights/RightsResolver.js";
10
16
  import type { EffectivePermissions, Scope } from "./rights/types.js";
@@ -31,10 +37,53 @@ export interface AuthResult {
31
37
  strategyCrash?: true;
32
38
  }
33
39
 
40
+ /**
41
+ * What a test client must send to act as a user (AdonisJS `AuthClientResponse`).
42
+ *
43
+ * Each guard answers in its own currency — a header for a token guard, a
44
+ * session entry for a session guard — so the test harness applies whichever
45
+ * fields come back instead of knowing how each guard authenticates.
46
+ */
47
+ export interface AuthClientResponse {
48
+ /** Headers to set on the request. */
49
+ headers?: Record<string, string>;
50
+ /** Session values to seed before the request. */
51
+ session?: Record<string, unknown>;
52
+ /** Cookies to send. */
53
+ cookies?: Record<string, string>;
54
+ }
55
+
56
+ /**
57
+ * The event namespace for a guard, taken from its DRIVER.
58
+ *
59
+ * AdonisJS namespaces auth events per driver — `session_auth:*`,
60
+ * `access_tokens_auth:*`, `basic_auth:*` — so an app can audit session logins
61
+ * without also hearing about every bearer token. Warden emitted `session_auth:*`
62
+ * whatever authenticated, which told a session listener about JWT traffic and
63
+ * left no name to subscribe to for the others.
64
+ *
65
+ * Driven by the strategy's `name` rather than the guard's config key: a guard
66
+ * called `web` running a `SessionStrategy` is still the session driver, exactly
67
+ * as upstream. A driver already ending in `_auth` (`basic_auth`) keeps its name
68
+ * rather than growing a second suffix, which is how AdonisJS spells it.
69
+ */
70
+ export function authEventPrefix(driverName: string | undefined): string {
71
+ if (!driverName) return "session_auth";
72
+ return driverName.endsWith("_auth") ? driverName : `${driverName}_auth`;
73
+ }
74
+
34
75
  export interface AuthStrategy {
35
76
  name: string;
36
77
  authenticate(credentials: Record<string, unknown>): Promise<AuthResult>;
37
78
  verify(token: string, context?: Record<string, unknown>): Promise<AuthResult>;
79
+ /**
80
+ * Build what a test client sends to be this user (AdonisJS
81
+ * `authenticateAsClient`). Optional: a guard with no test seam simply has
82
+ * none, and the harness says so instead of forging one.
83
+ */
84
+ authenticateAsClient?(
85
+ ...args: never[]
86
+ ): Promise<AuthClientResponse> | AuthClientResponse;
38
87
  }
39
88
 
40
89
  /**
@@ -86,6 +135,14 @@ function isTokenIssuer(
86
135
  /**
87
136
  * Manages authentication strategies and provides guard/permission checks.
88
137
  */
138
+ /**
139
+ * The slice of an event emitter warden publishes through — `emit(name, data)`,
140
+ * which is what both `@c9up/ream`'s Emitter and Adonis' expose.
141
+ */
142
+ export interface WardenEmitter {
143
+ emit(event: string, data: unknown): unknown;
144
+ }
145
+
89
146
  export class AuthManager {
90
147
  // AdonisJS names: `guards` (name → strategy) and `default` (the guard used
91
148
  // when none is named). Renamed from the previous `strategies`/`defaultStrategy`.
@@ -93,6 +150,40 @@ export class AuthManager {
93
150
  private default: string;
94
151
  private readonly rights: RightsResolver;
95
152
 
153
+ /**
154
+ * Where auth events go. Structural and optional: warden is a leaf and must
155
+ * not import an emitter — a host wires its own through `setEmitter`, and one
156
+ * that wires none simply gets no events.
157
+ */
158
+ #emitter: WardenEmitter | undefined;
159
+
160
+ /**
161
+ * Publish auth events on `emitter`. AdonisJS emits six of them from its
162
+ * session guard, and an app that audits logins reads exactly those.
163
+ */
164
+ setEmitter(emitter: WardenEmitter): this {
165
+ this.#emitter = emitter;
166
+ return this;
167
+ }
168
+
169
+ /**
170
+ * Publish one auth event. Public so the per-request `Authenticator` can
171
+ * report what it observed — it holds the guard chain, the manager holds the
172
+ * emitter.
173
+ */
174
+ emitAuthEvent(event: string, payload: Record<string, unknown>): void {
175
+ this.#emit(event, payload);
176
+ }
177
+
178
+ /** Fire-and-forget: an event listener must never break authentication. */
179
+ #emit(event: string, payload: Record<string, unknown>): void {
180
+ try {
181
+ void this.#emitter?.emit(event, payload);
182
+ } catch {
183
+ // A throwing listener is the listener's problem, not the login's.
184
+ }
185
+ }
186
+
96
187
  constructor(config: AuthConfig) {
97
188
  // Normalise the two accepted forms — AdonisJS `{ default, guards }` and
98
189
  // the legacy `{ defaultStrategy, strategies }` — to the AdonisJS names.
@@ -257,6 +348,63 @@ export class AuthManager {
257
348
  }
258
349
 
259
350
  /** Get a registered strategy by name. */
351
+ /**
352
+ * An {@link Authenticator} bound to one request (AdonisJS
353
+ * `createAuthenticator`).
354
+ *
355
+ * What the HTTP middleware builds per request. Exposed so anything outside
356
+ * that path — a console command acting as a user, a background job — can
357
+ * build one without reaching for the class.
358
+ */
359
+ createAuthenticator(ctx: WardenContext): Authenticator {
360
+ return new Authenticator(ctx, this);
361
+ }
362
+
363
+ /**
364
+ * What a test client needs to authenticate as a user (AdonisJS
365
+ * `createAuthenticatorClient`).
366
+ *
367
+ * Delegates to the guard's own `authenticateAsClient`, so a guard with no
368
+ * test seam says so instead of having one forged for it.
369
+ */
370
+ createAuthenticatorClient(): {
371
+ use(guard?: string): {
372
+ authenticateAsClient(
373
+ ...args: never[]
374
+ ): Promise<AuthClientResponse> | AuthClientResponse;
375
+ };
376
+ } {
377
+ return {
378
+ use: (guard?: string) => {
379
+ const strategy = this.getStrategy(guard);
380
+ const seam = strategy.authenticateAsClient?.bind(strategy);
381
+ if (!seam) {
382
+ throw new WardenError(
383
+ "STRATEGY_HAS_NO_CLIENT",
384
+ `Auth strategy '${guard ?? this.default}' has no authenticateAsClient() — it cannot forge a client request.`,
385
+ {
386
+ hint: "Implement authenticateAsClient() on the strategy, or authenticate through a real login in the test.",
387
+ },
388
+ );
389
+ }
390
+ return { authenticateAsClient: seam };
391
+ },
392
+ };
393
+ }
394
+
395
+ /**
396
+ * The event namespace a guard's events carry, resolved from its driver.
397
+ * Falls back to `session_auth` when the guard cannot be resolved, so a
398
+ * failure to look one up never becomes a second failure at emit time.
399
+ */
400
+ eventPrefixFor(guardName?: string): string {
401
+ try {
402
+ return authEventPrefix(this.getStrategy(guardName).name);
403
+ } catch {
404
+ return authEventPrefix(undefined);
405
+ }
406
+ }
407
+
260
408
  getStrategy(name?: string): AuthStrategy {
261
409
  const strategyName = name ?? this.default;
262
410
  const strategy = this.guards.get(strategyName);
@@ -316,7 +464,17 @@ export class AuthManager {
316
464
  },
317
465
  );
318
466
  }
467
+ const prefix = authEventPrefix(strategy.name);
468
+ this.#emit(`${prefix}:login_attempted`, {
469
+ guardName: strategyName ?? this.default,
470
+ user,
471
+ });
319
472
  await strategy.login(user, session);
473
+ this.#emit(`${prefix}:login_succeeded`, {
474
+ guardName: strategyName ?? this.default,
475
+ user,
476
+ sessionId: undefined,
477
+ });
320
478
  }
321
479
 
322
480
  /**
@@ -333,6 +491,11 @@ export class AuthManager {
333
491
  );
334
492
  }
335
493
  await strategy.logout(session);
494
+ this.#emit(`${authEventPrefix(strategy.name)}:logged_out`, {
495
+ guardName: strategyName ?? this.default,
496
+ user: null,
497
+ error: null,
498
+ });
336
499
  }
337
500
  }
338
501
 
@@ -366,10 +529,3 @@ function isLoginCapable(
366
529
  * directly (not `AuthManager.verify`), so without this it would skip
367
530
  * the guard JWT / api-key users get.
368
531
  */
369
- export function sanitizePayload(user: UserPayload): void {
370
- for (const key of ["__proto__", "constructor", "prototype"]) {
371
- if (key in user) {
372
- delete (user as Record<string, unknown>)[key];
373
- }
374
- }
375
- }