mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-30 07:37:38 +00:00
Quartz now lives in github.com/vitorpamplona/quartz, split into quartz-core, quartz-social, quartz-relay-client and the other quartz-* libraries, with history kept. Amethyst depends on the `quartz` umbrella artifact at a released version (1.20.0) instead of the :quartz project. - Remove the quartz/ module, jitpack.yml and the Quartz CI, release and pre-push steps; tools/unicode-nfkc moved with it. - Point every module at libs.quartz. - Move the device-test fixtures the benchmark and relayBench still read to testdata/. - NostrConnectLoginUseCase parses bunker messages with BunkerJson, which now owns NIP-46 JSON. - Repoint docs and skills at the Quartz repository; the nostr-expert scripts read a Quartz checkout (QUARTZ_REPO, default ../quartz). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014ZR5ZBfhFzRiXubJc5Evyv
42 lines
2.6 KiB
Markdown
42 lines
2.6 KiB
Markdown
# NIP-55 Android external signer
|
|
|
|
Another Android app (Amber, …) holds the key; Amethyst asks it through `Intent`s
|
|
(foreground, with UI) or its `ContentProvider` (background, pre-approved). Android only.
|
|
|
|
## Layout ([nip55-android-signer/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/](https://github.com/vitorpamplona/quartz/tree/main/nip55-android-signer/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner))
|
|
|
|
- `api/CommandType.kt` — `sign_event`, `nip04_encrypt`/`decrypt`, `nip44_encrypt`/`decrypt`,
|
|
`get_public_key`, `decrypt_zap_event`, `derive_key`, `sign_psbt`.
|
|
- `api/foreground/` — `IntentRequestManager` (id → channel, launches the intent, waits
|
|
`foregroundApprovalTimeout` = 30 s) and `intents/requests|responses|results/` per command.
|
|
- `api/background/queries/` — one `ContentResolver` query per command (`SignQuery`,
|
|
`Nip44EncryptQuery`, `LoginQuery`, …).
|
|
- `api/permission/` — `Permission` + its serializers (the permissions requested at login).
|
|
- `client/` — `NostrSignerExternal(pubKey, packageName, contentResolver)` (the `NostrSigner`),
|
|
`ExternalSignerLogin` (`createIntent(permissions, packageName)`, `parseResult(intent)`),
|
|
`IActivityLauncher` (`registerForegroundLauncher`, `unregisterForegroundLauncher`,
|
|
`newResponse`, `hasForegroundActivity`), `IsExternalSignerInstalled.kt`
|
|
(`isExternalSignerInstalled(context)`, `getExternalSignersInstalled(context)`),
|
|
`handlers/BackgroundRequestHandler` + `ForegroundRequestHandler`.
|
|
- `SignString.kt`, `JsonMapperNip55.kt`.
|
|
|
|
## Flow
|
|
|
|
1. Login: `ExternalSignerLogin.createIntent(...)` → the signer app returns pubkey + package →
|
|
`parseResult(data)` → `NostrSignerExternal(pubKey, packageName, contentResolver)`.
|
|
2. Each call tries the background query first; if the signer has not pre-approved that
|
|
command, it falls back to a foreground intent through the registered launcher.
|
|
3. No registered Activity → `SignerExceptions.RunningOnBackgroundWithoutAutomaticPermissionException`;
|
|
no answer in 30 s → `TimedOutException`.
|
|
|
|
The Android entry point is
|
|
`amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/ExternalSignerButton.kt`.
|
|
|
|
## Gotchas
|
|
|
|
- Without "always allow", every reaction or zap is an Activity round-trip — bad UX; ask for
|
|
the permissions at login.
|
|
- Desktop has no NIP-55; it uses `NostrSignerInternal` or `NostrSignerRemote`.
|
|
- Tests, in the Quartz repository: [nip55-android-signer/src/androidHostTest](https://github.com/vitorpamplona/quartz/tree/main/nip55-android-signer/src/androidHostTest) (JVM host) and
|
|
`quartz/src/androidDeviceTest/.../nip55AndroidSigner/` in its umbrella module (device/emulator only).
|