refactor: clean up code and improve error handling in authentication and database modules
This commit is contained in:
@@ -1,12 +1,8 @@
|
||||
const query = require('../storage/database').query;
|
||||
const track = require('../tools/tracking')
|
||||
const track = require('../tools/tracking');
|
||||
const { v4: uuid } = require('uuid');
|
||||
const security = require('../tools/security')
|
||||
const security = require('../tools/security');
|
||||
|
||||
|
||||
/**
|
||||
* Registra un nuovo utente
|
||||
*/
|
||||
async function register(username, password) {
|
||||
const userExists = await query('SELECT id FROM users WHERE username = $1', [username]);
|
||||
|
||||
@@ -17,132 +13,89 @@ async function register(username, password) {
|
||||
const hashedPassword = await security.hashPassword(password);
|
||||
const id = uuid();
|
||||
|
||||
await query('INSERT INTO users (id, username, password_hash) VALUES ($1, $2, $3)', [id, username, hashedPassword]);
|
||||
await query(
|
||||
'INSERT INTO users (id, username, password_hash) VALUES ($1, $2, $3)',
|
||||
[id, username, hashedPassword]
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
user: {
|
||||
id,
|
||||
username
|
||||
}
|
||||
};
|
||||
return { success: true, user: { id, username } };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Esegue il login di un utente
|
||||
*/
|
||||
async function login(username, password) {
|
||||
console.log('[DEBUG AUTH] login() START - username:', username);
|
||||
|
||||
const result = await query('SELECT id, username, password_hash, created_at FROM users WHERE username = $1', [username]);
|
||||
console.log('[DEBUG AUTH] login() - query result rows:', result.rows.length);
|
||||
|
||||
const result = await query(
|
||||
'SELECT id, username, password_hash, is_active, created_at FROM users WHERE username = $1',
|
||||
[username]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
console.log('[DEBUG AUTH] login() - user not found');
|
||||
throw new Error('No user matched')
|
||||
throw new Error('No user matched');
|
||||
}
|
||||
|
||||
const user = result.rows[0];
|
||||
console.log('[DEBUG AUTH] login() - user found:', { id: user.id, username: user.username });
|
||||
|
||||
const isValid = await security.verifyPassword(password, user.password_hash);
|
||||
console.log('[DEBUG AUTH] login() - password valid:', isValid);
|
||||
|
||||
if (!isValid) {
|
||||
console.log('[DEBUG AUTH] login() - password mismatch');
|
||||
throw new Error('Password mismatch')
|
||||
if (!user.is_active) {
|
||||
throw new Error('User account is not active');
|
||||
}
|
||||
|
||||
const result_obj = {
|
||||
const isValid = await security.verifyPassword(password, user.password_hash);
|
||||
|
||||
if (!isValid) {
|
||||
throw new Error('Password mismatch');
|
||||
}
|
||||
|
||||
return {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
created: user.created_at
|
||||
};
|
||||
console.log('[DEBUG AUTH] login() SUCCESS - returning user:', result_obj);
|
||||
return result_obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Esegue il logout di un utente
|
||||
*
|
||||
*/
|
||||
async function logout(sessionID) {
|
||||
if (!sessionID) {
|
||||
throw new Error('no sessio id passed');
|
||||
throw new Error('No session ID provided');
|
||||
}
|
||||
|
||||
const result = await query('UPDATE sessions SET is_revoked = TRUE WHERE id = $1', [sessionID]);
|
||||
return result.rowCount > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea una nuova sessione per un utente che ha appaena eseguito il login
|
||||
*/
|
||||
async function newSession(userId, userAgent, ip) {
|
||||
console.log('[DEBUG AUTH] newSession() START - userId:', userId);
|
||||
|
||||
const id = uuid();
|
||||
const sessionCode = security.generateSessionCode();
|
||||
const metadata = track.getBasicMetadata(userAgent);
|
||||
console.log('[DEBUG AUTH] newSession() - sessionCode generated:', sessionCode, 'metadata:', metadata);
|
||||
|
||||
const insertResult = await query(
|
||||
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, sessionCode, '', ip, userAgent, metadata.browser, metadata.os, metadata.device_type]
|
||||
);
|
||||
console.log('[DEBUG AUTH] newSession() - INSERT result:', { rowCount: insertResult.rowCount });
|
||||
|
||||
const result = { id, sessionCode };
|
||||
console.log('[DEBUG AUTH] newSession() SUCCESS - returning:', result);
|
||||
return result;
|
||||
return { id, sessionCode };
|
||||
}
|
||||
|
||||
/**
|
||||
* Valida una sessione tramite il suo UUID
|
||||
*/
|
||||
async function validateSession(sessionId) {
|
||||
console.log('[DEBUG AUTH] validateSession() START - sessionId:', sessionId);
|
||||
|
||||
if (!sessionId || typeof sessionId !== 'string') {
|
||||
console.log('[DEBUG AUTH] validateSession() - invalid sessionId type');
|
||||
throw new Error('Invalid session ID');
|
||||
}
|
||||
|
||||
console.log('[DEBUG AUTH] validateSession() - executing query with sessionId:', sessionId);
|
||||
|
||||
try {
|
||||
const result = await query(
|
||||
'SELECT s.id, u.is_active FROM sessions s JOIN users u ON s.user_id = u.id WHERE s.id = $1 AND s.is_revoked = FALSE',
|
||||
[sessionId]
|
||||
);
|
||||
console.log('[DEBUG AUTH] validateSession() - query SUCCESS, rows:', result.rows.length);
|
||||
const result = await query(
|
||||
'SELECT s.id, u.is_active FROM sessions s JOIN users u ON s.user_id = u.id WHERE s.id = $1 AND s.is_revoked = FALSE',
|
||||
[sessionId]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
console.log('[DEBUG AUTH] validateSession() - session not found or revoked');
|
||||
throw new Error('Session not found or revoked');
|
||||
}
|
||||
if (result.rows.length === 0) {
|
||||
throw new Error('Session not found or revoked');
|
||||
}
|
||||
|
||||
console.log('[DEBUG AUTH] validateSession() - row data:', result.rows[0]);
|
||||
|
||||
if (!result.rows[0].is_active) {
|
||||
console.log('[DEBUG AUTH] validateSession() - user not active');
|
||||
throw new Error('User account is not active');
|
||||
}
|
||||
|
||||
console.log('[DEBUG AUTH] validateSession() SUCCESS');
|
||||
} catch (err) {
|
||||
console.error('[DEBUG AUTH] validateSession() ERROR:', err.message, err.code);
|
||||
throw err;
|
||||
if (!result.rows[0].is_active) {
|
||||
throw new Error('User account is not active');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
register,
|
||||
login,
|
||||
logout,
|
||||
newSession,
|
||||
validateSession
|
||||
}
|
||||
};
|
||||
|
||||
@@ -61,10 +61,13 @@ const authRateLimit = createRateLimiter(RATE_LIMIT_AUTH_MAX);
|
||||
app.use((req, res, next) => {
|
||||
res.setHeader('X-Content-Type-Options', 'nosniff');
|
||||
res.setHeader('X-Frame-Options', 'DENY');
|
||||
res.setHeader('X-XSS-Protection', '0'); // Disabilitato a favore di CSP
|
||||
res.setHeader('X-XSS-Protection', '0');
|
||||
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
|
||||
res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
|
||||
// Rimuovi header che rivelano info sul server
|
||||
res.setHeader(
|
||||
'Content-Security-Policy',
|
||||
"default-src 'self'; style-src 'self'; script-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'"
|
||||
);
|
||||
res.removeHeader('X-Powered-By');
|
||||
next();
|
||||
});
|
||||
@@ -134,11 +137,7 @@ app.use((req, res) => {
|
||||
|
||||
// ─── ERROR HANDLER GLOBALE ──────────────────────────────────────────
|
||||
app.use((err, req, res, _next) => {
|
||||
console.error('[ERROR HANDLER] Global error caught:');
|
||||
console.error('[ERROR HANDLER] Message:', err.message);
|
||||
console.error('[ERROR HANDLER] Code:', err.code);
|
||||
console.error('[ERROR HANDLER] Full error:', err);
|
||||
console.error('[ERROR HANDLER] Stack:', err.stack);
|
||||
console.error('[ERROR]', err.message, '| code:', err.code);
|
||||
res.status(500).json({ error: 'Errore interno del server' });
|
||||
});
|
||||
|
||||
|
||||
@@ -2,58 +2,32 @@ const jwt = require('../tools/jwt');
|
||||
const { validateSession } = require('../core/auth.core');
|
||||
|
||||
const userAuth = async (req, res, next) => {
|
||||
console.log('[DEBUG MIDDLEWARE] userAuth() START - path:', req.path);
|
||||
|
||||
const token = (req.cookies && req.cookies.auth_token) || jwt.getToken(req.headers['authorization']);
|
||||
console.log('[DEBUG MIDDLEWARE] token found:', !!token);
|
||||
|
||||
const redirectToLogin = () => {
|
||||
console.log('[DEBUG MIDDLEWARE] redirectToLogin()');
|
||||
const unauthorized = (reason) => {
|
||||
if (req.accepts('html')) {
|
||||
const redirect = encodeURIComponent(req.originalUrl);
|
||||
return res.redirect(`/login?redirect=${redirect}`);
|
||||
}
|
||||
return res.status(401).json({ error: 'Accesso negato: token mancante' });
|
||||
return res.status(401).json({ error: reason || 'Non autorizzato' });
|
||||
};
|
||||
|
||||
if (!token || typeof token !== 'string') {
|
||||
console.log('[DEBUG MIDDLEWARE] no token or invalid type');
|
||||
return redirectToLogin();
|
||||
}
|
||||
|
||||
if (token.length > 2048) {
|
||||
console.log('[DEBUG MIDDLEWARE] token too long');
|
||||
return redirectToLogin();
|
||||
if (!token || typeof token !== 'string' || token.length > 2048) {
|
||||
return unauthorized('Token mancante o non valido');
|
||||
}
|
||||
|
||||
const verified = jwt.verifyToken(token);
|
||||
console.log('[DEBUG MIDDLEWARE] jwt.verifyToken() result - valid:', verified.valid);
|
||||
|
||||
if (!verified.valid) {
|
||||
console.log('[DEBUG MIDDLEWARE] token not valid - reason:', verified.reason);
|
||||
if (req.accepts('html')) {
|
||||
return res.redirect('/login');
|
||||
}
|
||||
return res.status(401).json({
|
||||
error: 'Sessione non valida o scaduta',
|
||||
reason: verified.reason
|
||||
});
|
||||
return unauthorized(`Sessione non valida (${verified.reason})`);
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('[DEBUG MIDDLEWARE] calling validateSession() with session_id:', verified.payload.session_id);
|
||||
await validateSession(verified.payload.session_id);
|
||||
console.log('[DEBUG MIDDLEWARE] validateSession() SUCCESS');
|
||||
} catch (err) {
|
||||
console.error('[DEBUG MIDDLEWARE] validateSession() FAILED:', err.message);
|
||||
if (req.accepts('html')) {
|
||||
return res.redirect('/login');
|
||||
}
|
||||
return res.status(401).json({ error: 'Sessione non valida o revocata' });
|
||||
return unauthorized('Sessione non valida o revocata');
|
||||
}
|
||||
|
||||
req.user = verified.payload;
|
||||
console.log('[DEBUG MIDDLEWARE] auth SUCCESS - user_id:', req.user.user_id);
|
||||
next();
|
||||
};
|
||||
|
||||
|
||||
@@ -5,100 +5,93 @@ const jwt = require('../tools/jwt');
|
||||
const CONSOLE_URL = process.env.CONSOLE_URL || 'http://localhost:3004';
|
||||
const COOKIE_DOMAIN = process.env.COOKIE_DOMAIN || undefined;
|
||||
|
||||
// Validazione input
|
||||
const USERNAME_REGEX = /^[a-zA-Z0-9_.\-]{3,50}$/;
|
||||
const PASSWORD_MIN_LENGTH = 8;
|
||||
const PASSWORD_MAX_LENGTH = 128;
|
||||
|
||||
const ERROR_RESPONSES = {
|
||||
csrf: { success: false, error: 'csrf', message: 'Richiesta non valida, riprova' },
|
||||
invalid_credentials: { success: false, error: 'invalid_credentials', message: 'Credenziali non valide' },
|
||||
internal: { success: false, error: 'internal', message: 'Errore interno, riprova più tardi' }
|
||||
};
|
||||
|
||||
/**
|
||||
* Restituisce un redirect sicuro, scartando URL che puntano ad API
|
||||
* o ad host diversi da CONSOLE_URL.
|
||||
*/
|
||||
function resolveSafeRedirect(redirect) {
|
||||
if (!redirect || typeof redirect !== 'string') return CONSOLE_URL;
|
||||
|
||||
try {
|
||||
const redirectUrl = new URL(redirect);
|
||||
const consoleUrl = new URL(CONSOLE_URL);
|
||||
|
||||
const sameHost = redirectUrl.hostname === consoleUrl.hostname;
|
||||
const notApi = !redirectUrl.pathname.startsWith('/api/');
|
||||
|
||||
if (sameHost && notApi) return redirect;
|
||||
} catch {
|
||||
// URL non valido / relativo: fallback a CONSOLE_URL
|
||||
}
|
||||
|
||||
return CONSOLE_URL;
|
||||
}
|
||||
|
||||
router.post('/register', async (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password) {
|
||||
return res.status(400).json({ error: 'Username e password richiesti' });
|
||||
}
|
||||
|
||||
if (typeof username !== 'string' || typeof password !== 'string') {
|
||||
return res.status(400).json({ error: 'Formato dati non valido' });
|
||||
if (!username || !password || typeof username !== 'string' || typeof password !== 'string') {
|
||||
return res.status(400).json({ success: false, error: 'Username e password richiesti' });
|
||||
}
|
||||
|
||||
if (!USERNAME_REGEX.test(username)) {
|
||||
return res.status(400).json({
|
||||
error: 'Username non valido. 3-50 caratteri alfanumerici, underscore, punto o trattino.'
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Username non valido. 3-50 caratteri alfanumerici, underscore, punto o trattino.'
|
||||
});
|
||||
}
|
||||
|
||||
if (password.length < PASSWORD_MIN_LENGTH || password.length > PASSWORD_MAX_LENGTH) {
|
||||
return res.status(400).json({
|
||||
error: `Password deve essere tra ${PASSWORD_MIN_LENGTH} e ${PASSWORD_MAX_LENGTH} caratteri`
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: `Password deve essere tra ${PASSWORD_MIN_LENGTH} e ${PASSWORD_MAX_LENGTH} caratteri`
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await auth.register(username, password);
|
||||
res.status(201).end();
|
||||
return res.status(201).json({ success: true });
|
||||
} catch (err) {
|
||||
if (err.message === 'User already exists') {
|
||||
return res.status(409).json({ success: false, error: 'User already exists' });
|
||||
}
|
||||
console.error('[AUTH] Register failed:', err.message);
|
||||
const status = err.message === 'User already exists' ? 409 : 500;
|
||||
res.status(status).json({ error: err.message === 'User already exists' ? err.message : 'Errore interno' });
|
||||
return res.status(500).json({ success: false, error: 'Errore interno' });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/login', async (req, res) => {
|
||||
const { username, password, redirect, _csrf } = req.body;
|
||||
|
||||
console.log('[DEBUG ROUTES] POST /api/auth/login START - username:', username);
|
||||
|
||||
const ERROR_RESPONSES = {
|
||||
csrf: { success: false, error: 'csrf', message: 'Richiesta non valida, riprova' },
|
||||
invalid_credentials: { success: false, error: 'invalid_credentials', message: 'Credenziali non valide' },
|
||||
invalid_redirect: { success: false, error: 'invalid_redirect', message: 'Redirect non autorizzato' }
|
||||
};
|
||||
|
||||
// Validazione CSRF (double-submit cookie)
|
||||
const csrfCookie = req.cookies && req.cookies._csrf;
|
||||
if (!_csrf || !csrfCookie || _csrf !== csrfCookie) {
|
||||
console.log('[DEBUG ROUTES] CSRF validation failed');
|
||||
return res.status(400).json(ERROR_RESPONSES.csrf);
|
||||
}
|
||||
|
||||
// Validazione base
|
||||
if (!username || !password || typeof username !== 'string' || typeof password !== 'string') {
|
||||
console.log('[DEBUG ROUTES] Invalid credentials format');
|
||||
return res.status(400).json(ERROR_RESPONSES.invalid_credentials);
|
||||
}
|
||||
|
||||
// Limiti di lunghezza per prevenire abuse
|
||||
if (username.length > 50 || password.length > PASSWORD_MAX_LENGTH) {
|
||||
console.log('[DEBUG ROUTES] Input too long');
|
||||
return res.status(400).json(ERROR_RESPONSES.invalid_credentials);
|
||||
}
|
||||
|
||||
// Validazione redirect URL per prevenire open redirect attacks
|
||||
let safeRedirect = CONSOLE_URL;
|
||||
if (redirect && typeof redirect === 'string') {
|
||||
try {
|
||||
const redirectUrl = new URL(redirect);
|
||||
const consoleUrl = new URL(CONSOLE_URL);
|
||||
if (redirectUrl.hostname !== consoleUrl.hostname) {
|
||||
console.log('[DEBUG ROUTES] Invalid redirect hostname');
|
||||
return res.status(400).json(ERROR_RESPONSES.invalid_redirect);
|
||||
}
|
||||
safeRedirect = redirect;
|
||||
} catch {
|
||||
// URL relativo o non valido — usa CONSOLE_URL di default
|
||||
console.log('[DEBUG ROUTES] Redirect URL parse error, using default');
|
||||
}
|
||||
}
|
||||
const safeRedirect = resolveSafeRedirect(redirect);
|
||||
|
||||
try {
|
||||
const user = await auth.login(username, password);
|
||||
console.log('[DEBUG ROUTES] auth.login() success - user:', user);
|
||||
|
||||
const session = await auth.newSession(user.id, req.headers['user-agent'], req.ip);
|
||||
console.log('[DEBUG ROUTES] auth.newSession() success - session:', session);
|
||||
|
||||
const token = jwt.generateToken(user, session.id);
|
||||
console.log('[DEBUG ROUTES] jwt.generateToken() success');
|
||||
|
||||
const cookieOptions = {
|
||||
httpOnly: true,
|
||||
@@ -106,14 +99,10 @@ router.post('/login', async (req, res) => {
|
||||
sameSite: 'lax',
|
||||
maxAge: 7 * 24 * 60 * 60 * 1000
|
||||
};
|
||||
|
||||
if (COOKIE_DOMAIN) {
|
||||
cookieOptions.domain = COOKIE_DOMAIN;
|
||||
}
|
||||
if (COOKIE_DOMAIN) cookieOptions.domain = COOKIE_DOMAIN;
|
||||
|
||||
res.cookie('auth_token', token, cookieOptions);
|
||||
res.clearCookie('_csrf');
|
||||
console.log('[DEBUG ROUTES] cookies set - returning response with redirect_url:', safeRedirect);
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
@@ -121,8 +110,18 @@ router.post('/login', async (req, res) => {
|
||||
message: 'Login effettuato con successo'
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('[DEBUG ROUTES] Login FAILED:', err.message, err.code);
|
||||
return res.status(401).json(ERROR_RESPONSES.invalid_credentials);
|
||||
if (err.message === 'No user matched' || err.message === 'Password mismatch') {
|
||||
return res.status(401).json(ERROR_RESPONSES.invalid_credentials);
|
||||
}
|
||||
if (err.message === 'User account is not active') {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: 'account_inactive',
|
||||
message: 'Account disattivato'
|
||||
});
|
||||
}
|
||||
console.error('[AUTH] Login error:', err.message);
|
||||
return res.status(500).json(ERROR_RESPONSES.internal);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -141,12 +140,10 @@ router.post('/logout', async (req, res) => {
|
||||
}
|
||||
|
||||
const clearOptions = { httpOnly: true, sameSite: 'lax' };
|
||||
if (COOKIE_DOMAIN) {
|
||||
clearOptions.domain = COOKIE_DOMAIN;
|
||||
}
|
||||
if (COOKIE_DOMAIN) clearOptions.domain = COOKIE_DOMAIN;
|
||||
|
||||
res.clearCookie('auth_token', clearOptions);
|
||||
res.redirect('/login');
|
||||
return res.status(200).json({ success: true, redirect_url: '/login' });
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -5,74 +5,46 @@ const config = {
|
||||
password: process.env.DB_PASSWORD,
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
database: process.env.USERS_DB || process.env.DB_NAME,
|
||||
max: 10,
|
||||
idleTimeoutMillis: 30000,
|
||||
connectionTimeoutMillis: 5000
|
||||
}
|
||||
};
|
||||
|
||||
const pool = new Pool({ ...config, database: process.env.USERS_DB });
|
||||
const pool = new Pool(config);
|
||||
|
||||
pool.on('error', (err) => {
|
||||
console.error('Error in database', err);
|
||||
console.error('[DB] Pool error:', err.message);
|
||||
});
|
||||
|
||||
/**
|
||||
* Execute a query with parameters
|
||||
* @param {string} text - SQL query
|
||||
* @param {Array} params - Query parameters
|
||||
* @returns {Promise<Object>} Query result
|
||||
*/
|
||||
async function query(text, params) {
|
||||
const start = Date.now();
|
||||
console.log('[DEBUG DB] Executing query:', text.substring(0, 120));
|
||||
if (params && params.length > 0) {
|
||||
console.log('[DEBUG DB] Parameters:', params);
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await pool.query(text, params);
|
||||
const duration = Date.now() - start;
|
||||
|
||||
if (duration > 100) {
|
||||
console.warn(`[DB] Slow query (${duration}ms):`, text.substring(0, 80));
|
||||
}
|
||||
|
||||
console.log('[DEBUG DB] Query successful - rows:', result.rowCount, 'duration:', duration + 'ms');
|
||||
return result;
|
||||
} catch (err) {
|
||||
const duration = Date.now() - start;
|
||||
console.error('[DEBUG DB] Query FAILED:', err.message);
|
||||
console.error('[DEBUG DB] Error code:', err.code);
|
||||
console.error('[DEBUG DB] Query:', text.substring(0, 120));
|
||||
console.error('[DEBUG DB] Duration:', duration + 'ms');
|
||||
console.error('[DEBUG DB] Full error:', err);
|
||||
console.error('[DB] Query failed:', err.message, '| code:', err.code);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a client from pool for transactions
|
||||
* @returns {Promise<Object>} Pool client
|
||||
*/
|
||||
async function getClient() {
|
||||
return await pool.connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize database and ensure tables exist
|
||||
*/
|
||||
async function initDb() {
|
||||
// Test connection
|
||||
await pool.query('SELECT NOW()');
|
||||
// Ensure pgcrypto extension (provides gen_random_uuid)
|
||||
// Note: creating extensions requires proper DB permissions (usually superuser in PG)
|
||||
|
||||
try {
|
||||
await pool.query(`CREATE EXTENSION IF NOT EXISTS pgcrypto;`);
|
||||
} catch (err) {
|
||||
console.warn('[DB] Could not create pgcrypto extension (may require superuser):', err.message);
|
||||
console.warn('[DB] Could not create pgcrypto extension:', err.message);
|
||||
}
|
||||
|
||||
// Ensure tables exist (UUID default generated by DB)
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
@@ -92,7 +64,7 @@ async function initDb() {
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
session_code VARCHAR(64) NOT NULL,
|
||||
encoded_username TEXT NOT NULL,
|
||||
encoded_username TEXT NOT NULL DEFAULT '',
|
||||
ip_address INET,
|
||||
user_agent TEXT,
|
||||
browser VARCHAR(100),
|
||||
@@ -105,9 +77,6 @@ async function initDb() {
|
||||
is_revoked BOOLEAN DEFAULT FALSE
|
||||
);
|
||||
|
||||
-- Altera colonna in base al nuovo standard token 32 byte - 64 url chars
|
||||
ALTER TABLE sessions ALTER COLUMN session_code TYPE VARCHAR(64);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_sessions_code ON sessions(session_code);
|
||||
CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);
|
||||
`);
|
||||
@@ -117,7 +86,7 @@ async function checkPostgres() {
|
||||
try {
|
||||
await pool.query('SELECT NOW()');
|
||||
return true;
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
const formData = new FormData(form);
|
||||
|
||||
try {
|
||||
console.log('[LOGIN] Sending login request...');
|
||||
const response = await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -67,14 +66,11 @@
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
console.log('[LOGIN] Response:', data);
|
||||
const data = await response.json().catch(() => ({}));
|
||||
|
||||
if (data.success) {
|
||||
console.log('[LOGIN] Login successful, redirecting to:', data.redirect_url);
|
||||
if (response.ok && data.success && data.redirect_url) {
|
||||
window.location.href = data.redirect_url;
|
||||
} else {
|
||||
console.log('[LOGIN] Login failed:', data.error);
|
||||
const errorMsg = data.message || 'Errore durante il login';
|
||||
|
||||
if (errorMessage) {
|
||||
@@ -93,7 +89,6 @@
|
||||
}, 2000);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[LOGIN] Error:', err);
|
||||
const errorMsg = 'Errore di connessione. Riprova più tardi.';
|
||||
|
||||
if (errorMessage) {
|
||||
|
||||
Reference in New Issue
Block a user