102 lines
2.4 KiB
JavaScript
102 lines
2.4 KiB
JavaScript
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;
|