@vsaas/loopback 12.1.1 → 12.2.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.
Files changed (117) hide show
  1. package/README.md +6 -0
  2. package/common/models/rate-limit-state.json +121 -0
  3. package/common/models/two-factor-challenge.json +112 -0
  4. package/common/models/two-factor-credential.json +117 -0
  5. package/common/models/two-factor-recovery-code.json +63 -0
  6. package/common/models/user.json +30 -0
  7. package/dist/_virtual/_rolldown/runtime.cjs +9 -2
  8. package/dist/common/models/access-token.d.cts +3 -0
  9. package/dist/common/models/acl.cjs +1 -3
  10. package/dist/common/models/acl.d.cts +1 -0
  11. package/dist/common/models/application.d.cts +3 -0
  12. package/dist/common/models/change.cjs +21 -18
  13. package/dist/common/models/change.d.cts +1 -0
  14. package/dist/common/models/checkpoint.d.cts +3 -0
  15. package/dist/common/models/email.d.cts +3 -0
  16. package/dist/common/models/key-value-model.d.cts +3 -0
  17. package/dist/common/models/rate-limit-state.cjs +7 -0
  18. package/dist/common/models/rate-limit-state.d.cts +3 -0
  19. package/dist/common/models/rate-limit-state2.cjs +109 -0
  20. package/dist/common/models/role-mapping.d.cts +3 -0
  21. package/dist/common/models/role.cjs +12 -8
  22. package/dist/common/models/role.d.cts +1 -0
  23. package/dist/common/models/scope.d.cts +3 -0
  24. package/dist/common/models/two-factor-challenge.cjs +7 -0
  25. package/dist/common/models/two-factor-challenge.d.cts +3 -0
  26. package/dist/common/models/two-factor-challenge2.cjs +108 -0
  27. package/dist/common/models/two-factor-credential.cjs +7 -0
  28. package/dist/common/models/two-factor-credential.d.cts +3 -0
  29. package/dist/common/models/two-factor-credential2.cjs +103 -0
  30. package/dist/common/models/two-factor-recovery-code.cjs +7 -0
  31. package/dist/common/models/two-factor-recovery-code.d.cts +3 -0
  32. package/dist/common/models/two-factor-recovery-code2.cjs +57 -0
  33. package/dist/common/models/user.cjs +258 -21
  34. package/dist/common/models/user.d.cts +3 -0
  35. package/dist/common/models/user2.cjs +30 -0
  36. package/dist/index.cjs +2 -0
  37. package/dist/index.d.cts +3 -0
  38. package/dist/lib/access-context.d.cts +33 -0
  39. package/dist/lib/application.d.cts +1 -0
  40. package/dist/lib/authentication-security-initializer.cjs +351 -0
  41. package/dist/lib/authentication-security-initializer.d.cts +4 -0
  42. package/dist/lib/builtin-models.cjs +12 -0
  43. package/dist/lib/builtin-models.d.cts +3 -0
  44. package/dist/lib/configure-shared-methods.cjs +7 -4
  45. package/dist/lib/configure-shared-methods.d.cts +3 -0
  46. package/dist/lib/connectors/base-connector.d.cts +6 -0
  47. package/dist/lib/connectors/mail-direct-transport.cjs +26 -23
  48. package/dist/lib/connectors/mail-direct-transport.d.cts +22 -0
  49. package/dist/lib/connectors/mail-stub-transport.d.cts +14 -0
  50. package/dist/lib/connectors/mail.d.cts +7 -0
  51. package/dist/lib/connectors/memory.d.cts +6 -0
  52. package/dist/lib/current-context.d.cts +3 -0
  53. package/dist/lib/globalize.d.cts +10 -0
  54. package/dist/lib/loopback.cjs +6 -0
  55. package/dist/lib/loopback.d.cts +1 -0
  56. package/dist/lib/model.d.cts +1 -0
  57. package/dist/lib/persisted-model.cjs +7 -12
  58. package/dist/lib/persisted-model.d.cts +1 -0
  59. package/dist/lib/rate-limit/algorithms/common.cjs +37 -0
  60. package/dist/lib/rate-limit/algorithms/failure-lockout.cjs +70 -0
  61. package/dist/lib/rate-limit/algorithms/fixed-window.cjs +61 -0
  62. package/dist/lib/rate-limit/algorithms/index.cjs +55 -0
  63. package/dist/lib/rate-limit/config.cjs +107 -0
  64. package/dist/lib/rate-limit/errors.cjs +58 -0
  65. package/dist/lib/rate-limit/index.cjs +15 -0
  66. package/dist/lib/rate-limit/index.d.cts +1 -0
  67. package/dist/lib/rate-limit/initializer.cjs +92 -0
  68. package/dist/lib/rate-limit/initializer.d.cts +4 -0
  69. package/dist/lib/rate-limit/limiter.cjs +368 -0
  70. package/dist/lib/rate-limit/registry.cjs +92 -0
  71. package/dist/lib/rate-limit/remote.cjs +180 -0
  72. package/dist/lib/rate-limit/remote.d.cts +6 -0
  73. package/dist/lib/rate-limit/stores/persisted-model.cjs +353 -0
  74. package/dist/lib/rate-limit/subject.cjs +127 -0
  75. package/dist/lib/rate-limit/types.cjs +1 -0
  76. package/dist/lib/rate-limit/types.d.cts +167 -0
  77. package/dist/lib/registry.d.cts +1 -0
  78. package/dist/lib/runtime.d.cts +10 -0
  79. package/dist/lib/server-app.d.cts +3 -0
  80. package/dist/lib/two-factor/config.cjs +199 -0
  81. package/dist/lib/two-factor/config.d.cts +55 -0
  82. package/dist/lib/two-factor/crypto.cjs +68 -0
  83. package/dist/lib/two-factor/crypto.d.cts +16 -0
  84. package/dist/lib/two-factor/errors.cjs +58 -0
  85. package/dist/lib/two-factor/errors.d.cts +18 -0
  86. package/dist/lib/two-factor/rate-limit.cjs +153 -0
  87. package/dist/lib/two-factor/rate-limit.d.cts +22 -0
  88. package/dist/lib/two-factor/recovery-codes.cjs +49 -0
  89. package/dist/lib/two-factor/recovery-codes.d.cts +16 -0
  90. package/dist/lib/two-factor/service.cjs +1108 -0
  91. package/dist/lib/two-factor/service.d.cts +78 -0
  92. package/dist/lib/two-factor/totp.cjs +50 -0
  93. package/dist/lib/two-factor/totp.d.cts +14 -0
  94. package/dist/lib/utils.d.cts +36 -0
  95. package/dist/package.cjs +46 -10
  96. package/dist/server/middleware/context.d.cts +3 -0
  97. package/dist/server/middleware/error-handler.d.cts +3 -0
  98. package/dist/server/middleware/favicon.d.cts +7 -0
  99. package/dist/server/middleware/rest.d.cts +6 -0
  100. package/dist/server/middleware/static.d.cts +3 -0
  101. package/dist/server/middleware/status.d.cts +19 -0
  102. package/dist/server/middleware/token.d.cts +3 -0
  103. package/dist/server/middleware/url-not-found.d.cts +13 -0
  104. package/docs/api-explorer-details.md +110 -0
  105. package/docs/application-guide.md +1110 -0
  106. package/docs/assets/explorer-api.png +0 -0
  107. package/docs/assets/explorer-endpoint.png +0 -0
  108. package/docs/assets/explorer-listing.png +0 -0
  109. package/docs/assets/explorer-req-res.png +0 -0
  110. package/docs/assets/lb-modules.png +0 -0
  111. package/docs/assets/loopback-architecture.png +0 -0
  112. package/docs/assets/loopback-concepts.png +0 -0
  113. package/docs/assets/loopback_ov.png +0 -0
  114. package/docs/rate-limiting.md +879 -0
  115. package/docs/two-factor-authentication.md +611 -0
  116. package/docs/two-factor-authenticator-loss-runbook.md +117 -0
  117. package/package.json +56 -20
