halkyon/packages/halkyon_app/lib/l10n/halkyon_app_localizations_en.dart

1164 lines
35 KiB
Dart
Raw Normal View History

// ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'halkyon_app_localizations.dart';
// ignore_for_file: type=lint
/// The translations for English (`en`).
class HalkyonAppLocalizationsEn extends HalkyonAppLocalizations {
HalkyonAppLocalizationsEn([String locale = 'en']) : super(locale);
@override
String get tryAgain => 'Try again';
@override
String instanceWelcome(String app) {
return 'Welcome to $app';
}
@override
String get instanceBuiltInTagline => 'Comes with the app';
@override
String get instanceAnother => 'Another instance';
@override
String get instanceAnotherTagline => 'Enter its address';
@override
String get instanceAddress => 'Instance address';
@override
String get instanceAddressInvalid => 'This isn\'t an address.';
@override
String instanceAddressInsecure(String app) {
return '$app reaches instances over HTTPS only, so that nobody on the way reads or changes what it sends. Ask for the instance\'s HTTPS address.';
}
@override
String instanceInsecure(String name, String app) {
return '$name is reached over plain HTTP, where anyone on the way could read and change what $app sends, so $app no longer opens it. Its account stays on $name and on this device. Use another instance, or remove it from this device.';
}
@override
String get instanceInsecureUseAnother => 'Use another instance';
@override
String get instanceInsecureRemove => 'Remove from this device';
@override
String get instanceAddressRequired => 'Enter the address of an instance.';
@override
String get instanceContinue => 'Continue';
@override
String instanceUnreachable(String app, String name) {
return 'No instance of $app answers at $name.';
}
@override
String instanceUseBuiltIn(String name) {
return 'Use $name';
}
@override
String instanceOpenFailed(String name) {
return 'Couldn\'t open the app on $name.';
}
@override
String instanceDataAndBackupsIn(String place) {
return 'Data and backups: $place';
}
@override
String instanceDataIn(String place) {
return 'Data: $place';
}
@override
String instanceBackupsIn(String place) {
return 'Backups: $place';
}
@override
String get instanceNoBackups => 'No backups';
@override
String get instanceEuropeanUnion => 'European Union';
@override
String instanceCountryInEu(String country) {
return '$country (EU)';
}
@override
String instanceSubdivisionOf(String subdivision, String country) {
return '$subdivision, $country';
}
@override
String get accountsTitle => 'Accounts';
@override
String get accountAdd => 'Add account';
@override
String get accountAddSubtitle =>
'Choose the instance for the account to add.';
@override
String get accountSignedIn => 'Signed in';
@override
String get accountRemoveTooltip => 'Remove account';
@override
String get accountRemoveTitle => 'Remove account?';
@override
String accountRemoveMessage(String name) {
return 'Removes the account on $name from this device, with all the device holds of it. What it synced stays on $name: sign in there again to have it.';
}
@override
String get accountRemoveConfirm => 'Remove';
@override
String accountSignedInOn(String instance) {
return 'Signed in on $instance';
}
@override
String get accountSwitch => 'Switch account';
@override
String get accountSignOut => 'Sign out';
@override
String get accountDelete => 'Delete account';
@override
String get accountDeleteTitle => 'Delete your account?';
@override
String get accountSignOutFailed =>
'Couldn\'t sign out on this device. Try again.';
@override
String get accountDeleteFailed =>
'Couldn\'t delete your account: the instance wasn\'t reached. Try again.';
@override
String get aboutSourceCode => 'The source of what this instance runs:';
@override
String get aboutSourceUnreachable =>
'Couldn\'t reach this instance to ask where its source is.';
@override
String get sessionUnreachable => 'Couldn\'t reach the server.';
@override
String get personDataFailed => 'Couldn\'t open this device\'s data.';
@override
String get startSignedOut => 'Signed out';
@override
String startOn(String instance) {
return 'Start on $instance:';
}
@override
String get startOtherInstance => 'Use another instance';
@override
String startNoWay(String instance) {
return '$instance offers no way to create an account.';
}
@override
String startSignUpsApproved(String instance) {
return 'New accounts on $instance wait until its operator approves them.';
}
@override
String startSignUpsClosed(String instance) {
return '$instance takes no new accounts: sign in with yours.';
}
@override
String get syncTitle => 'Sync';
@override
String get syncNow => 'Sync now';
@override
String get syncStateSyncing => 'Syncing…';
@override
String get syncStateSynced => 'Everything synced';
@override
String get syncStateFailing => 'Sync is failing';
@override
String get syncStateNotYet => 'Not synced yet';
@override
String syncStateMismatch(String server) {
return 'This app can\'t sync with $server';
}
@override
String get syncMismatchDetail =>
'Update the app. If it is up to date, the server needs an update. What you do meanwhile stays on this device and syncs afterwards.';
@override
String syncLastCompleted(String time) {
return 'Last completed at $time';
}
@override
String syncLastFailed(String time) {
return 'Last attempt failed at $time';
}
@override
String get syncNoRunYet => 'No sync has completed since the app started';
@override
String syncPending(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count changes wait to sync',
one: '1 change waits to sync',
);
return '$_temp0';
}
@override
String get syncTroubleLabel => 'Sync needs attention';
@override
String syncMismatchBanner(String server) {
return 'This app can\'t sync with $server any more. Update it to keep syncing.';
}
@override
String get syncMismatchMore => 'More';
feat(app): sign in with a password and TOTP on the device 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>
2026-10-20 15:42:45 +02:00
@override
String get startSignIn => 'Sign in';
@override
String get startCreateAccount => 'Create an account';
@override
String waitWaiting(String instance) {
return 'Your account waits until the operator of $instance approves it.';
}
@override
String waitSuspended(String instance) {
return 'The operator of $instance has suspended your account. Only they can lift it.';
}
@override
String waitApproved(String instance) {
return 'The operator of $instance has approved your account. Sign in once more, as you did before.';
}
@override
String waitEnded(String instance) {
return 'This sign-up has ended: the operator of $instance refused it, or it waited too long.';
}
@override
String get waitBack => 'Back to the start';
@override
String get waitMatchingCode => 'Matching code';
@override
String waitMatchingNote(String instance) {
return 'When the operator of $instance reads you four words, check that they are these. Never read them out yourself: Halkyon never asks anyone to.';
}
@override
String get waitCheckNow => 'Check now';
@override
String waitUnreachable(String instance) {
return '$instance couldn\'t be reached. It\'s asked again every 30 seconds.';
}
@override
String get waitDelete => 'Delete this account';
@override
String get waitDeleteTitle => 'Delete this account?';
@override
String get waitDeleteMessage =>
'It goes with everything it has, and nobody can sign in to it again.';
@override
String get waitDeleteFailed => 'Couldn\'t delete the account. Try again.';
feat(app): sign in with a password and TOTP on the device 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>
2026-10-20 15:42:45 +02:00
@override
String get passwordAddress => 'Email address';
@override
String get passwordPassword => 'Password';
@override
String get passwordNewPassword => 'New password';
@override
String get passwordCurrent => 'Current password';
@override
String get passwordRepeat => 'New password again';
@override
String get passwordsDiffer => 'The two passwords differ.';
@override
String get passwordShow => 'Show password';
@override
String get passwordHide => 'Hide password';
@override
String get passwordContinue => 'Continue';
@override
String get passwordBack => 'Back';
@override
String get passwordDone => 'Done';
@override
String get passwordSave => 'Save as a file';
@override
String get passwordQrCode => 'QR code for your authenticator app';
@override
String get passwordMailCode => 'Code from the email';
@override
String passwordMailCodeSent(String address) {
return 'We emailed a code to $address. It\'s valid for 15 minutes.';
}
feat(base)!: a handle at password sign-up (ADR 0020, D26, D28–D30) Every new account gets a handle, and an account without one gets its first as it sets a password. The handle is private until its person goes public (D5). - `passwordSignIn.signUp` takes a handle. `passwordSignIn.checkHandle` says whether a sign-up could take one, only while that sign-up's mailed code waits (`codeExpired` otherwise), counted per code request (30 an hour) and per network (60) (D29). Members ask the register. - `password.set` takes the first handle of an account without one (D28); `SignInWays.handle` tells the app whether there is one. - Each checks the handle before the code is used, so a refusal leaves the code for another try. An existing account at the address keeps its own handle where it has one, and the typed handle is still checked, so the answer says nothing about the address. - `first_handle.dart` holds what SimpleLogin, the keys and passwords share: `refusalOfNewHandle`, `insertFirstProfile`, `hasHandle`. - halkyon_app: one `HandleField` with its `HandleCheckCubit` (asked 300 ms after typing pauses, only about the handle typed last; the instance's suggestion is free without asking) (D30). The password setup asks for the handle between the phrase check and the code, and a refusal at the code sends back to it. SimpleLogin's sign-up and keys steps use the same field and now check as it is typed. - The module's README and ADR 0020 (D29, D30, the built state) amended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 18:09:04 +02:00
@override
String passwordHandleIntro(String address) {
return 'A code is on its way to $address. Meanwhile, choose your handle: others find you by it. It stays private until you publish something or fill in your profile, and can change until your first publish.';
}
feat(app): sign in with a password and TOTP on the device 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>
2026-10-20 15:42:45 +02:00
@override
String get passwordResendCode => 'Send a new code';
@override
String get passwordTotpCode => 'Code from your authenticator app';
@override
String get passwordRecoveryCode => 'Recovery code';
@override
String get passwordUseRecoveryCode => 'Use a recovery code instead';
@override
String get passwordUseTotpCode => 'Use your authenticator app instead';
@override
String get passwordUnlocking => 'Unlocking your password on this device…';
@override
String get passwordMakingKeys => 'Making your keys on this device…';
@override
String get passwordSignInTitle => 'Sign in';
@override
String get passwordSignInAction => 'Sign in';
@override
String passwordSignInIntro(String instance) {
return 'With the email address and password of your account on $instance.';
}
@override
String passwordSecondFactorIntro(String instance) {
return 'Enter the code your authenticator app shows for $instance.';
}
@override
String get passwordRecoveryCodeIntro =>
'Enter one of the recovery codes you kept. Each signs in once.';
@override
String get passwordForgot => 'Forgot your password?';
@override
String get passwordOtherPassword => 'Change the address or password';
@override
String get passwordLostAuthenticator => 'Lost your authenticator?';
@override
String get passwordLostAuthenticatorTitle => 'Lost authenticator';
@override
String get passwordLostAuthenticatorIntro =>
'With a recovery code you sign in as usual. Without one, ask to reset your authenticators: it takes effect 72 hours later, and signing in with a code before then stops it.';
@override
String get passwordResetWithMail => 'Reset with a code by email';
@override
String passwordResetWithMailHint(String address) {
return 'We email a code to $address.';
}
@override
String get passwordResetWithPhrase => 'Reset with your recovery phrase';
@override
String get passwordResetWithPhraseHint => 'The 24 words you wrote down.';
@override
String get passwordSignInWithoutCode => 'Sign in without a code';
@override
String get passwordSignInWithoutCodeHint =>
'Once a reset you asked for has taken effect.';
@override
String get passwordResetAction => 'Reset';
@override
String passwordAuthenticatorResetAt(String date) {
return 'Your authenticators are reset on $date. We emailed you: if it wasn\'t you, sign in with a code before then to stop it. After that, sign in with your password alone and set up a new authenticator.';
}
@override
String passwordUnfinishedIntro(String address) {
return 'Your account was never finished. We emailed a code to $address: with it, you sign in and set up an authenticator.';
}
@override
String get passwordPhraseField => 'Recovery phrase';
@override
String get passwordPhraseFieldHint =>
'The 24 words, with spaces between them';
@override
String get passwordPhraseFieldIntro =>
'Enter your recovery phrase: it proves the account is yours.';
@override
String get passwordAuthenticatorTitle => 'Set up an authenticator';
@override
String get passwordAuthenticatorIntro =>
'Every sign-in takes a code from an authenticator app, such as Aegis, 2FAS or Proton Authenticator. Scan this code with it, or type in the key.';
@override
String get passwordAuthenticatorKey => 'Key';
@override
String get passwordAuthenticatorOpen => 'Open in your authenticator app';
@override
String get passwordAuthenticatorNoApp =>
'No app on this device opens it. Scan the code or type in the key.';
@override
String get passwordAuthenticatorCodeIntro => 'Then enter the code it shows.';
@override
String get passwordAuthenticatorOwnerIntro =>
'To add it, confirm it is you: your password and a code from an authenticator you added before.';
feat(app): sign in with a password and TOTP on the device 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>
2026-10-20 15:42:45 +02:00
@override
String get passwordExistingCode =>
'Code from an authenticator you added before';
@override
String get passwordRecoveryCodesTitle => 'Recovery codes';
@override
String get passwordRecoveryCodesIntro =>
'Each signs in once in place of a code from your authenticator, should you lose it. Keep them where only you find them: they\'re shown only now.';
@override
String get passwordCodesKept => 'I\'ve kept them';
@override
String get passwordPhraseTitle => 'Your recovery phrase';
@override
String get passwordPhraseIntro =>
'These 24 words open your account\'s keys should you forget your password: without them, what\'s encrypted is lost. Write them down in order, and keep them where only you find them. They\'re shown only now.';
@override
String get passwordPhraseWrittenDown => 'I\'ve written it down';
@override
String get passwordPhraseCheckTitle => 'Check your recovery phrase';
@override
String get passwordPhraseCheckIntro =>
'Type the words asked for, from what you wrote down.';
@override
String passwordPhraseWord(int number) {
return 'Word $number';
}
@override
String get passwordPhraseWrong =>
'These aren\'t the words. Look again at what you wrote down.';
@override
String get passwordPhraseShowAgain => 'Show the phrase again';
@override
String get passwordCreateTitle => 'Create an account';
@override
String passwordCreateIntro(String instance) {
return 'On $instance, with your email address, a password, and an authenticator app for the code every sign-in takes.';
}
@override
String get passwordSetUpTitle => 'Set up a password';
@override
String get passwordSetUpIntro =>
'Sign in with your email address, a password and an authenticator app, on this device and others. Everything you have stays.';
@override
String get passwordChooseIntro =>
'Choose a password. It never leaves this device: the instance can\'t read it, and can\'t reset it without what it protects being lost.';
@override
String get passwordFinishResetTitle => 'Finish the reset';
@override
String get passwordFinishResetIntro =>
'72 hours after you asked to reset your account, finish it here with a new code by email.';
@override
String get passwordFinishResetHavePhrase => 'I have my recovery phrase';
@override
String get passwordFinishResetKeepsKeys =>
'Your account keeps its keys: nothing encrypted is lost.';
@override
String get passwordFinishResetNewKeys =>
'Without your recovery phrase, your account gets new keys: what was encrypted with the old ones is lost.';
@override
String get passwordRecoveryTitle => 'Get back into your account';
@override
String get passwordRecoveryWithPhrase => 'I have my recovery phrase';
@override
String get passwordRecoveryWithPhraseHint =>
'Set a new password at once. Everything stays.';
@override
String get passwordRecoveryWithPhraseIntro =>
'Your recovery phrase opens your account\'s keys, which your new password then protects. A code from your authenticator, or a recovery code, confirms it.';
@override
String get passwordRecoveryNoCodeHint =>
'Lost your authenticator as well? Reset your account 72 hours later with your recovery phrase: it keeps everything.';
@override
String get passwordRecoveryWithoutPhrase => 'Reset my account';
@override
String get passwordRecoveryWithoutPhraseHint =>
'Takes effect 72 hours later. Without your recovery phrase, what\'s encrypted is lost.';
@override
String get passwordRecoveryStartIntro =>
'We email a code to your address. Your account can then be reset 72 hours later; signing in with your password before then stops it.';
@override
String get passwordRecoveryFinish => 'Finish a reset';
@override
String get passwordRecoveryFinishHint => '72 hours after you asked for it.';
@override
String passwordResetStarted(String date) {
return 'Your account can be reset from $date. We emailed you: if it wasn\'t you, sign in with your password before then to stop it.';
}
@override
String get passwordSectionTitle => 'Password and authenticator';
@override
String get passwordSectionFailed =>
'Couldn\'t read how your account signs in.';
@override
String get passwordSectionSetUp => 'Set up a password';
@override
String get passwordSectionSetUpHint =>
'Sign in with your email address, a password and an authenticator app.';
@override
String get passwordSectionUnfinished =>
'Finish setting up: add an authenticator';
@override
String get passwordSectionUnfinishedHint =>
'Your password signs in once an authenticator is set up.';
@override
String get passwordSectionChange => 'Change password';
@override
String get passwordSectionKeysMissing =>
'Sign in on this device with your password to change it.';
@override
String get passwordSectionNotConfirmed => 'Not set up yet';
@override
String passwordSectionRemove(String name) {
return 'Remove $name?';
}
@override
String get passwordSectionRemoveIntro =>
'Enter your password and a code from one of your authenticators to confirm.';
feat(app): sign in with a password and TOTP on the device 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>
2026-10-20 15:42:45 +02:00
@override
String get passwordSectionRemoveAction => 'Remove';
@override
String get passwordSectionAddAuthenticator => 'Add an authenticator';
@override
String get passwordSectionRecoveryCodes => 'New recovery codes';
@override
String get passwordSectionRecoveryCodesHint => 'The old ones stop working.';
@override
String get passwordSectionNewPhrase => 'New recovery phrase';
@override
String get passwordSectionPhraseHint => 'Your old phrase stops working.';
@override
String get passwordChangeTitle => 'Change password';
@override
String get passwordChangeIntro =>
'Your other devices are signed out. Your keys stay: nothing is lost.';
@override
String get passwordChangeAction => 'Change password';
@override
String get passwordChanged =>
'Password changed. Your other devices are signed out.';
@override
String get passwordNewCodesIntro =>
'Enter your password and a code from your authenticator app. Your old recovery codes stop working.';
feat(app): sign in with a password and TOTP on the device 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>
2026-10-20 15:42:45 +02:00
@override
String get passwordNewPhraseIntro =>
'Your new recovery phrase. Write the 24 words down in order: once you confirm it, your old phrase opens nothing any more.';
@override
String get passwordPhraseKept =>
'New recovery phrase set. The old one no longer works.';
@override
String get passwordWrongCredentials =>
'The address, the password or the code isn\'t right.';
@override
String get passwordTooManyAttempts =>
'Too many attempts. Try again in an hour.';
@override
String get passwordSetupIncomplete =>
'Your account was never finished: set up an authenticator.';
@override
String passwordNotDue(String date) {
return 'This takes effect on $date.';
}
@override
String get passwordNotDueYet => 'This hasn\'t taken effect yet.';
@override
String get passwordNoReset => 'No reset waits for this address.';
@override
String get passwordExists =>
'This address\'s account has a password already. Sign in with it, or get back in if you\'ve forgotten it.';
@override
String get passwordAddressTaken => 'This address belongs to another account.';
@override
String get passwordNoPassword => 'This account has no password.';
@override
String get passwordWrongCode =>
'This code isn\'t right. Enter the one your app shows now.';
@override
String get passwordLastAuthenticator =>
'Your last authenticator can\'t go: every sign-in needs one.';
@override
String get passwordTooManyAuthenticators =>
'Your account has as many authenticators as it may. Remove one first.';
@override
String get passwordUnknownAuthenticator => 'This authenticator is gone.';
@override
String get passwordInvalidSetup =>
'The instance didn\'t accept what this device made. Update the app, or try again.';
@override
String get passwordChallengeExpired => 'That took too long. Try again.';
@override
String get passwordUnavailable => 'This instance offers no password sign-in.';
@override
String get passwordNotAnAddress => 'This isn\'t an email address.';
@override
String get passwordTooManyCodes =>
'Too many codes asked for. Try again in an hour.';
@override
String get passwordWrongMailCode => 'This code isn\'t right.';
@override
String get passwordTooManyMailTries =>
'Too many wrong codes. Ask for a new one.';
@override
String get passwordMailCodeExpired =>
'This code is no longer valid. Ask for a new one.';
@override
String get passwordMailFailed =>
'The instance couldn\'t send the email. Try again later.';
@override
String get passwordOtherAddressLinked =>
'Your account has another email address.';
@override
String get passwordNotAPhrase =>
'This isn\'t a recovery phrase: check every word and their number.';
@override
String get passwordPhraseDoesNotFit =>
'The address or the recovery phrase isn\'t right.';
@override
String get passwordUnusable =>
'This password can\'t be used: it\'s empty, or holds characters that aren\'t text.';
@override
String get passwordInstanceUnproven =>
'The instance couldn\'t prove it knows your password, so this device trusts nothing it says. Try again; if it happens again, the instance isn\'t the one it claims to be.';
@override
String get passwordKeysMissing =>
'Your account\'s keys aren\'t on this device. Sign out and in again with your password here.';
@override
String get signUpsClosed => 'This instance takes no new accounts.';
@override
String get signUpsTooManyWaiting =>
'As many new accounts wait for approval as may. Try again later.';
@override
String get passwordUnsafeCosts =>
'The instance asked for your password to be checked in a way no account uses, so nothing was sent. If it happens again, the instance isn\'t the one it claims to be.';
feat(app): sign in with a password and TOTP on the device 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>
2026-10-20 15:42:45 +02:00
@override
String get passwordFailed =>
'Couldn\'t reach the instance. Check the connection and try again.';
@override
String passwordMinLength(int count) {
return 'At least $count characters';
}
@override
String passwordTooShort(int count) {
return 'A new password needs at least $count characters: should the instance\'s database ever leak, a short one is guessed first.';
}
fix(auth): codes wait after ten wrong in a row, and the owner is told Whoever knew the password could guess codes at 10 an hour forever, unnoticed, each guess checked against every authenticator (the second reading's M4). Every code an account's second factor refuses after a right password (sign-in, a phrase's reset, a change) or from a signed-in device (removing an authenticator, new recovery codes, the code from one confirmed before) now counts, per account, from every network; after every tenth in a row no code is taken (codesWait, saying until when), an hour, then twice as long each time, a day at the most (longestCodeWait, second_factor_waits.dart): at a day, ten guesses a day still have about a 1 % chance a year against one authenticator, so the first wait mails the owner that someone knows their password. The instance keeps no address, so sign-in and the phrase's reset now send the address the device typed (and its language), used only for that mail after its hash is checked against the account's. A code accepted clears it all. Migration (module, Learn's and Todo's servers, Learn's device schema): CREATE TABLE "second_factor_failures" ("id" bigserial PRIMARY KEY, "authUserId" uuid NOT NULL, "failures" bigint NOT NULL, "waits" bigint NOT NULL, "waitUntil" timestamp, "updatedAt" timestamp NOT NULL) with a unique index on "authUserId": a new table, nothing touched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-20 21:47:38 +02:00
@override
String passwordCodesWait(String date) {
return 'Too many wrong codes in a row: no code is taken until $date. If they weren\'t yours, someone knows your password: change it then.';
}
@override
String get passwordDeleteIntro =>
'Your account goes with everything in it, in every service of this instance. To confirm, type your password and a code from your authenticator app.';
fix(auth): a session's wrong codes end the session, not the account's codes Wrong codes for removing an authenticator, new recovery codes or confirming one counted toward the account's waits (the re-review's third finding): a stolen session alone, without the password, could keep the owner's codes waiting for up to a day at a time, renewed without end, holding them out of signing in and of changing the password, the way to end that session, and nobody was mailed. Those codes now count per session, where the session is (the register's own, or a member's, which forwards the code): each try counted before its code is checked (one statement, so tries sent at once count each), a code accepted clearing the count, and the tenth wrong in a row ending the session (sessionEnded; the device says it was signed out). A try that checked no code (a refusal of something else) is taken back. The account's waits now count only codes after a right password, and the per-account ten tries an hour, which a session could fill as well, go. Migration (module, Learn's and Todo's servers, Learn's device schema): CREATE TABLE "session_code_failures" ("id" bigserial PRIMARY KEY, "sessionId" uuid NOT NULL, "authUserId" uuid NOT NULL, "failures" bigint NOT NULL, "updatedAt" timestamp NOT NULL) with a unique index on "sessionId": a new table, nothing touched. Its rows go with a code accepted, with the person, and hourly once their session is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-20 22:53:20 +02:00
@override
String get passwordSessionEnded =>
'Too many wrong codes in a row from this device: it was signed out. Sign in again with your password and a code.';
@override
String get passwordAddressUnknown =>
'Enter your account\'s email address: the code goes there.';
@override
String get passwordDeleteIntroByMail =>
'Your account goes with everything in it, in every service of this instance. None of its authenticators works now, so a code by mail confirms it: type your password, then the code we email to your address.';
@override
String get passwordDeleteSendCode => 'Email me a code';
@override
String get passwordAuthenticatorPasswordIntro =>
'To add it, confirm it is you with your password.';
@override
String get passwordWarningTitle => 'Someone tried your password';
@override
String passwordWarningBody(String date) {
return 'On $date, a device signed in to your account sent a wrong password or code ten times in a row, and was signed out. If that wasn\'t you, someone else may have that device or its session: change your password.';
}
@override
String get passwordWarningDismiss => 'Dismiss';
@override
String get passwordWarningLater => 'Remind me later';
@override
String get passwordResetsTitle => 'A reset is waiting';
@override
String passwordResetsAuthenticator(String date) {
return 'Your authenticators will be removed on $date: someone asked with your password. If that wasn\'t you, call it off and change your password.';
}
@override
String passwordResetsAccount(String date) {
return 'Your account will get a new password and new keys on $date, and what is encrypted under the old ones will be lost: someone asked with a code by mail. If that wasn\'t you, call it off.';
}
@override
String get passwordResetsCallOff => 'Call it off';
@override
String get passwordCallOffTitle => 'Call off the reset';
@override
String get passwordCallOffIntro =>
'Your password and a code call off every reset waiting.';
@override
String get passwordSignedInBefore =>
'Only a device signed in since then can dismiss this warning: sign in again on this one, or change your password.';
feat(app): signing in with SimpleLogin, its sheet and the start screen's offer (ADR 0020) Where the instance offers SimpleLogin, the start screen offers it first, saying that the instance keeps only the SimpleLogin ID, and opens a sheet that waits for SimpleLogin's page in the browser (Cancel ends the wait), then: for someone new, the choice between creating an account (the suggested handle or another, checked with the instance, the password twice, the recovery phrase shown once and three of its words typed back, nothing reaching the instance before) and linking theirs again with its handle and recovery phrase; for an account, its password opening its keys; for an account of before, the keys made with the handle it lacks. SimpleLoginCubit holds the steps, each refusal shown where it is mended (a handle's on the handle, a sign-in to begin again on the browser's), and closing the sheet stops waiting on the loopback. The suggested handle is never checked: the instance suggests none that anybody has, and every answer about a handle counts against its limit (D5). The fake's handle rule is now the module's. Learn and Todo build it with SimpleLogin's browser (halkyon_oidc_flutter, now a direct dependency of both, with their names on the loopback's page), their schemes and their loopback ports (43823, 43824), as the instance's forwarding page has them. Their tests offer no SimpleLogin; halkyon_app's test the sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 01:21:29 +02:00
@override
String get simpleLoginContinue => 'Continue with SimpleLogin';
@override
String simpleLoginNote(String instance) {
return 'SimpleLogin is Proton\'s sign-in, and a Proton account works there too. It learns that you use $instance, which keeps only your SimpleLogin ID: your name suggests a handle once, and nothing else is kept.';
}
@override
String get simpleLoginTitle => 'Sign in with SimpleLogin';
@override
String get simpleLoginAddTitle => 'Add SimpleLogin';
@override
String get simpleLoginInBrowser => 'Continue in your browser.';
@override
String get simpleLoginNewcomerTitle => 'New here?';
@override
String simpleLoginNewcomerIntro(String instance) {
return 'Your SimpleLogin account has no account on $instance yet.';
}
@override
String get simpleLoginCreateHint =>
'Choose a handle and a password; you get a recovery phrase.';
@override
String get simpleLoginHaveOne => 'I already have one';
@override
String get simpleLoginHaveOneHint =>
'Link it again with your handle and your recovery phrase.';
@override
feat(base)!: a handle at password sign-up (ADR 0020, D26, D28–D30) Every new account gets a handle, and an account without one gets its first as it sets a password. The handle is private until its person goes public (D5). - `passwordSignIn.signUp` takes a handle. `passwordSignIn.checkHandle` says whether a sign-up could take one, only while that sign-up's mailed code waits (`codeExpired` otherwise), counted per code request (30 an hour) and per network (60) (D29). Members ask the register. - `password.set` takes the first handle of an account without one (D28); `SignInWays.handle` tells the app whether there is one. - Each checks the handle before the code is used, so a refusal leaves the code for another try. An existing account at the address keeps its own handle where it has one, and the typed handle is still checked, so the answer says nothing about the address. - `first_handle.dart` holds what SimpleLogin, the keys and passwords share: `refusalOfNewHandle`, `insertFirstProfile`, `hasHandle`. - halkyon_app: one `HandleField` with its `HandleCheckCubit` (asked 300 ms after typing pauses, only about the handle typed last; the instance's suggestion is free without asking) (D30). The password setup asks for the handle between the phrase check and the code, and a refusal at the code sends back to it. SimpleLogin's sign-up and keys steps use the same field and now check as it is typed. - The module's README and ADR 0020 (D29, D30, the built state) amended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 18:09:04 +02:00
String get handleIntro =>
feat(app): signing in with SimpleLogin, its sheet and the start screen's offer (ADR 0020) Where the instance offers SimpleLogin, the start screen offers it first, saying that the instance keeps only the SimpleLogin ID, and opens a sheet that waits for SimpleLogin's page in the browser (Cancel ends the wait), then: for someone new, the choice between creating an account (the suggested handle or another, checked with the instance, the password twice, the recovery phrase shown once and three of its words typed back, nothing reaching the instance before) and linking theirs again with its handle and recovery phrase; for an account, its password opening its keys; for an account of before, the keys made with the handle it lacks. SimpleLoginCubit holds the steps, each refusal shown where it is mended (a handle's on the handle, a sign-in to begin again on the browser's), and closing the sheet stops waiting on the loopback. The suggested handle is never checked: the instance suggests none that anybody has, and every answer about a handle counts against its limit (D5). The fake's handle rule is now the module's. Learn and Todo build it with SimpleLogin's browser (halkyon_oidc_flutter, now a direct dependency of both, with their names on the loopback's page), their schemes and their loopback ports (43823, 43824), as the instance's forwarding page has them. Their tests offer no SimpleLogin; halkyon_app's test the sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 01:21:29 +02:00
'Others find you by your handle. It stays private until you publish something or fill in your profile, and can change until your first publish.';
@override
feat(base)!: a handle at password sign-up (ADR 0020, D26, D28–D30) Every new account gets a handle, and an account without one gets its first as it sets a password. The handle is private until its person goes public (D5). - `passwordSignIn.signUp` takes a handle. `passwordSignIn.checkHandle` says whether a sign-up could take one, only while that sign-up's mailed code waits (`codeExpired` otherwise), counted per code request (30 an hour) and per network (60) (D29). Members ask the register. - `password.set` takes the first handle of an account without one (D28); `SignInWays.handle` tells the app whether there is one. - Each checks the handle before the code is used, so a refusal leaves the code for another try. An existing account at the address keeps its own handle where it has one, and the typed handle is still checked, so the answer says nothing about the address. - `first_handle.dart` holds what SimpleLogin, the keys and passwords share: `refusalOfNewHandle`, `insertFirstProfile`, `hasHandle`. - halkyon_app: one `HandleField` with its `HandleCheckCubit` (asked 300 ms after typing pauses, only about the handle typed last; the instance's suggestion is free without asking) (D30). The password setup asks for the handle between the phrase check and the code, and a refusal at the code sends back to it. SimpleLogin's sign-up and keys steps use the same field and now check as it is typed. - The module's README and ADR 0020 (D29, D30, the built state) amended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 18:09:04 +02:00
String get handleLabel => 'Handle';
feat(app): signing in with SimpleLogin, its sheet and the start screen's offer (ADR 0020) Where the instance offers SimpleLogin, the start screen offers it first, saying that the instance keeps only the SimpleLogin ID, and opens a sheet that waits for SimpleLogin's page in the browser (Cancel ends the wait), then: for someone new, the choice between creating an account (the suggested handle or another, checked with the instance, the password twice, the recovery phrase shown once and three of its words typed back, nothing reaching the instance before) and linking theirs again with its handle and recovery phrase; for an account, its password opening its keys; for an account of before, the keys made with the handle it lacks. SimpleLoginCubit holds the steps, each refusal shown where it is mended (a handle's on the handle, a sign-in to begin again on the browser's), and closing the sheet stops waiting on the loopback. The suggested handle is never checked: the instance suggests none that anybody has, and every answer about a handle counts against its limit (D5). The fake's handle rule is now the module's. Learn and Todo build it with SimpleLogin's browser (halkyon_oidc_flutter, now a direct dependency of both, with their names on the loopback's page), their schemes and their loopback ports (43823, 43824), as the instance's forwarding page has them. Their tests offer no SimpleLogin; halkyon_app's test the sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 01:21:29 +02:00
@override
feat(base)!: a handle at password sign-up (ADR 0020, D26, D28–D30) Every new account gets a handle, and an account without one gets its first as it sets a password. The handle is private until its person goes public (D5). - `passwordSignIn.signUp` takes a handle. `passwordSignIn.checkHandle` says whether a sign-up could take one, only while that sign-up's mailed code waits (`codeExpired` otherwise), counted per code request (30 an hour) and per network (60) (D29). Members ask the register. - `password.set` takes the first handle of an account without one (D28); `SignInWays.handle` tells the app whether there is one. - Each checks the handle before the code is used, so a refusal leaves the code for another try. An existing account at the address keeps its own handle where it has one, and the typed handle is still checked, so the answer says nothing about the address. - `first_handle.dart` holds what SimpleLogin, the keys and passwords share: `refusalOfNewHandle`, `insertFirstProfile`, `hasHandle`. - halkyon_app: one `HandleField` with its `HandleCheckCubit` (asked 300 ms after typing pauses, only about the handle typed last; the instance's suggestion is free without asking) (D30). The password setup asks for the handle between the phrase check and the code, and a refusal at the code sends back to it. SimpleLogin's sign-up and keys steps use the same field and now check as it is typed. - The module's README and ADR 0020 (D29, D30, the built state) amended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 18:09:04 +02:00
String handleFree(String handle) {
feat(app): signing in with SimpleLogin, its sheet and the start screen's offer (ADR 0020) Where the instance offers SimpleLogin, the start screen offers it first, saying that the instance keeps only the SimpleLogin ID, and opens a sheet that waits for SimpleLogin's page in the browser (Cancel ends the wait), then: for someone new, the choice between creating an account (the suggested handle or another, checked with the instance, the password twice, the recovery phrase shown once and three of its words typed back, nothing reaching the instance before) and linking theirs again with its handle and recovery phrase; for an account, its password opening its keys; for an account of before, the keys made with the handle it lacks. SimpleLoginCubit holds the steps, each refusal shown where it is mended (a handle's on the handle, a sign-in to begin again on the browser's), and closing the sheet stops waiting on the loopback. The suggested handle is never checked: the instance suggests none that anybody has, and every answer about a handle counts against its limit (D5). The fake's handle rule is now the module's. Learn and Todo build it with SimpleLogin's browser (halkyon_oidc_flutter, now a direct dependency of both, with their names on the loopback's page), their schemes and their loopback ports (43823, 43824), as the instance's forwarding page has them. Their tests offer no SimpleLogin; halkyon_app's test the sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 01:21:29 +02:00
return '@$handle is free';
}
feat(base)!: a handle at password sign-up (ADR 0020, D26, D28–D30) Every new account gets a handle, and an account without one gets its first as it sets a password. The handle is private until its person goes public (D5). - `passwordSignIn.signUp` takes a handle. `passwordSignIn.checkHandle` says whether a sign-up could take one, only while that sign-up's mailed code waits (`codeExpired` otherwise), counted per code request (30 an hour) and per network (60) (D29). Members ask the register. - `password.set` takes the first handle of an account without one (D28); `SignInWays.handle` tells the app whether there is one. - Each checks the handle before the code is used, so a refusal leaves the code for another try. An existing account at the address keeps its own handle where it has one, and the typed handle is still checked, so the answer says nothing about the address. - `first_handle.dart` holds what SimpleLogin, the keys and passwords share: `refusalOfNewHandle`, `insertFirstProfile`, `hasHandle`. - halkyon_app: one `HandleField` with its `HandleCheckCubit` (asked 300 ms after typing pauses, only about the handle typed last; the instance's suggestion is free without asking) (D30). The password setup asks for the handle between the phrase check and the code, and a refusal at the code sends back to it. SimpleLogin's sign-up and keys steps use the same field and now check as it is typed. - The module's README and ADR 0020 (D29, D30, the built state) amended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 18:09:04 +02:00
@override
String get handleChecking => 'Checking…';
feat(app): signing in with SimpleLogin, its sheet and the start screen's offer (ADR 0020) Where the instance offers SimpleLogin, the start screen offers it first, saying that the instance keeps only the SimpleLogin ID, and opens a sheet that waits for SimpleLogin's page in the browser (Cancel ends the wait), then: for someone new, the choice between creating an account (the suggested handle or another, checked with the instance, the password twice, the recovery phrase shown once and three of its words typed back, nothing reaching the instance before) and linking theirs again with its handle and recovery phrase; for an account, its password opening its keys; for an account of before, the keys made with the handle it lacks. SimpleLoginCubit holds the steps, each refusal shown where it is mended (a handle's on the handle, a sign-in to begin again on the browser's), and closing the sheet stops waiting on the loopback. The suggested handle is never checked: the instance suggests none that anybody has, and every answer about a handle counts against its limit (D5). The fake's handle rule is now the module's. Learn and Todo build it with SimpleLogin's browser (halkyon_oidc_flutter, now a direct dependency of both, with their names on the loopback's page), their schemes and their loopback ports (43823, 43824), as the instance's forwarding page has them. Their tests offer no SimpleLogin; halkyon_app's test the sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 01:21:29 +02:00
@override
String get simpleLoginPasswordIntro =>
'Choose a password: you type it when you sign in on another device. It never leaves this device: the instance can\'t read it, and can\'t reset it without what it protects being lost.';
@override
String get simpleLoginCreate => 'Create the account';
@override
String get simpleLoginUnlockTitle => 'Your password';
@override
String simpleLoginUnlockIntroAs(String handle) {
return 'Signed in with SimpleLogin as @$handle. Your password opens your keys on this device.';
}
@override
String get simpleLoginUnlockIntro =>
'Signed in with SimpleLogin. Your password opens your keys on this device.';
@override
String get simpleLoginOpen => 'Open';
@override
String get simpleLoginMendTitle => 'Link your account';
@override
String get simpleLoginMendIntro =>
'Your SimpleLogin account isn\'t the one your account knows any more. Link them again with your handle and your recovery phrase: your other devices are then signed out.';
@override
String get simpleLoginMend => 'Link';
@override
String get simpleLoginWrongPassword => 'The password isn\'t right.';
@override
String get simpleLoginMendDoesNotFit =>
'The handle or the recovery phrase isn\'t right.';
@override
String get simpleLoginForgotTitle => 'A new password';
@override
String get simpleLoginForgotIntro =>
'Your recovery phrase opens your keys, which your new password then protects. Everything stays; your other devices are signed out.';
@override
String get simpleLoginForgotDoesNotFit => 'The recovery phrase isn\'t right.';
feat(app): a reset of the keys without the phrase, its banner, and the keys' proof key for a password that signs in (ADR 0020, D31–D35) SimpleLogin's sheet, its password and its recovery phrase both lost: under the lost-password step's phrase field, Lost your recovery phrase too? says what stays and what is lost and asks for new keys (`keys.startReset`) with the sign-in of a moment ago, which the device then drops. The next sign-in says when while it waits, and once due offers new keys, the sign-up's own password and phrase steps (`keys.completeReset`), or the password, which calls it off (D31). Every app's home shows `KeysResetBanner` where "too old" shows, and the account section's SimpleLogin row the same words (`KeysResetNotice`), each with Call it off, the password's proof alone (`keys.callOffResets`, D32), and, once due on a device that holds the keys, Finish here, which wraps the same keys anew (D33, D35). Both show only a reset of an account that signs in with SimpleLogin alone; ADR 0017's resets show in its own section, which now shares `AlertBox` with them. An account whose password signs in has no Forgot your password? there, and is asked its password and a code once while its keys lack the proof key, at a sign-in or on adding SimpleLogin (`password.setProofKey`, D34). `PasswordUnlock` carries the proof key, which its forgetting leaves, and the keys' password proves for a purpose given. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 22:37:17 +02:00
@override
String simpleLoginResetWaiting(String date) {
return 'New keys were asked for: from $date, a SimpleLogin sign-in can set them up. Your password opening your keys calls it off.';
}
@override
String get simpleLoginPhraseLost => 'Lost your recovery phrase too?';
@override
String get simpleLoginResetTitle => 'New keys';
@override
String simpleLoginResetIntro(String instance) {
return 'Without your password or your recovery phrase, nobody can open your keys, not even $instance. New ones can be set up 72 hours from now, when you sign in with SimpleLogin again. Your handle, your profile and what you published stay; what was encrypted under your old keys is lost, unless you finish on a device still signed in, which keeps them.';
}
@override
String get simpleLoginResetIntroDevices =>
'Meanwhile your signed-in devices show the reset, and your password calls it off there, should someone else have asked for it.';
@override
String get simpleLoginResetAsk => 'Ask for new keys';
@override
String get simpleLoginResetAskedTitle => 'New keys asked for';
@override
String simpleLoginResetAskedIntro(String date) {
return 'From $date, sign in with SimpleLogin again to set them up. Should you find your password or your recovery phrase before then, opening your keys with it calls the reset off.';
}
@override
String get simpleLoginResetDueTitle => 'Your new keys';
@override
String get simpleLoginResetDueIntro =>
'The new keys you asked for can be set up now. Or open your old keys with your password, which calls the reset off.';
@override
String get simpleLoginResetNewKeys => 'Set up new keys';
@override
String get simpleLoginResetNewKeysHint =>
'A new password and recovery phrase. What was encrypted under your old keys is lost, unless you finish on a device still signed in.';
@override
String get simpleLoginResetHavePassword => 'I have my password';
@override
String get simpleLoginResetHavePasswordHint => 'Your keys open, and stay.';
@override
String get simpleLoginResetKeepIntro =>
'Choose a new password: your keys stay, under it and a new recovery phrase, so nothing is lost. Your other devices are signed out.';
@override
String get simpleLoginResetFinish => 'Set up the keys';
@override
String get simpleLoginProofKeyTitle => 'Your password and a code';
@override
String simpleLoginProofKeyIntroAs(String handle) {
return 'Signed in with SimpleLogin as @$handle. Your account also signs in with a password: type it and a code from your authenticator once, and your password opens your keys after SimpleLogin from then on.';
}
@override
String get simpleLoginProofKeyIntro =>
'Your account also signs in with a password: type it and a code from your authenticator once, and your password opens your keys after SimpleLogin from then on.';
@override
String simpleLoginResetBanner(String date) {
return 'New keys were asked for with your SimpleLogin account: from $date, whoever has it can set them up. Unless that was you, call it off with your password.';
}
@override
String get simpleLoginResetBannerDue =>
'New keys were asked for with your SimpleLogin account, and whoever has it can set them up now. Unless that was you, call it off with your password.';
@override
String get simpleLoginResetBannerDueHere =>
'New keys were asked for with your SimpleLogin account and can be set up now. If that was you, finish here: your keys stay. If not, call it off with your password.';
@override
String get simpleLoginResetFinishHere => 'Finish here';
@override
String get simpleLoginCallOffIntro =>
'Your password calls off the reset of your keys.';
@override
String get simpleLoginResetCalledOff => 'Reset called off.';
@override
String get simpleLoginResetFinished =>
'New password and recovery phrase set.';
feat(app): signing in with SimpleLogin, its sheet and the start screen's offer (ADR 0020) Where the instance offers SimpleLogin, the start screen offers it first, saying that the instance keeps only the SimpleLogin ID, and opens a sheet that waits for SimpleLogin's page in the browser (Cancel ends the wait), then: for someone new, the choice between creating an account (the suggested handle or another, checked with the instance, the password twice, the recovery phrase shown once and three of its words typed back, nothing reaching the instance before) and linking theirs again with its handle and recovery phrase; for an account, its password opening its keys; for an account of before, the keys made with the handle it lacks. SimpleLoginCubit holds the steps, each refusal shown where it is mended (a handle's on the handle, a sign-in to begin again on the browser's), and closing the sheet stops waiting on the loopback. The suggested handle is never checked: the instance suggests none that anybody has, and every answer about a handle counts against its limit (D5). The fake's handle rule is now the module's. Learn and Todo build it with SimpleLogin's browser (halkyon_oidc_flutter, now a direct dependency of both, with their names on the loopback's page), their schemes and their loopback ports (43823, 43824), as the instance's forwarding page has them. Their tests offer no SimpleLogin; halkyon_app's test the sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 01:21:29 +02:00
@override
String get simpleLoginUnavailable =>
'This instance doesn\'t offer sign-in with SimpleLogin.';
@override
String get simpleLoginDenied =>
'SimpleLogin\'s sign-in was declined, so nothing was shared.';
@override
String get simpleLoginNoBrowser =>
'There\'s no browser to open SimpleLogin\'s page in.';
@override
String get simpleLoginStartAgain =>
'The sign-in took too long, or another one took its place. Begin it again.';
@override
String get simpleLoginRejected =>
'SimpleLogin didn\'t confirm the sign-in. Begin it again.';
@override
String get simpleLoginProviderUnavailable =>
'The instance can\'t reach SimpleLogin right now. Try again later.';
@override
String get simpleLoginTakenByAnotherPerson =>
'This SimpleLogin account belongs to another account here.';
@override
String get simpleLoginOtherIdentityLinked =>
'Your account has another SimpleLogin account already.';
@override
String get simpleLoginTooManyAttempts =>
'Too many sign-ins began from this network. Try again in an hour.';
@override
feat(base)!: a handle at password sign-up (ADR 0020, D26, D28–D30) Every new account gets a handle, and an account without one gets its first as it sets a password. The handle is private until its person goes public (D5). - `passwordSignIn.signUp` takes a handle. `passwordSignIn.checkHandle` says whether a sign-up could take one, only while that sign-up's mailed code waits (`codeExpired` otherwise), counted per code request (30 an hour) and per network (60) (D29). Members ask the register. - `password.set` takes the first handle of an account without one (D28); `SignInWays.handle` tells the app whether there is one. - Each checks the handle before the code is used, so a refusal leaves the code for another try. An existing account at the address keeps its own handle where it has one, and the typed handle is still checked, so the answer says nothing about the address. - `first_handle.dart` holds what SimpleLogin, the keys and passwords share: `refusalOfNewHandle`, `insertFirstProfile`, `hasHandle`. - halkyon_app: one `HandleField` with its `HandleCheckCubit` (asked 300 ms after typing pauses, only about the handle typed last; the instance's suggestion is free without asking) (D30). The password setup asks for the handle between the phrase check and the code, and a refusal at the code sends back to it. SimpleLogin's sign-up and keys steps use the same field and now check as it is typed. - The module's README and ADR 0020 (D29, D30, the built state) amended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 18:09:04 +02:00
String get handleInvalid =>
feat(app): signing in with SimpleLogin, its sheet and the start screen's offer (ADR 0020) Where the instance offers SimpleLogin, the start screen offers it first, saying that the instance keeps only the SimpleLogin ID, and opens a sheet that waits for SimpleLogin's page in the browser (Cancel ends the wait), then: for someone new, the choice between creating an account (the suggested handle or another, checked with the instance, the password twice, the recovery phrase shown once and three of its words typed back, nothing reaching the instance before) and linking theirs again with its handle and recovery phrase; for an account, its password opening its keys; for an account of before, the keys made with the handle it lacks. SimpleLoginCubit holds the steps, each refusal shown where it is mended (a handle's on the handle, a sign-in to begin again on the browser's), and closing the sheet stops waiting on the loopback. The suggested handle is never checked: the instance suggests none that anybody has, and every answer about a handle counts against its limit (D5). The fake's handle rule is now the module's. Learn and Todo build it with SimpleLogin's browser (halkyon_oidc_flutter, now a direct dependency of both, with their names on the loopback's page), their schemes and their loopback ports (43823, 43824), as the instance's forwarding page has them. Their tests offer no SimpleLogin; halkyon_app's test the sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 01:21:29 +02:00
'A handle is 1 to 30 letters (a to z), digits or underscores.';
@override
feat(base)!: a handle at password sign-up (ADR 0020, D26, D28–D30) Every new account gets a handle, and an account without one gets its first as it sets a password. The handle is private until its person goes public (D5). - `passwordSignIn.signUp` takes a handle. `passwordSignIn.checkHandle` says whether a sign-up could take one, only while that sign-up's mailed code waits (`codeExpired` otherwise), counted per code request (30 an hour) and per network (60) (D29). Members ask the register. - `password.set` takes the first handle of an account without one (D28); `SignInWays.handle` tells the app whether there is one. - Each checks the handle before the code is used, so a refusal leaves the code for another try. An existing account at the address keeps its own handle where it has one, and the typed handle is still checked, so the answer says nothing about the address. - `first_handle.dart` holds what SimpleLogin, the keys and passwords share: `refusalOfNewHandle`, `insertFirstProfile`, `hasHandle`. - halkyon_app: one `HandleField` with its `HandleCheckCubit` (asked 300 ms after typing pauses, only about the handle typed last; the instance's suggestion is free without asking) (D30). The password setup asks for the handle between the phrase check and the code, and a refusal at the code sends back to it. SimpleLogin's sign-up and keys steps use the same field and now check as it is typed. - The module's README and ADR 0020 (D29, D30, the built state) amended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 18:09:04 +02:00
String get handleReserved => 'This handle is kept for the instance.';
feat(app): signing in with SimpleLogin, its sheet and the start screen's offer (ADR 0020) Where the instance offers SimpleLogin, the start screen offers it first, saying that the instance keeps only the SimpleLogin ID, and opens a sheet that waits for SimpleLogin's page in the browser (Cancel ends the wait), then: for someone new, the choice between creating an account (the suggested handle or another, checked with the instance, the password twice, the recovery phrase shown once and three of its words typed back, nothing reaching the instance before) and linking theirs again with its handle and recovery phrase; for an account, its password opening its keys; for an account of before, the keys made with the handle it lacks. SimpleLoginCubit holds the steps, each refusal shown where it is mended (a handle's on the handle, a sign-in to begin again on the browser's), and closing the sheet stops waiting on the loopback. The suggested handle is never checked: the instance suggests none that anybody has, and every answer about a handle counts against its limit (D5). The fake's handle rule is now the module's. Learn and Todo build it with SimpleLogin's browser (halkyon_oidc_flutter, now a direct dependency of both, with their names on the loopback's page), their schemes and their loopback ports (43823, 43824), as the instance's forwarding page has them. Their tests offer no SimpleLogin; halkyon_app's test the sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 01:21:29 +02:00
@override
feat(base)!: a handle at password sign-up (ADR 0020, D26, D28–D30) Every new account gets a handle, and an account without one gets its first as it sets a password. The handle is private until its person goes public (D5). - `passwordSignIn.signUp` takes a handle. `passwordSignIn.checkHandle` says whether a sign-up could take one, only while that sign-up's mailed code waits (`codeExpired` otherwise), counted per code request (30 an hour) and per network (60) (D29). Members ask the register. - `password.set` takes the first handle of an account without one (D28); `SignInWays.handle` tells the app whether there is one. - Each checks the handle before the code is used, so a refusal leaves the code for another try. An existing account at the address keeps its own handle where it has one, and the typed handle is still checked, so the answer says nothing about the address. - `first_handle.dart` holds what SimpleLogin, the keys and passwords share: `refusalOfNewHandle`, `insertFirstProfile`, `hasHandle`. - halkyon_app: one `HandleField` with its `HandleCheckCubit` (asked 300 ms after typing pauses, only about the handle typed last; the instance's suggestion is free without asking) (D30). The password setup asks for the handle between the phrase check and the code, and a refusal at the code sends back to it. SimpleLogin's sign-up and keys steps use the same field and now check as it is typed. - The module's README and ADR 0020 (D29, D30, the built state) amended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 18:09:04 +02:00
String get handleTaken => 'Someone else has this handle.';
feat(app): signing in with SimpleLogin, its sheet and the start screen's offer (ADR 0020) Where the instance offers SimpleLogin, the start screen offers it first, saying that the instance keeps only the SimpleLogin ID, and opens a sheet that waits for SimpleLogin's page in the browser (Cancel ends the wait), then: for someone new, the choice between creating an account (the suggested handle or another, checked with the instance, the password twice, the recovery phrase shown once and three of its words typed back, nothing reaching the instance before) and linking theirs again with its handle and recovery phrase; for an account, its password opening its keys; for an account of before, the keys made with the handle it lacks. SimpleLoginCubit holds the steps, each refusal shown where it is mended (a handle's on the handle, a sign-in to begin again on the browser's), and closing the sheet stops waiting on the loopback. The suggested handle is never checked: the instance suggests none that anybody has, and every answer about a handle counts against its limit (D5). The fake's handle rule is now the module's. Learn and Todo build it with SimpleLogin's browser (halkyon_oidc_flutter, now a direct dependency of both, with their names on the loopback's page), their schemes and their loopback ports (43823, 43824), as the instance's forwarding page has them. Their tests offer no SimpleLogin; halkyon_app's test the sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 01:21:29 +02:00
@override
feat(base)!: a handle at password sign-up (ADR 0020, D26, D28–D30) Every new account gets a handle, and an account without one gets its first as it sets a password. The handle is private until its person goes public (D5). - `passwordSignIn.signUp` takes a handle. `passwordSignIn.checkHandle` says whether a sign-up could take one, only while that sign-up's mailed code waits (`codeExpired` otherwise), counted per code request (30 an hour) and per network (60) (D29). Members ask the register. - `password.set` takes the first handle of an account without one (D28); `SignInWays.handle` tells the app whether there is one. - Each checks the handle before the code is used, so a refusal leaves the code for another try. An existing account at the address keeps its own handle where it has one, and the typed handle is still checked, so the answer says nothing about the address. - `first_handle.dart` holds what SimpleLogin, the keys and passwords share: `refusalOfNewHandle`, `insertFirstProfile`, `hasHandle`. - halkyon_app: one `HandleField` with its `HandleCheckCubit` (asked 300 ms after typing pauses, only about the handle typed last; the instance's suggestion is free without asking) (D30). The password setup asks for the handle between the phrase check and the code, and a refusal at the code sends back to it. SimpleLogin's sign-up and keys steps use the same field and now check as it is typed. - The module's README and ADR 0020 (D29, D30, the built state) amended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 18:09:04 +02:00
String get handleTooManyChecks =>
feat(app): signing in with SimpleLogin, its sheet and the start screen's offer (ADR 0020) Where the instance offers SimpleLogin, the start screen offers it first, saying that the instance keeps only the SimpleLogin ID, and opens a sheet that waits for SimpleLogin's page in the browser (Cancel ends the wait), then: for someone new, the choice between creating an account (the suggested handle or another, checked with the instance, the password twice, the recovery phrase shown once and three of its words typed back, nothing reaching the instance before) and linking theirs again with its handle and recovery phrase; for an account, its password opening its keys; for an account of before, the keys made with the handle it lacks. SimpleLoginCubit holds the steps, each refusal shown where it is mended (a handle's on the handle, a sign-in to begin again on the browser's), and closing the sheet stops waiting on the loopback. The suggested handle is never checked: the instance suggests none that anybody has, and every answer about a handle counts against its limit (D5). The fake's handle rule is now the module's. Learn and Todo build it with SimpleLogin's browser (halkyon_oidc_flutter, now a direct dependency of both, with their names on the loopback's page), their schemes and their loopback ports (43823, 43824), as the instance's forwarding page has them. Their tests offer no SimpleLogin; halkyon_app's test the sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 01:21:29 +02:00
'Too many handles were tried. Try again in an hour.';
@override
String get simpleLoginSectionTitle => 'SimpleLogin';
@override
String get simpleLoginSignsYouIn => 'Signs you in';
@override
String get simpleLoginAddHint =>
'Sign in with SimpleLogin, or with your Proton account.';
@override
String get simpleLoginAdded => 'SimpleLogin added.';
}
/// The translations for English, as used in the United Kingdom (`en_GB`).
class HalkyonAppLocalizationsEnGb extends HalkyonAppLocalizationsEn {
HalkyonAppLocalizationsEnGb() : super('en_GB');
}
/// The translations for English, as used in the United States (`en_US`).
class HalkyonAppLocalizationsEnUs extends HalkyonAppLocalizationsEn {
HalkyonAppLocalizationsEnUs() : super('en_US');
}