makerstash/server/routes/auth.js

246 lines
6.6 KiB
JavaScript

import express from 'express';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import db from '../database.js';
import { authenticateToken } from '../middleware/auth.js';
const router = express.Router();
// Register new user
router.post('/register', async (req, res) => {
const { username, email, password } = req.body;
if (!username || !email || !password) {
return res.status(400).json({ error: 'Username, email, and password are required' });
}
if (password.length < 6) {
return res.status(400).json({ error: 'Password must be at least 6 characters long' });
}
try {
const hashedPassword = await bcrypt.hash(password, 10);
const query = 'INSERT INTO users (username, email, password_hash) VALUES (?, ?, ?)';
db.run(query, [username, email, hashedPassword], function (err) {
if (err) {
if (err.message.includes('UNIQUE')) {
return res.status(400).json({ error: 'Username or email already exists' });
}
return res.status(500).json({ error: err.message });
}
const token = jwt.sign(
{ id: this.lastID, username, email },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
res.status(201).json({
message: 'User registered successfully',
token,
user: {
id: this.lastID,
username,
email
}
});
});
} catch (error) {
res.status(500).json({ error: 'Error hashing password' });
}
});
// Login
router.post('/login', (req, res) => {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({ error: 'Username and password are required' });
}
const query = 'SELECT * FROM users WHERE username = ?';
db.get(query, [username], async (err, user) => {
if (err) {
return res.status(500).json({ error: err.message });
}
if (!user) {
return res.status(401).json({ error: 'Invalid username or password' });
}
try {
const validPassword = await bcrypt.compare(password, user.password_hash);
if (!validPassword) {
return res.status(401).json({ error: 'Invalid username or password' });
}
const token = jwt.sign(
{ id: user.id, username: user.username, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
res.json({
message: 'Login successful',
token,
user: {
id: user.id,
username: user.username,
email: user.email
}
});
} catch (error) {
res.status(500).json({ error: 'Error verifying password' });
}
});
});
// Get current user
router.get('/me', authenticateToken, (req, res) => {
const query = 'SELECT id, username, email, theme, created_at FROM users WHERE id = ?';
db.get(query, [req.user.id], (err, user) => {
if (err) {
return res.status(500).json({ error: err.message });
}
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json({ user });
});
});
// Update user theme preference
router.put('/me/theme', authenticateToken, (req, res) => {
const { theme } = req.body;
if (!['light', 'dark'].includes(theme)) {
return res.status(400).json({ error: 'Theme must be "light" or "dark"' });
}
const query = 'UPDATE users SET theme = ? WHERE id = ?';
db.run(query, [theme, req.user.id], (err) => {
if (err) {
return res.status(500).json({ error: err.message });
}
res.json({ message: 'Theme updated', theme });
});
});
// Update user email
router.put('/me/email', authenticateToken, async (req, res) => {
const { newEmail, password } = req.body;
if (!newEmail || !password) {
return res.status(400).json({ error: 'New email and password are required' });
}
try {
// Get current user
const userQuery = 'SELECT * FROM users WHERE id = ?';
db.get(userQuery, [req.user.id], async (err, user) => {
if (err) {
return res.status(500).json({ error: err.message });
}
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
// Verify password
const validPassword = await bcrypt.compare(password, user.password_hash);
if (!validPassword) {
return res.status(401).json({ error: 'Invalid password' });
}
// Check if email already exists
const emailCheckQuery = 'SELECT id FROM users WHERE email = ? AND id != ?';
db.get(emailCheckQuery, [newEmail, req.user.id], (err, existingUser) => {
if (err) {
return res.status(500).json({ error: err.message });
}
if (existingUser) {
return res.status(400).json({ error: 'Email already in use' });
}
// Update email
const updateQuery = 'UPDATE users SET email = ? WHERE id = ?';
db.run(updateQuery, [newEmail, req.user.id], (err) => {
if (err) {
return res.status(500).json({ error: err.message });
}
res.json({ message: 'Email updated successfully', email: newEmail });
});
});
});
} catch (error) {
res.status(500).json({ error: 'Error updating email' });
}
});
// Update user password
router.put('/me/password', authenticateToken, async (req, res) => {
const { currentPassword, newPassword } = req.body;
if (!currentPassword || !newPassword) {
return res.status(400).json({ error: 'Current and new password are required' });
}
if (newPassword.length < 6) {
return res.status(400).json({ error: 'New password must be at least 6 characters long' });
}
try {
// Get current user
const userQuery = 'SELECT * FROM users WHERE id = ?';
db.get(userQuery, [req.user.id], async (err, user) => {
if (err) {
return res.status(500).json({ error: err.message });
}
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
// Verify current password
const validPassword = await bcrypt.compare(currentPassword, user.password_hash);
if (!validPassword) {
return res.status(401).json({ error: 'Invalid current password' });
}
// Hash new password
const hashedPassword = await bcrypt.hash(newPassword, 10);
// Update password
const updateQuery = 'UPDATE users SET password_hash = ? WHERE id = ?';
db.run(updateQuery, [hashedPassword, req.user.id], (err) => {
if (err) {
return res.status(500).json({ error: err.message });
}
res.json({ message: 'Password updated successfully' });
});
});
} catch (error) {
res.status(500).json({ error: 'Error updating password' });
}
});
export default router;