@@ -0,0 +1,351 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
3
+ const require_persisted_model = require("./rate-limit/stores/persisted-model.cjs");
4
+ const require_lib_two_factor_config = require("./two-factor/config.cjs");
5
+ const require_lib_two_factor_errors = require("./two-factor/errors.cjs");
6
+ const require_lib_two_factor_rate_limit = require("./two-factor/rate-limit.cjs");
7
+ const require_lib_two_factor_service = require("./two-factor/service.cjs");
8
+ //#region src/lib/authentication-security-initializer.ts
9
+ var authentication_security_initializer_exports = /* @__PURE__ */ require_runtime.__exportAll({ installAuthenticationSecurity: () => installAuthenticationSecurity });
10
+ function isUserModel(model, baseUser) {
11
+ return model === baseUser || model?.prototype && baseUser?.prototype && model.prototype instanceof baseUser;
12
+ }
13
+ function requirePrivateModel(app, name) {
14
+ const model = app.models[name];
15
+ if (!model || !model.dataSource) throw new Error(`Authentication security model ${name} is not connected`);
16
+ if ((model.config || {}).public === true) throw new Error(`Authentication security model ${name} must be private`);
17
+ return model;
18
+ }
19
+ function resultCount(result) {
20
+ return typeof result === "number" ? result : Number(result?.count || 0);
21
+ }
22
+ function requireUniquePrincipalProviderIndex(model) {
23
+ const index = (model.settings?.indexes || model.definition?.settings?.indexes || {}).two_factor_principal_provider_unique;
24
+ if (!index || index.options?.unique !== true || Number(index.keys?.principalType) !== 1 || Number(index.keys?.principalId) !== 1 || Number(index.keys?.provider) !== 1) throw new Error("TwoFactorCredential requires a unique principalType/principalId/provider index");
25
+ }
26
+ function installAuthenticationSecurity(app) {
27
+ let initialization = null;
28
+ app.authenticationSecurityReadiness = {
29
+ ready: false,
30
+ error: null
31
+ };
32
+ const twoFactorMethods = [
33
+ "verifyTwoFactor",
34
+ "beginTwoFactorEnrollment",
35
+ "confirmTwoFactorEnrollment",
36
+ "regenerateTwoFactorRecoveryCodes",
37
+ "disableTwoFactor"
38
+ ];
39
+ function disableUnconfiguredRemoteMethods() {
40
+ const BaseUser = app.registry.findModel("User");
41
+ if (!BaseUser) return;
42
+ for (const model of app.models().filter((candidate) => isUserModel(candidate, BaseUser))) if (model.settings.twoFactor == null) for (const method of twoFactorMethods) model.disableRemoteMethodByName(method);
43
+ }
44
+ app.on("modelRemoted", disableUnconfiguredRemoteMethods);
45
+ app.initializeAuthenticationSecurity = function(callback) {
46
+ if (!initialization) initialization = Promise.resolve().then(async () => {
47
+ const BaseUser = app.registry.findModel("User");
48
+ const userModels = BaseUser ? app.models().filter((model) => isUserModel(model, BaseUser)) : [];
49
+ disableUnconfiguredRemoteMethods();
50
+ const models = userModels.filter((model) => model.settings.twoFactor != null || model.settings.authenticationRateLimit?.enabled === true);
51
+ if (models.some((model) => model.settings.twoFactor != null)) {
52
+ requireUniquePrincipalProviderIndex(requirePrivateModel(app, "TwoFactorCredential"));
53
+ requirePrivateModel(app, "TwoFactorChallenge");
54
+ requirePrivateModel(app, "TwoFactorRecoveryCode");
55
+ }
56
+ const normalized = models.map((model) => ({
57
+ model,
58
+ twoFactor: require_lib_two_factor_config.normalizeTwoFactorConfig(model.settings.twoFactor),
59
+ rateLimit: require_lib_two_factor_config.normalizeAuthenticationRateLimitConfig(model.settings.authenticationRateLimit, model.modelName, app.get("rateLimit") || {})
60
+ }));
61
+ for (const item of normalized) {
62
+ if (item.twoFactor?.mode === "disabled") {
63
+ if (await app.models.TwoFactorCredential.count({
64
+ principalType: item.model.modelName,
65
+ status: "enabled"
66
+ }) !== 0) throw new Error(`Cannot disable two-factor authentication for ${item.model.modelName} with active credentials`);
67
+ }
68
+ if (!item.rateLimit) continue;
69
+ app.registerRateLimitSubjectKeyring(item.rateLimit.keyringName, item.model.settings.authenticationRateLimit.subjectHash);
70
+ if (item.rateLimit.usesApplicationStore) continue;
71
+ if (item.rateLimit.store.provider !== "persisted-model") throw new Error(`Rate limit provider ${item.rateLimit.store.provider} is not available`);
72
+ const stateModel = app.models[item.rateLimit.store.model || "RateLimitState"];
73
+ if (!stateModel || !stateModel.dataSource) throw new Error(`Rate limit state model ${item.rateLimit.store.model || "RateLimitState"} is not connected`);
74
+ const connectorName = stateModel.dataSource.connector?.name || stateModel.dataSource.settings?.connector;
75
+ const allowMemory = item.rateLimit.store.allowMemory === true;
76
+ if (connectorName === "memory" && !allowMemory) throw new Error("Memory rate limit store is allowed only when explicitly enabled");
77
+ app.registerRateLimitStore(item.rateLimit.storeName, new require_persisted_model.PersistedModelRateLimitStore({
78
+ model: stateModel,
79
+ allowMemory,
80
+ maxRetries: item.rateLimit.store.maxRetries
81
+ }));
82
+ }
83
+ await app.initializeRateLimiting();
84
+ for (const item of normalized) {
85
+ const limiter = item.rateLimit ? new require_lib_two_factor_rate_limit.AuthenticationRateLimiter(item.model.modelName, item.rateLimit, app.rateLimit.limiter) : null;
86
+ item.model._authenticationSecurity = new require_lib_two_factor_service.TwoFactorService(item.model, item.twoFactor, limiter, app);
87
+ item.model._authenticationSecurityReady = true;
88
+ }
89
+ app.authenticationSecurityReadiness.ready = true;
90
+ }).catch((error) => {
91
+ app.authenticationSecurityReadiness.error = error;
92
+ throw error;
93
+ });
94
+ if (typeof callback === "function") {
95
+ initialization.then(() => callback(null), callback);
96
+ return;
97
+ }
98
+ return initialization;
99
+ };
100
+ app.assertAuthenticationSecurityReady = function(UserModel) {
101
+ if ((UserModel.settings.twoFactor != null || UserModel.settings.authenticationRateLimit?.enabled === true) && !UserModel._authenticationSecurityReady) throw require_lib_two_factor_errors.authError("AUTHENTICATION_SECURITY_UNAVAILABLE", 503);
102
+ };
103
+ app.cleanupAuthenticationSecurity = function(options = {}, callback) {
104
+ const promise = Promise.resolve().then(async () => {
105
+ const now = options.now || /* @__PURE__ */ new Date();
106
+ const nowMs = now.getTime();
107
+ const terminalRetention = options.terminalRetentionMs ?? 6048e5;
108
+ const credentialRetention = options.disabledCredentialRetentionMs ?? 2592e6;
109
+ const consumingTimeout = options.consumingTimeoutMs ?? 6e5;
110
+ const Challenge = requirePrivateModel(app, "TwoFactorChallenge");
111
+ const Credential = requirePrivateModel(app, "TwoFactorCredential");
112
+ const RecoveryCode = requirePrivateModel(app, "TwoFactorRecoveryCode");
113
+ const result = {
114
+ expiredChallenges: 0,
115
+ recoveredVerifications: 0,
116
+ quarantinedConsumptions: 0,
117
+ reconciledTokens: 0,
118
+ releasedReservations: 0,
119
+ finalizedReservations: 0,
120
+ removedChallenges: 0,
121
+ expiredEnrollments: 0,
122
+ removedCredentials: 0,
123
+ removedRecoveryCodes: 0
124
+ };
125
+ const releaseReservations = async (ownerId) => {
126
+ const released = await RecoveryCode.updateAll({
127
+ status: "reserved",
128
+ reservationOwnerId: ownerId
129
+ }, {
130
+ status: "unused",
131
+ reservationId: null,
132
+ reservationExpiresAt: null,
133
+ reservationOwnerType: null,
134
+ reservationOwnerId: null
135
+ });
136
+ result.releasedReservations += resultCount(released);
137
+ };
138
+ const expiredChallenges = await Challenge.updateAll({
139
+ status: "pending",
140
+ expiresAt: { lte: now }
141
+ }, { status: "expired" });
142
+ result.expiredChallenges += resultCount(expiredChallenges);
143
+ const expiredLeases = await Challenge.find({ where: {
144
+ status: "verifying",
145
+ verificationLeaseExpiresAt: { lte: now }
146
+ } });
147
+ for (const challenge of expiredLeases) {
148
+ if (resultCount(await Challenge.updateAll({
149
+ id: challenge.id,
150
+ status: "verifying",
151
+ verificationLeaseId: challenge.verificationLeaseId
152
+ }, {
153
+ status: "reconciling_no_token",
154
+ verificationLeaseId: null,
155
+ verificationLeaseExpiresAt: null
156
+ })) !== 1) continue;
157
+ await releaseReservations(`challenge:${challenge.id}`);
158
+ await Challenge.updateAll({
159
+ id: challenge.id,
160
+ status: "reconciling_no_token"
161
+ }, { status: new Date(challenge.expiresAt).getTime() <= nowMs ? "expired" : "pending" });
162
+ result.recoveredVerifications++;
163
+ }
164
+ const stuckConsumptions = await Challenge.find({ where: {
165
+ status: "consuming",
166
+ claimedAt: { lte: new Date(nowMs - consumingTimeout) }
167
+ } });
168
+ for (const challenge of stuckConsumptions) {
169
+ const quarantined = await Challenge.updateAll({
170
+ id: challenge.id,
171
+ status: "consuming"
172
+ }, { status: "token_revocation_pending" });
173
+ result.quarantinedConsumptions += resultCount(quarantined);
174
+ }
175
+ const pendingRevocations = await Challenge.find({ where: {
176
+ status: "token_revocation_pending",
177
+ issuedTokenId: { neq: null }
178
+ } });
179
+ for (const challenge of pendingRevocations) {
180
+ const AccessToken = app.models[challenge.principalType]?.relations?.accessTokens?.modelTo;
181
+ if (!AccessToken || !challenge.issuedTokenId) continue;
182
+ try {
183
+ await AccessToken.destroyById(challenge.issuedTokenId);
184
+ if (await AccessToken.findById(challenge.issuedTokenId)) continue;
185
+ } catch {
186
+ continue;
187
+ }
188
+ if (resultCount(await Challenge.updateAll({
189
+ id: challenge.id,
190
+ status: "token_revocation_pending",
191
+ issuedTokenId: challenge.issuedTokenId
192
+ }, {
193
+ status: "token_failed",
194
+ issuedTokenId: null
195
+ })) !== 1) continue;
196
+ await releaseReservations(`challenge:${challenge.id}`);
197
+ result.reconciledTokens++;
198
+ }
199
+ const expiredReservations = await RecoveryCode.find({ where: {
200
+ status: "reserved",
201
+ reservationExpiresAt: { lte: now }
202
+ } });
203
+ for (const recoveryCode of expiredReservations) {
204
+ const ownerId = String(recoveryCode.reservationOwnerId || "");
205
+ if (!ownerId.startsWith("challenge:")) continue;
206
+ const challenge = await Challenge.findById(ownerId.slice(10));
207
+ if (!challenge) continue;
208
+ if (challenge.status === "consumed") {
209
+ const finalized = await RecoveryCode.updateAll({
210
+ id: recoveryCode.id,
211
+ status: "reserved",
212
+ reservationId: recoveryCode.reservationId,
213
+ reservationOwnerId: ownerId
214
+ }, {
215
+ status: "used",
216
+ usedAt: challenge.consumedAt || now,
217
+ reservationId: null,
218
+ reservationExpiresAt: null,
219
+ reservationOwnerType: null,
220
+ reservationOwnerId: null
221
+ });
222
+ result.finalizedReservations += resultCount(finalized);
223
+ } else if ([
224
+ "expired",
225
+ "locked",
226
+ "token_failed"
227
+ ].includes(challenge.status)) await releaseReservations(ownerId);
228
+ }
229
+ const expiredEnrollments = await Credential.updateAll({
230
+ status: "pending",
231
+ pendingExpiresAt: { lte: now }
232
+ }, {
233
+ status: "disabled",
234
+ encryptedSecret: null,
235
+ secretKeyId: null,
236
+ enrollmentTokenDigest: null,
237
+ disabledAt: now,
238
+ updatedAt: now
239
+ });
240
+ result.expiredEnrollments += resultCount(expiredEnrollments);
241
+ const credentials = await Credential.find({});
242
+ const retainedCredentialIds = new Set(credentials.map((credential) => String(credential.id)));
243
+ for (const credential of credentials) {
244
+ const UserModel = app.models[credential.principalType];
245
+ const principalExists = UserModel && await UserModel.findById(credential.principalId, { fields: { id: true } });
246
+ const disabledExpired = credential.status === "disabled" && credential.disabledAt && new Date(credential.disabledAt).getTime() <= nowMs - credentialRetention;
247
+ if (!principalExists || disabledExpired) {
248
+ const removedCodes = await RecoveryCode.destroyAll({ credentialId: String(credential.id) });
249
+ const removedChallenges = await Challenge.destroyAll({ credentialId: String(credential.id) });
250
+ const removedCredential = await Credential.destroyAll({ id: credential.id });
251
+ result.removedRecoveryCodes += resultCount(removedCodes);
252
+ result.removedChallenges += resultCount(removedChallenges);
253
+ result.removedCredentials += resultCount(removedCredential);
254
+ retainedCredentialIds.delete(String(credential.id));
255
+ continue;
256
+ }
257
+ if (credential.activeRecoveryCodeSetId) {
258
+ const removedCodes = await RecoveryCode.destroyAll({
259
+ credentialId: String(credential.id),
260
+ setId: { neq: credential.activeRecoveryCodeSetId },
261
+ status: { neq: "reserved" }
262
+ });
263
+ result.removedRecoveryCodes += resultCount(removedCodes);
264
+ } else {
265
+ const removedCodes = await RecoveryCode.destroyAll({
266
+ credentialId: String(credential.id),
267
+ status: { neq: "reserved" }
268
+ });
269
+ result.removedRecoveryCodes += resultCount(removedCodes);
270
+ }
271
+ }
272
+ const recoveryCredentialIds = new Set((await RecoveryCode.find({ fields: { credentialId: true } })).map((recoveryCode) => String(recoveryCode.credentialId)));
273
+ const orphanedCredentialIds = Array.from(recoveryCredentialIds).filter((credentialId) => !retainedCredentialIds.has(credentialId));
274
+ if (orphanedCredentialIds.length) {
275
+ const removedCodes = await RecoveryCode.destroyAll({
276
+ credentialId: { inq: orphanedCredentialIds },
277
+ status: { neq: "reserved" }
278
+ });
279
+ result.removedRecoveryCodes += resultCount(removedCodes);
280
+ }
281
+ const terminalChallenges = await Challenge.find({
282
+ where: {
283
+ status: { inq: [
284
+ "expired",
285
+ "consumed",
286
+ "locked",
287
+ "token_failed"
288
+ ] },
289
+ expiresAt: { lt: new Date(nowMs - terminalRetention) }
290
+ },
291
+ fields: { id: true }
292
+ });
293
+ for (const challenge of terminalChallenges) {
294
+ if (await RecoveryCode.count({
295
+ status: "reserved",
296
+ reservationOwnerId: `challenge:${challenge.id}`
297
+ }) !== 0) continue;
298
+ const removed = await Challenge.destroyAll({ id: challenge.id });
299
+ result.removedChallenges += resultCount(removed);
300
+ }
301
+ return result;
302
+ });
303
+ if (typeof callback === "function") {
304
+ promise.then((result) => callback(null, result), callback);
305
+ return;
306
+ }
307
+ return promise;
308
+ };
309
+ app.rotateAuthenticationSecurityEncryption = function(options = {}, callback) {
310
+ const promise = Promise.resolve().then(async () => {
311
+ if (!app.authenticationSecurityReadiness.ready) throw require_lib_two_factor_errors.authError("AUTHENTICATION_SECURITY_UNAVAILABLE", 503);
312
+ const BaseUser = app.registry.findModel("User");
313
+ const models = BaseUser ? app.models().filter((model) => isUserModel(model, BaseUser) && model.settings.twoFactor != null && model._authenticationSecurity) : [];
314
+ const perModel = {};
315
+ for (const model of models) perModel[model.modelName] = await model._authenticationSecurity.rotateEncryption(options);
316
+ return perModel;
317
+ });
318
+ if (typeof callback === "function") {
319
+ promise.then((result) => callback(null, result), callback);
320
+ return;
321
+ }
322
+ return promise;
323
+ };
324
+ app.once("booted", function() {
325
+ app.initializeAuthenticationSecurity().catch((error) => {
326
+ app.emit("authenticationSecurityError", error);
327
+ });
328
+ });
329
+ }
330
+ var init_authentication_security_initializer = require_runtime.__esmMin((() => {
331
+ require_persisted_model.init_persisted_model();
332
+ require_lib_two_factor_config.init_config();
333
+ require_lib_two_factor_rate_limit.init_rate_limit();
334
+ require_lib_two_factor_service.init_service();
335
+ require_lib_two_factor_errors.init_errors();
336
+ }));
337
+ //#endregion
338
+ init_authentication_security_initializer();
339
+ Object.defineProperty(exports, "authentication_security_initializer_exports", {
340
+ enumerable: true,
341
+ get: function() {
342
+ return authentication_security_initializer_exports;
343
+ }
344
+ });
345
+ Object.defineProperty(exports, "init_authentication_security_initializer", {
346
+ enumerable: true,
347
+ get: function() {
348
+ return init_authentication_security_initializer;
349
+ }
350
+ });
351
+ exports.installAuthenticationSecurity = installAuthenticationSecurity;
@@ -0,0 +1,4 @@
1
+ //#region src/lib/authentication-security-initializer.d.ts
2
+ declare function installAuthenticationSecurity(app: any): void;
3
+ //#endregion
4
+ export { installAuthenticationSecurity };
@@ -10,6 +10,14 @@ const require_access_token$2 = require("../common/models/access-token2.cjs");
10
10
  const require_common_models_access_token = require("../common/models/access-token.cjs");
