@spinajs/rbac 2.0.521 → 2.0.522

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 (81) hide show
  1. package/lib/cjs/actions.d.ts +269 -93
  2. package/lib/cjs/actions.d.ts.map +1 -1
  3. package/lib/cjs/actions.js +695 -354
  4. package/lib/cjs/actions.js.map +1 -1
  5. package/lib/cjs/auth.d.ts.map +1 -1
  6. package/lib/cjs/auth.js +6 -6
  7. package/lib/cjs/auth.js.map +1 -1
  8. package/lib/cjs/cli/ChangeUserPassword.d.ts.map +1 -1
  9. package/lib/cjs/cli/ChangeUserPassword.js +2 -2
  10. package/lib/cjs/cli/ChangeUserPassword.js.map +1 -1
  11. package/lib/cjs/cli/CreateUser.d.ts.map +1 -1
  12. package/lib/cjs/cli/CreateUser.js +8 -1
  13. package/lib/cjs/cli/CreateUser.js.map +1 -1
  14. package/lib/cjs/config/rbac.d.ts +40 -0
  15. package/lib/cjs/config/rbac.d.ts.map +1 -1
  16. package/lib/cjs/config/rbac.js +40 -0
  17. package/lib/cjs/config/rbac.js.map +1 -1
  18. package/lib/cjs/events/UserCreated.d.ts +2 -1
  19. package/lib/cjs/events/UserCreated.d.ts.map +1 -1
  20. package/lib/cjs/events/UserCreated.js +13 -3
  21. package/lib/cjs/events/UserCreated.js.map +1 -1
  22. package/lib/cjs/exceptions.d.ts +69 -0
  23. package/lib/cjs/exceptions.d.ts.map +1 -0
  24. package/lib/cjs/exceptions.js +86 -0
  25. package/lib/cjs/exceptions.js.map +1 -0
  26. package/lib/cjs/index.d.ts +1 -0
  27. package/lib/cjs/index.d.ts.map +1 -1
  28. package/lib/cjs/index.js +1 -0
  29. package/lib/cjs/index.js.map +1 -1
  30. package/lib/cjs/interfaces.d.ts +2 -7
  31. package/lib/cjs/interfaces.d.ts.map +1 -1
  32. package/lib/cjs/interfaces.js +1 -8
  33. package/lib/cjs/interfaces.js.map +1 -1
  34. package/lib/cjs/password.d.ts +18 -1
  35. package/lib/cjs/password.d.ts.map +1 -1
  36. package/lib/cjs/password.js +61 -5
  37. package/lib/cjs/password.js.map +1 -1
  38. package/lib/cjs/profile.js +1 -1
  39. package/lib/cjs/profile.js.map +1 -1
  40. package/lib/mjs/actions.d.ts +269 -93
  41. package/lib/mjs/actions.d.ts.map +1 -1
  42. package/lib/mjs/actions.js +682 -358
  43. package/lib/mjs/actions.js.map +1 -1
  44. package/lib/mjs/auth.d.ts.map +1 -1
  45. package/lib/mjs/auth.js +7 -7
  46. package/lib/mjs/auth.js.map +1 -1
  47. package/lib/mjs/cli/ChangeUserPassword.d.ts.map +1 -1
  48. package/lib/mjs/cli/ChangeUserPassword.js +3 -3
  49. package/lib/mjs/cli/ChangeUserPassword.js.map +1 -1
  50. package/lib/mjs/cli/CreateUser.d.ts.map +1 -1
  51. package/lib/mjs/cli/CreateUser.js +8 -1
  52. package/lib/mjs/cli/CreateUser.js.map +1 -1
  53. package/lib/mjs/config/rbac.d.ts +40 -0
  54. package/lib/mjs/config/rbac.d.ts.map +1 -1
  55. package/lib/mjs/config/rbac.js +40 -0
  56. package/lib/mjs/config/rbac.js.map +1 -1
  57. package/lib/mjs/events/UserCreated.d.ts +2 -1
  58. package/lib/mjs/events/UserCreated.d.ts.map +1 -1
  59. package/lib/mjs/events/UserCreated.js +13 -3
  60. package/lib/mjs/events/UserCreated.js.map +1 -1
  61. package/lib/mjs/exceptions.d.ts +69 -0
  62. package/lib/mjs/exceptions.d.ts.map +1 -0
  63. package/lib/mjs/exceptions.js +71 -0
  64. package/lib/mjs/exceptions.js.map +1 -0
  65. package/lib/mjs/index.d.ts +1 -0
  66. package/lib/mjs/index.d.ts.map +1 -1
  67. package/lib/mjs/index.js +1 -0
  68. package/lib/mjs/index.js.map +1 -1
  69. package/lib/mjs/interfaces.d.ts +2 -7
  70. package/lib/mjs/interfaces.d.ts.map +1 -1
  71. package/lib/mjs/interfaces.js +0 -7
  72. package/lib/mjs/interfaces.js.map +1 -1
  73. package/lib/mjs/password.d.ts +18 -1
  74. package/lib/mjs/password.d.ts.map +1 -1
  75. package/lib/mjs/password.js +62 -6
  76. package/lib/mjs/password.js.map +1 -1
  77. package/lib/mjs/profile.js +2 -2
  78. package/lib/mjs/profile.js.map +1 -1
  79. package/lib/tsconfig.cjs.tsbuildinfo +1 -1
  80. package/lib/tsconfig.mjs.tsbuildinfo +1 -1
  81. package/package.json +11 -11
