feat(base): mending a broken SimpleLogin link with the handle and the recovery phrase (ADR 0020, D7)

Someone whose SimpleLogin identity is new to the register but who has an
account ("I already have one") names their handle and proves the
account's recovery phrase; the new identity takes the old one's place.

- `simpleLogin.beginMend(attempt, handle)`: the keys wrapped under the
  phrase's key, the public keys and a nonce, for the account with that
  handle (whatever its case). Only an account with keys and a SimpleLogin
  identity is mended, a link it had, as nobody adds SimpleLogin signed
  out (D10); a handle nobody has, or any other account's, gets a decoy
  from `signInDecoyKey`, the same each time. At most 10 an hour per
  handle and 30 per network.
- `simpleLogin.mend(attempt, proof)`: the phrase's proof for `mendLink`,
  binding the attempt (`mendLinkDigest`, on both sides), so a proof
  relayed from another sign-in links nobody's identity but the device's
  own; checked for the waiting identity first, which leaves the proof
  unspent. Every session of the account ends, in every service, and the
  sign-in stands ten minutes for a change, such as a lost password.
- SimpleLogin needs `SIGN_IN_DECOY_KEY` alone of ADR 0017's three keys
  (`signInDecoyKeyOf`); `addInstanceRoutes` stops a server with a
  SimpleLogin app and without it (`checkSimpleLoginMending`).
- Members ask the register for both; `RemoteRegister` and the instance
  API carry them.

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:26:58 +02:00
commit e5b9578916
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -44,7 +44,14 @@
password, a lost one with the phrase (`keys.beginPhrase`, `keys.resetPassword`), a new
phrase and the deletion (`account.delete`'s `keysProof`), each with the proof and the
sign-in, which the change takes: one change for each sign-in. A new or lost password
ends every other session, as ADR 0017's change does. The mending comes next.
ends every other session, as ADR 0017's change does. Then mending a broken link
(8, D7): `simpleLogin.beginMend(attempt, handle)` and `simpleLogin.mend(attempt,
proof)`, the phrase's proof binding the attempt, so a relayed proof links nobody
else's identity. Otherwise than proposed: only an account with a SimpleLogin identity
is mended (D10: nobody adds SimpleLogin signed out), every other answered with a
decoy; mending ends every session of the account, as whoever came in through the old
link may still be in; and SimpleLogin needs `SIGN_IN_DECOY_KEY` alone of ADR 0017's
three keys, a server with a SimpleLogin app and without it stopping as it starts.
- **Builds on:** ADR 0010 (email sign-in), ADR 0011 (profile pages), ADR 0016 (the
register), ADR 0017 (a password, TOTP and the keys).
- **Changes:** ADR 0017's way in on an instance that offers SimpleLogin (its keys, their