diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-01 01:03:43 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-01 01:03:43 +0200 |
| commit | fe30860c58e0f1b1efd457ff5eb5146d1e592da0 (patch) | |
| tree | 99a3e96994738c4e96f969a365679475dc4cf5cd /packages/meshbay-hub/src/meshbay_hub/static/locales/de.js | |
| parent | 51d2d734c228f1e46670962480258abfe586d6c4 (diff) | |
| download | meshbay-fe30860c58e0f1b1efd457ff5eb5146d1e592da0.tar.gz | |
feat: passphrase change and account recovery (auth-confirm)
The passphrase derives two independent client-side values: auth_key (the
hub verifier) and bundle_key (AES-GCM key for the per-node identity
bundles, which live on nodes and never on the hub). Changing or
recovering a passphrase is therefore two operations — swap the hub
verifier, and re-wrap every reachable node's identity bundle.
Flow A — change a known passphrase (Profile page)
- POST /v1/users/password re-proves the current passphrase, swaps
pw_hash/salt/version, revokes every refresh token and returns a fresh
pair so the tab that made the change stays signed in.
- MeshBayTransport.rewrapAllNodes: for every group's online node, connect
with the old key, read the identity off the handshake, store it back
under the new key. Returns updated / unreachable / failed so the UI can
point at the operator-unpin fallback for the gaps. Always-shown
confirmation dialog listing reachable and unreachable groups.
Recovery key
- keyderive.js generateRecoveryKey (32 random bytes, grouped Base32) and
deriveRecoveryKey (HKDF-SHA256, domain meshbay:recovery:v1:<username>).
- Every per-node identity gets a second copy wrapped under the recovery
key: keypair_bundles.bundle_enc_recovery (node-only column, added in
_SCHEMA_KEYPAIR and via a PRAGMA-guarded ALTER for existing DBs),
carried on keypair_bundle_store / _resp. MNP 0.13 -> 0.14, additive.
- session.recoveryKey is persisted in IndexedDB (slot rk) and lazy-loaded
on connect, so a group joined in any later session still leaves a
recovery copy.
- Shown once at registration; optionally folded into the verification
e-mail as a pass-through the hub never stores or logs, with an opt-out.
- Profile -> Recovery key re-loads R and backfills every reachable node
via rewrapAllNodes in bundleKey mode (no passphrase re-entry).
Flow B — recover a lost passphrase (#/reset, linked from sign-in)
- POST /v1/users/password/reset-request {username, email}: both must be
the pair on file, checked against the blind email_hash (never
decrypted). A mismatch — wrong e-mail, unknown username, non-active
account — takes the identical no-op path (no code, no mail, same 200),
so it reveals nothing and cannot be used to spray reset mail from a
username alone. 5/min, 1-hour single-use code.
- POST /v1/users/password/reset {username, code, new_auth_key}: same
expiry / attempts / single-use checks as e-mail verification; revokes
every session and deletes every registered device key so a stored one
cannot sign back in past the reset.
- ResetPasswordPage: request code -> code + optional recovery key + new
passphrase -> reset + sign-in -> fan-out. connect() falls back to the
recovery-wrapped copy when the passphrase key cannot open bundle_enc.
Without a recovery key: sign-in is restored and each group needs the
operator-unpin fallback.
Supporting fixes (found in live testing)
- member unpin now also deletes the keypair bundle; connect() mints a
fresh identity when handed a bundle it cannot open (unless _rewrapOnly,
set by rewrapAllNodes), so a rejoin completes instead of dead-ending
before the invite-code prompt.
- A browser with no bundle key gets a passphrase prompt on the group page
instead of a "go back to the browser you registered on" message.
- RegisterPage / LoginPage / ResetPasswordPage trim the username so every
key derivation matches the hub's stored form.
Docs: docs/auth-confirm.md. Locale keys across all ten catalogues.
Tests: test_password_change, test_password_reset, test_recovery_email,
test_recovery_key, test_rewrap_fanout, test_bundle_store_recovery, plus
additions to test_admin_ops_mnp and test_webrtc_transport. Hub suite 492
passed; node suite 741 passed (the lone test_packaging_units failure is a
pre-existing RPM-spec flake, reproducible on main).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGkxJW9br8Y9bhT8ywJ3oc
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/locales/de.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/locales/de.js | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js index 909fec5..363df86 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js @@ -29,6 +29,25 @@ export default { 'login.loading': 'Anmeldung läuft …', 'login.no_account': 'Noch kein Konto?', 'login.register_link': 'Konto erstellen', + 'login.forgot': 'Passphrase vergessen?', + 'reset.title': 'Passphrase zurücksetzen', + 'reset.request_intro': 'Geben Sie Ihren Benutzernamen und die E-Mail des Kontos ein. Stimmen sie überein, wird ein Zurücksetzungscode an diese Adresse gesendet.', + 'reset.send_code': 'Code senden', + 'reset.form_intro': 'Geben Sie den Code aus Ihrer E-Mail ein und wählen Sie eine neue Passphrase. Wenn Sie Ihren Wiederherstellungsschlüssel haben, fügen Sie ihn hinzu, um auch den Zugang zu Ihren Gruppen wiederherzustellen.', + 'reset.code': 'Zurücksetzungscode', + 'reset.recovery_key': 'Wiederherstellungsschlüssel (optional)', + 'reset.recovery_key_hint': 'Leer lassen, wenn Sie ihn nicht haben. Ohne ihn wird Ihre Anmeldung wiederhergestellt, aber jeder Gruppe müssen Sie erneut beitreten.', + 'reset.new_pass': 'Neue Passphrase', + 'reset.new_pass_repeat': 'Neue Passphrase wiederholen', + 'reset.submit': 'Passphrase zurücksetzen', + 'reset.working': 'Ihre Gruppenidentitäten werden wiederhergestellt…', + 'reset.signin_restored': 'Ihre Anmeldung wurde wiederhergestellt.', + 'reset.groups_restored': 'Ihre Gruppenidentitäten wurden auf jedem erreichbaren Knoten wiederhergestellt.', + 'reset.no_recovery': 'Ihre Gruppenidentitäten wurden nicht wiederhergestellt. Bitten Sie für jede Gruppe deren Betreiber, Ihre Anheftung zu entfernen und einen neuen Einladungscode zu senden, und treten Sie dann erneut bei.', + 'reset.needs_operator': 'Diese Gruppen erfordern noch eine Aktion — bitten Sie jeden Betreiber, Ihre Anheftung zu entfernen und einen neuen Code zu senden:', + 'reset.go_app': 'Zur App', + 'reset.back_to_login': 'Zurück zur Anmeldung', + 'reset.err_unsupported': 'Das Zurücksetzen der Passphrase benötigt das Krypto-Modul des Browsers, das hier nicht verfügbar ist.', // Register 'register.title': 'Konto erstellen', @@ -40,6 +59,16 @@ export default { 'register.loading': 'Konto wird erstellt …', 'register.has_account': 'Sie haben bereits ein Konto?', 'register.login_link': 'Anmelden', + 'register.recovery_title': 'Speichern Sie Ihren Wiederherstellungsschlüssel', + 'register.recovery_intro': 'Dieser Schlüssel stellt Ihre Gruppenidentitäten wieder her, falls Sie jemals Ihre Passphrase vergessen. Bewahren Sie ihn in einem Passwortmanager oder an einem sicheren Ort auf — er wird nur einmal angezeigt, und der Hub sieht ihn nie.', + 'register.recovery_copy': 'Kopieren', + 'register.recovery_copied': 'Kopiert', + 'register.recovery_warning': 'Wenn Sie sowohl Ihre Passphrase als auch diesen Schlüssel verlieren, bleiben Ihre Dateien auf ihren Knoten, aber Sie treten jeder Gruppe mit einer neuen Identität erneut bei.', + 'register.recovery_saved': 'Ich habe meinen Wiederherstellungsschlüssel an einem sicheren Ort gespeichert.', + 'register.recovery_continue': 'Weiter', + 'register.recovery_email_opt': 'Diesen Wiederherstellungsschlüssel zur Sicherung auch per E-Mail an mich senden', + 'register.recovery_emailed': 'Eine Kopie wurde auch an Ihre E-Mail-Adresse gesendet, in derselben Nachricht wie Ihr Bestätigungscode.', + 'register.recovery_not_emailed': 'Dies wurde nicht per E-Mail gesendet. Speichern Sie es jetzt — es wird nur dieses eine Mal angezeigt.', 'register.success_title': 'E-Mail bestätigen', 'register.success_msg': 'Ein Bestätigungscode wurde an Ihre E-Mail-Adresse gesendet. Geben Sie ihn unten ein, um Ihr Konto zu aktivieren.', 'register.go_login': 'Zur Anmeldung', @@ -294,6 +323,36 @@ export default { other: '{n} gemerkt', }, 'settings.node_pins_clear': 'Gemerkte Identitäten löschen', + 'settings.passphrase': 'Passphrase', + 'settings.passphrase_hint': 'Ändert die Passphrase dieses Kontos. Ihre Identitätsschlüssel werden in jeder Gruppe neu verpackt, deren Knoten online ist; einer Gruppe, deren Knoten offline ist, müssen Sie danach erneut beitreten.', + 'settings.passphrase_change': 'Passphrase ändern', + 'settings.passphrase_current': 'Aktuelle Passphrase', + 'settings.passphrase_new': 'Neue Passphrase', + 'settings.passphrase_new_repeat': 'Neue Passphrase wiederholen', + 'settings.continue': 'Weiter', + 'settings.done': 'Fertig', + 'settings.passphrase_confirm_intro': 'Ihre Identitätsschlüssel werden jetzt in jeder Gruppe neu verpackt, deren Knoten erreichbar ist:', + 'settings.passphrase_reachable': 'Jetzt aktualisiert', + 'settings.passphrase_unreachable': 'Nicht erreichbar', + 'settings.passphrase_fallback_note': 'Bitten Sie bei einer nicht erreichbaren Gruppe deren Betreiber, Ihre Anheftung zu entfernen und einen neuen Einladungscode zu senden, und treten Sie dann erneut bei. Ihre Dateien und Nachrichten gehen nicht verloren.', + 'settings.passphrase_confirm_btn': 'Ändern', + 'settings.passphrase_working': 'Ihre Schlüssel werden neu verpackt…', + 'settings.passphrase_done': 'Passphrase geändert.', + 'settings.passphrase_needs_operator': 'Diese Gruppen erfordern noch eine Aktion — bitten Sie jeden Betreiber, Ihre Anheftung zu entfernen und einen neuen Code zu senden:', + 'settings.pw_too_short': 'Die neue Passphrase muss mindestens 12 Zeichen lang sein.', + 'settings.pw_mismatch': 'Die beiden neuen Passphrasen stimmen nicht überein.', + 'settings.pw_same': 'Die neue Passphrase muss sich von der aktuellen unterscheiden.', + 'settings.pw_wrong_current': 'Die aktuelle Passphrase ist nicht korrekt. Es wurde nichts geändert.', + 'settings.recovery': 'Wiederherstellungsschlüssel', + 'settings.recovery_hint': 'Fügt jeder Gruppe eine mit Ihrem Wiederherstellungsschlüssel verschlüsselte Kopie Ihrer Identität hinzu. Machen Sie das einmal in jedem Browser, den Sie nutzen; ohne sie bedeutet eine verlorene Passphrase, jeder Gruppe von Hand erneut beizutreten.', + 'settings.recovery_loaded': 'In diesem Browser geladen — neue Gruppen sind automatisch abgedeckt.', + 'settings.recovery_open': 'Wiederherstellungsschlüssel eingeben', + 'settings.recovery_input_ph': 'Fügen Sie Ihren Wiederherstellungsschlüssel ein', + 'settings.recovery_submit': 'Sicherungskopien hinzufügen', + 'settings.recovery_working': 'Ihre Gruppen werden aktualisiert…', + 'settings.recovery_done': 'Ihre Gruppen haben jetzt eine Wiederherstellungskopie.', + 'settings.recovery_partial': 'Diese Gruppen waren nicht erreichbar. Öffnen Sie sie später oder führen Sie dies erneut aus:', + 'settings.recovery_need_relogin': 'Bitte melden Sie sich ab und wieder an und versuchen Sie es erneut.', 'settings.danger': 'Konto löschen', 'settings.delete_hint': 'Entfernt Ihr Konto, Ihre Gruppenmitgliedschaften und Ihre ' + 'Benachrichtigungen vom Hub und gibt Ihren Benutzernamen frei. Was auf den Nodes ' @@ -527,6 +586,9 @@ export default { + 'Einmalcode und geben Sie ihn hier ein. Danach ist dieser Browser bekannt und Sie ' + 'werden nicht erneut gefragt.', 'group.join_code_btn': 'Beitreten', + 'group.pass_title': 'Geben Sie Ihre Passphrase ein', + 'group.pass_hint': 'Dieser Browser hat Ihre Schlüssel noch nicht entsperrt. Geben Sie Ihre Passphrase einmal ein, um Ihre Gruppen hier zu öffnen.', + 'group.pass_btn': 'Entsperren', 'notif.purge': 'Alle löschen', 'notif.title': 'Benachrichtigungen', |