11
11
  const require_user$2 = require("../common/models/user2.cjs");
12
12
  const require_common_models_user = require("../common/models/user.cjs");
13
+ const require_rate_limit_state$2 = require("../common/models/rate-limit-state2.cjs");
14
+ const require_common_models_rate_limit_state = require("../common/models/rate-limit-state.cjs");
15
+ const require_two_factor_credential$2 = require("../common/models/two-factor-credential2.cjs");
16
+ const require_common_models_two_factor_credential = require("../common/models/two-factor-credential.cjs");
17
+ const require_two_factor_challenge$2 = require("../common/models/two-factor-challenge2.cjs");
18
+ const require_common_models_two_factor_challenge = require("../common/models/two-factor-challenge.cjs");
19
+ const require_two_factor_recovery_code$2 = require("../common/models/two-factor-recovery-code2.cjs");
20
+ const require_common_models_two_factor_recovery_code = require("../common/models/two-factor-recovery-code.cjs");
13
21
  const require_role_mapping$2 = require("../common/models/role-mapping2.cjs");
14
22
  const require_common_models_role_mapping = require("../common/models/role-mapping.cjs");
15
23
  const require_role$2 = require("../common/models/role2.cjs");
@@ -31,6 +39,10 @@ var require_builtin_models = /* @__PURE__ */ require_runtime.__commonJSMin(((exp
31
39
  registry.Application = createModel(registry, require_application$2.default, require_common_models_application);
32
40
  registry.AccessToken = createModel(registry, require_access_token$2.default, require_common_models_access_token);
33
41
  registry.User = createModel(registry, require_user$2.default, require_common_models_user);
42
+ registry.RateLimitState = createModel(registry, require_rate_limit_state$2.default, require_common_models_rate_limit_state);
43
+ registry.TwoFactorCredential = createModel(registry, require_two_factor_credential$2.default, require_common_models_two_factor_credential);
44
+ registry.TwoFactorChallenge = createModel(registry, require_two_factor_challenge$2.default, require_common_models_two_factor_challenge);
45
+ registry.TwoFactorRecoveryCode = createModel(registry, require_two_factor_recovery_code$2.default, require_common_models_two_factor_recovery_code);
34
46
  registry.RoleMapping = createModel(registry, require_role_mapping$2.default, require_common_models_role_mapping);
35
47
  registry.Role = createModel(registry, require_role$2.default, require_common_models_role);
36
48
  registry.ACL = createModel(registry, require_acl$2.default, require_common_models_acl);
@@ -0,0 +1,3 @@
1
+ //#region src/lib/builtin-models.d.ts
2
+ declare function defineBuiltinModels(registry: any): void;
3
+ export = defineBuiltinModels;
@@ -24,11 +24,14 @@ var require_configure_shared_methods = /* @__PURE__ */ require_runtime.__commonJ
24
24
  }) || [];
25
25
  sharedMethods.forEach(function(sharedMethod) {
26
26
  const methodName = sharedMethod.isStatic ? sharedMethod.name : "prototype." + sharedMethod.name;
27
- if (Object.prototype.hasOwnProperty.call(settings, methodName)) if (settings[methodName] === false) sharedMethod.sharedClass.disableMethodByName(methodName);
28
- else sharedMethod.shared = true;
29
- else tests.forEach(function(glob) {
30
- if (glob.regex.test(methodName)) if (glob.setting === false) sharedMethod.sharedClass.disableMethodByName(methodName);
27
+ if (Object.prototype.hasOwnProperty.call(settings, methodName)) {
28
+ if (settings[methodName] === false) sharedMethod.sharedClass.disableMethodByName(methodName);
31
29
  else sharedMethod.shared = true;
30
+ } else tests.forEach(function(glob) {
31
+ if (glob.regex.test(methodName)) {
32
+ if (glob.setting === false) sharedMethod.sharedClass.disableMethodByName(methodName);
33
+ else sharedMethod.shared = true;
34
+ }
32
35
  });
33
36
  });
34
37
  }
@@ -0,0 +1,3 @@
1
+ //#region src/lib/configure-shared-methods.d.ts
2
+ declare function configureSharedMethods(modelCtor: any, remotingConfig: any, modelConfig: any): void;
3
+ export = configureSharedMethods;
@@ -0,0 +1,6 @@
1
+ //#region src/lib/connectors/base-connector.d.ts
2
+ declare function Connector(options: any): void;
3
+ declare namespace Connector {
4
+ var _createJDBAdapter: (jdbModule: any) => void;
5
+ }
6
+ export = Connector;
@@ -160,11 +160,13 @@ var require_mail_direct_transport = /* @__PURE__ */ require("../../_virtual/_rol
160
160
  combinedInfo.pending = combinedInfo.pending.concat(info.pending || []);
161
161
  combinedInfo.messageId = info.messageId;
162
162
  }
163
- if (returned >= domains.length) if (combinedInfo.errors.length === domains.length) {
164
- const sendError = /* @__PURE__ */ new Error("Sending failed");
165
- sendError.errors = combinedInfo.errors;
166
- callback(sendError);
167
- } else callback(null, combinedInfo);
163
+ if (returned >= domains.length) {
164
+ if (combinedInfo.errors.length === domains.length) {
165
+ const sendError = /* @__PURE__ */ new Error("Sending failed");
166
+ sendError.errors = combinedInfo.errors;
167
+ callback(sendError);
168
+ } else callback(null, combinedInfo);
169
+ }
168
170
  }
169
171
  };
