diff --git a/server.js b/server.js index d5fa729..584f3b5 100644 --- a/server.js +++ b/server.js @@ -40,6 +40,13 @@ const dbAll = (sql, params = []) => new Promise((resolve, reject) => { }); }); +const dbGet = (sql, params = []) => new Promise((resolve, reject) => { + db.get(sql, params, (err, row) => { + if (err) reject(err); + else resolve(row); + }); +}); + // Setup Storage const uploadDir = path.join(__dirname, 'uploads'); if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir); @@ -172,8 +179,23 @@ apiRouter.post('/auth/login', (req, res) => { }); }); -apiRouter.get('/state', (req, res) => { +apiRouter.get('/state', async (req, res) => { const state = { isStarted: false, teams: [], challenges: [], solves: [], blogs: [], config: {} }; + + // Security Check: Identify requester and admin status + const authHeader = req.headers.authorization; + const teamId = authHeader ? authHeader.replace('Bearer mock-token-', '') : null; + let isAdmin = false; + + if (teamId) { + try { + const team = await dbGet("SELECT isAdmin FROM teams WHERE id = ?", [teamId]); + isAdmin = team && team.isAdmin === 1; + } catch (err) { + console.error("Auth verify failed in state API:", err); + } + } + db.all("SELECT key, value FROM config", (err, configRows) => { if (err) return res.status(500).json({ error: 'Failed to fetch config' }); configRows.forEach(row => { state.config[row.key] = row.value; }); @@ -189,11 +211,18 @@ apiRouter.get('/state', (req, res) => { if (err) return res.status(500).json({ error: 'Failed to fetch blogs' }); state.solves = solves || []; state.blogs = blogs || []; - state.challenges = (challenges || []).map(c => ({ - ...c, - files: JSON.parse(c.files || '[]'), - solves: state.solves.filter(s => s.challengeId === c.id).map(s => s.teamId) - })); + state.challenges = (challenges || []).map(c => { + const enriched = { + ...c, + files: JSON.parse(c.files || '[]'), + solves: state.solves.filter(s => s.challengeId === c.id).map(s => s.teamId) + }; + // CRITICAL SECURITY FIX: Hide flag if not admin + if (!isAdmin) { + delete enriched.flag; + } + return enriched; + }); res.json(state); }); }); @@ -392,3 +421,4 @@ if (fs.existsSync(distPath)) { app.get('*', (req, res) => { if (!req.path.startsWith('/api') && !req.path.startsWith('/files')) res.sendFile(path.join(distPath, 'index.html')); else res.status(404).json({ error: 'Not found' }); }); } app.listen(port, '0.0.0.0', () => console.log(`CTF Backend running on port ${port}`)); +