@@ -1,109 +1,86 @@
1
1
  import { User } from './models/User.js';
2
2
  import { Constructor } from '@spinajs/di';
3
3
  import { UserEvent } from './events/UserEvent.js';
4
- export declare enum E_CODES {
5
- E_TOKEN_EXPIRED = 0,
6
- E_TOKEN_INVALID = 1,
7
- E_PASSWORD_DOES_NOT_MEET_REQUIREMENTS = 2,
8
- E_USER_NOT_FOUND = 3,
9
- E_USER_ALREADY_EXISTS = 4,
10
- E_USER_NOT_ACTIVE = 5,
11
- E_USER_BANNED = 6,
12
- E_METADATA_NOT_FOUND = 7,
13
- E_METADATA_NOT_POPULATED = 8,
14
- E_EMAIL_NOT_CONFIGURED = 9,
15
- E_NO_EMAIL_TEMPLATE = 10,
16
- E_NOT_LOGGED = 11
17
- }
4
+ import { DateTime } from 'luxon';
18
5
  /**
19
6
  * ===============================================
20
- * HELPER FUNCTIONS
7
+ * FUNDAMENTALS ( imperative helpers )
21
8
  * ===============================================
22
9
  */
23
10
  /**
11
+ * Resolves a user by identifier with metadata populated.
12
+ * If a {@link User} instance is passed it is returned as-is; otherwise the user is
13
+ * looked up by id, uuid, email, or login and its metadata relation is populated.
24
14
  *
25
- * Gets system user account
26
- *
27
- * @returns system user
15
+ * @param identifier - numeric id, uuid / email / login string, or an existing {@link User} instance
28
16
  */
29
- export declare function _get_system_user(): Promise<unknown>;
17
+ export declare function getUser(identifier: number | string | User): Promise<User>;
30
18
  /**
19
+ * Unsafe user retrieval. It does not check for rbac permission, so this
20
+ * function can read ANY user in system. USE IT CAREFULLY
31
21
  *
32
- * Gets users by role helper func.
33
- *
34
- * @param role user role
35
- * @returns
22
+ * @param identifier - numeric id, uuid / email / login string, or an existing {@link User} instance
36
23
  */
