@spinajs/rbac-http-user 2.0.486 → 2.0.487

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 (239) hide show
  1. package/lib/cjs/config/rbac-http.d.ts +0 -15
  2. package/lib/cjs/config/rbac-http.d.ts.map +1 -1
  3. package/lib/cjs/config/rbac-http.js +6 -16
  4. package/lib/cjs/config/rbac-http.js.map +1 -1
  5. package/lib/cjs/controllers/ActiveRoleController.d.ts +2 -1
  6. package/lib/cjs/controllers/ActiveRoleController.d.ts.map +1 -1
  7. package/lib/cjs/controllers/ActiveRoleController.js +7 -17
  8. package/lib/cjs/controllers/ActiveRoleController.js.map +1 -1
  9. package/lib/cjs/controllers/ImpersonationController.d.ts +7 -9
  10. package/lib/cjs/controllers/ImpersonationController.d.ts.map +1 -1
  11. package/lib/cjs/controllers/ImpersonationController.js +31 -56
  12. package/lib/cjs/controllers/ImpersonationController.js.map +1 -1
  13. package/lib/cjs/controllers/LoginController.d.ts +10 -3
  14. package/lib/cjs/controllers/LoginController.d.ts.map +1 -1
  15. package/lib/cjs/controllers/LoginController.js +39 -40
  16. package/lib/cjs/controllers/LoginController.js.map +1 -1
  17. package/lib/cjs/controllers/PasswordResetController.d.ts +54 -0
  18. package/lib/cjs/controllers/PasswordResetController.d.ts.map +1 -0
  19. package/lib/cjs/controllers/PasswordResetController.js +129 -0
  20. package/lib/cjs/controllers/PasswordResetController.js.map +1 -0
  21. package/lib/cjs/controllers/SessionsController.d.ts +65 -0
  22. package/lib/cjs/controllers/SessionsController.d.ts.map +1 -0
  23. package/lib/cjs/controllers/SessionsController.js +143 -0
  24. package/lib/cjs/controllers/SessionsController.js.map +1 -0
  25. package/lib/cjs/controllers/TwoFactorAuthController.d.ts +24 -23
  26. package/lib/cjs/controllers/TwoFactorAuthController.d.ts.map +1 -1
  27. package/lib/cjs/controllers/TwoFactorAuthController.js +39 -72
  28. package/lib/cjs/controllers/TwoFactorAuthController.js.map +1 -1
  29. package/lib/cjs/controllers/TwoFactorAuthUserController.d.ts +98 -0
  30. package/lib/cjs/controllers/TwoFactorAuthUserController.d.ts.map +1 -0
  31. package/lib/cjs/controllers/TwoFactorAuthUserController.js +195 -0
  32. package/lib/cjs/controllers/TwoFactorAuthUserController.js.map +1 -0
  33. package/lib/cjs/controllers/UserController.d.ts +10 -7
  34. package/lib/cjs/controllers/UserController.d.ts.map +1 -1
  35. package/lib/cjs/controllers/UserController.js +56 -58
  36. package/lib/cjs/controllers/UserController.js.map +1 -1
  37. package/lib/cjs/controllers/UserMetadataController.d.ts +6 -12
  38. package/lib/cjs/controllers/UserMetadataController.d.ts.map +1 -1
  39. package/lib/cjs/controllers/UserMetadataController.js +23 -72
  40. package/lib/cjs/controllers/UserMetadataController.js.map +1 -1
  41. package/lib/cjs/dto/confirm-password-dto.d.ts +23 -0
  42. package/lib/cjs/dto/confirm-password-dto.d.ts.map +1 -0
  43. package/lib/cjs/dto/{restore-password-dto.js → confirm-password-dto.js} +16 -12
  44. package/lib/cjs/dto/confirm-password-dto.js.map +1 -0
  45. package/lib/cjs/dto/password-reset-dto.d.ts +58 -0
  46. package/lib/cjs/dto/password-reset-dto.d.ts.map +1 -0
  47. package/lib/cjs/dto/password-reset-dto.js +57 -0
  48. package/lib/cjs/dto/password-reset-dto.js.map +1 -0
  49. package/lib/cjs/handlers/DefaultLogoutHandler.d.ts +4 -1
  50. package/lib/cjs/handlers/DefaultLogoutHandler.d.ts.map +1 -1
  51. package/lib/cjs/handlers/DefaultLogoutHandler.js +20 -13
  52. package/lib/cjs/handlers/DefaultLogoutHandler.js.map +1 -1
  53. package/lib/cjs/handlers/ImpersonationLogoutHandler.d.ts +4 -7
  54. package/lib/cjs/handlers/ImpersonationLogoutHandler.d.ts.map +1 -1
  55. package/lib/cjs/handlers/ImpersonationLogoutHandler.js +30 -31
  56. package/lib/cjs/handlers/ImpersonationLogoutHandler.js.map +1 -1
  57. package/lib/cjs/index.d.ts +20 -0
  58. package/lib/cjs/index.d.ts.map +1 -1
  59. package/lib/cjs/index.js +22 -0
  60. package/lib/cjs/index.js.map +1 -1
  61. package/lib/cjs/logout.d.ts +7 -0
  62. package/lib/cjs/logout.d.ts.map +1 -1
  63. package/lib/cjs/logout.js.map +1 -1
  64. package/lib/cjs/policies/2FaPolicy.d.ts +21 -1
  65. package/lib/cjs/policies/2FaPolicy.d.ts.map +1 -1
  66. package/lib/cjs/policies/2FaPolicy.js +31 -7
  67. package/lib/cjs/policies/2FaPolicy.js.map +1 -1
  68. package/lib/cjs/services/ImpersonationService.d.ts +90 -0
  69. package/lib/cjs/services/ImpersonationService.d.ts.map +1 -0
  70. package/lib/cjs/services/ImpersonationService.js +147 -0
  71. package/lib/cjs/services/ImpersonationService.js.map +1 -0
  72. package/lib/cjs/services/SessionCookies.d.ts +41 -0
  73. package/lib/cjs/services/SessionCookies.d.ts.map +1 -0
  74. package/lib/cjs/services/SessionCookies.js +62 -0
  75. package/lib/cjs/services/SessionCookies.js.map +1 -0
  76. package/lib/cjs/services/UserMetadataService.d.ts +53 -0
  77. package/lib/cjs/services/UserMetadataService.d.ts.map +1 -0
  78. package/lib/cjs/services/UserMetadataService.js +94 -0
  79. package/lib/cjs/services/UserMetadataService.js.map +1 -0
  80. package/lib/cjs/services/grants.d.ts +29 -0
  81. package/lib/cjs/services/grants.d.ts.map +1 -0
  82. package/lib/cjs/services/grants.js +43 -0
  83. package/lib/cjs/services/grants.js.map +1 -0
  84. package/lib/mjs/config/rbac-http.d.ts +0 -15
  85. package/lib/mjs/config/rbac-http.d.ts.map +1 -1
  86. package/lib/mjs/config/rbac-http.js +6 -16
  87. package/lib/mjs/config/rbac-http.js.map +1 -1
  88. package/lib/mjs/controllers/ActiveRoleController.d.ts +2 -1
  89. package/lib/mjs/controllers/ActiveRoleController.d.ts.map +1 -1
  90. package/lib/mjs/controllers/ActiveRoleController.js +8 -18
  91. package/lib/mjs/controllers/ActiveRoleController.js.map +1 -1
  92. package/lib/mjs/controllers/ImpersonationController.d.ts +7 -9
  93. package/lib/mjs/controllers/ImpersonationController.d.ts.map +1 -1
  94. package/lib/mjs/controllers/ImpersonationController.js +32 -57
  95. package/lib/mjs/controllers/ImpersonationController.js.map +1 -1
  96. package/lib/mjs/controllers/LoginController.d.ts +10 -3
  97. package/lib/mjs/controllers/LoginController.d.ts.map +1 -1
  98. package/lib/mjs/controllers/LoginController.js +42 -43
  99. package/lib/mjs/controllers/LoginController.js.map +1 -1
  100. package/lib/mjs/controllers/PasswordResetController.d.ts +54 -0
  101. package/lib/mjs/controllers/PasswordResetController.d.ts.map +1 -0
  102. package/lib/mjs/controllers/PasswordResetController.js +126 -0
  103. package/lib/mjs/controllers/PasswordResetController.js.map +1 -0
  104. package/lib/mjs/controllers/SessionsController.d.ts +65 -0
  105. package/lib/mjs/controllers/SessionsController.d.ts.map +1 -0
  106. package/lib/mjs/controllers/SessionsController.js +140 -0
  107. package/lib/mjs/controllers/SessionsController.js.map +1 -0
  108. package/lib/mjs/controllers/TwoFactorAuthController.d.ts +24 -23
  109. package/lib/mjs/controllers/TwoFactorAuthController.d.ts.map +1 -1
  110. package/lib/mjs/controllers/TwoFactorAuthController.js +43 -76
  111. package/lib/mjs/controllers/TwoFactorAuthController.js.map +1 -1
  112. package/lib/mjs/controllers/TwoFactorAuthUserController.d.ts +98 -0
  113. package/lib/mjs/controllers/TwoFactorAuthUserController.d.ts.map +1 -0
  114. package/lib/mjs/controllers/TwoFactorAuthUserController.js +192 -0
  115. package/lib/mjs/controllers/TwoFactorAuthUserController.js.map +1 -0
  116. package/lib/mjs/controllers/UserController.d.ts +10 -7
  117. package/lib/mjs/controllers/UserController.d.ts.map +1 -1
  118. package/lib/mjs/controllers/UserController.js +59 -28
  119. package/lib/mjs/controllers/UserController.js.map +1 -1
  120. package/lib/mjs/controllers/UserMetadataController.d.ts +6 -12
  121. package/lib/mjs/controllers/UserMetadataController.d.ts.map +1 -1
  122. package/lib/mjs/controllers/UserMetadataController.js +23 -72
  123. package/lib/mjs/controllers/UserMetadataController.js.map +1 -1
  124. package/lib/mjs/dto/confirm-password-dto.d.ts +23 -0
  125. package/lib/mjs/dto/confirm-password-dto.d.ts.map +1 -0
  126. package/lib/mjs/dto/{user-dto.js → confirm-password-dto.js} +15 -10
  127. package/lib/mjs/dto/confirm-password-dto.js.map +1 -0
  128. package/lib/mjs/dto/password-reset-dto.d.ts +58 -0
  129. package/lib/mjs/dto/password-reset-dto.d.ts.map +1 -0
  130. package/lib/mjs/dto/password-reset-dto.js +54 -0
  131. package/lib/mjs/dto/password-reset-dto.js.map +1 -0
  132. package/lib/mjs/handlers/DefaultLogoutHandler.d.ts +4 -1
  133. package/lib/mjs/handlers/DefaultLogoutHandler.d.ts.map +1 -1
  134. package/lib/mjs/handlers/DefaultLogoutHandler.js +23 -16
  135. package/lib/mjs/handlers/DefaultLogoutHandler.js.map +1 -1
  136. package/lib/mjs/handlers/ImpersonationLogoutHandler.d.ts +4 -7
  137. package/lib/mjs/handlers/ImpersonationLogoutHandler.d.ts.map +1 -1
  138. package/lib/mjs/handlers/ImpersonationLogoutHandler.js +31 -32
  139. package/lib/mjs/handlers/ImpersonationLogoutHandler.js.map +1 -1
  140. package/lib/mjs/index.d.ts +20 -0
  141. package/lib/mjs/index.d.ts.map +1 -1
  142. package/lib/mjs/index.js +22 -0
  143. package/lib/mjs/index.js.map +1 -1
  144. package/lib/mjs/logout.d.ts +7 -0
  145. package/lib/mjs/logout.d.ts.map +1 -1
  146. package/lib/mjs/logout.js.map +1 -1
  147. package/lib/mjs/policies/2FaPolicy.d.ts +21 -1
  148. package/lib/mjs/policies/2FaPolicy.d.ts.map +1 -1
  149. package/lib/mjs/policies/2FaPolicy.js +29 -6
  150. package/lib/mjs/policies/2FaPolicy.js.map +1 -1
  151. package/lib/mjs/services/ImpersonationService.d.ts +90 -0
  152. package/lib/mjs/services/ImpersonationService.d.ts.map +1 -0
  153. package/lib/mjs/services/ImpersonationService.js +144 -0
  154. package/lib/mjs/services/ImpersonationService.js.map +1 -0
  155. package/lib/mjs/services/SessionCookies.d.ts +41 -0
  156. package/lib/mjs/services/SessionCookies.d.ts.map +1 -0
  157. package/lib/mjs/services/SessionCookies.js +59 -0
  158. package/lib/mjs/services/SessionCookies.js.map +1 -0
  159. package/lib/mjs/services/UserMetadataService.d.ts +53 -0
  160. package/lib/mjs/services/UserMetadataService.d.ts.map +1 -0
  161. package/lib/mjs/services/UserMetadataService.js +91 -0
  162. package/lib/mjs/services/UserMetadataService.js.map +1 -0
  163. package/lib/mjs/services/grants.d.ts +29 -0
  164. package/lib/mjs/services/grants.d.ts.map +1 -0
  165. package/lib/mjs/services/grants.js +38 -0
  166. package/lib/mjs/services/grants.js.map +1 -0
  167. package/lib/tsconfig.cjs.tsbuildinfo +1 -1
  168. package/lib/tsconfig.mjs.tsbuildinfo +1 -1
  169. package/package.json +17 -11
  170. package/lib/cjs/controllers/AuthController.d.ts +0 -1
  171. package/lib/cjs/controllers/AuthController.d.ts.map +0 -1
  172. package/lib/cjs/controllers/AuthController.js +0 -211
  173. package/lib/cjs/controllers/AuthController.js.map +0 -1
  174. package/lib/cjs/controllers/FederatedLoginController.d.ts +0 -1
  175. package/lib/cjs/controllers/FederatedLoginController.d.ts.map +0 -1
  176. package/lib/cjs/controllers/FederatedLoginController.js +0 -38
  177. package/lib/cjs/controllers/FederatedLoginController.js.map +0 -1
  178. package/lib/cjs/dto/login-dto.d.ts +0 -17
  179. package/lib/cjs/dto/login-dto.d.ts.map +0 -1
  180. package/lib/cjs/dto/login-dto.js +0 -33
  181. package/lib/cjs/dto/login-dto.js.map +0 -1
  182. package/lib/cjs/dto/restore-password-dto.d.ts +0 -24
  183. package/lib/cjs/dto/restore-password-dto.d.ts.map +0 -1
  184. package/lib/cjs/dto/restore-password-dto.js.map +0 -1
  185. package/lib/cjs/dto/user-dto.d.ts +0 -22
  186. package/lib/cjs/dto/user-dto.d.ts.map +0 -1
  187. package/lib/cjs/dto/user-dto.js +0 -33
  188. package/lib/cjs/dto/user-dto.js.map +0 -1
  189. package/lib/cjs/fingerprint/FingerprintJs.d.ts +0 -1
  190. package/lib/cjs/fingerprint/FingerprintJs.d.ts.map +0 -1
  191. package/lib/cjs/fingerprint/FingerprintJs.js +0 -5
  192. package/lib/cjs/fingerprint/FingerprintJs.js.map +0 -1
  193. package/lib/cjs/middlewares/AttributeFilter.d.ts +0 -11
  194. package/lib/cjs/middlewares/AttributeFilter.d.ts.map +0 -1
  195. package/lib/cjs/middlewares/AttributeFilter.js +0 -19
  196. package/lib/cjs/middlewares/AttributeFilter.js.map +0 -1
  197. package/lib/cjs/policies/AllowFederatedLoginPolicy.d.ts +0 -7
  198. package/lib/cjs/policies/AllowFederatedLoginPolicy.d.ts.map +0 -1
  199. package/lib/cjs/policies/AllowFederatedLoginPolicy.js +0 -32
  200. package/lib/cjs/policies/AllowFederatedLoginPolicy.js.map +0 -1
  201. package/lib/cjs/policies/CaptchaPolicy.d.ts +0 -1
  202. package/lib/cjs/policies/CaptchaPolicy.d.ts.map +0 -1
  203. package/lib/cjs/policies/CaptchaPolicy.js +0 -1
  204. package/lib/cjs/policies/CaptchaPolicy.js.map +0 -1
  205. package/lib/mjs/controllers/AuthController.d.ts +0 -2
  206. package/lib/mjs/controllers/AuthController.d.ts.map +0 -1
  207. package/lib/mjs/controllers/AuthController.js +0 -212
  208. package/lib/mjs/controllers/AuthController.js.map +0 -1
  209. package/lib/mjs/controllers/FederatedLoginController.d.ts +0 -2
  210. package/lib/mjs/controllers/FederatedLoginController.d.ts.map +0 -1
  211. package/lib/mjs/controllers/FederatedLoginController.js +0 -39
  212. package/lib/mjs/controllers/FederatedLoginController.js.map +0 -1
  213. package/lib/mjs/dto/login-dto.d.ts +0 -17
  214. package/lib/mjs/dto/login-dto.d.ts.map +0 -1
  215. package/lib/mjs/dto/login-dto.js +0 -30
  216. package/lib/mjs/dto/login-dto.js.map +0 -1
  217. package/lib/mjs/dto/restore-password-dto.d.ts +0 -24
  218. package/lib/mjs/dto/restore-password-dto.d.ts.map +0 -1
  219. package/lib/mjs/dto/restore-password-dto.js +0 -31
  220. package/lib/mjs/dto/restore-password-dto.js.map +0 -1
  221. package/lib/mjs/dto/user-dto.d.ts +0 -22
  222. package/lib/mjs/dto/user-dto.d.ts.map +0 -1
  223. package/lib/mjs/dto/user-dto.js.map +0 -1
  224. package/lib/mjs/fingerprint/FingerprintJs.d.ts +0 -2
  225. package/lib/mjs/fingerprint/FingerprintJs.d.ts.map +0 -1
  226. package/lib/mjs/fingerprint/FingerprintJs.js +0 -6
  227. package/lib/mjs/fingerprint/FingerprintJs.js.map +0 -1
  228. package/lib/mjs/middlewares/AttributeFilter.d.ts +0 -11
  229. package/lib/mjs/middlewares/AttributeFilter.d.ts.map +0 -1
  230. package/lib/mjs/middlewares/AttributeFilter.js +0 -15
  231. package/lib/mjs/middlewares/AttributeFilter.js.map +0 -1
  232. package/lib/mjs/policies/AllowFederatedLoginPolicy.d.ts +0 -7
  233. package/lib/mjs/policies/AllowFederatedLoginPolicy.d.ts.map +0 -1
  234. package/lib/mjs/policies/AllowFederatedLoginPolicy.js +0 -28
  235. package/lib/mjs/policies/AllowFederatedLoginPolicy.js.map +0 -1
  236. package/lib/mjs/policies/CaptchaPolicy.d.ts +0 -2
  237. package/lib/mjs/policies/CaptchaPolicy.d.ts.map +0 -1
  238. package/lib/mjs/policies/CaptchaPolicy.js +0 -2
  239. package/lib/mjs/policies/CaptchaPolicy.js.map +0 -1
