@syncello/auth 3.3.1 → 3.4.1
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 +84 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +100 -81
- package/dist/index.d.ts +100 -81
- package/dist/index.js +84 -66
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1341,11 +1341,12 @@ var import_drizzle_orm4 = require("drizzle-orm");
|
|
|
1341
1341
|
|
|
1342
1342
|
// src/factory.ts
|
|
1343
1343
|
function createAuth(config) {
|
|
1344
|
-
const { db, schema, getEnv } = config;
|
|
1344
|
+
const { db, schema, getEnv, emailBranding } = config;
|
|
1345
1345
|
const getContext = (c) => ({
|
|
1346
1346
|
db,
|
|
1347
1347
|
schema,
|
|
1348
|
-
env: getEnv(c)
|
|
1348
|
+
env: getEnv(c),
|
|
1349
|
+
emailBranding
|
|
1349
1350
|
});
|
|
1350
1351
|
return {
|
|
1351
1352
|
db,
|
|
@@ -1927,11 +1928,15 @@ function generateEmailTemplate(options) {
|
|
|
1927
1928
|
appName = "App",
|
|
1928
1929
|
buttonBgColor = "#00fe9a",
|
|
1929
1930
|
buttonTextColor = "#000004",
|
|
1930
|
-
buttonFontWeight = 500
|
|
1931
|
+
buttonFontWeight = 500,
|
|
1932
|
+
buttonRadius = "6px",
|
|
1933
|
+
logoUrl,
|
|
1934
|
+
footerColor = "#1e1b4b"
|
|
1931
1935
|
} = options;
|
|
1932
1936
|
const safeButtonUrl = buttonUrl ? sanitizeEmailUrl(buttonUrl, appUrl) : "";
|
|
1933
1937
|
const safeAppUrl = appUrl ? sanitizeEmailUrl(appUrl, appUrl) : "";
|
|
1934
1938
|
const safeMarketingUrl = marketingUrl ? sanitizeEmailUrl(marketingUrl, appUrl) : "";
|
|
1939
|
+
const safeLogoUrl = logoUrl ? sanitizeEmailUrl(logoUrl, appUrl) : `${safeAppUrl.replace(/\/$/, "")}/email-header-image.png`;
|
|
1935
1940
|
return `
|
|
1936
1941
|
<!DOCTYPE html>
|
|
1937
1942
|
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" lang="en">
|
|
@@ -2071,7 +2076,7 @@ function generateEmailTemplate(options) {
|
|
|
2071
2076
|
<td class="pad" style="padding-left:40px;padding-right:40px;width:100%;">
|
|
2072
2077
|
<div class="alignment" align="center">
|
|
2073
2078
|
<div class="fullWidth" style="max-width: 50%;">
|
|
2074
|
-
<img src="${
|
|
2079
|
+
<img src="${safeLogoUrl}" style="display: block; height: auto; border: 0; width: 100%;" alt="${appName}" title="${appName}" height="auto">
|
|
2075
2080
|
</div>
|
|
2076
2081
|
</div>
|
|
2077
2082
|
</td>
|
|
@@ -2128,7 +2133,7 @@ function generateEmailTemplate(options) {
|
|
|
2128
2133
|
<v:textbox inset="0px,0px,0px,0px">
|
|
2129
2134
|
<center dir="false" style="color:${buttonTextColor};font-family:'Montserrat',Arial,sans-serif;font-size:16px;font-weight:${buttonFontWeight};">
|
|
2130
2135
|
<![endif]-->
|
|
2131
|
-
<a href="${safeButtonUrl}" style="background-color: ${buttonBgColor}; border: 0px solid transparent; border-radius:
|
|
2136
|
+
<a href="${safeButtonUrl}" style="background-color: ${buttonBgColor}; border: 0px solid transparent; border-radius: ${buttonRadius}; color: ${buttonTextColor}; display: inline-block; font-family: 'Montserrat', Arial, sans-serif; font-size: 16px; font-weight: ${buttonFontWeight}; mso-border-alt: none; padding: 10px 20px; text-align: center; text-decoration: none; text-transform: capitalize; word-break: keep-all;">
|
|
2132
2137
|
${buttonText}
|
|
2133
2138
|
</a>
|
|
2134
2139
|
<!--[if mso]>
|
|
@@ -2219,7 +2224,7 @@ function generateEmailTemplate(options) {
|
|
|
2219
2224
|
<tbody>
|
|
2220
2225
|
<tr>
|
|
2221
2226
|
<td>
|
|
2222
|
-
<table class="row-content stack" align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color:
|
|
2227
|
+
<table class="row-content stack" align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: ${footerColor}; color: #000000; max-width: 640px; width: 100%; margin: 0 auto;">
|
|
2223
2228
|
<tbody>
|
|
2224
2229
|
<tr>
|
|
2225
2230
|
<td class="column column-1" width="100%" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; font-weight: 400; text-align: left; vertical-align: top; padding: 20px;">
|
|
@@ -2278,7 +2283,7 @@ function extractAppUrl(url) {
|
|
|
2278
2283
|
return "https://your-domain.com";
|
|
2279
2284
|
}
|
|
2280
2285
|
}
|
|
2281
|
-
function generateVerificationEmail(data, appName = "Your App", configuredAppUrl = "") {
|
|
2286
|
+
function generateVerificationEmail(data, appName = "Your App", configuredAppUrl = "", branding) {
|
|
2282
2287
|
const { email, verificationUrl, firstName } = data;
|
|
2283
2288
|
const appUrl = configuredAppUrl;
|
|
2284
2289
|
const safeUrl = sanitizeEmailUrl(verificationUrl, appUrl);
|
|
@@ -2288,12 +2293,10 @@ function generateVerificationEmail(data, appName = "Your App", configuredAppUrl
|
|
|
2288
2293
|
body: `Please verify that your email address is <strong>${escapeHtml(email)}</strong>, and that you entered it when signing up for ${escapeHtml(appName)}.`,
|
|
2289
2294
|
buttonText: "Verify Email",
|
|
2290
2295
|
buttonUrl: safeUrl,
|
|
2291
|
-
buttonBgColor: "#00fe9a",
|
|
2292
|
-
buttonTextColor: "#000004",
|
|
2293
|
-
buttonFontWeight: 500,
|
|
2294
2296
|
welcomeMessage: safeFirstName ? `Hi ${safeFirstName}, Welcome to ${escapeHtml(appName)}!` : void 0,
|
|
2295
2297
|
footerNote: "",
|
|
2296
|
-
appUrl
|
|
2298
|
+
appUrl,
|
|
2299
|
+
...branding
|
|
2297
2300
|
});
|
|
2298
2301
|
return {
|
|
2299
2302
|
to: email,
|
|
@@ -2313,7 +2316,7 @@ If you didn't create an account with ${appName}, you can safely ignore this emai
|
|
|
2313
2316
|
}
|
|
2314
2317
|
};
|
|
2315
2318
|
}
|
|
2316
|
-
function generatePasswordResetEmail(data, appName = "Your App", configuredAppUrl = "") {
|
|
2319
|
+
function generatePasswordResetEmail(data, appName = "Your App", configuredAppUrl = "", branding) {
|
|
2317
2320
|
const { email, resetUrl } = data;
|
|
2318
2321
|
const appUrl = configuredAppUrl;
|
|
2319
2322
|
const safeUrl = sanitizeEmailUrl(resetUrl, appUrl);
|
|
@@ -2322,15 +2325,13 @@ function generatePasswordResetEmail(data, appName = "Your App", configuredAppUrl
|
|
|
2322
2325
|
body: "We received a request to reset your password. Click the button below to create a new password.",
|
|
2323
2326
|
buttonText: "Reset Password",
|
|
2324
2327
|
buttonUrl: safeUrl,
|
|
2325
|
-
buttonBgColor: "#00fe9a",
|
|
2326
|
-
buttonTextColor: "#000004",
|
|
2327
|
-
buttonFontWeight: 500,
|
|
2328
2328
|
securityWarning: `
|
|
2329
2329
|
<strong>Link expires in 1 hour.</strong><br>
|
|
2330
2330
|
For security, this link can only be used once.
|
|
2331
2331
|
`,
|
|
2332
2332
|
footerNote: "If you didn't request this change, no action is needed. Your password will remain unchanged.",
|
|
2333
|
-
appUrl
|
|
2333
|
+
appUrl,
|
|
2334
|
+
...branding
|
|
2334
2335
|
});
|
|
2335
2336
|
return {
|
|
2336
2337
|
to: email,
|
|
@@ -2350,7 +2351,7 @@ If you didn't request a password reset, you can safely ignore this email.`,
|
|
|
2350
2351
|
}
|
|
2351
2352
|
};
|
|
2352
2353
|
}
|
|
2353
|
-
function generateEmailChangeConfirmation(data, appName = "Your App", configuredAppUrl = "") {
|
|
2354
|
+
function generateEmailChangeConfirmation(data, appName = "Your App", configuredAppUrl = "", branding) {
|
|
2354
2355
|
const { newEmail, confirmUrl } = data;
|
|
2355
2356
|
const appUrl = configuredAppUrl;
|
|
2356
2357
|
const safeUrl = sanitizeEmailUrl(confirmUrl, appUrl);
|
|
@@ -2359,15 +2360,13 @@ function generateEmailChangeConfirmation(data, appName = "Your App", configuredA
|
|
|
2359
2360
|
body: `We received a request to change your ${escapeHtml(appName)} account email to this address. Click the button below to confirm this change.`,
|
|
2360
2361
|
buttonText: "Confirm Email Change",
|
|
2361
2362
|
buttonUrl: safeUrl,
|
|
2362
|
-
buttonBgColor: "#00fe9a",
|
|
2363
|
-
buttonTextColor: "#000004",
|
|
2364
|
-
buttonFontWeight: 500,
|
|
2365
2363
|
securityWarning: `
|
|
2366
2364
|
<strong>This link expires in 24 hours.</strong><br>
|
|
2367
2365
|
For security, this link can only be used once.
|
|
2368
2366
|
`,
|
|
2369
2367
|
footerNote: "If you didn't request this change, you can safely ignore this email.",
|
|
2370
|
-
appUrl
|
|
2368
|
+
appUrl,
|
|
2369
|
+
...branding
|
|
2371
2370
|
});
|
|
2372
2371
|
return {
|
|
2373
2372
|
to: newEmail,
|
|
@@ -2389,7 +2388,7 @@ If you didn't request this change, you can safely ignore this email.`,
|
|
|
2389
2388
|
}
|
|
2390
2389
|
};
|
|
2391
2390
|
}
|
|
2392
|
-
function generateEmailChangeNotification(data, appName = "Your App", configuredAppUrl = "") {
|
|
2391
|
+
function generateEmailChangeNotification(data, appName = "Your App", configuredAppUrl = "", branding) {
|
|
2393
2392
|
const { oldEmail, newEmail, cancelUrl } = data;
|
|
2394
2393
|
const appUrl = configuredAppUrl;
|
|
2395
2394
|
const safeUrl = sanitizeEmailUrl(cancelUrl, appUrl);
|
|
@@ -2399,15 +2398,13 @@ function generateEmailChangeNotification(data, appName = "Your App", configuredA
|
|
|
2399
2398
|
body: `Someone requested to change your ${escapeHtml(appName)} account email to <strong>${safeNewEmail}</strong>.`,
|
|
2400
2399
|
buttonText: "This Wasn't Me - Cancel Change",
|
|
2401
2400
|
buttonUrl: safeUrl,
|
|
2402
|
-
buttonBgColor: "#00fe9a",
|
|
2403
|
-
buttonTextColor: "#000004",
|
|
2404
|
-
buttonFontWeight: 500,
|
|
2405
2401
|
securityWarning: `
|
|
2406
2402
|
If you made this request, no action is needed.<br>
|
|
2407
2403
|
Complete the change by clicking the link sent to your new email address.
|
|
2408
2404
|
`,
|
|
2409
2405
|
footerNote: "If you didn't request this change, click the button above to cancel it.",
|
|
2410
|
-
appUrl
|
|
2406
|
+
appUrl,
|
|
2407
|
+
...branding
|
|
2411
2408
|
});
|
|
2412
2409
|
return {
|
|
2413
2410
|
to: oldEmail,
|
|
@@ -2427,7 +2424,7 @@ ${safeUrl}`,
|
|
|
2427
2424
|
}
|
|
2428
2425
|
};
|
|
2429
2426
|
}
|
|
2430
|
-
function generate2faCodeEmail(data, appName = "Your App", appUrl = "") {
|
|
2427
|
+
function generate2faCodeEmail(data, appName = "Your App", appUrl = "", branding) {
|
|
2431
2428
|
const { email, firstName, code } = data;
|
|
2432
2429
|
const safeFirstName = firstName ? escapeHtml(firstName) : "there";
|
|
2433
2430
|
const html = generateEmailTemplate({
|
|
@@ -2442,7 +2439,8 @@ function generate2faCodeEmail(data, appName = "Your App", appUrl = "") {
|
|
|
2442
2439
|
buttonText: "",
|
|
2443
2440
|
buttonUrl: "",
|
|
2444
2441
|
footerNote: "",
|
|
2445
|
-
appUrl
|
|
2442
|
+
appUrl,
|
|
2443
|
+
...branding
|
|
2446
2444
|
});
|
|
2447
2445
|
return {
|
|
2448
2446
|
to: email,
|
|
@@ -2462,7 +2460,7 @@ If you didn't request this code, you can safely ignore this email.
|
|
|
2462
2460
|
tags: { type: "2fa_code" }
|
|
2463
2461
|
};
|
|
2464
2462
|
}
|
|
2465
|
-
function generate2faEnabledEmail(data, appName = "Your App", appUrl = "") {
|
|
2463
|
+
function generate2faEnabledEmail(data, appName = "Your App", appUrl = "", branding) {
|
|
2466
2464
|
const { email, firstName, method } = data;
|
|
2467
2465
|
const safeFirstName = firstName ? escapeHtml(firstName) : "there";
|
|
2468
2466
|
const methodName = method === "totp" ? "an authenticator app" : "email codes";
|
|
@@ -2476,7 +2474,8 @@ function generate2faEnabledEmail(data, appName = "Your App", appUrl = "") {
|
|
|
2476
2474
|
buttonText: "",
|
|
2477
2475
|
buttonUrl: "",
|
|
2478
2476
|
footerNote: "",
|
|
2479
|
-
appUrl
|
|
2477
|
+
appUrl,
|
|
2478
|
+
...branding
|
|
2480
2479
|
});
|
|
2481
2480
|
return {
|
|
2482
2481
|
to: email,
|
|
@@ -2492,7 +2491,7 @@ If you didn't make this change, please contact support immediately and reset you
|
|
|
2492
2491
|
tags: { type: "2fa_enabled" }
|
|
2493
2492
|
};
|
|
2494
2493
|
}
|
|
2495
|
-
function generate2faDisabledEmail(data, appName = "Your App", appUrl = "") {
|
|
2494
|
+
function generate2faDisabledEmail(data, appName = "Your App", appUrl = "", branding) {
|
|
2496
2495
|
const { email, firstName } = data;
|
|
2497
2496
|
const safeFirstName = firstName ? escapeHtml(firstName) : "there";
|
|
2498
2497
|
const html = generateEmailTemplate({
|
|
@@ -2504,10 +2503,9 @@ function generate2faDisabledEmail(data, appName = "Your App", appUrl = "") {
|
|
|
2504
2503
|
`,
|
|
2505
2504
|
buttonText: "Reset Password",
|
|
2506
2505
|
buttonUrl: appUrl ? `${appUrl}/forgot-password` : "",
|
|
2507
|
-
buttonBgColor: "#ef4444",
|
|
2508
|
-
buttonTextColor: "#ffffff",
|
|
2509
2506
|
footerNote: "",
|
|
2510
|
-
appUrl
|
|
2507
|
+
appUrl,
|
|
2508
|
+
...branding
|
|
2511
2509
|
});
|
|
2512
2510
|
return {
|
|
2513
2511
|
to: email,
|
|
@@ -2697,6 +2695,7 @@ function createEmailAdapter(env) {
|
|
|
2697
2695
|
var EmailService = class {
|
|
2698
2696
|
adapter;
|
|
2699
2697
|
env;
|
|
2698
|
+
branding;
|
|
2700
2699
|
get fromAddress() {
|
|
2701
2700
|
if (this.env.EMAIL_FROM) {
|
|
2702
2701
|
return this.env.EMAIL_FROM;
|
|
@@ -2710,9 +2709,10 @@ var EmailService = class {
|
|
|
2710
2709
|
}
|
|
2711
2710
|
return `${appName} <hello@${domain}>`;
|
|
2712
2711
|
}
|
|
2713
|
-
constructor(env, adapter) {
|
|
2712
|
+
constructor(env, adapter, branding) {
|
|
2714
2713
|
this.env = env;
|
|
2715
2714
|
this.adapter = adapter ?? createEmailAdapter(env);
|
|
2715
|
+
this.branding = branding;
|
|
2716
2716
|
}
|
|
2717
2717
|
/**
|
|
2718
2718
|
* Check if email address has bounced or complained
|
|
@@ -2764,7 +2764,8 @@ var EmailService = class {
|
|
|
2764
2764
|
const template = generateVerificationEmail(
|
|
2765
2765
|
data,
|
|
2766
2766
|
this.env.APP_NAME ?? "Your App",
|
|
2767
|
-
this.env.APP_URL ?? ""
|
|
2767
|
+
this.env.APP_URL ?? "",
|
|
2768
|
+
this.branding
|
|
2768
2769
|
);
|
|
2769
2770
|
const recipient = this.getRecipientEmail(data.email, "verification");
|
|
2770
2771
|
logger_default.info("Sending verification email", {
|
|
@@ -2824,7 +2825,8 @@ var EmailService = class {
|
|
|
2824
2825
|
const template = generatePasswordResetEmail(
|
|
2825
2826
|
data,
|
|
2826
2827
|
this.env.APP_NAME ?? "Your App",
|
|
2827
|
-
this.env.APP_URL ?? ""
|
|
2828
|
+
this.env.APP_URL ?? "",
|
|
2829
|
+
this.branding
|
|
2828
2830
|
);
|
|
2829
2831
|
const recipient = this.getRecipientEmail(data.email, "password_reset");
|
|
2830
2832
|
logger_default.info("Sending password reset email", {
|
|
@@ -2884,7 +2886,8 @@ var EmailService = class {
|
|
|
2884
2886
|
const template = generateEmailChangeConfirmation(
|
|
2885
2887
|
data,
|
|
2886
2888
|
this.env.APP_NAME ?? "Your App",
|
|
2887
|
-
this.env.APP_URL ?? ""
|
|
2889
|
+
this.env.APP_URL ?? "",
|
|
2890
|
+
this.branding
|
|
2888
2891
|
);
|
|
2889
2892
|
const recipient = this.getRecipientEmail(data.newEmail, "email_change_confirmation");
|
|
2890
2893
|
logger_default.info("Sending email change confirmation", {
|
|
@@ -2944,7 +2947,8 @@ var EmailService = class {
|
|
|
2944
2947
|
const template = generateEmailChangeNotification(
|
|
2945
2948
|
data,
|
|
2946
2949
|
this.env.APP_NAME ?? "Your App",
|
|
2947
|
-
this.env.APP_URL ?? ""
|
|
2950
|
+
this.env.APP_URL ?? "",
|
|
2951
|
+
this.branding
|
|
2948
2952
|
);
|
|
2949
2953
|
const recipient = this.getRecipientEmail(data.oldEmail, "email_change_notification");
|
|
2950
2954
|
logger_default.info("Sending email change notification", {
|
|
@@ -3001,7 +3005,8 @@ var EmailService = class {
|
|
|
3001
3005
|
const template = generate2faCodeEmail(
|
|
3002
3006
|
data,
|
|
3003
3007
|
this.env.APP_NAME ?? "Your App",
|
|
3004
|
-
this.env.APP_URL ?? ""
|
|
3008
|
+
this.env.APP_URL ?? "",
|
|
3009
|
+
this.branding
|
|
3005
3010
|
);
|
|
3006
3011
|
const recipient = this.getRecipientEmail(data.email, "2fa_code");
|
|
3007
3012
|
logger_default.info("Sending 2FA code email", {
|
|
@@ -3058,7 +3063,8 @@ var EmailService = class {
|
|
|
3058
3063
|
const template = generate2faEnabledEmail(
|
|
3059
3064
|
data,
|
|
3060
3065
|
this.env.APP_NAME ?? "Your App",
|
|
3061
|
-
this.env.APP_URL ?? ""
|
|
3066
|
+
this.env.APP_URL ?? "",
|
|
3067
|
+
this.branding
|
|
3062
3068
|
);
|
|
3063
3069
|
const recipient = this.getRecipientEmail(data.email, "2fa_enabled");
|
|
3064
3070
|
logger_default.info("Sending 2FA enabled email", {
|
|
@@ -3116,7 +3122,8 @@ var EmailService = class {
|
|
|
3116
3122
|
const template = generate2faDisabledEmail(
|
|
3117
3123
|
data,
|
|
3118
3124
|
this.env.APP_NAME ?? "Your App",
|
|
3119
|
-
this.env.APP_URL ?? ""
|
|
3125
|
+
this.env.APP_URL ?? "",
|
|
3126
|
+
this.branding
|
|
3120
3127
|
);
|
|
3121
3128
|
const recipient = this.getRecipientEmail(data.email, "2fa_disabled");
|
|
3122
3129
|
logger_default.info("Sending 2FA disabled email", {
|
|
@@ -3448,7 +3455,7 @@ var signupRoute = (0, import_zod_openapi2.createRoute)({
|
|
|
3448
3455
|
});
|
|
3449
3456
|
var signupHandler = async (c) => {
|
|
3450
3457
|
const { email, password, name, turnstileToken, oauthToken } = c.req.valid("json");
|
|
3451
|
-
const { db: database, schema } = getAuthContext(c);
|
|
3458
|
+
const { db: database, schema, emailBranding } = getAuthContext(c);
|
|
3452
3459
|
const env = c.env;
|
|
3453
3460
|
if (oauthToken) {
|
|
3454
3461
|
const stored = await env.OAUTH_STATES.get(`oauth:signup:${oauthToken}`);
|
|
@@ -3548,7 +3555,7 @@ var signupHandler = async (c) => {
|
|
|
3548
3555
|
expiresAt,
|
|
3549
3556
|
createdAt: Date.now()
|
|
3550
3557
|
});
|
|
3551
|
-
const emailService = new EmailService(env);
|
|
3558
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
3552
3559
|
const verificationUrl = `${env.APP_URL}/verify-email?token=${emailToken}`;
|
|
3553
3560
|
await emailService.sendVerificationEmail(
|
|
3554
3561
|
{
|
|
@@ -4032,7 +4039,7 @@ var forgotPasswordRoute = (0, import_zod_openapi7.createRoute)({
|
|
|
4032
4039
|
});
|
|
4033
4040
|
var forgotPasswordHandler = async (c) => {
|
|
4034
4041
|
const { email, turnstileToken } = c.req.valid("json");
|
|
4035
|
-
const { db: database, schema } = getAuthContext(c);
|
|
4042
|
+
const { db: database, schema, emailBranding } = getAuthContext(c);
|
|
4036
4043
|
const env = c.env;
|
|
4037
4044
|
const turnstileValid = await verifyTurnstileToken(
|
|
4038
4045
|
turnstileToken,
|
|
@@ -4051,7 +4058,7 @@ var forgotPasswordHandler = async (c) => {
|
|
|
4051
4058
|
if (!resetResult) {
|
|
4052
4059
|
return c.json({ success: true });
|
|
4053
4060
|
}
|
|
4054
|
-
const emailService = new EmailService(env);
|
|
4061
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
4055
4062
|
const resetUrl = `${env.APP_URL}/reset-password?token=${resetResult.token}`;
|
|
4056
4063
|
await emailService.sendPasswordResetEmail(
|
|
4057
4064
|
{
|
|
@@ -4102,7 +4109,7 @@ var resetPasswordRoute = (0, import_zod_openapi8.createRoute)({
|
|
|
4102
4109
|
});
|
|
4103
4110
|
var resetPasswordHandler = async (c) => {
|
|
4104
4111
|
const { token, password, turnstileToken } = c.req.valid("json");
|
|
4105
|
-
const database = c
|
|
4112
|
+
const { db: database, schema } = getAuthContext(c);
|
|
4106
4113
|
const env = c.env;
|
|
4107
4114
|
const turnstileValid = await verifyTurnstileToken(
|
|
4108
4115
|
turnstileToken,
|
|
@@ -4117,7 +4124,18 @@ var resetPasswordHandler = async (c) => {
|
|
|
4117
4124
|
if (!passwordValidation.valid) {
|
|
4118
4125
|
return problems.badRequest(c, passwordValidation.error || "Invalid password");
|
|
4119
4126
|
}
|
|
4120
|
-
const result = await resetPassword(
|
|
4127
|
+
const result = await resetPassword(
|
|
4128
|
+
database,
|
|
4129
|
+
{
|
|
4130
|
+
users: schema.users,
|
|
4131
|
+
passwordResetTokens: schema.passwordResetTokens,
|
|
4132
|
+
sessions: schema.sessions
|
|
4133
|
+
},
|
|
4134
|
+
token,
|
|
4135
|
+
password,
|
|
4136
|
+
env.PASSWORD_PEPPER_V1,
|
|
4137
|
+
"v1"
|
|
4138
|
+
);
|
|
4121
4139
|
if (!result.success) {
|
|
4122
4140
|
return problems.badRequest(c, result.error || "Invalid or expired reset token");
|
|
4123
4141
|
}
|
|
@@ -4299,7 +4317,7 @@ var changeEmailHandler = async (c) => {
|
|
|
4299
4317
|
const userId = c.get("userId");
|
|
4300
4318
|
if (!userId) return problems.unauthorized(c, "Not authenticated");
|
|
4301
4319
|
const { password, newEmail } = c.req.valid("json");
|
|
4302
|
-
const { db: database, schema } = getAuthContext(c);
|
|
4320
|
+
const { db: database, schema, emailBranding } = getAuthContext(c);
|
|
4303
4321
|
const env = c.env;
|
|
4304
4322
|
const appUrl = env.APP_URL || "http://localhost:5173";
|
|
4305
4323
|
const result = await requestEmailChange({
|
|
@@ -4316,7 +4334,7 @@ var changeEmailHandler = async (c) => {
|
|
|
4316
4334
|
}
|
|
4317
4335
|
return problems.badRequest(c, result.error || "Failed to request email change");
|
|
4318
4336
|
}
|
|
4319
|
-
const emailService = new EmailService(env);
|
|
4337
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
4320
4338
|
const confirmUrl = `${appUrl}/confirm-email-change?token=${result.confirmToken}`;
|
|
4321
4339
|
const confirmResult = await emailService.sendEmailChangeConfirmation(
|
|
4322
4340
|
{ newEmail, confirmUrl },
|
|
@@ -4621,7 +4639,7 @@ var resendVerificationRoute = (0, import_zod_openapi21.createRoute)({
|
|
|
4621
4639
|
});
|
|
4622
4640
|
var resendVerificationHandler = async (c) => {
|
|
4623
4641
|
const userId = c.get("userId");
|
|
4624
|
-
const { db, schema } = getAuthContext(c);
|
|
4642
|
+
const { db, schema, emailBranding } = getAuthContext(c);
|
|
4625
4643
|
const env = c.env;
|
|
4626
4644
|
const [user] = await db.select({
|
|
4627
4645
|
id: schema.users.id,
|
|
@@ -4646,7 +4664,7 @@ var resendVerificationHandler = async (c) => {
|
|
|
4646
4664
|
expiresAt,
|
|
4647
4665
|
createdAt: Date.now()
|
|
4648
4666
|
});
|
|
4649
|
-
const emailService = new EmailService(env);
|
|
4667
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
4650
4668
|
const verificationUrl = `${env.APP_URL}/verify-email?token=${emailToken}`;
|
|
4651
4669
|
await emailService.sendVerificationEmail(
|
|
4652
4670
|
{
|
|
@@ -4934,7 +4952,7 @@ var totpVerifyHandler = async (c) => {
|
|
|
4934
4952
|
const userId = c.get("userId");
|
|
4935
4953
|
if (!userId) return problems.unauthorized(c);
|
|
4936
4954
|
const { code } = c.req.valid("json");
|
|
4937
|
-
const { db, schema, env } = getAuthContext(c);
|
|
4955
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
4938
4956
|
const secret = await env.OAUTH_STATES.get(`totp_setup:${userId}`);
|
|
4939
4957
|
if (!secret) {
|
|
4940
4958
|
return problems.badRequest(c, "Setup expired. Please start again.");
|
|
@@ -4978,7 +4996,7 @@ var totpVerifyHandler = async (c) => {
|
|
|
4978
4996
|
backupCodes = codes.map(formatBackupCode);
|
|
4979
4997
|
}
|
|
4980
4998
|
if (user) {
|
|
4981
|
-
const emailService = new EmailService(env);
|
|
4999
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
4982
5000
|
const firstName = user.name?.split(" ")[0] || null;
|
|
4983
5001
|
await emailService.send2faEnabledEmail(
|
|
4984
5002
|
{ email: user.email, firstName, method: "totp" },
|
|
@@ -5026,7 +5044,7 @@ var totpDisableHandler = async (c) => {
|
|
|
5026
5044
|
return problems.unauthorized(c);
|
|
5027
5045
|
}
|
|
5028
5046
|
const { code, method } = c.req.valid("json");
|
|
5029
|
-
const { db, schema, env } = getAuthContext(c);
|
|
5047
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
5030
5048
|
const verification = await verifyAny2faCode(db, env, userId, code, method, {
|
|
5031
5049
|
user2faMethods: schema.user2faMethods,
|
|
5032
5050
|
userBackupCodes: schema.userBackupCodes
|
|
@@ -5043,7 +5061,7 @@ var totpDisableHandler = async (c) => {
|
|
|
5043
5061
|
await invalidateAllUserSessions(db, { sessions: schema.sessions, users: schema.users }, userId);
|
|
5044
5062
|
const [user] = await db.select({ email: schema.users.email, name: schema.users.name }).from(schema.users).where((0, import_drizzle_orm23.eq)(schema.users.id, userId)).limit(1);
|
|
5045
5063
|
if (user) {
|
|
5046
|
-
const emailService = new EmailService(env);
|
|
5064
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
5047
5065
|
const firstName = user.name?.split(" ")[0] || null;
|
|
5048
5066
|
await emailService.send2faDisabledEmail({ email: user.email, firstName }, db, schema.users);
|
|
5049
5067
|
}
|
|
@@ -5089,7 +5107,7 @@ var emailSetupRoute = (0, import_zod_openapi28.createRoute)({
|
|
|
5089
5107
|
var emailSetupHandler = async (c) => {
|
|
5090
5108
|
const userId = c.get("userId");
|
|
5091
5109
|
if (!userId) return problems.unauthorized(c);
|
|
5092
|
-
const { db, schema, env } = getAuthContext(c);
|
|
5110
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
5093
5111
|
const existing = await db.select({ id: schema.user2faMethods.id }).from(schema.user2faMethods).where((0, import_drizzle_orm24.and)((0, import_drizzle_orm24.eq)(schema.user2faMethods.userId, userId), (0, import_drizzle_orm24.eq)(schema.user2faMethods.method, "email"))).limit(1);
|
|
5094
5112
|
if (existing.length > 0) {
|
|
5095
5113
|
return problems.badRequest(c, "Email 2FA already enabled");
|
|
@@ -5099,7 +5117,7 @@ var emailSetupHandler = async (c) => {
|
|
|
5099
5117
|
const code = generateEmailOtp();
|
|
5100
5118
|
const codeHash = await hashToken(code);
|
|
5101
5119
|
await env.OAUTH_STATES.put(`email_2fa_setup:${userId}`, codeHash, { expirationTtl: 300 });
|
|
5102
|
-
const emailService = new EmailService(env);
|
|
5120
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
5103
5121
|
const firstName = user.name?.split(" ")[0] || null;
|
|
5104
5122
|
await emailService.send2faCodeEmail({ email: user.email, firstName, code }, db, schema.users);
|
|
5105
5123
|
logSecurityEvent("2fa_email_setup_initiated", "low", { userId });
|
|
@@ -5140,7 +5158,7 @@ var emailVerifyHandler = async (c) => {
|
|
|
5140
5158
|
const userId = c.get("userId");
|
|
5141
5159
|
if (!userId) return problems.unauthorized(c);
|
|
5142
5160
|
const { code } = c.req.valid("json");
|
|
5143
|
-
const { db, schema, env } = getAuthContext(c);
|
|
5161
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
5144
5162
|
const storedHash = await env.OAUTH_STATES.get(`email_2fa_setup:${userId}`);
|
|
5145
5163
|
if (!storedHash) {
|
|
5146
5164
|
return problems.badRequest(c, "Code expired. Please request a new one.");
|
|
@@ -5178,7 +5196,7 @@ var emailVerifyHandler = async (c) => {
|
|
|
5178
5196
|
backupCodes = codes.map(formatBackupCode);
|
|
5179
5197
|
}
|
|
5180
5198
|
if (user) {
|
|
5181
|
-
const emailService = new EmailService(env);
|
|
5199
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
5182
5200
|
const firstName = user.name?.split(" ")[0] || null;
|
|
5183
5201
|
await emailService.send2faEnabledEmail(
|
|
5184
5202
|
{ email: user.email, firstName, method: "email" },
|
|
@@ -5221,7 +5239,7 @@ var emailSendCodeRoute = (0, import_zod_openapi30.createRoute)({
|
|
|
5221
5239
|
var emailSendCodeHandler = async (c) => {
|
|
5222
5240
|
const userId = c.get("userId");
|
|
5223
5241
|
if (!userId) return problems.unauthorized(c);
|
|
5224
|
-
const { db, schema, env } = getAuthContext(c);
|
|
5242
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
5225
5243
|
const [emailMethod] = await db.select().from(schema.user2faMethods).where((0, import_drizzle_orm26.and)((0, import_drizzle_orm26.eq)(schema.user2faMethods.userId, userId), (0, import_drizzle_orm26.eq)(schema.user2faMethods.method, "email"))).limit(1);
|
|
5226
5244
|
if (!emailMethod) {
|
|
5227
5245
|
return problems.badRequest(c, "Email 2FA not enabled");
|
|
@@ -5233,7 +5251,7 @@ var emailSendCodeHandler = async (c) => {
|
|
|
5233
5251
|
await env.OAUTH_STATES.put(`email_2fa_challenge:${userId}`, codeHash, {
|
|
5234
5252
|
expirationTtl: 300
|
|
5235
5253
|
});
|
|
5236
|
-
const emailService = new EmailService(env);
|
|
5254
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
5237
5255
|
const firstName = user.name?.split(" ")[0] || null;
|
|
5238
5256
|
const emailResult = await emailService.send2faCodeEmail(
|
|
5239
5257
|
{ email: user.email, firstName, code },
|
|
@@ -5286,7 +5304,7 @@ var emailDisableHandler = async (c) => {
|
|
|
5286
5304
|
return problems.unauthorized(c);
|
|
5287
5305
|
}
|
|
5288
5306
|
const { code, method } = c.req.valid("json");
|
|
5289
|
-
const { db, schema, env } = getAuthContext(c);
|
|
5307
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
5290
5308
|
const verification = await verifyAny2faCode(db, env, userId, code, method, {
|
|
5291
5309
|
user2faMethods: schema.user2faMethods,
|
|
5292
5310
|
userBackupCodes: schema.userBackupCodes
|
|
@@ -5303,7 +5321,7 @@ var emailDisableHandler = async (c) => {
|
|
|
5303
5321
|
await invalidateAllUserSessions(db, { sessions: schema.sessions, users: schema.users }, userId);
|
|
5304
5322
|
const [user] = await db.select({ email: schema.users.email, name: schema.users.name }).from(schema.users).where((0, import_drizzle_orm27.eq)(schema.users.id, userId)).limit(1);
|
|
5305
5323
|
if (user) {
|
|
5306
|
-
const emailService = new EmailService(env);
|
|
5324
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
5307
5325
|
const firstName = user.name?.split(" ")[0] || null;
|
|
5308
5326
|
await emailService.send2faDisabledEmail({ email: user.email, firstName }, db, schema.users);
|
|
5309
5327
|
}
|
|
@@ -5600,7 +5618,7 @@ var challengeResendRoute = (0, import_zod_openapi35.createRoute)({
|
|
|
5600
5618
|
}
|
|
5601
5619
|
});
|
|
5602
5620
|
var challengeResendHandler = async (c) => {
|
|
5603
|
-
const { db, schema } = getAuthContext(c);
|
|
5621
|
+
const { db, schema, emailBranding } = getAuthContext(c);
|
|
5604
5622
|
const cookieName = getChallengeCookieName(c.env);
|
|
5605
5623
|
const challengeToken = (0, import_cookie4.getCookie)(c, cookieName);
|
|
5606
5624
|
if (!challengeToken) {
|
|
@@ -5624,7 +5642,7 @@ var challengeResendHandler = async (c) => {
|
|
|
5624
5642
|
await c.env.OAUTH_STATES.put(`email_2fa_challenge:${payload.userId}`, codeHash, {
|
|
5625
5643
|
expirationTtl: 300
|
|
5626
5644
|
});
|
|
5627
|
-
const emailService = new EmailService(c.env);
|
|
5645
|
+
const emailService = new EmailService(c.env, void 0, emailBranding);
|
|
5628
5646
|
const firstName = user.name?.split(" ")[0] || null;
|
|
5629
5647
|
await emailService.send2faCodeEmail({ email: user.email, firstName, code }, db, schema.users);
|
|
5630
5648
|
logger_default.info("Email 2FA code resent", { userId: payload.userId });
|