updated features

This commit is contained in:
2026-02-07 09:05:22 +01:00
parent a1e41a7692
commit d83a3e0542
2 changed files with 179 additions and 53 deletions
+52 -16
View File
@@ -10,13 +10,13 @@ const DB_PATH = process.env.DB_PATH || '/data/revfulop.db';
// Simple auth config (set SIMPLE_AUTH_PASSWORD env var to enable)
const AUTH_PASSWORD = process.env.SIMPLE_AUTH_PASSWORD || '';
const AUTH_ENABLED = AUTH_PASSWORD.length > 0;
const SESSION_SECRET = process.env.SESSION_SECRET || crypto.randomBytes(32).toString('hex');
// Family members config (can be overridden via FAMILY_MEMBERS env var as JSON)
const DEFAULT_MEMBERS = [
{ id: "katinka", name: "Katinka", color: "#513eff" },
{ id: "orsi", name: "Orsi", color: "#a15dd8" },
{ id: "lili", name: "Lili", color: "#ffe70c" },
{ id: "mama", name: "Mama", color: "#513eff" },
{ id: "bazsi", name: "Bazsi", color: "#2db84a" },
];
let FAMILY_MEMBERS;
@@ -48,27 +48,35 @@ db.exec(`
app.use(express.json());
// Session tokens (in-memory, simple approach)
// Session tokens: token -> { created, memberId }
const sessions = new Map();
// Simple auth middleware
// Auth helper: get logged-in member from token
function getMember(req) {
const token = req.headers['x-auth-token'];
if (!token) return null;
const session = sessions.get(token);
if (!session) return null;
return session.memberId;
}
// Auth middleware
function authMiddleware(req, res, next) {
if (!AUTH_ENABLED) return next();
// Skip auth for login endpoint and static assets
if (req.path === '/api/login' || req.path === '/api/auth-status') return next();
// Skip auth for login, auth-status, and members endpoints
if (req.path === '/api/login' || req.path === '/api/auth-status' || req.path === '/api/members') return next();
const token = req.headers['x-auth-token'];
if (token && sessions.has(token)) {
return next();
}
// For API routes, return 401
if (req.path.startsWith('/api/')) {
return res.status(401).json({ error: 'Unauthorized' });
}
next(); // Let static files through (frontend handles auth UI)
next();
}
app.use(authMiddleware);
@@ -79,22 +87,36 @@ app.get('/api/auth-status', (req, res) => {
});
app.post('/api/login', (req, res) => {
if (!AUTH_ENABLED) return res.json({ success: true, token: 'none' });
if (!AUTH_ENABLED) return res.json({ success: true, token: 'none', memberId: null });
const { password, memberId } = req.body;
// Validate member exists
if (!memberId || !FAMILY_MEMBERS.find(m => m.id === memberId)) {
return res.status(400).json({ success: false, error: 'Válassz egy családtagot' });
}
const { password } = req.body;
if (password === AUTH_PASSWORD) {
const token = crypto.randomBytes(32).toString('hex');
sessions.set(token, { created: Date.now() });
// Clean old sessions (>24h)
sessions.set(token, { created: Date.now(), memberId });
// Clean old sessions (>7 days)
for (const [t, s] of sessions) {
if (Date.now() - s.created > 86400000) sessions.delete(t);
if (Date.now() - s.created > 7 * 86400000) sessions.delete(t);
}
res.json({ success: true, token });
res.json({ success: true, token, memberId });
} else {
res.status(401).json({ success: false, error: 'Hibás jelszó' });
}
});
// Who am I endpoint
app.get('/api/me', (req, res) => {
const memberId = getMember(req);
if (!memberId) return res.json({ memberId: null });
const member = FAMILY_MEMBERS.find(m => m.id === memberId);
res.json({ memberId, member });
});
// Members endpoint
app.get('/api/members', (req, res) => {
res.json(FAMILY_MEMBERS);
@@ -107,7 +129,9 @@ app.get('/api/bookings', (req, res) => {
});
app.post('/api/bookings', (req, res) => {
const { member_id, start_date, end_date, status } = req.body;
const { start_date, end_date, status } = req.body;
// Use logged-in member if auth enabled, otherwise accept from body
const member_id = AUTH_ENABLED ? getMember(req) : req.body.member_id;
if (!member_id || !start_date || !end_date) {
return res.status(400).json({ error: 'Missing fields' });
}
@@ -135,7 +159,8 @@ app.get('/api/comments', (req, res) => {
});
app.post('/api/comments', (req, res) => {
const { member_id, text } = req.body;
const { text } = req.body;
const member_id = AUTH_ENABLED ? getMember(req) : req.body.member_id;
if (!member_id || !text) {
return res.status(400).json({ error: 'Missing fields' });
}
@@ -145,6 +170,17 @@ app.post('/api/comments', (req, res) => {
res.json({ id: result.lastInsertRowid });
});
app.delete('/api/comments/:id', (req, res) => {
const memberId = AUTH_ENABLED ? getMember(req) : req.body.member_id;
const comment = db.prepare('SELECT * FROM comments WHERE id = ?').get(req.params.id);
if (!comment) return res.status(404).json({ error: 'Not found' });
if (AUTH_ENABLED && comment.member_id !== memberId) {
return res.status(403).json({ error: 'Csak a saját hozzászólásod törölheted' });
}
db.prepare('DELETE FROM comments WHERE id = ?').run(req.params.id);
res.json({ success: true });
});
// Serve static frontend
app.use(express.static(path.join(__dirname, 'public')));
app.get('*', (req, res) => {