diff --git a/pb_public/status.html b/pb_public/status.html index a57e8b2..bc63314 100644 --- a/pb_public/status.html +++ b/pb_public/status.html @@ -64,6 +64,8 @@ pre{margin:8px 0 0;background:#0b0c10;border:1px solid var(--line);border-radius:8px; padding:10px;max-height:340px;overflow:auto;font-family:var(--mono);font-size:11.5px; white-space:pre-wrap;word-break:break-word} + .accts input.pw{width:190px;margin-right:6px} + .accts td:last-child{white-space:nowrap} .login{max-width:340px;margin:14vh auto;padding:0 16px} .login section{padding:18px} .row{display:flex;gap:8px;align-items:center;flex-wrap:wrap} @@ -675,11 +677,60 @@ async function setNoticeActive(id, to){ } catch (e) { alert("nepovedlo se: " + e.message); } } +/** + * Set someone's password directly. + * + * Exists because the emailed reset cannot be relied on, and the reason is not + * the mail server: PocketBase looks accounts up **case-sensitively**, so a + * family member typing `Vojta.Markup@seznam.cz` for an account stored in + * lowercase matches nothing — and the endpoint answers 204 either way, so that + * nobody can use it to discover which addresses exist. From the sofa that is + * indistinguishable from mail being broken, which is how it was reported. + * + * The app now lower-cases addresses before sending them, so this should stop + * happening. This stays for the case it cannot fix: somebody who has genuinely + * forgotten a password and cannot receive mail. + * + * No confirmation prompt. The button is one row of a table only a superuser can + * load, the field says what it does, and an accidental press with an empty box + * does nothing. + */ +async function setPassword(id, btn){ + var input = el("pw_" + id); + var out = el("pwout_" + id); + var pw = (input.value || "").trim(); + out.style.color = ""; + if (pw.length < 8) { out.textContent = "nejméně 8 znaků"; return; } + btn.disabled = true; + out.textContent = "nastavuji…"; + try { + // A superuser may set a password without the old one. `passwordConfirm` is + // required by the collection rules even so. + await api("/api/collections/users/records/" + id, + { method: "PATCH", body: { password: pw, passwordConfirm: pw } }); + // Cleared immediately: it was only ever here to be typed and handed over, + // and a password left sitting in a field is one that ends up in a + // screenshot. + input.value = ""; + out.textContent = "hotovo — předej mu ho"; + } catch (e) { + out.style.color = "var(--bad)"; + out.textContent = "nepovedlo se: " + e.message; + } finally { + btn.disabled = false; + } +} + function viewAdmin(users, tpls){ var rows = (users || []).map(function(u){ + var id = esc(u.id); return "" + esc(u.email || u.username || u.id) + "" + "" + esc(u.ratingDefault || "—") + "" + - "" + esc(String(u.created).substring(0, 10)) + ""; + "" + esc(String(u.created).substring(0, 10)) + "" + + "" + + "" + + ""; }).join(""); return '

Nový účet

' + @@ -711,8 +762,12 @@ function viewAdmin(users, tpls){ "tohle jde přes superuživatele, kterým jsi právě přihlášený.

" + '

Účty

' + - "" + - (rows || "") + "
e-mailstropvznik
nic
" + + "e-mailstropvznikheslo" + + (rows || "nic") + "" + + '

Heslo nastavíš rovnou, bez e-mailu — reset přes e-mail ' + + "selhává tiše, když si adresu někdo napíše s velkým písmenem, protože " + + "PocketBase hledá účty přesně na znak a stejně vždycky odpoví „odesláno“, " + + "aby přes něj nešlo zjišťovat, které adresy existují.

" + '

Varianta rozhoduje, jaký build dostane přes automatickou ' + "aktualizaci — server ji vybírá podle tohohle příznaku, klient si ji nemůže " + "vyžádat.

"; @@ -1019,6 +1074,9 @@ function wire(){ b.onclick = function(){ showLog(b.getAttribute("data-log"), b); }; }); if (el("createBtn")) el("createBtn").onclick = createAccount; + Array.prototype.forEach.call(el("main").querySelectorAll("button[data-pw]"), function(b){ + b.onclick = function(){ setPassword(b.getAttribute("data-pw"), b); }; + }); if (el("nSave")) el("nSave").onclick = saveNotice; Array.prototype.forEach.call(el("main").querySelectorAll("button[data-notice]"), function(b){ b.onclick = function(){ setNoticeActive(b.getAttribute("data-notice"), b.getAttribute("data-to")); };