if (process.stdout._handle && typeof process.stdout._handle.setBlocking === 'function') { process.stdout._handle.setBlocking(true); } if (process.stderr._handle && typeof process.stderr._handle.setBlocking === 'function') { process.stderr._handle.setBlocking(true); } const express = require('express'); const cors = require('cors'); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const pool = require('./db'); require('dotenv').config(); const app = express(); const PORT = process.env.PORT || 5000; app.use(cors()); app.use(express.json()); // Request logger middleware app.use((req, res, next) => { console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`); if (req.body && Object.keys(req.body).length > 0) { const logBody = { ...req.body }; if (logBody.password) logBody.password = '[REDACTED]'; console.log(' Body:', JSON.stringify(logBody)); } next(); }); // Middleware to verify JWT token const authenticateToken = (req, res, next) => { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; if (!token) return res.status(401).json({ error: 'No token provided' }); jwt.verify(token, process.env.JWT_SECRET || 'fallback_secret', (err, user) => { if (err) return res.status(403).json({ error: 'Invalid token' }); req.user = user; next(); }); }; // Registration app.post('/api/register', async (req, res) => { try { const { username, email, password } = req.body; if (!username || !email || !password) { return res.status(400).json({ error: 'All fields are required' }); } // Check if user exists const userExists = await pool.query('SELECT * FROM users WHERE email = $1 OR username = $2', [email, username]); if (userExists.rows.length > 0) { return res.status(400).json({ error: 'User already exists' }); } // Hash password const salt = await bcrypt.genSalt(10); const passwordHash = await bcrypt.hash(password, salt); // Save to DB const newUser = await pool.query( 'INSERT INTO users (username, email, password_hash) VALUES ($1, $2, $3) RETURNING id, username, email', [username, email, passwordHash] ); res.status(201).json({ message: 'Registration successful', user: newUser.rows[0] }); } catch (err) { console.error(err); res.status(500).json({ error: 'Server error' }); } }); // Login app.post('/api/login', async (req, res) => { try { const { email, password } = req.body; if (!email || !password) { return res.status(400).json({ error: 'Email and password are required' }); } // Find user const user = await pool.query('SELECT * FROM users WHERE email = $1', [email]); if (user.rows.length === 0) { return res.status(400).json({ error: 'Invalid credentials' }); } // Check password const validPassword = await bcrypt.compare(password, user.rows[0].password_hash); if (!validPassword) { return res.status(400).json({ error: 'Invalid credentials' }); } // Create token const token = jwt.sign( { id: user.rows[0].id, username: user.rows[0].username }, process.env.JWT_SECRET || 'fallback_secret', { expiresIn: '24h' } ); res.json({ token, user: { id: user.rows[0].id, username: user.rows[0].username, email: user.rows[0].email } }); } catch (err) { console.error(err); res.status(500).json({ error: 'Server error' }); } }); // Get user profile (protected route) app.get('/api/profile', authenticateToken, async (req, res) => { try { const user = await pool.query('SELECT id, username, email, created_at FROM users WHERE id = $1', [req.user.id]); if (user.rows.length === 0) { return res.status(404).json({ error: 'User not found' }); } res.json(user.rows[0]); } catch (err) { console.error(err); res.status(500).json({ error: 'Server error' }); } }); // Verify token app.post('/api/verify-token', authenticateToken, (req, res) => { res.json({ valid: true, user: req.user }); }); app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });