const express = require('express'); const router = express.Router(); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const crypto = require('crypto'); const { Pool } = require('pg'); const { sendMail } = require('../utils/emailService'); const pgPool = new Pool({ host: process.env.PGHOST || 'postgres', port: process.env.PGPORT || 5432, user: process.env.PGUSER || 'postgres', password: process.env.PGPASSWORD || 'postgres', database: process.env.PGDATABASE || 'ckqr', }); const JWT_SECRET = process.env.JWT_SECRET || 'supersecret123'; // Register router.post('/register', async (req, res) => { const { email, password } = req.body; if (!email || !password) return res.status(400).json({ error: 'Email and password required' }); try { const checkUser = await pgPool.query('SELECT id FROM users WHERE email = $1', [email]); if (checkUser.rows.length > 0) return res.status(400).json({ error: 'User already exists' }); const countQuery = await pgPool.query('SELECT COUNT(*) FROM users'); const userCount = parseInt(countQuery.rows[0].count, 10); const assignedRole = userCount === 0 ? 'enterprise' : 'free_trial'; const salt = await bcrypt.genSalt(10); const hash = await bcrypt.hash(password, salt); const newUser = await pgPool.query( 'INSERT INTO users (email, password_hash, role) VALUES ($1, $2, $3) RETURNING id, email, role', [email, hash, assignedRole] ); const userId = newUser.rows[0].id; const userEmail = newUser.rows[0].email; // Auto send verification email const tokenStr = crypto.randomBytes(32).toString('hex'); await pgPool.query('UPDATE users SET email_verification_token = $1 WHERE id = $2', [tokenStr, userId]); const baseUrl = process.env.FRONTEND_URL || 'https://qr.houseofwebsites.ai'; const verifyLink = `${baseUrl}/verify-email?token=${tokenStr}`; const html = `

Verify Your Email

Thanks for registering for CK-QR! Please verify your email address to unlock your dashboard features.

Verify Email

Or copy and paste this link:
${verifyLink}

`; // Send email asynchronously without blocking registration response sendMail(userEmail, 'Verify your CK-QR account', html).catch(e => console.error('Failed to send auto-verify email:', e)); const token = jwt.sign({ id: userId, email: userEmail, role: newUser.rows[0].role }, JWT_SECRET, { expiresIn: '14d' }); res.cookie('token', token, { httpOnly: true, maxAge: 14 * 24 * 60 * 60 * 1000, secure: false, sameSite: 'lax' }); res.status(201).json({ message: 'User registered', user: newUser.rows[0] }); } catch (err) { console.error(err); res.status(500).json({ error: 'Server error' }); } }); // Login router.post('/login', async (req, res) => { const { email, password } = req.body; if (!email || !password) return res.status(400).json({ error: 'Email and password required' }); try { const userQuery = await pgPool.query('SELECT * FROM users WHERE email = $1', [email]); if (userQuery.rows.length === 0) return res.status(404).json({ error: 'User not found' }); const user = userQuery.rows[0]; const isMatch = await bcrypt.compare(password, user.password_hash); if (!isMatch) return res.status(401).json({ error: 'Invalid credentials' }); const token = jwt.sign({ id: user.id, email: user.email, role: user.role }, JWT_SECRET, { expiresIn: '14d' }); res.cookie('token', token, { httpOnly: true, maxAge: 14 * 24 * 60 * 60 * 1000, secure: false, sameSite: 'lax' }); res.json({ user: { id: user.id, email: user.email, role: user.role } }); } catch (err) { console.error(err); res.status(500).json({ error: 'Server error' }); } }); // Get Current User (Validate Session) const { verifyToken } = require('../middleware/auth'); router.get('/me', verifyToken, async (req, res) => { try { const userQuery = await pgPool.query('SELECT id, email, role, is_email_verified FROM users WHERE id = $1', [req.user.id]); if (userQuery.rows.length === 0) return res.status(404).json({ error: 'User not found' }); res.json({ user: userQuery.rows[0] }); } catch (err) { console.error(err); res.status(500).json({ error: 'Server error' }); } }); // Send Verification Email router.post('/send-verification', verifyToken, async (req, res) => { try { const userQuery = await pgPool.query('SELECT email, is_email_verified FROM users WHERE id = $1', [req.user.id]); if (userQuery.rows.length === 0) return res.status(404).json({ error: 'User not found' }); const user = userQuery.rows[0]; if (user.is_email_verified) { return res.status(400).json({ error: 'Email is already verified' }); } const token = crypto.randomBytes(32).toString('hex'); await pgPool.query('UPDATE users SET email_verification_token = $1 WHERE id = $2', [token, req.user.id]); const baseUrl = process.env.FRONTEND_URL || 'https://qr.houseofwebsites.ai'; const verifyLink = `${baseUrl}/verify-email?token=${token}`; const html = `

Verify Your Email

Thanks for using CK-QR! Please verify your email address to unlock Pro tier upgrades.

Verify Email

Or copy and paste this link:
${verifyLink}

`; await sendMail(user.email, 'Verify your CK-QR account', html); res.json({ message: 'Verification email sent' }); } catch (err) { console.error(err); res.status(500).json({ error: 'Failed to send verification email' }); } }); // Verify Email Token router.get('/verify-email/:token', async (req, res) => { const { token } = req.params; if (!token) return res.status(400).json({ error: 'Token is required' }); try { const result = await pgPool.query( 'UPDATE users SET is_email_verified = true, email_verification_token = NULL WHERE email_verification_token = $1 RETURNING id, email', [token] ); if (result.rows.length === 0) { return res.status(400).json({ error: 'Invalid or expired token' }); } res.json({ message: 'Email verified successfully!' }); } catch (err) { console.error(err); res.status(500).json({ error: 'Server error during verification' }); } }); // Logout router.post('/logout', (req, res) => { res.clearCookie('token'); res.json({ message: 'Logged out' }); }); module.exports = router;