| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- import express from 'express';
- import bcrypt from 'bcrypt';
- import { userDb, db } from '../database/db.js';
- import { generateToken, authenticateToken } from '../middleware/auth.js';
- import { DISABLE_LOCAL_AUTH } from '../constants/config.js';
- const router = express.Router();
- // Check auth status and setup requirements
- router.get('/status', async (req, res) => {
- try {
- if (DISABLE_LOCAL_AUTH) {
- return res.json({
- needsSetup: false,
- isAuthenticated: true,
- authDisabled: true,
- });
- }
- 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 {
- if (DISABLE_LOCAL_AUTH) {
- return res.status(403).json({ error: 'Registration is disabled (PILOTDECK_DISABLE_LOCAL_AUTH)' });
- }
- 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' });
- }
-
- // Use a transaction to prevent race conditions
- db.prepare('BEGIN').run();
- try {
- // Check if users already exist (only allow one user)
- const hasUsers = userDb.hasUsers();
- if (hasUsers) {
- db.prepare('ROLLBACK').run();
- 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 = userDb.createUser(username, passwordHash);
-
- // Generate token
- const token = generateToken(user);
-
- db.prepare('COMMIT').run();
- // Update last login (non-fatal, outside transaction)
- userDb.updateLastLogin(user.id);
- res.json({
- success: true,
- user: { id: user.id, username: user.username },
- token
- });
- } catch (error) {
- db.prepare('ROLLBACK').run();
- throw error;
- }
-
- } 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 {
- if (DISABLE_LOCAL_AUTH) {
- return res.status(403).json({ error: 'Login is disabled (PILOTDECK_DISABLE_LOCAL_AUTH)' });
- }
- 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 = 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
- 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' });
- });
- export default router;
|