37
- export declare function _get_users_by_role(role: string[]): () => import("@spinajs/orm").ISelectQueryBuilder<User[]> & import("./models/User.js").UserQueryScopes;
24
+ export declare function getUserUnsafe(identifier: number | string | User): Promise<User>;
38
25
  /**
26
+ * Gets system user account
39
27
  *
40
- * Gets rbac user model
28
+ * @returns system user
29
+ */
30
+ export declare function getSystemUser(): Promise<User>;
31
+ /**
32
+ * Gets users by role.
41
33
  *
42
- * @param user
43
- * @returns
34
+ * @param role user roles
44
35
  */
45
- export declare function _get_user(user: User | number | string): () => Promise<User>;
36
+ export declare function getUsersByRole(role: string[]): Promise<User[]>;
46
37
  /**
47
38
  * Sets metadata key-value pairs on a user.
48
39
  * Accepts either an array of `{ key, value }` objects or a single metadata key string with a separate value.
49
40
  * Emits a {@link UserMetadataChange} event after the metadata is persisted.
50
41
  *
42
+ * @param u - user to modify
51
43
  * @param meta - metadata key (string) or array of `{ key, value }` entries to set
52
44
  * @param value - value to assign when `meta` is a single key string (default: `null`)
53
- * @returns a function that receives a {@link User} and returns the updated user
54
45
  */
55
- export declare function _set_user_meta(meta: string | {
46
+ export declare function setUserMeta(u: User, meta: string | {
56
47
  key: string;
57
48
  value: any;
58
- }[], value?: any): (u: User) => Promise<User>;
49
+ }[], value?: any): Promise<User>;
59
50
  /**
60
51
  * Retrieves a single metadata value from a user by key.
61
52
  * Throws if the user's metadata has not been populated or the requested key does not exist.
62
53
  *
54
+ * @param u - user to read from
63
55
  * @param key - metadata key to retrieve
64
- * @returns a function that receives a {@link User} and returns the metadata value
65
- */
66
- export declare function _get_user_meta(key: string): (u: User) => Promise<any>;
67
- /**
68
- * Helper function for sending user notification emails
69
- * Templates are defined in rbac configuration
70
- *
71
- * @param cfgTemplate
72
- * @returns
73
56
  */
74
- export declare function _user_email(cfgTemplate: 'changePassword' | 'created' | 'confirm' | 'deactivated' | 'activated' | 'deleted' | 'unbanned' | 'banned' | 'passwordWillExpire' | 'passwordExpired'): (u: User) => Promise<User>;
57
+ export declare function getUserMeta(u: User, key: string): Promise<any>;
75
58
  /**
76
- * Emits a user-related event through the queue service.
77
- *
78
- * @param event - constructor of the {@link UserEvent} subclass to emit
79
- * @param args - additional arguments forwarded to the event constructor
80
- * @returns a function that receives a {@link User}, emits the event, and returns the user
59
+ * Sends a user notification email. Templates are defined in rbac configuration.
60
+ *
61
+ * The email send result is deliberately discarded - actions end with this step
62
+ * and must resolve with the User, not with an EmailSend job.
63
+ *
64
+ * @param u - recipient
65
+ * @param cfgTemplate - which `rbac.email.*` entry describes the message
66
+ * @param model - extra template variables merged over the user's own fields.
67
+ * Given as a FUNCTION of the user so a caller can compute them from the row it
68
+ * has just written ( the password-reset token is the case that needs it ).
69
+ * Nothing here is persisted and nothing is logged: whatever it carries goes
70
+ * straight into the rendered message.
81
71
  */
