helpyourneighbour/backend/routes/auth.js
BibaBot Jarvis 7c9862a08a
Some checks are pending
Docker Test / test (push) Waiting to run
feat: implement role-based access control and auth routes
2026-03-16 00:07:16 +00:00

309 lines
No EOL
8.2 KiB
JavaScript

// routes/auth.js
const express = require('express');
const router = express.Router();
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const db = require('../db');
const requireRole = require('../middleware/requireRole');
/**
* @swagger
* /auth/register:
* post:
* summary: Registriert einen neuen Benutzer
* tags: [Auth]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - username
* - email
* - password
* properties:
* username:
* type: string
* email:
* type: string
* password:
* type: string
* responses:
* 201:
* description: Benutzer erfolgreich registriert
* content:
* application/json:
* schema:
* type: object
* properties:
* user:
* type: object
* properties:
* id:
* type: integer
* username:
* type: string
* email:
* type: string
* role:
* type: string
* token:
* type: string
* 400:
* description: Ungültige Eingabedaten
* 409:
* description: Benutzer existiert bereits
*/
router.post('/register', async (req, res) => {
const { username, email, password } = req.body;
if (!username || !email || !password) {
return res.status(400).json({ error: 'Missing required fields' });
}
try {
// Prüfen, ob Benutzer bereits existiert
const existingUser = await db.get('SELECT id FROM users WHERE email = ?', [email]);
if (existingUser) {
return res.status(409).json({ error: 'User already exists' });
}
// Passwort hashen
const hashedPassword = await bcrypt.hash(password, 10);
// Neuen Benutzer anlegen
const result = await db.run(
'INSERT INTO users (username, email, password_hash, role) VALUES (?, ?, ?, ?)',
[username, email, hashedPassword, 'user']
);
// Token generieren
const token = jwt.sign(
{ id: result.lastID, username, email, role: 'user' },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
res.status(201).json({
user: {
id: result.lastID,
username,
email,
role: 'user'
},
token
});
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});
/**
* @swagger
* /auth/login:
* post:
* summary: Loggt einen Benutzer ein
* tags: [Auth]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - email
* - password
* properties:
* email:
* type: string
* password:
* type: string
* responses:
* 200:
* description: Login erfolgreich
* content:
* application/json:
* schema:
* type: object
* properties:
* user:
* type: object
* properties:
* id:
* type: integer
* username:
* type: string
* email:
* type: string
* role:
* type: string
* token:
* type: string
* 400:
* description: Ungültige Eingabedaten
* 401:
* description: Falsche Anmeldedaten
*/
router.post('/login', async (req, res) => {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ error: 'Missing email or password' });
}
try {
const user = await db.get('SELECT id, username, email, password_hash, role FROM users WHERE email = ?', [email]);
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const isValidPassword = await bcrypt.compare(password, user.password_hash);
if (!isValidPassword) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Token generieren
const token = jwt.sign(
{ id: user.id, username: user.username, email: user.email, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
res.json({
user: {
id: user.id,
username: user.username,
email: user.email,
role: user.role
},
token
});
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});
/**
* @swagger
* /auth/profile:
* get:
* summary: Holt das Profil des eingeloggten Benutzers
* tags: [Auth]
* security:
* - bearerAuth: []
* responses:
* 200:
* description: Profil erfolgreich abgerufen
* content:
* application/json:
* schema:
* type: object
* properties:
* user:
* type: object
* properties:
* id:
* type: integer
* username:
* type: string
* email:
* type: string
* role:
* type: string
* 401:
* description: Nicht autorisiert
*/
router.get('/profile', requireRole(['user', 'moderator', 'admin']), async (req, res) => {
try {
const user = await db.get('SELECT id, username, email, role FROM users WHERE id = ?', [req.user.id]);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json({ user });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});
/**
* @swagger
* /auth/profile:
* put:
* summary: Aktualisiert das Profil des eingeloggten Benutzers
* tags: [Auth]
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* username:
* type: string
* email:
* type: string
* responses:
* 200:
* description: Profil erfolgreich aktualisiert
* content:
* application/json:
* schema:
* type: object
* properties:
* user:
* type: object
* properties:
* id:
* type: integer
* username:
* type: string
* email:
* type: string
* role:
* type: string
* 400:
* description: Ungültige Eingabedaten
* 401:
* description: Nicht autorisiert
*/
router.put('/profile', requireRole(['user', 'moderator', 'admin']), async (req, res) => {
const { username, email } = req.body;
if (!username && !email) {
return res.status(400).json({ error: 'At least one field must be provided' });
}
try {
let updateFields = [];
let values = [];
if (username) {
updateFields.push('username = ?');
values.push(username);
}
if (email) {
updateFields.push('email = ?');
values.push(email);
}
values.push(req.user.id);
const query = `UPDATE users SET ${updateFields.join(', ')} WHERE id = ?`;
await db.run(query, values);
// Aktualisierte Daten abrufen
const updatedUser = await db.get('SELECT id, username, email, role FROM users WHERE id = ?', [req.user.id]);
res.json({ user: updatedUser });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});
module.exports = router;