@@ -22,6 +22,9 @@ const configuration_1 = require("@spinajs/configuration");
22
22
  const rbac_http_1 = require("@spinajs/rbac-http");
23
23
  const rbac_2 = require("@spinajs/rbac");
24
24
  const logout_js_1 = require("../logout.js");
25
+ const SessionCookies_js_1 = require("../services/SessionCookies.js");
26
+ const grants_js_1 = require("../services/grants.js");
27
+ const Default2FaToken_js_1 = require("../2fa/Default2FaToken.js");
25
28
  /**
26
29
  * Authentication endpoints.
27
30
  * Handles user login, logout, and current-session inspection.
@@ -62,7 +65,8 @@ let LoginController = class LoginController extends http_1.BaseController {
62
65
  // user is automatically authorized at login
63
66
  session.Data.set('Logged', true);
64
67
  session.UserId = user.Id;
65
- if (this.TwoFactorAuthForceUser && !user.Metadata['2fa:enabled']) {
68
+ const twoFaEnabledForUser = Boolean(user.Metadata[Default2FaToken_js_1.TWO_FA_METATADATA_KEYS.ENABLED]);
69
+ if (this.TwoFactorAuthForceUser && !twoFaEnabledForUser) {
66
70
  this._log.trace('User logged in, 2fa init required', {
67
71
  Uuid: user.Uuid
68
72
  });
@@ -70,7 +74,7 @@ let LoginController = class LoginController extends http_1.BaseController {
70
74
  session.Data.set('TwoFactorAuth', true);
71
75
  result = { TwoFactorInitRequired: true };
72
76
  }
73
- else if (this.TwoFactorAuthEnabled && user.Metadata['2fa:enabled']) {
77
+ else if (this.TwoFactorAuthEnabled && twoFaEnabledForUser) {
74
78
  this._log.trace('User logged in, 2fa required', {
75
79
  Uuid: user.Uuid
76
80
  });
@@ -80,40 +84,25 @@ let LoginController = class LoginController extends http_1.BaseController {
80
84
  }
81
85
  else {
82
86
  session.Data.set('Authorized', true);
83
- const grants = this.AC.getGrants();
84
- const combinedGrants = activeRole ? (0, rbac_1._unwindGrants)(activeRole, grants) : {};
85
- // dehydrateWithRelations({ dateTimeFormat: 'iso' }) converts DateTime to ISO strings
86
- // at runtime the ORM types don't reflect the dateTimeFormat option in generics
87
- result = {
88
- ...user.dehydrateWithRelations({ dateTimeFormat: "iso" }),
89
- Role: user.Role, // temp fix for role grants, as dehydrateWithRelations returns string of roles, not array
90
- ActiveRole: activeRole,
91
- Grants: combinedGrants,
92
- };
87
+ this._log.trace('User logged in, no 2fa required', {
88
+ Uuid: user.Uuid
89
+ });
90
+ result = (0, grants_js_1.buildUserWithGrants)(user, activeRole, this.AC);
93
91
  }
94
- this._log.trace('User logged in, no 2fa required', {
95
- Uuid: user.Uuid
96
- });
97
92
  // save() schedules the session's initial expiration via the configured
98
93
  // strategy; the cookie maxAge is then derived from that real expiry (B1),
99
94
  // no longer the bogus `expiration * 1000` (~2 min) value.
100
95
  await this.SessionProvider.save(session);
101
- const coockies = [
102
- {
103
- Name: 'ssid',
104
- Value: session.SessionId,
105
- Options: {
106
- signed: true,
107
- httpOnly: true,
108
- // cookie lifetime tracks the session's real expiration
109
- maxAge: (0, rbac_1.sessionCookieMaxAge)(session),
110
- // any optional cookie options / override default ones
111
- ...this.SessionCookieConfig
112
- },
113
- },
114
- ];
96
+ this._log.info(`Session created`, {
97
+ // never the raw id — a log file must not be a bag of live credentials
98
+ Session: (0, rbac_1.hashSessionId)(session.SessionId),
99
+ User: user.Uuid,
100
+ });
115
101
  return new http_1.Ok(result, {
116
- Coockies: coockies
102
+ Coockies: [this.SessionCookies.issue(session)],
103
+ // The response carries the session id in a Set-Cookie and the user's
104
+ // own data in the body. Neither may be written to any cache.
105
+ Headers: [{ Name: 'Cache-Control', Value: 'no-store' }],
117
106
  });
118
107
  }
119
108
  catch (err) {
@@ -145,6 +134,10 @@ let LoginController = class LoginController extends http_1.BaseController {
145
134
  * If an impersonation is active, the session is NOT destroyed — instead the
146
135
  * impersonation is ended and the original user resumes their session.
147
136
  * Requires the user to be logged in (session exists), but full authorization (2FA) is not required.
137
+ *
138
+ * POST, not GET: under `SameSite=Lax` a cookie rides a top-level cross-site
139
+ * GET, so a third-party page could log any visitor out simply by linking to
140
+ * this route.
148
141
  * @security cookieAuth
149
142
  * @response 401 No active session
150
143
  */
