@fonderie/auth 7.9.4 → 7.10.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.
- package/README.md +31 -0
- package/brain/outcomes.md +2 -0
- package/brain/signatures.md +34 -0
- package/dist/index.cjs +132 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +130 -20
- package/dist/index.js.map +1 -1
- package/dist/middlewares/index.cjs +93 -4
- package/dist/middlewares/index.cjs.map +1 -1
- package/dist/middlewares/index.d.cts +1 -1
- package/dist/middlewares/index.d.ts +1 -1
- package/dist/middlewares/index.js +93 -4
- package/dist/middlewares/index.js.map +1 -1
- package/dist/migrations/sql/018_login_event_location.sql +6 -0
- package/dist/migrations/sql/019_session_location.sql +5 -0
- package/dist/{session-Bv4qu9xV.d.cts → session-DU9QTf7f.d.cts} +37 -1
- package/dist/{session-Bv4qu9xV.d.ts → session-DU9QTf7f.d.ts} +37 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -3,8 +3,8 @@ export { IMfaChallenge, ISession } from './types.cjs';
|
|
|
3
3
|
import { IFonderieModule, IAdminDescription, IReadinessProblem, IFonderieApp, IAdminRoute } from '@fonderie/core';
|
|
4
4
|
import { IStoreAdapter } from '@fonderie/store';
|
|
5
5
|
import { EventBus } from '@fonderie/events';
|
|
6
|
-
import { I as IAuthConfig } from './session-
|
|
7
|
-
export { A as AUTH_CONFIG_KEYS,
|
|
6
|
+
import { I as IAuthConfig, a as IRequestLocation } from './session-DU9QTf7f.cjs';
|
|
7
|
+
export { A as AUTH_CONFIG_KEYS, b as AuthLimitedRoute, c as AuthMessageKey, d as IAuthRateLimitConfig, e as IAuthRuntimeConfig, f as IAuthSecrets, g as IDataExportContributor, h as ILocationRequest, L as LocationResolver, M as MESSAGE_KEYS, i as buildAuthAccountLimiter, j as buildAuthIpLimiter, r as resolveLocation, s as sanitizeLocation, w as withSession } from './session-DU9QTf7f.cjs';
|
|
8
8
|
import { IUserDTO } from './dtos/user.cjs';
|
|
9
9
|
export { toUserDTO } from './dtos/user.cjs';
|
|
10
10
|
export { requireAuth, validate } from '@fonderie/core/middlewares';
|
|
@@ -96,6 +96,9 @@ interface ILoginEventDTO {
|
|
|
96
96
|
failureReason: string | null;
|
|
97
97
|
ipAddress: string | null;
|
|
98
98
|
userAgent: string | null;
|
|
99
|
+
/** Where the attempt came from — present only when the app configures
|
|
100
|
+
* `location`. Country is reliable; region/city are approximate. */
|
|
101
|
+
location: IRequestLocation | null;
|
|
99
102
|
createdAt: string;
|
|
100
103
|
}
|
|
101
104
|
interface ILoginHistoryPageDTO {
|
|
@@ -107,6 +110,8 @@ interface ISessionDTO {
|
|
|
107
110
|
current: boolean;
|
|
108
111
|
ipAddress: string | null;
|
|
109
112
|
userAgent: string | null;
|
|
113
|
+
/** Where the session was opened from, when `location` is configured. */
|
|
114
|
+
location: IRequestLocation | null;
|
|
110
115
|
createdAt: string;
|
|
111
116
|
expiresAt: string;
|
|
112
117
|
}
|
|
@@ -257,4 +262,4 @@ interface IAdminUserPageDTO {
|
|
|
257
262
|
declare function toAdminUserPageDTO(page: IUserPage): IAdminUserPageDTO;
|
|
258
263
|
declare function describeAuthAdminRoutes(store: IStoreAdapter): IAdminRoute[];
|
|
259
264
|
|
|
260
|
-
export { AuthModule, type ChangePasswordInput, DEFAULT_TEMPLATES, type IAdminUserDTO, IAuthConfig, type IImportUser, type ILoginEventDTO, type ILoginHistoryPageDTO, type IPurgeOptions, type ISessionDTO, IUser, IUserDTO, type IUserRetentionScheduleOptions, type LoginInput, type RegisterInput, type ResetPasswordInput, describeAuthAdminRoutes, importUser, normalizeEmail, normalizeEmailSafe, purgeSoftDeletedUsers, schemas, startUserRetention, toAdminUserDTO, toAdminUserPageDTO, validateAuthConfig };
|
|
265
|
+
export { AuthModule, type ChangePasswordInput, DEFAULT_TEMPLATES, type IAdminUserDTO, IAuthConfig, type IImportUser, type ILoginEventDTO, type ILoginHistoryPageDTO, type IPurgeOptions, IRequestLocation, type ISessionDTO, IUser, IUserDTO, type IUserRetentionScheduleOptions, type LoginInput, type RegisterInput, type ResetPasswordInput, describeAuthAdminRoutes, importUser, normalizeEmail, normalizeEmailSafe, purgeSoftDeletedUsers, schemas, startUserRetention, toAdminUserDTO, toAdminUserPageDTO, validateAuthConfig };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export { IMfaChallenge, ISession } from './types.js';
|
|
|
3
3
|
import { IFonderieModule, IAdminDescription, IReadinessProblem, IFonderieApp, IAdminRoute } from '@fonderie/core';
|
|
4
4
|
import { IStoreAdapter } from '@fonderie/store';
|
|
5
5
|
import { EventBus } from '@fonderie/events';
|
|
6
|
-
import { I as IAuthConfig } from './session-
|
|
7
|
-
export { A as AUTH_CONFIG_KEYS,
|
|
6
|
+
import { I as IAuthConfig, a as IRequestLocation } from './session-DU9QTf7f.js';
|
|
7
|
+
export { A as AUTH_CONFIG_KEYS, b as AuthLimitedRoute, c as AuthMessageKey, d as IAuthRateLimitConfig, e as IAuthRuntimeConfig, f as IAuthSecrets, g as IDataExportContributor, h as ILocationRequest, L as LocationResolver, M as MESSAGE_KEYS, i as buildAuthAccountLimiter, j as buildAuthIpLimiter, r as resolveLocation, s as sanitizeLocation, w as withSession } from './session-DU9QTf7f.js';
|
|
8
8
|
import { IUserDTO } from './dtos/user.js';
|
|
9
9
|
export { toUserDTO } from './dtos/user.js';
|
|
10
10
|
export { requireAuth, validate } from '@fonderie/core/middlewares';
|
|
@@ -96,6 +96,9 @@ interface ILoginEventDTO {
|
|
|
96
96
|
failureReason: string | null;
|
|
97
97
|
ipAddress: string | null;
|
|
98
98
|
userAgent: string | null;
|
|
99
|
+
/** Where the attempt came from — present only when the app configures
|
|
100
|
+
* `location`. Country is reliable; region/city are approximate. */
|
|
101
|
+
location: IRequestLocation | null;
|
|
99
102
|
createdAt: string;
|
|
100
103
|
}
|
|
101
104
|
interface ILoginHistoryPageDTO {
|
|
@@ -107,6 +110,8 @@ interface ISessionDTO {
|
|
|
107
110
|
current: boolean;
|
|
108
111
|
ipAddress: string | null;
|
|
109
112
|
userAgent: string | null;
|
|
113
|
+
/** Where the session was opened from, when `location` is configured. */
|
|
114
|
+
location: IRequestLocation | null;
|
|
110
115
|
createdAt: string;
|
|
111
116
|
expiresAt: string;
|
|
112
117
|
}
|
|
@@ -257,4 +262,4 @@ interface IAdminUserPageDTO {
|
|
|
257
262
|
declare function toAdminUserPageDTO(page: IUserPage): IAdminUserPageDTO;
|
|
258
263
|
declare function describeAuthAdminRoutes(store: IStoreAdapter): IAdminRoute[];
|
|
259
264
|
|
|
260
|
-
export { AuthModule, type ChangePasswordInput, DEFAULT_TEMPLATES, type IAdminUserDTO, IAuthConfig, type IImportUser, type ILoginEventDTO, type ILoginHistoryPageDTO, type IPurgeOptions, type ISessionDTO, IUser, IUserDTO, type IUserRetentionScheduleOptions, type LoginInput, type RegisterInput, type ResetPasswordInput, describeAuthAdminRoutes, importUser, normalizeEmail, normalizeEmailSafe, purgeSoftDeletedUsers, schemas, startUserRetention, toAdminUserDTO, toAdminUserPageDTO, validateAuthConfig };
|
|
265
|
+
export { AuthModule, type ChangePasswordInput, DEFAULT_TEMPLATES, type IAdminUserDTO, IAuthConfig, type IImportUser, type ILoginEventDTO, type ILoginHistoryPageDTO, type IPurgeOptions, IRequestLocation, type ISessionDTO, IUser, IUserDTO, type IUserRetentionScheduleOptions, type LoginInput, type RegisterInput, type ResetPasswordInput, describeAuthAdminRoutes, importUser, normalizeEmail, normalizeEmailSafe, purgeSoftDeletedUsers, schemas, startUserRetention, toAdminUserDTO, toAdminUserPageDTO, validateAuthConfig };
|
package/dist/index.js
CHANGED
|
@@ -838,18 +838,106 @@ var UserModel = class {
|
|
|
838
838
|
};
|
|
839
839
|
var MAX_LIST_LIMIT = 200;
|
|
840
840
|
|
|
841
|
+
// src/services/request-location.ts
|
|
842
|
+
var LOCATION_TIMEOUT_MS = 500;
|
|
843
|
+
var TEXT_MAX = 128;
|
|
844
|
+
function str(v, re) {
|
|
845
|
+
if (typeof v !== "string") return null;
|
|
846
|
+
const t = v.trim();
|
|
847
|
+
if (t.length === 0 || t.length > TEXT_MAX) return null;
|
|
848
|
+
return re && !re.test(t) ? null : t;
|
|
849
|
+
}
|
|
850
|
+
function upperCode(v, re) {
|
|
851
|
+
const t = str(v, re);
|
|
852
|
+
return t ? t.toUpperCase() : null;
|
|
853
|
+
}
|
|
854
|
+
function bool(v) {
|
|
855
|
+
return typeof v === "boolean" ? v : null;
|
|
856
|
+
}
|
|
857
|
+
function coord(v, limit) {
|
|
858
|
+
if (typeof v !== "number" || !Number.isFinite(v) || Math.abs(v) > limit) return null;
|
|
859
|
+
return Math.round(v * 100) / 100;
|
|
860
|
+
}
|
|
861
|
+
function radius(v) {
|
|
862
|
+
if (typeof v !== "number" || !Number.isFinite(v) || v <= 0 || v > 2e4) return null;
|
|
863
|
+
return Math.round(v);
|
|
864
|
+
}
|
|
865
|
+
function sanitizeLocation(input) {
|
|
866
|
+
if (!input || typeof input !== "object") return null;
|
|
867
|
+
const i = input;
|
|
868
|
+
const out = {
|
|
869
|
+
country: upperCode(i["country"], /^[A-Za-z]{2}$/),
|
|
870
|
+
countryName: str(i["countryName"]),
|
|
871
|
+
subdivision: upperCode(i["subdivision"], /^[A-Za-z0-9]{1,3}$/),
|
|
872
|
+
subdivisionName: str(i["subdivisionName"]),
|
|
873
|
+
city: str(i["city"]),
|
|
874
|
+
postalCode: upperCode(i["postalCode"], /^[A-Za-z0-9][A-Za-z0-9 -]{0,11}$/),
|
|
875
|
+
continent: upperCode(i["continent"], /^[A-Za-z]{2}$/),
|
|
876
|
+
timeZone: str(i["timeZone"], /^(UTC|[A-Za-z_]+(\/[A-Za-z0-9_+-]+)+)$/),
|
|
877
|
+
latitude: coord(i["latitude"], 90),
|
|
878
|
+
longitude: coord(i["longitude"], 180),
|
|
879
|
+
accuracyRadius: radius(i["accuracyRadius"]),
|
|
880
|
+
isp: str(i["isp"]),
|
|
881
|
+
org: str(i["org"]),
|
|
882
|
+
asn: upperCode(i["asn"], /^AS\d{1,10}$/i),
|
|
883
|
+
mobile: bool(i["mobile"]),
|
|
884
|
+
proxy: bool(i["proxy"]),
|
|
885
|
+
hosting: bool(i["hosting"])
|
|
886
|
+
};
|
|
887
|
+
const known = Object.fromEntries(Object.entries(out).filter(([, v]) => v !== null));
|
|
888
|
+
return Object.keys(known).length > 0 ? known : null;
|
|
889
|
+
}
|
|
890
|
+
var perRequest = /* @__PURE__ */ new WeakMap();
|
|
891
|
+
function resolveLocation(resolver, req, timeoutMs = LOCATION_TIMEOUT_MS) {
|
|
892
|
+
if (!resolver) return Promise.resolve(null);
|
|
893
|
+
const cached = perRequest.get(req.headers);
|
|
894
|
+
if (cached && cached.resolver === resolver) return cached.result;
|
|
895
|
+
const result = resolveOnce(resolver, req, timeoutMs);
|
|
896
|
+
perRequest.set(req.headers, { resolver, result });
|
|
897
|
+
return result;
|
|
898
|
+
}
|
|
899
|
+
async function resolveOnce(resolver, req, timeoutMs) {
|
|
900
|
+
let timer;
|
|
901
|
+
try {
|
|
902
|
+
const result = await Promise.race([
|
|
903
|
+
Promise.resolve().then(() => resolver(req)),
|
|
904
|
+
new Promise((resolve2) => {
|
|
905
|
+
timer = setTimeout(() => resolve2(null), timeoutMs);
|
|
906
|
+
})
|
|
907
|
+
]);
|
|
908
|
+
return sanitizeLocation(result);
|
|
909
|
+
} catch (err) {
|
|
910
|
+
console.warn("[auth] location resolver failed; recording without a location:", err);
|
|
911
|
+
return null;
|
|
912
|
+
} finally {
|
|
913
|
+
if (timer) clearTimeout(timer);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
841
917
|
// src/models/session.model.ts
|
|
842
918
|
var SessionModel = class {
|
|
843
|
-
|
|
919
|
+
// `locate` is IAuthConfig.location. Absent ⇒ sessions carry no location.
|
|
920
|
+
constructor(store, locate) {
|
|
844
921
|
this.store = store;
|
|
922
|
+
this.locate = locate;
|
|
845
923
|
}
|
|
846
924
|
store;
|
|
925
|
+
locate;
|
|
847
926
|
async create(userId, token, expiresAt, sid, meta) {
|
|
927
|
+
const location = this.locate && meta?.headers ? await resolveLocation(this.locate, { ip: meta.ipAddress, headers: meta.headers }) : null;
|
|
848
928
|
await this.store.query(
|
|
849
|
-
`INSERT INTO fonderie_sessions (user_id, token, expires_at, sid, user_agent, ip_address)
|
|
850
|
-
VALUES ($1, $2, $3, $4, $5, $6)
|
|
929
|
+
`INSERT INTO fonderie_sessions (user_id, token, expires_at, sid, user_agent, ip_address, location)
|
|
930
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
851
931
|
ON CONFLICT (token) DO NOTHING`,
|
|
852
|
-
[
|
|
932
|
+
[
|
|
933
|
+
userId,
|
|
934
|
+
token,
|
|
935
|
+
expiresAt,
|
|
936
|
+
sid ?? null,
|
|
937
|
+
meta?.userAgent ?? null,
|
|
938
|
+
meta?.ipAddress ?? null,
|
|
939
|
+
location ? JSON.stringify(location) : null
|
|
940
|
+
]
|
|
853
941
|
);
|
|
854
942
|
}
|
|
855
943
|
async delete(token) {
|
|
@@ -888,6 +976,7 @@ var SessionModel = class {
|
|
|
888
976
|
`SELECT id, sid,
|
|
889
977
|
user_agent AS "userAgent",
|
|
890
978
|
ip_address AS "ipAddress",
|
|
979
|
+
location,
|
|
891
980
|
created_at AS "createdAt",
|
|
892
981
|
expires_at AS "expiresAt"
|
|
893
982
|
FROM fonderie_sessions
|
|
@@ -971,15 +1060,20 @@ var BackupCodeModel = class {
|
|
|
971
1060
|
// src/models/login-event.model.ts
|
|
972
1061
|
import { background } from "@fonderie/core";
|
|
973
1062
|
var LoginEventModel = class {
|
|
974
|
-
|
|
1063
|
+
// `locate` is IAuthConfig.location. Absent ⇒ rows carry no location,
|
|
1064
|
+
// exactly as before.
|
|
1065
|
+
constructor(store, locate) {
|
|
975
1066
|
this.store = store;
|
|
1067
|
+
this.locate = locate;
|
|
976
1068
|
}
|
|
977
1069
|
store;
|
|
1070
|
+
locate;
|
|
978
1071
|
async record(e) {
|
|
1072
|
+
const location = this.locate ? await resolveLocation(this.locate, { ip: e.ipAddress, headers: e.headers ?? new Headers() }) : null;
|
|
979
1073
|
await this.store.query(
|
|
980
1074
|
`INSERT INTO fonderie_login_events
|
|
981
|
-
(user_id, email_attempted, method, outcome, failure_reason, ip_address, user_agent)
|
|
982
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
|
|
1075
|
+
(user_id, email_attempted, method, outcome, failure_reason, ip_address, user_agent, location)
|
|
1076
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
|
|
983
1077
|
[
|
|
984
1078
|
e.userId,
|
|
985
1079
|
e.emailAttempted ?? null,
|
|
@@ -987,7 +1081,8 @@ var LoginEventModel = class {
|
|
|
987
1081
|
e.outcome,
|
|
988
1082
|
e.failureReason ?? null,
|
|
989
1083
|
e.ipAddress,
|
|
990
|
-
e.userAgent
|
|
1084
|
+
e.userAgent,
|
|
1085
|
+
location ? JSON.stringify(location) : null
|
|
991
1086
|
]
|
|
992
1087
|
);
|
|
993
1088
|
}
|
|
@@ -1026,7 +1121,7 @@ var LoginEventModel = class {
|
|
|
1026
1121
|
params.push(limit + 1);
|
|
1027
1122
|
const rows = await this.store.query(
|
|
1028
1123
|
`SELECT id, method, outcome, failure_reason AS "failureReason",
|
|
1029
|
-
ip_address AS "ipAddress", user_agent AS "userAgent",
|
|
1124
|
+
ip_address AS "ipAddress", user_agent AS "userAgent", location,
|
|
1030
1125
|
created_at AS "createdAt", created_at::text AS "createdAtRaw"
|
|
1031
1126
|
FROM fonderie_login_events
|
|
1032
1127
|
WHERE ${where.join(" AND ")}
|
|
@@ -1054,7 +1149,8 @@ function requestMeta(ctx) {
|
|
|
1054
1149
|
const ua = ctx.request.headers.get("user-agent");
|
|
1055
1150
|
const meta = {
|
|
1056
1151
|
ipAddress: typeof ip === "string" && ip.length > 0 ? ip : null,
|
|
1057
|
-
userAgent: ua && ua.length > 0 ? ua.slice(0, UA_MAX) : null
|
|
1152
|
+
userAgent: ua && ua.length > 0 ? ua.slice(0, UA_MAX) : null,
|
|
1153
|
+
headers: ctx.request.headers
|
|
1058
1154
|
};
|
|
1059
1155
|
if (meta.ipAddress === null && meta.userAgent === null) warnIfIdentityless(ctx);
|
|
1060
1156
|
return meta;
|
|
@@ -1063,9 +1159,9 @@ function requestMeta(ctx) {
|
|
|
1063
1159
|
// src/controllers/mfa.controller.ts
|
|
1064
1160
|
function mfaController(store, config, issuer, bus) {
|
|
1065
1161
|
const users = new UserModel(store);
|
|
1066
|
-
const sessions = new SessionModel(store);
|
|
1162
|
+
const sessions = new SessionModel(store, config.location);
|
|
1067
1163
|
const backupCodes = new BackupCodeModel(store);
|
|
1068
|
-
const loginEvents = new LoginEventModel(store);
|
|
1164
|
+
const loginEvents = new LoginEventModel(store, config.location);
|
|
1069
1165
|
const mfaCipher = makeMfaCipher(config.mfaSecretKey);
|
|
1070
1166
|
return {
|
|
1071
1167
|
// ── 1. Setup ───────────────────────────────────────────────
|
|
@@ -1463,8 +1559,8 @@ function extractRefreshToken(ctx) {
|
|
|
1463
1559
|
}
|
|
1464
1560
|
function authController(store, config, bus) {
|
|
1465
1561
|
const users = new UserModel(store);
|
|
1466
|
-
const sessions = new SessionModel(store);
|
|
1467
|
-
const loginEvents = new LoginEventModel(store);
|
|
1562
|
+
const sessions = new SessionModel(store, config.location);
|
|
1563
|
+
const loginEvents = new LoginEventModel(store, config.location);
|
|
1468
1564
|
const passwordReset = new PasswordResetModel(store);
|
|
1469
1565
|
const emailVerif = new EmailVerificationModel(store);
|
|
1470
1566
|
const phoneVerif = new PhoneVerificationModel(store);
|
|
@@ -1532,7 +1628,15 @@ function authController(store, config, bus) {
|
|
|
1532
1628
|
const { accessToken, refreshToken, sid } = issueTokenPair(user.id, config, {
|
|
1533
1629
|
loginMethod: "email"
|
|
1534
1630
|
});
|
|
1535
|
-
|
|
1631
|
+
const registerMeta = requestMeta(ctx);
|
|
1632
|
+
await sessions.create(user.id, refreshToken, refreshTokenExpiry(refreshToken), sid, registerMeta);
|
|
1633
|
+
await loginEvents.recordSafe({
|
|
1634
|
+
userId: user.id,
|
|
1635
|
+
emailAttempted: normalizedEmail,
|
|
1636
|
+
method: "registration",
|
|
1637
|
+
outcome: "success",
|
|
1638
|
+
...registerMeta
|
|
1639
|
+
});
|
|
1536
1640
|
const resolvedRegister = { ...config, ...config.resolve?.(ctx) };
|
|
1537
1641
|
const requiresVerification = !!resolvedRegister.requireVerification && !user.emailVerifiedAt;
|
|
1538
1642
|
return Response.json(
|
|
@@ -2091,6 +2195,9 @@ function toLoginEventDTO(row) {
|
|
|
2091
2195
|
failureReason: row.failureReason,
|
|
2092
2196
|
ipAddress: row.ipAddress,
|
|
2093
2197
|
userAgent: row.userAgent,
|
|
2198
|
+
// Re-sanitized on read: the column is JSONB and could have been written
|
|
2199
|
+
// by anything with database access.
|
|
2200
|
+
location: sanitizeLocation(row.location),
|
|
2094
2201
|
createdAt: row.createdAt instanceof Date ? row.createdAt.toISOString() : String(row.createdAt)
|
|
2095
2202
|
};
|
|
2096
2203
|
}
|
|
@@ -2106,6 +2213,7 @@ function toSessionDTO(row, currentSid) {
|
|
|
2106
2213
|
current: currentSid !== null && row.sid === currentSid,
|
|
2107
2214
|
ipAddress: row.ipAddress,
|
|
2108
2215
|
userAgent: row.userAgent,
|
|
2216
|
+
location: sanitizeLocation(row.location),
|
|
2109
2217
|
createdAt: row.createdAt instanceof Date ? row.createdAt.toISOString() : String(row.createdAt),
|
|
2110
2218
|
expiresAt: row.expiresAt instanceof Date ? row.expiresAt.toISOString() : String(row.expiresAt)
|
|
2111
2219
|
};
|
|
@@ -2120,8 +2228,8 @@ function isValidPhone2(phone2) {
|
|
|
2120
2228
|
}
|
|
2121
2229
|
function userController(store, config, bus) {
|
|
2122
2230
|
const users = new UserModel(store);
|
|
2123
|
-
const sessions = new SessionModel(store);
|
|
2124
|
-
const loginEvents = new LoginEventModel(store);
|
|
2231
|
+
const sessions = new SessionModel(store, config.location);
|
|
2232
|
+
const loginEvents = new LoginEventModel(store, config.location);
|
|
2125
2233
|
const emailVerif = new EmailVerificationModel(store);
|
|
2126
2234
|
const phoneVerif = new PhoneVerificationModel(store);
|
|
2127
2235
|
return {
|
|
@@ -2565,8 +2673,8 @@ async function verifyAppleIdToken(idToken, opts) {
|
|
|
2565
2673
|
var appleEmailVerified = (c) => c.email_verified === true || c.email_verified === "true";
|
|
2566
2674
|
function oauthController(store, config, bus) {
|
|
2567
2675
|
const users = new UserModel(store);
|
|
2568
|
-
const sessions = new SessionModel(store);
|
|
2569
|
-
const loginEvents = new LoginEventModel(store);
|
|
2676
|
+
const sessions = new SessionModel(store, config.location);
|
|
2677
|
+
const loginEvents = new LoginEventModel(store, config.location);
|
|
2570
2678
|
const consumedTokens = new ConsumedTokenModel(store);
|
|
2571
2679
|
const announceOAuthUpsert = async (ctx, upserted, provider, user) => {
|
|
2572
2680
|
if (!bus) return;
|
|
@@ -3355,7 +3463,7 @@ var AuthModule = class {
|
|
|
3355
3463
|
name = "@fonderie/auth";
|
|
3356
3464
|
// Baked in at build time by tsup.base, so the operator's Modules page can
|
|
3357
3465
|
// say what is actually deployed rather than 'not reported'.
|
|
3358
|
-
version = "7.
|
|
3466
|
+
version = "7.10.0";
|
|
3359
3467
|
// Users, sessions, login history, suspend — only through @fonderie/admin.
|
|
3360
3468
|
describeAdmin() {
|
|
3361
3469
|
return { routes: describeAuthAdminRoutes(this.store) };
|
|
@@ -3632,6 +3740,8 @@ export {
|
|
|
3632
3740
|
normalizeEmailSafe,
|
|
3633
3741
|
purgeSoftDeletedUsers,
|
|
3634
3742
|
requireAuth2 as requireAuth,
|
|
3743
|
+
resolveLocation,
|
|
3744
|
+
sanitizeLocation,
|
|
3635
3745
|
schemas_exports as schemas,
|
|
3636
3746
|
startUserRetention,
|
|
3637
3747
|
toAdminUserDTO,
|