| 1 | // Sign in: one form, one ceremony. |
| 2 | // |
| 3 | // Signing in is not unlocking. This proves who you are to the server, which |
| 4 | // then serves you ciphertext it cannot read; the vault asks for the |
| 5 | // passphrase again to open it. |
| 6 | |
| 7 | import { signIn } from "../crypto/account.js"; |
| 8 | |
| 9 | function say(form, text, kind = "working") { |
| 10 | const p = document.createElement("p"); |
| 11 | p.setAttribute("data-kind", kind); |
| 12 | p.append(document.createTextNode(text)); |
| 13 | form.querySelector("[data-status]").replaceChildren(p); |
| 14 | } |
| 15 | |
| 16 | function busy(form, on) { |
| 17 | for (const c of form.querySelectorAll("input, button")) c.disabled = on; |
| 18 | } |
| 19 | |
| 20 | const form = document.querySelector("[data-signin]"); |
| 21 | if (form) { |
| 22 | form.addEventListener("submit", async (e) => { |
| 23 | e.preventDefault(); |
| 24 | busy(form, true); |
| 25 | let step = "start"; |
| 26 | try { |
| 27 | await signIn( |
| 28 | form.querySelector("[name=email]").value, |
| 29 | form.querySelector("[name=passphrase]").value, |
| 30 | (m) => { |
| 31 | step = m; |
| 32 | say(form, m + "…"); |
| 33 | }); |
| 34 | window.location.assign("/vault"); |
| 35 | } catch (err) { |
| 36 | // The full error goes to the console; the screen says one thing. |
| 37 | // |
| 38 | // An unknown address, a wrong passphrase and an expired challenge are |
| 39 | // three different facts, and telling them apart is the attacker's |
| 40 | // problem, not ours to solve for them. What the screen does say is |
| 41 | // which step it reached, because "it failed" with no location is what |
| 42 | // made the old signup impossible to report. |
| 43 | console.error("CONTRA sign-in failed while", step, err); |
| 44 | say(form, "Could not sign in. Check the address and passphrase. " + |
| 45 | `(Failed while: ${step}. The browser console has the detail.)`, "error"); |
| 46 | busy(form, false); |
| 47 | } |
| 48 | }); |
| 49 | } |
| 50 | |