From ec15095da3098c1f6e7d567fe537733ac0136615 Mon Sep 17 00:00:00 2001 From: Chi Cong Tran Date: Thu, 21 Aug 2025 10:52:29 +0200 Subject: [PATCH] remove jssha and add bcrypt for password hashing with salt --- package-lock.json | 45 ++++++++++++++----- package.json | 2 +- src/init/init_db.ts | 5 ++- src/lib/auth.ts | 8 ++-- .../(angemeldet)/user-management/+page.svelte | 3 +- src/routes/api/users/+server.ts | 6 ++- 6 files changed, 48 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index c3e8588..9e00d04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,9 +12,9 @@ "@sveltejs/adapter-node": "^5.2.12", "@tailwindcss/forms": "^0.5.10", "autoprefixer": "^10.4.21", + "bcrypt": "^6.0.0", "better-sqlite3": "^12.2.0", "jsonwebtoken": "^9.0.2", - "jssha": "^3.3.1", "minio": "^8.0.5", "postcss": "^8.5.4", "sqlite3": "^5.1.7", @@ -2483,6 +2483,29 @@ ], "license": "MIT" }, + "node_modules/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/bcrypt/node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, "node_modules/better-sqlite3": { "version": "12.2.0", "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.2.0.tgz", @@ -4617,15 +4640,6 @@ "npm": ">=6" } }, - "node_modules/jssha": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jssha/-/jssha-3.3.1.tgz", - "integrity": "sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ==", - "license": "BSD-3-Clause", - "engines": { - "node": "*" - } - }, "node_modules/jwa": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", @@ -5309,6 +5323,17 @@ "node": ">= 10.12.0" } }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", diff --git a/package.json b/package.json index 9d7f33c..4742a0c 100644 --- a/package.json +++ b/package.json @@ -47,9 +47,9 @@ "@sveltejs/adapter-node": "^5.2.12", "@tailwindcss/forms": "^0.5.10", "autoprefixer": "^10.4.21", + "bcrypt": "^6.0.0", "better-sqlite3": "^12.2.0", "jsonwebtoken": "^9.0.2", - "jssha": "^3.3.1", "minio": "^8.0.5", "postcss": "^8.5.4", "sqlite3": "^5.1.7", diff --git a/src/init/init_db.ts b/src/init/init_db.ts index b057c3c..394bb58 100644 --- a/src/init/init_db.ts +++ b/src/init/init_db.ts @@ -1,5 +1,5 @@ import Database from 'better-sqlite3'; -import jsSHA from 'jssha'; +import bcrypt from 'bcrypt'; const db = new Database('./src/lib/data/tatort.db'); @@ -11,7 +11,8 @@ db.exec(createSQLStmt); // check if there are any users; if not add one default admin one const userPassword = 'A-InnoHUB_2025!'; -const hashedUserPassword = new jsSHA('SHA-512', 'TEXT').update(userPassword).getHash('HEX'); +const saltRounds = 12; +const hashedUserPassword = bcrypt.hashSync(userPassword, saltRounds); const checkInsertSQLStmt = `INSERT INTO users (name, pw) SELECT 'admin', '${hashedUserPassword}' WHERE NOT EXISTS (SELECT * FROM users);`; diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 4529d6e..8895111 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,5 +1,5 @@ import jwt from 'jsonwebtoken'; -import jsSHA from 'jssha'; +import bcrypt from 'bcrypt'; import { db } from '$lib/server/dbService'; import config from '$lib/config'; @@ -18,9 +18,6 @@ export function decryptToken(token: string) { export function authenticate(user, password) { let JWTToken; - // hash user password - const hashedPW = new jsSHA('SHA-512', 'TEXT').update(password).getHash('HEX'); - const getUserSQLStmt = 'SELECT name, pw FROM users WHERE name = ?'; const row = db.prepare(getUserSQLStmt).get(user); @@ -29,7 +26,8 @@ export function authenticate(user, password) { } const storedPW = row.pw; - if (hashedPW && hashedPW === storedPW) { + const isValid = bcrypt.compareSync(password, storedPW) + if (isValid) { JWTToken = createToken({ id: user, admin: true }); } diff --git a/src/routes/(angemeldet)/user-management/+page.svelte b/src/routes/(angemeldet)/user-management/+page.svelte index 957326c..d0d1874 100644 --- a/src/routes/(angemeldet)/user-management/+page.svelte +++ b/src/routes/(angemeldet)/user-management/+page.svelte @@ -45,8 +45,7 @@ } const URL = '/api/users'; - const hashedUserPassword = new jsSHA('SHA-512', 'TEXT').update(userPassword).getHash('HEX'); - const userData = { userName: userName, userPassword: hashedUserPassword }; + const userData = { userName: userName, userPassword: userPassword }; try { const response = await fetch(URL, { diff --git a/src/routes/api/users/+server.ts b/src/routes/api/users/+server.ts index 7eaece3..7bf820c 100644 --- a/src/routes/api/users/+server.ts +++ b/src/routes/api/users/+server.ts @@ -1,5 +1,8 @@ import { json } from '@sveltejs/kit'; import { addUser, getUsers } from '$lib/server/userService'; +import bcrypt from 'bcrypt'; + +const saltRounds = 12; export function GET({ locals }) { if (!locals.user) { @@ -24,7 +27,8 @@ export async function POST({ request, locals }) { return json({ error: 'Missing input' }, { status: 400 }); } - const rowInfo = addUser(userName, userPassword); + const hashedPassword = bcrypt.hashSync(userPassword, saltRounds); + const rowInfo = addUser(userName, hashedPassword); if (rowInfo?.changes == 1) { return json({ userId: rowInfo.lastInsertRowid, userName: userName }, { status: 201 });