From 22f8129b52f4fa7de2e8a679976dab06ee40a3f8 Mon Sep 17 00:00:00 2001 From: Dorian Date: Mon, 31 Aug 2026 13:53:52 +0100 Subject: [PATCH] =?UTF-8?q?feat(companion):=20backup=20&=20restore=20+=20N?= =?UTF-8?q?IP-46=20remote=20signer=20=E2=80=94=200.5.28=20(#128,=20#139)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Companion 0.5.28 (versionCode 48), the companion-agent queue items: #128 Backup & Restore — the phone side of losing your phone or wiping it to cross a border. Hub card → SAF export/import of an encrypted .json: everything the app holds (servers+passwords, FIPS identity/peers, signer key) sealed in the node's ADR-005 envelope (Argon2id + ChaCha20-Poly1305, native backup.rs — same blob layout as the node's, node-shaped envelopes decrypt too). Restore is merge-only: servers upsert npub-first, identity and signer key adopt only when absent, peers union by npub. No cloud, no telemetry — the file goes wherever the user saves it. #139 Remote Signer — the phone IS the NIP-46 bunker. Generate/import a nostr key, scan a nostrconnect:// QR (in-app scanner or deep link), and approve/deny each sign_event request from a legible card (kind label, content, tags, time) — nothing signs without a human. Wire-faithful to rust-nostr's reference bunker (connect-carrying-secret handshake, NIP-44 v2 transport with NIP-04 receive fallback, kind-24133 responses); get_public_key/describe/ping handled, everything else 'not authorized'. Session state in BunkerManager, UI in SignerScreen, hub card wired. Plus NativeCore (JNI object for the new native surface), FipsPreferences peers-merge for restore, nostrconnect:// intent filter, and the release docs (companion-backup-restore.md, companion-nip46-remote-signer.md). Also Android/tools/nip46-test-client.py: a pure-Python NIP-46 client that plays the node's login role (QR, handshake, get_public_key, sign_event) and verifies the phone's signature with an independent BIP-340 — the end-to-end test for the feature until node-side lands. Its crypto matches the official NIP-44 + BIP-340 vectors byte-for-byte, the same vectors the Rust core passes, so the two interop by construction. Built + smoke: assembleDebug v0.5.28/vc48, same signing cert as the served 0.5.27 (d622e07e…644d) so it updates in place. --- Android/app/build.gradle.kts | 4 +- Android/app/src/main/AndroidManifest.xml | 9 + .../java/com/archipelago/app/NativeCore.kt | 69 +++ .../com/archipelago/app/data/BackupManager.kt | 229 ++++++++ .../archipelago/app/fips/FipsPreferences.kt | 32 ++ .../archipelago/app/nostr/BunkerManager.kt | 450 +++++++++++++++ .../app/nostr/NostrSignerPreferences.kt | 95 ++++ .../archipelago/app/ui/components/NESMenu.kt | 18 +- .../archipelago/app/ui/navigation/NavGraph.kt | 77 ++- .../app/ui/screens/BackupRestoreScreen.kt | 385 +++++++++++++ .../app/ui/screens/SignerScreen.kt | 511 ++++++++++++++++++ .../app/ui/screens/WebViewScreen.kt | 6 + Android/tools/nip46-test-client.py | 384 +++++++++++++ docs/companion-backup-restore.md | 87 +++ docs/companion-nip46-remote-signer.md | 105 ++++ 15 files changed, 2440 insertions(+), 21 deletions(-) create mode 100644 Android/app/src/main/java/com/archipelago/app/NativeCore.kt create mode 100644 Android/app/src/main/java/com/archipelago/app/data/BackupManager.kt create mode 100644 Android/app/src/main/java/com/archipelago/app/nostr/BunkerManager.kt create mode 100644 Android/app/src/main/java/com/archipelago/app/nostr/NostrSignerPreferences.kt create mode 100644 Android/app/src/main/java/com/archipelago/app/ui/screens/BackupRestoreScreen.kt create mode 100644 Android/app/src/main/java/com/archipelago/app/ui/screens/SignerScreen.kt create mode 100644 Android/tools/nip46-test-client.py create mode 100644 docs/companion-backup-restore.md create mode 100644 docs/companion-nip46-remote-signer.md diff --git a/Android/app/build.gradle.kts b/Android/app/build.gradle.kts index d7706d12..9e1b2b3f 100644 --- a/Android/app/build.gradle.kts +++ b/Android/app/build.gradle.kts @@ -11,8 +11,8 @@ android { applicationId = "com.archipelago.app" minSdk = 26 targetSdk = 35 - versionCode = 47 - versionName = "0.5.27" + versionCode = 48 + versionName = "0.5.28" vectorDrawables { useSupportLibrary = true diff --git a/Android/app/src/main/AndroidManifest.xml b/Android/app/src/main/AndroidManifest.xml index 1ed5e9a3..335a8837 100644 --- a/Android/app/src/main/AndroidManifest.xml +++ b/Android/app/src/main/AndroidManifest.xml @@ -54,6 +54,15 @@ + + + + + + +