aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-03-18 12:08:53 +0000
committerMohamedBassem <me@mbassem.com>2024-03-18 12:08:53 +0000
commit549520919c482e72cdf7adae5ba852d1b6cbe5aa (patch)
tree8599e55fe214f673685f9dbab7ea26f796748e01 /packages
parent60467f1d7fdc63e8ec3b10ad0d183248cebac4ee (diff)
downloadkarakeep-549520919c482e72cdf7adae5ba852d1b6cbe5aa.tar.zst
feature(web): Add the ability to change passwords
Diffstat (limited to 'packages')
-rw-r--r--packages/trpc/routers/users.ts42
-rw-r--r--packages/trpc/types/users.ts15
2 files changed, 48 insertions, 9 deletions
diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts
index 1a851b05..db06c0ad 100644
--- a/packages/trpc/routers/users.ts
+++ b/packages/trpc/routers/users.ts
@@ -1,16 +1,19 @@
-import { zSignUpSchema } from "../types/users";
+import { TRPCError } from "@trpc/server";
+import { count, eq } from "drizzle-orm";
+import invariant from "tiny-invariant";
+import { z } from "zod";
+
+import { SqliteError } from "@hoarder/db";
+import { users } from "@hoarder/db/schema";
+
+import { hashPassword, validatePassword } from "../auth";
import {
adminProcedure,
authedProcedure,
publicProcedure,
router,
} from "../index";
-import { SqliteError } from "@hoarder/db";
-import { z } from "zod";
-import { hashPassword } from "../auth";
-import { TRPCError } from "@trpc/server";
-import { users } from "@hoarder/db/schema";
-import { count, eq } from "drizzle-orm";
+import { zSignUpSchema } from "../types/users";
export const usersAppRouter = router({
create: publicProcedure
@@ -83,6 +86,29 @@ export const usersAppRouter = router({
});
return { users };
}),
+ changePassword: authedProcedure
+ .input(
+ z.object({
+ currentPassword: z.string(),
+ newPassword: z.string(),
+ }),
+ )
+ .mutation(async ({ input, ctx }) => {
+ invariant(ctx.user.email, "A user always has an email specified");
+ let user;
+ try {
+ user = await validatePassword(ctx.user.email, input.currentPassword);
+ } catch (e) {
+ throw new TRPCError({ code: "UNAUTHORIZED" });
+ }
+ invariant(user.id, ctx.user.id);
+ await ctx.db
+ .update(users)
+ .set({
+ password: await hashPassword(input.newPassword),
+ })
+ .where(eq(users.id, ctx.user.id));
+ }),
delete: adminProcedure
.input(
z.object({
@@ -103,7 +129,7 @@ export const usersAppRouter = router({
email: z.string().nullish(),
}),
)
- .query(async ({ ctx }) => {
+ .query(({ ctx }) => {
return { id: ctx.user.id, name: ctx.user.name, email: ctx.user.email };
}),
});
diff --git a/packages/trpc/types/users.ts b/packages/trpc/types/users.ts
index c2fe182a..3026337a 100644
--- a/packages/trpc/types/users.ts
+++ b/packages/trpc/types/users.ts
@@ -1,13 +1,26 @@
import { z } from "zod";
+const PASSWORD_MAX_LENGTH = 100;
+
export const zSignUpSchema = z
.object({
name: z.string().min(1, { message: "Name can't be empty" }),
email: z.string().email(),
- password: z.string().min(8),
+ password: z.string().min(8).max(PASSWORD_MAX_LENGTH),
confirmPassword: z.string(),
})
.refine((data) => data.password === data.confirmPassword, {
message: "Passwords don't match",
path: ["confirmPassword"],
});
+
+export const zChangePasswordSchema = z
+ .object({
+ currentPassword: z.string(),
+ newPassword: z.string().min(8).max(PASSWORD_MAX_LENGTH),
+ newPasswordConfirm: z.string(),
+ })
+ .refine((data) => data.newPassword === data.newPasswordConfirm, {
+ message: "Passwords don't match",
+ path: ["newPasswordConfirm"],
+ });