myheats

Live heats, scoring and leaderboard for sport events
git clone https://git.in0rdr.ch/myheats.git
Log | Files | Refs | Pull requests |Archive | README | LICENSE

commit e14711b8ae55b3bca1439708f8a93db12a04a8f9
parent ba9a6e54c0b6c0787576b174a048e4781704c619
Author: Andreas Gruhler <agruhl@gmx.ch>
Date:   Mon,  9 Mar 2026 17:07:00 +0100

fix(137): fix verifyToken & add notAuthorized

The new behavior of verifyToken does not throw an error any more when
not authorized.

Explicitly check the user of the token and return a 401 unauthorized
error when no user is found.

Diffstat:
Msrc/api/server.cjs | 590+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
1 file changed, 336 insertions(+), 254 deletions(-)

diff --git a/src/api/server.cjs b/src/api/server.cjs @@ -177,7 +177,7 @@ server.on('request', async (req, res) => { data: judges, })); } else { - notAllowed(res, req.method) + notAuthorized(res) } } catch(error) { serverError(res, error); @@ -194,7 +194,7 @@ server.on('request', async (req, res) => { data: athletes, })); } else { - notAllowed(res, req.method) + notAuthorized(res) } } catch(error) { serverError(res, error); @@ -218,7 +218,7 @@ server.on('request', async (req, res) => { data: setting[0].value, })); } else { - notAllowed(res, req.method) + notAuthorized(res) } } catch(error) { serverError(res, error); @@ -345,22 +345,26 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") - } - input = JSON.parse(b); - console.log(' startlistWithAthletes request with headId:', input.heat_id); - - const startlist = await db.startlistWithAthletes(input.heat_id); - - if (startlist.length < 1) { - throw new Error("No athletes for this startlist") + const user = await verifyToken(req, token) + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' startlistWithAthletes request with headId:', input.heat_id); + + const startlist = await db.startlistWithAthletes(input.heat_id); + + if (startlist.length < 1) { + throw new Error("No athletes for this startlist") + } + res.end(JSON.stringify({ + message: 'Startlist with athletes for heat', + data: startlist, + })); + } else { + notAuthorized(res) } - res.end(JSON.stringify({ - message: 'Startlist with athletes for heat', - data: startlist, - })); } catch(error) { serverError(res, error); } @@ -434,28 +438,33 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") - } - input = JSON.parse(b); - console.log(' GetScore request for:', input); - - const scores = await db.getScore( - input.heat, - input.athlete, - input.judge - ); - - if (scores.length < 1) { - noContent(res); - return + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' GetScore request for:', input); + + const scores = await db.getScore( + input.heat, + input.athlete, + input.judge + ); + + if (scores.length < 1) { + noContent(res); + return + } + + res.end(JSON.stringify({ + message: 'Requested score for heat, user and judge', + data: scores[0], + })); + } else { + notAuthorized(res) } - - res.end(JSON.stringify({ - message: 'Requested score for heat, user and judge', - data: scores[0], - })); } catch (error) { serverError(res, error); } @@ -467,28 +476,33 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") - } - input = JSON.parse(b); - console.log(' SetScore request for:', input); - - const scores = await db.setScore( - input.heat, - input.athlete, - input.judge, - input.score, - ); - - if (scores.length < 1) { - throw new Error("Score not updated") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' SetScore request for:', input); + + const scores = await db.setScore( + input.heat, + input.athlete, + input.judge, + input.score, + ); + + if (scores.length < 1) { + throw new Error("Score not updated") + } + + res.end(JSON.stringify({ + message: 'Score update for heat, user and judge', + data: scores[0], + })); + } else { + notAuthorized(res) } - - res.end(JSON.stringify({ - message: 'Score update for heat, user and judge', - data: scores[0], - })); } catch (error) { serverError(res, error); } @@ -500,27 +514,32 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' newHeat request for:', input); + + const heats = await db.newHeat( + input.name, + input.location, + input.planned_start, + input.private + ); + if (heats.length < 1) { + throw new Error("Heat not created") + } + + res.end(JSON.stringify({ + message: 'New heat', + data: heats[0], + })); + } else { + notAuthorized(res) } - input = JSON.parse(b); - console.log(' newHeat request for:', input); - - const heats = await db.newHeat( - input.name, - input.location, - input.planned_start, - input.private - ); - if (heats.length < 1) { - throw new Error("Heat not created") - } - - res.end(JSON.stringify({ - message: 'New heat', - data: heats[0], - })); } catch (error) { serverError(res, error); } @@ -532,24 +551,29 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") - } - input = JSON.parse(b); - console.log(' getHeat request for:', input); - - const heats = await db.getHeat( - input.heat_id, - ); - if (heats.length < 1) { - throw new Error("Heat not found") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' getHeat request for:', input); + + const heats = await db.getHeat( + input.heat_id, + ); + if (heats.length < 1) { + throw new Error("Heat not found") + } + + res.end(JSON.stringify({ + message: 'New heat', + data: heats[0], + })); + } else { + notAuthorized(res) } - - res.end(JSON.stringify({ - message: 'New heat', - data: heats[0], - })); } catch (error) { serverError(res, error); } @@ -561,21 +585,26 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") - } - input = JSON.parse(b); - console.log(' removeHeat request for:', input); - - const heats = await db.removeHeat(input.heat_id) - if (heats.length < 1) { - throw new Error("Heat not removed") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' removeHeat request for:', input); + + const heats = await db.removeHeat(input.heat_id) + if (heats.length < 1) { + throw new Error("Heat not removed") + } + res.end(JSON.stringify({ + message: 'Heat removed', + data: heats[0], + })); + } else { + notAuthorized(res) } - res.end(JSON.stringify({ - message: 'Heat removed', - data: heats[0], - })); } catch (error) { serverError(res, error); } @@ -587,21 +616,26 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") - } - input = JSON.parse(b); - console.log(' toggleHeatVisibility request for:', input); - - const heats = await db.toggleHeatVisibility(input.heat_id) - if (heats.length < 1) { - throw new Error("Heat visibility unchanged") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' toggleHeatVisibility request for:', input); + + const heats = await db.toggleHeatVisibility(input.heat_id) + if (heats.length < 1) { + throw new Error("Heat visibility unchanged") + } + res.end(JSON.stringify({ + message: 'Heat visibility toggled', + data: heats[0], + })); + } else { + notAuthorized(res) } - res.end(JSON.stringify({ - message: 'Heat visibility toggled', - data: heats[0], - })); } catch (error) { serverError(res, error); } @@ -613,25 +647,30 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") - } - input = JSON.parse(b); - console.log(' addAthleteToHeat request for:', input); - - const startlist = await db.addAthleteToHeat( - input.athlete, - input.heat, - ); - if (startlist.length < 1) { - throw new Error("Startlist not updated") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' addAthleteToHeat request for:', input); + + const startlist = await db.addAthleteToHeat( + input.athlete, + input.heat, + ); + if (startlist.length < 1) { + throw new Error("Startlist not updated") + } + + res.end(JSON.stringify({ + message: 'Athlete added to startlist', + data: startlist[0], + })); + } else { + notAuthorized(res) } - - res.end(JSON.stringify({ - message: 'Athlete added to startlist', - data: startlist[0], - })); } catch (error) { serverError(res, error); } @@ -643,22 +682,27 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") - } - input = JSON.parse(b); - console.log(' removeAthleteFromHeat request for:', input); - - const startlist = await db.removeAthleteFromHeat(input.startlist_id) - if (startlist.length < 1) { - throw new Error("Startlist not updated") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' removeAthleteFromHeat request for:', input); + + const startlist = await db.removeAthleteFromHeat(input.startlist_id) + if (startlist.length < 1) { + throw new Error("Startlist not updated") + } + + res.end(JSON.stringify({ + message: 'Athlete removed from startlist', + data: startlist[0], + })); + } else { + notAuthorized(res) } - - res.end(JSON.stringify({ - message: 'Athlete removed from startlist', - data: startlist[0], - })); } catch (error) { serverError(res, error); } @@ -670,28 +714,33 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' addAthlete request for:', input); + + const athlete = await db.addAthlete( + input.nr, + input.firstname, + input.lastname, + input.birthday, + input.school, + ); + if (athlete.length < 1) { + throw new Error("Athlete not removed") + } + + res.end(JSON.stringify({ + message: 'Athlete created', + data: athlete[0] + })); + } else { + notAuthorized(res) } - input = JSON.parse(b); - console.log(' addAthlete request for:', input); - - const athlete = await db.addAthlete( - input.nr, - input.firstname, - input.lastname, - input.birthday, - input.school, - ); - if (athlete.length < 1) { - throw new Error("Athlete not removed") - } - - res.end(JSON.stringify({ - message: 'Athlete created', - data: athlete[0] - })); } catch (error) { serverError(res, error); } @@ -703,21 +752,26 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") - } - input = JSON.parse(b); - console.log(' removeAthlete request for:', input); - - const athlete = await db.removeAthlete(input.athlete_id) - if (athlete.length < 1) { - throw new Error("Athlete not removed") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' removeAthlete request for:', input); + + const athlete = await db.removeAthlete(input.athlete_id) + if (athlete.length < 1) { + throw new Error("Athlete not removed") + } + res.end(JSON.stringify({ + message: 'Athlete removed', + data: athlete[0], + })); + } else { + notAuthorized(res) } - res.end(JSON.stringify({ - message: 'Athlete removed', - data: athlete[0], - })); } catch (error) { serverError(res, error); } @@ -729,26 +783,31 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") - } - input = JSON.parse(b); - console.log(' addJudge request for:', input); - - const judge = await db.addJudge( - input.email, - input.firstname, - input.lastname, - ); - if (judge.length < 1) { - throw new Error("Judge not added") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' addJudge request for:', input); + + const judge = await db.addJudge( + input.email, + input.firstname, + input.lastname, + ); + if (judge.length < 1) { + throw new Error("Judge not added") + } + + res.end(JSON.stringify({ + message: 'Judge created', + data: judge[0] + })); + } else { + notAuthorized(res) } - - res.end(JSON.stringify({ - message: 'Judge created', - data: judge[0] - })); } catch (error) { serverError(res, error); } @@ -760,21 +819,26 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") - } - input = JSON.parse(b); - console.log(' removeJudge request for:', input); - - const judge = await db.removeJudge(input.judge_id) - if (judge.length < 1) { - throw new Error("Judge not removed") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' removeJudge request for:', input); + + const judge = await db.removeJudge(input.judge_id) + if (judge.length < 1) { + throw new Error("Judge not removed") + } + res.end(JSON.stringify({ + message: 'Judge removed', + data: judge[0], + })); + } else { + notAuthorized(res) } - res.end(JSON.stringify({ - message: 'Judge removed', - data: judge[0], - })); } catch (error) { serverError(res, error); } @@ -786,21 +850,26 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' updateSetting request for:', input); + + const setting = await db.updateSetting(input.name, input.value) + if (setting.length < 1) { + throw new Error("Setting not updated") + } + res.end(JSON.stringify({ + message: 'Setting updated', + data: setting[0], + })); + } else { + notAuthorized(res) } - input = JSON.parse(b); - console.log(' updateSetting request for:', input); - - const setting = await db.updateSetting(input.name, input.value) - if (setting.length < 1) { - throw new Error("Setting not updated") - } - res.end(JSON.stringify({ - message: 'Setting updated', - data: setting[0], - })); } catch (error) { serverError(res, error); } @@ -812,21 +881,26 @@ server.on('request', async (req, res) => { }).on('end', async () => { const b = Buffer.concat(body); try { - await verifyToken(req, token) - if (b.length < 1) { - throw new Error("Empty request body") + const user = await verifyToken(req, token) + + if (user !== false) { + if (b.length < 1) { + throw new Error("Empty request body") + } + input = JSON.parse(b); + console.log(' removeSetting request for:', input); + + const settings = await db.removeSetting(input.name) + if (settings.length < 1) { + throw new Error("Setting not removed") + } + res.end(JSON.stringify({ + message: 'Setting removed', + data: settings[0], + })); + } else { + notAuthorized(res) } - input = JSON.parse(b); - console.log(' removeSetting request for:', input); - - const settings = await db.removeSetting(input.name) - if (settings.length < 1) { - throw new Error("Setting not removed") - } - res.end(JSON.stringify({ - message: 'Setting removed', - data: settings[0], - })); } catch (error) { serverError(res, error); } @@ -906,6 +980,14 @@ function notAllowed(res, method) { error: `403 method ${method} not allowed`, })); } +function notAuthorized(res) { + console.error('x Error: 401 not authorized'); + res.statusCode = 401; + res.end(JSON.stringify({ + message: 'what is bbc let me see 🤔 ohh it\'s a british broadcasting corporation!', + error: `401 not authorized`, + })); +} function serverError(res, err) { console.error('x Error:', err); res.statusCode = 500;