feat(base): the changes of SimpleLogin accounts' keys, each with the password and a fresh sign-in (ADR 0020, D20)

Every change takes the password's proof by its own proof key (the
recovery phrase's for a lost password) and a SimpleLogin sign-in of the
last ten minutes on the device (`KeysOwnerProof`, its attempt), as ADR
0017's take the password and a code. The sign-in is checked before the
proof and taken with the change, so a wrong proof leaves it standing and
each sign-in serves one change.

- `keys.set(attempt, setup, handle?)`: the first keys of an account that
  SimpleLogin was added to (anonymous before, or signing in with GitHub
  or a code), with the handle where it has none; the sign-in alone, as
  there is no password to prove yet.
- `keys.changePassword`, `keys.beginPhrase` and `keys.resetPassword` (a
  lost password, with the phrase): every other session ends, in every
  service, as ADR 0017's change has it.
- `keys.setRecoveryKeys`: a new phrase.
- `account.delete(keysProof)`: an account without SRP's verifier deletes
  itself with the proof and the sign-in; `requireOwnerToDelete` no longer
  asks such an account for SRP.
- `newKeysPasswordDigest` on both sides, held to each other by a test; a
  challenge purpose of its own for the phrase's proof while signed in.
- Members ask the register for all of it; `RemoteRegister` and the
  instance API carry the five new operations and the deletion's proof.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-23 22:11:49 +02:00
commit 7c58d23424
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -20,11 +20,11 @@ Endpoints, under the nickname `base` in a host's client (`client.modules.base.em
| `authenticator` | `enrol`, `confirm` (the first brings ten recovery codes; another takes a code from one confirmed before), `list`, `remove`, `newRecoveryCodes` | signed in |
| `accountRecovery` | `resetAuthenticator`, `beginKeyProof`, `resetPassword` (with the recovery phrase), `startAccountReset`, `completeAccountReset` | without a session |
| `simpleLogin` | `begin(platform)`: an attempt and SimpleLogin's address to open, at most 30 an hour per network; `complete(attempt, code)`: signed out, a session for the account with that SimpleLogin ID, or for someone new the handle suggested from their name; signed in, SimpleLogin added to the caller's account, who becomes `identified`; for an account, whether it has its keys and its handle, the attempt standing ten minutes for the sign-in; `checkHandle(attempt, handle)`: whether someone new could take a handle, at most 30 an hour per attempt and 60 per network; `signUp(attempt, handle, setup)`, without a session: someone new's account, `identified`, with the handle and the keys the device made; a session | anyone |
| `keys` | `begin`, `unlock`: the caller's keys for their device, once the password is proven with its own proof key (an account that signs in with SimpleLogin, Halkyon Learn's ADR 0020, D19); the tenth wrong proof in a row ends the session, as ADR 0017's do | signed in |
| `keys` | for an account that signs in with SimpleLogin (Halkyon Learn's ADR 0020, D19 and D20): `begin`, `unlock`: the caller's keys for their device, once the password is proven with its own proof key; `set`: the first keys (and handle) of an account SimpleLogin was added to, with a SimpleLogin sign-in of the last ten minutes; `changePassword`, `beginPhrase` and `resetPassword` (a lost password, with the recovery phrase), `setRecoveryKeys`: each with the password's proof (the phrase's) and such a sign-in (`KeysOwnerProof`), a new password ending every other session; the tenth wrong proof in a row ends the session, as ADR 0017's do | signed in |
| `gitHubUpgrade` | `upgrade`: links a GitHub account to the caller, who becomes `identified`; refused where passwords or SimpleLogin are offered (deprecated) | signed in |
| `gitHubSignIn` | `signIn`: a session for whoever has that GitHub account, unless they sign in with a password; none once `GITHUB_SIGN_IN_ENDS` has come | without a session |
| `emailCode` | `sendCode`: a code by mail, which proves the address and signs nobody in | anyone |
| `account` | `delete`, `signInWays` | signed in |
| `account` | `delete` (with the password's proof where the account has one, `keysProof` for one that signs in with SimpleLogin), `signInWays` | signed in |
| `instance` | `basics`: the app it serves, GitHub's client ID if any and when GitHub sign-in ends, whether codes by mail, password sign-in and SimpleLogin are on, the source link, the oldest app build, where data and backups are | anyone |
| `profile` | `mine`, `save`, `checkHandle`, `checkLinks` (at most 10 an hour), `setAvatar`, `removeAvatar`, `remove`: the caller's own public profile | `identified` |
| `profiles` | `byHandle`: anyone's public profile, whatever the handle's case | signed in |
@ -60,7 +60,9 @@ Endpoints, under the nickname `base` in a host's client (`client.modules.base.em
password's own proof key (Ed25519) in place of SRP's verifier (D19). The password
opens the keys and signs nobody in, so such an account has no authenticator (`enrol`
refuses it `noPassword`). A sign-in into an account keeps its attempt ten minutes
more, the account its caller: it confirms a change the device asks for next (D20).
more, the account its caller: it confirms a change the device asks for next (D20),
which takes it, so each sign-in serves one change. A change checks the sign-in before
the proof, and takes it with the change, so a wrong proof leaves it standing.
- SimpleLogin's forwarding page (Halkyon Learn's ADR 0020; `addSimpleLoginCallbackRoute`,
on the register, on halkyon_oidc's `addOidcCallbackForwarding`, ADR 0023):
`/simplelogin-callback`, the one address the instance's SimpleLogin