import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { createLogger } from './logger';
const logger = createLogger();
export interface User {
id: string;
username: string;
email: string;
role: 'admin' | 'user';
password_hash: string;
created_at: Date;
updated_at: Date;
}
export class AuthService {
private static instance: AuthService;
private users: Map<string, User> = new Map();
private constructor() {
// Initialize with default admin user
this.createDefaultUser();
}
public static getInstance(): AuthService {
if (!AuthService.instance) {
AuthService.instance = new AuthService();
}
return AuthService.instance;
}
private async createDefaultUser(): Promise<void> {
const defaultPassword = process.env.DEFAULT_ADMIN_PASSWORD || 'admin123';
const hashedPassword = await bcrypt.hash(defaultPassword, 10);
const defaultUser: User = {
id: '1',
username: 'admin',
email: 'admin@example.com',
role: 'admin',
password_hash: hashedPassword,
created_at: new Date(),
updated_at: new Date()
};
this.users.set(defaultUser.id, defaultUser);
this.users.set(defaultUser.username, defaultUser);
logger.info('Default admin user created', { username: defaultUser.username });
}
public async validateUser(username: string, password: string): Promise<User | null> {
try {
const user = this.users.get(username);
if (!user) {
logger.warn('User not found', { username });
return null;
}
const isValid = await bcrypt.compare(password, user.password_hash);
if (!isValid) {
logger.warn('Invalid password', { username });
return null;
}
logger.info('User validated successfully', { username, role: user.role });
return user;
} catch (error) {
logger.error('Error validating user', { username, error });
return null;
}
}
public generateToken(user: User): string {
const payload = {
id: user.id,
username: user.username,
email: user.email,
role: user.role
};
const secret = process.env.JWT_SECRET || 'your-secret-key';
const expiresIn = process.env.JWT_EXPIRES_IN || '24h';
return jwt.sign(payload, secret, { expiresIn });
}
public verifyToken(token: string): any {
try {
const secret = process.env.JWT_SECRET || 'your-secret-key';
return jwt.verify(token, secret);
} catch (error) {
logger.error('Token verification failed', { error });
return null;
}
}
public async createUser(userData: Omit<User, 'id' | 'password_hash' | 'created_at' | 'updated_at'>, password: string): Promise<User> {
const hashedPassword = await bcrypt.hash(password, 10);
const user: User = {
...userData,
id: Date.now().toString(),
password_hash: hashedPassword,
created_at: new Date(),
updated_at: new Date()
};
this.users.set(user.id, user);
this.users.set(user.username, user);
logger.info('User created', { username: user.username, role: user.role });
return user;
}
public getUserById(id: string): User | null {
return this.users.get(id) || null;
}
public getUserByUsername(username: string): User | null {
return this.users.get(username) || null;
}
}