swarm/lib/src/nostr_signer_actor.dart

98 lines
2.6 KiB
Dart
Raw Normal View History

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
}