const jwt = require('jsonwebtoken'); const crypto = require('crypto'); const { APP_URL, JWT_REFRESH_SECRET, USERS } = require('./env'); const { sequelize, getUserIdByEmail, getPendingOtp } = require('./db'); /** Build the cookie jar for context.addCookies() from a refresh token. */ function buildCookies(refreshToken, csrfToken = 'e2e-csrf') { return [ { name: 'refreshToken', value: refreshToken, domain: 'localhost', path: '/', httpOnly: true, secure: false, sameSite: 'Lax' }, { name: 'csrfToken', value: csrfToken, domain: 'localhost', path: '/', httpOnly: false, secure: false, sameSite: 'Lax' }, { name: 'sidebar_state', value: 'false', domain: 'localhost', path: '/', httpOnly: false, secure: false, sameSite: 'Lax' }, ]; } /** * Generate a fresh refresh token + DB session row for a client user, keyed * by email (not a hardcoded user_id — those drift as test accounts get * recreated, see chibistar/automation/starr/config.cjs history). */ async function generateClientSession(email) { const user_id = await getUserIdByEmail(email); const refreshToken = jwt.sign({ user_id }, JWT_REFRESH_SECRET, { expiresIn: '7d' }); const tokenHash = crypto.createHash('sha256').update(refreshToken).digest('hex'); await sequelize.query( `INSERT INTO user_sessions (user_id, refresh_token_hash, is_active, login_info, "createdAt", "updatedAt") VALUES (:uid, :hash, true, '{}', NOW(), NOW())`, { replacements: { uid: user_id, hash: tokenHash }, type: sequelize.QueryTypes.INSERT }, ); return { user_id, refreshToken }; } /** * Authenticate as admin via cookie injection (same mechanism as * generateClientSession), not the UI login form. * * REAL FINDING (2026-08-25): the admin account (k80308392@gmail.com) is * Google-OAuth-only now — submitting the UI email/password form returns * "Login failed — Please log in with Google." This matches a prior finding * that the *live*-domain admin session had gone Google-only, but it turns * out to be true here against localhost too, so the email+password+OTP flow * this helper originally ported from chibistar/automation/starr/config.cjs * (loginAsAdmin) is dead — forging the session cookie is the only way in now. */ async function loginAsAdmin(page) { const { refreshToken } = await generateClientSession(USERS.admin.email); await page.context().addCookies(buildCookies(refreshToken)); await page.goto(`${APP_URL}/admin`, { waitUntil: 'networkidle' }); if (/\/login/.test(page.url())) { throw new Error('Cookie-based admin auth bounced to /login — check JWT_REFRESH_SECRET / user_sessions wiring.'); } } module.exports = { buildCookies, generateClientSession, loginAsAdmin };