38eefb22e8
- leaderboard.html, replays.html: escape user-supplied display_name and username before inserting into innerHTML to prevent stored XSS - game.js: call POST /api/replays on win so browser-game completions are recorded; scores were never submitted before this fix - replays.rs: after replay insert, upsert leaderboard best_score / best_time_secs for opted-in users when the new score beats their current best (classic mode only); scores were never updated before this fix - leaderboard.rs: add LIMIT 100 to GET /api/leaderboard to prevent unbounded query growth Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
39 lines
1.1 KiB
JSON
39 lines
1.1 KiB
JSON
{
|
|
"db_name": "SQLite",
|
|
"query": "SELECT l.display_name, l.best_score, l.best_time_secs, l.recorded_at\n FROM leaderboard l\n JOIN users u ON u.id = l.user_id\n WHERE u.leaderboard_opt_in = 1\n ORDER BY\n CASE WHEN l.best_score IS NULL THEN 1 ELSE 0 END ASC,\n l.best_score DESC,\n CASE WHEN l.best_time_secs IS NULL THEN 1 ELSE 0 END ASC,\n l.best_time_secs ASC\n LIMIT 100",
|
|
"describe": {
|
|
"columns": [
|
|
{
|
|
"name": "display_name",
|
|
"ordinal": 0,
|
|
"type_info": "Text"
|
|
},
|
|
{
|
|
"name": "best_score",
|
|
"ordinal": 1,
|
|
"type_info": "Integer"
|
|
},
|
|
{
|
|
"name": "best_time_secs",
|
|
"ordinal": 2,
|
|
"type_info": "Integer"
|
|
},
|
|
{
|
|
"name": "recorded_at",
|
|
"ordinal": 3,
|
|
"type_info": "Text"
|
|
}
|
|
],
|
|
"parameters": {
|
|
"Right": 0
|
|
},
|
|
"nullable": [
|
|
false,
|
|
true,
|
|
true,
|
|
false
|
|
]
|
|
},
|
|
"hash": "2b814989a6632ca930ae1e895f97a7fc3389c91d1d2abf6900a21fb0d6e94ef3"
|
|
}
|