@fonderie/auth 7.9.4 → 7.11.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 +35 -0
- package/dist/index.cjs +137 -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 +135 -20
- package/dist/index.js.map +1 -1
- package/dist/middlewares/index.cjs +98 -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 +98 -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-BBF5t-3Y.d.cts} +41 -1
- package/dist/{session-Bv4qu9xV.d.ts → session-BBF5t-3Y.d.ts} +41 -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-BBF5t-3Y.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-BBF5t-3Y.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-BBF5t-3Y.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-BBF5t-3Y.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,111 @@ 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 placeId(v) {
|
|
866
|
+
const n = typeof v === "string" && /^\d{1,10}$/.test(v) ? Number(v) : v;
|
|
867
|
+
return typeof n === "number" && Number.isInteger(n) && n > 0 && n <= 2147483647 ? n : null;
|
|
868
|
+
}
|
|
869
|
+
function sanitizeLocation(input) {
|
|
870
|
+
if (!input || typeof input !== "object") return null;
|
|
871
|
+
const i = input;
|
|
872
|
+
const out = {
|
|
873
|
+
country: upperCode(i["country"], /^[A-Za-z]{2}$/),
|
|
874
|
+
countryName: str(i["countryName"]),
|
|
875
|
+
subdivision: upperCode(i["subdivision"], /^[A-Za-z0-9]{1,3}$/),
|
|
876
|
+
subdivisionName: str(i["subdivisionName"]),
|
|
877
|
+
city: str(i["city"]),
|
|
878
|
+
postalCode: upperCode(i["postalCode"], /^[A-Za-z0-9][A-Za-z0-9 -]{0,11}$/),
|
|
879
|
+
continent: upperCode(i["continent"], /^[A-Za-z]{2}$/),
|
|
880
|
+
timeZone: str(i["timeZone"], /^(UTC|[A-Za-z_]+(\/[A-Za-z0-9_+-]+)+)$/),
|
|
881
|
+
latitude: coord(i["latitude"], 90),
|
|
882
|
+
longitude: coord(i["longitude"], 180),
|
|
883
|
+
accuracyRadius: radius(i["accuracyRadius"]),
|
|
884
|
+
geonameId: placeId(i["geonameId"]),
|
|
885
|
+
isp: str(i["isp"]),
|
|
886
|
+
org: str(i["org"]),
|
|
887
|
+
asn: upperCode(i["asn"], /^AS\d{1,10}$/i),
|
|
888
|
+
mobile: bool(i["mobile"]),
|
|
889
|
+
proxy: bool(i["proxy"]),
|
|
890
|
+
hosting: bool(i["hosting"])
|
|
891
|
+
};
|
|
892
|
+
const known = Object.fromEntries(Object.entries(out).filter(([, v]) => v !== null));
|
|
893
|
+
return Object.keys(known).length > 0 ? known : null;
|
|
894
|
+
}
|
|
895
|
+
var perRequest = /* @__PURE__ */ new WeakMap();
|
|
896
|
+
function resolveLocation(resolver, req, timeoutMs = LOCATION_TIMEOUT_MS) {
|
|
897
|
+
if (!resolver) return Promise.resolve(null);
|
|
898
|
+
const cached = perRequest.get(req.headers);
|
|
899
|
+
if (cached && cached.resolver === resolver) return cached.result;
|
|
900
|
+
const result = resolveOnce(resolver, req, timeoutMs);
|
|
901
|
+
perRequest.set(req.headers, { resolver, result });
|
|
902
|
+
return result;
|
|
903
|
+
}
|
|
904
|
+
async function resolveOnce(resolver, req, timeoutMs) {
|
|
905
|
+
let timer;
|
|
906
|
+
try {
|
|
907
|
+
const result = await Promise.race([
|
|
908
|
+
Promise.resolve().then(() => resolver(req)),
|
|
909
|
+
new Promise((resolve2) => {
|
|
910
|
+
timer = setTimeout(() => resolve2(null), timeoutMs);
|
|
911
|
+
})
|
|
912
|
+
]);
|
|
913
|
+
return sanitizeLocation(result);
|
|
914
|
+
} catch (err) {
|
|
915
|
+
console.warn("[auth] location resolver failed; recording without a location:", err);
|
|
916
|
+
return null;
|
|
917
|
+
} finally {
|
|
918
|
+
if (timer) clearTimeout(timer);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
841
922
|
// src/models/session.model.ts
|
|
842
923
|
var SessionModel = class {
|
|
843
|
-
|
|
924
|
+
// `locate` is IAuthConfig.location. Absent ⇒ sessions carry no location.
|
|
925
|
+
constructor(store, locate) {
|
|
844
926
|
this.store = store;
|
|
927
|
+
this.locate = locate;
|
|
845
928
|
}
|
|
846
929
|
store;
|
|
930
|
+
locate;
|
|
847
931
|
async create(userId, token, expiresAt, sid, meta) {
|
|
932
|
+
const location = this.locate && meta?.headers ? await resolveLocation(this.locate, { ip: meta.ipAddress, headers: meta.headers }) : null;
|
|
848
933
|
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)
|
|
934
|
+
`INSERT INTO fonderie_sessions (user_id, token, expires_at, sid, user_agent, ip_address, location)
|
|
935
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
851
936
|
ON CONFLICT (token) DO NOTHING`,
|
|
852
|
-
[
|
|
937
|
+
[
|
|
938
|
+
userId,
|
|
939
|
+
token,
|
|
940
|
+
expiresAt,
|
|
941
|
+
sid ?? null,
|
|
942
|
+
meta?.userAgent ?? null,
|
|
943
|
+
meta?.ipAddress ?? null,
|
|
944
|
+
location ? JSON.stringify(location) : null
|
|
945
|
+
]
|
|
853
946
|
);
|
|
854
947
|
}
|
|
855
948
|
async delete(token) {
|
|
@@ -888,6 +981,7 @@ var SessionModel = class {
|
|
|
888
981
|
`SELECT id, sid,
|
|
889
982
|
user_agent AS "userAgent",
|
|
890
983
|
ip_address AS "ipAddress",
|
|
984
|
+
location,
|
|
891
985
|
created_at AS "createdAt",
|
|
892
986
|
expires_at AS "expiresAt"
|
|
893
987
|
FROM fonderie_sessions
|
|
@@ -971,15 +1065,20 @@ var BackupCodeModel = class {
|
|
|
971
1065
|
// src/models/login-event.model.ts
|
|
972
1066
|
import { background } from "@fonderie/core";
|
|
973
1067
|
var LoginEventModel = class {
|
|
974
|
-
|
|
1068
|
+
// `locate` is IAuthConfig.location. Absent ⇒ rows carry no location,
|
|
1069
|
+
// exactly as before.
|
|
1070
|
+
constructor(store, locate) {
|
|
975
1071
|
this.store = store;
|
|
1072
|
+
this.locate = locate;
|
|
976
1073
|
}
|
|
977
1074
|
store;
|
|
1075
|
+
locate;
|
|
978
1076
|
async record(e) {
|
|
1077
|
+
const location = this.locate ? await resolveLocation(this.locate, { ip: e.ipAddress, headers: e.headers ?? new Headers() }) : null;
|
|
979
1078
|
await this.store.query(
|
|
980
1079
|
`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)`,
|
|
1080
|
+
(user_id, email_attempted, method, outcome, failure_reason, ip_address, user_agent, location)
|
|
1081
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
|
|
983
1082
|
[
|
|
984
1083
|
e.userId,
|
|
985
1084
|
e.emailAttempted ?? null,
|
|
@@ -987,7 +1086,8 @@ var LoginEventModel = class {
|
|
|
987
1086
|
e.outcome,
|
|
988
1087
|
e.failureReason ?? null,
|
|
989
1088
|
e.ipAddress,
|
|
990
|
-
e.userAgent
|
|
1089
|
+
e.userAgent,
|
|
1090
|
+
location ? JSON.stringify(location) : null
|
|
991
1091
|
]
|
|
992
1092
|
);
|
|
993
1093
|
}
|
|
@@ -1026,7 +1126,7 @@ var LoginEventModel = class {
|
|
|
1026
1126
|
params.push(limit + 1);
|
|
1027
1127
|
const rows = await this.store.query(
|
|
1028
1128
|
`SELECT id, method, outcome, failure_reason AS "failureReason",
|
|
1029
|
-
ip_address AS "ipAddress", user_agent AS "userAgent",
|
|
1129
|
+
ip_address AS "ipAddress", user_agent AS "userAgent", location,
|
|
1030
1130
|
created_at AS "createdAt", created_at::text AS "createdAtRaw"
|
|
1031
1131
|
FROM fonderie_login_events
|
|
1032
1132
|
WHERE ${where.join(" AND ")}
|
|
@@ -1054,7 +1154,8 @@ function requestMeta(ctx) {
|
|
|
1054
1154
|
const ua = ctx.request.headers.get("user-agent");
|
|
1055
1155
|
const meta = {
|
|
1056
1156
|
ipAddress: typeof ip === "string" && ip.length > 0 ? ip : null,
|
|
1057
|
-
userAgent: ua && ua.length > 0 ? ua.slice(0, UA_MAX) : null
|
|
1157
|
+
userAgent: ua && ua.length > 0 ? ua.slice(0, UA_MAX) : null,
|
|
1158
|
+
headers: ctx.request.headers
|
|
1058
1159
|
};
|
|
1059
1160
|
if (meta.ipAddress === null && meta.userAgent === null) warnIfIdentityless(ctx);
|
|
1060
1161
|
return meta;
|
|
@@ -1063,9 +1164,9 @@ function requestMeta(ctx) {
|
|
|
1063
1164
|
// src/controllers/mfa.controller.ts
|
|
1064
1165
|
function mfaController(store, config, issuer, bus) {
|
|
1065
1166
|
const users = new UserModel(store);
|
|
1066
|
-
const sessions = new SessionModel(store);
|
|
1167
|
+
const sessions = new SessionModel(store, config.location);
|
|
1067
1168
|
const backupCodes = new BackupCodeModel(store);
|
|
1068
|
-
const loginEvents = new LoginEventModel(store);
|
|
1169
|
+
const loginEvents = new LoginEventModel(store, config.location);
|
|
1069
1170
|
const mfaCipher = makeMfaCipher(config.mfaSecretKey);
|
|
1070
1171
|
return {
|
|
1071
1172
|
// ── 1. Setup ───────────────────────────────────────────────
|
|
@@ -1463,8 +1564,8 @@ function extractRefreshToken(ctx) {
|
|
|
1463
1564
|
}
|
|
1464
1565
|
function authController(store, config, bus) {
|
|
1465
1566
|
const users = new UserModel(store);
|
|
1466
|
-
const sessions = new SessionModel(store);
|
|
1467
|
-
const loginEvents = new LoginEventModel(store);
|
|
1567
|
+
const sessions = new SessionModel(store, config.location);
|
|
1568
|
+
const loginEvents = new LoginEventModel(store, config.location);
|
|
1468
1569
|
const passwordReset = new PasswordResetModel(store);
|
|
1469
1570
|
const emailVerif = new EmailVerificationModel(store);
|
|
1470
1571
|
const phoneVerif = new PhoneVerificationModel(store);
|
|
@@ -1532,7 +1633,15 @@ function authController(store, config, bus) {
|
|
|
1532
1633
|
const { accessToken, refreshToken, sid } = issueTokenPair(user.id, config, {
|
|
1533
1634
|
loginMethod: "email"
|
|
1534
1635
|
});
|
|
1535
|
-
|
|
1636
|
+
const registerMeta = requestMeta(ctx);
|
|
1637
|
+
await sessions.create(user.id, refreshToken, refreshTokenExpiry(refreshToken), sid, registerMeta);
|
|
1638
|
+
await loginEvents.recordSafe({
|
|
1639
|
+
userId: user.id,
|
|
1640
|
+
emailAttempted: normalizedEmail,
|
|
1641
|
+
method: "registration",
|
|
1642
|
+
outcome: "success",
|
|
1643
|
+
...registerMeta
|
|
1644
|
+
});
|
|
1536
1645
|
const resolvedRegister = { ...config, ...config.resolve?.(ctx) };
|
|
1537
1646
|
const requiresVerification = !!resolvedRegister.requireVerification && !user.emailVerifiedAt;
|
|
1538
1647
|
return Response.json(
|
|
@@ -2091,6 +2200,9 @@ function toLoginEventDTO(row) {
|
|
|
2091
2200
|
failureReason: row.failureReason,
|
|
2092
2201
|
ipAddress: row.ipAddress,
|
|
2093
2202
|
userAgent: row.userAgent,
|
|
2203
|
+
// Re-sanitized on read: the column is JSONB and could have been written
|
|
2204
|
+
// by anything with database access.
|
|
2205
|
+
location: sanitizeLocation(row.location),
|
|
2094
2206
|
createdAt: row.createdAt instanceof Date ? row.createdAt.toISOString() : String(row.createdAt)
|
|
2095
2207
|
};
|
|
2096
2208
|
}
|
|
@@ -2106,6 +2218,7 @@ function toSessionDTO(row, currentSid) {
|
|
|
2106
2218
|
current: currentSid !== null && row.sid === currentSid,
|
|
2107
2219
|
ipAddress: row.ipAddress,
|
|
2108
2220
|
userAgent: row.userAgent,
|
|
2221
|
+
location: sanitizeLocation(row.location),
|
|
2109
2222
|
createdAt: row.createdAt instanceof Date ? row.createdAt.toISOString() : String(row.createdAt),
|
|
2110
2223
|
expiresAt: row.expiresAt instanceof Date ? row.expiresAt.toISOString() : String(row.expiresAt)
|
|
2111
2224
|
};
|
|
@@ -2120,8 +2233,8 @@ function isValidPhone2(phone2) {
|
|
|
2120
2233
|
}
|
|
2121
2234
|
function userController(store, config, bus) {
|
|
2122
2235
|
const users = new UserModel(store);
|
|
2123
|
-
const sessions = new SessionModel(store);
|
|
2124
|
-
const loginEvents = new LoginEventModel(store);
|
|
2236
|
+
const sessions = new SessionModel(store, config.location);
|
|
2237
|
+
const loginEvents = new LoginEventModel(store, config.location);
|
|
2125
2238
|
const emailVerif = new EmailVerificationModel(store);
|
|
2126
2239
|
const phoneVerif = new PhoneVerificationModel(store);
|
|
2127
2240
|
return {
|
|
@@ -2565,8 +2678,8 @@ async function verifyAppleIdToken(idToken, opts) {
|
|
|
2565
2678
|
var appleEmailVerified = (c) => c.email_verified === true || c.email_verified === "true";
|
|
2566
2679
|
function oauthController(store, config, bus) {
|
|
2567
2680
|
const users = new UserModel(store);
|
|
2568
|
-
const sessions = new SessionModel(store);
|
|
2569
|
-
const loginEvents = new LoginEventModel(store);
|
|
2681
|
+
const sessions = new SessionModel(store, config.location);
|
|
2682
|
+
const loginEvents = new LoginEventModel(store, config.location);
|
|
2570
2683
|
const consumedTokens = new ConsumedTokenModel(store);
|
|
2571
2684
|
const announceOAuthUpsert = async (ctx, upserted, provider, user) => {
|
|
2572
2685
|
if (!bus) return;
|
|
@@ -3355,7 +3468,7 @@ var AuthModule = class {
|
|
|
3355
3468
|
name = "@fonderie/auth";
|
|
3356
3469
|
// Baked in at build time by tsup.base, so the operator's Modules page can
|
|
3357
3470
|
// say what is actually deployed rather than 'not reported'.
|
|
3358
|
-
version = "7.
|
|
3471
|
+
version = "7.11.0";
|
|
3359
3472
|
// Users, sessions, login history, suspend — only through @fonderie/admin.
|
|
3360
3473
|
describeAdmin() {
|
|
3361
3474
|
return { routes: describeAuthAdminRoutes(this.store) };
|
|
@@ -3632,6 +3745,8 @@ export {
|
|
|
3632
3745
|
normalizeEmailSafe,
|
|
3633
3746
|
purgeSoftDeletedUsers,
|
|
3634
3747
|
requireAuth2 as requireAuth,
|
|
3748
|
+
resolveLocation,
|
|
3749
|
+
sanitizeLocation,
|
|
3635
3750
|
schemas_exports as schemas,
|
|
3636
3751
|
startUserRetention,
|
|
3637
3752
|
toAdminUserDTO,
|