Skip to content

Implement 1d4_web: basic web UI for chess game indexer#1034

Merged
aaylward merged 3 commits intomainfrom
1d4_web
Feb 22, 2026
Merged

Implement 1d4_web: basic web UI for chess game indexer#1034
aaylward merged 3 commits intomainfrom
1d4_web

Conversation

@aaylward
Copy link
Copy Markdown
Collaborator

@aaylward aaylward commented Feb 22, 2026

Implements #1031.

  • Vanilla HTML/JS/CSS at domains/games/apps/1d4_web
  • Games: browse indexed games with sortable columns, motif badges, pagination, link to game URL
  • Index: enqueue form (username, platform chess.com, start/end month), POST api.1d4.net/index, request status list with auto-poll
  • Query: ChessQL input with example chips and syntax help, results table, limit selector
  • Cloudflare Worker + wrangler.toml, BUILD.bazel tar of static assets

Fixes #1031

- Vanilla HTML/JS/CSS at domains/games/apps/1d4_web
- Games browser (sortable table, motif badges, pagination)
- Index form (POST api.1d4.net/index) and request status with auto-poll
- ChessQL query view with example chips and syntax help
- Cloudflare Worker + wrangler.toml, BUILD.bazel tar of static assets

Fixes #1031
@aaylward aaylward enabled auto-merge (squash) February 22, 2026 20:47
view.id = `view-${route}`;
main.appendChild(view);
const fn = routes[route] || routes.games;
fn(view);

Check failure

Code scanning / CodeQL

Unvalidated dynamic method call High

Invocation of method with user-controlled name may dispatch to unexpected target and cause an exception.

Copilot Autofix

AI about 2 months ago

In general, to fix unvalidated dynamic method calls, you should ensure that the user‑controlled key is checked against a whitelist (or at least verified as an own property) and that the resolved value is indeed a function before invoking it. This prevents dispatch to unexpected targets (including properties on Object.prototype) and avoids calling non‑function values.

For this specific case, the best low‑impact fix is to restrict route to a known set of route names and only then select the corresponding function, with a final fallback to routes.games. We can do this entirely within render() by introducing a small whitelist array and validating route against it. Then we safely compute fn as routes[safeRoute] || routes.games and call it. This preserves existing functionality (unknown hashes still render the games view) while making the dispatch explicit and safe.

Concretely, in domains/games/apps/1d4_web/src/app.js, modify lines 27–36 in render() so that:

  • We define const allowedRoutes = ['games', 'index', 'query'];
  • We compute const safeRoute = allowedRoutes.includes(route) ? route : 'games';
  • We use safeRoute for setActiveNav, view.id, and for selecting fn.
  • Optionally, add a typeof fn === 'function' guard with a fallback to routes.games to be extra defensive.

No new imports are needed; this uses only standard JavaScript.

Suggested changeset 1
domains/games/apps/1d4_web/src/app.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/domains/games/apps/1d4_web/src/app.js b/domains/games/apps/1d4_web/src/app.js
--- a/domains/games/apps/1d4_web/src/app.js
+++ b/domains/games/apps/1d4_web/src/app.js
@@ -25,14 +25,19 @@
 
 function render() {
   const route = getRoute();
-  setActiveNav(route);
+  const allowedRoutes = ['games', 'index', 'query'];
+  const safeRoute = allowedRoutes.includes(route) ? route : 'games';
+  setActiveNav(safeRoute);
   const main = document.getElementById('app');
   main.innerHTML = '';
   const view = document.createElement('div');
   view.className = 'view active';
-  view.id = `view-${route}`;
+  view.id = `view-${safeRoute}`;
   main.appendChild(view);
-  const fn = routes[route] || routes.games;
+  let fn = routes[safeRoute] || routes.games;
+  if (typeof fn !== 'function') {
+    fn = routes.games;
+  }
   fn(view);
 }
 
EOF
@@ -25,14 +25,19 @@

function render() {
const route = getRoute();
setActiveNav(route);
const allowedRoutes = ['games', 'index', 'query'];
const safeRoute = allowedRoutes.includes(route) ? route : 'games';
setActiveNav(safeRoute);
const main = document.getElementById('app');
main.innerHTML = '';
const view = document.createElement('div');
view.className = 'view active';
view.id = `view-${route}`;
view.id = `view-${safeRoute}`;
main.appendChild(view);
const fn = routes[route] || routes.games;
let fn = routes[safeRoute] || routes.games;
if (typeof fn !== 'function') {
fn = routes.games;
}
fn(view);
}

Copilot is powered by AI and may make mistakes. Always verify output.
@aaylward aaylward committed this autofix suggestion about 2 months ago.
aaylward and others added 2 commits February 22, 2026 15:49
…od call

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@aaylward aaylward disabled auto-merge February 22, 2026 20:50
@aaylward aaylward merged commit 8906115 into main Feb 22, 2026
9 checks passed
@aaylward aaylward deleted the 1d4_web branch February 22, 2026 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1d4_web: Basic web interface for chess game indexer

2 participants