170
172
  this._queue.insert(item);
@@ -191,29 +193,30 @@ var require_mail_direct_transport = /* @__PURE__ */ require("../../_virtual/_rol
191
193
  return item.exchange;
192
194
  });
193
195
  this._process([].concat(exchanges), data, (processErr, response) => {
194
- if (processErr) if (processErr.responseCode && processErr.responseCode >= 500) {
195
- processErr.domain = data.domain;
196
- processErr.exchange = exchanges[0];
197
- processErr.recipients = data.envelope.to;
198
- data.callback(processErr);
199
- } else {
200
- data.replies = (data.replies || 0) + 1;
201
- if (data.replies <= 5) {
202
- this._queue.insert(data, this.options.retryDelay || data.replies * 15 * 60 * 1e3);
203
- data.callback(null, { pending: {
204
- domain: data.domain,
205
- exchange: exchanges[0],
206
- recipients: data.envelope.to,
207
- response: processErr.response
208
- } });
209
- } else {
196
+ if (processErr) {
197
+ if (processErr.responseCode && processErr.responseCode >= 500) {
210
198
  processErr.domain = data.domain;
211
199
  processErr.exchange = exchanges[0];
212
200
  processErr.recipients = data.envelope.to;
213
201
  data.callback(processErr);
202
+ } else {
203
+ data.replies = (data.replies || 0) + 1;
204
+ if (data.replies <= 5) {
205
+ this._queue.insert(data, this.options.retryDelay || data.replies * 15 * 60 * 1e3);
206
+ data.callback(null, { pending: {
207
+ domain: data.domain,
208
+ exchange: exchanges[0],
209
+ recipients: data.envelope.to,
210
+ response: processErr.response
211
+ } });
212
+ } else {
213
+ processErr.domain = data.domain;
214
+ processErr.exchange = exchanges[0];
215
+ processErr.recipients = data.envelope.to;
216
+ data.callback(processErr);
217
+ }
214
218
  }
215
- }
216
- else data.callback(null, response);
219
+ } else data.callback(null, response);
217
220
  setImmediate(this._loop.bind(this));
218
221
  });
219
222
  });
