@vsaas/loopback 12.4.0 → 12.5.0

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.
@@ -52,6 +52,12 @@
52
52
  "permission": "ALLOW",
53
53
  "property": "verifyTwoFactor"
54
54
  },
55
+ {
56
+ "principalType": "ROLE",
57
+ "principalId": "$authenticated",
58
+ "permission": "ALLOW",
59
+ "property": "getTwoFactorStatus"
60
+ },
55
61
  {
56
62
  "principalType": "ROLE",
57
63
  "principalId": "$authenticated",
@@ -3,6 +3,7 @@ const require_runtime$1 = require("../../_virtual/_rolldown/runtime.cjs");
3
3
  const require_lib_globalize = require("../../lib/globalize.cjs");
4
4
  const require_lib_runtime = require("../../lib/runtime.cjs");
5
5
  const require_lib_utils = require("../../lib/utils.cjs");
6
+ const require_lib_two_factor_service = require("../../lib/two-factor/service.cjs");
6
7
  //#region src/common/models/user.ts
7
8
  var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, module) => {
8
9
  const path = require("path");
@@ -12,6 +13,7 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
12
13
  require("fs");
13
14
  const isEmail = require("isemail");
14
15
  const utils = require_lib_utils;
16
+ const { TWO_FACTOR_ENROLLMENT_SCOPE } = (require_lib_two_factor_service.init_service(), require_runtime$1.__toCommonJS(require_lib_two_factor_service.service_exports));
15
17
  const qs = require("querystring");
16
18
  const crypto = require("crypto");
17
19
  const assert = require("assert");
@@ -209,6 +211,17 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
209
211
  process.nextTick(fn, null, true);
210
212
  return fn.promise;
211
213
  };
214
+ /**
215
+ * Whether the application requires `user` to use a second factor. Override
216
+ * it to enforce a policy: a user that has not enrolled yet logs in with a
217
+ * session restricted to the enrollment, and cannot disable the factor.
218
+ */
219
+ User.isTwoFactorRequired = function(user, options, fn) {
220
+ if (typeof options === "function") fn = options;
221
+ fn = fn || utils.createPromiseCallback();
222
+ process.nextTick(fn, null, false);
223
+ return fn.promise;
224
+ };
212
225
  User.buildTwoFactorLoginContext = function(credentials, options, fn) {
213
226
  if (typeof options === "function") fn = options;
214
227
  fn = fn || utils.createPromiseCallback();
@@ -235,6 +248,61 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
235
248
  }
236
249
  return this._authenticationSecurity.verifyTwoFactor(verification, options || {}, fn);
237
250
  };
