@spinajs/rbac-http-user 2.0.502 → 2.0.504
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.
- package/lib/cjs/2fa/Default2FaToken.d.ts +8 -0
- package/lib/cjs/2fa/Default2FaToken.d.ts.map +1 -1
- package/lib/cjs/2fa/Default2FaToken.js +25 -3
- package/lib/cjs/2fa/Default2FaToken.js.map +1 -1
- package/lib/cjs/actions/2fa.d.ts +22 -3
- package/lib/cjs/actions/2fa.d.ts.map +1 -1
- package/lib/cjs/actions/2fa.js +44 -3
- package/lib/cjs/actions/2fa.js.map +1 -1
- package/lib/cjs/config/rbac-http.d.ts.map +1 -1
- package/lib/cjs/config/rbac-http.js +6 -0
- package/lib/cjs/config/rbac-http.js.map +1 -1
- package/lib/cjs/controllers/LoginController.d.ts.map +1 -1
- package/lib/cjs/controllers/LoginController.js +10 -1
- package/lib/cjs/controllers/LoginController.js.map +1 -1
- package/lib/cjs/controllers/TwoFactorAuthController.d.ts +20 -1
- package/lib/cjs/controllers/TwoFactorAuthController.d.ts.map +1 -1
- package/lib/cjs/controllers/TwoFactorAuthController.js +45 -2
- package/lib/cjs/controllers/TwoFactorAuthController.js.map +1 -1
- package/lib/cjs/controllers/TwoFactorAuthUserController.d.ts +83 -4
- package/lib/cjs/controllers/TwoFactorAuthUserController.d.ts.map +1 -1
- package/lib/cjs/controllers/TwoFactorAuthUserController.js +156 -12
- package/lib/cjs/controllers/TwoFactorAuthUserController.js.map +1 -1
- package/lib/cjs/policies/2FaPolicy.d.ts.map +1 -1
- package/lib/cjs/policies/2FaPolicy.js +27 -6
- package/lib/cjs/policies/2FaPolicy.js.map +1 -1
- package/lib/mjs/2fa/Default2FaToken.d.ts +8 -0
- package/lib/mjs/2fa/Default2FaToken.d.ts.map +1 -1
- package/lib/mjs/2fa/Default2FaToken.js +25 -3
- package/lib/mjs/2fa/Default2FaToken.js.map +1 -1
- package/lib/mjs/actions/2fa.d.ts +22 -3
- package/lib/mjs/actions/2fa.d.ts.map +1 -1
- package/lib/mjs/actions/2fa.js +41 -3
- package/lib/mjs/actions/2fa.js.map +1 -1
- package/lib/mjs/config/rbac-http.d.ts.map +1 -1
- package/lib/mjs/config/rbac-http.js +6 -0
- package/lib/mjs/config/rbac-http.js.map +1 -1
- package/lib/mjs/controllers/LoginController.d.ts.map +1 -1
- package/lib/mjs/controllers/LoginController.js +10 -1
- package/lib/mjs/controllers/LoginController.js.map +1 -1
- package/lib/mjs/controllers/TwoFactorAuthController.d.ts +20 -1
- package/lib/mjs/controllers/TwoFactorAuthController.d.ts.map +1 -1
- package/lib/mjs/controllers/TwoFactorAuthController.js +48 -5
- package/lib/mjs/controllers/TwoFactorAuthController.js.map +1 -1
- package/lib/mjs/controllers/TwoFactorAuthUserController.d.ts +83 -4
- package/lib/mjs/controllers/TwoFactorAuthUserController.d.ts.map +1 -1
- package/lib/mjs/controllers/TwoFactorAuthUserController.js +160 -16
- package/lib/mjs/controllers/TwoFactorAuthUserController.js.map +1 -1
- package/lib/mjs/policies/2FaPolicy.d.ts.map +1 -1
- package/lib/mjs/policies/2FaPolicy.js +26 -5
- package/lib/mjs/policies/2FaPolicy.js.map +1 -1
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.mjs.tsbuildinfo +1 -1
- package/package.json +15 -15
|
@@ -19,11 +19,12 @@ const di_1 = require("@spinajs/di");
|
|
|
19
19
|
const configuration_1 = require("@spinajs/configuration");
|
|
20
20
|
const rbac_http_1 = require("@spinajs/rbac-http");
|
|
21
21
|
const exceptions_1 = require("@spinajs/exceptions");
|
|
22
|
-
const _2FaPolicy_js_1 = require("../policies/2FaPolicy.js");
|
|
23
22
|
const confirm_password_dto_js_1 = require("../dto/confirm-password-dto.js");
|
|
23
|
+
const token_dto_js_1 = require("../dto/token-dto.js");
|
|
24
24
|
const SessionCookies_js_1 = require("../services/SessionCookies.js");
|
|
25
25
|
const _2fa_js_1 = require("../actions/2fa.js");
|
|
26
26
|
const Default2FaToken_js_1 = require("../2fa/Default2FaToken.js");
|
|
27
|
+
const _2FaPolicy_js_1 = require("../policies/2FaPolicy.js");
|
|
27
28
|
/**
|
|
28
29
|
* Self-service two-factor authentication.
|
|
29
30
|
*
|
|
@@ -38,6 +39,17 @@ const Default2FaToken_js_1 = require("../2fa/Default2FaToken.js");
|
|
|
38
39
|
* not be enough to attach an attacker-controlled authenticator or to strip the
|
|
39
40
|
* second factor off the account.
|
|
40
41
|
*
|
|
42
|
+
* `TwoFactorAuthEnabled` stays on the class as the guard for callers it is
|
|
43
|
+
* able to reject, but it cannot block an authorized caller here:
|
|
44
|
+
* `@spinajs/http` merges every policy on a route into ONE gate that lets the
|
|
45
|
+
* route run when ANY policy resolves, and `AuthorizedPolicy` below resolves
|
|
46
|
+
* for any logged-in caller — so once a session is authorized, that policy
|
|
47
|
+
* alone is enough to pass the gate regardless of what `TwoFactorAuthEnabled`
|
|
48
|
+
* decides. That is why the system-wide switch (`rbac.twoFactorAuth.enabled`)
|
|
49
|
+
* is *also* enforced directly in the mutating handlers, via
|
|
50
|
+
* {@link assertSystemEnabled}, which is the check that actually matters for
|
|
51
|
+
* an authorized caller.
|
|
52
|
+
*
|
|
41
53
|
* @tags Two-Factor Settings
|
|
42
54
|
*/
|
|
43
55
|
let TwoFactorAuthUserController = class TwoFactorAuthUserController extends http_1.BaseController {
|
|
@@ -50,12 +62,19 @@ let TwoFactorAuthUserController = class TwoFactorAuthUserController extends http
|
|
|
50
62
|
* @response 403 Forbidden — insufficient permissions
|
|
51
63
|
*/
|
|
52
64
|
async status(user) {
|
|
53
|
-
|
|
65
|
+
const enabled = Boolean(user.Metadata[Default2FaToken_js_1.TWO_FA_METATADATA_KEYS.ENABLED]);
|
|
66
|
+
return new http_1.Ok({
|
|
67
|
+
Enabled: enabled,
|
|
68
|
+
Pending: !enabled && Boolean(user.Metadata[Default2FaToken_js_1.TWO_FA_METATADATA_KEYS.TOKEN]),
|
|
69
|
+
SystemEnabled: this.TwoFactorConfig?.enabled !== false,
|
|
70
|
+
});
|
|
54
71
|
}
|
|
55
72
|
/**
|
|
56
73
|
* Enable own two-factor authentication
|
|
57
74
|
* Generates a TOTP secret for the authenticated user and returns the OTP provisioning
|
|
58
75
|
* URI to scan with an authenticator app. Requires the account password to be re-entered.
|
|
76
|
+
* 2FA stays off until the new code is confirmed with `POST /user/2fa/confirm` — a caller
|
|
77
|
+
* that stops after this call leaves the account unprotected, believing it is enrolled.
|
|
59
78
|
* @security cookieAuth
|
|
60
79
|
* @returns {IEnable2faResponse} OTP provisioning URI to scan with an authenticator app
|
|
61
80
|
* @response 400 Two-factor authentication is already enabled for this user
|
|
@@ -63,21 +82,61 @@ let TwoFactorAuthUserController = class TwoFactorAuthUserController extends http
|
|
|
63
82
|
* @response 403 Forbidden — insufficient permissions
|
|
64
83
|
*/
|
|
65
84
|
async enable(user, confirmation, session) {
|
|
85
|
+
this.assertSystemEnabled();
|
|
66
86
|
if (user.Metadata[Default2FaToken_js_1.TWO_FA_METATADATA_KEYS.ENABLED]) {
|
|
67
|
-
throw new exceptions_1.
|
|
87
|
+
throw new exceptions_1.BadRequest(`User ${user.Uuid} already has 2fa enabled`);
|
|
68
88
|
}
|
|
69
89
|
const confirmed = await this.confirmPassword(user, confirmation.Password);
|
|
70
90
|
if (confirmed !== true) {
|
|
71
91
|
return confirmed;
|
|
72
92
|
}
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
// the
|
|
76
|
-
//
|
|
77
|
-
// themselves out and needs an administrator 2FA reset to recover.
|
|
93
|
+
// The secret is stored but 2fa stays OFF until `POST /user/2fa/confirm`
|
|
94
|
+
// accepts a code generated from it. A user who never scans is left pending,
|
|
95
|
+
// which the login check treats exactly like having no device — no lockout,
|
|
96
|
+
// and the next attempt simply issues a new secret.
|
|
78
97
|
const result = await this.enrol(user);
|
|
79
98
|
return new http_1.Ok({ otp: result }, await this.rotate(session));
|
|
80
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Confirm own two-factor enrolment
|
|
102
|
+
* Verifies a code generated from the secret handed out by `POST /user/2fa/enable`
|
|
103
|
+
* or `POST /user/2fa/reset`, and only then switches 2FA on.
|
|
104
|
+
* @security cookieAuth
|
|
105
|
+
* @response 200 Two-factor authentication is now active
|
|
106
|
+
* @response 400 There is no pending enrolment to confirm
|
|
107
|
+
* @response 401 Unauthorized — valid session required
|
|
108
|
+
* @response 403 Invalid or expired TOTP code
|
|
109
|
+
*/
|
|
110
|
+
async confirm(user, token, session) {
|
|
111
|
+
this.assertSystemEnabled();
|
|
112
|
+
// `activate()` never clears the stored token, so an already-enabled
|
|
113
|
+
// account still has one and would otherwise be able to call this route
|
|
114
|
+
// again with a currently-valid code. Only the pending state — a token
|
|
115
|
+
// without 2fa being enabled yet — is an enrolment left to confirm.
|
|
116
|
+
if (user.Metadata[Default2FaToken_js_1.TWO_FA_METATADATA_KEYS.ENABLED] || !user.Metadata[Default2FaToken_js_1.TWO_FA_METATADATA_KEYS.TOKEN]) {
|
|
117
|
+
throw new exceptions_1.BadRequest(`User ${user.Uuid} has no pending 2fa enrolment`);
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
await this.confirmEnrolment(user, token.Token);
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
// `confirmUser2Fa` throws `Unauthorized` for a rejected code — the only
|
|
124
|
+
// case this route should report as "wrong code". Anything else (a
|
|
125
|
+
// database outage during activation, for instance) must surface as a
|
|
126
|
+
// 500, not be misreported to the user as a bad code.
|
|
127
|
+
if (!(err instanceof http_1.Unauthorized)) {
|
|
128
|
+
throw err;
|
|
129
|
+
}
|
|
130
|
+
this._log.warn(`2fa confirmation rejected for ${user.Uuid}`, { error: err });
|
|
131
|
+
return new http_1.ForbiddenResponse({
|
|
132
|
+
error: { code: 'E_2FA_FAILED', message: '2fa check failed' },
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
// No password here on purpose: the password was confirmed by the enable or
|
|
136
|
+
// reset call that issued this secret, and the code is itself the proof this
|
|
137
|
+
// route exists to demand.
|
|
138
|
+
return new http_1.Ok(null, await this.rotate(session));
|
|
139
|
+
}
|
|
81
140
|
/**
|
|
82
141
|
* Disable own two-factor authentication
|
|
83
142
|
* Removes the TOTP secret and disables 2FA for the authenticated user.
|
|
@@ -89,8 +148,9 @@ let TwoFactorAuthUserController = class TwoFactorAuthUserController extends http
|
|
|
89
148
|
* @response 403 Forbidden — insufficient permissions
|
|
90
149
|
*/
|
|
91
150
|
async disable(user, confirmation, session) {
|
|
151
|
+
this.assertSystemEnabled();
|
|
92
152
|
if (!user.Metadata[Default2FaToken_js_1.TWO_FA_METATADATA_KEYS.ENABLED]) {
|
|
93
|
-
throw new exceptions_1.
|
|
153
|
+
throw new exceptions_1.BadRequest(`User ${user.Uuid} already has 2fa disabled`);
|
|
94
154
|
}
|
|
95
155
|
const confirmed = await this.confirmPassword(user, confirmation.Password);
|
|
96
156
|
if (confirmed !== true) {
|
|
@@ -99,6 +159,61 @@ let TwoFactorAuthUserController = class TwoFactorAuthUserController extends http
|
|
|
99
159
|
await this.unenrol(user);
|
|
100
160
|
return new http_1.Ok(null, await this.rotate(session));
|
|
101
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Reset own two-factor authentication
|
|
164
|
+
* Removes the current TOTP device and issues a new secret in a single request,
|
|
165
|
+
* returning the provisioning URI to scan. 2FA stays off until the new code is
|
|
166
|
+
* confirmed with `POST /user/2fa/confirm`. Requires the account password.
|
|
167
|
+
*
|
|
168
|
+
* Folding disable-then-enable into one request removes the client-side gap
|
|
169
|
+
* where abandoning the flow between the two calls could strand the account
|
|
170
|
+
* without a second factor. It does not remove the server-side one: if
|
|
171
|
+
* `enrol` fails after `unenrol` already removed the old device, the account
|
|
172
|
+
* is left with no device at all — there is nothing to roll back to, since
|
|
173
|
+
* the old secret is already gone. That leaves the account in the ordinary
|
|
174
|
+
* `none` state, which every route here already handles: `GET /user/2fa`
|
|
175
|
+
* reports it and `POST /user/2fa/enable` starts a fresh enrolment.
|
|
176
|
+
*
|
|
177
|
+
* A caller who abandons before confirming is left password-only — the same
|
|
178
|
+
* gap as `enable`. The only built-in recovery is `rbac.twoFactorAuth.forceUser`
|
|
179
|
+
* pushing the account back through enrolment at next login, and this package's
|
|
180
|
+
* own default for that flag is `false` (see `src/config/rbac-http.ts`), so a
|
|
181
|
+
* consumer that has not set it will see the downgrade become silent and
|
|
182
|
+
* permanent rather than recovered.
|
|
183
|
+
* @security cookieAuth
|
|
184
|
+
* @returns {IEnable2faResponse} OTP provisioning URI to scan with an authenticator app
|
|
185
|
+
* @response 400 There is no two-factor device to reset
|
|
186
|
+
* @response 401 Unauthorized — valid session required, or password invalid
|
|
187
|
+
* @response 403 Forbidden — insufficient permissions
|
|
188
|
+
*/
|
|
189
|
+
async reset(user, confirmation, session) {
|
|
190
|
+
this.assertSystemEnabled();
|
|
191
|
+
if (!user.Metadata[Default2FaToken_js_1.TWO_FA_METATADATA_KEYS.ENABLED] && !user.Metadata[Default2FaToken_js_1.TWO_FA_METATADATA_KEYS.TOKEN]) {
|
|
192
|
+
throw new exceptions_1.BadRequest(`User ${user.Uuid} has no 2fa to reset`);
|
|
193
|
+
}
|
|
194
|
+
const confirmed = await this.confirmPassword(user, confirmation.Password);
|
|
195
|
+
if (confirmed !== true) {
|
|
196
|
+
return confirmed;
|
|
197
|
+
}
|
|
198
|
+
await this.unenrol(user);
|
|
199
|
+
const result = await this.enrol(user);
|
|
200
|
+
return new http_1.Ok({ otp: result }, await this.rotate(session));
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Refuse a mutation while 2FA is switched off system-wide.
|
|
204
|
+
*
|
|
205
|
+
* The `TwoFactorAuthEnabled` policy cannot do this job: @spinajs/http merges
|
|
206
|
+
* a route's policies into one gate that passes when ANY of them resolves, and
|
|
207
|
+
* these routes also carry AuthorizedPolicy, which succeeds for every
|
|
208
|
+
* logged-in caller. The check has to live where it cannot be short-circuited.
|
|
209
|
+
*/
|
|
210
|
+
assertSystemEnabled() {
|
|
211
|
+
if (this.TwoFactorConfig?.enabled === false) {
|
|
212
|
+
throw Object.assign(new exceptions_1.Forbidden('2 factor auth is not enabled'), {
|
|
213
|
+
error: { code: 'E_2FA_SYSTEM_DISABLED', message: '2 factor auth is not enabled' },
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
102
217
|
/**
|
|
103
218
|
* Rotates the session id after the account's authentication requirements
|
|
104
219
|
* changed, and returns the response options carrying the new cookie.
|
|
@@ -120,11 +235,16 @@ let TwoFactorAuthUserController = class TwoFactorAuthUserController extends http
|
|
|
120
235
|
};
|
|
121
236
|
}
|
|
122
237
|
/**
|
|
123
|
-
*
|
|
124
|
-
* the module-level action so tests can stub it without a
|
|
238
|
+
* Store the TOTP secret and return the provisioning URI, leaving 2fa off until
|
|
239
|
+
* confirmed. Wraps the module-level action so tests can stub it without a
|
|
240
|
+
* TOTP/DB setup.
|
|
125
241
|
*/
|
|
126
242
|
enrol(user) {
|
|
127
|
-
return (0, _2fa_js_1.
|
|
243
|
+
return (0, _2fa_js_1.beginUser2FaEnrolment)(user);
|
|
244
|
+
}
|
|
245
|
+
/** Verify a code against the pending secret and switch 2fa on. */
|
|
246
|
+
confirmEnrolment(user, token) {
|
|
247
|
+
return (0, _2fa_js_1.confirmUser2Fa)(user, token);
|
|
128
248
|
}
|
|
129
249
|
/** Clear the TOTP secret. Wrapped for the same reason as {@link enrol}. */
|
|
130
250
|
unenrol(user) {
|
|
@@ -158,6 +278,10 @@ __decorate([
|
|
|
158
278
|
(0, di_1.Autoinject)(SessionCookies_js_1.SessionCookieFactory),
|
|
159
279
|
__metadata("design:type", SessionCookies_js_1.SessionCookieFactory)
|
|
160
280
|
], TwoFactorAuthUserController.prototype, "SessionCookies", void 0);
|
|
281
|
+
__decorate([
|
|
282
|
+
(0, configuration_1.Config)('rbac.twoFactorAuth'),
|
|
283
|
+
__metadata("design:type", Object)
|
|
284
|
+
], TwoFactorAuthUserController.prototype, "TwoFactorConfig", void 0);
|
|
161
285
|
__decorate([
|
|
162
286
|
(0, http_1.Get)('2fa'),
|
|
163
287
|
(0, rbac_http_1.Permission)(['readOwn']),
|
|
@@ -176,6 +300,16 @@ __decorate([
|
|
|
176
300
|
__metadata("design:paramtypes", [rbac_1.User, confirm_password_dto_js_1.ConfirmPasswordDto, Object]),
|
|
177
301
|
__metadata("design:returntype", Promise)
|
|
178
302
|
], TwoFactorAuthUserController.prototype, "enable", null);
|
|
303
|
+
__decorate([
|
|
304
|
+
(0, http_1.Post)('2fa/confirm'),
|
|
305
|
+
(0, rbac_http_1.Permission)(['updateOwn']),
|
|
306
|
+
__param(0, (0, rbac_http_1.User)()),
|
|
307
|
+
__param(1, (0, http_1.Body)()),
|
|
308
|
+
__param(2, (0, rbac_http_1.Session)()),
|
|
309
|
+
__metadata("design:type", Function),
|
|
310
|
+
__metadata("design:paramtypes", [rbac_1.User, token_dto_js_1.TokenDto, Object]),
|
|
311
|
+
__metadata("design:returntype", Promise)
|
|
312
|
+
], TwoFactorAuthUserController.prototype, "confirm", null);
|
|
179
313
|
__decorate([
|
|
180
314
|
(0, http_1.Post)('2fa/disable'),
|
|
181
315
|
(0, rbac_http_1.Permission)(['updateOwn']),
|
|
@@ -186,6 +320,16 @@ __decorate([
|
|
|
186
320
|
__metadata("design:paramtypes", [rbac_1.User, confirm_password_dto_js_1.ConfirmPasswordDto, Object]),
|
|
187
321
|
__metadata("design:returntype", Promise)
|
|
188
322
|
], TwoFactorAuthUserController.prototype, "disable", null);
|
|
323
|
+
__decorate([
|
|
324
|
+
(0, http_1.Post)('2fa/reset'),
|
|
325
|
+
(0, rbac_http_1.Permission)(['updateOwn']),
|
|
326
|
+
__param(0, (0, rbac_http_1.User)()),
|
|
327
|
+
__param(1, (0, http_1.Body)()),
|
|
328
|
+
__param(2, (0, rbac_http_1.Session)()),
|
|
329
|
+
__metadata("design:type", Function),
|
|
330
|
+
__metadata("design:paramtypes", [rbac_1.User, confirm_password_dto_js_1.ConfirmPasswordDto, Object]),
|
|
331
|
+
__metadata("design:returntype", Promise)
|
|
332
|
+
], TwoFactorAuthUserController.prototype, "reset", null);
|
|
189
333
|
exports.TwoFactorAuthUserController = TwoFactorAuthUserController = __decorate([
|
|
190
334
|
(0, http_1.BasePath)('user'),
|
|
191
335
|
(0, rbac_http_1.Resource)('user'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TwoFactorAuthUserController.js","sourceRoot":"","sources":["../../../src/controllers/TwoFactorAuthUserController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"TwoFactorAuthUserController.js","sourceRoot":"","sources":["../../../src/controllers/TwoFactorAuthUserController.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"2FaPolicy.d.ts","sourceRoot":"","sources":["../../../src/policies/2FaPolicy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"2FaPolicy.d.ts","sourceRoot":"","sources":["../../../src/policies/2FaPolicy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGzD;;;;;;GAMG;AACH,qBAAa,oBAAqB,SAAQ,UAAU;IAElD,SAAS,CAAC,eAAe,EAAE,mBAAmB,CAAC;IAExC,SAAS,IAAI,OAAO,CAE1B;IAEY,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BlD;CACF;AAED;;;;;;;;;GASG;AACH,qBAAa,kBAAmB,SAAQ,oBAAoB;IAC7C,OAAO,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAejD;CACF"}
|
|
@@ -10,10 +10,9 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.TwoFacRouteEnabled = exports.TwoFactorAuthEnabled = void 0;
|
|
13
|
-
const exceptions_1 = require("@spinajs/exceptions");
|
|
14
13
|
const configuration_1 = require("@spinajs/configuration");
|
|
15
14
|
const http_1 = require("@spinajs/http");
|
|
16
|
-
const
|
|
15
|
+
const exceptions_1 = require("@spinajs/exceptions");
|
|
17
16
|
/**
|
|
18
17
|
* Guards routes that only make sense when 2FA is switched on system-wide.
|
|
19
18
|
*
|
|
@@ -25,11 +24,33 @@ class TwoFactorAuthEnabled extends http_1.BasePolicy {
|
|
|
25
24
|
isEnabled() {
|
|
26
25
|
return true;
|
|
27
26
|
}
|
|
28
|
-
execute(_req) {
|
|
27
|
+
async execute(_req) {
|
|
29
28
|
if (this.TwoFactorConfig.enabled === false) {
|
|
30
|
-
|
|
29
|
+
// Deliberately Forbidden and not InvalidOperation: the latter has no
|
|
30
|
+
// @HandleException mapping in @spinajs/http and reaches the client as a
|
|
31
|
+
// 500, which a caller cannot distinguish from a fault.
|
|
32
|
+
//
|
|
33
|
+
// `Forbidden`'s constructor only accepts a message string (see
|
|
34
|
+
// `Exception` in @spinajs/exceptions), so the structured payload that
|
|
35
|
+
// the HTTP error handler serializes into the response body is attached
|
|
36
|
+
// as an extra `error` property after construction.
|
|
37
|
+
//
|
|
38
|
+
// This method must stay `async`: `createPolicyGate` (see
|
|
39
|
+
// packages/http/src/route-builder.ts) builds its wait list with
|
|
40
|
+
// `enabledPolicies.map(p => p.execute(...).then(...))`. A synchronous
|
|
41
|
+
// `throw` here would escape that `.map()` call entirely instead of
|
|
42
|
+
// becoming a rejected promise in the array, so `Promise.allSettled`
|
|
43
|
+
// would never even run — the whole policy gate blows up for every
|
|
44
|
+
// caller, authorized or not, instead of just this policy losing the
|
|
45
|
+
// race. Marking the method `async` turns the throw into a promise
|
|
46
|
+
// rejection, which is what the gate is built to handle.
|
|
47
|
+
throw Object.assign(new exceptions_1.Forbidden('2 factor auth is not enabled'), {
|
|
48
|
+
error: {
|
|
49
|
+
code: 'E_2FA_SYSTEM_DISABLED',
|
|
50
|
+
message: '2 factor auth is not enabled',
|
|
51
|
+
},
|
|
52
|
+
});
|
|
31
53
|
}
|
|
32
|
-
return Promise.resolve();
|
|
33
54
|
}
|
|
34
55
|
}
|
|
35
56
|
exports.TwoFactorAuthEnabled = TwoFactorAuthEnabled;
|
|
@@ -57,7 +78,7 @@ class TwoFacRouteEnabled extends TwoFactorAuthEnabled {
|
|
|
57
78
|
* Check only if user passed login page and waiting for TwoFactorAuth
|
|
58
79
|
*/
|
|
59
80
|
if (!req.storage.Session?.Data.get('TwoFactorAuth')) {
|
|
60
|
-
throw new
|
|
81
|
+
throw new exceptions_1.Forbidden('user does not have 2fa enabled');
|
|
61
82
|
}
|
|
62
83
|
return Promise.resolve();
|
|
63
84
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"2FaPolicy.js","sourceRoot":"","sources":["../../../src/policies/2FaPolicy.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"2FaPolicy.js","sourceRoot":"","sources":["../../../src/policies/2FaPolicy.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,0DAAgD;AAChD,wCAAgE;AAEhE,oDAAkE;AAElE;;;;;;GAMG;AACH,0BAAkC,SAAQ,iBAAU;IAI3C,SAAS;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,IAAc;QACjC,IAAI,IAAI,CAAC,eAAe,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;YAC3C,qEAAqE;YACrE,wEAAwE;YACxE,uDAAuD;YACvD,EAAE;YACF,+DAA+D;YAC/D,sEAAsE;YACtE,uEAAuE;YACvE,mDAAmD;YACnD,EAAE;YACF,yDAAyD;YACzD,gEAAgE;YAChE,sEAAsE;YACtE,mEAAmE;YACnE,oEAAoE;YACpE,kEAAkE;YAClE,oEAAoE;YACpE,kEAAkE;YAClE,wDAAwD;YACxD,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,sBAAS,CAAC,8BAA8B,CAAC,EAAE;gBACjE,KAAK,EAAE;oBACL,IAAI,EAAE,uBAAuB;oBAC7B,OAAO,EAAE,8BAA8B;iBACxC;aACF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF;;AAlCW;IADT,IAAA,sBAAM,EAAC,oBAAoB,CAAC;;6DACkB;AAoCjD;;;;;;;;;GASG;AACH,wBAAgC,SAAQ,oBAAoB;IACnD,KAAK,CAAC,OAAO,CAAC,GAAa;QAChC,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAEzB,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACzC,MAAM,IAAI,6BAAgB,CAAC,oBAAoB,CAAC,CAAC;QACnD,CAAC;QAED;;WAEG;QACH,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,sBAAS,CAAC,gCAAgC,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -14,6 +14,14 @@ export declare class Default2FaToken extends TwoFactorAuthProvider {
|
|
|
14
14
|
execute(_: User): Promise<void>;
|
|
15
15
|
verifyToken(token: string, user: User): Promise<boolean>;
|
|
16
16
|
disable(user: User): Promise<void>;
|
|
17
|
+
beginEnrolment(user: User): Promise<any>;
|
|
18
|
+
activate(user: User): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Enrol and switch on in one step. This is what the CLI command, the
|
|
21
|
+
* administrator reset and user seeding use — they hand the secret to an
|
|
22
|
+
* operator rather than to the account owner, so there is nobody to confirm
|
|
23
|
+
* possession with.
|
|
24
|
+
*/
|
|
17
25
|
initialize(user: User): Promise<any>;
|
|
18
26
|
getOtpAuthUrl(user: User): Promise<string | null>;
|
|
19
27
|
isEnabled(user: User): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Default2FaToken.d.ts","sourceRoot":"","sources":["../../../src/2fa/Default2FaToken.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAI3D,oBAAY,sBAAsB;IAC9B,KAAK,cAAc;IACnB,OAAO,gBAAgB;IACvB,GAAG,YAAY;CAClB;AAED,qBACa,eAAgB,SAAQ,qBAAqB;IAEtD,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC;IAGtB,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAEnB,cAEC;IAED,OAAO,CAAC,OAAO;IAYR,OAAO,CAAC,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAIrC;IAEY,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAcpE;IAEY,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAY9C;IAEY,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"Default2FaToken.d.ts","sourceRoot":"","sources":["../../../src/2fa/Default2FaToken.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAI3D,oBAAY,sBAAsB;IAC9B,KAAK,cAAc;IACnB,OAAO,gBAAgB;IACvB,GAAG,YAAY;CAClB;AAED,qBACa,eAAgB,SAAQ,qBAAqB;IAEtD,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC;IAGtB,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAEnB,cAEC;IAED,OAAO,CAAC,OAAO;IAYR,OAAO,CAAC,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAIrC;IAEY,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAcpE;IAEY,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAY9C;IAEY,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAwBpD;IAEY,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAc/C;IAED;;;;;OAKG;IACU,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAKhD;IAEY,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAU7D;IAEY,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAGnD;IAEY,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAGvD;CACJ"}
|
|
@@ -60,17 +60,16 @@ let Default2FaToken = class Default2FaToken extends TwoFactorAuthProvider {
|
|
|
60
60
|
},
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
|
-
async
|
|
63
|
+
async beginEnrolment(user) {
|
|
64
64
|
if (user.Metadata[TWO_FA_METATADATA_KEYS.ENABLED]) {
|
|
65
65
|
throw new InvalidOperation(`user ${user.Uuid} alread have enabled 2f, disable it first.`);
|
|
66
66
|
}
|
|
67
67
|
const secret = new OTPAuth.Secret({ size: this.Config.secretSize });
|
|
68
68
|
const totp = this._getOTP(user, secret.base32);
|
|
69
69
|
user.Metadata[TWO_FA_METATADATA_KEYS.TOKEN] = secret.base32;
|
|
70
|
-
user.Metadata[TWO_FA_METATADATA_KEYS.ENABLED] = true;
|
|
71
70
|
user.Metadata[TWO_FA_METATADATA_KEYS.OTP] = totp.toString();
|
|
72
71
|
await user.Metadata.update();
|
|
73
|
-
this.Log.trace(`2fa
|
|
72
|
+
this.Log.trace(`2fa enrolment started for user ${user.Uuid}`, {
|
|
74
73
|
user: {
|
|
75
74
|
Uuid: user.Uuid
|
|
76
75
|
},
|
|
@@ -80,6 +79,29 @@ let Default2FaToken = class Default2FaToken extends TwoFactorAuthProvider {
|
|
|
80
79
|
*/
|
|
81
80
|
return totp.toString();
|
|
82
81
|
}
|
|
82
|
+
async activate(user) {
|
|
83
|
+
if (!user.Metadata[TWO_FA_METATADATA_KEYS.TOKEN]) {
|
|
84
|
+
throw new InvalidOperation(`user ${user.Uuid} has no 2fa secret to activate`);
|
|
85
|
+
}
|
|
86
|
+
user.Metadata[TWO_FA_METATADATA_KEYS.ENABLED] = true;
|
|
87
|
+
await user.Metadata.update();
|
|
88
|
+
this.Log.trace(`2fa activated for user ${user.Uuid}`, {
|
|
89
|
+
user: {
|
|
90
|
+
Uuid: user.Uuid
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Enrol and switch on in one step. This is what the CLI command, the
|
|
96
|
+
* administrator reset and user seeding use — they hand the secret to an
|
|
97
|
+
* operator rather than to the account owner, so there is nobody to confirm
|
|
98
|
+
* possession with.
|
|
99
|
+
*/
|
|
100
|
+
async initialize(user) {
|
|
101
|
+
const otp = await this.beginEnrolment(user);
|
|
102
|
+
await this.activate(user);
|
|
103
|
+
return otp;
|
|
104
|
+
}
|
|
83
105
|
async getOtpAuthUrl(user) {
|
|
84
106
|
const token = user.Metadata[TWO_FA_METATADATA_KEYS.TOKEN];
|
|
85
107
|
if (!token) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Default2FaToken.js","sourceRoot":"","sources":["../../../src/2fa/Default2FaToken.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAElE,MAAM,CAAN,IAAY,sBAIX;AAJD,WAAY,sBAAsB;IAC9B,6CAAmB,CAAA;IACnB,iDAAuB,CAAA;IACvB,yCAAe,CAAA;AACnB,CAAC,EAJW,sBAAsB,KAAtB,sBAAsB,QAIjC;AAGM,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,qBAAqB;IAOtD;QACI,KAAK,EAAE,CAAC;IACZ,CAAC;IAEO,OAAO,CAAC,IAAU,EAAE,MAAc;QACtC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YACpB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;YAChC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;SAC5C,CAAC,CAAC;IAEP,CAAC;IAEM,OAAO,CAAC,CAAO;QAClB,yDAAyD;QACzD,gCAAgC;QAChC,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,KAAa,EAAE,IAAU;QAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAE/D,IAAI,CAAC,UAAU,EAAE,CAAC;YACd,MAAM,IAAI,SAAS,CAAC,kDAAkD,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACvF,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;YAC3B,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;SAC7B,CAAC,CAAC;QAEH,OAAO,QAAQ,KAAK,IAAI,CAAC;IAC7B,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,IAAU;QAE3B,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC;QACzD,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;QAC3D,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;QAGvD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,8BAA8B,IAAI,CAAC,IAAI,EAAE,EAAE;YACtD,IAAI,EAAE;gBACF,IAAI,EAAE,IAAI,CAAC,IAAI;aAClB;SACJ,CAAC,CAAC;IACP,CAAC;IAEM,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"Default2FaToken.js","sourceRoot":"","sources":["../../../src/2fa/Default2FaToken.ts"],"names":[],"mappings":"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"}
|
package/lib/mjs/actions/2fa.d.ts
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
import { User } from '@spinajs/rbac';
|
|
2
2
|
/**
|
|
3
|
-
* NOTE for
|
|
4
|
-
*
|
|
3
|
+
* NOTE for enableUser2Fa: the event must be emitted for the USER, not for
|
|
4
|
+
* whatever the provider call returned ( `initialize()` returns the otpauth
|
|
5
5
|
* url ). `_user_ev` reads `Uuid` off its argument, so it is bound to `u`
|
|
6
|
-
* explicitly
|
|
6
|
+
* explicitly via `_tap`, which fires the event as a side effect while passing
|
|
7
|
+
* the provider result through untouched as the chain's result.
|
|
7
8
|
*/
|
|
8
9
|
export declare function enableUser2Fa(identifier: number | string | User): Promise<unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Hand the user a secret without switching 2fa on. No event is emitted: an
|
|
12
|
+
* enrolment nobody confirmed is not a fact about the account, and consumers
|
|
13
|
+
* listening for User2FaEnabled would otherwise fire on an abandoned attempt.
|
|
14
|
+
*/
|
|
15
|
+
export declare function beginUser2FaEnrolment(identifier: number | string | User): Promise<unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* Switch 2fa on for an account whose code was already verified by the caller.
|
|
18
|
+
* The login-window flow needs this split: `auth2Fa` has already checked the
|
|
19
|
+
* code and emitted User2FaPassed by the time the session is authorized.
|
|
20
|
+
*/
|
|
21
|
+
export declare function activateUser2Fa(identifier: number | string | User): Promise<unknown>;
|
|
22
|
+
/**
|
|
23
|
+
* Complete an enrolment started by `beginUser2FaEnrolment`: verify the code
|
|
24
|
+
* against the stored secret, then switch 2fa on. Throws Unauthorized when the
|
|
25
|
+
* code does not match, leaving the enrolment pending so the user can retry.
|
|
26
|
+
*/
|
|
27
|
+
export declare function confirmUser2Fa(identifier: number | string | User, token: string): Promise<unknown>;
|
|
9
28
|
export declare function disableUser2Fa(identifier: number | string | User): Promise<unknown>;
|
|
10
29
|
export declare function resetUser2Fa(identifier: number | string | User): Promise<unknown>;
|
|
11
30
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"2fa.d.ts","sourceRoot":"","sources":["../../../src/actions/2fa.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAyD,MAAM,eAAe,CAAC;AAa5F
|
|
1
|
+
{"version":3,"file":"2fa.d.ts","sourceRoot":"","sources":["../../../src/actions/2fa.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAyD,MAAM,eAAe,CAAC;AAa5F;;;;;;GAMG;AAEH,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,oBAYrE;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,oBAU7E;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,oBAWvE;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,oBAqBrF;AAED,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,oBAWtE;AAED,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,oBAiBpE;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,oBA8B9E"}
|
package/lib/mjs/actions/2fa.js
CHANGED
|
@@ -9,10 +9,11 @@ import { TwoFactorAuthProvider, } from '@spinajs/rbac-http';
|
|
|
9
9
|
import { User2FaReset } from '../events/User2FaReset.js';
|
|
10
10
|
import { User2FaDisabled } from '../events/User2FaDisabled.js';
|
|
11
11
|
/**
|
|
12
|
-
* NOTE for
|
|
13
|
-
*
|
|
12
|
+
* NOTE for enableUser2Fa: the event must be emitted for the USER, not for
|
|
13
|
+
* whatever the provider call returned ( `initialize()` returns the otpauth
|
|
14
14
|
* url ). `_user_ev` reads `Uuid` off its argument, so it is bound to `u`
|
|
15
|
-
* explicitly
|
|
15
|
+
* explicitly via `_tap`, which fires the event as a side effect while passing
|
|
16
|
+
* the provider result through untouched as the chain's result.
|
|
16
17
|
*/
|
|
17
18
|
export async function enableUser2Fa(identifier) {
|
|
18
19
|
return _chain(_user_unsafe(identifier), (u) => {
|
|
@@ -21,6 +22,43 @@ export async function enableUser2Fa(identifier) {
|
|
|
21
22
|
_tap(async () => _user_ev(User2FaEnabled)(u)));
|
|
22
23
|
});
|
|
23
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Hand the user a secret without switching 2fa on. No event is emitted: an
|
|
27
|
+
* enrolment nobody confirmed is not a fact about the account, and consumers
|
|
28
|
+
* listening for User2FaEnabled would otherwise fire on an abandoned attempt.
|
|
29
|
+
*/
|
|
30
|
+
export async function beginUser2FaEnrolment(identifier) {
|
|
31
|
+
return _chain(_user_unsafe(identifier), (u) => {
|
|
32
|
+
return _chain(_service('rbac.twoFactorAuth', TwoFactorAuthProvider), async (twoFa) => twoFa.beginEnrolment(u));
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Switch 2fa on for an account whose code was already verified by the caller.
|
|
37
|
+
* The login-window flow needs this split: `auth2Fa` has already checked the
|
|
38
|
+
* code and emitted User2FaPassed by the time the session is authorized.
|
|
39
|
+
*/
|
|
40
|
+
export async function activateUser2Fa(identifier) {
|
|
41
|
+
return _chain(_user_unsafe(identifier), (u) => {
|
|
42
|
+
return _chain(_service('rbac.twoFactorAuth', TwoFactorAuthProvider), async (twoFa) => twoFa.activate(u), () => _user_ev(User2FaEnabled)(u));
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Complete an enrolment started by `beginUser2FaEnrolment`: verify the code
|
|
47
|
+
* against the stored secret, then switch 2fa on. Throws Unauthorized when the
|
|
48
|
+
* code does not match, leaving the enrolment pending so the user can retry.
|
|
49
|
+
*/
|
|
50
|
+
export async function confirmUser2Fa(identifier, token) {
|
|
51
|
+
token = _check_arg(_trim(), _non_empty())(token, 'token');
|
|
52
|
+
return _chain(_user_unsafe(identifier), (u) => {
|
|
53
|
+
return _chain(_service('rbac.twoFactorAuth', TwoFactorAuthProvider), _either((twoFa) => twoFa.verifyToken(token, u),
|
|
54
|
+
// Delegates to `activateUser2Fa`, which re-resolves the provider
|
|
55
|
+
// itself. It is shared with the login-window flow, where the
|
|
56
|
+
// code is already verified by the time activation is needed.
|
|
57
|
+
() => activateUser2Fa(u), () => {
|
|
58
|
+
throw new Unauthorized('2fa confirmation failed');
|
|
59
|
+
}));
|
|
60
|
+
});
|
|
61
|
+
}
|
|
24
62
|
export async function disableUser2Fa(identifier) {
|
|
25
63
|
return _chain(_user_unsafe(identifier), (u) => {
|
|
26
64
|
return _chain(_service('rbac.twoFactorAuth', TwoFactorAuthProvider), async (twoFa) => twoFa.disable(u), () => _user_ev(User2FaDisabled)(u));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"2fa.js","sourceRoot":"","sources":["../../../src/actions/2fa.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC5F,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAmB,KAAK,EAAQ,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACpH,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,qBAAqB,GAAG,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAG/D
|
|
1
|
+
{"version":3,"file":"2fa.js","sourceRoot":"","sources":["../../../src/actions/2fa.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rbac-http.d.ts","sourceRoot":"","sources":["../../../src/config/rbac-http.ts"],"names":[],"mappings":"AAQA,QAAA,MAAM,QAAQ;IACZ,MAAM;QACJ,IAAI;YACF,WAAW;YACX,GAAG;;;IAGP,KAAK;QACH,OAAO;YACL,eAAe;gBAAI,UAAU;;YAC7B,cAAc;gBAAI,UAAU;;YAC5B,aAAa;gBAAI,UAAU;;YAC3B,YAAY;gBAAI,UAAU;;;;IAG9B,IAAI;QACF,OAAO;YACL;;eAEG;YACH,MAAM;YAEN;;eAEG;YACH,SAAS;YACT,MAAM;YACN,MAAM;YACN,MAAM;;QAER,aAAa;YACX,OAAO;
|
|
1
|
+
{"version":3,"file":"rbac-http.d.ts","sourceRoot":"","sources":["../../../src/config/rbac-http.ts"],"names":[],"mappings":"AAQA,QAAA,MAAM,QAAQ;IACZ,MAAM;QACJ,IAAI;YACF,WAAW;YACX,GAAG;;;IAGP,KAAK;QACH,OAAO;YACL,eAAe;gBAAI,UAAU;;YAC7B,cAAc;gBAAI,UAAU;;YAC5B,aAAa;gBAAI,UAAU;;YAC3B,YAAY;gBAAI,UAAU;;;;IAG9B,IAAI;QACF,OAAO;YACL;;eAEG;YACH,MAAM;YAEN;;eAEG;YACH,SAAS;YACT,MAAM;YACN,MAAM;YACN,MAAM;;QAER,aAAa;YACX,OAAO;YAQP,SAAS;YACT,OAAO;;QAMT,QAAQ;YAIN;;eAEG;YACH,kBAAkB;;;IAGtB,IAAI;CAKL,CAAC;eAEa,QAAQ"}
|
|
@@ -34,6 +34,12 @@ const rbacHttp = {
|
|
|
34
34
|
},
|
|
35
35
|
twoFactorAuth: {
|
|
36
36
|
enabled: true,
|
|
37
|
+
// `POST /user/2fa/reset` relies on this flag to recover an account that
|
|
38
|
+
// was left password-only after a reset was abandoned before the new
|
|
39
|
+
// secret was confirmed (see the docblock on `reset` in
|
|
40
|
+
// TwoFactorAuthUserController) — with it `false`, as it defaults here,
|
|
41
|
+
// that downgrade is silent and permanent for any consumer of this
|
|
42
|
+
// package that does not override it.
|
|
37
43
|
forceUser: false,
|
|
38
44
|
service: 'Default2FaToken',
|
|
39
45
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rbac-http.js","sourceRoot":"","sources":["../../../src/config/rbac-http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEhD,SAAS,GAAG,CAAC,IAAY;IACvB,MAAM,UAAU,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC;IACjD,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3K,CAAC;AAGD,MAAM,QAAQ,GAAG;IACf,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,WAAW,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACjC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;SAClB;KACF;IACD,KAAK,EAAE;QACL,OAAO,EAAE;YACP,eAAe,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACxD,cAAc,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACvD,aAAa,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACtD,YAAY,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;SACtD;KACF;IACD,IAAI,EAAE;QACJ,OAAO,EAAE;YACP;;eAEG;YACH,MAAM,EAAE,SAAS;YAEjB;;eAEG;YACH,SAAS,EAAE,MAAM;YACjB,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,CAAC;SACV;QACD,aAAa,EAAE;YACb,OAAO,EAAE,IAAI;
|
|
1
|
+
{"version":3,"file":"rbac-http.js","sourceRoot":"","sources":["../../../src/config/rbac-http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEhD,SAAS,GAAG,CAAC,IAAY;IACvB,MAAM,UAAU,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC;IACjD,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3K,CAAC;AAGD,MAAM,QAAQ,GAAG;IACf,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,WAAW,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACjC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;SAClB;KACF;IACD,KAAK,EAAE;QACL,OAAO,EAAE;YACP,eAAe,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACxD,cAAc,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACvD,aAAa,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACtD,YAAY,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;SACtD;KACF;IACD,IAAI,EAAE;QACJ,OAAO,EAAE;YACP;;eAEG;YACH,MAAM,EAAE,SAAS;YAEjB;;eAEG;YACH,SAAS,EAAE,MAAM;YACjB,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,CAAC;SACV;QACD,aAAa,EAAE;YACb,OAAO,EAAE,IAAI;YAEb,wEAAwE;YACxE,oEAAoE;YACpE,uDAAuD;YACvD,uEAAuE;YACvE,kEAAkE;YAClE,qCAAqC;YACrC,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,iBAAiB;SAC3B;QACD,sEAAsE;QACtE,0EAA0E;QAC1E,sEAAsE;QACtE,yCAAyC;QACzC,QAAQ,EAAE;YACR,qFAAqF;YACrF,4EAA4E;YAE5E;;eAEG;YACH,kBAAkB,EAAE,CAAC;SACtB;KACF;IACD,IAAI,EAAE;IACJ,iBAAiB;IACjB,+CAA+C;IAC/C,KAAK;KACN;CACF,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoginController.d.ts","sourceRoot":"","sources":["../../../src/controllers/LoginController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAwB,EAAE,EAAO,YAAY,EAAU,MAAM,eAAe,CAAC;AACpG,OAAO,EAAE,YAAY,EAAE,eAAe,EAAsB,aAAa,EAA0C,MAAM,eAAe,CAAC;AAGzI,OAAO,EAA6B,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAElF,OAAO,EAA0F,cAAc,EAAE,eAAe,EAAuB,MAAM,oBAAoB,CAAC;AAClL,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAKrE;;;;;GAKG;AACH,qBACa,eAAgB,SAAQ,cAAc;IAEjD,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;IAGvC,SAAS,CAAC,YAAY,EAAE,YAAY,CAAC;IAGrC,SAAS,CAAC,eAAe,EAAE,eAAe,CAAC;IAK3C,SAAS,CAAC,oBAAoB,EAAE,OAAO,CAAC;IAMxC,SAAS,CAAC,sBAAsB,EAAE,OAAO,CAAC;IAG1C,SAAS,CAAC,cAAc,EAAE,oBAAoB,CAAC;IAG/C,SAAS,CAAC,EAAE,EAAE,aAAa,CAAC;IAE5B;;;;;;;;;OASG;IAGU,KAAK,CAAiB,MAAM,EAAE,IAAI,EAAe,IAAI,EAAE,MAAM,EAAU,WAAW,EAAE,YAAY,GAAG,OAAO,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"LoginController.d.ts","sourceRoot":"","sources":["../../../src/controllers/LoginController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAwB,EAAE,EAAO,YAAY,EAAU,MAAM,eAAe,CAAC;AACpG,OAAO,EAAE,YAAY,EAAE,eAAe,EAAsB,aAAa,EAA0C,MAAM,eAAe,CAAC;AAGzI,OAAO,EAA6B,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAElF,OAAO,EAA0F,cAAc,EAAE,eAAe,EAAuB,MAAM,oBAAoB,CAAC;AAClL,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAKrE;;;;;GAKG;AACH,qBACa,eAAgB,SAAQ,cAAc;IAEjD,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;IAGvC,SAAS,CAAC,YAAY,EAAE,YAAY,CAAC;IAGrC,SAAS,CAAC,eAAe,EAAE,eAAe,CAAC;IAK3C,SAAS,CAAC,oBAAoB,EAAE,OAAO,CAAC;IAMxC,SAAS,CAAC,sBAAsB,EAAE,OAAO,CAAC;IAG1C,SAAS,CAAC,cAAc,EAAE,oBAAoB,CAAC;IAG/C,SAAS,CAAC,EAAE,EAAE,aAAa,CAAC;IAE5B;;;;;;;;;OASG;IAGU,KAAK,CAAiB,MAAM,EAAE,IAAI,EAAe,IAAI,EAAE,MAAM,EAAU,WAAW,EAAE,YAAY,GAAG,OAAO,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,YAAY,CAAC,CAqHzJ;IAED;;;;;;;;;;;;OAYG;IAGU,MAAM,CAAc,IAAI,EAAE,MAAM,EAAqB,OAAO,EAAE,QAAQ,EAAkB,IAAI,EAAE,IAAI,oBA8B9G;IAED;;;;;;;;;OASG;IAGU,MAAM,CAAiB,IAAI,EAAE,IAAI,EAAiB,UAAU,EAAE,MAAM,EAAqB,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAmBrJ;CACF"}
|