@@ -0,0 +1,22 @@
1
+ //#region src/lib/connectors/mail-direct-transport.d.ts
2
+ declare const EventEmitter: any;
3
+ declare function createDirectTransport(options: any): DirectTransport;
4
+ declare class DirectTransport extends EventEmitter {
5
+ options: any;
6
+ _queue: any;
7
+ _started: any;
8
+ _lastId: any;
9
+ name: any;
10
+ version: any;
11
+ constructor(options: any);
12
+ get length(): any;
13
+ getSocket(options: any, callback: any): void;
14
+ send(mail: any, callback: any): void;
15
+ _loop(): void;
16
+ _process(exchanges: any, data: any, callback: any): void;
17
+ _formatMessage(message: any): void;
18
+ _clearStreams(mail: any, callback: any): void;
19
+ _resolveMx(domain: any, callback: any): void;
20
+ _resolveHostname(name: any): any;
21
+ }
22
+ export = createDirectTransport;
@@ -0,0 +1,14 @@
1
+ //#region src/lib/connectors/mail-stub-transport.d.ts
2
+ declare const EventEmitter: any;
3
+ declare function createStubTransport(options: any): StubTransport;
4
+ declare class StubTransport extends EventEmitter {
5
+ options: any;
6
+ name: any;
7
+ version: any;
8
+ constructor(options: any);
9
+ isIdle(): boolean;
10
+ verify(callback: any): void;
11
+ send(mail: any, callback: any): void;
12
+ _log(level: any, type: any, ...args: any[]): void;
13
+ }
14
+ export = createStubTransport;
@@ -0,0 +1,7 @@
1
+ //#region src/lib/connectors/mail.d.ts
2
+ declare function MailConnector(settings: any): void;
3
+ declare namespace MailConnector {
4
+ var initialize: (dataSource: any, callback: any) => void;
5
+ var mailer: any;
6
+ }
7
+ export = MailConnector;
@@ -0,0 +1,6 @@
1
+ //#region src/lib/connectors/memory.d.ts
2
+ declare function Memory(): void;
3
+ declare namespace Memory {
4
+ var initialize: any;
5
+ }
6
+ export = Memory;
@@ -0,0 +1,3 @@
1
+ //#region src/lib/current-context.d.ts
2
+ declare function currentContext(loopback: any): void;
3
+ export = currentContext;
@@ -0,0 +1,10 @@
1
+ //#region src/lib/globalize.d.ts
2
+ declare function f(message: any): any;
3
+ declare function log(message: any): void;
4
+ declare function warn(message: any): void;
5
+ declare const globalize: {
6
+ f: typeof f;
7
+ log: typeof log;
8
+ warn: typeof warn;
9
+ };
10
+ export = globalize;
@@ -5,6 +5,8 @@ const require_lib_runtime = require("./runtime.cjs");
5
5
  const require_lib_registry = require("./registry.cjs");
