aaspai-authx 0.1.3 → 0.1.5
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/express/index.cjs +425 -30
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.js +425 -30
- package/dist/express/index.js.map +1 -1
- package/dist/index.cjs +425 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +425 -30
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +425 -30
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.js +425 -30
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -590,7 +590,7 @@ var AuthAdminService = class {
|
|
|
590
590
|
}
|
|
591
591
|
async updateUserPassword(userId, newPassword) {
|
|
592
592
|
const hashed = await bcrypt.hash(newPassword, 10);
|
|
593
|
-
await OrgUser.findOneAndUpdate({ id: userId }, {
|
|
593
|
+
await OrgUser.findOneAndUpdate({ id: userId }, { passwordHash: hashed });
|
|
594
594
|
}
|
|
595
595
|
// -------------------------------------------------------------------
|
|
596
596
|
// ADMIN TOKEN (self-issued JWT)
|
|
@@ -643,7 +643,6 @@ var EmailService = class {
|
|
|
643
643
|
return jwt3.verify(token, process.env.EMAIL_JWT_SECRET);
|
|
644
644
|
}
|
|
645
645
|
async send(to, subject, html) {
|
|
646
|
-
console.log("[EmailService] Attempting to send:", { to, subject });
|
|
647
646
|
try {
|
|
648
647
|
const info = await this.transporter.sendMail({
|
|
649
648
|
from: process.env.EMAIL_FROM,
|
|
@@ -671,18 +670,6 @@ var EmailService = class {
|
|
|
671
670
|
}
|
|
672
671
|
}
|
|
673
672
|
canSend(lastEmailSent) {
|
|
674
|
-
console.log(
|
|
675
|
-
process.env.EMAIL_PASSWORD,
|
|
676
|
-
"pssword",
|
|
677
|
-
process.env.EMAIL_USER,
|
|
678
|
-
"user",
|
|
679
|
-
process.env.EMAIL_SECURE,
|
|
680
|
-
"secure",
|
|
681
|
-
process.env.EMAIL_PORT,
|
|
682
|
-
"porat",
|
|
683
|
-
process.env.EMAIL_HOST,
|
|
684
|
-
"hosat"
|
|
685
|
-
);
|
|
686
673
|
const now = Date.now();
|
|
687
674
|
const windowStart = now - this.WINDOW_MINUTES * 60 * 1e3;
|
|
688
675
|
const emailsInWindow = (lastEmailSent || []).map((d) => new Date(d)).filter((d) => d.getTime() >= windowStart);
|
|
@@ -696,6 +683,386 @@ var EmailService = class {
|
|
|
696
683
|
}
|
|
697
684
|
};
|
|
698
685
|
|
|
686
|
+
// src/templates/email.templates.ts
|
|
687
|
+
var colors = {
|
|
688
|
+
background: "#0a0a0a",
|
|
689
|
+
cardBackground: "#111111",
|
|
690
|
+
cardBorder: "#1a1a1a",
|
|
691
|
+
accent: "#ffffff",
|
|
692
|
+
accentMuted: "rgba(255, 255, 255, 0.9)",
|
|
693
|
+
textPrimary: "#ffffff",
|
|
694
|
+
textSecondary: "rgba(255, 255, 255, 0.7)",
|
|
695
|
+
textMuted: "rgba(255, 255, 255, 0.5)",
|
|
696
|
+
divider: "rgba(255, 255, 255, 0.1)",
|
|
697
|
+
subtle: "#161616",
|
|
698
|
+
highlight: "rgba(255, 255, 255, 0.05)"
|
|
699
|
+
};
|
|
700
|
+
var styles = {
|
|
701
|
+
wrapper: `
|
|
702
|
+
margin: 0;
|
|
703
|
+
padding: 40px 20px;
|
|
704
|
+
background-color: ${colors.background};
|
|
705
|
+
background-image:
|
|
706
|
+
radial-gradient(ellipse at top, rgba(255,255,255,0.03) 0%, transparent 50%),
|
|
707
|
+
radial-gradient(ellipse at bottom, rgba(255,255,255,0.02) 0%, transparent 50%);
|
|
708
|
+
min-height: 100vh;
|
|
709
|
+
`,
|
|
710
|
+
container: `
|
|
711
|
+
max-width: 520px;
|
|
712
|
+
margin: 0 auto;
|
|
713
|
+
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
714
|
+
color: ${colors.textPrimary};
|
|
715
|
+
line-height: 1.7;
|
|
716
|
+
`,
|
|
717
|
+
card: `
|
|
718
|
+
background-color: ${colors.cardBackground};
|
|
719
|
+
border: 1px solid ${colors.cardBorder};
|
|
720
|
+
border-radius: 16px;
|
|
721
|
+
overflow: hidden;
|
|
722
|
+
box-shadow:
|
|
723
|
+
0 0 0 1px rgba(255,255,255,0.05),
|
|
724
|
+
0 20px 50px -20px rgba(0,0,0,0.5),
|
|
725
|
+
0 30px 60px -30px rgba(0,0,0,0.3);
|
|
726
|
+
`,
|
|
727
|
+
header: `
|
|
728
|
+
padding: 48px 40px 32px;
|
|
729
|
+
text-align: center;
|
|
730
|
+
border-bottom: 1px solid ${colors.divider};
|
|
731
|
+
`,
|
|
732
|
+
iconWrapper: `
|
|
733
|
+
width: 64px;
|
|
734
|
+
height: 64px;
|
|
735
|
+
margin: 0 auto 24px;
|
|
736
|
+
background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%);
|
|
737
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
738
|
+
border-radius: 16px;
|
|
739
|
+
display: flex;
|
|
740
|
+
align-items: center;
|
|
741
|
+
justify-content: center;
|
|
742
|
+
font-size: 28px;
|
|
743
|
+
`,
|
|
744
|
+
headerTitle: `
|
|
745
|
+
color: ${colors.textPrimary};
|
|
746
|
+
margin: 0;
|
|
747
|
+
font-size: 24px;
|
|
748
|
+
font-weight: 600;
|
|
749
|
+
letter-spacing: -0.5px;
|
|
750
|
+
`,
|
|
751
|
+
headerSubtitle: `
|
|
752
|
+
color: ${colors.textMuted};
|
|
753
|
+
margin: 8px 0 0;
|
|
754
|
+
font-size: 14px;
|
|
755
|
+
font-weight: 400;
|
|
756
|
+
`,
|
|
757
|
+
body: `
|
|
758
|
+
padding: 40px;
|
|
759
|
+
`,
|
|
760
|
+
greeting: `
|
|
761
|
+
margin: 0 0 24px;
|
|
762
|
+
color: ${colors.textPrimary};
|
|
763
|
+
font-size: 18px;
|
|
764
|
+
font-weight: 500;
|
|
765
|
+
`,
|
|
766
|
+
paragraph: `
|
|
767
|
+
margin: 0 0 20px;
|
|
768
|
+
color: ${colors.textSecondary};
|
|
769
|
+
font-size: 15px;
|
|
770
|
+
line-height: 1.7;
|
|
771
|
+
`,
|
|
772
|
+
buttonWrapper: `
|
|
773
|
+
text-align: center;
|
|
774
|
+
margin: 32px 0;
|
|
775
|
+
`,
|
|
776
|
+
button: `
|
|
777
|
+
display: inline-block;
|
|
778
|
+
background-color: ${colors.accent};
|
|
779
|
+
color: #000000 !important;
|
|
780
|
+
text-decoration: none;
|
|
781
|
+
padding: 14px 36px;
|
|
782
|
+
border-radius: 8px;
|
|
783
|
+
font-weight: 600;
|
|
784
|
+
font-size: 14px;
|
|
785
|
+
letter-spacing: 0.3px;
|
|
786
|
+
transition: all 0.2s ease;
|
|
787
|
+
`,
|
|
788
|
+
secondaryButton: `
|
|
789
|
+
display: inline-block;
|
|
790
|
+
background-color: transparent;
|
|
791
|
+
color: ${colors.textPrimary} !important;
|
|
792
|
+
text-decoration: none;
|
|
793
|
+
padding: 12px 28px;
|
|
794
|
+
border-radius: 8px;
|
|
795
|
+
font-weight: 500;
|
|
796
|
+
font-size: 14px;
|
|
797
|
+
border: 1px solid ${colors.divider};
|
|
798
|
+
`,
|
|
799
|
+
infoCard: `
|
|
800
|
+
background-color: ${colors.subtle};
|
|
801
|
+
border: 1px solid ${colors.divider};
|
|
802
|
+
border-radius: 12px;
|
|
803
|
+
padding: 20px 24px;
|
|
804
|
+
margin: 28px 0;
|
|
805
|
+
`,
|
|
806
|
+
infoCardTitle: `
|
|
807
|
+
margin: 0 0 12px;
|
|
808
|
+
color: ${colors.textPrimary};
|
|
809
|
+
font-size: 13px;
|
|
810
|
+
font-weight: 600;
|
|
811
|
+
text-transform: uppercase;
|
|
812
|
+
letter-spacing: 0.5px;
|
|
813
|
+
`,
|
|
814
|
+
infoCardText: `
|
|
815
|
+
margin: 0;
|
|
816
|
+
color: ${colors.textSecondary};
|
|
817
|
+
font-size: 14px;
|
|
818
|
+
line-height: 1.6;
|
|
819
|
+
`,
|
|
820
|
+
warningCard: `
|
|
821
|
+
background: linear-gradient(135deg, rgba(255,180,0,0.1) 0%, rgba(255,140,0,0.05) 100%);
|
|
822
|
+
border: 1px solid rgba(255,180,0,0.2);
|
|
823
|
+
border-radius: 12px;
|
|
824
|
+
padding: 20px 24px;
|
|
825
|
+
margin: 28px 0;
|
|
826
|
+
`,
|
|
827
|
+
warningCardTitle: `
|
|
828
|
+
margin: 0 0 12px;
|
|
829
|
+
color: #ffc107;
|
|
830
|
+
font-size: 13px;
|
|
831
|
+
font-weight: 600;
|
|
832
|
+
text-transform: uppercase;
|
|
833
|
+
letter-spacing: 0.5px;
|
|
834
|
+
`,
|
|
835
|
+
warningCardText: `
|
|
836
|
+
margin: 0;
|
|
837
|
+
color: rgba(255,255,255,0.7);
|
|
838
|
+
font-size: 14px;
|
|
839
|
+
line-height: 1.6;
|
|
840
|
+
`,
|
|
841
|
+
successCard: `
|
|
842
|
+
background: linear-gradient(135deg, rgba(0,255,150,0.1) 0%, rgba(0,200,100,0.05) 100%);
|
|
843
|
+
border: 1px solid rgba(0,255,150,0.2);
|
|
844
|
+
border-radius: 12px;
|
|
845
|
+
padding: 20px 24px;
|
|
846
|
+
margin: 28px 0;
|
|
847
|
+
`,
|
|
848
|
+
successCardTitle: `
|
|
849
|
+
margin: 0 0 12px;
|
|
850
|
+
color: #00ff96;
|
|
851
|
+
font-size: 13px;
|
|
852
|
+
font-weight: 600;
|
|
853
|
+
text-transform: uppercase;
|
|
854
|
+
letter-spacing: 0.5px;
|
|
855
|
+
`,
|
|
856
|
+
linkSection: `
|
|
857
|
+
margin: 32px 0;
|
|
858
|
+
padding: 20px;
|
|
859
|
+
background-color: ${colors.subtle};
|
|
860
|
+
border-radius: 8px;
|
|
861
|
+
border: 1px solid ${colors.divider};
|
|
862
|
+
`,
|
|
863
|
+
linkLabel: `
|
|
864
|
+
margin: 0 0 8px;
|
|
865
|
+
color: ${colors.textMuted};
|
|
866
|
+
font-size: 12px;
|
|
867
|
+
text-transform: uppercase;
|
|
868
|
+
letter-spacing: 0.5px;
|
|
869
|
+
`,
|
|
870
|
+
linkText: `
|
|
871
|
+
word-break: break-all;
|
|
872
|
+
color: ${colors.textSecondary};
|
|
873
|
+
font-size: 13px;
|
|
874
|
+
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;
|
|
875
|
+
margin: 0;
|
|
876
|
+
`,
|
|
877
|
+
divider: `
|
|
878
|
+
border: none;
|
|
879
|
+
border-top: 1px solid ${colors.divider};
|
|
880
|
+
margin: 32px 0;
|
|
881
|
+
`,
|
|
882
|
+
footer: `
|
|
883
|
+
padding: 24px 40px 32px;
|
|
884
|
+
text-align: center;
|
|
885
|
+
border-top: 1px solid ${colors.divider};
|
|
886
|
+
`,
|
|
887
|
+
footerText: `
|
|
888
|
+
margin: 0;
|
|
889
|
+
color: ${colors.textMuted};
|
|
890
|
+
font-size: 12px;
|
|
891
|
+
line-height: 1.8;
|
|
892
|
+
`,
|
|
893
|
+
footerLink: `
|
|
894
|
+
color: ${colors.textSecondary};
|
|
895
|
+
text-decoration: none;
|
|
896
|
+
`,
|
|
897
|
+
badge: `
|
|
898
|
+
display: inline-block;
|
|
899
|
+
background-color: rgba(255,255,255,0.1);
|
|
900
|
+
color: ${colors.textSecondary};
|
|
901
|
+
padding: 4px 12px;
|
|
902
|
+
border-radius: 20px;
|
|
903
|
+
font-size: 12px;
|
|
904
|
+
font-weight: 500;
|
|
905
|
+
letter-spacing: 0.3px;
|
|
906
|
+
`,
|
|
907
|
+
listItem: `
|
|
908
|
+
color: ${colors.textSecondary};
|
|
909
|
+
font-size: 14px;
|
|
910
|
+
margin: 8px 0;
|
|
911
|
+
padding-left: 8px;
|
|
912
|
+
`,
|
|
913
|
+
metaRow: `
|
|
914
|
+
display: flex;
|
|
915
|
+
justify-content: space-between;
|
|
916
|
+
padding: 12px 0;
|
|
917
|
+
border-bottom: 1px solid ${colors.divider};
|
|
918
|
+
`,
|
|
919
|
+
metaLabel: `
|
|
920
|
+
color: ${colors.textMuted};
|
|
921
|
+
font-size: 13px;
|
|
922
|
+
`,
|
|
923
|
+
metaValue: `
|
|
924
|
+
color: ${colors.textPrimary};
|
|
925
|
+
font-size: 13px;
|
|
926
|
+
font-weight: 500;
|
|
927
|
+
`
|
|
928
|
+
};
|
|
929
|
+
function buildVerificationEmailTemplate(data) {
|
|
930
|
+
const { firstName, verificationUrl, expiresIn } = data;
|
|
931
|
+
return `
|
|
932
|
+
<!DOCTYPE html>
|
|
933
|
+
<html lang="en">
|
|
934
|
+
<head>
|
|
935
|
+
<meta charset="UTF-8">
|
|
936
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
937
|
+
<meta name="color-scheme" content="dark">
|
|
938
|
+
<meta name="supported-color-schemes" content="dark">
|
|
939
|
+
<title>Verify Your Email</title>
|
|
940
|
+
<!--[if mso]>
|
|
941
|
+
<style type="text/css">
|
|
942
|
+
body, table, td {font-family: Arial, Helvetica, sans-serif !important;}
|
|
943
|
+
</style>
|
|
944
|
+
<![endif]-->
|
|
945
|
+
</head>
|
|
946
|
+
<body style="${styles.wrapper}">
|
|
947
|
+
<div style="${styles.container}">
|
|
948
|
+
<div style="${styles.card}">
|
|
949
|
+
<!-- Header -->
|
|
950
|
+
<div style="${styles.header}">
|
|
951
|
+
<div style="${styles.iconWrapper}">
|
|
952
|
+
\u2709\uFE0F
|
|
953
|
+
</div>
|
|
954
|
+
<h1 style="${styles.headerTitle}">Verify your email</h1>
|
|
955
|
+
<p style="${styles.headerSubtitle}">One quick step to get started</p>
|
|
956
|
+
</div>
|
|
957
|
+
|
|
958
|
+
<!-- Body -->
|
|
959
|
+
<div style="${styles.body}">
|
|
960
|
+
<p style="${styles.greeting}">Hi ${firstName},</p>
|
|
961
|
+
|
|
962
|
+
<p style="${styles.paragraph}">
|
|
963
|
+
Thanks for signing up. To complete your registration and unlock all features,
|
|
964
|
+
please verify your email address by clicking the button below.
|
|
965
|
+
</p>
|
|
966
|
+
|
|
967
|
+
<div style="${styles.buttonWrapper}">
|
|
968
|
+
<a href="${verificationUrl}" style="${styles.button}" target="_blank">
|
|
969
|
+
Verify Email Address
|
|
970
|
+
</a>
|
|
971
|
+
</div>
|
|
972
|
+
|
|
973
|
+
<div style="${styles.infoCard}">
|
|
974
|
+
<p style="${styles.infoCardTitle}">\u23F1 Time Sensitive</p>
|
|
975
|
+
<p style="${styles.infoCardText}">
|
|
976
|
+
This verification link will expire in <strong>${expiresIn}</strong>.
|
|
977
|
+
If you didn't create an account, you can safely ignore this email.
|
|
978
|
+
</p>
|
|
979
|
+
</div>
|
|
980
|
+
</div>
|
|
981
|
+
|
|
982
|
+
<!-- Footer -->
|
|
983
|
+
<div style="${styles.footer}">
|
|
984
|
+
<p style="${styles.footerText}">
|
|
985
|
+
This is an automated message \u2014 please do not reply.<br>
|
|
986
|
+
\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} All rights reserved.
|
|
987
|
+
</p>
|
|
988
|
+
</div>
|
|
989
|
+
</div>
|
|
990
|
+
</div>
|
|
991
|
+
</body>
|
|
992
|
+
</html>
|
|
993
|
+
`;
|
|
994
|
+
}
|
|
995
|
+
function buildResetPasswordEmailTemplate(data) {
|
|
996
|
+
const { firstName, resetUrl, expiresIn } = data;
|
|
997
|
+
return `
|
|
998
|
+
<!DOCTYPE html>
|
|
999
|
+
<html lang="en">
|
|
1000
|
+
<head>
|
|
1001
|
+
<meta charset="UTF-8">
|
|
1002
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1003
|
+
<meta name="color-scheme" content="dark">
|
|
1004
|
+
<meta name="supported-color-schemes" content="dark">
|
|
1005
|
+
<title>Reset Your Password</title>
|
|
1006
|
+
</head>
|
|
1007
|
+
<body style="${styles.wrapper}">
|
|
1008
|
+
<div style="${styles.container}">
|
|
1009
|
+
<div style="${styles.card}">
|
|
1010
|
+
<!-- Header -->
|
|
1011
|
+
<div style="${styles.header}">
|
|
1012
|
+
<div style="${styles.iconWrapper}">
|
|
1013
|
+
\u{1F510}
|
|
1014
|
+
</div>
|
|
1015
|
+
<h1 style="${styles.headerTitle}">Reset your password</h1>
|
|
1016
|
+
<p style="${styles.headerSubtitle}">We received a reset request</p>
|
|
1017
|
+
</div>
|
|
1018
|
+
|
|
1019
|
+
<!-- Body -->
|
|
1020
|
+
<div style="${styles.body}">
|
|
1021
|
+
<p style="${styles.greeting}">Hi ${firstName},</p>
|
|
1022
|
+
|
|
1023
|
+
<p style="${styles.paragraph}">
|
|
1024
|
+
We received a request to reset the password for your account.
|
|
1025
|
+
Click the button below to create a new password.
|
|
1026
|
+
</p>
|
|
1027
|
+
|
|
1028
|
+
<div style="${styles.buttonWrapper}">
|
|
1029
|
+
<a href="${resetUrl}" style="${styles.button}" target="_blank">
|
|
1030
|
+
Reset Password
|
|
1031
|
+
</a>
|
|
1032
|
+
</div>
|
|
1033
|
+
|
|
1034
|
+
<div style="${styles.warningCard}">
|
|
1035
|
+
<p style="${styles.warningCardTitle}">\u26A0\uFE0F Security Notice</p>
|
|
1036
|
+
<p style="${styles.warningCardText}">
|
|
1037
|
+
\u2022 This link expires in <strong>${expiresIn}</strong><br>
|
|
1038
|
+
\u2022 This link can only be used once<br>
|
|
1039
|
+
\u2022 If you didn't request this, ignore this email
|
|
1040
|
+
</p>
|
|
1041
|
+
</div>
|
|
1042
|
+
|
|
1043
|
+
<hr style="${styles.divider}" />
|
|
1044
|
+
|
|
1045
|
+
<p style="${styles.paragraph}; font-size: 13px; color: ${colors.textMuted};">
|
|
1046
|
+
<strong>Didn't request this?</strong><br>
|
|
1047
|
+
Your password remains unchanged. If you're concerned about your account
|
|
1048
|
+
security, please contact our support team immediately.
|
|
1049
|
+
</p>
|
|
1050
|
+
</div>
|
|
1051
|
+
|
|
1052
|
+
<!-- Footer -->
|
|
1053
|
+
<div style="${styles.footer}">
|
|
1054
|
+
<p style="${styles.footerText}">
|
|
1055
|
+
This is an automated message \u2014 please do not reply.<br>
|
|
1056
|
+
\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} All rights reserved.
|
|
1057
|
+
</p>
|
|
1058
|
+
</div>
|
|
1059
|
+
</div>
|
|
1060
|
+
</div>
|
|
1061
|
+
</body>
|
|
1062
|
+
</html>
|
|
1063
|
+
`;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
699
1066
|
// src/express/auth.routes.ts
|
|
700
1067
|
function createAuthRouter(options = {}) {
|
|
701
1068
|
const googleClientId = process.env.GOOGLE_CLIENT_ID;
|
|
@@ -727,10 +1094,8 @@ function createAuthRouter(options = {}) {
|
|
|
727
1094
|
);
|
|
728
1095
|
r.post("/login", validateLogin, async (req, res) => {
|
|
729
1096
|
const { email: emailAddress, password } = req.body || {};
|
|
730
|
-
console.log(emailAddress, password, "body");
|
|
731
1097
|
try {
|
|
732
1098
|
const user = await OrgUser.findOne({ email: emailAddress }).select("+password").lean();
|
|
733
|
-
console.log(user, "user");
|
|
734
1099
|
if (!user) {
|
|
735
1100
|
return res.status(400).json({
|
|
736
1101
|
error: "Invalid email or password",
|
|
@@ -804,10 +1169,20 @@ function createAuthRouter(options = {}) {
|
|
|
804
1169
|
emailService: email,
|
|
805
1170
|
user,
|
|
806
1171
|
subject: "Verify your email",
|
|
807
|
-
html: buildVerificationTemplate(
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
)
|
|
1172
|
+
// html: buildVerificationTemplate(
|
|
1173
|
+
// email.sign({ userId: kcUser.id, email: kcUser.email }),
|
|
1174
|
+
// options,
|
|
1175
|
+
// ),
|
|
1176
|
+
html: buildVerificationEmailTemplate({
|
|
1177
|
+
firstName: user.firstName,
|
|
1178
|
+
verificationUrl: `${getFrontendBaseUrl(options)}/verify-email?token=${email.sign(
|
|
1179
|
+
{
|
|
1180
|
+
userId: user.id,
|
|
1181
|
+
email: user.email
|
|
1182
|
+
}
|
|
1183
|
+
)}`,
|
|
1184
|
+
expiresIn: "1 hour"
|
|
1185
|
+
})
|
|
811
1186
|
});
|
|
812
1187
|
if (emailResult.rateLimited) {
|
|
813
1188
|
return res.status(429).json({
|
|
@@ -887,7 +1262,17 @@ function createAuthRouter(options = {}) {
|
|
|
887
1262
|
emailService: email,
|
|
888
1263
|
user,
|
|
889
1264
|
subject: "Verify your email",
|
|
890
|
-
html: buildVerificationTemplate(token, options)
|
|
1265
|
+
// html: buildVerificationTemplate(token, options),
|
|
1266
|
+
html: buildVerificationEmailTemplate({
|
|
1267
|
+
firstName: user.firstName,
|
|
1268
|
+
verificationUrl: `${getFrontendBaseUrl(options)}/verify-email?token=${email.sign(
|
|
1269
|
+
{
|
|
1270
|
+
userId: user.id,
|
|
1271
|
+
email: user.email
|
|
1272
|
+
}
|
|
1273
|
+
)}`,
|
|
1274
|
+
expiresIn: "1 hour"
|
|
1275
|
+
})
|
|
891
1276
|
});
|
|
892
1277
|
if (resendResult.rateLimited) {
|
|
893
1278
|
return res.status(429).json({
|
|
@@ -916,7 +1301,17 @@ function createAuthRouter(options = {}) {
|
|
|
916
1301
|
emailService: email,
|
|
917
1302
|
user,
|
|
918
1303
|
subject: "Reset password",
|
|
919
|
-
html: buildResetTemplate(resetToken, options)
|
|
1304
|
+
// html: buildResetTemplate(resetToken, options),
|
|
1305
|
+
html: buildResetPasswordEmailTemplate({
|
|
1306
|
+
firstName: user.firstName,
|
|
1307
|
+
resetUrl: `${getFrontendBaseUrl(options)}/reset-password?token=${email.sign(
|
|
1308
|
+
{
|
|
1309
|
+
userId: user.id,
|
|
1310
|
+
email: user.email
|
|
1311
|
+
}
|
|
1312
|
+
)}`,
|
|
1313
|
+
expiresIn: "1 hour"
|
|
1314
|
+
})
|
|
920
1315
|
});
|
|
921
1316
|
if (resetResult.rateLimited) {
|
|
922
1317
|
return res.status(429).json({
|
|
@@ -929,9 +1324,16 @@ function createAuthRouter(options = {}) {
|
|
|
929
1324
|
});
|
|
930
1325
|
r.post("/reset-password", validateResetPassword, async (req, res) => {
|
|
931
1326
|
const { token, newPassword } = req.body || {};
|
|
1327
|
+
if (!token || !newPassword) {
|
|
1328
|
+
return res.status(400).json({
|
|
1329
|
+
ok: false,
|
|
1330
|
+
error: "Token and new password are required",
|
|
1331
|
+
code: "MISSING_FIELDS"
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
932
1334
|
try {
|
|
933
1335
|
const payload = email.verify(token);
|
|
934
|
-
const user = await OrgUser.findOne({
|
|
1336
|
+
const user = await OrgUser.findOne({ id: payload.userId });
|
|
935
1337
|
if (!user) {
|
|
936
1338
|
return res.status(404).json({ ok: false, error: "User not found" });
|
|
937
1339
|
}
|
|
@@ -1322,12 +1724,6 @@ function respondWithKeycloakError(res, err, fallback, status = 400) {
|
|
|
1322
1724
|
const description = err?.response?.data?.error_description || err?.response?.data?.errorMessage || err?.message || fallback;
|
|
1323
1725
|
return res.status(status).json({ ok: false, error: description });
|
|
1324
1726
|
}
|
|
1325
|
-
function buildVerificationTemplate(token, options) {
|
|
1326
|
-
return `<a href="${getFrontendBaseUrl(options)}/auth/verify-email?token=${token}">Verify</a>`;
|
|
1327
|
-
}
|
|
1328
|
-
function buildResetTemplate(token, options) {
|
|
1329
|
-
return `<a href="${getFrontendBaseUrl(options)}/auth/reset-password?token=${token}">Reset</a>`;
|
|
1330
|
-
}
|
|
1331
1727
|
function getFrontendBaseUrl(options) {
|
|
1332
1728
|
if (options.frontendBaseUrl)
|
|
1333
1729
|
return options.frontendBaseUrl.replace(/\/$/, "");
|
|
@@ -1345,7 +1741,6 @@ async function sendRateLimitedEmail({
|
|
|
1345
1741
|
if (!can.ok) {
|
|
1346
1742
|
return { rateLimited: true, waitMs: can.waitMs };
|
|
1347
1743
|
}
|
|
1348
|
-
console.log(can, "can");
|
|
1349
1744
|
await emailService.send(user.email, subject, html);
|
|
1350
1745
|
user.lastEmailSent = [...user.lastEmailSent || [], /* @__PURE__ */ new Date()];
|
|
1351
1746
|
await user.save();
|