Admin login: ignore surrounding spaces/quotes in a pasted password; show-password toggle

This commit is contained in:
Jonathan Sykes
2026-10-15 11:52:41 +08:00
parent b6e019c352
commit 7ceefa3d6a
2 changed files with 17 additions and 4 deletions

View File

@@ -468,7 +468,10 @@
<h2>Sign in</h2>
<p class="muted">Admin password</p>
<form id="loginForm" class="row">
<input class="field" type="password" id="pw" placeholder="Password" autocomplete="current-password" />
<span style="position:relative;flex:1;display:flex;min-width:0">
<input class="field" type="password" id="pw" placeholder="Password" autocomplete="current-password" autocapitalize="off" autocorrect="off" spellcheck="false" style="flex:1;padding-right:48px" />
<button type="button" id="pwShow" aria-label="Show password" aria-pressed="false" style="position:absolute;right:4px;top:50%;transform:translateY(-50%);width:40px;height:40px;border:0;background:none;color:inherit;opacity:.7;cursor:pointer"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg></button>
</span>
<button class="btn pri" type="submit">Sign in</button>
</form>
<div id="loginMsg" class="msg"></div>
@@ -948,11 +951,20 @@
$('loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
$('loginMsg').className = 'msg'; $('loginMsg').textContent = 'Signing in…';
const j = await api('/api/admin/login', { method: 'POST', body: { password: $('pw').value } });
// Pasted from a chat or note: drop surrounding spaces and a wrapping pair of
// backticks or quotes, which are never part of the password.
const password = $('pw').value.trim().replace(/^([`'"\u2018\u201C])(.*)([`'"\u2019\u201D])$/s, '$2');
const j = await api('/api/admin/login', { method: 'POST', body: { password } });
if (!j.ok) { $('loginMsg').className = 'msg err'; $('loginMsg').textContent = j.error || 'failed'; return; }
$('pw').value = ''; $('loginMsg').textContent = '';
boot();
});
$('pwShow').addEventListener('click', () => {
const show = $('pw').type === 'password';
$('pw').type = show ? 'text' : 'password';
$('pwShow').setAttribute('aria-pressed', String(show));
$('pwShow').setAttribute('aria-label', show ? 'Hide password' : 'Show password');
});
$('logoutBtn').addEventListener('click', async () => { await api('/api/admin/logout', { method: 'POST' }); showLogin(); });
/* ---------------- server analytics / metadata collection ---------------- */