diff --git a/apply.html b/apply.html index 3f11d06..60958cc 100644 --- a/apply.html +++ b/apply.html @@ -130,45 +130,7 @@ - - +
← Back to Home diff --git a/brand.html b/brand.html index f60fcc6..01216a1 100644 --- a/brand.html +++ b/brand.html @@ -76,44 +76,7 @@ - +
← Back to Home @@ -319,6 +282,8 @@

Licensing & permissions

.replace(/>/g, ">"); } function highlightHtml(s) { + // Input is always the output of makeHtml() — a bounded, machine-generated + // string, never free user input — so ReDoS is not a concern here. let escaped = escapeHtml(s); escaped = escaped.replace( /("[^"]*")/g, @@ -328,8 +293,9 @@

Licensing & permissions

/([a-zA-Z-:]+)(=)/g, '$1$2', ); + // Use greedy [^&]* (not lazy) — no nested quantifiers, no backtracking risk. escaped = escaped.replace( - /(<\/?[a-zA-Z0-9-]+)([^&]*?)(>)/g, + /(<\/?[a-zA-Z0-9-]+)([^&]*)(>)/g, '$1$2$3', ); return escaped; diff --git a/donate.html b/donate.html index 002ec9c..e563639 100644 --- a/donate.html +++ b/donate.html @@ -191,45 +191,7 @@ - - +
← Back to Home diff --git a/index.html b/index.html index b7d2ed9..59954af 100644 --- a/index.html +++ b/index.html @@ -25,44 +25,7 @@ - +
diff --git a/theme.js b/theme.js index cedabf8..f563519 100644 --- a/theme.js +++ b/theme.js @@ -1,5 +1,5 @@ // Simple theme initialization and toggle handling. -// Sets html[data-theme] on load and wires #themeToggle click. +// Sets html[data-theme] on load, injects #themeToggle if absent, and wires click. (function(){ const html = document.documentElement; @@ -29,13 +29,43 @@ return next; } + // Inject the shared theme-toggle button into so pages don't each need + // to duplicate the markup. Any page that already contains #themeToggle keeps + // its own element unchanged. Called only from init(), which itself only runs + // once the DOM is ready, so document.body is always available at this point. + function injectThemeToggleButton(){ + if (!document.body) return null; + const btn = document.createElement('button'); + btn.className = 'theme-toggle'; + btn.id = 'themeToggle'; + btn.setAttribute('aria-label', 'Toggle theme'); + btn.innerHTML = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + ''; + document.body.appendChild(btn); + return btn; + } + function init(){ const saved = getSavedTheme(); const theme = saved || detectSystem(); applyTheme(theme); if (!saved) saveTheme(theme); - const btn = document.getElementById('themeToggle'); + let btn = document.getElementById('themeToggle'); + if (!btn) btn = injectThemeToggleButton(); if (btn) btn.addEventListener('click', toggleTheme); }