@factiii/auth 0.2.0 → 0.4.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 +5 -1
- package/dist/{chunk-PYVDWODF.mjs → chunk-EHI4P63M.mjs} +0 -21
- package/dist/{hooks-B41uikq7.d.mts → hooks-BXNxNK4S.d.mts} +1 -55
- package/dist/{hooks-B41uikq7.d.ts → hooks-BXNxNK4S.d.ts} +1 -55
- package/dist/index.d.mts +30 -51
- package/dist/index.d.ts +30 -51
- package/dist/index.js +115 -191
- package/dist/index.mjs +111 -171
- package/dist/validators.d.mts +1 -1
- package/dist/validators.d.ts +1 -1
- package/dist/validators.js +0 -26
- package/dist/validators.mjs +1 -11
- package/package.json +1 -1
- package/prisma/schema.prisma +17 -19
package/dist/index.js
CHANGED
|
@@ -35,12 +35,12 @@ __export(index_exports, {
|
|
|
35
35
|
biometricVerifySchema: () => biometricVerifySchema,
|
|
36
36
|
changePasswordSchema: () => changePasswordSchema,
|
|
37
37
|
cleanBase32String: () => cleanBase32String,
|
|
38
|
-
|
|
38
|
+
clearAuthCookie: () => clearAuthCookie,
|
|
39
39
|
comparePassword: () => comparePassword,
|
|
40
|
-
createAccessToken: () => createAccessToken,
|
|
41
40
|
createAuthConfig: () => createAuthConfig,
|
|
42
41
|
createAuthGuard: () => createAuthGuard,
|
|
43
42
|
createAuthRouter: () => createAuthRouter,
|
|
43
|
+
createAuthToken: () => createAuthToken,
|
|
44
44
|
createConsoleEmailAdapter: () => createConsoleEmailAdapter,
|
|
45
45
|
createNoopEmailAdapter: () => createNoopEmailAdapter,
|
|
46
46
|
createOAuthVerifier: () => createOAuthVerifier,
|
|
@@ -60,20 +60,16 @@ __export(index_exports, {
|
|
|
60
60
|
isTokenExpiredError: () => isTokenExpiredError,
|
|
61
61
|
isTokenInvalidError: () => isTokenInvalidError,
|
|
62
62
|
loginSchema: () => loginSchema,
|
|
63
|
-
logoutSchema: () => logoutSchema,
|
|
64
63
|
oAuthLoginSchema: () => oAuthLoginSchema,
|
|
65
|
-
|
|
66
|
-
otpLoginVerifySchema: () => otpLoginVerifySchema,
|
|
67
|
-
parseAuthCookies: () => parseAuthCookies,
|
|
64
|
+
parseAuthCookie: () => parseAuthCookie,
|
|
68
65
|
requestPasswordResetSchema: () => requestPasswordResetSchema,
|
|
69
66
|
resetPasswordSchema: () => resetPasswordSchema,
|
|
70
|
-
|
|
67
|
+
setAuthCookie: () => setAuthCookie,
|
|
71
68
|
signupSchema: () => signupSchema,
|
|
72
69
|
twoFaResetSchema: () => twoFaResetSchema,
|
|
73
|
-
twoFaSetupSchema: () => twoFaSetupSchema,
|
|
74
70
|
twoFaVerifySchema: () => twoFaVerifySchema,
|
|
75
71
|
validatePasswordStrength: () => validatePasswordStrength,
|
|
76
|
-
|
|
72
|
+
verifyAuthToken: () => verifyAuthToken,
|
|
77
73
|
verifyEmailSchema: () => verifyEmailSchema,
|
|
78
74
|
verifyTotp: () => verifyTotp
|
|
79
75
|
});
|
|
@@ -137,7 +133,8 @@ function createConsoleEmailAdapter() {
|
|
|
137
133
|
|
|
138
134
|
// src/utilities/config.ts
|
|
139
135
|
var defaultTokenSettings = {
|
|
140
|
-
|
|
136
|
+
jwtExpiry: 30 * 24 * 60 * 60,
|
|
137
|
+
// 30 days in seconds
|
|
141
138
|
passwordResetExpiryMs: 60 * 60 * 1e3,
|
|
142
139
|
// 1 hour
|
|
143
140
|
otpValidityMs: 15 * 60 * 1e3
|
|
@@ -146,15 +143,13 @@ var defaultTokenSettings = {
|
|
|
146
143
|
var defaultCookieSettings = {
|
|
147
144
|
secure: true,
|
|
148
145
|
sameSite: "Strict",
|
|
149
|
-
httpOnly:
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
// 1 year in seconds
|
|
146
|
+
httpOnly: false,
|
|
147
|
+
path: "/",
|
|
148
|
+
maxAge: 30 * 24 * 60 * 60
|
|
149
|
+
// 30 days in seconds
|
|
154
150
|
};
|
|
155
151
|
var defaultStorageKeys = {
|
|
156
|
-
|
|
157
|
-
refreshToken: "auth-rt"
|
|
152
|
+
authToken: "auth-token"
|
|
158
153
|
};
|
|
159
154
|
var defaultFeatures = {
|
|
160
155
|
twoFa: true,
|
|
@@ -186,21 +181,17 @@ var defaultAuthConfig = {
|
|
|
186
181
|
|
|
187
182
|
// src/utilities/cookies.ts
|
|
188
183
|
var DEFAULT_STORAGE_KEYS = {
|
|
189
|
-
|
|
190
|
-
REFRESH_TOKEN: "auth-rt"
|
|
184
|
+
AUTH_TOKEN: "auth-token"
|
|
191
185
|
};
|
|
192
|
-
function
|
|
193
|
-
|
|
194
|
-
refreshToken: DEFAULT_STORAGE_KEYS.REFRESH_TOKEN
|
|
186
|
+
function parseAuthCookie(cookieHeader, storageKeys = {
|
|
187
|
+
authToken: DEFAULT_STORAGE_KEYS.AUTH_TOKEN
|
|
195
188
|
}) {
|
|
196
189
|
if (!cookieHeader) {
|
|
197
190
|
return {};
|
|
198
191
|
}
|
|
199
|
-
const
|
|
200
|
-
const refreshToken = cookieHeader.split(`${storageKeys.refreshToken}=`)[1]?.split(";")[0];
|
|
192
|
+
const authToken = cookieHeader.split(`${storageKeys.authToken}=`)[1]?.split(";")[0];
|
|
201
193
|
return {
|
|
202
|
-
|
|
203
|
-
refreshToken: refreshToken || void 0
|
|
194
|
+
authToken: authToken || void 0
|
|
204
195
|
};
|
|
205
196
|
}
|
|
206
197
|
function extractDomain(req) {
|
|
@@ -224,76 +215,47 @@ function extractDomain(req) {
|
|
|
224
215
|
}
|
|
225
216
|
return void 0;
|
|
226
217
|
}
|
|
227
|
-
function
|
|
228
|
-
|
|
229
|
-
refreshToken: DEFAULT_STORAGE_KEYS.REFRESH_TOKEN
|
|
218
|
+
function setAuthCookie(res, authToken, settings, storageKeys = {
|
|
219
|
+
authToken: DEFAULT_STORAGE_KEYS.AUTH_TOKEN
|
|
230
220
|
}) {
|
|
231
|
-
const cookies = [];
|
|
232
221
|
const domain = settings.domain ?? extractDomain(res.req);
|
|
233
222
|
const expiresDate = settings.maxAge ? new Date(Date.now() + settings.maxAge * 1e3).toUTCString() : void 0;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
cookies.push(refreshCookie);
|
|
245
|
-
}
|
|
246
|
-
if (credentials.accessToken) {
|
|
247
|
-
const accessCookie = [
|
|
248
|
-
`${storageKeys.accessToken}=${credentials.accessToken}`,
|
|
249
|
-
settings.secure ? "Secure=true" : "",
|
|
250
|
-
`SameSite=${settings.sameSite}`,
|
|
251
|
-
`Path=${settings.accessTokenPath}`,
|
|
252
|
-
domain ? `Domain=${domain}` : "",
|
|
253
|
-
`Expires=${expiresDate}`
|
|
254
|
-
].filter(Boolean).join("; ");
|
|
255
|
-
cookies.push(accessCookie);
|
|
256
|
-
}
|
|
257
|
-
if (cookies.length > 0) {
|
|
258
|
-
res.setHeader("Set-Cookie", cookies);
|
|
259
|
-
}
|
|
223
|
+
const cookie = [
|
|
224
|
+
`${storageKeys.authToken}=${authToken}`,
|
|
225
|
+
settings.httpOnly ? "HttpOnly" : "",
|
|
226
|
+
settings.secure ? "Secure=true" : "",
|
|
227
|
+
`SameSite=${settings.sameSite}`,
|
|
228
|
+
`Path=${settings.path ?? "/"}`,
|
|
229
|
+
domain ? `Domain=${domain}` : "",
|
|
230
|
+
expiresDate ? `Expires=${expiresDate}` : ""
|
|
231
|
+
].filter(Boolean).join("; ");
|
|
232
|
+
res.setHeader("Set-Cookie", cookie);
|
|
260
233
|
}
|
|
261
|
-
function
|
|
262
|
-
|
|
263
|
-
refreshToken: DEFAULT_STORAGE_KEYS.REFRESH_TOKEN
|
|
234
|
+
function clearAuthCookie(res, settings, storageKeys = {
|
|
235
|
+
authToken: DEFAULT_STORAGE_KEYS.AUTH_TOKEN
|
|
264
236
|
}) {
|
|
265
237
|
const domain = extractDomain(res.req);
|
|
266
238
|
const expiredDate = (/* @__PURE__ */ new Date(0)).toUTCString();
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
[
|
|
278
|
-
`${storageKeys.accessToken}=destroy`,
|
|
279
|
-
settings.secure ? "Secure=true" : "",
|
|
280
|
-
`SameSite=${settings.sameSite}`,
|
|
281
|
-
`Path=${settings.accessTokenPath}`,
|
|
282
|
-
domain ? `Domain=${domain}` : "",
|
|
283
|
-
`Expires=${expiredDate}`
|
|
284
|
-
].filter(Boolean).join("; ")
|
|
285
|
-
];
|
|
286
|
-
res.setHeader("Set-Cookie", cookies);
|
|
239
|
+
const cookie = [
|
|
240
|
+
`${storageKeys.authToken}=destroy`,
|
|
241
|
+
settings.httpOnly ? "HttpOnly" : "",
|
|
242
|
+
settings.secure ? "Secure=true" : "",
|
|
243
|
+
`SameSite=${settings.sameSite}`,
|
|
244
|
+
`Path=${settings.path ?? "/"}`,
|
|
245
|
+
domain ? `Domain=${domain}` : "",
|
|
246
|
+
`Expires=${expiredDate}`
|
|
247
|
+
].filter(Boolean).join("; ");
|
|
248
|
+
res.setHeader("Set-Cookie", cookie);
|
|
287
249
|
}
|
|
288
250
|
|
|
289
251
|
// src/utilities/jwt.ts
|
|
290
252
|
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
|
|
291
|
-
function
|
|
253
|
+
function createAuthToken(payload, options) {
|
|
292
254
|
return import_jsonwebtoken.default.sign(payload, options.secret, {
|
|
293
255
|
expiresIn: options.expiresIn
|
|
294
256
|
});
|
|
295
257
|
}
|
|
296
|
-
function
|
|
258
|
+
function verifyAuthToken(token, options) {
|
|
297
259
|
return import_jsonwebtoken.default.verify(token, options.secret, {
|
|
298
260
|
ignoreExpiration: options.ignoreExpiration ?? false
|
|
299
261
|
});
|
|
@@ -320,9 +282,10 @@ function createAuthGuard(config, t) {
|
|
|
320
282
|
const storageKeys = config.storageKeys ?? defaultStorageKeys;
|
|
321
283
|
const cookieSettings = { ...defaultCookieSettings, ...config.cookieSettings };
|
|
322
284
|
const revokeSession = async (ctx, sessionId, description, errorStack, path) => {
|
|
323
|
-
|
|
285
|
+
clearAuthCookie(ctx.res, cookieSettings, storageKeys);
|
|
324
286
|
if (config.hooks?.logError) {
|
|
325
287
|
try {
|
|
288
|
+
const cookieHeader = ctx.headers.cookie;
|
|
326
289
|
const contextInfo = {
|
|
327
290
|
reason: description,
|
|
328
291
|
sessionId,
|
|
@@ -330,6 +293,10 @@ function createAuthGuard(config, t) {
|
|
|
330
293
|
ip: ctx.ip,
|
|
331
294
|
userAgent: ctx.headers["user-agent"],
|
|
332
295
|
...path ? { path } : {},
|
|
296
|
+
hasCookieHeader: Boolean(cookieHeader),
|
|
297
|
+
cookieKeys: cookieHeader ? cookieHeader.split(";").map((c) => c.trim().split("=")[0]).filter(Boolean) : [],
|
|
298
|
+
origin: ctx.headers.origin ?? null,
|
|
299
|
+
referer: ctx.headers.referer ?? null,
|
|
333
300
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
334
301
|
};
|
|
335
302
|
const combinedStack = [
|
|
@@ -368,9 +335,8 @@ ${errorStack}` : null,
|
|
|
368
335
|
}
|
|
369
336
|
};
|
|
370
337
|
const authGuard = t.middleware(async ({ ctx, meta, next, path }) => {
|
|
371
|
-
const cookies =
|
|
372
|
-
const authToken = cookies.
|
|
373
|
-
const refreshToken = cookies.refreshToken;
|
|
338
|
+
const cookies = parseAuthCookie(ctx.headers.cookie, storageKeys);
|
|
339
|
+
const authToken = cookies.authToken;
|
|
374
340
|
const userAgent = ctx.headers["user-agent"];
|
|
375
341
|
if (!userAgent) {
|
|
376
342
|
throw new import_server.TRPCError({
|
|
@@ -380,27 +346,13 @@ ${errorStack}` : null,
|
|
|
380
346
|
}
|
|
381
347
|
if (authToken) {
|
|
382
348
|
try {
|
|
383
|
-
const decodedToken =
|
|
349
|
+
const decodedToken = verifyAuthToken(authToken, {
|
|
384
350
|
secret: config.secrets.jwt,
|
|
385
351
|
ignoreExpiration: meta?.ignoreExpiration ?? false
|
|
386
352
|
});
|
|
387
|
-
if (path === "auth.refresh" && !refreshToken) {
|
|
388
|
-
await revokeSession(
|
|
389
|
-
ctx,
|
|
390
|
-
decodedToken.id,
|
|
391
|
-
"Session revoked: No refresh token",
|
|
392
|
-
void 0,
|
|
393
|
-
path
|
|
394
|
-
);
|
|
395
|
-
throw new import_server.TRPCError({
|
|
396
|
-
message: "Unauthorized",
|
|
397
|
-
code: "UNAUTHORIZED"
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
353
|
const session = await config.prisma.session.findUnique({
|
|
401
354
|
where: {
|
|
402
|
-
id: decodedToken.id
|
|
403
|
-
...path === "auth.refresh" ? { refreshToken } : {}
|
|
355
|
+
id: decodedToken.id
|
|
404
356
|
},
|
|
405
357
|
select: {
|
|
406
358
|
userId: true,
|
|
@@ -491,8 +443,7 @@ ${errorStack}` : null,
|
|
|
491
443
|
...ctx,
|
|
492
444
|
userId: session.userId,
|
|
493
445
|
socketId: session.socketId,
|
|
494
|
-
sessionId: session.id
|
|
495
|
-
refreshToken
|
|
446
|
+
sessionId: session.id
|
|
496
447
|
}
|
|
497
448
|
});
|
|
498
449
|
} catch (err) {
|
|
@@ -537,7 +488,6 @@ ${errorStack}` : null,
|
|
|
537
488
|
}
|
|
538
489
|
|
|
539
490
|
// src/procedures/base.ts
|
|
540
|
-
var import_node_crypto = require("crypto");
|
|
541
491
|
var import_server2 = require("@trpc/server");
|
|
542
492
|
|
|
543
493
|
// src/utilities/browser.ts
|
|
@@ -736,9 +686,6 @@ var twoFaVerifySchema = import_zod.z.object({
|
|
|
736
686
|
code: import_zod.z.string().min(6, { message: "Verification code is required" }),
|
|
737
687
|
sessionId: import_zod.z.number().optional()
|
|
738
688
|
});
|
|
739
|
-
var twoFaSetupSchema = import_zod.z.object({
|
|
740
|
-
code: import_zod.z.string().min(6, { message: "Verification code is required" })
|
|
741
|
-
});
|
|
742
689
|
var twoFaResetSchema = import_zod.z.object({
|
|
743
690
|
username: import_zod.z.string().min(1),
|
|
744
691
|
password: import_zod.z.string().min(1)
|
|
@@ -750,9 +697,6 @@ var twoFaResetVerifySchema = import_zod.z.object({
|
|
|
750
697
|
var verifyEmailSchema = import_zod.z.object({
|
|
751
698
|
code: import_zod.z.string().min(1, { message: "Verification code is required" })
|
|
752
699
|
});
|
|
753
|
-
var resendVerificationSchema = import_zod.z.object({
|
|
754
|
-
email: import_zod.z.string().email().optional()
|
|
755
|
-
});
|
|
756
700
|
var biometricVerifySchema = import_zod.z.object({});
|
|
757
701
|
var registerPushTokenSchema = import_zod.z.object({
|
|
758
702
|
pushToken: import_zod.z.string().min(1, { message: "Push token is required" })
|
|
@@ -766,19 +710,9 @@ var getTwofaSecretSchema = import_zod.z.object({
|
|
|
766
710
|
var disableTwofaSchema = import_zod.z.object({
|
|
767
711
|
password: import_zod.z.string().min(1, { message: "Password is required" })
|
|
768
712
|
});
|
|
769
|
-
var logoutSchema = import_zod.z.object({
|
|
770
|
-
allDevices: import_zod.z.boolean().optional().default(false)
|
|
771
|
-
});
|
|
772
713
|
var endAllSessionsSchema = import_zod.z.object({
|
|
773
714
|
skipCurrentSession: import_zod.z.boolean().optional().default(true)
|
|
774
715
|
});
|
|
775
|
-
var otpLoginRequestSchema = import_zod.z.object({
|
|
776
|
-
email: import_zod.z.string().email({ message: "Invalid email address" })
|
|
777
|
-
});
|
|
778
|
-
var otpLoginVerifySchema = import_zod.z.object({
|
|
779
|
-
email: import_zod.z.string().email(),
|
|
780
|
-
code: import_zod.z.number().min(1e5).max(999999)
|
|
781
|
-
});
|
|
782
716
|
function createSchemas(extensions) {
|
|
783
717
|
return {
|
|
784
718
|
signup: extensions?.signup ? signupSchema.merge(extensions.signup) : signupSchema,
|
|
@@ -857,31 +791,29 @@ var BaseProcedureFactory = class {
|
|
|
857
791
|
if (this.config.hooks?.onUserCreated) {
|
|
858
792
|
await this.config.hooks.onUserCreated(user.id, typedInput);
|
|
859
793
|
}
|
|
860
|
-
const refreshToken = (0, import_node_crypto.randomUUID)();
|
|
861
794
|
const extraSessionData = this.config.hooks?.getSessionData ? await this.config.hooks.getSessionData(typedInput) : {};
|
|
862
795
|
const session = await this.config.prisma.session.create({
|
|
863
796
|
data: {
|
|
864
797
|
userId: user.id,
|
|
865
798
|
browserName: detectBrowser(userAgent),
|
|
866
799
|
socketId: null,
|
|
867
|
-
refreshToken,
|
|
868
800
|
...extraSessionData
|
|
869
801
|
},
|
|
870
|
-
select: { id: true,
|
|
802
|
+
select: { id: true, userId: true }
|
|
871
803
|
});
|
|
872
804
|
if (this.config.hooks?.onSessionCreated) {
|
|
873
805
|
await this.config.hooks.onSessionCreated(session.id, typedInput);
|
|
874
806
|
}
|
|
875
|
-
const
|
|
807
|
+
const authToken = createAuthToken(
|
|
876
808
|
{ id: session.id, userId: session.userId, verifiedHumanAt: null },
|
|
877
809
|
{
|
|
878
810
|
secret: this.config.secrets.jwt,
|
|
879
|
-
expiresIn: this.config.tokenSettings.
|
|
811
|
+
expiresIn: this.config.tokenSettings.jwtExpiry
|
|
880
812
|
}
|
|
881
813
|
);
|
|
882
|
-
|
|
814
|
+
setAuthCookie(
|
|
883
815
|
ctx.res,
|
|
884
|
-
|
|
816
|
+
authToken,
|
|
885
817
|
this.config.cookieSettings,
|
|
886
818
|
this.config.storageKeys
|
|
887
819
|
);
|
|
@@ -973,19 +905,13 @@ var BaseProcedureFactory = class {
|
|
|
973
905
|
}
|
|
974
906
|
}
|
|
975
907
|
if (!validCode) {
|
|
976
|
-
const checkOTP = await this.config.prisma.
|
|
977
|
-
where: {
|
|
978
|
-
code: Number(code),
|
|
979
|
-
userId: user.id,
|
|
980
|
-
disabled: false,
|
|
981
|
-
createdAt: { gte: new Date(Date.now() - this.config.tokenSettings.otpValidityMs) }
|
|
982
|
-
}
|
|
908
|
+
const checkOTP = await this.config.prisma.oTP.findUnique({
|
|
909
|
+
where: { userId: user.id }
|
|
983
910
|
});
|
|
984
|
-
if (checkOTP) {
|
|
911
|
+
if (checkOTP && checkOTP.code === Number(code) && checkOTP.expiredAt >= /* @__PURE__ */ new Date()) {
|
|
985
912
|
validCode = true;
|
|
986
|
-
await this.config.prisma.
|
|
987
|
-
where: {
|
|
988
|
-
data: { disabled: true }
|
|
913
|
+
await this.config.prisma.oTP.delete({
|
|
914
|
+
where: { userId: user.id }
|
|
989
915
|
});
|
|
990
916
|
}
|
|
991
917
|
}
|
|
@@ -996,19 +922,16 @@ var BaseProcedureFactory = class {
|
|
|
996
922
|
});
|
|
997
923
|
}
|
|
998
924
|
}
|
|
999
|
-
const refreshToken = (0, import_node_crypto.randomUUID)();
|
|
1000
925
|
const extraSessionData = this.config.hooks?.getSessionData ? await this.config.hooks.getSessionData(typedInput) : {};
|
|
1001
926
|
const session = await this.config.prisma.session.create({
|
|
1002
927
|
data: {
|
|
1003
928
|
userId: user.id,
|
|
1004
929
|
browserName: detectBrowser(userAgent),
|
|
1005
930
|
socketId: null,
|
|
1006
|
-
refreshToken,
|
|
1007
931
|
...extraSessionData
|
|
1008
932
|
},
|
|
1009
933
|
select: {
|
|
1010
934
|
id: true,
|
|
1011
|
-
refreshToken: true,
|
|
1012
935
|
userId: true,
|
|
1013
936
|
socketId: true,
|
|
1014
937
|
browserName: true,
|
|
@@ -1025,16 +948,16 @@ var BaseProcedureFactory = class {
|
|
|
1025
948
|
if (this.config.hooks?.onSessionCreated) {
|
|
1026
949
|
await this.config.hooks.onSessionCreated(session.id, typedInput);
|
|
1027
950
|
}
|
|
1028
|
-
const
|
|
951
|
+
const authToken = createAuthToken(
|
|
1029
952
|
{ id: session.id, userId: session.userId, verifiedHumanAt: user.verifiedHumanAt },
|
|
1030
953
|
{
|
|
1031
954
|
secret: this.config.secrets.jwt,
|
|
1032
|
-
expiresIn: this.config.tokenSettings.
|
|
955
|
+
expiresIn: this.config.tokenSettings.jwtExpiry
|
|
1033
956
|
}
|
|
1034
957
|
);
|
|
1035
|
-
|
|
958
|
+
setAuthCookie(
|
|
1036
959
|
ctx.res,
|
|
1037
|
-
|
|
960
|
+
authToken,
|
|
1038
961
|
this.config.cookieSettings,
|
|
1039
962
|
this.config.storageKeys
|
|
1040
963
|
);
|
|
@@ -1045,7 +968,7 @@ var BaseProcedureFactory = class {
|
|
|
1045
968
|
});
|
|
1046
969
|
}
|
|
1047
970
|
logout() {
|
|
1048
|
-
return this.
|
|
971
|
+
return this.authProcedure.meta({ ignoreExpiration: true }).mutation(async ({ ctx }) => {
|
|
1049
972
|
const { userId, sessionId } = ctx;
|
|
1050
973
|
if (sessionId) {
|
|
1051
974
|
await this.config.prisma.session.update({
|
|
@@ -1062,18 +985,17 @@ var BaseProcedureFactory = class {
|
|
|
1062
985
|
await this.config.hooks.afterLogout(userId, sessionId, ctx.socketId);
|
|
1063
986
|
}
|
|
1064
987
|
}
|
|
1065
|
-
|
|
988
|
+
clearAuthCookie(ctx.res, this.config.cookieSettings, this.config.storageKeys);
|
|
1066
989
|
return { success: true };
|
|
1067
990
|
});
|
|
1068
991
|
}
|
|
1069
992
|
refresh() {
|
|
1070
|
-
return this.authProcedure.
|
|
993
|
+
return this.authProcedure.query(async ({ ctx }) => {
|
|
1071
994
|
const session = await this.config.prisma.session.update({
|
|
1072
995
|
where: { id: ctx.sessionId },
|
|
1073
|
-
data: {
|
|
996
|
+
data: { lastUsed: /* @__PURE__ */ new Date() },
|
|
1074
997
|
select: {
|
|
1075
998
|
id: true,
|
|
1076
|
-
refreshToken: true,
|
|
1077
999
|
userId: true,
|
|
1078
1000
|
user: { select: { verifiedHumanAt: true } }
|
|
1079
1001
|
}
|
|
@@ -1082,16 +1004,16 @@ var BaseProcedureFactory = class {
|
|
|
1082
1004
|
this.config.hooks.onRefresh(session.userId).catch(() => {
|
|
1083
1005
|
});
|
|
1084
1006
|
}
|
|
1085
|
-
const
|
|
1007
|
+
const authToken = createAuthToken(
|
|
1086
1008
|
{ id: session.id, userId: session.userId, verifiedHumanAt: session.user.verifiedHumanAt },
|
|
1087
1009
|
{
|
|
1088
1010
|
secret: this.config.secrets.jwt,
|
|
1089
|
-
expiresIn: this.config.tokenSettings.
|
|
1011
|
+
expiresIn: this.config.tokenSettings.jwtExpiry
|
|
1090
1012
|
}
|
|
1091
1013
|
);
|
|
1092
|
-
|
|
1014
|
+
setAuthCookie(
|
|
1093
1015
|
ctx.res,
|
|
1094
|
-
|
|
1016
|
+
authToken,
|
|
1095
1017
|
this.config.cookieSettings,
|
|
1096
1018
|
this.config.storageKeys
|
|
1097
1019
|
);
|
|
@@ -1319,7 +1241,7 @@ var BiometricProcedureFactory = class {
|
|
|
1319
1241
|
};
|
|
1320
1242
|
|
|
1321
1243
|
// src/procedures/emailVerification.ts
|
|
1322
|
-
var
|
|
1244
|
+
var import_node_crypto = require("crypto");
|
|
1323
1245
|
var import_server4 = require("@trpc/server");
|
|
1324
1246
|
var EmailVerificationProcedureFactory = class {
|
|
1325
1247
|
constructor(config, authProcedure) {
|
|
@@ -1352,7 +1274,7 @@ var EmailVerificationProcedureFactory = class {
|
|
|
1352
1274
|
if (user.emailVerificationStatus === "VERIFIED") {
|
|
1353
1275
|
return { message: "Email is already verified", emailSent: false };
|
|
1354
1276
|
}
|
|
1355
|
-
const otp = (0,
|
|
1277
|
+
const otp = (0, import_node_crypto.randomUUID)();
|
|
1356
1278
|
await this.config.prisma.user.update({
|
|
1357
1279
|
where: { id: userId },
|
|
1358
1280
|
data: { emailVerificationStatus: "PENDING", otpForEmailVerification: otp }
|
|
@@ -1417,7 +1339,6 @@ var EmailVerificationProcedureFactory = class {
|
|
|
1417
1339
|
};
|
|
1418
1340
|
|
|
1419
1341
|
// src/procedures/oauth.ts
|
|
1420
|
-
var import_node_crypto3 = require("crypto");
|
|
1421
1342
|
var import_server5 = require("@trpc/server");
|
|
1422
1343
|
var OAuthLoginProcedureFactory = class {
|
|
1423
1344
|
constructor(config, procedure) {
|
|
@@ -1516,19 +1437,16 @@ var OAuthLoginProcedureFactory = class {
|
|
|
1516
1437
|
if (user.status === "BANNED") {
|
|
1517
1438
|
throw new import_server5.TRPCError({ code: "FORBIDDEN", message: "Your account has been banned." });
|
|
1518
1439
|
}
|
|
1519
|
-
const refreshToken = (0, import_node_crypto3.randomUUID)();
|
|
1520
1440
|
const extraSessionData = this.config.hooks?.getSessionData ? await this.config.hooks.getSessionData(typedInput) : {};
|
|
1521
1441
|
const session = await this.config.prisma.session.create({
|
|
1522
1442
|
data: {
|
|
1523
1443
|
userId: user.id,
|
|
1524
1444
|
browserName: detectBrowser(userAgent),
|
|
1525
1445
|
socketId: null,
|
|
1526
|
-
refreshToken,
|
|
1527
1446
|
...extraSessionData
|
|
1528
1447
|
},
|
|
1529
1448
|
select: {
|
|
1530
1449
|
id: true,
|
|
1531
|
-
refreshToken: true,
|
|
1532
1450
|
userId: true,
|
|
1533
1451
|
socketId: true,
|
|
1534
1452
|
browserName: true,
|
|
@@ -1545,16 +1463,16 @@ var OAuthLoginProcedureFactory = class {
|
|
|
1545
1463
|
if (this.config.hooks?.onSessionCreated) {
|
|
1546
1464
|
await this.config.hooks.onSessionCreated(session.id, typedInput);
|
|
1547
1465
|
}
|
|
1548
|
-
const
|
|
1466
|
+
const authToken = createAuthToken(
|
|
1549
1467
|
{ id: session.id, userId: session.userId, verifiedHumanAt: user.verifiedHumanAt ?? null },
|
|
1550
1468
|
{
|
|
1551
1469
|
secret: this.config.secrets.jwt,
|
|
1552
|
-
expiresIn: this.config.tokenSettings.
|
|
1470
|
+
expiresIn: this.config.tokenSettings.jwtExpiry
|
|
1553
1471
|
}
|
|
1554
1472
|
);
|
|
1555
|
-
|
|
1473
|
+
setAuthCookie(
|
|
1556
1474
|
ctx.res,
|
|
1557
|
-
|
|
1475
|
+
authToken,
|
|
1558
1476
|
this.config.cookieSettings,
|
|
1559
1477
|
this.config.storageKeys
|
|
1560
1478
|
);
|
|
@@ -1752,8 +1670,11 @@ var TwoFaProcedureFactory = class {
|
|
|
1752
1670
|
throw new import_server6.TRPCError({ code: "FORBIDDEN", message: "Invalid credentials." });
|
|
1753
1671
|
}
|
|
1754
1672
|
const otp = generateOtp();
|
|
1755
|
-
|
|
1756
|
-
|
|
1673
|
+
const expiredAt = new Date(Date.now() + this.config.tokenSettings.otpValidityMs);
|
|
1674
|
+
await this.config.prisma.oTP.upsert({
|
|
1675
|
+
where: { userId: user.id },
|
|
1676
|
+
update: { code: otp, expiredAt },
|
|
1677
|
+
create: { userId: user.id, code: otp, expiredAt }
|
|
1757
1678
|
});
|
|
1758
1679
|
if (this.config.emailService) {
|
|
1759
1680
|
await this.config.emailService.sendOTPEmail(user.email, otp);
|
|
@@ -1772,20 +1693,14 @@ var TwoFaProcedureFactory = class {
|
|
|
1772
1693
|
if (!user) {
|
|
1773
1694
|
throw new import_server6.TRPCError({ code: "NOT_FOUND", message: "User not found" });
|
|
1774
1695
|
}
|
|
1775
|
-
const otp = await this.config.prisma.
|
|
1776
|
-
where: {
|
|
1777
|
-
userId: user.id,
|
|
1778
|
-
code,
|
|
1779
|
-
disabled: false,
|
|
1780
|
-
createdAt: { gte: new Date(Date.now() - this.config.tokenSettings.otpValidityMs) }
|
|
1781
|
-
}
|
|
1696
|
+
const otp = await this.config.prisma.oTP.findUnique({
|
|
1697
|
+
where: { userId: user.id }
|
|
1782
1698
|
});
|
|
1783
|
-
if (!otp) {
|
|
1699
|
+
if (!otp || otp.code !== code || otp.expiredAt < /* @__PURE__ */ new Date()) {
|
|
1784
1700
|
throw new import_server6.TRPCError({ code: "FORBIDDEN", message: "Invalid or expired OTP" });
|
|
1785
1701
|
}
|
|
1786
|
-
await this.config.prisma.
|
|
1787
|
-
where: {
|
|
1788
|
-
data: { disabled: true }
|
|
1702
|
+
await this.config.prisma.oTP.delete({
|
|
1703
|
+
where: { userId: user.id }
|
|
1789
1704
|
});
|
|
1790
1705
|
await this.config.prisma.user.update({
|
|
1791
1706
|
where: { id: user.id },
|
|
@@ -1838,21 +1753,35 @@ var TwoFaProcedureFactory = class {
|
|
|
1838
1753
|
});
|
|
1839
1754
|
}
|
|
1840
1755
|
deregisterPushToken() {
|
|
1841
|
-
return this.authProcedure.
|
|
1756
|
+
return this.authProcedure.input(deregisterPushTokenSchema).mutation(async ({ ctx, input }) => {
|
|
1842
1757
|
this.checkConfig();
|
|
1843
1758
|
const { userId } = ctx;
|
|
1844
1759
|
const { pushToken } = input;
|
|
1845
1760
|
const device = await this.config.prisma.device.findFirst({
|
|
1846
1761
|
where: {
|
|
1847
|
-
|
|
1762
|
+
users: { some: { id: userId } },
|
|
1848
1763
|
pushToken
|
|
1849
1764
|
},
|
|
1850
1765
|
select: { id: true }
|
|
1851
1766
|
});
|
|
1852
1767
|
if (device) {
|
|
1853
|
-
await this.config.prisma.
|
|
1854
|
-
where: {
|
|
1768
|
+
await this.config.prisma.session.updateMany({
|
|
1769
|
+
where: { userId, deviceId: device.id },
|
|
1770
|
+
data: { deviceId: null }
|
|
1855
1771
|
});
|
|
1772
|
+
await this.config.prisma.device.update({
|
|
1773
|
+
where: { id: device.id },
|
|
1774
|
+
data: { users: { disconnect: { id: userId } } }
|
|
1775
|
+
});
|
|
1776
|
+
const remainingUsers = await this.config.prisma.device.findUnique({
|
|
1777
|
+
where: { id: device.id },
|
|
1778
|
+
select: { users: { select: { id: true }, take: 1 } }
|
|
1779
|
+
});
|
|
1780
|
+
if (!remainingUsers?.users.length) {
|
|
1781
|
+
await this.config.prisma.device.delete({
|
|
1782
|
+
where: { id: device.id }
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1856
1785
|
}
|
|
1857
1786
|
return { deregistered: true };
|
|
1858
1787
|
});
|
|
@@ -1943,7 +1872,6 @@ var createContext = ({ req, res }) => ({
|
|
|
1943
1872
|
headers: req.headers,
|
|
1944
1873
|
userId: null,
|
|
1945
1874
|
sessionId: null,
|
|
1946
|
-
refreshToken: null,
|
|
1947
1875
|
socketId: null,
|
|
1948
1876
|
ip: getClientIp(req),
|
|
1949
1877
|
res
|
|
@@ -2003,12 +1931,12 @@ function createAuthRouter(config) {
|
|
|
2003
1931
|
biometricVerifySchema,
|
|
2004
1932
|
changePasswordSchema,
|
|
2005
1933
|
cleanBase32String,
|
|
2006
|
-
|
|
1934
|
+
clearAuthCookie,
|
|
2007
1935
|
comparePassword,
|
|
2008
|
-
createAccessToken,
|
|
2009
1936
|
createAuthConfig,
|
|
2010
1937
|
createAuthGuard,
|
|
2011
1938
|
createAuthRouter,
|
|
1939
|
+
createAuthToken,
|
|
2012
1940
|
createConsoleEmailAdapter,
|
|
2013
1941
|
createNoopEmailAdapter,
|
|
2014
1942
|
createOAuthVerifier,
|
|
@@ -2028,20 +1956,16 @@ function createAuthRouter(config) {
|
|
|
2028
1956
|
isTokenExpiredError,
|
|
2029
1957
|
isTokenInvalidError,
|
|
2030
1958
|
loginSchema,
|
|
2031
|
-
logoutSchema,
|
|
2032
1959
|
oAuthLoginSchema,
|
|
2033
|
-
|
|
2034
|
-
otpLoginVerifySchema,
|
|
2035
|
-
parseAuthCookies,
|
|
1960
|
+
parseAuthCookie,
|
|
2036
1961
|
requestPasswordResetSchema,
|
|
2037
1962
|
resetPasswordSchema,
|
|
2038
|
-
|
|
1963
|
+
setAuthCookie,
|
|
2039
1964
|
signupSchema,
|
|
2040
1965
|
twoFaResetSchema,
|
|
2041
|
-
twoFaSetupSchema,
|
|
2042
1966
|
twoFaVerifySchema,
|
|
2043
1967
|
validatePasswordStrength,
|
|
2044
|
-
|
|
1968
|
+
verifyAuthToken,
|
|
2045
1969
|
verifyEmailSchema,
|
|
2046
1970
|
verifyTotp
|
|
2047
1971
|
});
|