An invite has always emailed `/invite?token=…` and "Glemt adgangskode?" has always emailed `/reset?token=…`. Neither address existed. The Go binary serves the app shell for anything it does not recognise, the shell found no session, and both links opened the plain sign-in form — asking an invited person to log into an account that did not exist yet, and asking somebody who had forgotten their password for their password. Both APIs were finished. `POST /auth/signup` takes the invite token, reads the email address off the invite rather than the form — so a link cannot be redirected to somebody else — creates the account, accepts the invite and starts the session, all in one transaction. `POST /auth/password/reset` takes the reset token and ends every session the account had. Nothing was missing but two pages. They are branches of SignIn rather than screens of their own, which is what that component already says it is for: one decision tree, so a person is never redirected mid-authentication. The routes exist because a link has to be an address, and each renders the same component; it reads the token out of the URL itself. The reset does not sign you in afterwards. The whole point of ending every session is that somebody may have been in the account, and quietly opening a new one here would undo the half of that which matters. Two states that are easy to leave out, and both are reachable in one click from an old email: a link with no token says so instead of showing a form that cannot succeed, and a link opened while already signed in as somebody else offers to log out rather than creating a second account for a person who is right there in the first one. The smoke test walks the whole invite: share a project, read the link out of the panel that shows it when there is no mail server, open it in a second browser context, create the account, and find the shared project in the sidebar. A second context and not a second page — inheriting the session would test the one case that never happens, which is what it did on the first run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
20 lines
719 B
Svelte
20 lines
719 B
Svelte
<script>
|
|
/**
|
|
* The address an invite link points at.
|
|
*
|
|
* It exists as a route because the server has been emailing this URL since
|
|
* invites were built, and until now nothing answered for it: the SPA fallback
|
|
* served the app shell, the shell found no session, and the recipient was shown
|
|
* a plain sign-in form for an account they did not have yet. A 200 the whole
|
|
* way, which is exactly how that class of bug hides here.
|
|
*
|
|
* The form is SignIn's: signing up from an invite is one branch of signing in,
|
|
* and it reads the token out of the URL itself.
|
|
*/
|
|
import SignIn from '$lib/components/SignIn.svelte';
|
|
</script>
|
|
|
|
<svelte:head><title>Invitation · verdande</title></svelte:head>
|
|
|
|
<SignIn />
|