diff --git a/README.md b/README.md index 6e9b675..c84df0a 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,8 @@ final actor = NostrSignerActor(privateKeyHex); |---|---|---| | `SignEvent(kind, content, tags?, createdAt?)` | `EventSigned(event)` | Returns a signed event as a JSON string with all seven NIP-01 fields | | `GetPublicKey()` | `PublicKeyResult(publicKey)` | Returns the hex public key for this signer | +| `Nip44Encrypt(plaintext)` | `Nip44Text(value)` | NIP-44 v2 encrypt-to-self: seals `plaintext` with this signer's own key (base64 payload). Useful for kind-30078 app data. | +| `Nip44Decrypt(payload)` | `Nip44Text(value)` | Inverse of `Nip44Encrypt`. Throws on a version mismatch or HMAC failure. | `tags` defaults to `[]`. `createdAt` defaults to `DateTime.now()` (Unix seconds). @@ -107,6 +109,9 @@ Implements the same `SignerMessage`/`SignerResult` protocol as `NostrSignerActor | `GetPublicKey()` | `PublicKeyResult(publicKey)` | Returns the signer's public key (cached after first call) | | `SignEvent(kind, content, tags?, createdAt?)` | `EventSigned(event)` | Sends a `sign_event` request to the remote signer; returns the fully signed event JSON | +The `Nip44Encrypt`/`Nip44Decrypt` messages are **not** supported by the remote +signer yet — only `GetPublicKey` and `SignEvent` are proxied over NIP-46. + Call `actor.close()` when done to tear down the relay connection. ```dart diff --git a/lib/src/nostr_signer_actor.dart b/lib/src/nostr_signer_actor.dart index 9e24b1d..c8d5ebe 100644 --- a/lib/src/nostr_signer_actor.dart +++ b/lib/src/nostr_signer_actor.dart @@ -1,6 +1,7 @@ import 'package:actors/actors.dart'; import 'package:bip340/bip340.dart' as bip340; +import 'nip44.dart'; import 'nostr_event.dart'; sealed class SignerMessage { @@ -24,6 +25,20 @@ final class GetPublicKey extends SignerMessage { const GetPublicKey(); } +/// NIP-44 v2 encrypt-to-self: encrypts [plaintext] with this signer's own key +/// (conversation key derived from its private key and public key). +final class Nip44Encrypt extends SignerMessage { + final String plaintext; + const Nip44Encrypt(this.plaintext); +} + +/// NIP-44 v2 decrypt-from-self: inverse of [Nip44Encrypt]. Throws on a version +/// mismatch or HMAC failure (e.g. a payload sealed with a different key). +final class Nip44Decrypt extends SignerMessage { + final String payload; + const Nip44Decrypt(this.payload); +} + sealed class SignerResult { const SignerResult(); } @@ -38,6 +53,12 @@ final class PublicKeyResult extends SignerResult { const PublicKeyResult(this.publicKey); } +/// Result of a [Nip44Encrypt] (base64 payload) or [Nip44Decrypt] (plaintext). +final class Nip44Text extends SignerResult { + final String value; + const Nip44Text(this.value); +} + class NostrSignerActor with Handler { final String _privateKey; final String _publicKey; @@ -51,6 +72,12 @@ class NostrSignerActor with Handler { SignEvent(:final kind, :final tags, :final content, :final createdAt) => Future.value(_signEvent(kind, tags, content, createdAt)), GetPublicKey() => Future.value(PublicKeyResult(_publicKey)), + Nip44Encrypt(:final plaintext) => Future.value( + Nip44Text(nip44Encrypt(plaintext, _privateKey, _publicKey)), + ), + Nip44Decrypt(:final payload) => Future.value( + Nip44Text(nip44Decrypt(payload, _privateKey, _publicKey)), + ), }; EventSigned _signEvent(