@vsaas/loopback 12.1.1 → 12.2.1
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/README.md +6 -0
- package/common/models/rate-limit-state.json +121 -0
- package/common/models/two-factor-challenge.json +112 -0
- package/common/models/two-factor-credential.json +117 -0
- package/common/models/two-factor-recovery-code.json +63 -0
- package/common/models/user.json +30 -0
- package/dist/_virtual/_rolldown/runtime.cjs +9 -2
- package/dist/common/models/access-token.d.cts +3 -0
- package/dist/common/models/acl.cjs +1 -3
- package/dist/common/models/acl.d.cts +1 -0
- package/dist/common/models/application.d.cts +3 -0
- package/dist/common/models/change.cjs +21 -18
- package/dist/common/models/change.d.cts +1 -0
- package/dist/common/models/checkpoint.d.cts +3 -0
- package/dist/common/models/email.d.cts +3 -0
- package/dist/common/models/key-value-model.d.cts +3 -0
- package/dist/common/models/rate-limit-state.cjs +7 -0
- package/dist/common/models/rate-limit-state.d.cts +3 -0
- package/dist/common/models/rate-limit-state2.cjs +109 -0
- package/dist/common/models/role-mapping.d.cts +3 -0
- package/dist/common/models/role.cjs +12 -8
- package/dist/common/models/role.d.cts +1 -0
- package/dist/common/models/scope.d.cts +3 -0
- package/dist/common/models/two-factor-challenge.cjs +7 -0
- package/dist/common/models/two-factor-challenge.d.cts +3 -0
- package/dist/common/models/two-factor-challenge2.cjs +108 -0
- package/dist/common/models/two-factor-credential.cjs +7 -0
- package/dist/common/models/two-factor-credential.d.cts +3 -0
- package/dist/common/models/two-factor-credential2.cjs +103 -0
- package/dist/common/models/two-factor-recovery-code.cjs +7 -0
- package/dist/common/models/two-factor-recovery-code.d.cts +3 -0
- package/dist/common/models/two-factor-recovery-code2.cjs +57 -0
- package/dist/common/models/user.cjs +261 -21
- package/dist/common/models/user.d.cts +3 -0
- package/dist/common/models/user2.cjs +30 -0
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +3 -0
- package/dist/lib/access-context.d.cts +33 -0
- package/dist/lib/application.d.cts +1 -0
- package/dist/lib/authentication-security-initializer.cjs +351 -0
- package/dist/lib/authentication-security-initializer.d.cts +4 -0
- package/dist/lib/builtin-models.cjs +12 -0
- package/dist/lib/builtin-models.d.cts +3 -0
- package/dist/lib/configure-shared-methods.cjs +7 -4
- package/dist/lib/configure-shared-methods.d.cts +3 -0
- package/dist/lib/connectors/base-connector.d.cts +6 -0
- package/dist/lib/connectors/mail-direct-transport.cjs +26 -23
- package/dist/lib/connectors/mail-direct-transport.d.cts +22 -0
- package/dist/lib/connectors/mail-stub-transport.d.cts +14 -0
- package/dist/lib/connectors/mail.d.cts +7 -0
- package/dist/lib/connectors/memory.d.cts +6 -0
- package/dist/lib/current-context.d.cts +3 -0
- package/dist/lib/globalize.d.cts +10 -0
- package/dist/lib/loopback.cjs +6 -0
- package/dist/lib/loopback.d.cts +1 -0
- package/dist/lib/model.d.cts +1 -0
- package/dist/lib/persisted-model.cjs +7 -12
- package/dist/lib/persisted-model.d.cts +1 -0
- package/dist/lib/rate-limit/algorithms/common.cjs +37 -0
- package/dist/lib/rate-limit/algorithms/failure-lockout.cjs +70 -0
- package/dist/lib/rate-limit/algorithms/fixed-window.cjs +61 -0
- package/dist/lib/rate-limit/algorithms/index.cjs +55 -0
- package/dist/lib/rate-limit/config.cjs +107 -0
- package/dist/lib/rate-limit/errors.cjs +58 -0
- package/dist/lib/rate-limit/index.cjs +15 -0
- package/dist/lib/rate-limit/index.d.cts +1 -0
- package/dist/lib/rate-limit/initializer.cjs +92 -0
- package/dist/lib/rate-limit/initializer.d.cts +4 -0
- package/dist/lib/rate-limit/limiter.cjs +368 -0
- package/dist/lib/rate-limit/registry.cjs +92 -0
- package/dist/lib/rate-limit/remote.cjs +180 -0
- package/dist/lib/rate-limit/remote.d.cts +6 -0
- package/dist/lib/rate-limit/stores/persisted-model.cjs +353 -0
- package/dist/lib/rate-limit/subject.cjs +127 -0
- package/dist/lib/rate-limit/types.cjs +1 -0
- package/dist/lib/rate-limit/types.d.cts +167 -0
- package/dist/lib/registry.d.cts +1 -0
- package/dist/lib/runtime.d.cts +10 -0
- package/dist/lib/server-app.d.cts +3 -0
- package/dist/lib/two-factor/config.cjs +199 -0
- package/dist/lib/two-factor/config.d.cts +55 -0
- package/dist/lib/two-factor/crypto.cjs +68 -0
- package/dist/lib/two-factor/crypto.d.cts +16 -0
- package/dist/lib/two-factor/errors.cjs +58 -0
- package/dist/lib/two-factor/errors.d.cts +18 -0
- package/dist/lib/two-factor/rate-limit.cjs +153 -0
- package/dist/lib/two-factor/rate-limit.d.cts +22 -0
- package/dist/lib/two-factor/recovery-codes.cjs +49 -0
- package/dist/lib/two-factor/recovery-codes.d.cts +16 -0
- package/dist/lib/two-factor/service.cjs +1108 -0
- package/dist/lib/two-factor/service.d.cts +78 -0
- package/dist/lib/two-factor/totp.cjs +50 -0
- package/dist/lib/two-factor/totp.d.cts +14 -0
- package/dist/lib/utils.d.cts +36 -0
- package/dist/package.cjs +46 -10
- package/dist/server/middleware/context.d.cts +3 -0
- package/dist/server/middleware/error-handler.d.cts +3 -0
- package/dist/server/middleware/favicon.d.cts +7 -0
- package/dist/server/middleware/rest.d.cts +6 -0
- package/dist/server/middleware/static.d.cts +3 -0
- package/dist/server/middleware/status.d.cts +19 -0
- package/dist/server/middleware/token.d.cts +3 -0
- package/dist/server/middleware/url-not-found.d.cts +13 -0
- package/docs/api-explorer-details.md +110 -0
- package/docs/application-guide.md +1110 -0
- package/docs/assets/explorer-api.png +0 -0
- package/docs/assets/explorer-endpoint.png +0 -0
- package/docs/assets/explorer-listing.png +0 -0
- package/docs/assets/explorer-req-res.png +0 -0
- package/docs/assets/lb-modules.png +0 -0
- package/docs/assets/loopback-architecture.png +0 -0
- package/docs/assets/loopback-concepts.png +0 -0
- package/docs/assets/loopback_ov.png +0 -0
- package/docs/rate-limiting.md +879 -0
- package/docs/two-factor-authentication.md +611 -0
- package/docs/two-factor-authenticator-loss-runbook.md +117 -0
- package/package.json +56 -20
|
@@ -143,16 +143,17 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
|
|
|
143
143
|
if (err) {
|
|
144
144
|
debug("An error is reported from User.hasPassword: %j", err);
|
|
145
145
|
fn(defaultError);
|
|
146
|
-
} else if (isMatch)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
146
|
+
} else if (isMatch) {
|
|
147
|
+
if (self.settings.emailVerificationRequired && !user.emailVerified) {
|
|
148
|
+
debug("User email has not been verified");
|
|
149
|
+
err = new Error(g.f("login failed as the email has not been verified"));
|
|
150
|
+
err.statusCode = 401;
|
|
151
|
+
err.code = "LOGIN_FAILED_EMAIL_NOT_VERIFIED";
|
|
152
|
+
err.details = { userId: user.id };
|
|
153
|
+
fn(err);
|
|
154
|
+
} else if (user.createAccessToken.length === 2) user.createAccessToken(credentials.ttl, tokenHandler);
|
|
155
|
+
else user.createAccessToken(credentials.ttl, credentials, tokenHandler);
|
|
156
|
+
} else {
|
|
156
157
|
debug("The password is invalid for user %s", query.email || query.username);
|
|
157
158
|
fn(defaultError);
|
|
158
159
|
}
|
|
@@ -164,6 +165,102 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
|
|
|
164
165
|
});
|
|
165
166
|
return fn.promise;
|
|
166
167
|
};
|
|
168
|
+
User._legacyLogin = User.login;
|
|
169
|
+
User.login = function(credentials, include, options, fn) {
|
|
170
|
+
if (typeof include === "function") {
|
|
171
|
+
fn = include;
|
|
172
|
+
include = void 0;
|
|
173
|
+
options = void 0;
|
|
174
|
+
} else if (typeof options === "function") {
|
|
175
|
+
fn = options;
|
|
176
|
+
options = void 0;
|
|
177
|
+
}
|
|
178
|
+
if (!(this.settings.twoFactor != null || this.settings.authenticationRateLimit?.enabled === true)) return this._legacyLogin(credentials, include, fn);
|
|
179
|
+
if (!this._authenticationSecurityReady || !this._authenticationSecurity) {
|
|
180
|
+
fn = fn || utils.createPromiseCallback();
|
|
181
|
+
const error = /* @__PURE__ */ new Error("Authentication security is not ready");
|
|
182
|
+
error.statusCode = 503;
|
|
183
|
+
error.code = "AUTHENTICATION_SECURITY_UNAVAILABLE";
|
|
184
|
+
process.nextTick(fn, error);
|
|
185
|
+
return fn.promise;
|
|
186
|
+
}
|
|
187
|
+
return this._authenticationSecurity.login(credentials, include, options || {}, fn);
|
|
188
|
+
};
|
|
189
|
+
User.getTwoFactorPrincipalBindingMaterial = function(user, options, fn) {
|
|
190
|
+
if (typeof options === "function") {
|
|
191
|
+
fn = options;
|
|
192
|
+
options = void 0;
|
|
193
|
+
}
|
|
194
|
+
fn = fn || utils.createPromiseCallback();
|
|
195
|
+
process.nextTick(function() {
|
|
196
|
+
if (!user || typeof user.password !== "string" || !user.password) {
|
|
197
|
+
const error = /* @__PURE__ */ new Error("Two-factor principal binding is unavailable");
|
|
198
|
+
error.code = "AUTHENTICATION_SECURITY_UNAVAILABLE";
|
|
199
|
+
error.statusCode = 503;
|
|
200
|
+
return fn(error);
|
|
201
|
+
}
|
|
202
|
+
fn(null, user.password);
|
|
203
|
+
});
|
|
204
|
+
return fn.promise;
|
|
205
|
+
};
|
|
206
|
+
User.validateTwoFactorLoginPrincipal = function(user, options, fn) {
|
|
207
|
+
if (typeof options === "function") fn = options;
|
|
208
|
+
fn = fn || utils.createPromiseCallback();
|
|
209
|
+
process.nextTick(fn, null, true);
|
|
210
|
+
return fn.promise;
|
|
211
|
+
};
|
|
212
|
+
User.buildTwoFactorLoginContext = function(credentials, options, fn) {
|
|
213
|
+
if (typeof options === "function") fn = options;
|
|
214
|
+
fn = fn || utils.createPromiseCallback();
|
|
215
|
+
process.nextTick(fn, null, { ttl: credentials && credentials.ttl });
|
|
216
|
+
return fn.promise;
|
|
217
|
+
};
|
|
218
|
+
User.resolveAuthenticationRateLimitSource = function(options, fn) {
|
|
219
|
+
fn = fn || utils.createPromiseCallback();
|
|
220
|
+
process.nextTick(fn, null, options && (options.authenticationSource || options.req?.ip || options.req?.socket?.remoteAddress || null));
|
|
221
|
+
return fn.promise;
|
|
222
|
+
};
|
|
223
|
+
User.verifyTwoFactor = function(verification, options, fn) {
|
|
224
|
+
if (typeof options === "function") {
|
|
225
|
+
fn = options;
|
|
226
|
+
options = void 0;
|
|
227
|
+
}
|
|
228
|
+
if (!this._authenticationSecurityReady || !this._authenticationSecurity) {
|
|
229
|
+
fn = fn || utils.createPromiseCallback();
|
|
230
|
+
const error = /* @__PURE__ */ new Error("Two-factor authentication is not configured");
|
|
231
|
+
error.statusCode = this.settings.twoFactor == null ? 404 : 503;
|
|
232
|
+
error.code = this.settings.twoFactor == null ? "TWO_FACTOR_NOT_CONFIGURED" : "AUTHENTICATION_SECURITY_UNAVAILABLE";
|
|
233
|
+
process.nextTick(fn, error);
|
|
234
|
+
return fn.promise;
|
|
235
|
+
}
|
|
236
|
+
return this._authenticationSecurity.verifyTwoFactor(verification, options || {}, fn);
|
|
237
|
+
};
|
|
238
|
+
for (const method of [
|
|
239
|
+
"beginTwoFactorEnrollment",
|
|
240
|
+
"confirmTwoFactorEnrollment",
|
|
241
|
+
"regenerateTwoFactorRecoveryCodes",
|
|
242
|
+
"disableTwoFactor"
|
|
243
|
+
]) User[method] = function(userId, request, options, fn) {
|
|
244
|
+
if (typeof options === "function") {
|
|
245
|
+
fn = options;
|
|
246
|
+
options = void 0;
|
|
247
|
+
}
|
|
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
|
+
}
|
|
256
|
+
const serviceMethod = {
|
|
257
|
+
beginTwoFactorEnrollment: "beginEnrollment",
|
|
258
|
+
confirmTwoFactorEnrollment: "confirmEnrollment",
|
|
259
|
+
regenerateTwoFactorRecoveryCodes: "regenerateRecoveryCodes",
|
|
260
|
+
disableTwoFactor: "disable"
|
|
261
|
+
}[method];
|
|
262
|
+
return this._authenticationSecurity[serviceMethod](userId, request, options || {}, fn);
|
|
263
|
+
};
|
|
167
264
|
User.logout = function(tokenId, fn) {
|
|
168
265
|
fn = fn || utils.createPromiseCallback();
|
|
169
266
|
let err;
|
|
@@ -184,8 +281,12 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
|
|
|
184
281
|
return fn.promise;
|
|
185
282
|
};
|
|
186
283
|
User.observe("before delete", function(ctx, next) {
|
|
187
|
-
if (
|
|
188
|
-
|
|
284
|
+
if ((ctx.Model.settings.twoFactor != null || ctx.Model.settings.authenticationRateLimit?.enabled === true) && !ctx.Model._authenticationSecurity) {
|
|
285
|
+
const error = /* @__PURE__ */ new Error("Authentication security is not ready");
|
|
286
|
+
error.statusCode = 503;
|
|
287
|
+
error.code = "AUTHENTICATION_SECURITY_UNAVAILABLE";
|
|
288
|
+
return next(error);
|
|
289
|
+
}
|
|
189
290
|
const pkName = ctx.Model.definition.idName() || "id";
|
|
190
291
|
ctx.Model.find({
|
|
191
292
|
where: ctx.where,
|
|
@@ -196,7 +297,11 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
|
|
|
196
297
|
for (let i = 0; i < list.length; i++) ids[i] = list[i][pkName];
|
|
197
298
|
ctx.where = {};
|
|
198
299
|
ctx.where[pkName] = { inq: ids };
|
|
199
|
-
|
|
300
|
+
const cleanup = [];
|
|
301
|
+
const AccessToken = ctx.Model.relations.accessTokens?.modelTo;
|
|
302
|
+
if (AccessToken) cleanup.push(AccessToken.destroyAll({ userId: { inq: ids } }));
|
|
303
|
+
if (ctx.Model._authenticationSecurity) cleanup.push(ctx.Model._authenticationSecurity.deletePrincipals(ids));
|
|
304
|
+
Promise.all(cleanup).then(() => next(), next);
|
|
200
305
|
});
|
|
201
306
|
});
|
|
202
307
|
User.prototype.hasPassword = function(plain, fn) {
|
|
@@ -475,6 +580,9 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
|
|
|
475
580
|
};
|
|
476
581
|
User.hashPassword = function(plain) {
|
|
477
582
|
this.validatePassword(plain);
|
|
583
|
+
return this._hashPasswordWithoutValidation(plain);
|
|
584
|
+
};
|
|
585
|
+
User._hashPasswordWithoutValidation = function(plain) {
|
|
478
586
|
const salt = bcrypt.genSaltSync(this.settings.saltWorkFactor || SALT_WORK_FACTOR);
|
|
479
587
|
return bcrypt.hashSync(plain, salt);
|
|
480
588
|
};
|
|
@@ -532,24 +640,118 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
|
|
|
532
640
|
});
|
|
533
641
|
UserModel.remoteMethod("login", {
|
|
534
642
|
description: "Login a user with username/email and password.",
|
|
643
|
+
accepts: [
|
|
644
|
+
{
|
|
645
|
+
arg: "credentials",
|
|
646
|
+
type: "object",
|
|
647
|
+
required: true,
|
|
648
|
+
http: { source: "body" }
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
arg: "include",
|
|
652
|
+
type: ["string"],
|
|
653
|
+
http: { source: "query" },
|
|
654
|
+
description: "Related objects to include in the response. See the description of return value for more details."
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
arg: "options",
|
|
658
|
+
type: "object",
|
|
659
|
+
http: buildAuthenticationOptions
|
|
660
|
+
}
|
|
661
|
+
],
|
|
662
|
+
returns: {
|
|
663
|
+
arg: "accessToken",
|
|
664
|
+
type: "object",
|
|
665
|
+
root: true,
|
|
666
|
+
description: g.f("The response body contains properties of the {{AccessToken}} created on login.\nDepending on the value of `include` parameter, the body may contain additional properties:\n\n - `user` - `U+007BUserU+007D` - Data of the currently logged in user. {{(`include=user`)}}\n\n")
|
|
667
|
+
},
|
|
668
|
+
http: { verb: "post" }
|
|
669
|
+
});
|
|
670
|
+
UserModel.getTwoFactorAuthenticationOptions = buildAuthenticationOptions;
|
|
671
|
+
UserModel.remoteMethod("verifyTwoFactor", {
|
|
672
|
+
description: "Complete login by verifying a second factor.",
|
|
535
673
|
accepts: [{
|
|
536
|
-
arg: "
|
|
674
|
+
arg: "verification",
|
|
537
675
|
type: "object",
|
|
538
676
|
required: true,
|
|
539
677
|
http: { source: "body" }
|
|
540
678
|
}, {
|
|
541
|
-
arg: "
|
|
542
|
-
type:
|
|
543
|
-
http:
|
|
544
|
-
description: "Related objects to include in the response. See the description of return value for more details."
|
|
679
|
+
arg: "options",
|
|
680
|
+
type: "object",
|
|
681
|
+
http: buildAuthenticationOptions
|
|
545
682
|
}],
|
|
546
683
|
returns: {
|
|
547
684
|
arg: "accessToken",
|
|
548
685
|
type: "object",
|
|
549
|
-
root: true
|
|
550
|
-
description: g.f("The response body contains properties of the {{AccessToken}} created on login.\nDepending on the value of `include` parameter, the body may contain additional properties:\n\n - `user` - `U+007BUserU+007D` - Data of the currently logged in user. {{(`include=user`)}}\n\n")
|
|
686
|
+
root: true
|
|
551
687
|
},
|
|
552
|
-
http: {
|
|
688
|
+
http: {
|
|
689
|
+
verb: "post",
|
|
690
|
+
path: "/two-factor/verify"
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
function registerTwoFactorManagementMethod(name, path, description) {
|
|
694
|
+
UserModel.remoteMethod(name, {
|
|
695
|
+
description,
|
|
696
|
+
accepts: [
|
|
697
|
+
{
|
|
698
|
+
arg: "userId",
|
|
699
|
+
type: "any",
|
|
700
|
+
http: getUserIdFromRequestContext
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
arg: "request",
|
|
704
|
+
type: "object",
|
|
705
|
+
required: true,
|
|
706
|
+
http: { source: "body" }
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
arg: "options",
|
|
710
|
+
type: "object",
|
|
711
|
+
http: buildAuthenticationOptions
|
|
712
|
+
}
|
|
713
|
+
],
|
|
714
|
+
returns: {
|
|
715
|
+
arg: "result",
|
|
716
|
+
type: "object",
|
|
717
|
+
root: true
|
|
718
|
+
},
|
|
719
|
+
http: {
|
|
720
|
+
verb: "post",
|
|
721
|
+
path
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
registerTwoFactorManagementMethod("beginTwoFactorEnrollment", "/two-factor/setup", "Begin two-factor enrollment.");
|
|
726
|
+
registerTwoFactorManagementMethod("confirmTwoFactorEnrollment", "/two-factor/confirm", "Confirm two-factor enrollment.");
|
|
727
|
+
registerTwoFactorManagementMethod("regenerateTwoFactorRecoveryCodes", "/two-factor/recovery-codes", "Regenerate two-factor recovery codes.");
|
|
728
|
+
registerTwoFactorManagementMethod("disableTwoFactor", "/two-factor/disable", "Disable two-factor authentication.");
|
|
729
|
+
for (const method of [
|
|
730
|
+
"login",
|
|
731
|
+
"verifyTwoFactor",
|
|
732
|
+
"beginTwoFactorEnrollment",
|
|
733
|
+
"confirmTwoFactorEnrollment",
|
|
734
|
+
"regenerateTwoFactorRecoveryCodes",
|
|
735
|
+
"disableTwoFactor"
|
|
736
|
+
]) UserModel.afterRemote(method, function(ctx, result, next) {
|
|
737
|
+
ctx.res.setHeader("Cache-Control", "no-store");
|
|
738
|
+
ctx.res.setHeader("Pragma", "no-cache");
|
|
739
|
+
next();
|
|
740
|
+
});
|
|
741
|
+
for (const method of [
|
|
742
|
+
"login",
|
|
743
|
+
"verifyTwoFactor",
|
|
744
|
+
"beginTwoFactorEnrollment",
|
|
745
|
+
"confirmTwoFactorEnrollment",
|
|
746
|
+
"regenerateTwoFactorRecoveryCodes",
|
|
747
|
+
"disableTwoFactor"
|
|
748
|
+
]) UserModel.afterRemoteError(method, function(ctx, next) {
|
|
749
|
+
if (ctx.error) {
|
|
750
|
+
ctx.res.setHeader("Cache-Control", "no-store");
|
|
751
|
+
ctx.res.setHeader("Pragma", "no-cache");
|
|
752
|
+
}
|
|
753
|
+
if (ctx.error && ctx.error.retryAfter) ctx.res.setHeader("Retry-After", String(ctx.error.retryAfter));
|
|
754
|
+
next();
|
|
553
755
|
});
|
|
554
756
|
UserModel.remoteMethod("logout", {
|
|
555
757
|
description: "Logout a user with access token.",
|
|
@@ -682,6 +884,13 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
|
|
|
682
884
|
}
|
|
683
885
|
return token.userId;
|
|
684
886
|
}
|
|
887
|
+
function buildAuthenticationOptions(ctx) {
|
|
888
|
+
const req = ctx && ctx.req;
|
|
889
|
+
return {
|
|
890
|
+
accessToken: req && req.accessToken,
|
|
891
|
+
authenticationSource: req && (req.ip || req.socket && req.socket.remoteAddress)
|
|
892
|
+
};
|
|
893
|
+
}
|
|
685
894
|
UserModel.afterRemote("confirm", function(ctx, inst, next) {
|
|
686
895
|
if (ctx.args.redirect !== void 0) {
|
|
687
896
|
if (!ctx.res) return next(new Error(g.f("The transport does not support HTTP redirects.")));
|
|
@@ -780,6 +989,37 @@ var require_user = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports, mo
|
|
|
780
989
|
}
|
|
781
990
|
ctx.Model._invalidateAccessTokensOfUsers(userIdsToExpire, ctx.options, next);
|
|
782
991
|
});
|
|
992
|
+
User.observe("after save", function invalidateTwoFactorChallenges(ctx, next) {
|
|
993
|
+
if (!ctx.hookState.originalUserData || !(ctx.instance || ctx.data).password) return next();
|
|
994
|
+
const Challenge = ctx.Model.app && ctx.Model.app.models.TwoFactorChallenge;
|
|
995
|
+
if (!Challenge) return next();
|
|
996
|
+
const pkName = ctx.Model.definition.idName() || "id";
|
|
997
|
+
const principalIds = ctx.hookState.originalUserData.map(function(user) {
|
|
998
|
+
return String(user[pkName]);
|
|
999
|
+
});
|
|
1000
|
+
Challenge.updateAll({
|
|
1001
|
+
principalType: ctx.Model.modelName,
|
|
1002
|
+
principalId: { inq: principalIds },
|
|
1003
|
+
status: { inq: ["pending", "verifying"] }
|
|
1004
|
+
}, { status: "expired" }, function(err) {
|
|
1005
|
+
if (err) {
|
|
1006
|
+
debug("Unable to invalidate two-factor challenges: %j", err);
|
|
1007
|
+
const event = {
|
|
1008
|
+
error: err,
|
|
1009
|
+
modelName: ctx.Model.modelName,
|
|
1010
|
+
principalCount: principalIds.length,
|
|
1011
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1012
|
+
};
|
|
1013
|
+
try {
|
|
1014
|
+
ctx.Model.emit("twoFactorChallengeInvalidationError", event);
|
|
1015
|
+
} catch {}
|
|
1016
|
+
try {
|
|
1017
|
+
ctx.Model.app.emit("authenticationSecurityCleanupError", err);
|
|
1018
|
+
} catch {}
|
|
1019
|
+
}
|
|
1020
|
+
next();
|
|
1021
|
+
});
|
|
1022
|
+
});
|
|
783
1023
|
}
|
|
784
1024
|
function hasMoreThanOneOwnEnumerableKey(object) {
|
|
785
1025
|
let count = 0;
|
|
@@ -42,6 +42,36 @@ var require_user = /* @__PURE__ */ require("../../_virtual/_rolldown/runtime.cjs
|
|
|
42
42
|
"permission": "ALLOW",
|
|
43
43
|
"property": "login"
|
|
44
44
|
},
|
|
45
|
+
{
|
|
46
|
+
"principalType": "ROLE",
|
|
47
|
+
"principalId": "$everyone",
|
|
48
|
+
"permission": "ALLOW",
|
|
49
|
+
"property": "verifyTwoFactor"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"principalType": "ROLE",
|
|
53
|
+
"principalId": "$authenticated",
|
|
54
|
+
"permission": "ALLOW",
|
|
55
|
+
"property": "beginTwoFactorEnrollment"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"principalType": "ROLE",
|
|
59
|
+
"principalId": "$authenticated",
|
|
60
|
+
"permission": "ALLOW",
|
|
61
|
+
"property": "confirmTwoFactorEnrollment"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"principalType": "ROLE",
|
|
65
|
+
"principalId": "$authenticated",
|
|
66
|
+
"permission": "ALLOW",
|
|
67
|
+
"property": "regenerateTwoFactorRecoveryCodes"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"principalType": "ROLE",
|
|
71
|
+
"principalId": "$authenticated",
|
|
72
|
+
"permission": "ALLOW",
|
|
73
|
+
"property": "disableTwoFactor"
|
|
74
|
+
},
|
|
45
75
|
{
|
|
46
76
|
"principalType": "ROLE",
|
|
47
77
|
"principalId": "$everyone",
|
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,7 @@ const require_lib_loopback = require("./lib/loopback.cjs");
|
|
|
2
2
|
const require_lib_connectors_base_connector = require("./lib/connectors/base-connector.cjs");
|
|
3
3
|
const require_lib_connectors_memory = require("./lib/connectors/memory.cjs");
|
|
4
4
|
const require_lib_connectors_mail = require("./lib/connectors/mail.cjs");
|
|
5
|
+
const require_lib_rate_limit_index = require("./lib/rate-limit/index.cjs");
|
|
5
6
|
//#region src/index.ts
|
|
6
7
|
const loopback = require_lib_loopback;
|
|
7
8
|
require("@vsaas/loopback-datasource-juggler");
|
|
@@ -12,5 +13,6 @@ loopback.Remote = require("@vsaas/loopback-connector-remote");
|
|
|
12
13
|
loopback.GeoPoint = require("@vsaas/loopback-datasource-juggler/geo").GeoPoint;
|
|
13
14
|
loopback.DateString = require("@vsaas/loopback-datasource-juggler/date-string");
|
|
14
15
|
loopback.ValidationError = loopback.Model.ValidationError;
|
|
16
|
+
loopback.rateLimit = require_lib_rate_limit_index;
|
|
15
17
|
module.exports = loopback;
|
|
16
18
|
//#endregion
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/lib/access-context.d.ts
|
|
2
|
+
declare const DEFAULT_SCOPES: string[];
|
|
3
|
+
declare function AccessContext(context: any): any;
|
|
4
|
+
declare namespace AccessContext {
|
|
5
|
+
var ALL: string;
|
|
6
|
+
var READ: string;
|
|
7
|
+
var REPLICATE: string;
|
|
8
|
+
var WRITE: string;
|
|
9
|
+
var EXECUTE: string;
|
|
10
|
+
var DEFAULT: string;
|
|
11
|
+
var ALLOW: string;
|
|
12
|
+
var ALARM: string;
|
|
13
|
+
var AUDIT: string;
|
|
14
|
+
var DENY: string;
|
|
15
|
+
var permissionOrder: {
|
|
16
|
+
DEFAULT: number;
|
|
17
|
+
ALLOW: number;
|
|
18
|
+
ALARM: number;
|
|
19
|
+
AUDIT: number;
|
|
20
|
+
DENY: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
declare function Principal(type: any, id: any, name: any): any;
|
|
24
|
+
declare namespace Principal {
|
|
25
|
+
var USER: string;
|
|
26
|
+
var APP: string;
|
|
27
|
+
var APPLICATION: string;
|
|
28
|
+
var ROLE: string;
|
|
29
|
+
var SCOPE: string;
|
|
30
|
+
}
|
|
31
|
+
declare function AccessRequest(model: any, property: any, accessType: any, permission: any, methodNames: any, registry: any): any;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { AccessContext, AccessRequest, DEFAULT_SCOPES, Principal };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|