mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
Every dashboard persona login spent 25s times the onion multiplier in clickOidcLoginLink before it clicked anything. The markup probe matched a[href*='openid-connect'], and the dashboard header renders the Account dropdown's hidden Logout item, whose Keycloak end-session URL contains the same string, before its Login link. .first() pinned the hidden item until the 5s probe expired; the exact-name probe then missed for 20s because Playwright counts the Font Awesome ::before glyph in the link's accessible name. The probe now skips logout hrefs and resolves to the Login anchor the loose probe used to click. The adapter readiness wait cost every other role 15s times the multiplier, because only the dashboard sets __oidcLoginReady. The helper now waits for the load event and then only while the flag is false. The dashboard loader, an inline head script, declares it false before the Login link renders; oidc.js still sets it true once the click handler is wired. Traces of run 34421944328 show the two probes expiring at 5.07s + 20.00s on clearnet and 25.01s + 100.00s over Tor. Across runs 34421944328 and 34419507038 the Tor dashboard persona test took 150-156s in all 102 compose runs against 32-34s in the 92 clearnet ones. Replayed on the dashboard HTML those traces captured, the helper reaches the Keycloak authorize endpoint in 0.08s instead of 40.09s, and still waits for the adapter (1.52s) when the flag flips to true after 1.5s. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
50 lines
1.8 KiB
Django/Jinja
50 lines
1.8 KiB
Django/Jinja
// ===== Runtime loader for external JS files (no Jinja includes) =====
|
|
(function () {
|
|
// 1) Values injected by Ansible/Jinja
|
|
// Base URL where your files were deployed (e.g. CDN), made safe w/o trailing slash
|
|
const BASE_URL = ("{{ DASHBOARD_JS_BASE_URL }}").replace(/\/+$/, "");
|
|
// List of files to load, in order
|
|
const FILES = [
|
|
{% for f in DASHBOARD_JS_FILES -%}
|
|
"{{ f }}"{% if not loop.last %},{% endif %}
|
|
{%- endfor %}
|
|
];
|
|
// Cache buster (highest mtime computed during deploy)
|
|
const VERSION = "{{ javascript_file_version }}";
|
|
{% if 'oidc.js' in DASHBOARD_JS_FILES %}
|
|
window.__oidcLoginReady = false;
|
|
{% endif %}
|
|
|
|
// 2) Helper to load a <script> with proper query param
|
|
function loadScriptSequential(url) {
|
|
return new Promise((resolve, reject) => {
|
|
const s = document.createElement("script");
|
|
// Append ?v=... (or &v=... if there are already params)
|
|
s.src = url + (url.includes("?") ? "&" : "?") + "v=" + encodeURIComponent(VERSION);
|
|
// Keep execution order: do not set async/defer
|
|
s.onload = () => resolve();
|
|
s.onerror = () => reject(new Error("Failed to load " + url));
|
|
document.head.appendChild(s);
|
|
});
|
|
}
|
|
|
|
// 3) Load all files in order
|
|
async function loadAll() {
|
|
for (const name of FILES) {
|
|
const fullUrl = BASE_URL + "/" + name.replace(/^\/+/, "");
|
|
await loadScriptSequential(fullUrl);
|
|
}
|
|
// Optional: hook after everything is ready
|
|
if (typeof window.onDashboardJsLoaded === "function") {
|
|
try { window.onDashboardJsLoaded(); } catch {}
|
|
}
|
|
}
|
|
|
|
// 4) Start after DOM is ready (safe point to inject <script> tags)
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", loadAll);
|
|
} else {
|
|
loadAll();
|
|
}
|
|
})();
|