diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-04-15 19:36:51 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2025-04-15 19:36:51 +0000 |
| commit | 7e39afa29f1674df4cac51c7894181f55f66aa12 (patch) | |
| tree | 55caff2f4d14e222a2d9c2b63157d28a438a96e7 /packages/trpc | |
| parent | d7244978e9e99ca20b99a9f751b1bfef77810e94 (diff) | |
| download | karakeep-7e39afa29f1674df4cac51c7894181f55f66aa12.tar.zst | |
fix: Add password salt to the user table
Diffstat (limited to 'packages/trpc')
| -rw-r--r-- | packages/trpc/auth.ts | 13 | ||||
| -rw-r--r-- | packages/trpc/routers/admin.ts | 7 | ||||
| -rw-r--r-- | packages/trpc/routers/users.ts | 10 |
3 files changed, 21 insertions, 9 deletions
diff --git a/packages/trpc/auth.ts b/packages/trpc/auth.ts index f5ce88e5..1c3b860d 100644 --- a/packages/trpc/auth.ts +++ b/packages/trpc/auth.ts @@ -11,6 +11,10 @@ import { authFailureLogger } from "@karakeep/shared/logger"; const BCRYPT_SALT_ROUNDS = 10; const API_KEY_PREFIX = "ak1"; +export function generatePasswordSalt() { + return randomBytes(32).toString("hex"); +} + export async function generateApiKey(name: string, userId: string) { const id = randomBytes(10).toString("hex"); const secret = randomBytes(10).toString("hex"); @@ -76,8 +80,8 @@ export async function authenticateApiKey(key: string) { return apiKey.user; } -export async function hashPassword(password: string) { - return bcrypt.hash(password, BCRYPT_SALT_ROUNDS); +export async function hashPassword(password: string, salt: string | null) { + return await bcrypt.hash(password + (salt ?? ""), BCRYPT_SALT_ROUNDS); } export async function validatePassword(email: string, password: string) { @@ -96,7 +100,10 @@ export async function validatePassword(email: string, password: string) { throw new Error("This user doesn't have a password defined"); } - const validation = await bcrypt.compare(password, user.password); + const validation = await bcrypt.compare( + password + (user.salt ?? ""), + user.password, + ); if (!validation) { throw new Error("Wrong password"); } diff --git a/packages/trpc/routers/admin.ts b/packages/trpc/routers/admin.ts index 9b44f7c9..85869ba8 100644 --- a/packages/trpc/routers/admin.ts +++ b/packages/trpc/routers/admin.ts @@ -22,7 +22,7 @@ import { zAdminCreateUserSchema, } from "@karakeep/shared/types/admin"; -import { hashPassword } from "../auth"; +import { generatePasswordSalt, hashPassword } from "../auth"; import { adminProcedure, router } from "../index"; import { createUser } from "./users"; @@ -338,10 +338,11 @@ export const adminAppRouter = router({ message: "Cannot reset own password", }); } - const hashedPassword = await hashPassword(input.newPassword); + const newSalt = generatePasswordSalt(); + const hashedPassword = await hashPassword(input.newPassword, newSalt); const result = await ctx.db .update(users) - .set({ password: hashedPassword }) + .set({ password: hashedPassword, salt: newSalt }) .where(eq(users.id, input.userId)); if (result.changes == 0) { diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts index 75a1db0c..c56daaee 100644 --- a/packages/trpc/routers/users.ts +++ b/packages/trpc/routers/users.ts @@ -19,7 +19,7 @@ import { zWhoAmIResponseSchema, } from "@karakeep/shared/types/users"; -import { hashPassword, validatePassword } from "../auth"; +import { generatePasswordSalt, hashPassword, validatePassword } from "../auth"; import { adminProcedure, authedProcedure, @@ -42,13 +42,15 @@ export async function createUser( userRole = userCount == 0 ? "admin" : "user"; } + const salt = generatePasswordSalt(); try { const result = await trx .insert(users) .values({ name: input.name, email: input.email, - password: await hashPassword(input.password), + password: await hashPassword(input.password, salt), + salt, role: userRole, }) .returning({ @@ -149,10 +151,12 @@ export const usersAppRouter = router({ throw new TRPCError({ code: "UNAUTHORIZED" }); } invariant(user.id, ctx.user.id); + const newSalt = generatePasswordSalt(); await ctx.db .update(users) .set({ - password: await hashPassword(input.newPassword), + password: await hashPassword(input.newPassword, newSalt), + salt: newSalt, }) .where(eq(users.id, ctx.user.id)); }), |
