123 lines
3.7 KiB
JavaScript
123 lines
3.7 KiB
JavaScript
import express from 'express';
|
|
import helmet from 'helmet';
|
|
import cors from 'cors';
|
|
import rateLimit from 'express-rate-limit';
|
|
import { initDb, getAllCars, addCar, updateCar, deleteCar, replaceAllCars, verifyPassword } from './db.js';
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname, join } from 'path';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 3456;
|
|
|
|
app.use(helmet({
|
|
contentSecurityPolicy: {
|
|
directives: {
|
|
defaultSrc: ["'self'"],
|
|
scriptSrc: ["'self'"],
|
|
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
|
|
fontSrc: ["'self'", "https://fonts.gstatic.com", "data:"],
|
|
imgSrc: ["'self'", "data:", "blob:"],
|
|
connectSrc: ["'self'"],
|
|
},
|
|
},
|
|
}));
|
|
app.use(cors());
|
|
app.use(express.json({ limit: '1mb' }));
|
|
|
|
const apiLimiter = rateLimit({
|
|
windowMs: 15 * 60 * 1000,
|
|
max: 200,
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
});
|
|
app.use('/api/', apiLimiter);
|
|
|
|
const authLimiter = rateLimit({
|
|
windowMs: 15 * 60 * 1000,
|
|
max: 10,
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
});
|
|
|
|
initDb();
|
|
|
|
// Serve static frontend files
|
|
const distPath = join(__dirname, '..', 'dist');
|
|
app.use(express.static(distPath));
|
|
|
|
// API routes
|
|
app.get('/api/cars', (_req, res) => {
|
|
const cars = getAllCars();
|
|
res.json(cars);
|
|
});
|
|
|
|
app.post('/api/cars', (req, res) => {
|
|
const { name, width, height, rearWidth, rearHeight } = req.body;
|
|
if (!name || typeof width !== 'number' || typeof height !== 'number') {
|
|
return res.status(400).json({ error: 'name, width en height zijn verplicht' });
|
|
}
|
|
if (width <= 0 || height <= 0) {
|
|
return res.status(400).json({ error: 'width en height moeten positief zijn' });
|
|
}
|
|
if (rearWidth !== undefined && (typeof rearWidth !== 'number' || rearWidth <= 0)) {
|
|
return res.status(400).json({ error: 'rearWidth moet een positief getal zijn' });
|
|
}
|
|
if (rearHeight !== undefined && (typeof rearHeight !== 'number' || rearHeight <= 0)) {
|
|
return res.status(400).json({ error: 'rearHeight moet een positief getal zijn' });
|
|
}
|
|
const car = addCar({ name: String(name).trim(), width, height, rearWidth: rearWidth || null, rearHeight: rearHeight || null });
|
|
res.status(201).json(car);
|
|
});
|
|
|
|
app.put('/api/cars/:id', (req, res) => {
|
|
const id = parseInt(req.params.id, 10);
|
|
const { name, width, height, rearWidth, rearHeight } = req.body;
|
|
if (!name || typeof width !== 'number' || typeof height !== 'number') {
|
|
return res.status(400).json({ error: 'name, width en height zijn verplicht' });
|
|
}
|
|
const car = updateCar(id, { name: String(name).trim(), width, height, rearWidth: rearWidth || null, rearHeight: rearHeight || null });
|
|
if (!car) {
|
|
return res.status(404).json({ error: 'Auto niet gevonden' });
|
|
}
|
|
res.json(car);
|
|
});
|
|
|
|
app.delete('/api/cars/:id', (req, res) => {
|
|
const id = parseInt(req.params.id, 10);
|
|
const deleted = deleteCar(id);
|
|
if (!deleted) {
|
|
return res.status(404).json({ error: 'Auto niet gevonden' });
|
|
}
|
|
res.json({ success: true });
|
|
});
|
|
|
|
app.put('/api/cars', (req, res) => {
|
|
const cars = req.body;
|
|
if (!Array.isArray(cars)) {
|
|
return res.status(400).json({ error: 'Array van auto\'s verwacht' });
|
|
}
|
|
replaceAllCars(cars);
|
|
res.json(getAllCars());
|
|
});
|
|
|
|
app.post('/api/auth/verify', authLimiter, (req, res) => {
|
|
const { password } = req.body;
|
|
if (!password) {
|
|
return res.status(400).json({ error: 'Wachtwoord is verplicht' });
|
|
}
|
|
const valid = verifyPassword(password);
|
|
res.json({ authenticated: valid });
|
|
});
|
|
|
|
// SPA fallback - serve index.html for all non-API routes
|
|
app.get('*', (_req, res) => {
|
|
res.sendFile(join(distPath, 'index.html'));
|
|
});
|
|
|
|
app.listen(PORT, '127.0.0.1', () => {
|
|
console.log(`Kenteken Gen server draait op poort ${PORT}`);
|
|
});
|