Files
OLD-server-architecture/auth/src/core/auth.core.js

167 lines
5.5 KiB
JavaScript

const { v4: uuid } = require('uuid');
const { query } = require('../storage/database');
const security = require('../tools/security');
const tracking = require('../tools/tracking');
// ─── ERRORI CUSTOM ──────────────────────────────────────────────────
class AuthError extends Error {
constructor(code, message) {
super(message || code);
this.code = code;
}
}
// ─── REGISTRAZIONE ──────────────────────────────────────────────────
async function register(username, password) {
const exists = await query('SELECT id FROM users WHERE username = $1', [username]);
if (exists.rows.length) throw new AuthError('USER_EXISTS', 'Username già in uso');
const hash = await security.hashPassword(password);
const id = uuid();
await query(
'INSERT INTO users (id, username, password_hash) VALUES ($1, $2, $3)',
[id, username, hash]
);
return { id, username };
}
// ─── LOGIN ──────────────────────────────────────────────────────────
async function login(username, password) {
const { rows } = await query(
'SELECT id, username, password_hash, is_active, created_at FROM users WHERE username = $1',
[username]
);
if (!rows.length) throw new AuthError('INVALID_CREDENTIALS', 'Credenziali non valide');
const user = rows[0];
if (!user.is_active) throw new AuthError('ACCOUNT_INACTIVE', 'Account disattivato');
const ok = await security.verifyPassword(password, user.password_hash);
if (!ok) throw new AuthError('INVALID_CREDENTIALS', 'Credenziali non valide');
return { id: user.id, username: user.username, created_at: user.created_at };
}
// ─── SESSIONI ───────────────────────────────────────────────────────
async function createSession(userId, userAgent, ip) {
const id = uuid();
const code = security.sessionCode();
const meta = tracking.extract(userAgent);
await query(
`INSERT INTO sessions
(id, user_id, session_code, encoded_username, ip_address, user_agent, browser, os, device_type)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
[id, userId, code, '', ip, userAgent, meta.browser, meta.os, meta.device_type]
);
return { id, code };
}
async function validateSession(sessionId) {
if (!sessionId || typeof sessionId !== 'string') {
throw new AuthError('INVALID_SESSION', 'Sessione non valida');
}
const { rows } = await query(
`SELECT s.id, s.is_revoked, u.is_active
FROM sessions s
JOIN users u ON s.user_id = u.id
WHERE s.id = $1`,
[sessionId]
);
if (!rows.length) throw new AuthError('INVALID_SESSION', 'Sessione non trovata');
if (rows[0].is_revoked) throw new AuthError('SESSION_REVOKED', 'Sessione revocata');
if (!rows[0].is_active) throw new AuthError('ACCOUNT_INACTIVE', 'Account disattivato');
// Aggiorna last_active in modo non bloccante
query('UPDATE sessions SET last_active = NOW() WHERE id = $1', [sessionId]).catch(() => {});
return true;
}
async function revokeSession(sessionId, userId) {
if (userId) {
const r = await query(
'UPDATE sessions SET is_revoked = TRUE WHERE id = $1 AND user_id = $2 AND is_revoked = FALSE',
[sessionId, userId]
);
return r.rowCount > 0;
}
const r = await query(
'UPDATE sessions SET is_revoked = TRUE WHERE id = $1 AND is_revoked = FALSE',
[sessionId]
);
return r.rowCount > 0;
}
async function listSessions(userId) {
const { rows } = await query(
`SELECT id, ip_address, browser, os, device_type,
location_country, location_city, created_at, last_active, is_revoked
FROM sessions
WHERE user_id = $1
ORDER BY last_active DESC`,
[userId]
);
return rows;
}
// ─── LOOKUP UTENTE ──────────────────────────────────────────────────
async function getUserById(userId) {
const { rows } = await query(
'SELECT id, username, is_active, created_at, telegram_id FROM users WHERE id = $1',
[userId]
);
return rows[0] || null;
}
async function getAllUsers() {
const { rows } = await query(
'SELECT id, username, is_active, created_at, telegram_id FROM users'
);
return rows;
}
async function getUsersToNotify() {
const { rows } = await query(
'SELECT telegram_id FROM users WHERE telegram_id IS NOT NULL'
);
return rows;
}
async function updateUsername(userId, newUsername) {
const r = await query(
'UPDATE users SET username = $1 WHERE id = $2 RETURNING username',
[newUsername, userId]
);
return r.rowCount > 0 ? r.rows[0] : null;
}
async function updateTelegram(userId, telegramId) {
await query(
'UPDATE users SET telegram_id = $1 WHERE id = $2',
[telegramId, userId]
);
}
module.exports = {
AuthError,
register,
login,
createSession,
validateSession,
revokeSession,
listSessions,
getUserById,
getAllUsers,
getUsersToNotify,
updateUsername,
updateTelegram
};