82
- export declare function _user_ev(event: Constructor<UserEvent>, ...args: any[]): (u: User) => Promise<User>;
72
+ export declare function sendUserEmail(u: User, cfgTemplate: 'changePassword' | 'created' | 'confirm' | 'deactivated' | 'activated' | 'deleted' | 'unbanned' | 'banned' | 'passwordWillExpire' | 'passwordExpired', model?: (u: User) => Promise<{
73
+ [key: string]: unknown;
74
+ }> | {
75
+ [key: string]: unknown;
76
+ }): Promise<User>;
83
77
  /**
84
78
  * Persists partial changes to a user record and emits a {@link UserChanged} event.
85
79
  *
80
+ * @param u - user to update
86
81
  * @param data - optional partial user fields to merge into the existing record
87
- * @returns a function that receives a {@link User}, applies the update, and returns the user
88
- */
89
- export declare function _user_update(data?: Partial<User>): (u: User) => Promise<User>;
90
- /**
91
- * Resolves a user by identifier with metadata populated.
92
- * If a {@link User} instance is passed it is returned as-is; otherwise the user is
93
- * looked up by id, uuid, email, or login and its metadata relation is populated.
94
- *
95
- * @param identifier - numeric id, uuid / email / login string, or an existing {@link User} instance
96
- * @returns a thunk that resolves to the {@link User}
97
82
  */
98
- export declare function _user(identifier: number | string | User): () => Promise<User>;
99
- /**
100
- * Unsafe user retrieval. It does not chack for rbac permission, to this
101
- * function can read ANY user in system. USE IT CAREFULLY
102
- *
103
- * @param identifier
104
- * @returns
105
- */
106
- export declare function _user_unsafe(identifier: number | string | User): () => Promise<User>;
83
+ export declare function updateUser(u: User, data?: Partial<User>): Promise<User>;
107
84
  /**
108
85
  * Destroys every session belonging to a user, on every device.
109
86
  *
@@ -120,6 +97,54 @@ export declare function _user_unsafe(identifier: number | string | User): () =>
120
97
  * @param user - the user whose sessions are destroyed, or their numeric id
121
98
  */
122
99
  export declare function revokeUserSessions(user: User | number): Promise<void>;
100
+ /**
101
+ * ===============================================
102
+ * FP WRAPPERS ( kept for compatibility and for use in chains )
103
+ * ===============================================
104
+ */
105
+ /**
106
+ * Thunk form of {@link getSystemUser}.
107
+ */
108
+ export declare function _get_system_user(): Promise<User>;
109
+ /**
110
+ * Thunk form of {@link getUsersByRole}.
111
+ */
112
+ export declare function _get_users_by_role(role: string[]): () => Promise<User[]>;
113
+ /**
114
+ * Gets rbac user model by uuid or id, WITHOUT metadata populated.
115
+ */
116
+ export declare function _get_user(user: User | number | string): () => Promise<User>;
117
+ /**
118
+ * Thunk form of {@link getUser}.
119
+ */
120
+ export declare function _user(identifier: number | string | User): () => Promise<User>;
121
+ /**
122
+ * Thunk form of {@link getUserUnsafe}.
123
+ */
124
+ export declare function _user_unsafe(identifier: number | string | User): () => Promise<User>;
125
+ /**
126
+ * Chain step form of {@link setUserMeta}.
127
+ */
128
+ export declare function _set_user_meta(meta: string | {
129
+ key: string;
130
+ value: any;
131
+ }[], value?: any): (u: User) => Promise<User>;
132
+ /**
133
+ * Chain step form of {@link getUserMeta}.
134
+ */
135
+ export declare function _get_user_meta(key: string): (u: User) => Promise<any>;
136
+ /**
137
+ * Chain step form of {@link sendUserEmail}.
138
+ */
139
+ export declare function _user_email(cfgTemplate: Parameters<typeof sendUserEmail>[1], model?: Parameters<typeof sendUserEmail>[2]): (u: User) => Promise<User>;
140
+ /**
141
+ * Chain step: emits a user-related event and forwards the user.
142
+ */
143
+ export declare function _user_ev(event: Constructor<UserEvent>, ...args: any[]): (u: User) => Promise<User>;
144
+ /**
145
+ * Chain step form of {@link updateUser}.
146
+ */
147
+ export declare function _user_update(data?: Partial<User>): (u: User) => Promise<User>;
123
148
  /**
124
149
  * ===============================================
125
150
  * USER ACTIONS
@@ -143,24 +168,119 @@ export declare function deactivate(identifier: number | string | User): Promise<
143
168
  * Middleware signature used by the `create` action's `beforeCreate` / `afterCreate` hooks.
144
169
  */
