@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.js
CHANGED
|
@@ -949,11 +949,12 @@ import { eq as eq4, and as and2, gt as gt2 } from "drizzle-orm";
|
|
|
949
949
|
|
|
950
950
|
// src/factory.ts
|
|
951
951
|
function createAuth(config) {
|
|
952
|
-
const { db, schema, getEnv } = config;
|
|
952
|
+
const { db, schema, getEnv, emailBranding } = config;
|
|
953
953
|
const getContext = (c) => ({
|
|
954
954
|
db,
|
|
955
955
|
schema,
|
|
956
|
-
env: getEnv(c)
|
|
956
|
+
env: getEnv(c),
|
|
957
|
+
emailBranding
|
|
957
958
|
});
|
|
958
959
|
return {
|
|
959
960
|
db,
|
|
@@ -1535,11 +1536,15 @@ function generateEmailTemplate(options) {
|
|
|
1535
1536
|
appName = "App",
|
|
1536
1537
|
buttonBgColor = "#00fe9a",
|
|
1537
1538
|
buttonTextColor = "#000004",
|
|
1538
|
-
buttonFontWeight = 500
|
|
1539
|
+
buttonFontWeight = 500,
|
|
1540
|
+
buttonRadius = "6px",
|
|
1541
|
+
logoUrl,
|
|
1542
|
+
footerColor = "#1e1b4b"
|
|
1539
1543
|
} = options;
|
|
1540
1544
|
const safeButtonUrl = buttonUrl ? sanitizeEmailUrl(buttonUrl, appUrl) : "";
|
|
1541
1545
|
const safeAppUrl = appUrl ? sanitizeEmailUrl(appUrl, appUrl) : "";
|
|
1542
1546
|
const safeMarketingUrl = marketingUrl ? sanitizeEmailUrl(marketingUrl, appUrl) : "";
|
|
1547
|
+
const safeLogoUrl = logoUrl ? sanitizeEmailUrl(logoUrl, appUrl) : `${safeAppUrl.replace(/\/$/, "")}/email-header-image.png`;
|
|
1543
1548
|
return `
|
|
1544
1549
|
<!DOCTYPE html>
|
|
1545
1550
|
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" lang="en">
|
|
@@ -1679,7 +1684,7 @@ function generateEmailTemplate(options) {
|
|
|
1679
1684
|
<td class="pad" style="padding-left:40px;padding-right:40px;width:100%;">
|
|
1680
1685
|
<div class="alignment" align="center">
|
|
1681
1686
|
<div class="fullWidth" style="max-width: 50%;">
|
|
1682
|
-
<img src="${
|
|
1687
|
+
<img src="${safeLogoUrl}" style="display: block; height: auto; border: 0; width: 100%;" alt="${appName}" title="${appName}" height="auto">
|
|
1683
1688
|
</div>
|
|
1684
1689
|
</div>
|
|
1685
1690
|
</td>
|
|
@@ -1736,7 +1741,7 @@ function generateEmailTemplate(options) {
|
|
|
1736
1741
|
<v:textbox inset="0px,0px,0px,0px">
|
|
1737
1742
|
<center dir="false" style="color:${buttonTextColor};font-family:'Montserrat',Arial,sans-serif;font-size:16px;font-weight:${buttonFontWeight};">
|
|
1738
1743
|
<![endif]-->
|
|
1739
|
-
<a href="${safeButtonUrl}" style="background-color: ${buttonBgColor}; border: 0px solid transparent; border-radius:
|
|
1744
|
+
<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;">
|
|
1740
1745
|
${buttonText}
|
|
1741
1746
|
</a>
|
|
1742
1747
|
<!--[if mso]>
|
|
@@ -1827,7 +1832,7 @@ function generateEmailTemplate(options) {
|
|
|
1827
1832
|
<tbody>
|
|
1828
1833
|
<tr>
|
|
1829
1834
|
<td>
|
|
1830
|
-
<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:
|
|
1835
|
+
<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;">
|
|
1831
1836
|
<tbody>
|
|
1832
1837
|
<tr>
|
|
1833
1838
|
<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;">
|
|
@@ -1886,7 +1891,7 @@ function extractAppUrl(url) {
|
|
|
1886
1891
|
return "https://your-domain.com";
|
|
1887
1892
|
}
|
|
1888
1893
|
}
|
|
1889
|
-
function generateVerificationEmail(data, appName = "Your App", configuredAppUrl = "") {
|
|
1894
|
+
function generateVerificationEmail(data, appName = "Your App", configuredAppUrl = "", branding) {
|
|
1890
1895
|
const { email, verificationUrl, firstName } = data;
|
|
1891
1896
|
const appUrl = configuredAppUrl;
|
|
1892
1897
|
const safeUrl = sanitizeEmailUrl(verificationUrl, appUrl);
|
|
@@ -1896,12 +1901,10 @@ function generateVerificationEmail(data, appName = "Your App", configuredAppUrl
|
|
|
1896
1901
|
body: `Please verify that your email address is <strong>${escapeHtml(email)}</strong>, and that you entered it when signing up for ${escapeHtml(appName)}.`,
|
|
1897
1902
|
buttonText: "Verify Email",
|
|
1898
1903
|
buttonUrl: safeUrl,
|
|
1899
|
-
buttonBgColor: "#00fe9a",
|
|
1900
|
-
buttonTextColor: "#000004",
|
|
1901
|
-
buttonFontWeight: 500,
|
|
1902
1904
|
welcomeMessage: safeFirstName ? `Hi ${safeFirstName}, Welcome to ${escapeHtml(appName)}!` : void 0,
|
|
1903
1905
|
footerNote: "",
|
|
1904
|
-
appUrl
|
|
1906
|
+
appUrl,
|
|
1907
|
+
...branding
|
|
1905
1908
|
});
|
|
1906
1909
|
return {
|
|
1907
1910
|
to: email,
|
|
@@ -1921,7 +1924,7 @@ If you didn't create an account with ${appName}, you can safely ignore this emai
|
|
|
1921
1924
|
}
|
|
1922
1925
|
};
|
|
1923
1926
|
}
|
|
1924
|
-
function generatePasswordResetEmail(data, appName = "Your App", configuredAppUrl = "") {
|
|
1927
|
+
function generatePasswordResetEmail(data, appName = "Your App", configuredAppUrl = "", branding) {
|
|
1925
1928
|
const { email, resetUrl } = data;
|
|
1926
1929
|
const appUrl = configuredAppUrl;
|
|
1927
1930
|
const safeUrl = sanitizeEmailUrl(resetUrl, appUrl);
|
|
@@ -1930,15 +1933,13 @@ function generatePasswordResetEmail(data, appName = "Your App", configuredAppUrl
|
|
|
1930
1933
|
body: "We received a request to reset your password. Click the button below to create a new password.",
|
|
1931
1934
|
buttonText: "Reset Password",
|
|
1932
1935
|
buttonUrl: safeUrl,
|
|
1933
|
-
buttonBgColor: "#00fe9a",
|
|
1934
|
-
buttonTextColor: "#000004",
|
|
1935
|
-
buttonFontWeight: 500,
|
|
1936
1936
|
securityWarning: `
|
|
1937
1937
|
<strong>Link expires in 1 hour.</strong><br>
|
|
1938
1938
|
For security, this link can only be used once.
|
|
1939
1939
|
`,
|
|
1940
1940
|
footerNote: "If you didn't request this change, no action is needed. Your password will remain unchanged.",
|
|
1941
|
-
appUrl
|
|
1941
|
+
appUrl,
|
|
1942
|
+
...branding
|
|
1942
1943
|
});
|
|
1943
1944
|
return {
|
|
1944
1945
|
to: email,
|
|
@@ -1958,7 +1959,7 @@ If you didn't request a password reset, you can safely ignore this email.`,
|
|
|
1958
1959
|
}
|
|
1959
1960
|
};
|
|
1960
1961
|
}
|
|
1961
|
-
function generateEmailChangeConfirmation(data, appName = "Your App", configuredAppUrl = "") {
|
|
1962
|
+
function generateEmailChangeConfirmation(data, appName = "Your App", configuredAppUrl = "", branding) {
|
|
1962
1963
|
const { newEmail, confirmUrl } = data;
|
|
1963
1964
|
const appUrl = configuredAppUrl;
|
|
1964
1965
|
const safeUrl = sanitizeEmailUrl(confirmUrl, appUrl);
|
|
@@ -1967,15 +1968,13 @@ function generateEmailChangeConfirmation(data, appName = "Your App", configuredA
|
|
|
1967
1968
|
body: `We received a request to change your ${escapeHtml(appName)} account email to this address. Click the button below to confirm this change.`,
|
|
1968
1969
|
buttonText: "Confirm Email Change",
|
|
1969
1970
|
buttonUrl: safeUrl,
|
|
1970
|
-
buttonBgColor: "#00fe9a",
|
|
1971
|
-
buttonTextColor: "#000004",
|
|
1972
|
-
buttonFontWeight: 500,
|
|
1973
1971
|
securityWarning: `
|
|
1974
1972
|
<strong>This link expires in 24 hours.</strong><br>
|
|
1975
1973
|
For security, this link can only be used once.
|
|
1976
1974
|
`,
|
|
1977
1975
|
footerNote: "If you didn't request this change, you can safely ignore this email.",
|
|
1978
|
-
appUrl
|
|
1976
|
+
appUrl,
|
|
1977
|
+
...branding
|
|
1979
1978
|
});
|
|
1980
1979
|
return {
|
|
1981
1980
|
to: newEmail,
|
|
@@ -1997,7 +1996,7 @@ If you didn't request this change, you can safely ignore this email.`,
|
|
|
1997
1996
|
}
|
|
1998
1997
|
};
|
|
1999
1998
|
}
|
|
2000
|
-
function generateEmailChangeNotification(data, appName = "Your App", configuredAppUrl = "") {
|
|
1999
|
+
function generateEmailChangeNotification(data, appName = "Your App", configuredAppUrl = "", branding) {
|
|
2001
2000
|
const { oldEmail, newEmail, cancelUrl } = data;
|
|
2002
2001
|
const appUrl = configuredAppUrl;
|
|
2003
2002
|
const safeUrl = sanitizeEmailUrl(cancelUrl, appUrl);
|
|
@@ -2007,15 +2006,13 @@ function generateEmailChangeNotification(data, appName = "Your App", configuredA
|
|
|
2007
2006
|
body: `Someone requested to change your ${escapeHtml(appName)} account email to <strong>${safeNewEmail}</strong>.`,
|
|
2008
2007
|
buttonText: "This Wasn't Me - Cancel Change",
|
|
2009
2008
|
buttonUrl: safeUrl,
|
|
2010
|
-
buttonBgColor: "#00fe9a",
|
|
2011
|
-
buttonTextColor: "#000004",
|
|
2012
|
-
buttonFontWeight: 500,
|
|
2013
2009
|
securityWarning: `
|
|
2014
2010
|
If you made this request, no action is needed.<br>
|
|
2015
2011
|
Complete the change by clicking the link sent to your new email address.
|
|
2016
2012
|
`,
|
|
2017
2013
|
footerNote: "If you didn't request this change, click the button above to cancel it.",
|
|
2018
|
-
appUrl
|
|
2014
|
+
appUrl,
|
|
2015
|
+
...branding
|
|
2019
2016
|
});
|
|
2020
2017
|
return {
|
|
2021
2018
|
to: oldEmail,
|
|
@@ -2035,7 +2032,7 @@ ${safeUrl}`,
|
|
|
2035
2032
|
}
|
|
2036
2033
|
};
|
|
2037
2034
|
}
|
|
2038
|
-
function generate2faCodeEmail(data, appName = "Your App", appUrl = "") {
|
|
2035
|
+
function generate2faCodeEmail(data, appName = "Your App", appUrl = "", branding) {
|
|
2039
2036
|
const { email, firstName, code } = data;
|
|
2040
2037
|
const safeFirstName = firstName ? escapeHtml(firstName) : "there";
|
|
2041
2038
|
const html = generateEmailTemplate({
|
|
@@ -2050,7 +2047,8 @@ function generate2faCodeEmail(data, appName = "Your App", appUrl = "") {
|
|
|
2050
2047
|
buttonText: "",
|
|
2051
2048
|
buttonUrl: "",
|
|
2052
2049
|
footerNote: "",
|
|
2053
|
-
appUrl
|
|
2050
|
+
appUrl,
|
|
2051
|
+
...branding
|
|
2054
2052
|
});
|
|
2055
2053
|
return {
|
|
2056
2054
|
to: email,
|
|
@@ -2070,7 +2068,7 @@ If you didn't request this code, you can safely ignore this email.
|
|
|
2070
2068
|
tags: { type: "2fa_code" }
|
|
2071
2069
|
};
|
|
2072
2070
|
}
|
|
2073
|
-
function generate2faEnabledEmail(data, appName = "Your App", appUrl = "") {
|
|
2071
|
+
function generate2faEnabledEmail(data, appName = "Your App", appUrl = "", branding) {
|
|
2074
2072
|
const { email, firstName, method } = data;
|
|
2075
2073
|
const safeFirstName = firstName ? escapeHtml(firstName) : "there";
|
|
2076
2074
|
const methodName = method === "totp" ? "an authenticator app" : "email codes";
|
|
@@ -2084,7 +2082,8 @@ function generate2faEnabledEmail(data, appName = "Your App", appUrl = "") {
|
|
|
2084
2082
|
buttonText: "",
|
|
2085
2083
|
buttonUrl: "",
|
|
2086
2084
|
footerNote: "",
|
|
2087
|
-
appUrl
|
|
2085
|
+
appUrl,
|
|
2086
|
+
...branding
|
|
2088
2087
|
});
|
|
2089
2088
|
return {
|
|
2090
2089
|
to: email,
|
|
@@ -2100,7 +2099,7 @@ If you didn't make this change, please contact support immediately and reset you
|
|
|
2100
2099
|
tags: { type: "2fa_enabled" }
|
|
2101
2100
|
};
|
|
2102
2101
|
}
|
|
2103
|
-
function generate2faDisabledEmail(data, appName = "Your App", appUrl = "") {
|
|
2102
|
+
function generate2faDisabledEmail(data, appName = "Your App", appUrl = "", branding) {
|
|
2104
2103
|
const { email, firstName } = data;
|
|
2105
2104
|
const safeFirstName = firstName ? escapeHtml(firstName) : "there";
|
|
2106
2105
|
const html = generateEmailTemplate({
|
|
@@ -2112,10 +2111,9 @@ function generate2faDisabledEmail(data, appName = "Your App", appUrl = "") {
|
|
|
2112
2111
|
`,
|
|
2113
2112
|
buttonText: "Reset Password",
|
|
2114
2113
|
buttonUrl: appUrl ? `${appUrl}/forgot-password` : "",
|
|
2115
|
-
buttonBgColor: "#ef4444",
|
|
2116
|
-
buttonTextColor: "#ffffff",
|
|
2117
2114
|
footerNote: "",
|
|
2118
|
-
appUrl
|
|
2115
|
+
appUrl,
|
|
2116
|
+
...branding
|
|
2119
2117
|
});
|
|
2120
2118
|
return {
|
|
2121
2119
|
to: email,
|
|
@@ -2305,6 +2303,7 @@ function createEmailAdapter(env) {
|
|
|
2305
2303
|
var EmailService = class {
|
|
2306
2304
|
adapter;
|
|
2307
2305
|
env;
|
|
2306
|
+
branding;
|
|
2308
2307
|
get fromAddress() {
|
|
2309
2308
|
if (this.env.EMAIL_FROM) {
|
|
2310
2309
|
return this.env.EMAIL_FROM;
|
|
@@ -2318,9 +2317,10 @@ var EmailService = class {
|
|
|
2318
2317
|
}
|
|
2319
2318
|
return `${appName} <hello@${domain}>`;
|
|
2320
2319
|
}
|
|
2321
|
-
constructor(env, adapter) {
|
|
2320
|
+
constructor(env, adapter, branding) {
|
|
2322
2321
|
this.env = env;
|
|
2323
2322
|
this.adapter = adapter ?? createEmailAdapter(env);
|
|
2323
|
+
this.branding = branding;
|
|
2324
2324
|
}
|
|
2325
2325
|
/**
|
|
2326
2326
|
* Check if email address has bounced or complained
|
|
@@ -2372,7 +2372,8 @@ var EmailService = class {
|
|
|
2372
2372
|
const template = generateVerificationEmail(
|
|
2373
2373
|
data,
|
|
2374
2374
|
this.env.APP_NAME ?? "Your App",
|
|
2375
|
-
this.env.APP_URL ?? ""
|
|
2375
|
+
this.env.APP_URL ?? "",
|
|
2376
|
+
this.branding
|
|
2376
2377
|
);
|
|
2377
2378
|
const recipient = this.getRecipientEmail(data.email, "verification");
|
|
2378
2379
|
logger_default.info("Sending verification email", {
|
|
@@ -2432,7 +2433,8 @@ var EmailService = class {
|
|
|
2432
2433
|
const template = generatePasswordResetEmail(
|
|
2433
2434
|
data,
|
|
2434
2435
|
this.env.APP_NAME ?? "Your App",
|
|
2435
|
-
this.env.APP_URL ?? ""
|
|
2436
|
+
this.env.APP_URL ?? "",
|
|
2437
|
+
this.branding
|
|
2436
2438
|
);
|
|
2437
2439
|
const recipient = this.getRecipientEmail(data.email, "password_reset");
|
|
2438
2440
|
logger_default.info("Sending password reset email", {
|
|
@@ -2492,7 +2494,8 @@ var EmailService = class {
|
|
|
2492
2494
|
const template = generateEmailChangeConfirmation(
|
|
2493
2495
|
data,
|
|
2494
2496
|
this.env.APP_NAME ?? "Your App",
|
|
2495
|
-
this.env.APP_URL ?? ""
|
|
2497
|
+
this.env.APP_URL ?? "",
|
|
2498
|
+
this.branding
|
|
2496
2499
|
);
|
|
2497
2500
|
const recipient = this.getRecipientEmail(data.newEmail, "email_change_confirmation");
|
|
2498
2501
|
logger_default.info("Sending email change confirmation", {
|
|
@@ -2552,7 +2555,8 @@ var EmailService = class {
|
|
|
2552
2555
|
const template = generateEmailChangeNotification(
|
|
2553
2556
|
data,
|
|
2554
2557
|
this.env.APP_NAME ?? "Your App",
|
|
2555
|
-
this.env.APP_URL ?? ""
|
|
2558
|
+
this.env.APP_URL ?? "",
|
|
2559
|
+
this.branding
|
|
2556
2560
|
);
|
|
2557
2561
|
const recipient = this.getRecipientEmail(data.oldEmail, "email_change_notification");
|
|
2558
2562
|
logger_default.info("Sending email change notification", {
|
|
@@ -2609,7 +2613,8 @@ var EmailService = class {
|
|
|
2609
2613
|
const template = generate2faCodeEmail(
|
|
2610
2614
|
data,
|
|
2611
2615
|
this.env.APP_NAME ?? "Your App",
|
|
2612
|
-
this.env.APP_URL ?? ""
|
|
2616
|
+
this.env.APP_URL ?? "",
|
|
2617
|
+
this.branding
|
|
2613
2618
|
);
|
|
2614
2619
|
const recipient = this.getRecipientEmail(data.email, "2fa_code");
|
|
2615
2620
|
logger_default.info("Sending 2FA code email", {
|
|
@@ -2666,7 +2671,8 @@ var EmailService = class {
|
|
|
2666
2671
|
const template = generate2faEnabledEmail(
|
|
2667
2672
|
data,
|
|
2668
2673
|
this.env.APP_NAME ?? "Your App",
|
|
2669
|
-
this.env.APP_URL ?? ""
|
|
2674
|
+
this.env.APP_URL ?? "",
|
|
2675
|
+
this.branding
|
|
2670
2676
|
);
|
|
2671
2677
|
const recipient = this.getRecipientEmail(data.email, "2fa_enabled");
|
|
2672
2678
|
logger_default.info("Sending 2FA enabled email", {
|
|
@@ -2724,7 +2730,8 @@ var EmailService = class {
|
|
|
2724
2730
|
const template = generate2faDisabledEmail(
|
|
2725
2731
|
data,
|
|
2726
2732
|
this.env.APP_NAME ?? "Your App",
|
|
2727
|
-
this.env.APP_URL ?? ""
|
|
2733
|
+
this.env.APP_URL ?? "",
|
|
2734
|
+
this.branding
|
|
2728
2735
|
);
|
|
2729
2736
|
const recipient = this.getRecipientEmail(data.email, "2fa_disabled");
|
|
2730
2737
|
logger_default.info("Sending 2FA disabled email", {
|
|
@@ -3056,7 +3063,7 @@ var signupRoute = createRoute({
|
|
|
3056
3063
|
});
|
|
3057
3064
|
var signupHandler = async (c) => {
|
|
3058
3065
|
const { email, password, name, turnstileToken, oauthToken } = c.req.valid("json");
|
|
3059
|
-
const { db: database, schema } = getAuthContext(c);
|
|
3066
|
+
const { db: database, schema, emailBranding } = getAuthContext(c);
|
|
3060
3067
|
const env = c.env;
|
|
3061
3068
|
if (oauthToken) {
|
|
3062
3069
|
const stored = await env.OAUTH_STATES.get(`oauth:signup:${oauthToken}`);
|
|
@@ -3156,7 +3163,7 @@ var signupHandler = async (c) => {
|
|
|
3156
3163
|
expiresAt,
|
|
3157
3164
|
createdAt: Date.now()
|
|
3158
3165
|
});
|
|
3159
|
-
const emailService = new EmailService(env);
|
|
3166
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
3160
3167
|
const verificationUrl = `${env.APP_URL}/verify-email?token=${emailToken}`;
|
|
3161
3168
|
await emailService.sendVerificationEmail(
|
|
3162
3169
|
{
|
|
@@ -3640,7 +3647,7 @@ var forgotPasswordRoute = createRoute6({
|
|
|
3640
3647
|
});
|
|
3641
3648
|
var forgotPasswordHandler = async (c) => {
|
|
3642
3649
|
const { email, turnstileToken } = c.req.valid("json");
|
|
3643
|
-
const { db: database, schema } = getAuthContext(c);
|
|
3650
|
+
const { db: database, schema, emailBranding } = getAuthContext(c);
|
|
3644
3651
|
const env = c.env;
|
|
3645
3652
|
const turnstileValid = await verifyTurnstileToken(
|
|
3646
3653
|
turnstileToken,
|
|
@@ -3659,7 +3666,7 @@ var forgotPasswordHandler = async (c) => {
|
|
|
3659
3666
|
if (!resetResult) {
|
|
3660
3667
|
return c.json({ success: true });
|
|
3661
3668
|
}
|
|
3662
|
-
const emailService = new EmailService(env);
|
|
3669
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
3663
3670
|
const resetUrl = `${env.APP_URL}/reset-password?token=${resetResult.token}`;
|
|
3664
3671
|
await emailService.sendPasswordResetEmail(
|
|
3665
3672
|
{
|
|
@@ -3710,7 +3717,7 @@ var resetPasswordRoute = createRoute7({
|
|
|
3710
3717
|
});
|
|
3711
3718
|
var resetPasswordHandler = async (c) => {
|
|
3712
3719
|
const { token, password, turnstileToken } = c.req.valid("json");
|
|
3713
|
-
const database = c
|
|
3720
|
+
const { db: database, schema } = getAuthContext(c);
|
|
3714
3721
|
const env = c.env;
|
|
3715
3722
|
const turnstileValid = await verifyTurnstileToken(
|
|
3716
3723
|
turnstileToken,
|
|
@@ -3725,7 +3732,18 @@ var resetPasswordHandler = async (c) => {
|
|
|
3725
3732
|
if (!passwordValidation.valid) {
|
|
3726
3733
|
return problems.badRequest(c, passwordValidation.error || "Invalid password");
|
|
3727
3734
|
}
|
|
3728
|
-
const result = await resetPassword(
|
|
3735
|
+
const result = await resetPassword(
|
|
3736
|
+
database,
|
|
3737
|
+
{
|
|
3738
|
+
users: schema.users,
|
|
3739
|
+
passwordResetTokens: schema.passwordResetTokens,
|
|
3740
|
+
sessions: schema.sessions
|
|
3741
|
+
},
|
|
3742
|
+
token,
|
|
3743
|
+
password,
|
|
3744
|
+
env.PASSWORD_PEPPER_V1,
|
|
3745
|
+
"v1"
|
|
3746
|
+
);
|
|
3729
3747
|
if (!result.success) {
|
|
3730
3748
|
return problems.badRequest(c, result.error || "Invalid or expired reset token");
|
|
3731
3749
|
}
|
|
@@ -3907,7 +3925,7 @@ var changeEmailHandler = async (c) => {
|
|
|
3907
3925
|
const userId = c.get("userId");
|
|
3908
3926
|
if (!userId) return problems.unauthorized(c, "Not authenticated");
|
|
3909
3927
|
const { password, newEmail } = c.req.valid("json");
|
|
3910
|
-
const { db: database, schema } = getAuthContext(c);
|
|
3928
|
+
const { db: database, schema, emailBranding } = getAuthContext(c);
|
|
3911
3929
|
const env = c.env;
|
|
3912
3930
|
const appUrl = env.APP_URL || "http://localhost:5173";
|
|
3913
3931
|
const result = await requestEmailChange({
|
|
@@ -3924,7 +3942,7 @@ var changeEmailHandler = async (c) => {
|
|
|
3924
3942
|
}
|
|
3925
3943
|
return problems.badRequest(c, result.error || "Failed to request email change");
|
|
3926
3944
|
}
|
|
3927
|
-
const emailService = new EmailService(env);
|
|
3945
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
3928
3946
|
const confirmUrl = `${appUrl}/confirm-email-change?token=${result.confirmToken}`;
|
|
3929
3947
|
const confirmResult = await emailService.sendEmailChangeConfirmation(
|
|
3930
3948
|
{ newEmail, confirmUrl },
|
|
@@ -4229,7 +4247,7 @@ var resendVerificationRoute = createRoute15({
|
|
|
4229
4247
|
});
|
|
4230
4248
|
var resendVerificationHandler = async (c) => {
|
|
4231
4249
|
const userId = c.get("userId");
|
|
4232
|
-
const { db, schema } = getAuthContext(c);
|
|
4250
|
+
const { db, schema, emailBranding } = getAuthContext(c);
|
|
4233
4251
|
const env = c.env;
|
|
4234
4252
|
const [user] = await db.select({
|
|
4235
4253
|
id: schema.users.id,
|
|
@@ -4254,7 +4272,7 @@ var resendVerificationHandler = async (c) => {
|
|
|
4254
4272
|
expiresAt,
|
|
4255
4273
|
createdAt: Date.now()
|
|
4256
4274
|
});
|
|
4257
|
-
const emailService = new EmailService(env);
|
|
4275
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
4258
4276
|
const verificationUrl = `${env.APP_URL}/verify-email?token=${emailToken}`;
|
|
4259
4277
|
await emailService.sendVerificationEmail(
|
|
4260
4278
|
{
|
|
@@ -4542,7 +4560,7 @@ var totpVerifyHandler = async (c) => {
|
|
|
4542
4560
|
const userId = c.get("userId");
|
|
4543
4561
|
if (!userId) return problems.unauthorized(c);
|
|
4544
4562
|
const { code } = c.req.valid("json");
|
|
4545
|
-
const { db, schema, env } = getAuthContext(c);
|
|
4563
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
4546
4564
|
const secret = await env.OAUTH_STATES.get(`totp_setup:${userId}`);
|
|
4547
4565
|
if (!secret) {
|
|
4548
4566
|
return problems.badRequest(c, "Setup expired. Please start again.");
|
|
@@ -4586,7 +4604,7 @@ var totpVerifyHandler = async (c) => {
|
|
|
4586
4604
|
backupCodes = codes.map(formatBackupCode);
|
|
4587
4605
|
}
|
|
4588
4606
|
if (user) {
|
|
4589
|
-
const emailService = new EmailService(env);
|
|
4607
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
4590
4608
|
const firstName = user.name?.split(" ")[0] || null;
|
|
4591
4609
|
await emailService.send2faEnabledEmail(
|
|
4592
4610
|
{ email: user.email, firstName, method: "totp" },
|
|
@@ -4634,7 +4652,7 @@ var totpDisableHandler = async (c) => {
|
|
|
4634
4652
|
return problems.unauthorized(c);
|
|
4635
4653
|
}
|
|
4636
4654
|
const { code, method } = c.req.valid("json");
|
|
4637
|
-
const { db, schema, env } = getAuthContext(c);
|
|
4655
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
4638
4656
|
const verification = await verifyAny2faCode(db, env, userId, code, method, {
|
|
4639
4657
|
user2faMethods: schema.user2faMethods,
|
|
4640
4658
|
userBackupCodes: schema.userBackupCodes
|
|
@@ -4651,7 +4669,7 @@ var totpDisableHandler = async (c) => {
|
|
|
4651
4669
|
await invalidateAllUserSessions(db, { sessions: schema.sessions, users: schema.users }, userId);
|
|
4652
4670
|
const [user] = await db.select({ email: schema.users.email, name: schema.users.name }).from(schema.users).where(eq22(schema.users.id, userId)).limit(1);
|
|
4653
4671
|
if (user) {
|
|
4654
|
-
const emailService = new EmailService(env);
|
|
4672
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
4655
4673
|
const firstName = user.name?.split(" ")[0] || null;
|
|
4656
4674
|
await emailService.send2faDisabledEmail({ email: user.email, firstName }, db, schema.users);
|
|
4657
4675
|
}
|
|
@@ -4697,7 +4715,7 @@ var emailSetupRoute = createRoute20({
|
|
|
4697
4715
|
var emailSetupHandler = async (c) => {
|
|
4698
4716
|
const userId = c.get("userId");
|
|
4699
4717
|
if (!userId) return problems.unauthorized(c);
|
|
4700
|
-
const { db, schema, env } = getAuthContext(c);
|
|
4718
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
4701
4719
|
const existing = await db.select({ id: schema.user2faMethods.id }).from(schema.user2faMethods).where(and10(eq23(schema.user2faMethods.userId, userId), eq23(schema.user2faMethods.method, "email"))).limit(1);
|
|
4702
4720
|
if (existing.length > 0) {
|
|
4703
4721
|
return problems.badRequest(c, "Email 2FA already enabled");
|
|
@@ -4707,7 +4725,7 @@ var emailSetupHandler = async (c) => {
|
|
|
4707
4725
|
const code = generateEmailOtp();
|
|
4708
4726
|
const codeHash = await hashToken(code);
|
|
4709
4727
|
await env.OAUTH_STATES.put(`email_2fa_setup:${userId}`, codeHash, { expirationTtl: 300 });
|
|
4710
|
-
const emailService = new EmailService(env);
|
|
4728
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
4711
4729
|
const firstName = user.name?.split(" ")[0] || null;
|
|
4712
4730
|
await emailService.send2faCodeEmail({ email: user.email, firstName, code }, db, schema.users);
|
|
4713
4731
|
logSecurityEvent("2fa_email_setup_initiated", "low", { userId });
|
|
@@ -4748,7 +4766,7 @@ var emailVerifyHandler = async (c) => {
|
|
|
4748
4766
|
const userId = c.get("userId");
|
|
4749
4767
|
if (!userId) return problems.unauthorized(c);
|
|
4750
4768
|
const { code } = c.req.valid("json");
|
|
4751
|
-
const { db, schema, env } = getAuthContext(c);
|
|
4769
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
4752
4770
|
const storedHash = await env.OAUTH_STATES.get(`email_2fa_setup:${userId}`);
|
|
4753
4771
|
if (!storedHash) {
|
|
4754
4772
|
return problems.badRequest(c, "Code expired. Please request a new one.");
|
|
@@ -4786,7 +4804,7 @@ var emailVerifyHandler = async (c) => {
|
|
|
4786
4804
|
backupCodes = codes.map(formatBackupCode);
|
|
4787
4805
|
}
|
|
4788
4806
|
if (user) {
|
|
4789
|
-
const emailService = new EmailService(env);
|
|
4807
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
4790
4808
|
const firstName = user.name?.split(" ")[0] || null;
|
|
4791
4809
|
await emailService.send2faEnabledEmail(
|
|
4792
4810
|
{ email: user.email, firstName, method: "email" },
|
|
@@ -4829,7 +4847,7 @@ var emailSendCodeRoute = createRoute22({
|
|
|
4829
4847
|
var emailSendCodeHandler = async (c) => {
|
|
4830
4848
|
const userId = c.get("userId");
|
|
4831
4849
|
if (!userId) return problems.unauthorized(c);
|
|
4832
|
-
const { db, schema, env } = getAuthContext(c);
|
|
4850
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
4833
4851
|
const [emailMethod] = await db.select().from(schema.user2faMethods).where(and11(eq25(schema.user2faMethods.userId, userId), eq25(schema.user2faMethods.method, "email"))).limit(1);
|
|
4834
4852
|
if (!emailMethod) {
|
|
4835
4853
|
return problems.badRequest(c, "Email 2FA not enabled");
|
|
@@ -4841,7 +4859,7 @@ var emailSendCodeHandler = async (c) => {
|
|
|
4841
4859
|
await env.OAUTH_STATES.put(`email_2fa_challenge:${userId}`, codeHash, {
|
|
4842
4860
|
expirationTtl: 300
|
|
4843
4861
|
});
|
|
4844
|
-
const emailService = new EmailService(env);
|
|
4862
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
4845
4863
|
const firstName = user.name?.split(" ")[0] || null;
|
|
4846
4864
|
const emailResult = await emailService.send2faCodeEmail(
|
|
4847
4865
|
{ email: user.email, firstName, code },
|
|
@@ -4894,7 +4912,7 @@ var emailDisableHandler = async (c) => {
|
|
|
4894
4912
|
return problems.unauthorized(c);
|
|
4895
4913
|
}
|
|
4896
4914
|
const { code, method } = c.req.valid("json");
|
|
4897
|
-
const { db, schema, env } = getAuthContext(c);
|
|
4915
|
+
const { db, schema, env, emailBranding } = getAuthContext(c);
|
|
4898
4916
|
const verification = await verifyAny2faCode(db, env, userId, code, method, {
|
|
4899
4917
|
user2faMethods: schema.user2faMethods,
|
|
4900
4918
|
userBackupCodes: schema.userBackupCodes
|
|
@@ -4911,7 +4929,7 @@ var emailDisableHandler = async (c) => {
|
|
|
4911
4929
|
await invalidateAllUserSessions(db, { sessions: schema.sessions, users: schema.users }, userId);
|
|
4912
4930
|
const [user] = await db.select({ email: schema.users.email, name: schema.users.name }).from(schema.users).where(eq26(schema.users.id, userId)).limit(1);
|
|
4913
4931
|
if (user) {
|
|
4914
|
-
const emailService = new EmailService(env);
|
|
4932
|
+
const emailService = new EmailService(env, void 0, emailBranding);
|
|
4915
4933
|
const firstName = user.name?.split(" ")[0] || null;
|
|
4916
4934
|
await emailService.send2faDisabledEmail({ email: user.email, firstName }, db, schema.users);
|
|
4917
4935
|
}
|
|
@@ -5208,7 +5226,7 @@ var challengeResendRoute = createRoute27({
|
|
|
5208
5226
|
}
|
|
5209
5227
|
});
|
|
5210
5228
|
var challengeResendHandler = async (c) => {
|
|
5211
|
-
const { db, schema } = getAuthContext(c);
|
|
5229
|
+
const { db, schema, emailBranding } = getAuthContext(c);
|
|
5212
5230
|
const cookieName = getChallengeCookieName(c.env);
|
|
5213
5231
|
const challengeToken = getCookie3(c, cookieName);
|
|
5214
5232
|
if (!challengeToken) {
|
|
@@ -5232,7 +5250,7 @@ var challengeResendHandler = async (c) => {
|
|
|
5232
5250
|
await c.env.OAUTH_STATES.put(`email_2fa_challenge:${payload.userId}`, codeHash, {
|
|
5233
5251
|
expirationTtl: 300
|
|
5234
5252
|
});
|
|
5235
|
-
const emailService = new EmailService(c.env);
|
|
5253
|
+
const emailService = new EmailService(c.env, void 0, emailBranding);
|
|
5236
5254
|
const firstName = user.name?.split(" ")[0] || null;
|
|
5237
5255
|
await emailService.send2faCodeEmail({ email: user.email, firstName, code }, db, schema.users);
|
|
5238
5256
|
logger_default.info("Email 2FA code resent", { userId: payload.userId });
|