Files
BrewJournal/server/index.js
2026-06-06 08:59:18 +05:30

135 lines
4.1 KiB
JavaScript

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}`);
});