251
+ function twoFactorUnavailable(Model, fn) {
252
+ fn = fn || utils.createPromiseCallback();
253
+ const error = /* @__PURE__ */ new Error("Two-factor authentication is not configured");
254
+ error.statusCode = Model.settings.twoFactor == null ? 404 : 503;
255
+ error.code = Model.settings.twoFactor == null ? "TWO_FACTOR_NOT_CONFIGURED" : "AUTHENTICATION_SECURITY_UNAVAILABLE";
256
+ process.nextTick(fn, error);
257
+ return fn.promise;
258
+ }
259
+ User.getTwoFactorStatus = function(userId, options, fn) {
260
+ if (typeof options === "function") {
261
+ fn = options;
262
+ options = void 0;
263
+ }
264
+ if (!this._authenticationSecurityReady || !this._authenticationSecurity) return twoFactorUnavailable(this, fn);
265
+ return this._authenticationSecurity.status(userId, options || {}, fn);
266
+ };
267
+ /**
268
+ * DANGER: removes the second factor of user `userId` and closes their
269
+ * sessions, so their account is protected by the password alone until they
270
+ * enroll again. Whoever can call this can strip 2FA from that user.
271
+ *
272
+ * It is deliberately not a remote method: an application that exposes it
273
+ * must declare its own endpoint and grant it to the narrowest roles. As a
274
+ * floor, this method requires an authenticated actor other than the user,
275
+ * who must prove themselves with `request.currentPassword` and, when they
276
+ * use 2FA, `request.totpCode`. It emits `twoFactorReset` with the actor.
277
+ */
278
+ User.resetTwoFactor = function(userId, request, options, fn) {
279
+ if (typeof options === "function") {
280
+ fn = options;
281
+ options = void 0;
282
+ }
283
+ fn = fn || utils.createPromiseCallback();
284
+ const Model = this;
285
+ const token = options && options.accessToken;
286
+ if (!Model._authenticationSecurityReady || !Model._authenticationSecurity) return twoFactorUnavailable(Model, fn);
287
+ const ActorModel = token && token.principalType && token.principalType !== Model.modelName ? Model.app && Model.app.models[token.principalType] : Model;
288
+ if (!token || token.userId == null || !ActorModel) {
289
+ const error = /* @__PURE__ */ new Error("Authorization required");
290
+ error.statusCode = 401;
291
+ error.code = "AUTHORIZATION_REQUIRED";
292
+ process.nextTick(fn, error);
293
+ return fn.promise;
294
+ }
295
+ if (ActorModel === Model && String(token.userId) === String(userId)) {
296
+ const error = /* @__PURE__ */ new Error("Use disable to change your own factor");
297
+ error.statusCode = 403;
298
+ error.code = "TWO_FACTOR_RESET_SELF";
299
+ process.nextTick(fn, error);
300
+ return fn.promise;
301
+ }
302
+ if (!ActorModel._authenticationSecurityReady || !ActorModel._authenticationSecurity) return twoFactorUnavailable(ActorModel, fn);
303
+ ActorModel._authenticationSecurity.proveActor(token.userId, request || {}, options).then(() => Model._authenticationSecurity.reset(userId, options)).then((result) => fn(null, result), fn);
304
+ return fn.promise;
305
+ };
238
306
  for (const method of [
239
307
  "beginTwoFactorEnrollment",
240
308
  "confirmTwoFactorEnrollment",
@@ -245,14 +313,7 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
245
313
  fn = options;
246
314
  options = void 0;
247
315
  }
248
- if (!this._authenticationSecurityReady || !this._authenticationSecurity) {
249
- fn = fn || utils.createPromiseCallback();
250
- const error = /* @__PURE__ */ new Error("Two-factor authentication is not configured");
251
- error.statusCode = this.settings.twoFactor == null ? 404 : 503;
252
- error.code = this.settings.twoFactor == null ? "TWO_FACTOR_NOT_CONFIGURED" : "AUTHENTICATION_SECURITY_UNAVAILABLE";
253
- process.nextTick(fn, error);
254
- return fn.promise;
255
- }
316
+ if (!this._authenticationSecurityReady || !this._authenticationSecurity) return twoFactorUnavailable(this, fn);
256
317
  const serviceMethod = {
257
318
  beginTwoFactorEnrollment: "beginEnrollment",
258
319
  confirmTwoFactorEnrollment: "confirmEnrollment",
@@ -690,9 +751,33 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
690
751
  path: "/two-factor/verify"
691
752
  }
692
753
  });
