@rpcbase/auth 0.164.0 → 0.166.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/handler-0nKR-P5B.js +84 -0
- package/dist/handler-0nKR-P5B.js.map +1 -0
- package/dist/handler-B8jPw9zh.js +74 -0
- package/dist/handler-B8jPw9zh.js.map +1 -0
- package/dist/handler-BGNM_dz1.js +19 -0
- package/dist/handler-BGNM_dz1.js.map +1 -0
- package/dist/handler-BoWTfKWi.js +56 -0
- package/dist/handler-BoWTfKWi.js.map +1 -0
- package/dist/handler-ClyVm_Us.js +92 -0
- package/dist/handler-ClyVm_Us.js.map +1 -0
- package/dist/handler-DNxEmrtP.js +67 -0
- package/dist/{handler-B_lItxOC.js.map → handler-DNxEmrtP.js.map} +1 -1
- package/dist/handler-DsPS6JXV.js +70 -0
- package/dist/handler-DsPS6JXV.js.map +1 -0
- package/dist/handler-GKdEwnBO.js +75 -0
- package/dist/handler-GKdEwnBO.js.map +1 -0
- package/dist/handler-IBGVDW5w.js +125 -0
- package/dist/handler-IBGVDW5w.js.map +1 -0
- package/dist/handler-J2OwFTyf.js +51 -0
- package/dist/handler-J2OwFTyf.js.map +1 -0
- package/dist/index.js +770 -756
- package/dist/index.js.map +1 -1
- package/dist/middleware-BT3Uput1.js +18 -0
- package/dist/middleware-BT3Uput1.js.map +1 -0
- package/dist/oauth/index.js +636 -761
- package/dist/oauth/index.js.map +1 -1
- package/dist/routes.js +19 -9
- package/dist/routes.js.map +1 -1
- package/dist/schemas-BgOpQqUv.js +3988 -0
- package/dist/schemas-BgOpQqUv.js.map +1 -0
- package/dist/session-BQ06Yo3C.js +20 -0
- package/dist/session-BQ06Yo3C.js.map +1 -0
- package/dist/sign-in-BG2ND3cO.js +18 -0
- package/dist/sign-in-BG2ND3cO.js.map +1 -0
- package/dist/sign-up-BCVi8UC9.js +18 -0
- package/dist/sign-up-BCVi8UC9.js.map +1 -0
- package/package.json +1 -1
- package/dist/handler-BBSeVt7x.js +0 -153
- package/dist/handler-BBSeVt7x.js.map +0 -1
- package/dist/handler-BKSik1j0.js +0 -83
- package/dist/handler-BKSik1j0.js.map +0 -1
- package/dist/handler-BXvh_Nx4.js +0 -95
- package/dist/handler-BXvh_Nx4.js.map +0 -1
- package/dist/handler-B_lItxOC.js +0 -66
- package/dist/handler-BuwKXMOu.js +0 -24
- package/dist/handler-BuwKXMOu.js.map +0 -1
- package/dist/handler-C-hPxnHG.js +0 -68
- package/dist/handler-C-hPxnHG.js.map +0 -1
- package/dist/handler-CoHpAhui.js +0 -81
- package/dist/handler-CoHpAhui.js.map +0 -1
- package/dist/handler-DfZwgoA4.js +0 -94
- package/dist/handler-DfZwgoA4.js.map +0 -1
- package/dist/handler-Eyjkxj9l.js +0 -58
- package/dist/handler-Eyjkxj9l.js.map +0 -1
- package/dist/handler-U3df_2Al.js +0 -59
- package/dist/handler-U3df_2Al.js.map +0 -1
- package/dist/index-1_ZKABa_.js +0 -20
- package/dist/index-1_ZKABa_.js.map +0 -1
- package/dist/index-D94-1Zwh.js +0 -20
- package/dist/index-D94-1Zwh.js.map +0 -1
- package/dist/middleware-8IfSkEEy.js +0 -25
- package/dist/middleware-8IfSkEEy.js.map +0 -1
- package/dist/schemas--f80aXK7.js +0 -4329
- package/dist/schemas--f80aXK7.js.map +0 -1
- package/dist/session-DoTNxRRA.js +0 -20
- package/dist/session-DoTNxRRA.js.map +0 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/session.ts
|
|
2
|
+
var AUTHENTICATED_USER_ID_HEADER = "rb-authenticated-user-id";
|
|
3
|
+
var AUTHENTICATED_TENANT_ID_HEADER = "rb-authenticated-tenant-id";
|
|
4
|
+
var completeAuthSignIn = (ctx, args) => {
|
|
5
|
+
if (!ctx.req.session) return false;
|
|
6
|
+
ctx.req.session.user = {
|
|
7
|
+
id: args.userId,
|
|
8
|
+
currentTenantId: args.currentTenantId,
|
|
9
|
+
signedInTenants: args.signedInTenants,
|
|
10
|
+
isEntryGateAuthorized: true,
|
|
11
|
+
tenantRoles: args.tenantRoles
|
|
12
|
+
};
|
|
13
|
+
ctx.res.setHeader(AUTHENTICATED_USER_ID_HEADER, args.userId);
|
|
14
|
+
ctx.res.setHeader(AUTHENTICATED_TENANT_ID_HEADER, args.currentTenantId);
|
|
15
|
+
return true;
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { completeAuthSignIn as n, AUTHENTICATED_TENANT_ID_HEADER as t };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=session-BQ06Yo3C.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-BQ06Yo3C.js","names":["Ctx","AuthSessionUser","AUTHENTICATED_USER_ID_HEADER","AUTHENTICATED_TENANT_ID_HEADER","CompleteAuthSignInArgs","userId","currentTenantId","signedInTenants","tenantRoles","Record","completeAuthSignIn","ctx","args","req","session","user","id","isEntryGateAuthorized","res","setHeader"],"sources":["../src/session.ts"],"sourcesContent":["import type { Ctx } from \"@rpcbase/api\"\n\nimport type { AuthSessionUser } from \"./types\"\n\n\nexport const AUTHENTICATED_USER_ID_HEADER = \"rb-authenticated-user-id\"\nexport const AUTHENTICATED_TENANT_ID_HEADER = \"rb-authenticated-tenant-id\"\n\ntype CompleteAuthSignInArgs = {\n userId: string\n currentTenantId: string\n signedInTenants: string[]\n tenantRoles?: Record<string, string[]>\n}\n\nexport const completeAuthSignIn = (\n ctx: Ctx<AuthSessionUser>,\n args: CompleteAuthSignInArgs,\n): boolean => {\n if (!ctx.req.session) return false\n\n ctx.req.session.user = {\n id: args.userId,\n currentTenantId: args.currentTenantId,\n signedInTenants: args.signedInTenants,\n isEntryGateAuthorized: true,\n tenantRoles: args.tenantRoles,\n }\n\n ctx.res.setHeader(AUTHENTICATED_USER_ID_HEADER, args.userId)\n ctx.res.setHeader(AUTHENTICATED_TENANT_ID_HEADER, args.currentTenantId)\n\n return true\n}\n"],"mappings":";AAKA,IAAaE,+BAA+B;AAC5C,IAAaC,iCAAiC;AAS9C,IAAaO,sBACXC,KACAC,SACY;CACZ,IAAI,CAACD,IAAIE,IAAIC,SAAS,OAAO;CAE7BH,IAAIE,IAAIC,QAAQC,OAAO;EACrBC,IAAIJ,KAAKP;EACTC,iBAAiBM,KAAKN;EACtBC,iBAAiBK,KAAKL;EACtBU,uBAAuB;EACvBT,aAAaI,KAAKJ;CACpB;CAEAG,IAAIO,IAAIC,UAAUjB,8BAA8BU,KAAKP,MAAM;CAC3DM,IAAIO,IAAIC,UAAUhB,gCAAgCS,KAAKN,eAAe;CAEtE,OAAO;AACT"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { a as string, i as object, n as boolean } from "./schemas-BgOpQqUv.js";
|
|
2
|
+
//#region src/api/sign-in/index.ts
|
|
3
|
+
var Route = "/api/rb/auth/sign-in";
|
|
4
|
+
var requestSchema = object({
|
|
5
|
+
email: string().nonempty("Email is required").email("Please enter a valid email address"),
|
|
6
|
+
password: string().min(1, { message: "Password is required" }),
|
|
7
|
+
rememberMe: boolean().default(true)
|
|
8
|
+
});
|
|
9
|
+
object({
|
|
10
|
+
success: boolean(),
|
|
11
|
+
error: string().optional(),
|
|
12
|
+
userId: string().optional(),
|
|
13
|
+
tenantId: string().optional()
|
|
14
|
+
});
|
|
15
|
+
//#endregion
|
|
16
|
+
export { requestSchema as n, Route as t };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=sign-in-BG2ND3cO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-in-BG2ND3cO.js","names":["z","Route","requestSchema","object","email","string","nonempty","password","min","message","rememberMe","boolean","default","RequestPayload","infer","responseSchema","success","error","optional","userId","tenantId","ResponsePayload"],"sources":["../src/api/sign-in/index.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const Route = \"/api/rb/auth/sign-in\"\n\nexport const requestSchema = z.object({\n email: z\n .string()\n .nonempty(\"Email is required\")\n .email(\"Please enter a valid email address\"),\n password: z.string().min(1, { message: \"Password is required\" }),\n rememberMe: z.boolean().default(true),\n})\n\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n userId: z.string().optional(),\n tenantId: z.string().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n"],"mappings":";;AAGA,IAAaC,QAAQ;AAErB,IAAaC,gBAAgBF,OAAS;CACpCI,OAAOJ,OACG,CAAC,CACRM,SAAS,mBAAmB,CAAC,CAC7BF,MAAM,oCAAoC;CAC7CG,UAAUP,OAAS,CAAC,CAACQ,IAAI,GAAG,EAAEC,SAAS,uBAAuB,CAAC;CAC/DC,YAAYV,QAAU,CAAC,CAACY,QAAQ,IAAI;AACtC,CAAC;AAI6BZ,OAAS;CACrCgB,SAAShB,QAAU;CACnBiB,OAAOjB,OAAS,CAAC,CAACkB,SAAS;CAC3BC,QAAQnB,OAAS,CAAC,CAACkB,SAAS;CAC5BE,UAAUpB,OAAS,CAAC,CAACkB,SAAS;AAChC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { a as string, i as object, n as boolean } from "./schemas-BgOpQqUv.js";
|
|
2
|
+
//#region src/api/sign-up/index.ts
|
|
3
|
+
var Route = "/api/rb/auth/sign-up";
|
|
4
|
+
var requestSchema = object({
|
|
5
|
+
email: string().nonempty("Email is required").email("Please enter a valid email address"),
|
|
6
|
+
password: string().min(8, { message: "Password must be at least 8 characters long." }),
|
|
7
|
+
rememberMe: boolean().default(true)
|
|
8
|
+
});
|
|
9
|
+
object({
|
|
10
|
+
success: boolean(),
|
|
11
|
+
error: string().optional(),
|
|
12
|
+
userId: string().optional(),
|
|
13
|
+
tenantId: string().optional()
|
|
14
|
+
});
|
|
15
|
+
//#endregion
|
|
16
|
+
export { requestSchema as n, Route as t };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=sign-up-BCVi8UC9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-up-BCVi8UC9.js","names":["z","Route","requestSchema","object","email","string","nonempty","password","min","message","rememberMe","boolean","default","RequestPayload","infer","responseSchema","success","error","optional","userId","tenantId","ResponsePayload"],"sources":["../src/api/sign-up/index.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const Route = \"/api/rb/auth/sign-up\"\n\nexport const requestSchema = z\n .object({\n email: z\n .string()\n .nonempty(\"Email is required\")\n .email(\"Please enter a valid email address\"),\n password: z.string().min(8, { message: \"Password must be at least 8 characters long.\" }),\n rememberMe: z.boolean().default(true),\n })\n\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n userId: z.string().optional(),\n tenantId: z.string().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n"],"mappings":";;AAGA,IAAaC,QAAQ;AAErB,IAAaC,gBAAgBF,OACnB;CACNI,OAAOJ,OACG,CAAC,CACRM,SAAS,mBAAmB,CAAC,CAC7BF,MAAM,oCAAoC;CAC7CG,UAAUP,OAAS,CAAC,CAACQ,IAAI,GAAG,EAAEC,SAAS,+CAA+C,CAAC;CACvFC,YAAYV,QAAU,CAAC,CAACY,QAAQ,IAAI;AACtC,CAAC;AAI2BZ,OAAS;CACrCgB,SAAShB,QAAU;CACnBiB,OAAOjB,OAAS,CAAC,CAACkB,SAAS;CAC3BC,QAAQnB,OAAS,CAAC,CAACkB,SAAS;CAC5BE,UAAUpB,OAAS,CAAC,CAACkB,SAAS;AAChC,CAAC"}
|
package/package.json
CHANGED
package/dist/handler-BBSeVt7x.js
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import crypto from "crypto";
|
|
2
|
-
import { models } from "@rpcbase/db";
|
|
3
|
-
import { sendEmail } from "@rpcbase/server";
|
|
4
|
-
import { o as object, s as string, n as number, b as boolean } from "./schemas--f80aXK7.js";
|
|
5
|
-
const Route = "/api/rb/auth/request-password-reset";
|
|
6
|
-
const requestSchema = object({
|
|
7
|
-
email: string().email()
|
|
8
|
-
});
|
|
9
|
-
object({
|
|
10
|
-
success: boolean(),
|
|
11
|
-
error: string().optional(),
|
|
12
|
-
retryAfterSeconds: number().int().positive().optional()
|
|
13
|
-
});
|
|
14
|
-
const PASSWORD_RESET_COOLDOWN_SECONDS = 60;
|
|
15
|
-
const PASSWORD_RESET_CODE_TTL_SECONDS = 10 * 60;
|
|
16
|
-
const maskEmailForLog = (email) => {
|
|
17
|
-
const [localRaw, domainRaw = ""] = email.split("@");
|
|
18
|
-
const local = localRaw || "";
|
|
19
|
-
const domain = domainRaw || "";
|
|
20
|
-
const localPrefix = local.slice(0, Math.min(3, local.length));
|
|
21
|
-
const localMask = "*".repeat(Math.max(5, local.length - localPrefix.length));
|
|
22
|
-
if (!domain) {
|
|
23
|
-
return `${localPrefix}${localMask}@****`;
|
|
24
|
-
}
|
|
25
|
-
const domainTailLength = Math.min(7, domain.length);
|
|
26
|
-
const domainTail = domain.slice(-domainTailLength);
|
|
27
|
-
const domainMask = "*".repeat(Math.max(4, domain.length - domainTailLength));
|
|
28
|
-
return `${localPrefix}${localMask}@${domainMask}${domainTail}`;
|
|
29
|
-
};
|
|
30
|
-
const requestPasswordReset = async (payload, ctx) => {
|
|
31
|
-
const User = await models.getGlobal("RBUser", ctx);
|
|
32
|
-
const parsed = requestSchema.safeParse(payload);
|
|
33
|
-
if (!parsed.success) {
|
|
34
|
-
ctx.res.status(400);
|
|
35
|
-
return {
|
|
36
|
-
success: false,
|
|
37
|
-
error: "invalid_payload"
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
const {
|
|
41
|
-
email
|
|
42
|
-
} = parsed.data;
|
|
43
|
-
const requestedAt = /* @__PURE__ */ new Date();
|
|
44
|
-
const cooldownEligibleExpiresAt = new Date(requestedAt.getTime() + (PASSWORD_RESET_CODE_TTL_SECONDS - PASSWORD_RESET_COOLDOWN_SECONDS) * 1e3);
|
|
45
|
-
const passwordResetCode = crypto.randomInt(0, 1e6).toString().padStart(6, "0");
|
|
46
|
-
const passwordResetCodeExpiresAt = new Date(requestedAt.getTime() + PASSWORD_RESET_CODE_TTL_SECONDS * 1e3);
|
|
47
|
-
const user = await User.findOneAndUpdate({
|
|
48
|
-
email,
|
|
49
|
-
$or: [{
|
|
50
|
-
passwordResetCodeExpiresAt: {
|
|
51
|
-
$exists: false
|
|
52
|
-
}
|
|
53
|
-
}, {
|
|
54
|
-
passwordResetCodeExpiresAt: {
|
|
55
|
-
$lte: cooldownEligibleExpiresAt
|
|
56
|
-
}
|
|
57
|
-
}]
|
|
58
|
-
}, {
|
|
59
|
-
$set: {
|
|
60
|
-
passwordResetCode,
|
|
61
|
-
passwordResetCodeExpiresAt
|
|
62
|
-
},
|
|
63
|
-
$unset: {
|
|
64
|
-
passwordResetToken: "",
|
|
65
|
-
passwordResetTokenExpiresAt: ""
|
|
66
|
-
}
|
|
67
|
-
}, {
|
|
68
|
-
returnDocument: "after"
|
|
69
|
-
});
|
|
70
|
-
ctx.res.setHeader("Retry-After", String(PASSWORD_RESET_COOLDOWN_SECONDS));
|
|
71
|
-
if (!user) {
|
|
72
|
-
const existingUser = await User.findOne({
|
|
73
|
-
email
|
|
74
|
-
}, {
|
|
75
|
-
_id: 1
|
|
76
|
-
});
|
|
77
|
-
if (!existingUser) {
|
|
78
|
-
try {
|
|
79
|
-
console.info(`sending password reset account notice to email ${maskEmailForLog(email)}`);
|
|
80
|
-
await sendEmail({
|
|
81
|
-
to: email,
|
|
82
|
-
subject: "No account found for your password reset request",
|
|
83
|
-
html: `
|
|
84
|
-
<p>Hello,</p>
|
|
85
|
-
<p>You requested a new password reset code for this email address, but unfortunately we couldn't find an account associated with it.</p>
|
|
86
|
-
<p>If you didn't request this, you can ignore this message.</p>
|
|
87
|
-
<p>If you're having trouble accessing your account, please contact support.</p>
|
|
88
|
-
`,
|
|
89
|
-
text: "Hello, You requested a new password reset code for this email address, but unfortunately we couldn't find an account associated with it. If you didn't request this, you can ignore this message. If you're having trouble accessing your account, please contact support."
|
|
90
|
-
});
|
|
91
|
-
} catch (err) {
|
|
92
|
-
console.error("failed to send password reset account notice email", err);
|
|
93
|
-
ctx.res.status(500);
|
|
94
|
-
return {
|
|
95
|
-
success: false,
|
|
96
|
-
error: "email_delivery_failed"
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
success: true,
|
|
102
|
-
retryAfterSeconds: PASSWORD_RESET_COOLDOWN_SECONDS
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
try {
|
|
106
|
-
console.info(`sending password reset to email ${maskEmailForLog(email)}`);
|
|
107
|
-
await sendEmail({
|
|
108
|
-
to: email,
|
|
109
|
-
subject: `Your password reset code: ${passwordResetCode}`,
|
|
110
|
-
html: `
|
|
111
|
-
<p>Your password reset code is <strong>${passwordResetCode}</strong>. It expires in 10 minutes.</p>
|
|
112
|
-
<p>If you didn't request this, you can ignore this message.</p>
|
|
113
|
-
`,
|
|
114
|
-
text: `Your password reset code is ${passwordResetCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`
|
|
115
|
-
});
|
|
116
|
-
} catch (err) {
|
|
117
|
-
console.error("failed to send password reset email", err);
|
|
118
|
-
try {
|
|
119
|
-
const releaseResult = await User.updateOne({
|
|
120
|
-
_id: user._id,
|
|
121
|
-
passwordResetCode
|
|
122
|
-
}, {
|
|
123
|
-
$unset: {
|
|
124
|
-
passwordResetCode: "",
|
|
125
|
-
passwordResetCodeExpiresAt: ""
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
if (releaseResult.modifiedCount > 0) {
|
|
129
|
-
ctx.res.removeHeader("Retry-After");
|
|
130
|
-
}
|
|
131
|
-
} catch (releaseErr) {
|
|
132
|
-
console.error("failed to release password reset cooldown", releaseErr);
|
|
133
|
-
}
|
|
134
|
-
ctx.res.status(500);
|
|
135
|
-
return {
|
|
136
|
-
success: false,
|
|
137
|
-
error: "email_delivery_failed"
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
return {
|
|
141
|
-
success: true,
|
|
142
|
-
retryAfterSeconds: PASSWORD_RESET_COOLDOWN_SECONDS
|
|
143
|
-
};
|
|
144
|
-
};
|
|
145
|
-
const handler = (api) => {
|
|
146
|
-
api.post(Route, requestPasswordReset);
|
|
147
|
-
};
|
|
148
|
-
export {
|
|
149
|
-
PASSWORD_RESET_COOLDOWN_SECONDS,
|
|
150
|
-
handler as default,
|
|
151
|
-
requestPasswordReset
|
|
152
|
-
};
|
|
153
|
-
//# sourceMappingURL=handler-BBSeVt7x.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler-BBSeVt7x.js","sources":["../src/api/request-password-reset/index.ts","../src/api/request-password-reset/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const Route = \"/api/rb/auth/request-password-reset\"\n\nexport const requestSchema = z.object({\n email: z.string().email(),\n})\n\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n retryAfterSeconds: z.number().int().positive().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n","import crypto from \"crypto\"\n\nimport { Api, ApiHandler, Ctx } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\nimport { sendEmail } from \"@rpcbase/server\"\n\nimport type { AuthSessionUser } from \"../../types\"\n\nimport * as RequestPasswordReset from \"./index\"\n\n\nexport const PASSWORD_RESET_COOLDOWN_SECONDS = 60\nconst PASSWORD_RESET_CODE_TTL_SECONDS = 10 * 60\n\nconst maskEmailForLog = (email: string) => {\n const [localRaw, domainRaw = \"\"] = email.split(\"@\")\n const local = localRaw || \"\"\n const domain = domainRaw || \"\"\n const localPrefix = local.slice(0, Math.min(3, local.length))\n const localMask = \"*\".repeat(Math.max(5, local.length - localPrefix.length))\n\n if (!domain) {\n return `${localPrefix}${localMask}@****`\n }\n\n const domainTailLength = Math.min(7, domain.length)\n const domainTail = domain.slice(-domainTailLength)\n const domainMask = \"*\".repeat(Math.max(4, domain.length - domainTailLength))\n\n return `${localPrefix}${localMask}@${domainMask}${domainTail}`\n}\n\n\nexport const requestPasswordReset: ApiHandler<\n RequestPasswordReset.RequestPayload,\n RequestPasswordReset.ResponsePayload,\n AuthSessionUser\n> = async(\n payload,\n ctx: Ctx<AuthSessionUser>\n): Promise<RequestPasswordReset.ResponsePayload> => {\n const User = await models.getGlobal(\"RBUser\", ctx)\n\n const parsed = RequestPasswordReset.requestSchema.safeParse(payload)\n\n if (!parsed.success) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_payload\" }\n }\n\n const { email } = parsed.data\n const requestedAt = new Date()\n const cooldownEligibleExpiresAt = new Date(\n requestedAt.getTime() + (PASSWORD_RESET_CODE_TTL_SECONDS - PASSWORD_RESET_COOLDOWN_SECONDS) * 1000,\n )\n const passwordResetCode = crypto.randomInt(0, 1_000_000).toString().padStart(6, \"0\")\n const passwordResetCodeExpiresAt = new Date(requestedAt.getTime() + PASSWORD_RESET_CODE_TTL_SECONDS * 1000)\n\n const user = await User.findOneAndUpdate(\n {\n email,\n $or: [\n { passwordResetCodeExpiresAt: { $exists: false } },\n { passwordResetCodeExpiresAt: { $lte: cooldownEligibleExpiresAt } },\n ],\n },\n {\n $set: {\n passwordResetCode,\n passwordResetCodeExpiresAt,\n },\n $unset: {\n passwordResetToken: \"\",\n passwordResetTokenExpiresAt: \"\",\n },\n },\n { returnDocument: \"after\" },\n )\n\n ctx.res.setHeader(\"Retry-After\", String(PASSWORD_RESET_COOLDOWN_SECONDS))\n\n if (!user) {\n const existingUser = await User.findOne({ email }, { _id: 1 })\n\n if (!existingUser) {\n try {\n console.info(`sending password reset account notice to email ${maskEmailForLog(email)}`)\n await sendEmail({\n to: email,\n subject: \"No account found for your password reset request\",\n html: `\n <p>Hello,</p>\n <p>You requested a new password reset code for this email address, but unfortunately we couldn't find an account associated with it.</p>\n <p>If you didn't request this, you can ignore this message.</p>\n <p>If you're having trouble accessing your account, please contact support.</p>\n `,\n text: \"Hello, You requested a new password reset code for this email address, but unfortunately we couldn't find an account associated with it. If you didn't request this, you can ignore this message. If you're having trouble accessing your account, please contact support.\",\n })\n } catch (err) {\n console.error(\"failed to send password reset account notice email\", err)\n ctx.res.status(500)\n return { success: false, error: \"email_delivery_failed\" }\n }\n }\n\n return { success: true, retryAfterSeconds: PASSWORD_RESET_COOLDOWN_SECONDS }\n }\n\n try {\n console.info(`sending password reset to email ${maskEmailForLog(email)}`)\n await sendEmail({\n to: email,\n subject: `Your password reset code: ${passwordResetCode}`,\n html: `\n <p>Your password reset code is <strong>${passwordResetCode}</strong>. It expires in 10 minutes.</p>\n <p>If you didn't request this, you can ignore this message.</p>\n `,\n text: `Your password reset code is ${passwordResetCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`,\n })\n } catch (err) {\n console.error(\"failed to send password reset email\", err)\n\n try {\n const releaseResult = await User.updateOne(\n { _id: user._id, passwordResetCode },\n {\n $unset: {\n passwordResetCode: \"\",\n passwordResetCodeExpiresAt: \"\",\n },\n },\n )\n if (releaseResult.modifiedCount > 0) {\n ctx.res.removeHeader(\"Retry-After\")\n }\n } catch (releaseErr) {\n console.error(\"failed to release password reset cooldown\", releaseErr)\n }\n\n ctx.res.status(500)\n return { success: false, error: \"email_delivery_failed\" }\n }\n\n return { success: true, retryAfterSeconds: PASSWORD_RESET_COOLDOWN_SECONDS }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.post(RequestPasswordReset.Route, requestPasswordReset)\n}\n"],"names":["Route","requestSchema","z","email","string","success","boolean","error","optional","retryAfterSeconds","number","int","positive","PASSWORD_RESET_COOLDOWN_SECONDS","PASSWORD_RESET_CODE_TTL_SECONDS","maskEmailForLog","localRaw","domainRaw","split","local","domain","localPrefix","slice","Math","min","length","localMask","repeat","max","domainTailLength","domainTail","domainMask","requestPasswordReset","payload","ctx","User","models","getGlobal","parsed","RequestPasswordReset","safeParse","res","status","data","requestedAt","Date","cooldownEligibleExpiresAt","getTime","passwordResetCode","crypto","randomInt","toString","padStart","passwordResetCodeExpiresAt","user","findOneAndUpdate","$or","$exists","$lte","$set","$unset","passwordResetToken","passwordResetTokenExpiresAt","returnDocument","setHeader","String","existingUser","findOne","_id","console","info","sendEmail","to","subject","html","text","err","releaseResult","updateOne","modifiedCount","removeHeader","releaseErr","api","post"],"mappings":"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"}
|
package/dist/handler-BKSik1j0.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import crypto from "crypto";
|
|
2
|
-
import { models } from "@rpcbase/db";
|
|
3
|
-
import { sendEmail } from "@rpcbase/server";
|
|
4
|
-
import { o as object, s as string, b as boolean } from "./schemas--f80aXK7.js";
|
|
5
|
-
const Route = "/api/rb/auth/resend-otp";
|
|
6
|
-
const requestSchema = object({
|
|
7
|
-
email: string().email()
|
|
8
|
-
});
|
|
9
|
-
object({
|
|
10
|
-
success: boolean(),
|
|
11
|
-
error: string().optional()
|
|
12
|
-
});
|
|
13
|
-
const resendOtp = async (payload, ctx) => {
|
|
14
|
-
const User = await models.getGlobal("RBUser", ctx);
|
|
15
|
-
const parsed = requestSchema.safeParse(payload);
|
|
16
|
-
if (!parsed.success) {
|
|
17
|
-
ctx.res.status(400);
|
|
18
|
-
return {
|
|
19
|
-
success: false,
|
|
20
|
-
error: "invalid_payload"
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
const {
|
|
24
|
-
email
|
|
25
|
-
} = parsed.data;
|
|
26
|
-
const user = await User.findOne({
|
|
27
|
-
email
|
|
28
|
-
});
|
|
29
|
-
if (!user) {
|
|
30
|
-
ctx.res.status(404);
|
|
31
|
-
return {
|
|
32
|
-
success: false,
|
|
33
|
-
error: "user_not_found"
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
const emailVerificationCode = crypto.randomInt(0, 1e6).toString().padStart(6, "0");
|
|
37
|
-
const emailVerificationExpiresAt = new Date(Date.now() + 10 * 60 * 1e3);
|
|
38
|
-
user.emailVerificationCode = emailVerificationCode;
|
|
39
|
-
user.emailVerificationExpiresAt = emailVerificationExpiresAt;
|
|
40
|
-
await user.save();
|
|
41
|
-
try {
|
|
42
|
-
await sendEmail({
|
|
43
|
-
to: email,
|
|
44
|
-
subject: `Your verification code: ${emailVerificationCode}`,
|
|
45
|
-
html: `
|
|
46
|
-
<p>Your verification code is <strong>${emailVerificationCode}</strong>. It expires in 10 minutes.</p>
|
|
47
|
-
<p>If you didn't request this, you can ignore this message.</p>
|
|
48
|
-
`,
|
|
49
|
-
text: `Your verification code is ${emailVerificationCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`
|
|
50
|
-
});
|
|
51
|
-
} catch (err) {
|
|
52
|
-
console.error("failed to resend otp email", err);
|
|
53
|
-
try {
|
|
54
|
-
await User.updateOne({
|
|
55
|
-
_id: user._id,
|
|
56
|
-
emailVerificationCode
|
|
57
|
-
}, {
|
|
58
|
-
$unset: {
|
|
59
|
-
emailVerificationCode: "",
|
|
60
|
-
emailVerificationExpiresAt: ""
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
} catch (releaseErr) {
|
|
64
|
-
console.error("failed to clear unsent otp", releaseErr);
|
|
65
|
-
}
|
|
66
|
-
ctx.res.status(500);
|
|
67
|
-
return {
|
|
68
|
-
success: false,
|
|
69
|
-
error: "email_delivery_failed"
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
return {
|
|
73
|
-
success: true
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
const handler = (api) => {
|
|
77
|
-
api.post(Route, resendOtp);
|
|
78
|
-
};
|
|
79
|
-
export {
|
|
80
|
-
handler as default,
|
|
81
|
-
resendOtp
|
|
82
|
-
};
|
|
83
|
-
//# sourceMappingURL=handler-BKSik1j0.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler-BKSik1j0.js","sources":["../src/api/resend-otp/index.ts","../src/api/resend-otp/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const Route = \"/api/rb/auth/resend-otp\"\n\nexport const requestSchema = z.object({\n email: z.string().email(),\n})\n\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n\n","import crypto from \"crypto\"\n\nimport { Api, ApiHandler, Ctx } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\nimport { sendEmail } from \"@rpcbase/server\"\n\nimport type { AuthSessionUser } from \"../../types\"\n\nimport * as ResendOtp from \"./index\"\n\n\nexport const resendOtp: ApiHandler<ResendOtp.RequestPayload, ResendOtp.ResponsePayload, AuthSessionUser> = async (\n payload,\n ctx: Ctx<AuthSessionUser>\n): Promise<ResendOtp.ResponsePayload> => {\n const User = await models.getGlobal(\"RBUser\", ctx)\n\n const parsed = ResendOtp.requestSchema.safeParse(payload)\n\n if (!parsed.success) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_payload\" }\n }\n\n const { email } = parsed.data\n\n const user = await User.findOne({ email })\n\n if (!user) {\n // TODO(auth): avoid account enumeration (return a generic success response even when the user doesn't exist)\n ctx.res.status(404)\n return { success: false, error: \"user_not_found\" }\n }\n\n // TODO(auth): add server-side throttling / rate limiting for resend-otp\n const emailVerificationCode = crypto.randomInt(0, 1_000_000).toString().padStart(6, \"0\")\n const emailVerificationExpiresAt = new Date(Date.now() + 10 * 60 * 1000)\n\n user.emailVerificationCode = emailVerificationCode\n user.emailVerificationExpiresAt = emailVerificationExpiresAt\n await user.save()\n\n try {\n await sendEmail({\n to: email,\n subject: `Your verification code: ${emailVerificationCode}`,\n html: `\n <p>Your verification code is <strong>${emailVerificationCode}</strong>. It expires in 10 minutes.</p>\n <p>If you didn't request this, you can ignore this message.</p>\n `,\n text: `Your verification code is ${emailVerificationCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`,\n })\n } catch (err) {\n console.error(\"failed to resend otp email\", err)\n\n try {\n await User.updateOne(\n { _id: user._id, emailVerificationCode },\n {\n $unset: {\n emailVerificationCode: \"\",\n emailVerificationExpiresAt: \"\",\n },\n },\n )\n } catch (releaseErr) {\n console.error(\"failed to clear unsent otp\", releaseErr)\n }\n\n ctx.res.status(500)\n return { success: false, error: \"email_delivery_failed\" }\n }\n\n return { success: true }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.post(ResendOtp.Route, resendOtp)\n}\n"],"names":["Route","requestSchema","z","email","string","success","boolean","error","optional","resendOtp","payload","ctx","User","models","getGlobal","parsed","ResendOtp","safeParse","res","status","data","user","findOne","emailVerificationCode","crypto","randomInt","toString","padStart","emailVerificationExpiresAt","Date","now","save","sendEmail","to","subject","html","text","err","console","updateOne","_id","$unset","releaseErr","api","post"],"mappings":";;;;AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,OAAOD,OAAEE,EAASD,MAAAA;AACpB,CAAC;AAI6BD,OAAS;AAAA,EACrCG,SAASH,QAAEI;AAAAA,EACXC,OAAOL,OAAEE,EAASI,SAAAA;AACpB,CAAC;ACHM,MAAMC,YAA8F,OACzGC,SACAC,QACuC;AACvC,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAAwBC,UAAUP,OAAO;AAExD,MAAI,CAACK,OAAOV,SAAS;AACnBM,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEd,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAEJ;AAAAA,EAAAA,IAAUY,OAAOK;AAEzB,QAAMC,OAAO,MAAMT,KAAKU,QAAQ;AAAA,IAAEnB;AAAAA,EAAAA,CAAO;AAEzC,MAAI,CAACkB,MAAM;AAETV,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEd,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAGA,QAAMgB,wBAAwBC,OAAOC,UAAU,GAAG,GAAS,EAAEC,WAAWC,SAAS,GAAG,GAAG;AACvF,QAAMC,6BAA6B,IAAIC,KAAKA,KAAKC,QAAQ,KAAK,KAAK,GAAI;AAEvET,OAAKE,wBAAwBA;AAC7BF,OAAKO,6BAA6BA;AAClC,QAAMP,KAAKU,KAAAA;AAEX,MAAI;AACF,UAAMC,UAAU;AAAA,MACdC,IAAI9B;AAAAA,MACJ+B,SAAS,2BAA2BX,qBAAqB;AAAA,MACzDY,MAAM;AAAA,+CACmCZ,qBAAqB;AAAA;AAAA;AAAA,MAG9Da,MAAM,6BAA6Bb,qBAAqB;AAAA,IAAA,CACzD;AAAA,EACH,SAASc,KAAK;AACZC,YAAQ/B,MAAM,8BAA8B8B,GAAG;AAE/C,QAAI;AACF,YAAMzB,KAAK2B,UACT;AAAA,QAAEC,KAAKnB,KAAKmB;AAAAA,QAAKjB;AAAAA,MAAAA,GACjB;AAAA,QACEkB,QAAQ;AAAA,UACNlB,uBAAuB;AAAA,UACvBK,4BAA4B;AAAA,QAAA;AAAA,MAC9B,CAEJ;AAAA,IACF,SAASc,YAAY;AACnBJ,cAAQ/B,MAAM,8BAA8BmC,UAAU;AAAA,IACxD;AAEA/B,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEd,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,SAAO;AAAA,IAAEF,SAAS;AAAA,EAAA;AACpB;AAEA,MAAA,UAAe,CAACsC,QAA8B;AAC5CA,MAAIC,KAAK5B,OAAiBP,SAAS;AACrC;"}
|
package/dist/handler-BXvh_Nx4.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import crypto from "crypto";
|
|
2
|
-
import { models } from "@rpcbase/db";
|
|
3
|
-
import { hashPasswordForStorage, sendEmail } from "@rpcbase/server";
|
|
4
|
-
import { R as Route, r as requestSchema } from "./index-1_ZKABa_.js";
|
|
5
|
-
const signUp = async (payload, ctx) => {
|
|
6
|
-
const User = await models.getGlobal("RBUser", ctx);
|
|
7
|
-
const Tenant = await models.getGlobal("RBTenant", ctx);
|
|
8
|
-
const parsed = requestSchema.safeParse(payload);
|
|
9
|
-
if (!parsed.success) {
|
|
10
|
-
ctx.res.status(400);
|
|
11
|
-
return {
|
|
12
|
-
success: false,
|
|
13
|
-
error: "invalid_payload"
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
const {
|
|
17
|
-
email,
|
|
18
|
-
password,
|
|
19
|
-
rememberMe: _rememberMe
|
|
20
|
-
} = parsed.data;
|
|
21
|
-
const existingUser = await User.findOne({
|
|
22
|
-
email
|
|
23
|
-
});
|
|
24
|
-
if (existingUser) {
|
|
25
|
-
console.log("user with email already exists", email);
|
|
26
|
-
ctx.res.status(409);
|
|
27
|
-
return {
|
|
28
|
-
success: false,
|
|
29
|
-
error: "user_exists"
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
const hashedPassword = await hashPasswordForStorage(password);
|
|
33
|
-
const tenantId = crypto.randomUUID();
|
|
34
|
-
const emailVerificationCode = crypto.randomInt(0, 1e6).toString().padStart(6, "0");
|
|
35
|
-
const emailVerificationExpiresAt = new Date(Date.now() + 10 * 60 * 1e3);
|
|
36
|
-
const user = new User({
|
|
37
|
-
email,
|
|
38
|
-
password: hashedPassword,
|
|
39
|
-
tenants: [tenantId],
|
|
40
|
-
tenantRoles: {
|
|
41
|
-
[tenantId]: ["owner"]
|
|
42
|
-
},
|
|
43
|
-
emailVerificationCode,
|
|
44
|
-
emailVerificationExpiresAt
|
|
45
|
-
});
|
|
46
|
-
await user.save();
|
|
47
|
-
try {
|
|
48
|
-
await sendEmail({
|
|
49
|
-
to: email,
|
|
50
|
-
subject: `Verify your email: ${emailVerificationCode}`,
|
|
51
|
-
html: `
|
|
52
|
-
<p>Welcome to rpcbase!</p>
|
|
53
|
-
<p>Your verification code is <strong>${emailVerificationCode}</strong>. It expires in 10 minutes.</p>
|
|
54
|
-
<p>If you didn't request this, you can ignore this message.</p>
|
|
55
|
-
`,
|
|
56
|
-
text: `Welcome to rpcbase! Your verification code is ${emailVerificationCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`
|
|
57
|
-
});
|
|
58
|
-
} catch (err) {
|
|
59
|
-
console.error("failed to send sign-up email", err);
|
|
60
|
-
try {
|
|
61
|
-
await User.deleteOne({
|
|
62
|
-
_id: user._id
|
|
63
|
-
});
|
|
64
|
-
} catch (rollbackErr) {
|
|
65
|
-
console.error("failed to roll back user after sign-up email failure", rollbackErr);
|
|
66
|
-
}
|
|
67
|
-
ctx.res.status(500);
|
|
68
|
-
return {
|
|
69
|
-
success: false,
|
|
70
|
-
error: "email_delivery_failed"
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
await Tenant.create({
|
|
75
|
-
tenantId,
|
|
76
|
-
name: email
|
|
77
|
-
});
|
|
78
|
-
} catch (err) {
|
|
79
|
-
console.warn("failed to create tenant for user", err);
|
|
80
|
-
}
|
|
81
|
-
console.log("created new user", user._id.toString());
|
|
82
|
-
return {
|
|
83
|
-
success: true,
|
|
84
|
-
userId: user._id.toString(),
|
|
85
|
-
tenantId
|
|
86
|
-
};
|
|
87
|
-
};
|
|
88
|
-
const handler = (api) => {
|
|
89
|
-
api.post(Route, signUp);
|
|
90
|
-
};
|
|
91
|
-
export {
|
|
92
|
-
handler as default,
|
|
93
|
-
signUp
|
|
94
|
-
};
|
|
95
|
-
//# sourceMappingURL=handler-BXvh_Nx4.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler-BXvh_Nx4.js","sources":["../src/api/sign-up/handler.ts"],"sourcesContent":["import crypto from \"crypto\"\n\nimport { Api, Ctx, ApiHandler } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\nimport { hashPasswordForStorage, sendEmail } from \"@rpcbase/server\"\n\nimport type { AuthSessionUser } from \"../../types\"\n\nimport * as SignUp from \"./index\"\n\n\nexport const signUp: ApiHandler<SignUp.RequestPayload, SignUp.ResponsePayload, AuthSessionUser> = async(\n payload,\n ctx: Ctx<AuthSessionUser>\n): Promise<SignUp.ResponsePayload> => {\n const User = await models.getGlobal(\"RBUser\", ctx)\n const Tenant = await models.getGlobal(\"RBTenant\", ctx)\n\n const parsed = SignUp.requestSchema.safeParse(payload)\n\n if (!parsed.success) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_payload\" }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { email, password, rememberMe: _rememberMe } = parsed.data\n\n const existingUser = await User.findOne({ email })\n\n if (existingUser) {\n console.log(\"user with email already exists\", email)\n // For security, we don't want to reveal if an email is registered.\n // But for this implementation, we'll make it simple.\n ctx.res.status(409)\n return { success: false, error: \"user_exists\" }\n }\n\n const hashedPassword = await hashPasswordForStorage(password)\n\n const tenantId = crypto.randomUUID()\n\n const emailVerificationCode = crypto.randomInt(0, 1_000_000).toString().padStart(6, \"0\")\n const emailVerificationExpiresAt = new Date(Date.now() + 10 * 60 * 1000)\n\n const user = new User({\n email,\n password: hashedPassword,\n tenants: [tenantId],\n tenantRoles: {\n [tenantId]: [\"owner\"],\n },\n emailVerificationCode,\n emailVerificationExpiresAt,\n })\n await user.save()\n\n try {\n await sendEmail({\n to: email,\n subject: `Verify your email: ${emailVerificationCode}`,\n html: `\n <p>Welcome to rpcbase!</p>\n <p>Your verification code is <strong>${emailVerificationCode}</strong>. It expires in 10 minutes.</p>\n <p>If you didn't request this, you can ignore this message.</p>\n `,\n text: `Welcome to rpcbase! Your verification code is ${emailVerificationCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`,\n })\n } catch (err) {\n console.error(\"failed to send sign-up email\", err)\n\n try {\n await User.deleteOne({ _id: user._id })\n } catch (rollbackErr) {\n console.error(\"failed to roll back user after sign-up email failure\", rollbackErr)\n }\n\n ctx.res.status(500)\n return { success: false, error: \"email_delivery_failed\" }\n }\n\n try {\n await Tenant.create({\n tenantId,\n name: email,\n })\n } catch (err) {\n // best-effort tenant creation; log and continue\n console.warn(\"failed to create tenant for user\", err)\n }\n\n console.log(\"created new user\", user._id.toString())\n\n return { success: true, userId: user._id.toString(), tenantId }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.post(SignUp.Route, signUp)\n}\n"],"names":["signUp","payload","ctx","User","models","getGlobal","Tenant","parsed","SignUp","safeParse","success","res","status","error","email","password","rememberMe","_rememberMe","data","existingUser","findOne","console","log","hashedPassword","hashPasswordForStorage","tenantId","crypto","randomUUID","emailVerificationCode","randomInt","toString","padStart","emailVerificationExpiresAt","Date","now","user","tenants","tenantRoles","save","sendEmail","to","subject","html","text","err","deleteOne","_id","rollbackErr","create","name","warn","userId","api","post"],"mappings":";;;;AAWO,MAAMA,SAAqF,OAChGC,SACAC,QACoC;AACpC,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AACjD,QAAMI,SAAS,MAAMF,OAAOC,UAAU,YAAYH,GAAG;AAErD,QAAMK,SAASC,cAAqBC,UAAUR,OAAO;AAErD,MAAI,CAACM,OAAOG,SAAS;AACnBR,QAAIS,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAGA,QAAM;AAAA,IAAEC;AAAAA,IAAOC;AAAAA,IAAUC,YAAYC;AAAAA,EAAAA,IAAgBV,OAAOW;AAE5D,QAAMC,eAAe,MAAMhB,KAAKiB,QAAQ;AAAA,IAAEN;AAAAA,EAAAA,CAAO;AAEjD,MAAIK,cAAc;AAChBE,YAAQC,IAAI,kCAAkCR,KAAK;AAGnDZ,QAAIS,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMU,iBAAiB,MAAMC,uBAAuBT,QAAQ;AAE5D,QAAMU,WAAWC,OAAOC,WAAAA;AAExB,QAAMC,wBAAwBF,OAAOG,UAAU,GAAG,GAAS,EAAEC,WAAWC,SAAS,GAAG,GAAG;AACvF,QAAMC,6BAA6B,IAAIC,KAAKA,KAAKC,QAAQ,KAAK,KAAK,GAAI;AAEvE,QAAMC,OAAO,IAAIhC,KAAK;AAAA,IACpBW;AAAAA,IACAC,UAAUQ;AAAAA,IACVa,SAAS,CAACX,QAAQ;AAAA,IAClBY,aAAa;AAAA,MACX,CAACZ,QAAQ,GAAG,CAAC,OAAO;AAAA,IAAA;AAAA,IAEtBG;AAAAA,IACAI;AAAAA,EAAAA,CACD;AACD,QAAMG,KAAKG,KAAAA;AAEX,MAAI;AACF,UAAMC,UAAU;AAAA,MACdC,IAAI1B;AAAAA,MACJ2B,SAAS,sBAAsBb,qBAAqB;AAAA,MACpDc,MAAM;AAAA;AAAA,+CAEmCd,qBAAqB;AAAA;AAAA;AAAA,MAG9De,MAAM,iDAAiDf,qBAAqB;AAAA,IAAA,CAC7E;AAAA,EACH,SAASgB,KAAK;AACZvB,YAAQR,MAAM,gCAAgC+B,GAAG;AAEjD,QAAI;AACF,YAAMzC,KAAK0C,UAAU;AAAA,QAAEC,KAAKX,KAAKW;AAAAA,MAAAA,CAAK;AAAA,IACxC,SAASC,aAAa;AACpB1B,cAAQR,MAAM,wDAAwDkC,WAAW;AAAA,IACnF;AAEA7C,QAAIS,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,MAAI;AACF,UAAMP,OAAO0C,OAAO;AAAA,MAClBvB;AAAAA,MACAwB,MAAMnC;AAAAA,IAAAA,CACP;AAAA,EACH,SAAS8B,KAAK;AAEZvB,YAAQ6B,KAAK,oCAAoCN,GAAG;AAAA,EACtD;AAEAvB,UAAQC,IAAI,oBAAoBa,KAAKW,IAAIhB,UAAU;AAEnD,SAAO;AAAA,IAAEpB,SAAS;AAAA,IAAMyC,QAAQhB,KAAKW,IAAIhB,SAAAA;AAAAA,IAAYL;AAAAA,EAAAA;AACvD;AAEA,MAAA,UAAe,CAAC2B,QAA8B;AAC5CA,MAAIC,KAAK7C,OAAcR,MAAM;AAC/B;"}
|
package/dist/handler-B_lItxOC.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { b as restrictSessionMiddleware } from "./middleware-8IfSkEEy.js";
|
|
2
|
-
import { A as AUTHENTICATED_TENANT_ID_HEADER } from "./session-DoTNxRRA.js";
|
|
3
|
-
import { o as object, s as string, b as boolean } from "./schemas--f80aXK7.js";
|
|
4
|
-
const Route = "/api/rb/auth/set-active-account";
|
|
5
|
-
const requestSchema = object({
|
|
6
|
-
tenantId: string().min(1, "Tenant is required")
|
|
7
|
-
});
|
|
8
|
-
object({
|
|
9
|
-
success: boolean(),
|
|
10
|
-
error: string().optional(),
|
|
11
|
-
tenantId: string().optional()
|
|
12
|
-
});
|
|
13
|
-
const setActiveAccount = async (payload, ctx) => {
|
|
14
|
-
const parsed = requestSchema.safeParse(payload);
|
|
15
|
-
if (!parsed.success) {
|
|
16
|
-
ctx.res.status(400);
|
|
17
|
-
return {
|
|
18
|
-
success: false,
|
|
19
|
-
error: "invalid_payload"
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
const sessionUser = ctx.req.session?.user;
|
|
23
|
-
if (!sessionUser?.id) {
|
|
24
|
-
ctx.res.status(401);
|
|
25
|
-
return {
|
|
26
|
-
success: false,
|
|
27
|
-
error: "unauthorized"
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
const tenantId = parsed.data.tenantId.trim();
|
|
31
|
-
const signedInTenants = Array.isArray(sessionUser.signedInTenants) ? sessionUser.signedInTenants.map(String) : [];
|
|
32
|
-
if (signedInTenants.length > 0 && !signedInTenants.includes(tenantId)) {
|
|
33
|
-
ctx.res.status(403);
|
|
34
|
-
return {
|
|
35
|
-
success: false,
|
|
36
|
-
error: "invalid_account"
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
if (signedInTenants.length === 0) {
|
|
40
|
-
const currentTenantId = typeof sessionUser.currentTenantId === "string" ? sessionUser.currentTenantId.trim() : "";
|
|
41
|
-
if (!currentTenantId || currentTenantId !== tenantId) {
|
|
42
|
-
ctx.res.status(403);
|
|
43
|
-
return {
|
|
44
|
-
success: false,
|
|
45
|
-
error: "invalid_account"
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
ctx.req.session.user = {
|
|
50
|
-
...sessionUser,
|
|
51
|
-
currentTenantId: tenantId
|
|
52
|
-
};
|
|
53
|
-
ctx.res.setHeader(AUTHENTICATED_TENANT_ID_HEADER, tenantId);
|
|
54
|
-
return {
|
|
55
|
-
success: true,
|
|
56
|
-
tenantId
|
|
57
|
-
};
|
|
58
|
-
};
|
|
59
|
-
const handler = (api) => {
|
|
60
|
-
api.use(Route, restrictSessionMiddleware);
|
|
61
|
-
api.post(Route, setActiveAccount);
|
|
62
|
-
};
|
|
63
|
-
export {
|
|
64
|
-
handler as default
|
|
65
|
-
};
|
|
66
|
-
//# sourceMappingURL=handler-B_lItxOC.js.map
|
package/dist/handler-BuwKXMOu.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { o as object, b as boolean } from "./schemas--f80aXK7.js";
|
|
2
|
-
const Route = "/api/rb/auth/sign-out";
|
|
3
|
-
object({});
|
|
4
|
-
object({
|
|
5
|
-
success: boolean()
|
|
6
|
-
});
|
|
7
|
-
const handleSignOut = async (_, ctx) => {
|
|
8
|
-
if (!ctx.req.session) {
|
|
9
|
-
return {
|
|
10
|
-
success: true
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
await new Promise((resolve) => ctx.req.session.destroy(() => resolve()));
|
|
14
|
-
return {
|
|
15
|
-
success: true
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
const handler = (api) => {
|
|
19
|
-
api.post(Route, handleSignOut);
|
|
20
|
-
};
|
|
21
|
-
export {
|
|
22
|
-
handler as default
|
|
23
|
-
};
|
|
24
|
-
//# sourceMappingURL=handler-BuwKXMOu.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler-BuwKXMOu.js","sources":["../src/api/sign-out/index.ts","../src/api/sign-out/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const Route = \"/api/rb/auth/sign-out\"\n\n// No request payload needed for signout\nexport const requestSchema = z.object({})\n\nexport type RequestPayload = z.infer<typeof requestSchema>;\n\nexport const responseSchema = z.object({\n success: z.boolean()\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>;\n","import { Api, Ctx } from \"@rpcbase/api\"\n\nimport * as SignOut from \"./index\"\n\n\nconst handleSignOut = async(_: SignOut.RequestPayload, ctx: Ctx): Promise<SignOut.ResponsePayload> => {\n // Destroy the session\n if (!ctx.req.session) {\n return { success: true }\n }\n\n await new Promise<void>((resolve) => ctx.req.session!.destroy(() => resolve()))\n\n return {\n success: true\n }\n}\n\nexport default (api: Api) => {\n api.post(SignOut.Route, handleSignOut)\n}\n"],"names":["Route","z","success","boolean","handleSignOut","_","ctx","req","session","Promise","resolve","destroy","api","post","SignOut"],"mappings":";AAGO,MAAMA,QAAQ;AAGQC,OAAS,CAAA,CAAE;AAIVA,OAAS;AAAA,EACrCC,SAASD,QAAEE;AACb,CAAC;ACPD,MAAMC,gBAAgB,OAAMC,GAA2BC,QAA+C;AAEpG,MAAI,CAACA,IAAIC,IAAIC,SAAS;AACpB,WAAO;AAAA,MAAEN,SAAS;AAAA,IAAA;AAAA,EACpB;AAEA,QAAM,IAAIO,QAAeC,CAAAA,YAAYJ,IAAIC,IAAIC,QAASG,QAAQ,MAAMD,QAAAA,CAAS,CAAC;AAE9E,SAAO;AAAA,IACLR,SAAS;AAAA,EAAA;AAEb;AAEA,MAAA,UAAe,CAACU,QAAa;AAC3BA,MAAIC,KAAKC,OAAeV,aAAa;AACvC;"}
|
package/dist/handler-C-hPxnHG.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { models } from "@rpcbase/db";
|
|
2
|
-
import { b as restrictSessionMiddleware } from "./middleware-8IfSkEEy.js";
|
|
3
|
-
import { o as object, s as string, a as array } from "./schemas--f80aXK7.js";
|
|
4
|
-
const Route = "/api/rb/auth/me";
|
|
5
|
-
object({});
|
|
6
|
-
object({
|
|
7
|
-
id: string().optional(),
|
|
8
|
-
email: string().email().optional(),
|
|
9
|
-
phone: string().optional(),
|
|
10
|
-
name: string().optional(),
|
|
11
|
-
tenants: array(string()).default([]),
|
|
12
|
-
currentTenantId: string().optional(),
|
|
13
|
-
signedInTenants: array(string()).default([]).optional(),
|
|
14
|
-
error: string().optional()
|
|
15
|
-
});
|
|
16
|
-
const me = async (_payload, ctx) => {
|
|
17
|
-
const sessionUser = ctx.req.session?.user;
|
|
18
|
-
if (!sessionUser?.id) {
|
|
19
|
-
ctx.res.status(401);
|
|
20
|
-
return {
|
|
21
|
-
id: "",
|
|
22
|
-
currentTenantId: "",
|
|
23
|
-
signedInTenants: [],
|
|
24
|
-
tenants: [],
|
|
25
|
-
error: "not_authenticated"
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
const User = await models.getGlobal("RBUser", ctx);
|
|
29
|
-
const user = await User.findById(sessionUser.id);
|
|
30
|
-
if (!user) {
|
|
31
|
-
ctx.res.status(404);
|
|
32
|
-
return {
|
|
33
|
-
id: "",
|
|
34
|
-
currentTenantId: "",
|
|
35
|
-
signedInTenants: [],
|
|
36
|
-
tenants: [],
|
|
37
|
-
error: "user_not_found"
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
const tenantId = typeof sessionUser.currentTenantId === "string" ? sessionUser.currentTenantId.trim() : "";
|
|
41
|
-
if (!tenantId) {
|
|
42
|
-
ctx.res.status(500);
|
|
43
|
-
return {
|
|
44
|
-
id: "",
|
|
45
|
-
currentTenantId: "",
|
|
46
|
-
signedInTenants: [],
|
|
47
|
-
tenants: [],
|
|
48
|
-
error: "tenant_missing"
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
return {
|
|
52
|
-
id: user._id.toString(),
|
|
53
|
-
email: user.email,
|
|
54
|
-
phone: user.get("phone"),
|
|
55
|
-
name: user.name,
|
|
56
|
-
tenants: (user.tenants || []).map(String),
|
|
57
|
-
currentTenantId: tenantId,
|
|
58
|
-
signedInTenants: sessionUser.signedInTenants || []
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
const handler = (api) => {
|
|
62
|
-
api.use(Route, restrictSessionMiddleware);
|
|
63
|
-
api.get(Route, me);
|
|
64
|
-
};
|
|
65
|
-
export {
|
|
66
|
-
handler as default
|
|
67
|
-
};
|
|
68
|
-
//# sourceMappingURL=handler-C-hPxnHG.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler-C-hPxnHG.js","sources":["../src/api/me/index.ts","../src/api/me/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const Route = \"/api/rb/auth/me\"\n\nexport const requestSchema = z.object({})\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n id: z.string().optional(),\n email: z.string().email().optional(),\n phone: z.string().optional(),\n name: z.string().optional(),\n tenants: z.array(z.string()).default([]),\n currentTenantId: z.string().optional(),\n signedInTenants: z.array(z.string()).default([]).optional(),\n error: z.string().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n","import { Api, ApiHandler, Ctx } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\n\nimport type { AuthSessionUser } from \"../../types\"\nimport { restrictSessionMiddleware } from \"../../middleware\"\n\nimport * as Me from \"./index\"\n\n\nconst me: ApiHandler<Me.RequestPayload, Me.ResponsePayload, AuthSessionUser> = async(\n _payload: Me.RequestPayload,\n ctx: Ctx<AuthSessionUser>\n): Promise<Me.ResponsePayload> => {\n const sessionUser = ctx.req.session?.user\n\n if (!sessionUser?.id) {\n ctx.res.status(401)\n return {\n id: \"\",\n currentTenantId: \"\",\n signedInTenants: [],\n tenants: [],\n error: \"not_authenticated\",\n } as unknown as Me.ResponsePayload\n }\n\n const User = await models.getGlobal(\"RBUser\", ctx)\n const user = await User.findById(sessionUser.id)\n\n if (!user) {\n ctx.res.status(404)\n return {\n id: \"\",\n currentTenantId: \"\",\n signedInTenants: [],\n tenants: [],\n error: \"user_not_found\",\n } as unknown as Me.ResponsePayload\n }\n\n const tenantId = typeof sessionUser.currentTenantId === \"string\" ? sessionUser.currentTenantId.trim() : \"\"\n if (!tenantId) {\n ctx.res.status(500)\n return {\n id: \"\",\n currentTenantId: \"\",\n signedInTenants: [],\n tenants: [],\n error: \"tenant_missing\",\n } as unknown as Me.ResponsePayload\n }\n\n return {\n id: user._id.toString(),\n email: user.email,\n phone: user.get(\"phone\") as string | undefined,\n name: user.name,\n tenants: (user.tenants || []).map(String),\n currentTenantId: tenantId,\n signedInTenants: sessionUser.signedInTenants || [],\n }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.use(Me.Route, restrictSessionMiddleware)\n api.get(Me.Route, me)\n}\n"],"names":["Route","z","id","string","optional","email","phone","name","tenants","default","currentTenantId","signedInTenants","error","me","_payload","ctx","sessionUser","req","session","user","res","status","User","models","getGlobal","findById","tenantId","trim","_id","toString","get","map","String","api","use","Me","restrictSessionMiddleware"],"mappings":";;;AAGO,MAAMA,QAAQ;AAEQC,OAAS,CAAA,CAAE;AAGVA,OAAS;AAAA,EACrCC,IAAID,OAAEE,EAASC,SAAAA;AAAAA,EACfC,OAAOJ,OAAEE,EAASE,MAAAA,EAAQD,SAAAA;AAAAA,EAC1BE,OAAOL,OAAEE,EAASC,SAAAA;AAAAA,EAClBG,MAAMN,OAAEE,EAASC,SAAAA;AAAAA,EACjBI,SAASP,MAAQA,QAAU,EAAEQ,QAAQ,CAAA,CAAE;AAAA,EACvCC,iBAAiBT,OAAEE,EAASC,SAAAA;AAAAA,EAC5BO,iBAAiBV,MAAQA,OAAEE,CAAQ,EAAEM,QAAQ,CAAA,CAAE,EAAEL,SAAAA;AAAAA,EACjDQ,OAAOX,OAAEE,EAASC,SAAAA;AACpB,CAAC;ACRD,MAAMS,KAAyE,OAC7EC,UACAC,QACgC;AAChC,QAAMC,cAAcD,IAAIE,IAAIC,SAASC;AAErC,MAAI,CAACH,aAAad,IAAI;AACpBa,QAAIK,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MACLnB,IAAI;AAAA,MACJQ,iBAAiB;AAAA,MACjBC,iBAAiB,CAAA;AAAA,MACjBH,SAAS,CAAA;AAAA,MACTI,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,QAAMU,OAAO,MAAMC,OAAOC,UAAU,UAAUT,GAAG;AACjD,QAAMI,OAAO,MAAMG,KAAKG,SAAST,YAAYd,EAAE;AAE/C,MAAI,CAACiB,MAAM;AACTJ,QAAIK,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MACLnB,IAAI;AAAA,MACJQ,iBAAiB;AAAA,MACjBC,iBAAiB,CAAA;AAAA,MACjBH,SAAS,CAAA;AAAA,MACTI,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,QAAMc,WAAW,OAAOV,YAAYN,oBAAoB,WAAWM,YAAYN,gBAAgBiB,SAAS;AACxG,MAAI,CAACD,UAAU;AACbX,QAAIK,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MACLnB,IAAI;AAAA,MACJQ,iBAAiB;AAAA,MACjBC,iBAAiB,CAAA;AAAA,MACjBH,SAAS,CAAA;AAAA,MACTI,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,SAAO;AAAA,IACLV,IAAIiB,KAAKS,IAAIC,SAAAA;AAAAA,IACbxB,OAAOc,KAAKd;AAAAA,IACZC,OAAOa,KAAKW,IAAI,OAAO;AAAA,IACvBvB,MAAMY,KAAKZ;AAAAA,IACXC,UAAUW,KAAKX,WAAW,CAAA,GAAIuB,IAAIC,MAAM;AAAA,IACxCtB,iBAAiBgB;AAAAA,IACjBf,iBAAiBK,YAAYL,mBAAmB,CAAA;AAAA,EAAA;AAEpD;AAEA,MAAA,UAAe,CAACsB,QAA8B;AAC5CA,MAAIC,IAAIC,OAAUC,yBAAyB;AAC3CH,MAAIH,IAAIK,OAAUtB,EAAE;AACtB;"}
|