@@ -166,7 +159,10 @@ let LoginController = class LoginController extends http_1.BaseController {
166
159
  for (const handler of sorted) {
167
160
  const result = await handler.handle(ctx);
168
161
  if (result) {
169
- return new http_1.Ok(result.Body ?? null, { Coockies: result.Cookies ?? [] });
162
+ return new http_1.Ok(result.Body ?? null, {
163
+ Coockies: result.Cookies ?? [],
164
+ Headers: result.Headers ?? [],
165
+ });
170
166
  }
171
167
  }
172
168
  // No handler claimed the request — should not happen as long as the
@@ -176,16 +172,18 @@ let LoginController = class LoginController extends http_1.BaseController {
176
172
  /**
177
173
  * Get current user
178
174
  * Returns the user object associated with the current session along with the
179
- * currently active role. Roles the user may switch to are listed in Role.
175
+ * currently active role and whether the session has completed 2FA (when
176
+ * required). Roles the user may switch to are listed in Role.
180
177
  * Requires the user to be logged in (session exists), but full authorization (2FA) is not required.
181
178
  * @security cookieAuth
182
179
  * @returns {User} User data from the current session
183
180
  * @response 401 No active session
184
181
  */
185
- async whoami(User, ActiveRole) {
182
+ async whoami(User, ActiveRole, session) {
186
183
  return new http_1.Ok({
187
184
  ...User.dehydrateWithRelations({ dateTimeFormat: 'iso' }),
188
185
  ActiveRole: ActiveRole ?? User.Role?.[0],
186
+ Authorized: session.Data.get('Authorized') ?? true,
189
187
  });
190
188
  }
191
189
  };
@@ -215,9 +213,9 @@ __decorate([
215
213
  __metadata("design:type", Boolean)
216
214
  ], LoginController.prototype, "TwoFactorAuthForceUser", void 0);
217
215
  __decorate([
218
- (0, configuration_1.Config)('rbac.session.cookie', {}),
219
- __metadata("design:type", Object)
220
- ], LoginController.prototype, "SessionCookieConfig", void 0);
216
+ (0, di_1.Autoinject)(SessionCookies_js_1.SessionCookieFactory),
217
+ __metadata("design:type", SessionCookies_js_1.SessionCookieFactory)
218
+ ], LoginController.prototype, "SessionCookies", void 0);
221
219
  __decorate([
222
220
  (0, di_1.Autoinject)(rbac_1.AccessControl),
223
221
  __metadata("design:type", rbac_1.AccessControl)
@@ -226,16 +224,16 @@ __decorate([
226
224
  (0, http_1.Post)(),
227
225
  (0, rbac_http_1.SkipModelPermission)(),
228
226
  __param(0, (0, rbac_http_1.User)()),
229
- __param(1, (0, http_1.Cookie)(true)),
227
+ __param(1, (0, rbac_http_1.SessionId)()),
230
228
  __param(2, (0, http_1.Body)()),
231
229
  __metadata("design:type", Function),
232
230
  __metadata("design:paramtypes", [rbac_2.User, String, userLogin_dto_js_1.UserLoginDto]),
233
231
  __metadata("design:returntype", Promise)
234
232
  ], LoginController.prototype, "login", null);
235
233
  __decorate([
236
- (0, http_1.Get)(),
234
+ (0, http_1.Post)(),
237
235
  (0, http_1.Policy)(rbac_http_1.LoggedPolicy),
238
- __param(0, (0, http_1.Cookie)(true)),
236
+ __param(0, (0, rbac_http_1.SessionId)()),
239
237
  __param(1, (0, rbac_http_1.Session)()),
240
238
  __param(2, (0, rbac_http_1.User)()),
241
239
  __metadata("design:type", Function),
@@ -247,8 +245,9 @@ __decorate([
247
245
  (0, http_1.Policy)(rbac_http_1.LoggedPolicy),
248
246
  __param(0, (0, rbac_http_1.User)()),
249
247
  __param(1, (0, rbac_http_1.FromSession)()),
248
+ __param(2, (0, rbac_http_1.Session)()),
250
249
  __metadata("design:type", Function),
251
- __metadata("design:paramtypes", [rbac_2.User, String]),
250
+ __metadata("design:paramtypes", [rbac_2.User, String, Object]),
252
251
  __metadata("design:returntype", Promise)
253
252
  ], LoginController.prototype, "whoami", null);
254
253
  exports.LoginController = LoginController = __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"LoginController.js","sourceRoot":"","sources":["../../../src/controllers/LoginController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LoginController.js","sourceRoot":"","sources":["../../../src/controllers/LoginController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,8DAAuD;AACvD,wCAAoG;AACpG,wCAAyI;AACzI,oDAAiE;AACjE,oCAA6C;AAC7C,0DAAkF;AAElF,kDAAiK;AACjK,wCAAqC;AAErC,4CAA6D;AAC7D,qEAAqE;AACrE,qDAA4D;AAC5D,kEAAmE;AAGnE;;;;;GAKG;AAEI,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,qBAAc;IA2BjD;;;;;;;;;OASG;IAGU,AAAN,KAAK,CAAC,KAAK,CAAiB,MAAY,EAAe,IAAY,EAAU,WAAyB;QAC3G,IAAI,CAAC;YAEH,0DAA0D;YAC1D,2BAA2B;YAC3B,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;gBACnB,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC1C,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,IAAA,YAAK,EAAC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;YAClE,MAAM,OAAO,GAAG,IAAI,kBAAW,EAAE,CAAC;YAElC,IAAI,MAAsB,CAAC;YAE3B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAEpC,8DAA8D;YAC9D,oEAAoE;YACpE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAClC,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;YAC7C,CAAC;YAED,8BAA8B;YAC9B,sEAAsE;YACtE,+EAA+E;YAC/E,yDAAyD;YACzD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACjC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;YAEzB,MAAM,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,2CAAsB,CAAC,OAAO,CAAC,CAAC,CAAC;YAEnF,IAAI,IAAI,CAAC,sBAAsB,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBACxD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,mCAAmC,EAAE;oBACnD,IAAI,EAAE,IAAI,CAAC,IAAI;iBAChB,CAAC,CAAC;gBAEH,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;gBACtC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;gBAExC,MAAM,GAAG,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC;YAC3C,CAAC;iBACI,IAAI,IAAI,CAAC,oBAAoB,IAAI,mBAAmB,EAAE,CAAC;gBAE1D,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,8BAA8B,EAAE;oBAC9C,IAAI,EAAE,IAAI,CAAC,IAAI;iBAChB,CAAC,CAAC;gBAEH,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;gBACtC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;gBAExC,MAAM,GAAG,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC;YAC3C,CAAC;iBAAM,CAAC;gBAEN,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;gBAErC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,iCAAiC,EAAE;oBACjD,IAAI,EAAE,IAAI,CAAC,IAAI;iBAChB,CAAC,CAAC;gBAEH,MAAM,GAAG,IAAA,+BAAmB,EAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;YAC1D,CAAC;YAED,uEAAuE;YACvE,0EAA0E;YAC1E,0DAA0D;YAC1D,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEzC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE;gBAChC,sEAAsE;gBACtE,OAAO,EAAE,IAAA,oBAAa,EAAC,OAAO,CAAC,SAAS,CAAC;gBACzC,IAAI,EAAE,IAAI,CAAC,IAAI;aAChB,CAAC,CAAC;YAEH,OAAO,IAAI,SAAE,CAAC,MAAM,EAAE;gBACpB,QAAQ,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAE9C,qEAAqE;gBACrE,6DAA6D;gBAC7D,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;aACxD,CAAC,CAAC;QAEL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,yEAAyE;YACzE,wEAAwE;YACxE,wEAAwE;YACxE,yEAAyE;YACzE,kEAAkE;YAClE,qEAAqE;YACrE,8CAA8C;YAC9C,MAAM,aAAa,GAAG,GAAG,YAAY,sBAAS,IAAI,GAAG,YAAY,4BAAe,CAAC;YAEjF,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAY,EAAE,iCAAiC,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;gBACrF,MAAM,GAAG,CAAC;YACZ,CAAC;YAED,MAAM,MAAM,GAAG,GAAG,YAAY,sBAAS,CAAC,CAAC,CAAC,8BAAuB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC;YAE/G,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAY,EAAE,oBAAoB,WAAW,EAAE,KAAK,KAAK,MAAM,EAAE,CAAC,CAAC;YAElF,OAAO,IAAI,mBAAY,CAAC;gBACtB,KAAK,EAAE;oBACL,IAAI,EAAE,eAAe;oBACrB,OAAO,EAAE,6BAA6B;iBACvC;aACF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;OAYG;IAGU,AAAN,KAAK,CAAC,MAAM,CAAc,IAAY,EAAqB,OAAiB,EAAkB,IAAU;QAC7G,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,IAAI,SAAE,EAAE,CAAC;QAClB,CAAC;QAED,uEAAuE;QACvE,wEAAwE;QACxE,kCAAkC;QAClC,iEAAiE;QACjE,gDAAgD;QAChD,0EAA0E;QAC1E,sBAAsB;QACtB,wEAAwE;QACxE,MAAM,QAAQ,GAAG,MAAM,OAAE,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,yBAAa,CAAC,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;QAErE,MAAM,GAAG,GAAmB,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACzE,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzC,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,IAAI,SAAE,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE;oBACjC,QAAQ,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;oBAC9B,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;iBAC9B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,oEAAoE;QACpE,qEAAqE;QACrE,OAAO,IAAI,SAAE,EAAE,CAAC;IAClB,CAAC;IAED;;;;;;;;;OASG;IAGU,AAAN,KAAK,CAAC,MAAM,CAAiB,IAAU,EAAiB,UAAkB,EAAqB,OAAiB;QAErH,OAAO,IAAI,SAAE,CAAC;YACZ,GAAG,IAAI,CAAC,sBAAsB,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;YACzD,UAAU,EAAE,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACxC,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI;SACnD,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAxNY,0CAAe;AAEhB;IADT,IAAA,eAAU,GAAE;8BACY,6BAAa;sDAAC;AAG7B;IADT,IAAA,iCAAiB,EAAC,WAAW,CAAC;8BACP,mBAAY;qDAAC;AAG3B;IADT,IAAA,iCAAiB,EAAC,cAAc,CAAC;8BACP,sBAAe;wDAAC;AAKjC;IAHT,IAAA,sBAAM,EAAC,4BAA4B,EAAE;QACpC,YAAY,EAAE,KAAK;KACpB,CAAC;;6DACsC;AAM9B;IAHT,IAAA,sBAAM,EAAC,8BAA8B,EAAE;QACtC,YAAY,EAAE,KAAK;KACpB,CAAC;;+DACwC;AAGhC;IADT,IAAA,eAAU,EAAC,wCAAoB,CAAC;8BACP,wCAAoB;uDAAC;AAGrC;IADT,IAAA,eAAU,EAAC,oBAAa,CAAC;8BACZ,oBAAa;2CAAC;AAcf;IAFZ,IAAA,WAAI,GAAE;IACN,IAAA,+BAAmB,GAAE;IACF,WAAA,IAAA,gBAAY,GAAE,CAAA;IAAgB,WAAA,IAAA,qBAAS,GAAE,CAAA;IAAgB,WAAA,IAAA,WAAI,GAAE,CAAA;;qCAAxC,WAAI,UAAkD,+BAAY;;4CA4G5G;AAiBY;IAFZ,IAAA,WAAI,GAAE;IACN,IAAA,aAAM,EAAC,wBAAY,CAAC;IACA,WAAA,IAAA,qBAAS,GAAE,CAAA;IAAgB,WAAA,IAAA,mBAAe,GAAE,CAAA;IAAqB,WAAA,IAAA,gBAAY,GAAE,CAAA;;qDAAO,WAAI;;6CA8B9G;AAcY;IAFZ,IAAA,UAAG,GAAE;IACL,IAAA,aAAM,EAAC,wBAAY,CAAC;IACA,WAAA,IAAA,gBAAY,GAAE,CAAA;IAAc,WAAA,IAAA,uBAAW,GAAE,CAAA;IAAsB,WAAA,IAAA,mBAAe,GAAE,CAAA;;qCAA3D,WAAI;;6CAO7C;0BAvNU,eAAe;IAD3B,IAAA,eAAQ,EAAC,MAAM,CAAC;GACJ,eAAe,CAwN3B"}
@@ -0,0 +1,54 @@
1
+ import { BaseController, BadRequestResponse, Ok } from '@spinajs/http';
2
+ import { PasswordResetConfirmDto, PasswordResetRequestDto } from '../dto/password-reset-dto.js';
3
+ /** Reply shared by both reset routes — deliberately says nothing about the account. */
4
+ export interface IPasswordResetAck {
5
+ Ok: true;
6
+ }
7
+ /**
8
+ * Password reset for users who cannot log in.
9
+ *
10
+ * Two public, unauthenticated steps: request a token, then redeem it. The token
11
+ * itself is issued into the user's metadata by `passwordChangeRequest` and
12
+ * delivered out of band (the `UserPasswordChangeRequest` event is what an app
13
+ * hooks to send the mail) — it is never returned over HTTP, so possession of
14
+ * the mailbox is what authorizes the reset.
15
+ *
16
+ * Neither route reveals whether an account exists. Both answer the same way for
17
+ * a known and an unknown address, which is the whole point of a reset endpoint
18
+ * that anybody may call: an attacker must not be able to farm valid addresses
19
+ * from it, and a failed redemption must not distinguish "no such user" from
20
+ * "wrong token".
21
+ *
22
+ * NOTE: these routes are unauthenticated and cheap to call in a loop. Put a
23
+ * rate limit in front of them at the edge — this package does not provide one.
24
+ *
25
+ * @tags Authentication
26
+ */
27
+ export declare class PasswordResetController extends BaseController {
28
+ /**
29
+ * Request a password reset
30
+ * Issues a reset token for the account and emits `UserPasswordChangeRequest` so the
31
+ * application can deliver it. Always succeeds, whether or not the address is known.
32
+ * @security []
33
+ * @returns {IPasswordResetAck} Acknowledgement — never indicates whether the account exists
34
+ */
35
+ requestReset(payload: PasswordResetRequestDto): Promise<Ok<IPasswordResetAck>>;
36
+ /**
37
+ * Complete a password reset
38
+ * Redeems the token issued by `POST /auth/password/reset-request` and sets the new
39
+ * password. The token is single-use and expires after `rbac.password.passwordResetWaitTime`.
40
+ * @security []
41
+ * @returns {IPasswordResetAck} Acknowledgement of a successful reset
42
+ * @response 400 New passwords do not match, or the token is invalid or expired
43
+ */
44
+ confirmReset(payload: PasswordResetConfirmDto): Promise<Ok<IPasswordResetAck> | BadRequestResponse>;
45
+ /**
46
+ * Issue a reset token into the user's metadata and emit
47
+ * `UserPasswordChangeRequest`. Wraps the module-level action so tests can
48
+ * stub it without a database.
49
+ */
50
+ protected issueToken(email: string): Promise<unknown>;
51
+ /** Redeem a reset token. Wrapped for the same reason as {@link issueToken}. */
52
+ protected redeemToken(email: string, password: string, token: string): Promise<unknown>;
53
+ }
54
+ //# sourceMappingURL=PasswordResetController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PasswordResetController.d.ts","sourceRoot":"","sources":["../../../src/controllers/PasswordResetController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAkB,kBAAkB,EAAE,EAAE,EAAQ,MAAM,eAAe,CAAC;AAI7F,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEhG,uFAAuF;AACvF,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,IAAI,CAAC;CACV;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,uBAAwB,SAAQ,cAAc;IACzD;;;;;;OAMG;IAGU,YAAY,CAAS,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC;IAcnG;;;;;;;OAOG;IAGU,YAAY,CAAS,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,EAAE,CAAC,iBAAiB,CAAC,GAAG,kBAAkB,CAAC;IA+BxH;;;;OAIG;IACH,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIrD,+EAA+E;IAC/E,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAGxF"}
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.PasswordResetController = void 0;
16
+ const http_1 = require("@spinajs/http");
17
+ const rbac_1 = require("@spinajs/rbac");
18
+ const exceptions_1 = require("@spinajs/exceptions");
19
+ const rbac_http_1 = require("@spinajs/rbac-http");
20
+ const password_reset_dto_js_1 = require("../dto/password-reset-dto.js");
21
+ /**
22
+ * Password reset for users who cannot log in.
23
+ *
24
+ * Two public, unauthenticated steps: request a token, then redeem it. The token
25
+ * itself is issued into the user's metadata by `passwordChangeRequest` and
26
+ * delivered out of band (the `UserPasswordChangeRequest` event is what an app
27
+ * hooks to send the mail) — it is never returned over HTTP, so possession of
28
+ * the mailbox is what authorizes the reset.
29
+ *
30
+ * Neither route reveals whether an account exists. Both answer the same way for
31
+ * a known and an unknown address, which is the whole point of a reset endpoint
32
+ * that anybody may call: an attacker must not be able to farm valid addresses
33
+ * from it, and a failed redemption must not distinguish "no such user" from
34
+ * "wrong token".
35
+ *
36
+ * NOTE: these routes are unauthenticated and cheap to call in a loop. Put a
37
+ * rate limit in front of them at the edge — this package does not provide one.
38
+ *
39
+ * @tags Authentication
40
+ */
41
+ let PasswordResetController = class PasswordResetController extends http_1.BaseController {
42
+ /**
43
+ * Request a password reset
44
+ * Issues a reset token for the account and emits `UserPasswordChangeRequest` so the
45
+ * application can deliver it. Always succeeds, whether or not the address is known.
46
+ * @security []
47
+ * @returns {IPasswordResetAck} Acknowledgement — never indicates whether the account exists
48
+ */
49
+ async requestReset(payload) {
50
+ try {
51
+ await this.issueToken(payload.Email);
52
+ }
53
+ catch (err) {
54
+ // Swallowed on purpose. An unknown address, a deleted account or a
55
+ // banned one must produce exactly the response a valid address does —
56
+ // otherwise this route becomes an account enumeration oracle. Real
57
+ // faults ( mail queue, database ) are logged for operators.
58
+ this._log.warn(err, `Password reset request could not be processed for ${payload.Email}`);
59
+ }
60
+ return new http_1.Ok({ Ok: true });
61
+ }
62
+ /**
63
+ * Complete a password reset
64
+ * Redeems the token issued by `POST /auth/password/reset-request` and sets the new
65
+ * password. The token is single-use and expires after `rbac.password.passwordResetWaitTime`.
66
+ * @security []
67
+ * @returns {IPasswordResetAck} Acknowledgement of a successful reset
68
+ * @response 400 New passwords do not match, or the token is invalid or expired
69
+ */
70
+ async confirmReset(payload) {
71
+ if (payload.Password !== payload.ConfirmPassword) {
72
+ throw new exceptions_1.InvalidArgument('password does not match');
73
+ }
74
+ try {
75
+ await this.redeemToken(payload.Email, payload.Password, payload.Token);
76
+ }
77
+ catch (err) {
78
+ // One opaque failure for every rejection reason: unknown account, wrong
79
+ // token, expired token. Distinguishing them would tell a caller which
80
+ // addresses exist and let them probe tokens by the error they get back.
81
+ const isRedemptionFailure = err instanceof exceptions_1.ErrorCode || err instanceof exceptions_1.InvalidArgument;
82
+ if (!isRedemptionFailure) {
83
+ this._log.error(err, `Password reset failed unexpectedly for ${payload.Email}`);
84
+ throw err;
85
+ }
86
+ this._log.warn(err, `Password reset rejected for ${payload.Email}`);
87
+ return new http_1.BadRequestResponse({
88
+ error: {
89
+ code: 'E_RESET_TOKEN_INVALID',
90
+ message: 'Password reset token is invalid or has expired',
91
+ },
92
+ });
93
+ }
94
+ return new http_1.Ok({ Ok: true });
95
+ }
96
+ /**
97
+ * Issue a reset token into the user's metadata and emit
98
+ * `UserPasswordChangeRequest`. Wraps the module-level action so tests can
99
+ * stub it without a database.
100
+ */
101
+ issueToken(email) {
102
+ return (0, rbac_1.passwordChangeRequest)(email);
103
+ }
104
+ /** Redeem a reset token. Wrapped for the same reason as {@link issueToken}. */
105
+ redeemToken(email, password, token) {
106
+ return (0, rbac_1.confirmPasswordReset)(email, password, token);
107
+ }
108
+ };
109
+ exports.PasswordResetController = PasswordResetController;
110
+ __decorate([
111
+ (0, http_1.Post)('password/reset-request'),
112
+ (0, rbac_http_1.SkipModelPermission)(),
113
+ __param(0, (0, http_1.Body)()),
114
+ __metadata("design:type", Function),
115
+ __metadata("design:paramtypes", [password_reset_dto_js_1.PasswordResetRequestDto]),
116
+ __metadata("design:returntype", Promise)
117
+ ], PasswordResetController.prototype, "requestReset", null);
118
+ __decorate([
119
+ (0, http_1.Post)('password/reset'),
120
+ (0, rbac_http_1.SkipModelPermission)(),
121
+ __param(0, (0, http_1.Body)()),
122
+ __metadata("design:type", Function),
123
+ __metadata("design:paramtypes", [password_reset_dto_js_1.PasswordResetConfirmDto]),
124
+ __metadata("design:returntype", Promise)
125
+ ], PasswordResetController.prototype, "confirmReset", null);
126
+ exports.PasswordResetController = PasswordResetController = __decorate([
127
+ (0, http_1.BasePath)('auth')
128
+ ], PasswordResetController);
129
+ //# sourceMappingURL=PasswordResetController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PasswordResetController.js","sourceRoot":"","sources":["../../../src/controllers/PasswordResetController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,wCAA6F;AAC7F,wCAA4E;AAC5E,oDAAiE;AACjE,kDAAyD;AACzD,wEAAgG;AAOhG;;;;;;;;;;;;;;;;;;;GAmBG;AAEI,IAAM,uBAAuB,GAA7B,MAAM,uBAAwB,SAAQ,qBAAc;IACzD;;;;;;OAMG;IAGU,AAAN,KAAK,CAAC,YAAY,CAAS,OAAgC;QAChE,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,mEAAmE;YACnE,sEAAsE;YACtE,mEAAmE;YACnE,4DAA4D;YAC5D,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAY,EAAE,qDAAqD,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACrG,CAAC;QAED,OAAO,IAAI,SAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAuB,CAAC,CAAC;IACnD,CAAC;IAED;;;;;;;OAOG;IAGU,AAAN,KAAK,CAAC,YAAY,CAAS,OAAgC;QAChE,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,eAAe,EAAE,CAAC;YACjD,MAAM,IAAI,4BAAe,CAAC,yBAAyB,CAAC,CAAC;QACvD,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACzE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,wEAAwE;YACxE,sEAAsE;YACtE,wEAAwE;YACxE,MAAM,mBAAmB,GAAG,GAAG,YAAY,sBAAS,IAAI,GAAG,YAAY,4BAAe,CAAC;YAEvF,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAY,EAAE,0CAA0C,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;gBACzF,MAAM,GAAG,CAAC;YACZ,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAY,EAAE,+BAA+B,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;YAE7E,OAAO,IAAI,yBAAkB,CAAC;gBAC5B,KAAK,EAAE;oBACL,IAAI,EAAE,uBAAuB;oBAC7B,OAAO,EAAE,gDAAgD;iBAC1D;aACF,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,SAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAuB,CAAC,CAAC;IACnD,CAAC;IAED;;;;OAIG;IACO,UAAU,CAAC,KAAa;QAChC,OAAO,IAAA,4BAAqB,EAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IAED,+EAA+E;IACrE,WAAW,CAAC,KAAa,EAAE,QAAgB,EAAE,KAAa;QAClE,OAAO,IAAA,2BAAoB,EAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC;CACF,CAAA;AA9EY,0DAAuB;AAUrB;IAFZ,IAAA,WAAI,EAAC,wBAAwB,CAAC;IAC9B,IAAA,+BAAmB,GAAE;IACK,WAAA,IAAA,WAAI,GAAE,CAAA;;qCAAU,+CAAuB;;2DAYjE;AAYY;IAFZ,IAAA,WAAI,EAAC,gBAAgB,CAAC;IACtB,IAAA,+BAAmB,GAAE;IACK,WAAA,IAAA,WAAI,GAAE,CAAA;;qCAAU,+CAAuB;;2DA6BjE;kCA/DU,uBAAuB;IADnC,IAAA,eAAQ,EAAC,MAAM,CAAC;GACJ,uBAAuB,CA8EnC"}
@@ -0,0 +1,65 @@
1
+ import { BaseController, NotFound, Ok } from '@spinajs/http';
2
+ import { SessionProvider, User as UserModel } from '@spinajs/rbac';
3
+ import type { ISession } from '@spinajs/rbac';
4
+ import { Log } from '@spinajs/log';
5
+ /** One live session of the calling user. */
6
+ export interface IUserSessionEntry {
7
+ /**
8
+ * Opaque, stable handle for the session. Deliberately NOT the session id:
9
+ * listing your own sessions must not hand out working credentials for them,
10
+ * because the response ( and anything that caches or logs it ) would then be
11
+ * as good as the cookies themselves.
12
+ */
13
+ Handle: string;
14
+ /** ISO instant the session was opened */
15
+ Created: string;
16
+ /** ISO instant the session expires, or null when it never does */
17
+ Expires: string | null;
18
+ /** True for the session making this request */
19
+ Current: boolean;
20
+ }
21
+ /**
22
+ * Active sessions of the calling user — "where am I logged in", plus the means
23
+ * to end any of them.
24
+ *
25
+ * OWASP asks for exactly this: the user should be able to see concurrent
26
+ * sessions and terminate them remotely, which is how a person who suspects a
27
+ * stolen cookie gets rid of it without an administrator.
28
+ *
29
+ * @tags User
30
+ */
31
+ export declare class SessionsController extends BaseController {
32
+ protected Log: Log;
33
+ protected SessionProvider: SessionProvider;
34
+ /**
35
+ * List own sessions
36
+ * Returns every live session of the authenticated user, newest first, with the
37
+ * one making the request flagged.
38
+ * @security cookieAuth
39
+ * @returns {IUserSessionEntry[]} Live sessions of the calling user
40
+ * @response 401 Unauthorized — valid session required
41
+ */
42
+ list(user: UserModel, ssid: string): Promise<Ok<IUserSessionEntry[]>>;
43
+ /**
44
+ * Revoke one session
45
+ * Ends the session identified by its handle. Revoking the current session is
46
+ * allowed and logs the caller out.
47
+ * @security cookieAuth
48
+ * @param handle Session handle as returned by `GET /user/sessions`
49
+ * @response 200 Session revoked
50
+ * @response 401 Unauthorized — valid session required
51
+ * @response 404 No such session for this user
52
+ */
53
+ revoke(user: UserModel, handle: string): Promise<Ok | NotFound>;
54
+ /**
55
+ * Revoke every other session
56
+ * Ends all sessions of the user except the one making the request — the
57
+ * "log out everywhere else" action after a suspected compromise.
58
+ * @security cookieAuth
59
+ * @response 200 Other sessions revoked
60
+ * @response 401 Unauthorized — valid session required
61
+ */
62
+ revokeOthers(user: UserModel, ssid: string): Promise<Ok>;
63
+ protected toEntry(session: ISession, currentHandle: string | null): IUserSessionEntry;
64
+ }
65
+ //# sourceMappingURL=SessionsController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionsController.d.ts","sourceRoot":"","sources":["../../../src/controllers/SessionsController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAsB,QAAQ,EAAE,EAAE,EAAiB,MAAM,eAAe,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,IAAI,IAAI,SAAS,EAAiB,MAAM,eAAe,CAAC;AAClF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAG3C,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAEhB,kEAAkE;IAClE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvB,+CAA+C;IAC/C,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,qBAGa,kBAAmB,SAAQ,cAAc;IAEpD,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAGnB,SAAS,CAAC,eAAe,EAAE,eAAe,CAAC;IAE3C;;;;;;;OAOG;IAGU,IAAI,CAAS,IAAI,EAAE,SAAS,EAAkB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAW1G;;;;;;;;;OASG;IAGU,MAAM,CAAS,IAAI,EAAE,SAAS,EAAW,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,GAAG,QAAQ,CAAC;IAkB7F;;;;;;;OAOG;IAGU,YAAY,CAAS,IAAI,EAAE,SAAS,EAAkB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IAkB7F,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,iBAAiB;CAUtF"}
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.SessionsController = void 0;
16
+ const http_1 = require("@spinajs/http");
17
+ const rbac_1 = require("@spinajs/rbac");
18
+ const configuration_1 = require("@spinajs/configuration");
19
+ const log_1 = require("@spinajs/log");
20
+ const rbac_http_1 = require("@spinajs/rbac-http");
21
+ /**
22
+ * Active sessions of the calling user — "where am I logged in", plus the means
23
+ * to end any of them.
24
+ *
25
+ * OWASP asks for exactly this: the user should be able to see concurrent
26
+ * sessions and terminate them remotely, which is how a person who suspects a
27
+ * stolen cookie gets rid of it without an administrator.
28
+ *
29
+ * @tags User
30
+ */
31
+ let SessionsController = class SessionsController extends http_1.BaseController {
32
+ /**
33
+ * List own sessions
34
+ * Returns every live session of the authenticated user, newest first, with the
35
+ * one making the request flagged.
36
+ * @security cookieAuth
37
+ * @returns {IUserSessionEntry[]} Live sessions of the calling user
38
+ * @response 401 Unauthorized — valid session required
39
+ */
40
+ async list(user, ssid) {
41
+ const sessions = await this.SessionProvider.listByUser(user.Id);
42
+ const current = ssid ? (0, rbac_1.hashSessionId)(ssid) : null;
43
+ const entries = sessions
44
+ .map((s) => this.toEntry(s, current))
45
+ .sort((a, b) => (a.Created < b.Created ? 1 : -1));
46
+ return new http_1.Ok(entries);
47
+ }
48
+ /**
49
+ * Revoke one session
50
+ * Ends the session identified by its handle. Revoking the current session is
51
+ * allowed and logs the caller out.
52
+ * @security cookieAuth
53
+ * @param handle Session handle as returned by `GET /user/sessions`
54
+ * @response 200 Session revoked
55
+ * @response 401 Unauthorized — valid session required
56
+ * @response 404 No such session for this user
57
+ */
58
+ async revoke(user, handle) {
59
+ // Resolved through the user's OWN session list, so a handle belonging to
60
+ // somebody else's session simply is not found here — the route cannot be
61
+ // used to end a stranger's session even if its handle leaks.
62
+ const sessions = await this.SessionProvider.listByUser(user.Id);
63
+ const match = sessions.find((s) => (0, rbac_1.hashSessionId)(s.SessionId) === handle);
64
+ if (!match) {
65
+ return new http_1.NotFound({ error: { code: 'E_SESSION_NOT_FOUND', message: 'No such session' } });
66
+ }
67
+ await this.SessionProvider.delete(match.SessionId);
68
+ this.Log.info(`Session revoked by its owner`, { Session: handle, User: user.Uuid });
69
+ return new http_1.Ok(null, { Headers: [{ Name: 'Cache-Control', Value: 'no-store' }] });
70
+ }
71
+ /**
72
+ * Revoke every other session
73
+ * Ends all sessions of the user except the one making the request — the
74
+ * "log out everywhere else" action after a suspected compromise.
75
+ * @security cookieAuth
76
+ * @response 200 Other sessions revoked
77
+ * @response 401 Unauthorized — valid session required
78
+ */
79
+ async revokeOthers(user, ssid) {
80
+ const sessions = await this.SessionProvider.listByUser(user.Id);
81
+ let revoked = 0;
82
+ for (const session of sessions) {
83
+ if (session.SessionId === ssid) {
84
+ continue;
85
+ }
86
+ await this.SessionProvider.delete(session.SessionId);
87
+ revoked++;
88
+ }
89
+ this.Log.info(`Revoked ${revoked} other session(s)`, { User: user.Uuid });
90
+ return new http_1.Ok({ Revoked: revoked }, { Headers: [{ Name: 'Cache-Control', Value: 'no-store' }] });
91
+ }
92
+ toEntry(session, currentHandle) {
93
+ const handle = (0, rbac_1.hashSessionId)(session.SessionId);
94
+ return {
95
+ Handle: handle,
96
+ Created: session.Creation?.toISO() ?? '',
97
+ Expires: session.Expiration?.toISO() ?? null,
98
+ Current: handle === currentHandle,
99
+ };
100
+ }
101
+ };
102
+ exports.SessionsController = SessionsController;
103
+ __decorate([
104
+ (0, log_1.Logger)('rbac-session'),
105
+ __metadata("design:type", log_1.Log)
106
+ ], SessionsController.prototype, "Log", void 0);
107
+ __decorate([
108
+ (0, configuration_1.AutoinjectService)('rbac.session'),
109
+ __metadata("design:type", rbac_1.SessionProvider)
110
+ ], SessionsController.prototype, "SessionProvider", void 0);
111
+ __decorate([
112
+ (0, http_1.Get)('sessions'),
113
+ (0, rbac_http_1.Permission)(['readOwn']),
114
+ __param(0, (0, rbac_http_1.User)()),
115
+ __param(1, (0, rbac_http_1.SessionId)()),
116
+ __metadata("design:type", Function),
117
+ __metadata("design:paramtypes", [rbac_1.User, String]),
118
+ __metadata("design:returntype", Promise)
119
+ ], SessionsController.prototype, "list", null);
120
+ __decorate([
121
+ (0, http_1.Del)('sessions/:handle'),
122
+ (0, rbac_http_1.Permission)(['updateOwn']),
123
+ __param(0, (0, rbac_http_1.User)()),
124
+ __param(1, (0, http_1.Param)()),
125
+ __metadata("design:type", Function),
126
+ __metadata("design:paramtypes", [rbac_1.User, String]),
127
+ __metadata("design:returntype", Promise)
128
+ ], SessionsController.prototype, "revoke", null);
129
+ __decorate([
130
+ (0, http_1.Del)('sessions'),
131
+ (0, rbac_http_1.Permission)(['updateOwn']),
132
+ __param(0, (0, rbac_http_1.User)()),
133
+ __param(1, (0, rbac_http_1.SessionId)()),
134
+ __metadata("design:type", Function),
135
+ __metadata("design:paramtypes", [rbac_1.User, String]),
136
+ __metadata("design:returntype", Promise)
137
+ ], SessionsController.prototype, "revokeOthers", null);
138
+ exports.SessionsController = SessionsController = __decorate([
139
+ (0, http_1.BasePath)('user'),
140
+ (0, rbac_http_1.Resource)('user'),
141
+ (0, http_1.Policy)(rbac_http_1.AuthorizedPolicy)
142
+ ], SessionsController);
143
+ //# sourceMappingURL=SessionsController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionsController.js","sourceRoot":"","sources":["../../../src/controllers/SessionsController.ts"],"names":[],"mappings":"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"}