11import bcrypt from 'bcryptjs' ;
22import jwt from 'jsonwebtoken' ;
33import { dbGet , dbRun } from './database.js' ;
4+ import { randomBytes , randomInt } from 'crypto' ;
45
5- const JWT_SECRET = process . env . JWT_SECRET || 'your-super-secret-jwt-key-change-in-production' ;
6+ const JWT_SECRET = process . env . JWT_SECRET || randomBytes ( 32 ) . toString ( 'hex' ) ;
7+ if ( process . env . NODE_ENV === 'production' && ! process . env . JWT_SECRET ) {
8+ console . warn ( 'JWT_SECRET is not set. A random key was generated at runtime; tokens will be invalidated on restart. Set JWT_SECRET in production.' ) ;
9+ }
610const SALT_ROUNDS = 12 ;
711
812// Check if this is the first time setup (no admin exists)
@@ -47,7 +51,7 @@ export const setupInitialCredentials = async (password) => {
4751// Authenticate user against database
4852export const authenticateUser = async ( password ) => {
4953 try {
50- console . log ( 'Authenticating admin user' ) ;
54+ console . log ( 'Authenticating admin user... ' ) ;
5155
5256 const user = await dbGet (
5357 'SELECT username, password_hash, salt FROM admin_users WHERE username = ?' ,
@@ -59,22 +63,26 @@ export const authenticateUser = async (password) => {
5963 return false ;
6064 }
6165
62- console . log ( 'Found admin user, comparing passwords...' ) ;
66+ console . log ( 'Found admin user in database' ) ;
67+ console . log ( 'Stored hash:' , user . password_hash ) ;
6368
64- // Hash the provided password with the stored salt
65- const hashedPassword = await bcrypt . hash ( password , user . salt ) ;
66- const isValid = hashedPassword === user . password_hash ;
69+ // Log the first few characters of the stored hash and salt for debugging
70+ console . log ( `Stored hash (first 10 chars): ${ user . password_hash ?. substring ( 0 , 10 ) } ...` ) ;
71+ console . log ( `Stored salt: ${ user . salt } ` ) ;
6772
68- if ( ! isValid ) {
69- console . log ( 'Password comparison failed' ) ;
70- console . log ( 'Stored hash:' , user . password_hash ) ;
71- console . log ( 'Computed hash:' , hashedPassword ) ;
72- console . log ( 'Using salt:' , user . salt ) ;
73+ // Use bcrypt.compare to verify the password
74+ console . log ( 'Verifying password...' ) ;
75+ const isMatch = await bcrypt . compare ( password , user . password_hash ) ;
76+
77+ if ( ! isMatch ) {
78+ console . log ( 'Password verification failed' ) ;
79+ // Log the first few characters of the attempted password for debugging
80+ console . log ( `Attempted password (first 5 chars): ${ password . substring ( 0 , 5 ) } ...` ) ;
7381 } else {
74- console . log ( 'Authentication successful' ) ;
82+ console . log ( 'Password verification successful' ) ;
7583 }
7684
77- return isValid ;
85+ return isMatch ;
7886 } catch ( error ) {
7987 console . error ( 'Error in authenticateUser:' , error ) ;
8088 return false ;
@@ -149,19 +157,24 @@ export const generateSecurePassword = () => {
149157
150158 // Ensure at least one character from each category
151159 let password = '' ;
152- password += uppercase [ Math . floor ( Math . random ( ) * uppercase . length ) ] ;
153- password += lowercase [ Math . floor ( Math . random ( ) * lowercase . length ) ] ;
154- password += numbers [ Math . floor ( Math . random ( ) * numbers . length ) ] ;
155- password += special [ Math . floor ( Math . random ( ) * special . length ) ] ;
160+ password += uppercase [ randomInt ( uppercase . length ) ] ;
161+ password += lowercase [ randomInt ( lowercase . length ) ] ;
162+ password += numbers [ randomInt ( numbers . length ) ] ;
163+ password += special [ randomInt ( special . length ) ] ;
156164
157165 // Fill remaining length with random characters
158166 const allChars = uppercase + lowercase + numbers + special ;
159167 for ( let i = 4 ; i < 16 ; i ++ ) {
160- password += allChars [ Math . floor ( Math . random ( ) * allChars . length ) ] ;
168+ password += allChars [ randomInt ( allChars . length ) ] ;
161169 }
162170
163- // Shuffle the password
164- return password . split ( '' ) . sort ( ( ) => Math . random ( ) - 0.5 ) . join ( '' ) ;
171+ // Secure Fisher-Yates shuffle using crypto randomness
172+ const arr = password . split ( '' ) ;
173+ for ( let i = arr . length - 1 ; i > 0 ; i -- ) {
174+ const j = randomInt ( i + 1 ) ;
175+ [ arr [ i ] , arr [ j ] ] = [ arr [ j ] , arr [ i ] ] ;
176+ }
177+ return arr . join ( '' ) ;
165178} ;
166179
167180// Middleware to verify authentication
0 commit comments