aboutsummaryrefslogtreecommitdiffstats
path: root/packages/trpc
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2026-02-01 17:20:17 +0000
committerGitHub <noreply@github.com>2026-02-01 17:20:17 +0000
commit4051594b2f410f01e883febad22eb9001a84f90e (patch)
tree37b74d93192e2399fb50a31436150ba671b2b5cc /packages/trpc
parent67501ed6229a63efc29b34513fac35239bd4f8e4 (diff)
downloadkarakeep-4051594b2f410f01e883febad22eb9001a84f90e.tar.zst
feat: add support for redirectUrl after signup (#2439)
* feat: add support for redirectUrl after signup * pr review * more fixes * format * another fix
Diffstat (limited to 'packages/trpc')
-rw-r--r--packages/trpc/email.ts6
-rw-r--r--packages/trpc/models/users.ts12
-rw-r--r--packages/trpc/routers/users.test.ts1
-rw-r--r--packages/trpc/routers/users.ts17
4 files changed, 29 insertions, 7 deletions
diff --git a/packages/trpc/email.ts b/packages/trpc/email.ts
index b837656e..15e1ef74 100644
--- a/packages/trpc/email.ts
+++ b/packages/trpc/email.ts
@@ -55,8 +55,12 @@ export const sendVerificationEmail = withTracing(
email: string,
name: string,
token: string,
+ redirectUrl?: string,
) => {
- const verificationUrl = `${serverConfig.publicUrl}/verify-email?token=${encodeURIComponent(token)}&email=${encodeURIComponent(email)}`;
+ let verificationUrl = `${serverConfig.publicUrl}/verify-email?token=${encodeURIComponent(token)}&email=${encodeURIComponent(email)}`;
+ if (redirectUrl) {
+ verificationUrl += `&redirectUrl=${encodeURIComponent(redirectUrl)}`;
+ }
const mailOptions = {
from: serverConfig.email.smtp!.from,
diff --git a/packages/trpc/models/users.ts b/packages/trpc/models/users.ts
index 5d3c3785..671f7d74 100644
--- a/packages/trpc/models/users.ts
+++ b/packages/trpc/models/users.ts
@@ -61,7 +61,7 @@ export class User {
static async create(
ctx: Context,
- input: z.infer<typeof zSignUpSchema>,
+ input: z.infer<typeof zSignUpSchema> & { redirectUrl?: string },
role?: "user" | "admin",
) {
const salt = generatePasswordSalt();
@@ -76,7 +76,12 @@ export class User {
if (serverConfig.auth.emailVerificationRequired) {
const token = await User.genEmailVerificationToken(ctx.db, input.email);
try {
- await sendVerificationEmail(input.email, input.name, token);
+ await sendVerificationEmail(
+ input.email,
+ input.name,
+ token,
+ input.redirectUrl,
+ );
} catch (error) {
console.error("Failed to send verification email:", error);
}
@@ -227,6 +232,7 @@ export class User {
static async resendVerificationEmail(
ctx: Context,
email: string,
+ redirectUrl?: string,
): Promise<void> {
if (
!serverConfig.auth.emailVerificationRequired ||
@@ -255,7 +261,7 @@ export class User {
const token = await User.genEmailVerificationToken(ctx.db, email);
try {
- await sendVerificationEmail(email, user.name, token);
+ await sendVerificationEmail(email, user.name, token, redirectUrl);
} catch (error) {
console.error("Failed to send verification email:", error);
throw new TRPCError({
diff --git a/packages/trpc/routers/users.test.ts b/packages/trpc/routers/users.test.ts
index 605d14fc..ccde4c86 100644
--- a/packages/trpc/routers/users.test.ts
+++ b/packages/trpc/routers/users.test.ts
@@ -1116,6 +1116,7 @@ describe("User Routes", () => {
"resend@test.com",
"Test User",
expect.any(String), // token
+ undefined, // redirectUrl
);
});
diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts
index abd50d63..c11a0ffd 100644
--- a/packages/trpc/routers/users.ts
+++ b/packages/trpc/routers/users.ts
@@ -11,6 +11,7 @@ import {
zWhoAmIResponseSchema,
zWrappedStatsResponseSchema,
} from "@karakeep/shared/types/users";
+import { validateRedirectUrl } from "@karakeep/shared/utils/redirectUrl";
import {
adminProcedure,
@@ -31,7 +32,7 @@ export const usersAppRouter = router({
maxRequests: 3,
}),
)
- .input(zSignUpSchema)
+ .input(zSignUpSchema.and(z.object({ redirectUrl: z.string().optional() })))
.output(
z.object({
id: z.string(),
@@ -65,7 +66,11 @@ export const usersAppRouter = router({
});
}
}
- const user = await User.create(ctx, input);
+ const validatedRedirectUrl = validateRedirectUrl(input.redirectUrl);
+ const user = await User.create(ctx, {
+ ...input,
+ redirectUrl: validatedRedirectUrl,
+ });
return {
id: user.id,
name: user.name,
@@ -206,10 +211,16 @@ export const usersAppRouter = router({
.input(
z.object({
email: z.string().email(),
+ redirectUrl: z.string().optional(),
}),
)
.mutation(async ({ input, ctx }) => {
- await User.resendVerificationEmail(ctx, input.email);
+ const validatedRedirectUrl = validateRedirectUrl(input.redirectUrl);
+ await User.resendVerificationEmail(
+ ctx,
+ input.email,
+ validatedRedirectUrl,
+ );
return { success: true };
}),
forgotPassword: publicProcedure