mirror of
https://github.com/PretendoNetwork/account.git
synced 2026-03-21 17:44:49 -05:00
commit
8349e55fc2
26
package-lock.json
generated
26
package-lock.json
generated
|
|
@ -27,6 +27,7 @@
|
|||
"fs-extra": "^8.1.0",
|
||||
"got": "^11.8.2",
|
||||
"hcaptcha": "^0.1.0",
|
||||
"he": "^1.2.0",
|
||||
"image-pixels": "^1.1.1",
|
||||
"ip2location-nodejs": "^9.6.3",
|
||||
"is-valid-hostname": "^1.0.2",
|
||||
|
|
@ -58,6 +59,7 @@
|
|||
"@types/dicer": "^0.2.2",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/fs-extra": "^11.0.1",
|
||||
"@types/he": "^1.2.3",
|
||||
"@types/morgan": "^1.9.4",
|
||||
"@types/ndarray": "^1.0.11",
|
||||
"@types/node": "^18.14.4",
|
||||
|
|
@ -2381,6 +2383,7 @@
|
|||
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz",
|
||||
"integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cluster-key-slot": "1.1.2",
|
||||
"generic-pool": "3.9.0",
|
||||
|
|
@ -3344,6 +3347,13 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/he": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/he/-/he-1.2.3.tgz",
|
||||
"integrity": "sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/http-cache-semantics": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
|
||||
|
|
@ -3419,6 +3429,7 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.112.tgz",
|
||||
"integrity": "sha512-i+Vukt9POdS/MBI7YrrkkI5fMfwFtOjphSmt4WXYLfwqsfr6z/HdCx7LqT9M7JktGob8WNgj8nFB4TbGNE4Cog==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
|
|
@ -3564,6 +3575,7 @@
|
|||
"integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
|
|
@ -4049,6 +4061,7 @@
|
|||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
|
@ -5842,6 +5855,7 @@
|
|||
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
|
|
@ -5988,6 +6002,7 @@
|
|||
"integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.8",
|
||||
|
|
@ -7116,6 +7131,15 @@
|
|||
"integrity": "sha512-iMrDmH2VpIEKOrcKWidVjI89FdDKTEdZ7PfPWkP27sTazIIkob8YfdY2ezaufAnWBiUUcvzsn0qF+dyXtBH2Vw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/http-cache-semantics": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
|
||||
|
|
@ -8416,6 +8440,7 @@
|
|||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.8.7.tgz",
|
||||
"integrity": "sha512-5Bo4CrUxrPITrhMKsqUTOkXXo2CoRC5tXxVQhnddCzqDMwRXfyStrxj1oY865g8gaekSBhxAeNkYyUSJvGm9Hw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"bson": "^5.5.0",
|
||||
"kareem": "2.5.1",
|
||||
|
|
@ -10654,6 +10679,7 @@
|
|||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
"fs-extra": "^8.1.0",
|
||||
"got": "^11.8.2",
|
||||
"hcaptcha": "^0.1.0",
|
||||
"he": "^1.2.0",
|
||||
"image-pixels": "^1.1.1",
|
||||
"ip2location-nodejs": "^9.6.3",
|
||||
"is-valid-hostname": "^1.0.2",
|
||||
|
|
@ -74,6 +75,7 @@
|
|||
"@types/dicer": "^0.2.2",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/fs-extra": "^11.0.1",
|
||||
"@types/he": "^1.2.3",
|
||||
"@types/morgan": "^1.9.4",
|
||||
"@types/ndarray": "^1.0.11",
|
||||
"@types/node": "^18.14.4",
|
||||
|
|
@ -88,4 +90,4 @@
|
|||
"ndarray": "^1.0.19",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,203 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap');
|
||||
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
supported-color-schemes:light dark;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
body.email-body,
|
||||
table.centerer,
|
||||
table.wrapper {
|
||||
background-color: #FFFFFF !important;
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
table.card {
|
||||
background-color: #673DB6 !important;
|
||||
}
|
||||
span.shoutout {
|
||||
color: #D9C6FA !important;
|
||||
}
|
||||
td.confirm-link {
|
||||
background-color: #9D6FF3 !important;
|
||||
}
|
||||
td.confirm-code {
|
||||
background-color: #D9C6FA !important;
|
||||
color: #45297A !important;
|
||||
}
|
||||
td.notice {
|
||||
color: #9D6FF3 !important;
|
||||
}
|
||||
td.notice a {
|
||||
color: #673DB6 !important;
|
||||
}
|
||||
img.logo {
|
||||
content: url("https://assets.pretendo.cc/images/pretendo-wordmark-singlecolor-purple.png") !important;
|
||||
}
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body.email-body,
|
||||
table.centerer,
|
||||
table.wrapper {
|
||||
background-color: #1B1F3B !important;
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
table.card {
|
||||
background-color: #23274A !important;
|
||||
}
|
||||
span.shoutout {
|
||||
color: #CAB1FB !important;
|
||||
}
|
||||
td.confirm-link {
|
||||
background-color: #673DB6 !important;
|
||||
}
|
||||
td.confirm-code {
|
||||
background-color: #373C65 !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
td.notice {
|
||||
color: #8990C1 !important;
|
||||
}
|
||||
td.notice a {
|
||||
color: #CAC1F5 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="email-body" bgcolor="#1B1F3B" style="margin-left: 0; margin-right: 0; margin-top: 0; margin-bottom: 0; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0; font-family: Poppins, Arial, Helvetica, sans-serif;">
|
||||
<div style="display:none;">Hello {{username}}! Your Pretendo Network ID activation is almost complete. Please click the link in this email to confirm your e-mail address and complete the activation process.</div>
|
||||
<table class="centerer" bgcolor="#1B1F3B" border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table class="wrapper" bgcolor="#1B1F3B" style="font-family: Poppins, Arial, Helvetica, sans-serif;" border="0" cellpadding="0" cellspacing="0" height="100%" width="420px">
|
||||
<tr>
|
||||
<td>
|
||||
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td width="32px"> </td>
|
||||
<td>
|
||||
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td height="36px" style="line-height: 36px;" width="100%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://pretendo.network">
|
||||
<img class="logo" width="auto" height="48px" src="https://assets.pretendo.cc/images/pretendo-wordmark-multicolor-purple+white.png" alt="Pretendo">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="36px" style="line-height: 36px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table class="card" bgcolor="#23274a" style="color: #ffffff; border-radius: 10px;" border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td width="24px" height="100%"> </td>
|
||||
<td>
|
||||
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr width="100%" height="48px" style="line-height: 48px;">
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr style="font-size: 24px; font-weight: 700;">
|
||||
<td>
|
||||
Hello <span class="shoutout" style="color: #cab1fb;">{{username}}</span>!
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="24px" style="line-height: 24px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #ffffff; ">
|
||||
Your Pretendo Network ID activation is almost complete. Please click the link below to confirm your e-mail address and complete the activation process.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="16px" style="line-height: 16px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="confirm-link" bgcolor="#673db6" style="font-size: 14px; font-weight: 700; border-radius: 10px; padding: 12px" align="center">
|
||||
<a href="{{confirmation-href}}" style="text-decoration: none; color: #ffffff; " width="100%">
|
||||
Confirm email address
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="48px" style="line-height: 48px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
You may also enter the following 6-digit code on your console:
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="16px" style="line-height: 16px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="confirm-code" bgcolor="#373c65" style="color: #ffffff; font-size: 14px; font-weight: 700; border-radius: 10px; padding: 12px" align="center">
|
||||
{{confirmation-code}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="48px" style="line-height: 48px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
We hope you have fun using our services!
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="36px" style="line-height: 36px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
The Pretendo Network team
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="24px" style="line-height: 24px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td width="24px" height="100%"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="18px" style="line-height: 18px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="notice" style="color: #8990c1; font-size: 12px;">
|
||||
Note: this email message was auto-generated, please do not respond. For further assistance, please join our <a href="https://invite.gg/pretendo" style="text-decoration: none; color: #ffffff; ">Discord server</a> or make a post on our <a href="https://forum.pretendo.network" style="text-decoration: none; color: #ffffff; ">Forum</a>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="48px" style="line-height: 48px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td width="32px"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" lang="en">
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
|
||||
lang="en">
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
|
||||
|
|
@ -8,45 +10,65 @@
|
|||
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
supported-color-schemes:light dark;
|
||||
supported-color-schemes: light dark;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
body.email-body,
|
||||
table.centerer,
|
||||
table.wrapper {
|
||||
background-color: #FFFFFF !important;
|
||||
color: #FFFFFF !important;
|
||||
background-color: #673DB6 !important;
|
||||
color: #673DB6 !important;
|
||||
}
|
||||
table.card {
|
||||
background-color: #673DB6 !important;
|
||||
background-color: #fff !important;
|
||||
}
|
||||
span.shoutout {
|
||||
color: #D9C6FA !important;
|
||||
color: #9D6FF3 !important;
|
||||
}
|
||||
td.confirm-link {
|
||||
td {
|
||||
color: #673DB6 !important;
|
||||
}
|
||||
td a {
|
||||
color: #673DB6 !important;
|
||||
font-weight: 700 !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
td.primary,
|
||||
td.primary a,
|
||||
td.primary span {
|
||||
background-color: #9D6FF3 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
td.confirm-code {
|
||||
td.secondary,
|
||||
td.secondary a,
|
||||
td.secondary span {
|
||||
background-color: #D9C6FA !important;
|
||||
color: #45297A !important;
|
||||
}
|
||||
td.notice {
|
||||
color: #9D6FF3 !important;
|
||||
color: #c5adf2 !important;
|
||||
}
|
||||
td.notice a {
|
||||
color: #673DB6 !important;
|
||||
color: #fff !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
td strong,
|
||||
td b {
|
||||
font-weight: 700 !important;
|
||||
color: #9D6FF3 !important;
|
||||
}
|
||||
img.logo {
|
||||
content: url("https://assets.pretendo.cc/images/pretendo-wordmark-singlecolor-purple.png") !important;
|
||||
content: url("https://assets.pretendo.cc/images/wordmark-white.png") !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body.email-body,
|
||||
table.centerer,
|
||||
table.wrapper {
|
||||
background-color: #1B1F3B !important;
|
||||
color: #FFFFFF !important;
|
||||
color: #A1A8D9 !important;
|
||||
}
|
||||
table.card {
|
||||
background-color: #23274A !important;
|
||||
|
|
@ -54,37 +76,131 @@
|
|||
span.shoutout {
|
||||
color: #CAB1FB !important;
|
||||
}
|
||||
td.confirm-link {
|
||||
td {
|
||||
color: #A1A8D9 !important;
|
||||
}
|
||||
td a {
|
||||
color: #fff !important;
|
||||
font-weight: 700 !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
td.header {
|
||||
color: #fff !important;
|
||||
}
|
||||
td.primary {
|
||||
background-color: #673DB6 !important;
|
||||
}
|
||||
td.confirm-code {
|
||||
td.secondary {
|
||||
background-color: #373C65 !important;
|
||||
color: #ffffff !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
td.signature {
|
||||
color: #A1A8D9 !important;
|
||||
}
|
||||
td.notice {
|
||||
color: #8990C1 !important;
|
||||
}
|
||||
td.notice a {
|
||||
color: #CAC1F5 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
td strong,
|
||||
td b {
|
||||
font-weight: 700 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
/* isn't this redundant? no. icloud web doesn't display the logo correctly without this. */
|
||||
img.logo {
|
||||
content: url("https://assets.pretendo.cc/images/wordmark-purple-white.png") !important;
|
||||
}
|
||||
}
|
||||
|
||||
td.button a,
|
||||
td.button span,
|
||||
u+.email-body td.button a,
|
||||
u+.email-body td.button span {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
/* the following specifically targets gmail, because it doesn't support media queries and automatically inverts colors */
|
||||
u+.email-body,
|
||||
u+.email-body table.centerer,
|
||||
u+.email-body table.wrapper {
|
||||
background-color: #1B1F3B !important;
|
||||
background-image: linear-gradient(#1B1F3B, #1B1F3B) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
u+.email-body table.card {
|
||||
background-color: #23274A !important;
|
||||
background-image: linear-gradient(#23274A, #23274A) !important;
|
||||
}
|
||||
u+.email-body span.shoutout {
|
||||
color: #fff !important;
|
||||
}
|
||||
u+.email-body td {
|
||||
color: #fff !important;
|
||||
}
|
||||
u+.email-body td a {
|
||||
color: #fff !important;
|
||||
font-weight: 700 !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
u+.email-body td.primary,
|
||||
u+.email-body td.primary a,
|
||||
u+.email-body td.primary span {
|
||||
background-color: #9D6FF3 !important;
|
||||
background-image: linear-gradient(#9D6FF3, #9D6FF3) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
u+.email-body td.secondary,
|
||||
u+.email-body td.secondary a,
|
||||
u+.email-body td.secondary span {
|
||||
background-color: #373C65 !important;
|
||||
background-image: linear-gradient(#373C65, #373C65) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
u+.email-body td.notice {
|
||||
color: #fff !important;
|
||||
}
|
||||
u+.email-body td.notice a {
|
||||
color: #fff !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
u+.email-body strong,
|
||||
u+.email-body b {
|
||||
font-weight: 700 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
u+.email-body .gmail-s {
|
||||
background: #000 !important;
|
||||
mix-blend-mode: screen !important;
|
||||
}
|
||||
u+.email-body .gmail-d {
|
||||
background: #000 !important;
|
||||
mix-blend-mode: difference !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="email-body" bgcolor="#1B1F3B" style="margin-left: 0; margin-right: 0; margin-top: 0; margin-bottom: 0; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0; font-family: Poppins, Arial, Helvetica, sans-serif;">
|
||||
<div style="display:none;">{{preview}}</div>
|
||||
<table class="centerer" bgcolor="#1B1F3B" border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
|
||||
<body class="email-body" bgcolor="#1B1F3B" color="#A1A8D9"
|
||||
style="margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;font-family:Poppins, Arial, Helvetica, sans-serif;color:#A1A8D9">
|
||||
|
||||
<div style="display:none;"><!--plainText--></div>
|
||||
|
||||
<table class="centerer" bgcolor="#1B1F3B" border="0" cellpadding="0" cellspacing="0" height="100%" width="100%"
|
||||
style="max-width:100%;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table class="wrapper" bgcolor="#1B1F3B" style="font-family: Poppins, Arial, Helvetica, sans-serif;" border="0" cellpadding="0" cellspacing="0" height="100%" width="420px">
|
||||
<table class="wrapper" bgcolor="#1B1F3B" style="font-family:Poppins, Arial, Helvetica, sans-serif;" border="0"
|
||||
cellpadding="0" cellspacing="0" height="100%" width="600px">
|
||||
<tr>
|
||||
<td>
|
||||
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td width="32px"> </td>
|
||||
<td width="16px"> </td>
|
||||
<td>
|
||||
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td height="36px" style="line-height: 36px;" width="100%"> </td>
|
||||
<td style="line-height:4em;" width="100%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
|
@ -92,72 +208,71 @@
|
|||
<tr>
|
||||
<td>
|
||||
<a href="https://pretendo.network">
|
||||
<img class="logo" width="auto" height="48px" src="https://assets.pretendo.cc/images/pretendo-wordmark-multicolor-purple+white.png" alt="Pretendo">
|
||||
</a>
|
||||
<img class="logo" width="auto" height="48px"
|
||||
src="https://assets.pretendo.cc/images/wordmark-purple-white.png" alt="Pretendo">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="36px" style="line-height: 36px;"> </td>
|
||||
<td width="100%" style="line-height:3em;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table class="card" bgcolor="#23274a" style="color: #ffffff; border-radius: 10px;" border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<table class="card" bgcolor="#23274a" style="color:#A1A8D9;border-radius:10px;"
|
||||
border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td width="24px" height="100%"> </td>
|
||||
<td width="36px" height="100%"> </td>
|
||||
<td>
|
||||
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr width="100%" height="48px" style="line-height: 48px;">
|
||||
<td> </td>
|
||||
|
||||
<!--innerHTML-->
|
||||
|
||||
<tr>
|
||||
<td width="100%" style="line-height:2em;"> </td>
|
||||
</tr>
|
||||
<tr style="font-size: 24px; font-weight: 700;">
|
||||
<td>
|
||||
Dear <span class="shoutout" style="color: #cab1fb;">{{username}}</span>,
|
||||
|
||||
<tr>
|
||||
<td align="right" class="signature">
|
||||
<div class="gmail-s">
|
||||
<div class="gmail-d">
|
||||
The Pretendo Network team
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="24px" style="line-height: 24px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #ffffff; ">
|
||||
{{paragraph}}
|
||||
</td>
|
||||
</tr>
|
||||
<!--{{buttonPlaceholder}}-->
|
||||
<tr>
|
||||
<td width="100%" height="36px" style="line-height: 36px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
The Pretendo Network team
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="24px" style="line-height: 24px;"> </td>
|
||||
<td width="100%" style="line-height:3em;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td width="24px" height="100%"> </td>
|
||||
<td width="36px" height="100%"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="18px" style="line-height: 18px;"> </td>
|
||||
<td width="100%" style="line-height:1.5em;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="notice" style="color: #8990c1; font-size: 12px;">
|
||||
Note: this email message was auto-generated, please do not respond. For further assistance, please join our <a href="https://invite.gg/pretendo" style="text-decoration: none; color: #ffffff; ">Discord server</a> or make a post on our <a href="https://forum.pretendo.network" style="text-decoration: none; color: #ffffff; ">Forum</a>.
|
||||
<td class="notice" style="color:#8990c1;text-align:center;font-size:14px;">
|
||||
<div class="gmail-s">
|
||||
<div class="gmail-d">
|
||||
Note: This is an automatic email; please do not respond.<br />For assistance, please
|
||||
visit <a href="https://forum.pretendo.network"
|
||||
style="text-decoration:none;color:#fff;">forum.pretendo.network</a>.
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="48px" style="line-height: 48px;"> </td>
|
||||
<td width="100%" style="line-height:5em;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td width="32px"> </td>
|
||||
<td width="16px"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
|
|
@ -166,5 +281,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
BIN
src/assets/images/wordmark-purple-white.png
Normal file
BIN
src/assets/images/wordmark-purple-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
BIN
src/assets/images/wordmark-white.png
Normal file
BIN
src/assets/images/wordmark-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
215
src/mailer.ts
215
src/mailer.ts
|
|
@ -2,11 +2,11 @@ import path from 'node:path';
|
|||
import fs from 'node:fs';
|
||||
import nodemailer from 'nodemailer';
|
||||
import * as aws from '@aws-sdk/client-ses';
|
||||
import { encode } from 'he';
|
||||
import { config, disabledFeatures } from '@/config-manager';
|
||||
import type { MailerOptions } from '@/types/common/mailer-options';
|
||||
|
||||
const genericEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/genericTemplate.html'), 'utf8');
|
||||
const confirmationEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/confirmationTemplate.html'), 'utf8');
|
||||
|
||||
let transporter: nodemailer.Transporter;
|
||||
|
||||
|
|
@ -28,31 +28,208 @@ if (!disabledFeatures.email) {
|
|||
});
|
||||
}
|
||||
|
||||
interface emailComponent {
|
||||
type: 'header' | 'paragraph';
|
||||
text: string;
|
||||
replacements?: emailTextReplacements;
|
||||
}
|
||||
interface paddingComponent {
|
||||
type: 'padding';
|
||||
size: number;
|
||||
}
|
||||
interface buttonComponent {
|
||||
type: 'button';
|
||||
text: string;
|
||||
link?: string;
|
||||
primary?: boolean;
|
||||
}
|
||||
interface emailTextReplacements {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export class CreateEmail {
|
||||
// an array which stores all components of the email
|
||||
private readonly componentArray: (emailComponent | paddingComponent | buttonComponent)[] = [];
|
||||
|
||||
/**
|
||||
* adds padding of the specified height in em units
|
||||
*/
|
||||
private addPadding(size: number): paddingComponent {
|
||||
return {
|
||||
type: 'padding',
|
||||
size
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a header. for greetings, do addHeader("Hi {{pnid}}!", { pnid: "theUsername" })
|
||||
*/
|
||||
public addHeader(text: string, replacements?: emailTextReplacements): this {
|
||||
const component: emailComponent = { type: 'header', text, replacements };
|
||||
this.componentArray.push(this.addPadding(3), component, this.addPadding(2));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a paragraph. for links, do addParagraph("this is a [named link](https://example.org)."). for greetings, do addParagraph("Hi {{pnid}}!", { pnid: "theUsername" })
|
||||
*/
|
||||
public addParagraph(text: string, replacements?: emailTextReplacements): this {
|
||||
const component: emailComponent = { type: 'paragraph', text, replacements };
|
||||
this.componentArray.push(component, this.addPadding(1));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a button
|
||||
*
|
||||
* @param {String} text the button text
|
||||
* @param {String} [link] the link
|
||||
* @param {boolean} [primary] set to false to use the secondary button styles (true by default)
|
||||
*/
|
||||
public addButton(text: string, link?: string, primary: boolean = true): this {
|
||||
const component: buttonComponent = { type: 'button', text, link, primary };
|
||||
this.componentArray.push(component, this.addPadding(2));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private addGmailDarkModeFix(el: string): string {
|
||||
return `<div class="gmail-s"><div class="gmail-d">${el}</div></div>`;
|
||||
}
|
||||
|
||||
// parses pnid name and links. set the plaintext bool (false by default) to use no html
|
||||
private parseReplacements(c: emailComponent, plainText: boolean = false): string {
|
||||
let tempText = c.text;
|
||||
|
||||
// for now only replaces the pnid for shoutouts. could easily be expanded to add more.
|
||||
if (c?.replacements) {
|
||||
Object.entries(c.replacements).forEach(([key, value]) => {
|
||||
const safeValue = encode(value);
|
||||
|
||||
if (key === 'pnid') {
|
||||
if (plainText) {
|
||||
tempText = tempText.replace(/{{pnid}}/g, safeValue);
|
||||
} else {
|
||||
tempText = tempText.replace(/{{pnid}}/g, `<span class="shoutout" style="color:#cab1fb;">${safeValue}</span>`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// wrap <b> and <strong> in a <span> element, to fix color on thunderbird and weight on icloud mail web
|
||||
const bRegex = /<b ?>.*?<\/b>|<strong ?>.*?<\/strong>/g;
|
||||
|
||||
if (!plainText) {
|
||||
tempText = tempText.replace(bRegex, el => `<span style="color:#fff;font-weight:bold;">${el}</span>`);
|
||||
}
|
||||
|
||||
// replace [links](https://example.com) with html anchor tags or a plaintext representation
|
||||
const linkRegex = /\[(?<linkText>.*?)\]\((?<linkAddress>.*?)\)/g;
|
||||
|
||||
if (plainText) {
|
||||
tempText = tempText.replace(linkRegex, '$<linkText> ($<linkAddress>)');
|
||||
} else {
|
||||
tempText = tempText.replace(linkRegex, '<a href="$<linkAddress>" style="text-decoration:underline;font-weight:700;color:#fff;"><u>$<linkText></u></a>');
|
||||
}
|
||||
|
||||
return tempText;
|
||||
}
|
||||
|
||||
// generates the html version of the email
|
||||
public toHTML(): string {
|
||||
let innerHTML = '';
|
||||
|
||||
this.componentArray.map((c, i) => {
|
||||
let el = '';
|
||||
|
||||
/* double padding causes issues, and the signature already has padding, so if the last element
|
||||
* is padding we just yeet it
|
||||
*/
|
||||
if (i === this.componentArray.length - 1 && c.type === 'padding') {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (c.type) {
|
||||
case 'padding':
|
||||
innerHTML += `\n<tr><td width="100%" style="line-height:${c.size}em;"> </td></tr>`;
|
||||
break;
|
||||
case 'header':
|
||||
el = this.parseReplacements(c);
|
||||
innerHTML += `\n<tr style="font-size:24px;font-weight:700;color:#fff"><td class="header">${this.addGmailDarkModeFix(el)}</td></tr>`;
|
||||
break;
|
||||
case 'paragraph':
|
||||
el = this.parseReplacements(c);
|
||||
innerHTML += `\n<tr><td>${this.addGmailDarkModeFix(el)}</td></tr>`;
|
||||
break;
|
||||
case 'button':
|
||||
if (c.link) {
|
||||
el = `<a href="${c.link}" style="color:#fff;" width="100%">${el}</a>`;
|
||||
} else {
|
||||
el = `<span style="color:#fff;" width="100%">${el}</span>`;
|
||||
}
|
||||
innerHTML += `\n<tr><td ${c.primary ? 'class="primary button" bgcolor="#673db6"' : 'class="secondary button" bgcolor="#373C65"'} style="font-weight:700;border-radius:10px;padding:12px" align="center">${this.addGmailDarkModeFix(el)}</td></tr>`;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
const generatedHTML = genericEmailTemplate
|
||||
.replace('<!--innerHTML-->', innerHTML)
|
||||
.replace('<!--plainText-->', this.toPlainText());
|
||||
|
||||
return generatedHTML;
|
||||
}
|
||||
|
||||
// generates the plaintext version that shows up on the email preview (and is shown by plaintext clients)
|
||||
public toPlainText(): string {
|
||||
let plainText = '';
|
||||
|
||||
this.componentArray.forEach((c) => {
|
||||
let el = '';
|
||||
switch (c.type) {
|
||||
case 'padding':
|
||||
break;
|
||||
case 'header':
|
||||
el = this.parseReplacements(c, true);
|
||||
plainText += `\n${el}`;
|
||||
break;
|
||||
case 'paragraph':
|
||||
el = this.parseReplacements(c, true);
|
||||
plainText += `\n${el}`;
|
||||
break;
|
||||
case 'button':
|
||||
if (c.link) {
|
||||
plainText += `\n\n${c.text}: ${c.link}\n`;
|
||||
} else {
|
||||
plainText += ` ${c.text}\n`;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// the signature is baked into the template, so it needs to be added manually to the plaintext version
|
||||
plainText += '\n\n- The Pretendo Network team';
|
||||
|
||||
// and so is the notice about the email being auto-generated
|
||||
plainText += '\n\nNote: This is an automatic email; please do not respond. For assistance, please visit https://forum.pretendo.network.';
|
||||
|
||||
plainText = plainText.replace(/(<([^>]+)>)/gi, '');
|
||||
|
||||
return plainText;
|
||||
}
|
||||
}
|
||||
|
||||
export async function sendMail(options: MailerOptions): Promise<void> {
|
||||
if (!disabledFeatures.email) {
|
||||
const { to, subject, username, paragraph, preview, text, link, confirmation } = options;
|
||||
|
||||
let html = confirmation ? confirmationEmailTemplate : genericEmailTemplate;
|
||||
|
||||
html = html.replace(/{{username}}/g, username);
|
||||
html = html.replace(/{{paragraph}}/g, paragraph || '');
|
||||
html = html.replace(/{{preview}}/g, preview || '');
|
||||
html = html.replace(/{{confirmation-href}}/g, confirmation?.href || '');
|
||||
html = html.replace(/{{confirmation-code}}/g, confirmation?.code || '');
|
||||
|
||||
if (link) {
|
||||
const { href, text } = link;
|
||||
|
||||
const button = `<tr><td width="100%" height="16px" style="line-height: 16px;"> </td></tr><tr><td class="confirm-link" bgcolor="#673db6" style="font-size: 14px; font-weight: 700; border-radius: 10px; padding: 12px" align="center"><a href="${href}" style="text-decoration: none; color: #ffffff; " width="100%">${text}</a></td></tr>`;
|
||||
html = html.replace(/<!--{{buttonPlaceholder}}-->/g, button);
|
||||
}
|
||||
const { to, subject, email } = options;
|
||||
|
||||
await transporter.sendMail({
|
||||
from: config.email.from,
|
||||
to,
|
||||
subject,
|
||||
text,
|
||||
html
|
||||
text: email.toPlainText(),
|
||||
html: email.toHTML()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,21 @@ async function consoleStatusVerificationMiddleware(request: express.Request, res
|
|||
return;
|
||||
}
|
||||
|
||||
const certificateDeviceID = parseInt(request.certificate.certificateName.slice(2).split('-')[0], 16);
|
||||
|
||||
if (deviceID !== certificateDeviceID) {
|
||||
// TODO - Change this to a different error
|
||||
response.status(400).send(xmlbuilder.create({
|
||||
error: {
|
||||
cause: 'Bad Request',
|
||||
code: '1600',
|
||||
message: 'Unable to process request'
|
||||
}
|
||||
}).end());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const serialNumber = getValueFromHeaders(request.headers, 'x-nintendo-serial-number');
|
||||
|
||||
// TODO - Verify serial numbers somehow?
|
||||
|
|
@ -122,21 +137,6 @@ async function consoleStatusVerificationMiddleware(request: express.Request, res
|
|||
return;
|
||||
}
|
||||
|
||||
const certificateDeviceID = parseInt(request.certificate.certificateName.slice(2).split('-')[0], 16);
|
||||
|
||||
if (deviceID !== certificateDeviceID) {
|
||||
// TODO - Change this to a different error
|
||||
response.status(400).send(xmlbuilder.create({
|
||||
error: {
|
||||
cause: 'Bad Request',
|
||||
code: '1600',
|
||||
message: 'Unable to process request'
|
||||
}
|
||||
}).end());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (device.access_level < 0) {
|
||||
response.status(400).send(xmlbuilder.create({
|
||||
errors: {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,7 @@
|
|||
import type { CreateEmail } from '@/mailer';
|
||||
|
||||
export interface MailerOptions {
|
||||
to: string;
|
||||
subject: string;
|
||||
username: string;
|
||||
paragraph?: string;
|
||||
preview?: string;
|
||||
text: string;
|
||||
link?: {
|
||||
href: string;
|
||||
text: string;
|
||||
};
|
||||
confirmation?: {
|
||||
href: string;
|
||||
code: string;
|
||||
};
|
||||
email: CreateEmail;
|
||||
}
|
||||
|
|
|
|||
64
src/util.ts
64
src/util.ts
|
|
@ -4,7 +4,7 @@ import { S3 } from '@aws-sdk/client-s3';
|
|||
import fs from 'fs-extra';
|
||||
import bufferCrc32 from 'buffer-crc32';
|
||||
import { crc32 } from 'crc';
|
||||
import { sendMail } from '@/mailer';
|
||||
import { sendMail, CreateEmail } from '@/mailer';
|
||||
import { SystemType } from '@/types/common/system-types';
|
||||
import { TokenType } from '@/types/common/token-types';
|
||||
import { config, disabledFeatures } from '@/config-manager';
|
||||
|
|
@ -201,39 +201,47 @@ export function nascError(errorCode: string): URLSearchParams {
|
|||
}
|
||||
|
||||
export async function sendConfirmationEmail(pnid: mongoose.HydratedDocument<IPNID, IPNIDMethods>): Promise<void> {
|
||||
const email = new CreateEmail()
|
||||
.addHeader('Hello {{pnid}}!', { pnid: pnid.username })
|
||||
.addParagraph('Your <b>Pretendo Network ID</b> activation is almost complete. Please click the link below to confirm your e-mail address and complete the activation process.')
|
||||
.addButton('Confirm email address', `https://api.pretendo.cc/v1/email/verify?token=${pnid.identification.email_token}`)
|
||||
.addParagraph('You may also enter the following 6-digit code on your console:')
|
||||
.addButton(pnid.identification.email_code, '', false)
|
||||
.addParagraph('We hope you have fun using our services!');
|
||||
|
||||
const options = {
|
||||
to: pnid.email.address,
|
||||
subject: '[Pretendo Network] Please confirm your email address',
|
||||
username: pnid.username,
|
||||
confirmation: {
|
||||
href: `https://api.pretendo.cc/v1/email/verify?token=${pnid.identification.email_token}`,
|
||||
code: pnid.identification.email_code
|
||||
},
|
||||
text: `Hello ${pnid.username}! \r\n\r\nYour Pretendo Network ID activation is almost complete. Please click the link to confirm your e-mail address and complete the activation process: \r\nhttps://api.pretendo.cc/v1/email/verify?token=${pnid.identification.email_token} \r\n\r\nYou may also enter the following 6-digit code on your console: ${pnid.identification.email_code}`
|
||||
email
|
||||
};
|
||||
|
||||
await sendMail(options);
|
||||
}
|
||||
|
||||
export async function sendEmailConfirmedEmail(pnid: mongoose.HydratedDocument<IPNID, IPNIDMethods>): Promise<void> {
|
||||
const email = new CreateEmail()
|
||||
.addHeader('Dear {{pnid}}!', { pnid: pnid.username })
|
||||
.addParagraph('Your email address has been confirmed.')
|
||||
.addParagraph('We hope you have fun on Pretendo Network!');
|
||||
|
||||
const options = {
|
||||
to: pnid.email.address,
|
||||
subject: '[Pretendo Network] Email address confirmed',
|
||||
username: pnid.username,
|
||||
paragraph: 'your email address has been confirmed. We hope you have fun on Pretendo Network!',
|
||||
text: `Dear ${pnid.username}, \r\n\r\nYour email address has been confirmed. We hope you have fun on Pretendo Network!`
|
||||
email
|
||||
};
|
||||
|
||||
await sendMail(options);
|
||||
}
|
||||
|
||||
export async function sendEmailConfirmedParentalControlsEmail(pnid: mongoose.HydratedDocument<IPNID, IPNIDMethods>): Promise<void> {
|
||||
const email = new CreateEmail()
|
||||
.addHeader('Dear {{pnid}},', { pnid: pnid.username })
|
||||
.addParagraph('your email address has been confirmed for use with Parental Controls.');
|
||||
|
||||
const options = {
|
||||
to: pnid.email.address,
|
||||
subject: '[Pretendo Network] Email address confirmed for Parental Controls',
|
||||
username: pnid.username,
|
||||
paragraph: 'your email address has been confirmed for use with Parental Controls.',
|
||||
text: `Dear ${pnid.username}, \r\n\r\nYour email address has been confirmed for use with Parental Controls.`
|
||||
email
|
||||
};
|
||||
|
||||
await sendMail(options);
|
||||
|
|
@ -254,31 +262,31 @@ export async function sendForgotPasswordEmail(pnid: mongoose.HydratedDocument<IP
|
|||
|
||||
// TODO - Handle null token
|
||||
|
||||
const email = new CreateEmail()
|
||||
.addHeader('Dear {{pnid}},', { pnid: pnid.username })
|
||||
.addParagraph('a password reset has been requested from this account.')
|
||||
.addParagraph('If you did not request the password reset, please ignore this email. If you did request this password reset, please click the link below to reset your password.')
|
||||
.addButton('Reset password', `${config.website_base}/account/reset-password?token=${encodeURIComponent(passwordResetToken)}`);
|
||||
|
||||
const mailerOptions = {
|
||||
to: pnid.email.address,
|
||||
subject: '[Pretendo Network] Forgot Password',
|
||||
username: pnid.username,
|
||||
paragraph: 'a password reset has been requested from this account. If you did not request the password reset, please ignore this email. If you did request this password reset, please click the link below to reset your password.',
|
||||
link: {
|
||||
text: 'Reset password',
|
||||
href: `${config.website_base}/account/reset-password?token=${encodeURIComponent(passwordResetToken)}`
|
||||
},
|
||||
text: `Dear ${pnid.username}, a password reset has been requested from this account. \r\n\r\nIf you did not request the password reset, please ignore this email. \r\nIf you did request this password reset, please click the link to reset your password: ${config.website_base}/account/reset-password?token=${encodeURIComponent(passwordResetToken)}`
|
||||
email
|
||||
};
|
||||
|
||||
await sendMail(mailerOptions);
|
||||
}
|
||||
|
||||
export async function sendPNIDDeletedEmail(email: string, username: string): Promise<void> {
|
||||
export async function sendPNIDDeletedEmail(emailAddress: string, username: string): Promise<void> {
|
||||
const email = new CreateEmail()
|
||||
.addHeader('Dear {{pnid}},', { pnid: username })
|
||||
.addParagraph('your PNID has successfully been deleted.')
|
||||
.addParagraph('If you had a tier subscription, a separate cancellation email will be sent. If you do not receive this cancellation email, or you are still being charged for your subscription, please contact <b>@jonbarrow</b> on our [Discord server](https://discord.pretendo.network/).');
|
||||
|
||||
const options = {
|
||||
to: email,
|
||||
to: emailAddress,
|
||||
subject: '[Pretendo Network] PNID Deleted',
|
||||
username: username,
|
||||
link: {
|
||||
text: 'Discord Server',
|
||||
href: 'https://discord.com/invite/pretendo'
|
||||
},
|
||||
text: `Your PNID ${username} has successfully been deleted. If you had a tier subscription, a separate cancellation email will be sent. If you do not receive this cancellation email, or your subscription is still being charged, please contact @jon on our Discord server`
|
||||
email
|
||||
};
|
||||
|
||||
await sendMail(options);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user