From b9fe5c294e350d36a5a07f16b2aa1d640266af22 Mon Sep 17 00:00:00 2001 From: balex Date: Mon, 9 Mar 2026 12:53:56 +0100 Subject: [PATCH] auth gateway --- src/public/index.html | 1 + src/public/js/app.js | 2 +- src/public/js/auth.js | 72 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/public/js/auth.js diff --git a/src/public/index.html b/src/public/index.html index a2aca5f..b6e12be 100644 --- a/src/public/index.html +++ b/src/public/index.html @@ -104,6 +104,7 @@ + diff --git a/src/public/js/app.js b/src/public/js/app.js index cd5e28b..a248d88 100644 --- a/src/public/js/app.js +++ b/src/public/js/app.js @@ -284,7 +284,7 @@ checkBtn.addEventListener('click', async () => { feedbackContent.innerHTML = '
'; try { - const res = await fetch('api/check', { + const res = await authFetch('api/check', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ diff --git a/src/public/js/auth.js b/src/public/js/auth.js new file mode 100644 index 0000000..9d95a47 --- /dev/null +++ b/src/public/js/auth.js @@ -0,0 +1,72 @@ +// ── Guest Auth ──────────────────────────────────────────────────────────────── +const GUEST_EMAIL = "guest@gmail.com"; +const GUEST_PASSWORD = "Guest123!"; + +let _token = null; +let _loginPromise = null; + +async function guestLogin() { + const res = await fetch('/api/auth/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email: GUEST_EMAIL, password: GUEST_PASSWORD }), + }); + + if (res.status === 401) { + // Guest doesn't exist yet — register + const reg = await fetch('/api/auth/register', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + username: 'Guest', + email: GUEST_EMAIL, + password: GUEST_PASSWORD, + confirmPassword: GUEST_PASSWORD, + }), + }); + if (!reg.ok) throw new Error('Guest registration failed'); + const regData = await reg.json(); + _token = regData.payload?.token ?? null; + return; + } + + if (!res.ok) throw new Error('Guest login failed'); + const data = await res.json(); + _token = data.payload?.token ?? null; +} + +function ensureAuth() { + if (!_loginPromise) { + _loginPromise = guestLogin().catch(err => { + _loginPromise = null; + throw err; + }); + } + return _loginPromise; +} + +// Authenticated fetch: adds Bearer token, retries once on 401 +async function authFetch(url, options = {}) { + await ensureAuth(); + + const doRequest = () => { + const headers = { ...(options.headers || {}) }; + if (_token) headers['Authorization'] = `Bearer ${_token}`; + return fetch(url, { ...options, headers }); + }; + + let res = await doRequest(); + + if (res.status === 401) { + // Token expired — re-login and retry once + _loginPromise = null; + _token = null; + await ensureAuth(); + res = await doRequest(); + } + + return res; +} + +// Kick off login immediately on page load (fire-and-forget) +ensureAuth().catch(() => {});