693
- function registerTwoFactorManagementMethod(name, path, description) {
754
+ const enrollmentScopes = ["DEFAULT", TWO_FACTOR_ENROLLMENT_SCOPE];
755
+ UserModel.remoteMethod("getTwoFactorStatus", {
756
+ description: "Two-factor state of the current user.",
757
+ accepts: [{
758
+ arg: "userId",
759
+ type: "any",
760
+ http: getUserIdFromRequestContext
761
+ }, {
762
+ arg: "options",
763
+ type: "object",
764
+ http: buildAuthenticationOptions
765
+ }],
766
+ returns: {
767
+ arg: "status",
768
+ type: "object",
769
+ root: true
770
+ },
771
+ accessScopes: enrollmentScopes,
772
+ http: {
773
+ verb: "get",
774
+ path: "/two-factor/status"
775
+ }
776
+ });
777
+ function registerTwoFactorManagementMethod(name, path, description, accessScopes) {
694
778
  UserModel.remoteMethod(name, {
695
779
  description,
780
+ ...accessScopes ? { accessScopes } : {},
696
781
  accepts: [
697
782
  {
698
783
  arg: "userId",
@@ -722,13 +807,14 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
722
807
  }
723
808
  });
724
809
  }
725
- registerTwoFactorManagementMethod("beginTwoFactorEnrollment", "/two-factor/setup", "Begin two-factor enrollment.");
726
- registerTwoFactorManagementMethod("confirmTwoFactorEnrollment", "/two-factor/confirm", "Confirm two-factor enrollment.");
810
+ registerTwoFactorManagementMethod("beginTwoFactorEnrollment", "/two-factor/setup", "Begin two-factor enrollment.", enrollmentScopes);
811
+ registerTwoFactorManagementMethod("confirmTwoFactorEnrollment", "/two-factor/confirm", "Confirm two-factor enrollment.", enrollmentScopes);
727
812
  registerTwoFactorManagementMethod("regenerateTwoFactorRecoveryCodes", "/two-factor/recovery-codes", "Regenerate two-factor recovery codes.");
728
813
  registerTwoFactorManagementMethod("disableTwoFactor", "/two-factor/disable", "Disable two-factor authentication.");
729
814
  for (const method of [
730
815
  "login",
731
816
  "verifyTwoFactor",
817
+ "getTwoFactorStatus",
732
818
  "beginTwoFactorEnrollment",
733
819
  "confirmTwoFactorEnrollment",
734
820
  "regenerateTwoFactorRecoveryCodes",
@@ -741,6 +827,7 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
741
827
  for (const method of [
742
828
  "login",
743
829
  "verifyTwoFactor",
830
+ "getTwoFactorStatus",
744
831
  "beginTwoFactorEnrollment",
745
832
  "confirmTwoFactorEnrollment",
746
833
  "regenerateTwoFactorRecoveryCodes",
@@ -765,6 +852,7 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
765
852
  },
766
853
  description: "Do not supply this argument, it is automatically extracted from request headers."
767
854
  }],
855
+ accessScopes: enrollmentScopes,
768
856
  http: { verb: "all" }
769
857
  });
770
858
  UserModel.remoteMethod("prototype.verify", {
@@ -48,6 +48,12 @@ var require_user = /* @__PURE__ */ require("../../_virtual/_rolldown/runtime.cjs
48
48
  "permission": "ALLOW",
49
49
  "property": "verifyTwoFactor"
50
50
  },
51
+ {
52
+ "principalType": "ROLE",
53
+ "principalId": "$authenticated",
54
+ "permission": "ALLOW",
55
+ "property": "getTwoFactorStatus"
56
+ },
51
57
  {
52
58
  "principalType": "ROLE",
53
59
  "principalId": "$authenticated",
@@ -5,6 +5,10 @@ const require_lib_two_factor_crypto = require("./crypto.cjs");
5
5
  const require_lib_two_factor_totp = require("./totp.cjs");
6
6
  const require_lib_two_factor_recovery_codes = require("./recovery-codes.cjs");
7
7
  //#region src/lib/two-factor/service.ts
8
+ var service_exports = /* @__PURE__ */ require_runtime.__exportAll({
9
+ TWO_FACTOR_ENROLLMENT_SCOPE: () => TWO_FACTOR_ENROLLMENT_SCOPE,
10
+ TwoFactorService: () => TwoFactorService
11
+ });
8
12
  function count(result) {
9
13
  return typeof result === "number" ? result : Number(result?.count || 0);
10
14
  }
@@ -30,6 +34,9 @@ function invoke(target, name, args) {
30
34
  if (result && typeof result.then === "function") result.then((value) => done(null, value), done);
31
35
  });
32
36
  }
37
+ function hasEnrollmentScope(token) {
38
+ return Array.isArray(token?.scopes) && token.scopes.includes("two-factor-enrollment");
39
+ }
33
40
  function includeUser(include) {
34
41
  if (Array.isArray(include)) return include.map(String).map((v) => v.toLowerCase()).includes("user");
35
42
  return String(include || "").toLowerCase() === "user";
@@ -40,12 +47,13 @@ function loginError() {
40
47
  error.code = "LOGIN_FAILED";
41
48
  return error;
42
49
  }
43
- var TwoFactorService;
50
+ var TWO_FACTOR_ENROLLMENT_SCOPE, TwoFactorService;
44
51
  var init_service = require_runtime.__esmMin((() => {
45
52
  require_lib_two_factor_errors.init_errors();
46
53
  require_lib_two_factor_crypto.init_crypto();
47
54
  require_lib_two_factor_totp.init_totp();
48
55
  require_lib_two_factor_recovery_codes.init_recovery_codes();
56
+ TWO_FACTOR_ENROLLMENT_SCOPE = "two-factor-enrollment";
49
57
  TwoFactorService = class {
50
58
  User;
51
59
  config;
@@ -84,12 +92,31 @@ var init_service = require_runtime.__esmMin((() => {
84
92
  confirmEnrollment(userId, request, options, callback) {
85
93
  return optionalCallback(this.confirmEnrollmentInternal(userId, request || {}, options || {}), callback);
86
94
  }
95
+ status(userId, options, callback) {
96
+ return optionalCallback(this.statusInternal(userId, options || {}), callback);
97
+ }
87
98
  regenerateRecoveryCodes(userId, request, options, callback) {
88
99
  return optionalCallback(this.regenerateRecoveryCodesInternal(userId, request || {}, options || {}), callback);
89
100
  }
90
101
  disable(userId, request, options, callback) {
91
102
  return optionalCallback(this.disableInternal(userId, request || {}, options || {}), callback);
92
103
  }
104
+ /**
105
+ * Removes the second factor of another user, e.g. after the device and the
106
+ * recovery codes were lost. Called through `User.resetTwoFactor` once the
107
+ * actor proved itself (`proveActor`); see its warning.
108
+ */
109
+ reset(principalId, options, callback) {
110
+ return optionalCallback(this.resetInternal(String(principalId), options || {}), callback);
111
+ }
112
+ /**
113
+ * Step-up for an operation on another user: the actor of `options` signs
114
+ * it with their password, and with their authenticator code when they use
115
+ * a second factor. Recovery codes are not accepted here.
116
+ */
117
+ proveActor(actorId, request, options, callback) {
118
+ return optionalCallback(this.proveActorInternal(String(actorId), request || {}, options || {}), callback);
119
+ }
93
120
  deletePrincipals(principalIds, callback) {
94
121
  return optionalCallback(this.deletePrincipalsInternal(principalIds.map(String)), callback);
95
122
  }
@@ -147,6 +174,7 @@ var init_service = require_runtime.__esmMin((() => {
147
174
  } }) : null;
148
175
  if (!credential) {
149
176
  if (this.rateLimiter) await this.rateLimiter.reset(observed);
177
+ if (await this.isRequired(user, options)) return this.issueEnrollmentToken(user, normalizedInclude);
150
178
  return this.issueAccessToken(user, credentials, normalizedInclude, false);
151
179
  }
152
180
  const secondFactorObserved = [];
@@ -268,6 +296,32 @@ var init_service = require_runtime.__esmMin((() => {
268
296
  if (includeUser(include)) token.__data.user = user;
269
297
  return token;
270
298
  }
299
+ /**
300
+ * Issues the session of a user that must enroll before using the API. The
301
+ * token has to come back restricted: an application `createAccessToken`
302
+ * override may swap the scope (e.g. a forced password change), but an
303
+ * unrestricted token would bypass the requirement, so it is revoked.
304
+ */
305
+ async issueEnrollmentToken(user, include) {
306
+ const config = this.requireConfig(true);
307
+ const token = await invoke(user, "createAccessToken", [{
308
+ ttl: Math.ceil(config.enrollmentTtlMs / 1e3),
309
+ scopes: [TWO_FACTOR_ENROLLMENT_SCOPE]
310
+ }, {}]);
311
+ if (!token?.id) throw require_lib_two_factor_errors.authError("AUTHENTICATION_SECURITY_UNAVAILABLE", 503);
312
+ const scopes = token.scopes;
313
+ if (!Array.isArray(scopes) || !scopes.length || scopes.includes("DEFAULT")) {
314
+ await this.revokeToken(token);
315
+ throw require_lib_two_factor_errors.authError("AUTHENTICATION_SECURITY_UNAVAILABLE", 503);
316
+ }
317
+ if (includeUser(include)) token.__data.user = user;
318
+ return token;
319
+ }
320
+ /** Enrollment can only be demanded while users are able to enroll. */
321
+ async isRequired(user, options) {
322
+ if (this.config?.mode !== "enroll-and-verify") return false;
323
+ return await invoke(this.User, "isTwoFactorRequired", [user, options]) === true;
324
+ }
271
325
  async buildTwoFactorTokenOptions(credentials, options) {
272
326
  return invoke(this.User, "buildTwoFactorLoginContext", [credentials, options]);
273
327
  }
@@ -607,6 +661,21 @@ var init_service = require_runtime.__esmMin((() => {
607
661
  throw require_lib_two_factor_errors.authError("AUTHENTICATION_SECURITY_UNAVAILABLE", 503, "Authentication security reconciliation required");
608
662
  }
609
663
  }
664
+ async statusInternal(userId, options) {
665
+ const config = this.requireConfig();
666
+ const user = await this.authenticatedUser(userId, options);
667
+ const enabled = config.mode !== "disabled" && await this.Credential.count({
668
+ principalType: this.User.modelName,
669
+ principalId: String(userId),
670
+ provider: "totp",
671
+ status: "enabled"
672
+ }) > 0;
673
+ return {
674
+ mode: config.mode,
675
+ enabled,
676
+ required: await this.isRequired(user, options)
677
+ };
678
+ }
610
679
  async beginEnrollmentInternal(userId, request, options) {
611
680
  const config = this.requireConfig(true);
612
681
  const user = await this.authenticatedUser(userId, options);
@@ -707,7 +776,7 @@ var init_service = require_runtime.__esmMin((() => {
707
776
  const generated = require_lib_two_factor_recovery_codes.generateRecoveryCodes(config.recoveryCodeCount, config.recoveryCodeBytes);
708
777
  await this.persistRecoverySet(credential, generated);
709
778
  try {
710
- await this.revokeSessions(principalId, options, config.sessions.onEnable);
779
+ await this.revokeSessions(principalId, options, hasEnrollmentScope(options.accessToken) ? "revoke-all" : config.sessions.onEnable);
711
780
  if (count(await this.Credential.updateAll({
712
781
  id: credential.id,
713
782
  status: "pending",
@@ -941,8 +1010,44 @@ var init_service = require_runtime.__esmMin((() => {
941
1010
  status: "unused"
942
1011
  }) !== rows.length) throw new Error("Incomplete recovery code set");
943
1012
  }
1013
+ async proveActorInternal(actorId, request, options) {
1014
+ const config = this.requireConfig();
1015
+ const actor = await this.authenticatedUser(actorId, options);
1016
+ const observed = await this.reauthenticateManagement(actor, request.currentPassword);
1017
+ const credential = config.mode === "disabled" ? null : await this.Credential.findOne({ where: {
1018
+ principalType: this.User.modelName,
1019
+ principalId: actorId,
1020
+ provider: "totp",
1021
+ status: "enabled"
1022
+ } });
1023
+ if (credential) {
1024
+ if (!(await this.verifyCredentialFactor(credential, "totp", request.totpCode, `management:${require_lib_two_factor_crypto.randomToken(16)}`)).valid) {
1025
+ await this.consumeManagementFailure(actorId);
1026
+ throw require_lib_two_factor_errors.invalidFactor();
1027
+ }
1028
+ }
1029
+ if (this.rateLimiter && observed) await this.rateLimiter.reset([observed]);
1030
+ }
1031
+ async resetInternal(principalId, options) {
1032
+ this.requireConfig();
1033
+ const token = options.accessToken;
1034
+ if (!token || token.userId == null) throw require_lib_two_factor_errors.authError("AUTHORIZATION_REQUIRED", 401, "Authorization required");
1035
+ if (String(token.userId) === principalId && (!("principalType" in token) || token.principalType === this.User.modelName)) throw require_lib_two_factor_errors.authError("TWO_FACTOR_RESET_SELF", 403, "Use disable to change your own factor");
1036
+ if (!await this.User.findById(principalId)) throw require_lib_two_factor_errors.authError("NOT_FOUND", 404, "User not found");
1037
+ await this.revokeSessions(principalId, {}, "revoke-all");
1038
+ await this.destroyFactors([principalId]);
1039
+ this.audit("twoFactorReset", {
1040
+ principalId,
1041
+ actorPrincipalType: token.principalType ?? this.User.modelName,
1042
+ actorPrincipalId: String(token.userId)
1043
+ });
1044
+ return { enabled: false };
1045
+ }
944
1046
  async deletePrincipalsInternal(principalIds) {
945
1047
  if (!principalIds.length) return;
1048
+ await Promise.all([this.destroyFactors(principalIds), this.rateLimiter ? Promise.all(principalIds.map((principalId) => this.rateLimiter.deletePrincipal(principalId))) : Promise.resolve()]);
1049
+ }
1050
+ async destroyFactors(principalIds) {
946
1051
  const credentialIds = (await this.Credential.find({
947
1052
  where: {
948
1053
  principalType: this.User.modelName,
@@ -959,8 +1064,7 @@ var init_service = require_runtime.__esmMin((() => {
959
1064
  this.Credential.destroyAll({
960
1065
  principalType: this.User.modelName,
961
1066
  principalId: { inq: principalIds }
962
- }),
963
- this.rateLimiter ? Promise.all(principalIds.map((principalId) => this.rateLimiter.deletePrincipal(principalId))) : Promise.resolve()
1067
+ })
964
1068
  ]);
965
1069
  }
966
1070
  async rotateEncryptionInternal(options) {
@@ -1099,6 +1203,7 @@ var init_service = require_runtime.__esmMin((() => {
1099
1203
  }));
1100
1204
  //#endregion
1101
1205
  init_service();
1206
+ exports.TWO_FACTOR_ENROLLMENT_SCOPE = TWO_FACTOR_ENROLLMENT_SCOPE;
1102
1207
  exports.TwoFactorService = TwoFactorService;
1103
1208
  Object.defineProperty(exports, "init_service", {
1104
1209
  enumerable: true,
@@ -1106,3 +1211,9 @@ Object.defineProperty(exports, "init_service", {
1106
1211
  return init_service;
1107
1212
  }
1108
1213
  });
1214
+ Object.defineProperty(exports, "service_exports", {
1215
+ enumerable: true,
1216
+ get: function() {
1217
+ return service_exports;
1218
+ }
1219
+ });
@@ -1,6 +1,12 @@
1
1
  import { NormalizedTwoFactorConfig } from "./config.cjs";
2
2
  import { AuthenticationRateLimiter } from "./rate-limit.cjs";
3
3
  //#region src/lib/two-factor/service.d.ts
4
+ /**
5
+ * Scope of the access token issued at login when the application requires a
6
+ * second factor (`User.isTwoFactorRequired`) and the user has not enrolled yet.
7
+ * It only reaches the methods that complete the enrollment.
8
+ */
9
+ declare const TWO_FACTOR_ENROLLMENT_SCOPE = "two-factor-enrollment";
4
10
  declare class TwoFactorService {
5
11
  private readonly User;
6
12
  private readonly config;
@@ -23,12 +29,31 @@ declare class TwoFactorService {
23
29
  enabled: boolean;
24
30
  recoveryCodes: string[];
25
31
  }>;
32
+ status(userId: any, options: any, callback?: Function): Promise<{
33
+ mode: "disabled" | "verify-only" | "enroll-and-verify";
34
+ enabled: boolean;
35
+ required: boolean;
36
+ }>;
26
37
  regenerateRecoveryCodes(userId: any, request: any, options: any, callback?: Function): Promise<{
27
38
  recoveryCodes: any;
28
39
  }>;
29
40
  disable(userId: any, request: any, options: any, callback?: Function): Promise<{
30
41
  enabled: boolean;
31
42
  }>;
43
+ /**
44
+ * Removes the second factor of another user, e.g. after the device and the
45
+ * recovery codes were lost. Called through `User.resetTwoFactor` once the
46
+ * actor proved itself (`proveActor`); see its warning.
47
+ */
48
+ reset(principalId: any, options: any, callback?: Function): Promise<{
49
+ enabled: boolean;
50
+ }>;
51
+ /**
52
+ * Step-up for an operation on another user: the actor of `options` signs
53
+ * it with their password, and with their authenticator code when they use
54
+ * a second factor. Recovery codes are not accepted here.
55
+ */
56
+ proveActor(actorId: any, request: any, options: any, callback?: Function): Promise<void>;
32
57
  deletePrincipals(principalIds: ReadonlyArray<any>, callback?: Function): Promise<void>;
33
58
  rotateEncryption(options?: any, callback?: Function): Promise<{
34
59
  credentialsReencrypted: number;
@@ -45,6 +70,15 @@ declare class TwoFactorService {
45
70
  private resolveSource;
46
71
  private hasPassword;
47
72
  private issueAccessToken;
73
+ /**
74
+ * Issues the session of a user that must enroll before using the API. The
75
+ * token has to come back restricted: an application `createAccessToken`
76
+ * override may swap the scope (e.g. a forced password change), but an
77
+ * unrestricted token would bypass the requirement, so it is revoked.
78
+ */
79
+ private issueEnrollmentToken;
80
+ /** Enrollment can only be demanded while users are able to enroll. */
81
+ private isRequired;
48
82
  private buildTwoFactorTokenOptions;
49
83
  private secretAad;
50
84
  private challengeAad;
@@ -58,6 +92,7 @@ declare class TwoFactorService {
58
92
  private confirmRecoveryReservation;
59
93
  private releaseRecoveryReservation;
60
94
  private compensateChallengeFailure;
95
+ private statusInternal;
61
96
  private beginEnrollmentInternal;
62
97
  private confirmEnrollmentInternal;
63
98
  private regenerateRecoveryCodesInternal;
@@ -67,7 +102,10 @@ declare class TwoFactorService {
67
102
  private consumeManagementFailure;
68
103
  private enabledCredential;
69
104
  private persistRecoverySet;
105
+ private proveActorInternal;
106
+ private resetInternal;
70
107
  private deletePrincipalsInternal;
108
+ private destroyFactors;
71
109
  private rotateEncryptionInternal;
72
110
  private revokeSessions;
73
111
  private revokeToken;
@@ -75,4 +113,4 @@ declare class TwoFactorService {
75
113
  private audit;
76
114
  }
77
115
  //#endregion
78
- export { TwoFactorService };
116
+ export { TWO_FACTOR_ENROLLMENT_SCOPE, TwoFactorService };
package/dist/package.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
  var require_package = /* @__PURE__ */ require("./_virtual/_rolldown/runtime.cjs").__commonJSMin(((exports, module) => {
3
3
  module.exports = {
4
4
  "name": "@vsaas/loopback",
5
- "version": "12.4.0",
5
+ "version": "12.5.0",
6
6
  "description": "Fork of LoopBack 3 framework for building APIs and microservices in Node.js",
7
7
  "keywords": [
8
8
  "StrongLoop",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vsaas/loopback",
3
- "version": "12.4.0",
3
+ "version": "12.5.0",
4
4
  "description": "Fork of LoopBack 3 framework for building APIs and microservices in Node.js",
5
5
  "keywords": [
6
6
  "StrongLoop",
@@ -124,8 +124,8 @@
124
124
  "tsdown": "0.22.14",
125
125
  "typescript": "6.0.2",
126
126
  "vitest": "4.1.11",
127
- "@vsaas/error-handler": "^12.0.1",
128
- "@vsaas/loopback-boot": "^12.0.2"
127
+ "@vsaas/loopback-boot": "^12.0.2",
128
+ "@vsaas/error-handler": "^12.0.1"
129
129
  },
130
130
  "engines": {
131
131
  "node": ">=24"