145
170
  export type CreateMiddleware = (u: User) => Promise<User> | User;
171
+ /**
172
+ * Optional inputs of the {@link create} action.
173
+ */
174
+ export interface ICreateUserOptions {
175
+ /**
176
+ * Plain-text password. Omit it and a random one is generated, the account is
177
+ * handed to its owner by a password-reset link, and the generated value is
178
+ * returned for a caller that needs it ( the CLI prints it ).
179
+ */
180
+ password?: string;
181
+ /** Explicit user id. Useful when migrating accounts from another system. */
182
+ id?: number;
183
+ /** Key-value metadata attached to the new account. */
184
+ metadata?: {
185
+ [key: string]: any;
186
+ };
187
+ }
188
+ /**
189
+ * The roles a request denotes, whether it arrives as one name or a list.
190
+ *
191
+ * Trimmed, stripped of blanks and de-duplicated. Order is preserved so a caller
192
+ * that treats the first entry as the primary role keeps that meaning.
193
+ *
194
+ * De-duplication is not cosmetic: every downstream guard is charged per entry,
195
+ * so `['user', ' user ']` costs two checks for one role.
196
+ *
197
+ * @param role - a single role name or a list of them
198
+ */
199
+ export declare function roleList(role?: string | string[]): string[];
200
+ /**
201
+ * Refuses a role the application has not configured.
202
+ *
203
+ * A role counts as configured if it either holds grants in the resolved
204
+ * {@link AccessControl} instance or is merely declared in `rbac.roles` - the
205
+ * same definition of "known" `DefaultRoleGuard` (`@spinajs/rbac-http-admin`)
206
+ * already uses for its own route-level check. A role may legitimately be named
207
+ * before it is given any permission, and a narrower definition here would
208
+ * refuse a role the route layer of this same codebase already accepts.
209
+ * `hasRole` resolves roles defined only through `$extend`, so an
210
+ * inheritance-only role such as `system` is recognised.
211
+ *
212
+ * `rbac.requireKnownRole: false` turns the whole check off - see the comment
213
+ * at its first use below.
214
+ *
215
+ * @param roles - role names to check; every unknown name is reported at once
216
+ */
217
+ export declare function assertRolesExist(roles: string[]): void;
218
+ /**
219
+ * Refuses metadata keys that decide account access.
220
+ *
221
+ * `user:pwd_reset:token` is a bearer credential redeemable at the PUBLIC reset
222
+ * endpoint and `user:2fa:*` is the second factor itself — writing either through
223
+ * a generic key-value merge hands out an account rather than annotating one.
224
+ * Ban and lockout keys are refused for the same reason bans have their own
225
+ * action: written directly they skip the event, the email and the session
226
+ * revocation that make a ban mean something.
227
+ *
228
+ * Lives here rather than in one http controller because the keys it protects are
229
+ * rbac's own, and an account seeded with a known reset token is an account
230
+ * takeover no matter which caller planted it — a CLI, a migration and a route
231
+ * all need the same refusal.
232
+ *
233
+ * @param metadata - the key-value bag a caller wants attached to an account
234
+ */
235
+ export declare function assertNoProtectedMetadata(metadata?: {
236
+ [key: string]: any;
237
+ }): void;
238
+ /**
239
+ * Refuses a login / email already taken by another account.
240
+ *
241
+ * Exported because uniqueness is not only a creation-time rule: an update that
242
+ * renames an account has to apply exactly the same one, and a second
243
+ * implementation of it would be a second thing to keep in step. `exceptUserId`
244
+ * is what an update passes so an account does not clash with itself.
245
+ *
246
+ * Queries the base {@link User} rather than `userModel()`: uniqueness is GLOBAL,
247
+ * and an application's scoped subclass would hide the clashing row — turning a
248
+ * clean refusal into a driver error on the unique index.
249
+ *
250
+ * Soft-deleted rows are included for the same reason. They still occupy the
251
+ * unique indexes, so ignoring them trades this error for that driver error.
252
+ *
253
+ * The thrown {@link UserAlreadyExists} carries `fields`, naming WHICH of login / email
254
+ * clashed, so an http caller can mark the offending input rather than reporting
255
+ * that something, somewhere, is already in use.
256
+ *
257
+ * @param login - login to check, or undefined to skip the login check
258
+ * @param email - email to check, or undefined to skip the email check
259
+ * @param exceptUserId - id of the account being updated, which may keep its own values
260
+ */
261
+ export declare function assertUserUnique(login?: string, email?: string, exceptUserId?: number): Promise<void>;
146
262
  /**
147
263
  * Creates a new user account.
148
264
  *
149
- * Validates and normalises inputs, hashes the password, inserts the user record,
150
- * optionally sets metadata, runs configured `beforeCreate` / `afterCreate` middleware,
151
- * emits a {@link UserCreated} event, and sends the "created" email.
265
+ * Validates and normalises inputs, refuses a duplicate login / email and
266
+ * protected metadata keys, hashes the password, inserts the user record,
267
+ * optionally sets metadata, runs configured `beforeCreate` / `afterCreate`
268
+ * middleware, emits a {@link UserCreated} event, and sends the "created" email.
269
+ *
270
+ * When no password is given, one is generated AND a password-reset link is
271
+ * mailed to the address. Those two are one decision, not two: a generated
272
+ * password is a secret nobody knows, so an account created without the reset
273
+ * link is an account with no way in at all. Callers that pass a password know
274
+ * it and own delivery themselves, so they get no link — which is what a CLI
275
+ * service account or a fixture wants.
152
276
  *
153
277
  * @param email - user email address (max 64 chars)
154
278
  * @param login - user login name (max 32 chars)
155
- * @param password - plain-text password; if empty a random one is generated
156
279
  * @param roles - array of role names to assign
157
- * @param id - optional explicit user id (useful when migrating from another system)
158
- * @param metadata - optional key-value metadata to attach to the new user
280
+ * @param options - see {@link ICreateUserOptions}
159
281
  * @returns an object containing the persisted {@link User} and the plain-text password
160
282
  */
