import bcrypt from 'bcrypt';
import { v4 as uuidv4 } from 'uuid';
import pg from 'pg';
const SALT_ROUNDS = 12;
export class AuthService {
constructor(private pool: pg.Pool) {}
async hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, SALT_ROUNDS);
}
async verifyPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}
generateApiKey(): string {
// Format: ciq_<uuid without dashes>
return `ciq_${uuidv4().replace(/-/g, '')}`;
}
async createUser(username: string, email: string, password: string): Promise<number> {
const passwordHash = await this.hashPassword(password);
const result = await this.pool.query(
`INSERT INTO users (username, email, password_hash)
VALUES ($1, $2, $3) RETURNING id`,
[username, email, passwordHash]
);
return result.rows[0].id;
}
async validateUser(username: string, password: string): Promise<{ id: number; username: string } | null> {
const result = await this.pool.query(
'SELECT id, username, password_hash FROM users WHERE username = $1 AND is_active = true',
[username]
);
if (result.rows.length === 0) return null;
const user = result.rows[0];
const valid = await this.verifyPassword(password, user.password_hash);
if (!valid) return null;
// Update last login
await this.pool.query('UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = $1', [user.id]);
return { id: user.id, username: user.username };
}
async getUserById(userId: number): Promise<{ id: number; username: string; email: string } | null> {
const result = await this.pool.query(
'SELECT id, username, email FROM users WHERE id = $1 AND is_active = true',
[userId]
);
return result.rows[0] || null;
}
}