@fonderie/auth 7.3.4 → 7.3.5
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/dist/index.cjs +216 -214
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +40 -38
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -235,7 +235,7 @@ function cookieHeaders(cookies) {
|
|
|
235
235
|
|
|
236
236
|
// src/controllers/mfa.controller.ts
|
|
237
237
|
import QRCode from "qrcode";
|
|
238
|
-
import { setApiResponse as setApiResponse2, HTTP as HTTP2, background } from "@fonderie/core";
|
|
238
|
+
import { setApiResponse as setApiResponse2, HTTP as HTTP2, background as background2 } from "@fonderie/core";
|
|
239
239
|
import { NOTIFICATION_EVENT } from "@fonderie/events";
|
|
240
240
|
|
|
241
241
|
// src/config.ts
|
|
@@ -836,6 +836,7 @@ var BackupCodeModel = class {
|
|
|
836
836
|
};
|
|
837
837
|
|
|
838
838
|
// src/models/login-event.model.ts
|
|
839
|
+
import { background } from "@fonderie/core";
|
|
839
840
|
var LoginEventModel = class {
|
|
840
841
|
constructor(store) {
|
|
841
842
|
this.store = store;
|
|
@@ -857,12 +858,13 @@ var LoginEventModel = class {
|
|
|
857
858
|
]
|
|
858
859
|
);
|
|
859
860
|
}
|
|
860
|
-
//
|
|
861
|
-
//
|
|
862
|
-
//
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
861
|
+
// Never throws — recording history must not fail a login. It IS awaited,
|
|
862
|
+
// though: this is a security audit trail (who signed in, from where), and a
|
|
863
|
+
// detached write is abandoned when a serverless instance freezes after the
|
|
864
|
+
// response, losing the row entirely. background() decides whether waiting is
|
|
865
|
+
// actually necessary for the current runtime.
|
|
866
|
+
async recordSafe(e) {
|
|
867
|
+
await background(this.record(e));
|
|
866
868
|
}
|
|
867
869
|
// One page of a user's own login history, newest first. Keyset-paginated on
|
|
868
870
|
// (created_at, id) — mirrors audit's event list so the two log UIs share a
|
|
@@ -952,7 +954,7 @@ function mfaController(store, config, issuer, bus) {
|
|
|
952
954
|
const token = body?.["token"];
|
|
953
955
|
const isLoginCompletion = ctx.user.mfaPending === true;
|
|
954
956
|
const meta = requestMeta(ctx);
|
|
955
|
-
const failedMfa = () => loginEvents.recordSafe({
|
|
957
|
+
const failedMfa = async () => await loginEvents.recordSafe({
|
|
956
958
|
userId: ctx.user.id,
|
|
957
959
|
emailAttempted: ctx.user.email,
|
|
958
960
|
method: "mfa",
|
|
@@ -970,7 +972,7 @@ function mfaController(store, config, issuer, bus) {
|
|
|
970
972
|
return setApiResponse2(HTTP2.UNAUTHORIZED, "INVALID_CODE", "Invalid MFA token");
|
|
971
973
|
}
|
|
972
974
|
await users.confirmMfaSecret(ctx.user.id);
|
|
973
|
-
await
|
|
975
|
+
await background2(bus?.emit(NOTIFICATION_EVENT, {
|
|
974
976
|
type: MESSAGE_KEYS.mfaEnabled,
|
|
975
977
|
locale: ctx.user.locale,
|
|
976
978
|
data: {},
|
|
@@ -999,7 +1001,7 @@ function mfaController(store, config, issuer, bus) {
|
|
|
999
1001
|
);
|
|
1000
1002
|
const matched = checks.find((r) => r.match);
|
|
1001
1003
|
if (!matched) {
|
|
1002
|
-
if (isLoginCompletion) failedMfa();
|
|
1004
|
+
if (isLoginCompletion) await failedMfa();
|
|
1003
1005
|
return setApiResponse2(HTTP2.UNAUTHORIZED, "INVALID_CODE", "Invalid backup code");
|
|
1004
1006
|
}
|
|
1005
1007
|
await backupCodes.consume(matched.id);
|
|
@@ -1017,7 +1019,7 @@ function mfaController(store, config, issuer, bus) {
|
|
|
1017
1019
|
}
|
|
1018
1020
|
const secret = mfaCipher.decrypt(storedSecret);
|
|
1019
1021
|
if (!verifyTotpToken(token, secret)) {
|
|
1020
|
-
if (isLoginCompletion) failedMfa();
|
|
1022
|
+
if (isLoginCompletion) await failedMfa();
|
|
1021
1023
|
return setApiResponse2(HTTP2.UNAUTHORIZED, "INVALID_CODE", "Invalid MFA token");
|
|
1022
1024
|
}
|
|
1023
1025
|
if (!ctx.user.mfaEnabled) {
|
|
@@ -1030,7 +1032,7 @@ function mfaController(store, config, issuer, bus) {
|
|
|
1030
1032
|
});
|
|
1031
1033
|
await sessions.create(ctx.user.id, refreshToken, refreshTokenExpiry(refreshToken), sid, meta);
|
|
1032
1034
|
if (isLoginCompletion) {
|
|
1033
|
-
loginEvents.recordSafe({
|
|
1035
|
+
await loginEvents.recordSafe({
|
|
1034
1036
|
userId: ctx.user.id,
|
|
1035
1037
|
emailAttempted: ctx.user.email,
|
|
1036
1038
|
method: "mfa",
|
|
@@ -1075,7 +1077,7 @@ function mfaController(store, config, issuer, bus) {
|
|
|
1075
1077
|
const plainCodes = generateBackupCodes();
|
|
1076
1078
|
const codeHashes = await Promise.all(plainCodes.map((c) => hashPassword(c)));
|
|
1077
1079
|
await backupCodes.replace(ctx.user.id, codeHashes);
|
|
1078
|
-
await
|
|
1080
|
+
await background2(bus?.emit(NOTIFICATION_EVENT, {
|
|
1079
1081
|
type: MESSAGE_KEYS.mfaBackupCodesRegenerated,
|
|
1080
1082
|
locale: ctx.user.locale,
|
|
1081
1083
|
data: {},
|
|
@@ -1102,7 +1104,7 @@ function mfaController(store, config, issuer, bus) {
|
|
|
1102
1104
|
return setApiResponse2(HTTP2.UNAUTHORIZED, "INVALID_CODE", "Invalid TOTP code");
|
|
1103
1105
|
}
|
|
1104
1106
|
await Promise.all([users.disableMfa(ctx.user.id), backupCodes.deleteByUser(ctx.user.id)]);
|
|
1105
|
-
await
|
|
1107
|
+
await background2(bus?.emit(NOTIFICATION_EVENT, {
|
|
1106
1108
|
type: MESSAGE_KEYS.mfaDisabled,
|
|
1107
1109
|
locale: user.locale,
|
|
1108
1110
|
data: {},
|
|
@@ -1116,7 +1118,7 @@ function mfaController(store, config, issuer, bus) {
|
|
|
1116
1118
|
// src/controllers/auth.controller.ts
|
|
1117
1119
|
import { randomBytes as randomBytes3, randomInt } from "crypto";
|
|
1118
1120
|
import { NOTIFICATION_EVENT as NOTIFICATION_EVENT2 } from "@fonderie/events";
|
|
1119
|
-
import { setApiResponse as setApiResponse3, HTTP as HTTP3, background as
|
|
1121
|
+
import { setApiResponse as setApiResponse3, HTTP as HTTP3, background as background3 } from "@fonderie/core";
|
|
1120
1122
|
|
|
1121
1123
|
// src/services/cooldown.ts
|
|
1122
1124
|
function checkCooldown(lastSentAt, cooldownMs) {
|
|
@@ -1363,7 +1365,7 @@ function authController(store, config, bus) {
|
|
|
1363
1365
|
}
|
|
1364
1366
|
const reqId = ctx.meta["requestId"];
|
|
1365
1367
|
const reqOpts = reqId !== void 0 ? { requestId: reqId } : void 0;
|
|
1366
|
-
await
|
|
1368
|
+
await background3(bus?.emit(
|
|
1367
1369
|
NOTIFICATION_EVENT2,
|
|
1368
1370
|
{
|
|
1369
1371
|
type: MESSAGE_KEYS.emailRegistration,
|
|
@@ -1373,7 +1375,7 @@ function authController(store, config, bus) {
|
|
|
1373
1375
|
},
|
|
1374
1376
|
reqOpts
|
|
1375
1377
|
));
|
|
1376
|
-
await
|
|
1378
|
+
await background3(bus?.emit(
|
|
1377
1379
|
EVENT_KEYS.userRegistered,
|
|
1378
1380
|
{
|
|
1379
1381
|
userId: user.id,
|
|
@@ -1425,7 +1427,7 @@ function authController(store, config, bus) {
|
|
|
1425
1427
|
}
|
|
1426
1428
|
const reqId2 = ctx.meta["requestId"];
|
|
1427
1429
|
const reqOpts2 = reqId2 !== void 0 ? { requestId: reqId2 } : void 0;
|
|
1428
|
-
await
|
|
1430
|
+
await background3(bus?.emit(
|
|
1429
1431
|
NOTIFICATION_EVENT2,
|
|
1430
1432
|
{
|
|
1431
1433
|
type: MESSAGE_KEYS.phoneOtp,
|
|
@@ -1435,7 +1437,7 @@ function authController(store, config, bus) {
|
|
|
1435
1437
|
},
|
|
1436
1438
|
reqOpts2
|
|
1437
1439
|
));
|
|
1438
|
-
await
|
|
1440
|
+
await background3(bus?.emit(
|
|
1439
1441
|
EVENT_KEYS.userRegistered,
|
|
1440
1442
|
{
|
|
1441
1443
|
userId: user.id,
|
|
@@ -1476,7 +1478,7 @@ function authController(store, config, bus) {
|
|
|
1476
1478
|
}
|
|
1477
1479
|
const user = await users.findByEmail(email2);
|
|
1478
1480
|
if (!user || !user.passwordHash) {
|
|
1479
|
-
loginEvents.recordSafe({
|
|
1481
|
+
await loginEvents.recordSafe({
|
|
1480
1482
|
userId: null,
|
|
1481
1483
|
emailAttempted: email2,
|
|
1482
1484
|
method: "password",
|
|
@@ -1492,7 +1494,7 @@ function authController(store, config, bus) {
|
|
|
1492
1494
|
config.legacyVerify
|
|
1493
1495
|
);
|
|
1494
1496
|
if (!valid) {
|
|
1495
|
-
loginEvents.recordSafe({
|
|
1497
|
+
await loginEvents.recordSafe({
|
|
1496
1498
|
userId: user.id,
|
|
1497
1499
|
emailAttempted: email2,
|
|
1498
1500
|
method: "password",
|
|
@@ -1522,7 +1524,7 @@ function authController(store, config, bus) {
|
|
|
1522
1524
|
loginMethod: "email"
|
|
1523
1525
|
});
|
|
1524
1526
|
await sessions.create(user.id, refreshToken, refreshTokenExpiry(refreshToken), sid, meta);
|
|
1525
|
-
loginEvents.recordSafe({
|
|
1527
|
+
await loginEvents.recordSafe({
|
|
1526
1528
|
userId: user.id,
|
|
1527
1529
|
emailAttempted: email2,
|
|
1528
1530
|
method: "password",
|
|
@@ -1563,7 +1565,7 @@ function authController(store, config, bus) {
|
|
|
1563
1565
|
const otp = randomInt(1e5, 1e6).toString();
|
|
1564
1566
|
const expiresAt = new Date(Date.now() + OTP_TTL_MS);
|
|
1565
1567
|
await phoneVerif.upsert(user.id, normalizePhone(phone2), otp, expiresAt);
|
|
1566
|
-
await
|
|
1568
|
+
await background3(bus?.emit(NOTIFICATION_EVENT2, {
|
|
1567
1569
|
type: MESSAGE_KEYS.phoneOtp,
|
|
1568
1570
|
locale: user.locale,
|
|
1569
1571
|
data: { otp },
|
|
@@ -1675,7 +1677,7 @@ function authController(store, config, bus) {
|
|
|
1675
1677
|
await passwordReset.create(user.id, pin, token, expiresAt);
|
|
1676
1678
|
const base = resolved.passwordResetUrl;
|
|
1677
1679
|
const resetUrl = base ? `${base}${base.includes("?") ? "&" : "?"}token=${token}` : "";
|
|
1678
|
-
await
|
|
1680
|
+
await background3(bus?.emit(NOTIFICATION_EVENT2, {
|
|
1679
1681
|
type: MESSAGE_KEYS.passwordReset,
|
|
1680
1682
|
locale: user.locale,
|
|
1681
1683
|
recipient: { email: email2, phone: null, deviceToken: null },
|
|
@@ -1855,7 +1857,7 @@ function authController(store, config, bus) {
|
|
|
1855
1857
|
const otp = randomInt(1e5, 1e6).toString();
|
|
1856
1858
|
const expiresAt2 = new Date(Date.now() + OTP_TTL_MS);
|
|
1857
1859
|
await phoneVerif.upsert(ctx.user.id, phone2, otp, expiresAt2);
|
|
1858
|
-
await
|
|
1860
|
+
await background3(bus?.emit(NOTIFICATION_EVENT2, {
|
|
1859
1861
|
type: MESSAGE_KEYS.phoneOtp,
|
|
1860
1862
|
locale: ctx.user.locale,
|
|
1861
1863
|
data: { otp },
|
|
@@ -1894,7 +1896,7 @@ function authController(store, config, bus) {
|
|
|
1894
1896
|
const pin = randomInt(1e5, 1e6).toString();
|
|
1895
1897
|
const expiresAt = new Date(Date.now() + 1e3 * 60 * 60 * 24);
|
|
1896
1898
|
await emailVerif.replace(ctx.user.id, pin, expiresAt);
|
|
1897
|
-
await
|
|
1899
|
+
await background3(bus?.emit(NOTIFICATION_EVENT2, {
|
|
1898
1900
|
type: MESSAGE_KEYS.emailVerification,
|
|
1899
1901
|
locale: ctx.user.locale,
|
|
1900
1902
|
recipient: { email: ctx.user.email, phone: null, deviceToken: null },
|
|
@@ -1909,7 +1911,7 @@ function authController(store, config, bus) {
|
|
|
1909
1911
|
|
|
1910
1912
|
// src/controllers/user.controller.ts
|
|
1911
1913
|
import { randomInt as randomInt2 } from "crypto";
|
|
1912
|
-
import { setApiResponse as setApiResponse4, HTTP as HTTP4, dateOrEmpty as dateOrEmpty2, background as
|
|
1914
|
+
import { setApiResponse as setApiResponse4, HTTP as HTTP4, dateOrEmpty as dateOrEmpty2, background as background4 } from "@fonderie/core";
|
|
1913
1915
|
import { NOTIFICATION_EVENT as NOTIFICATION_EVENT3 } from "@fonderie/events";
|
|
1914
1916
|
|
|
1915
1917
|
// src/dtos/login-activity.ts
|
|
@@ -2102,14 +2104,14 @@ function userController(store, config, bus) {
|
|
|
2102
2104
|
const expiresAt = new Date(Date.now() + 1e3 * 60 * 60 * 24);
|
|
2103
2105
|
await emailVerif.replace(ctx.user.id, pin, expiresAt);
|
|
2104
2106
|
await users.updateEmail(ctx.user.id, normalised);
|
|
2105
|
-
await
|
|
2107
|
+
await background4(bus?.emit(NOTIFICATION_EVENT3, {
|
|
2106
2108
|
type: MESSAGE_KEYS.emailVerification,
|
|
2107
2109
|
locale: ctx.user.locale,
|
|
2108
2110
|
data: { pin },
|
|
2109
2111
|
recipient: { email: normalised, phone: null, deviceToken: null }
|
|
2110
2112
|
}));
|
|
2111
2113
|
if (oldEmail) {
|
|
2112
|
-
await
|
|
2114
|
+
await background4(bus?.emit(NOTIFICATION_EVENT3, {
|
|
2113
2115
|
type: MESSAGE_KEYS.emailChanged,
|
|
2114
2116
|
locale: ctx.user.locale,
|
|
2115
2117
|
data: { newEmail: normalised },
|
|
@@ -2144,14 +2146,14 @@ function userController(store, config, bus) {
|
|
|
2144
2146
|
const expiresAt = new Date(Date.now() + 10 * 60 * 1e3);
|
|
2145
2147
|
await phoneVerif.upsert(ctx.user.id, normalised, otp, expiresAt);
|
|
2146
2148
|
await users.updatePhone(ctx.user.id, normalised);
|
|
2147
|
-
await
|
|
2149
|
+
await background4(bus?.emit(NOTIFICATION_EVENT3, {
|
|
2148
2150
|
type: MESSAGE_KEYS.phoneOtp,
|
|
2149
2151
|
locale: ctx.user.locale,
|
|
2150
2152
|
data: { otp },
|
|
2151
2153
|
recipient: { email: null, phone: normalised, deviceToken: null }
|
|
2152
2154
|
}));
|
|
2153
2155
|
if (ctx.user.email) {
|
|
2154
|
-
await
|
|
2156
|
+
await background4(bus?.emit(NOTIFICATION_EVENT3, {
|
|
2155
2157
|
type: MESSAGE_KEYS.phoneChanged,
|
|
2156
2158
|
locale: ctx.user.locale,
|
|
2157
2159
|
data: {},
|
|
@@ -2193,7 +2195,7 @@ function userController(store, config, bus) {
|
|
|
2193
2195
|
const userId = ctx.user.id;
|
|
2194
2196
|
await users.softDelete(userId);
|
|
2195
2197
|
const reqId = ctx.meta["requestId"];
|
|
2196
|
-
await
|
|
2198
|
+
await background4(bus?.emit(
|
|
2197
2199
|
EVENT_KEYS.userDeleted,
|
|
2198
2200
|
{ userId },
|
|
2199
2201
|
reqId !== void 0 ? { requestId: reqId } : void 0
|
|
@@ -2368,7 +2370,7 @@ function oauthController(store, config) {
|
|
|
2368
2370
|
}
|
|
2369
2371
|
const upserted = await users.upsertByProvider(normalizedEmail, "apple", claims.sub ?? "");
|
|
2370
2372
|
if (!upserted) {
|
|
2371
|
-
loginEvents.recordSafe({
|
|
2373
|
+
await loginEvents.recordSafe({
|
|
2372
2374
|
userId: null,
|
|
2373
2375
|
emailAttempted: normalizedEmail,
|
|
2374
2376
|
method: "oauth-apple",
|
|
@@ -2384,7 +2386,7 @@ function oauthController(store, config) {
|
|
|
2384
2386
|
}
|
|
2385
2387
|
const { accessToken, refreshToken, sid } = issueTokenPair(upserted.id, config, { loginMethod: "apple" });
|
|
2386
2388
|
await sessions.create(upserted.id, refreshToken, refreshTokenExpiry(refreshToken), sid, meta);
|
|
2387
|
-
loginEvents.recordSafe({
|
|
2389
|
+
await loginEvents.recordSafe({
|
|
2388
2390
|
userId: upserted.id,
|
|
2389
2391
|
emailAttempted: normalizedEmail,
|
|
2390
2392
|
method: "oauth-apple",
|
|
@@ -2518,7 +2520,7 @@ function oauthController(store, config) {
|
|
|
2518
2520
|
const meta = requestMeta(ctx);
|
|
2519
2521
|
const upserted = await users.upsertByProvider(normalizedEmail, "google", payload.sub ?? "");
|
|
2520
2522
|
if (!upserted) {
|
|
2521
|
-
loginEvents.recordSafe({
|
|
2523
|
+
await loginEvents.recordSafe({
|
|
2522
2524
|
userId: null,
|
|
2523
2525
|
emailAttempted: normalizedEmail,
|
|
2524
2526
|
method: "oauth-google",
|
|
@@ -2536,7 +2538,7 @@ function oauthController(store, config) {
|
|
|
2536
2538
|
loginMethod: "google"
|
|
2537
2539
|
});
|
|
2538
2540
|
await sessions.create(upserted.id, refreshToken, refreshTokenExpiry(refreshToken), sid, meta);
|
|
2539
|
-
loginEvents.recordSafe({
|
|
2541
|
+
await loginEvents.recordSafe({
|
|
2540
2542
|
userId: upserted.id,
|
|
2541
2543
|
emailAttempted: normalizedEmail,
|
|
2542
2544
|
method: "oauth-google",
|
|
@@ -2653,7 +2655,7 @@ function oauthController(store, config) {
|
|
|
2653
2655
|
const claims = await verifyAppleIdToken(identityToken, { audiences, nonce: body?.nonce });
|
|
2654
2656
|
if (!claims) {
|
|
2655
2657
|
const meta = requestMeta(ctx);
|
|
2656
|
-
loginEvents.recordSafe({
|
|
2658
|
+
await loginEvents.recordSafe({
|
|
2657
2659
|
userId: null,
|
|
2658
2660
|
emailAttempted: null,
|
|
2659
2661
|
method: "oauth-apple",
|
|
@@ -2668,7 +2670,7 @@ function oauthController(store, config) {
|
|
|
2668
2670
|
const firstUse = await consumedTokens.consumeOnce(tokenHash, new Date(expMs));
|
|
2669
2671
|
if (!firstUse) {
|
|
2670
2672
|
const meta = requestMeta(ctx);
|
|
2671
|
-
loginEvents.recordSafe({
|
|
2673
|
+
await loginEvents.recordSafe({
|
|
2672
2674
|
userId: null,
|
|
2673
2675
|
emailAttempted: claims.email ?? null,
|
|
2674
2676
|
method: "oauth-apple",
|