161
- export declare function create(email: string, login: string, password: string, roles: string[], id?: number, metadata?: {
162
- [key: string]: any;
163
- }): Promise<{
283
+ export declare function create(email: string, login: string, roles: string[], options?: ICreateUserOptions): Promise<{
164
284
  User: User;
165
285
  Password: string;
166
286
  }>;
@@ -190,31 +310,38 @@ export declare function grant(identifier: number | string | User, role: string):
190
310
  */
191
311
  export declare function revoke(identifier: number | string | User, role: string): Promise<User>;
192
312
  /**
193
- *
194
- * Bans user for specified time. If duration is 0 user is banned for 24h
313
+ * Bans user for specified time. If duration is not given user is banned for 24h
195
314
  *
196
315
  * @param identifier user identifier one of : id, uuid, email, login
197
- * @param reason reson for ban
316
+ * @param reason reason for ban
198
317
  * @param duration duration in seconds
199
- * @returns
200
318
  */
201
319
  export declare function ban(identifier: number | string | User, reason?: string, duration?: number): Promise<User>;
202
320
  /**
203
- *
204
321
  * Unban user
205
322
  *
206
- * @param identifier
207
- * @returns
323
+ * @param identifier - numeric id, uuid / email / login string, or an existing {@link User} instance
208
324
  */
209
325
  export declare function unban(identifier: number | string | User): Promise<User>;
210
326
  /**
211
327
  * Initiates a password-change request for a user.
212
328
  * Generates a reset token, stores it along with the current timestamp and configured
213
- * wait time in the user's metadata, and emits a {@link UserPasswordChangeRequest} event.
329
+ * wait time in the user's metadata, emits a {@link UserPasswordChangeRequest} event and
330
+ * sends the `changePassword` mail carrying the token.
331
+ *
332
+ * THE MAIL IS THE POINT. The token is issued into metadata and never returned over HTTP —
333
+ * possession of the mailbox is what authorizes the reset — so an installation that does not
334
+ * deliver it has a reset flow nobody can complete. It used to be the application's job, via
335
+ * the event, and every application that had not written that subscriber silently issued
336
+ * tokens into the void. `rbac.email.changePassword.enabled: false` still turns it off for an
337
+ * application that really does deliver it some other way.
338
+ *
339
+ * The token reaches the template through the model and is NOT logged: it is a bearer
340
+ * credential for `POST /auth/password/reset`.
214
341
  *
215
342
  * @param identifier - numeric id, uuid / email / login string, or an existing {@link User} instance
216
343
  */
217
- export declare function passwordChangeRequest(identifier: number | string | User): Promise<unknown>;
344
+ export declare function passwordChangeRequest(identifier: number | string | User): Promise<User>;
218
345
  /**
219
346
  * Confirms a password reset by validating the token and expiration, then changing the password.
220
347
  * Throws if the token has expired or does not match the stored value.
@@ -223,30 +350,55 @@ export declare function passwordChangeRequest(identifier: number | string | User
223
350
  * @param newPassword - the new plain-text password to set
224
351
  * @param token - the reset token that was issued by {@link passwordChangeRequest}
225
352
  */
226
- export declare function confirmPasswordReset(identifier: number | string | User, newPassword: string, token: string): Promise<unknown>;
353
+ export declare function confirmPasswordReset(identifier: number | string | User, newPassword: string, token: string): Promise<User>;
227
354
  /**
228
- * Returns a function that changes a user's password.
355
+ * Changes a user's password.
229
356
  * The new password is validated against the configured {@link PasswordValidationProvider},
230
357
  * hashed via the configured {@link PasswordProvider}, persisted, and a
231
358
  * {@link UserPasswordChanged} event is emitted.
232
359
  *
360
+ * @param u - user to change the password for
361
+ * @param password - new plain-text password
362
+ */
363
+ export declare function changeUserPassword(u: User, password: string): Promise<User>;
364
+ /**
365
+ * Chain step form of {@link changeUserPassword}.
366
+ *
233
367
  * @param password - new plain-text password
234
- * @returns a function that receives a {@link User} and returns the updated user
235
368
  */
236
369
  export declare function changePassword(password: string): (u: User) => Promise<User>;
237
370
  /**
371
+ * Expire password for user.
238
372
  *
239
- * Expire password for user
373
+ * The stored credential is replaced with a freshly generated random one, so the
374
+ * expired password stops working even if the account is re-activated without a
375
+ * reset. The account is deactivated, {@link UserPasswordExpired} is emitted and
376
+ * the 'passwordExpired' mail is sent.
240
377
  *
241
- * @param identifier
378
+ * @param identifier - numeric id, uuid / email / login string, or an existing {@link User} instance
242
379
  */
243
380
  export declare function expirePassword(identifier: number | string | User): Promise<void>;
244
381
  /**
245
- * Check if password match user password stored in db
382
+ * Sends the 'passwordWillExpire' warning mail. No account state changes -
383
+ * this is the notification half of the expiry flow, meant to be called by an
384
+ * application scheduler ahead of {@link expirePassword}.
385
+ *
386
+ * @param identifier - numeric id, uuid / email / login string, or an existing {@link User} instance
387
+ * @param expiresAt - optional instant the password expires, passed to the template
388
+ */
389
+ export declare function notifyPasswordWillExpire(identifier: number | string | User, expiresAt?: DateTime): Promise<User>;
390
+ /**
391
+ * Checks if password matches the user's password stored in db.
392
+ *
393
+ * @param u - user to check against
394
+ * @param password - plain-text password to verify
395
+ */
396
+ export declare function verifyPassword(u: User, password: string): Promise<boolean>;
397
+ /**
398
+ * Chain step form of {@link verifyPassword}. The user is taken from the step
399
+ * argument - a regression once read it from a never-passed second parameter.
246
400
  *
247
- * @param identifier
248
- * @param password
249
- * @returns
401
+ * @param password - plain-text password to verify
250
402
  */
251
403
  export declare function passwordMatch(password: string): (u: User) => Promise<boolean>;
252
404
  /**
@@ -260,4 +412,28 @@ export declare function passwordMatch(password: string): (u: User) => Promise<bo
260
412
  * @returns the authenticated {@link User}
261
413
  */
262
414
  export declare function login(identifier: number | string | User, password: string): Promise<User>;
415
+ /**
416
+ * Throws when the account is inside a lockout window opened by
417
+ * {@link registerFailedLogin}.
418
+ *
419
+ * @param u - user attempting to authenticate
420
+ */
421
+ export declare function assertNotLocked(u: User): void;
422
+ /**
423
+ * Clears the failure counter and any expired lock after a successful login.
424
+ */
425
+ export declare function clearLoginThrottle(u: User): Promise<void>;
426
+ /**
427
+ * Records one failed authentication and, at `rbac.password.blockAfterAttempts`
428
+ * consecutive failures, locks the account for `rbac.password.lockoutTime`
429
+ * seconds.
430
+ *
431
+ * `blockAfterAttempts <= 0` disables throttling entirely. A rejection that was
432
+ * itself the lockout is not counted — otherwise hammering a locked account
433
+ * would keep extending the lock indefinitely.
434
+ *
435
+ * @param u - user whose failed attempt is recorded
436
+ * @param err - the error that ended the login attempt
437
+ */
438
+ export declare function registerFailedLogin(u: User, err: unknown): Promise<void>;
263
439
  //# sourceMappingURL=actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/actions.ts"],"names":[],"mappings":"AAKA,OAAO,EAAwB,IAAI,EAAY,MAAM,kBAAkB,CAAC;AAGxE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAWlD,oBAAY,OAAO;IACjB,eAAe,IAAA;IAEf,eAAe,IAAA;IAEf,qCAAqC,IAAA;IAErC,gBAAgB,IAAA;IAEhB,qBAAqB,IAAA;IAErB,iBAAiB,IAAA;IAEjB,aAAa,IAAA;IAEb,oBAAoB,IAAA;IAEpB,wBAAwB,IAAA;IAExB,sBAAsB,IAAA;IAEtB,mBAAmB,KAAA;IAEnB,YAAY,KAAA;CACb;AAED;;;;GAIG;AAEH;;;;;GAKG;AACH,wBAAgB,gBAAgB,qBAW/B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,yGAEhD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,uBAUrD;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE,EAAE,EAAE,KAAK,GAAE,GAAU,OAC3E,IAAI,mBAoBtB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,OACvB,IAAI,kBAMtB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,oBAAoB,GAAG,iBAAiB,OAU3K,IAAI,mBAqBtB;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,OACnD,IAAI,mBAItB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,OAC9B,IAAI,mBAItB;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAQ7E;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAQpF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS3E;AAYD;;;;GAIG;AAEH;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhF;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAIlF;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAYjE;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAuDvL;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAelF;AAED;;;;;;;GAOG;AACH,wBAAsB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS3F;AAED;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS5F;AAED;;;;;;;;GAQG;AACH,wBAAsB,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B/G;AAED;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB7E;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,oBAY7E;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,oBAqDhH;AAyBD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAuC3E;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,OAG3B,IAAI,KAAG,OAAO,CAAC,OAAO,CAAC,CAQzC;AAED;;;;;;;;;GASG;AACH,wBAAsB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuC/F"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/actions.ts"],"names":[],"mappings":"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"}