| 1 | {{define "title"}}Sign in — CONTRA{{end}} |
| 2 | {{define "brand"}}<a rst-shell-brand href="/">CONTRA</a>{{end}} |
| 3 | {{define "head"}}<script type="module" src="{{asset "static/pages/signin.js"}}"></script>{{end}} |
| 4 | |
| 5 | {{define "content"}} |
| 6 | <h1>Sign in</h1> |
| 7 | |
| 8 | <p>Your passphrase is not sent. This page stretches it, derives a signing key |
| 9 | from it, and signs a challenge the server chose.</p> |
| 10 | |
| 11 | <form data-signin method="post" action="/auth/verify"> |
| 12 | <p> |
| 13 | <label for="email">Email address</label> |
| 14 | <input id="email" name="email" type="email" autocomplete="username" required> |
| 15 | </p> |
| 16 | |
| 17 | {{/* The tear-line, and it runs through the middle of this form because |
| 18 | that is where the boundary genuinely is: the address above it goes |
| 19 | to the server, as a blind index it cannot reverse. The passphrase |
| 20 | below it does not go anywhere — it is stretched here and used to |
| 21 | sign a challenge, which is what the paragraph above already says. |
| 22 | |
| 23 | This is the clearest place in the whole product to draw it: not a |
| 24 | diagram of the promise, the promise happening in one form. */}} |
| 25 | <div data-tear><span>goes to the server ↑</span><span>never leaves this page ↓</span></div> |
| 26 | |
| 27 | <p> |
| 28 | <label for="passphrase">Passphrase</label> |
| 29 | <input id="passphrase" name="passphrase" type="password" |
| 30 | autocomplete="current-password" required> |
| 31 | </p> |
| 32 | <p><button type="submit">Sign in</button></p> |
| 33 | <div data-status aria-live="polite"></div> |
| 34 | </form> |
| 35 | |
| 36 | <p>No account yet? <a href="/signup">Create one</a>.</p> |
| 37 | {{end}} |
| 38 | |