SimpleLoginRepository signs in with SimpleLogin in the browser
(OidcBrowser: the app's scheme on Android, iOS and macOS, the app's port
on the loopback on Linux and Windows, D9), then makes the account's keys
and signs someone new up, opens an account's keys with the password, gives
an account of before its first keys, or links a new SimpleLogin account in
place of a lost one with the recovery phrase (D7), which opens the keys on
the device first: a phrase that doesn't fit sends no proof, and no
password is asked after. An anonymous person adding SimpleLogin keeps the
keys their device holds. Nothing is the device's until `enter`.
SimpleLoginGateway calls halkyon_base's `simpleLogin` and `keys`
endpoints (ServerpodSimpleLoginGateway), with a fake for tests, as does
FakeOidcBrowser. The calls made on clients of their own (signed out, or as
a session not yet the device's) move from the password gateway into
BaseCalls, which both share.
Fixes BaseProtocol, the client of halkyon_base alone, which didn't read
halkyon_oidc's classes: every refusal of SimpleLogin's sign-in on a
signed-out call would have reached the app as a failure. OidcBrowser keeps
its loopback private, so that a fake can implement it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
`ContentCipher` makes a person's data keys, sealed to their account and
signed by it, opens them, and seals and opens a row's content with them for
the row it is stored in (`SodiumContentCipher`, on the isolate it is used
on, as rows are read and written one by one; `FakeContentCipher` for
tests). A sealed payload holds the signature, then the ciphertext.
`AccountCrypto.newDeviceKeys` makes the key pairs an anonymous person's
device encrypts their private studysets with (ADR 0017, point 9, not built
before); setting a password keeps them as the account's
(`keepingKeys` with a new phrase), so nothing they made private is lost.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
The recovery phrase, recovery codes and an authenticator's QR code and
key now show inside a SecretScreen: on Android it holds FLAG_SECURE while
it shows (through a channel each app's MainActivity answers, counting
holds, as several may show at once; ScreenGuard.kt), so screenshots,
screen recordings and the recents view don't get them; on iOS, which has
no such flag, it covers them while the app isn't in front, so the app
switcher's picture doesn't hold them (Dart-side, not checked on a device).
Desktops do neither: a window loses focus whenever its person turns to a
password manager. Todo's debug APK builds with it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
ADR 0017, step 3: halkyon_app's side, which Learn and Todo take.
- The account's cryptography on the device (`SodiumAccountCrypto`):
halkyon_keys and SRP's client half, each step on an isolate of its
own. sodium hands out results as views of native memory its
finalizers free once the isolate that made them ends, so everything
crossing back is copied first: a view read freed memory and crashed
the process.
- `PasswordGateway` on the module's endpoints (steps without a session
through a client holding none; an authenticator set up with a session
granted but not yet the device's), and `PasswordRepository` running
the flows: signing in (M2 checked, the keys opened before anything is
trusted), signing up, a password for someone signed in, an account
never finished, the authenticators, recovery codes, changing the
password, a new recovery phrase, and getting back in.
- The unlocked keys in the system's keyring per instance and person
(`SecureAccountKeyStore`), gone once another person signs in or
nobody, and with the instance's removal.
- The screens: the start screen's Sign in and Create an account (and
when GitHub sign-in ends), the sign-in sheet (codes, recovery codes,
an account never finished, a lost authenticator), the account's setup
(the recovery phrase shown once, three random words typed back before
anything reaches the instance; the authenticator's QR code, drawn
with pub.dev's qr; the recovery codes), getting back in, and the
account section (`AccountSecuritySection`).
- `FileSaver` moves from Learn into halkyon_app, for the phrase and the
codes in Todo too; `AppDependencies` names it and `passwords`.
- halkyon_keys rebuilds account keys from the secret keys a device kept;
the key proof's message is in halkyon_base_client, checked against
the register's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
What every Halkyon app's shell needs, taken from Halkyon Learn's and set
on halkyon_base's client: the instances a device keeps an account on,
the first start's tiles and where an instance keeps people's data, the
account switcher; signing in anonymously, with GitHub or an email code,
switching person and the start screen; the gates that build an app's
dependencies per instance and per person; and the sync service with its
status, Settings card and banner. Texts of its own in English and
German take the app's name; what only the app can say, it passes in.
Fakes for apps' tests are in testing.dart.
An instance's basics now name the app it serves (`app`, set by the
host's configuration), and an app accepts only an instance of its own.
SerialQueue and CoalescingRunner move into halkyon_core.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>