diff --git a/account.html b/account.html index ef8858a..04f9e24 100644 --- a/account.html +++ b/account.html @@ -41,13 +41,38 @@

Pod

Explore

- Profile /public/ + profile /private/ /inbox/ /settings/
+

Password

+

Climb from rung 1 (default me) to rung 2 (your password).

+ + +

Session

@@ -110,6 +135,72 @@

Session

fail('Sign-out failed: ' + (e.message || String(e))); } }); + + // Change-password flow. POSTs to JSS's PUT /idp/credentials with + // {currentPassword, newPassword}. The endpoint requires the + // session's DPoP-bound bearer token plus re-proof of the current + // password — session.authFetch handles the auth headers, the form + // collects the re-auth proof. + const pwToggle = document.getElementById('pw-toggle'); + const pwForm = document.getElementById('pw-form'); + const pwCancel = document.getElementById('pw-cancel'); + const pwSubmit = document.getElementById('pw-submit'); + const pwMsg = document.getElementById('pw-msg'); + const pwCurrent = document.getElementById('pw-current'); + const pwNew = document.getElementById('pw-new'); + const pwConfirm = document.getElementById('pw-confirm'); + + function pwStatus(text, isError) { + pwMsg.textContent = text; + pwMsg.style.display = 'block'; + pwMsg.style.background = isError ? '#fff0f0' : '#e8f5e9'; + pwMsg.style.color = isError ? '#a00' : '#1b5e20'; + } + function pwReset() { + pwForm.reset(); + pwMsg.style.display = 'none'; + } + + pwToggle.addEventListener('click', () => { + pwForm.hidden = false; + pwToggle.hidden = true; + pwCurrent.focus(); + }); + pwCancel.addEventListener('click', () => { + pwForm.hidden = true; + pwToggle.hidden = false; + pwReset(); + }); + pwForm.addEventListener('submit', async (ev) => { + ev.preventDefault(); + if (pwNew.value !== pwConfirm.value) { + pwStatus('New password and confirmation do not match.', true); + return; + } + pwSubmit.disabled = true; + pwStatus('Updating…'); + try { + const res = await session.authFetch(new URL('./idp/credentials', window.location.href).href, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ currentPassword: pwCurrent.value, newPassword: pwNew.value }) + }); + if (!res.ok) { + let detail = ''; + try { + const j = await res.json(); + detail = j.error_description || j.error || ''; + } catch {} + throw new Error('HTTP ' + res.status + (detail ? ' — ' + detail : '')); + } + pwStatus('Password updated. You\'re on rung 2 now.'); + pwCurrent.value = pwNew.value = pwConfirm.value = ''; + } catch (e) { + pwStatus('Change failed: ' + (e.message || String(e)), true); + } finally { + pwSubmit.disabled = false; + } + }); } else { signedOutEl.hidden = false; } diff --git a/package.json b/package.json index 235d8a8..ff8a11a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jspod", - "version": "0.0.18", + "version": "0.0.19", "description": "JavaScript Solid Pod - Just works, batteries included", "type": "module", "main": "index.js",