Update package version to 1.1.3, add new dependencies for authentication and database management, and implement user authentication features including registration and login. Enhance API routes for protected access and integrate WebSocket authentication.

This commit is contained in:
simos
2025-07-09 18:25:58 +00:00
parent b27702797f
commit ec9ff3336a
21 changed files with 2670 additions and 91 deletions

125
server/routes/auth.js Normal file
View File

@@ -0,0 +1,125 @@
const express = require('express');
const bcrypt = require('bcrypt');
const { userDb } = require('../database/db');
const { generateToken, authenticateToken } = require('../middleware/auth');
const router = express.Router();
// Check auth status and setup requirements
router.get('/status', async (req, res) => {
try {
const hasUsers = await userDb.hasUsers();
res.json({
needsSetup: !hasUsers,
isAuthenticated: false // Will be overridden by frontend if token exists
});
} catch (error) {
console.error('Auth status error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// User registration (setup) - only allowed if no users exist
router.post('/register', async (req, res) => {
try {
const { username, password } = req.body;
// Validate input
if (!username || !password) {
return res.status(400).json({ error: 'Username and password are required' });
}
if (username.length < 3 || password.length < 6) {
return res.status(400).json({ error: 'Username must be at least 3 characters, password at least 6 characters' });
}
// Check if users already exist (only allow one user)
const hasUsers = await userDb.hasUsers();
if (hasUsers) {
return res.status(403).json({ error: 'User already exists. This is a single-user system.' });
}
// Hash password
const saltRounds = 12;
const passwordHash = await bcrypt.hash(password, saltRounds);
// Create user
const user = await userDb.createUser(username, passwordHash);
// Generate token
const token = generateToken(user);
// Update last login
await userDb.updateLastLogin(user.id);
res.json({
success: true,
user: { id: user.id, username: user.username },
token
});
} catch (error) {
console.error('Registration error:', error);
if (error.code === 'SQLITE_CONSTRAINT_UNIQUE') {
res.status(409).json({ error: 'Username already exists' });
} else {
res.status(500).json({ error: 'Internal server error' });
}
}
});
// User login
router.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
// Validate input
if (!username || !password) {
return res.status(400).json({ error: 'Username and password are required' });
}
// Get user from database
const user = await userDb.getUserByUsername(username);
if (!user) {
return res.status(401).json({ error: 'Invalid username or password' });
}
// Verify password
const isValidPassword = await bcrypt.compare(password, user.password_hash);
if (!isValidPassword) {
return res.status(401).json({ error: 'Invalid username or password' });
}
// Generate token
const token = generateToken(user);
// Update last login
await userDb.updateLastLogin(user.id);
res.json({
success: true,
user: { id: user.id, username: user.username },
token
});
} catch (error) {
console.error('Login error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Get current user (protected route)
router.get('/user', authenticateToken, (req, res) => {
res.json({
user: req.user
});
});
// Logout (client-side token removal, but this endpoint can be used for logging)
router.post('/logout', authenticateToken, (req, res) => {
// In a simple JWT system, logout is mainly client-side
// This endpoint exists for consistency and potential future logging
res.json({ success: true, message: 'Logged out successfully' });
});
module.exports = router;