6
6
  const require_lib_application = require("./application.cjs");
7
7
  const require_lib_configure_shared_methods = require("./configure-shared-methods.cjs");
8
+ const require_lib_rate_limit_initializer = require("./rate-limit/initializer.cjs");
9
+ const require_lib_authentication_security_initializer = require("./authentication-security-initializer.cjs");
8
10
  const require_package$1 = require("../package.cjs");
9
11
  const require_lib_builtin_models = require("./builtin-models.cjs");
10
12
  const require_lib_current_context = require("./current-context.cjs");
@@ -24,6 +26,8 @@ var require_loopback = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports
24
26
  const Registry = require_lib_registry;
25
27
  const juggler = require("@vsaas/loopback-datasource-juggler");
26
28
  const configureSharedMethods = require_lib_configure_shared_methods;
29
+ const installRateLimiting = (require_lib_rate_limit_initializer.init_initializer(), require_runtime$1.__toCommonJS(require_lib_rate_limit_initializer.initializer_exports)).installRateLimiting;
30
+ const installAuthenticationSecurity = (require_lib_authentication_security_initializer.init_authentication_security_initializer(), require_runtime$1.__toCommonJS(require_lib_authentication_security_initializer.authentication_security_initializer_exports)).installAuthenticationSecurity;
27
31
  /**
28
32
  * LoopBack core module. It provides static properties and
29
33
  * methods to create models and data sources. The module itself is a function
@@ -73,6 +77,8 @@ var require_loopback = /* @__PURE__ */ require_runtime$1.__commonJSMin(((exports
73
77
  function createApplication(options) {
74
78
  const app = loopbackExpress();
75
79
  Object.assign(app, proto);
80
+ installRateLimiting(app);
81
+ installAuthenticationSecurity(app);
76
82
  app.loopback = loopback;
77
83
  app.on("modelRemoted", function() {
78
84
  app.models().forEach(function(Model) {
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1 @@
1
+ export {}
@@ -1389,9 +1389,7 @@ var require_persisted_model = /* @__PURE__ */ require_runtime$1.__commonJSMin(((
1389
1389
  });
1390
1390
  });
1391
1391
  break;
1392
- case Change.DELETE:
1393
- updates.push(update);
1394
- break;
1392
+ case Change.DELETE: updates.push(update);
1395
1393
  }
1396
1394
  });
1397
1395
  Promise.all(tasks.map(function(task) {
@@ -1434,11 +1432,9 @@ var require_persisted_model = /* @__PURE__ */ require_runtime$1.__commonJSMin(((
1434
1432
  applyCreate(Model, id, current, update.data, update.change, conflicts, options, cb);
1435
1433
  });
1436
1434
  break;
1437
- case Change.DELETE:
1438
- tasks.push(function(cb) {
1439
- applyDelete(Model, id, current, update.change, conflicts, options, cb);
1440
- });
1441
- break;
1435
+ case Change.DELETE: tasks.push(function(cb) {
1436
+ applyDelete(Model, id, current, update.change, conflicts, options, cb);
1437
+ });
1442
1438
  }
1443
1439
  });
1444
1440
  Promise.all(tasks.map(function(task) {
@@ -1554,7 +1550,8 @@ var require_persisted_model = /* @__PURE__ */ require_runtime$1.__commonJSMin(((
1554
1550
  */
1555
1551
  PersistedModel.getChangeModel = function() {
1556
1552
  const changeModel = this.Change;
1557
- assert(changeModel && changeModel.dataSource, "Cannot get a setup Change model for " + this.modelName);
1553
+ const isSetup = changeModel && changeModel.dataSource;
1554
+ assert(isSetup, "Cannot get a setup Change model for " + this.modelName);
1558
1555
  return changeModel;
1559
1556
  };
1560
1557
  /**
@@ -1750,9 +1747,7 @@ var require_persisted_model = /* @__PURE__ */ require_runtime$1.__commonJSMin(((
1750
1747
  if (ctx.isNewInstance === void 0) change.type = hasTarget ? "update" : "create";
1751
1748
  else change.type = ctx.isNewInstance ? "create" : "update";
1752
1749
  break;
1753
- case "delete":
1754
- change.type = "remove";
1755
- break;
1750
+ case "delete": change.type = "remove";
1756
1751
  }
1757
1752
  return change;
1758
1753
  }
@@ -0,0 +1 @@
1
+ export {}