2026-06-07 16:45:43 +03:00
|
|
|
import 'package:actors/actors.dart';
|
|
|
|
|
import 'package:bip340/bip340.dart' as bip340;
|
2026-06-10 11:20:20 +03:00
|
|
|
|
2026-07-11 17:33:08 +03:00
|
|
|
import 'nip44.dart';
|
2026-06-10 11:20:20 +03:00
|
|
|
import 'nostr_event.dart';
|
2026-06-07 16:45:43 +03:00
|
|
|
|
|
|
|
|
sealed class SignerMessage {
|
|
|
|
|
const SignerMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final class SignEvent extends SignerMessage {
|
|
|
|
|
final int kind;
|
|
|
|
|
final List<List<String>> tags;
|
|
|
|
|
final String content;
|
|
|
|
|
final int? createdAt;
|
|
|
|
|
const SignEvent({
|
|
|
|
|
required this.kind,
|
|
|
|
|
this.tags = const [],
|
|
|
|
|
required this.content,
|
|
|
|
|
this.createdAt,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final class GetPublicKey extends SignerMessage {
|
|
|
|
|
const GetPublicKey();
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-11 17:33:08 +03:00
|
|
|
/// 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);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-07 16:45:43 +03:00
|
|
|
sealed class SignerResult {
|
|
|
|
|
const SignerResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final class EventSigned extends SignerResult {
|
|
|
|
|
final String event;
|
|
|
|
|
const EventSigned(this.event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final class PublicKeyResult extends SignerResult {
|
|
|
|
|
final String publicKey;
|
|
|
|
|
const PublicKeyResult(this.publicKey);
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-11 17:33:08 +03:00
|
|
|
/// Result of a [Nip44Encrypt] (base64 payload) or [Nip44Decrypt] (plaintext).
|
|
|
|
|
final class Nip44Text extends SignerResult {
|
|
|
|
|
final String value;
|
|
|
|
|
const Nip44Text(this.value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-07 16:45:43 +03:00
|
|
|
class NostrSignerActor with Handler<SignerMessage, SignerResult> {
|
|
|
|
|
final String _privateKey;
|
|
|
|
|
final String _publicKey;
|
|
|
|
|
|
|
|
|
|
NostrSignerActor(String privateKey)
|
|
|
|
|
: _privateKey = privateKey,
|
|
|
|
|
_publicKey = bip340.getPublicKey(privateKey);
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Future<SignerResult> handle(SignerMessage message) => switch (message) {
|
|
|
|
|
SignEvent(:final kind, :final tags, :final content, :final createdAt) =>
|
|
|
|
|
Future.value(_signEvent(kind, tags, content, createdAt)),
|
|
|
|
|
GetPublicKey() => Future.value(PublicKeyResult(_publicKey)),
|
2026-07-11 17:33:08 +03:00
|
|
|
Nip44Encrypt(:final plaintext) => Future.value(
|
|
|
|
|
Nip44Text(nip44Encrypt(plaintext, _privateKey, _publicKey)),
|
|
|
|
|
),
|
|
|
|
|
Nip44Decrypt(:final payload) => Future.value(
|
|
|
|
|
Nip44Text(nip44Decrypt(payload, _privateKey, _publicKey)),
|
|
|
|
|
),
|
2026-06-07 16:45:43 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EventSigned _signEvent(
|
|
|
|
|
int kind,
|
|
|
|
|
List<List<String>> tags,
|
|
|
|
|
String content,
|
|
|
|
|
int? createdAt,
|
2026-06-10 11:20:20 +03:00
|
|
|
) =>
|
|
|
|
|
EventSigned(signNostrEvent(
|
|
|
|
|
privateKey: _privateKey,
|
|
|
|
|
publicKey: _publicKey,
|
|
|
|
|
kind: kind,
|
|
|
|
|
tags: tags,
|
|
|
|
|
content: content,
|
|
|
|
|
createdAt: createdAt,
|
|
|
|
|
));
|
2026-06-07 16:45:43 +03:00
|
|
|
}
|