const bcrypt = require('bcryptjs'); const logger = require('../../utils/logger'); const BCRYPT_COST = 12; const BCRYPT_HASH_PREFIX = '$2b$'; let instance = null; class AuthService { constructor() { if (instance) { return instance; } this.passwordHash = null; this.isHashed = false; this._initializePassword(); instance = this; } _initializePassword() { const config = require('../../utils/config'); const securityConfig = config.getSecurityConfig(); const password = securityConfig.password; if (!password) { logger.warn('No password configured. Authentication will be disabled.'); return; } if (password.startsWith(BCRYPT_HASH_PREFIX)) { this.passwordHash = password; this.isHashed = true; logger.info('AuthService initialized with bcrypt hash password'); } else { this.passwordHash = password; this.isHashed = false; logger.info('AuthService initialized with plaintext password'); } } async hashPassword(password) { return bcrypt.hash(password, BCRYPT_COST); } async verifyPassword(password, hash) { return bcrypt.compare(password, hash); } async authenticate(password) { if (!this.passwordHash) { logger.debug('Authentication skipped: no password configured'); return true; } if (!password) { logger.warn('Authentication failed: no password provided'); return false; } try { if (this.isHashed) { const isValid = await this.verifyPassword(password, this.passwordHash); if (isValid) { logger.debug('Authentication successful'); } else { logger.warn('Authentication failed: invalid password'); } return isValid; } else { const hashedInput = await this.hashPassword(password); const isValid = await this.verifyPassword(password, hashedInput); if (password === this.passwordHash) { logger.debug('Authentication successful'); return true; } else { logger.warn('Authentication failed: invalid password'); return false; } } } catch (error) { logger.error('Authentication error', { error: error.message }); return false; } } hasPassword() { return !!this.passwordHash; } static getInstance() { if (!instance) { instance = new AuthService(); } return instance; } } module.exports = AuthService;