import 'dart:convert'; import 'package:crypto/crypto.dart'; /// Represents a Nostr event. class NostrEvent { /// Event ID (32-byte hex string). final String id; /// Public key of the event creator (pubkey). final String pubkey; /// Unix timestamp in seconds. final int createdAt; /// Event kind (integer). final int kind; /// Event tags (array of arrays). final List> tags; /// Event content (string). final String content; /// Event signature (64-byte hex string). final String sig; /// Creates a [NostrEvent] with the provided values. NostrEvent({ required this.id, required this.pubkey, required this.createdAt, required this.kind, required this.tags, required this.content, required this.sig, }); /// Creates a [NostrEvent] from a JSON array (Nostr event format). factory NostrEvent.fromJson(List json) { return NostrEvent( id: json[0] as String, pubkey: json[1] as String, createdAt: json[2] as int, kind: json[3] as int, tags: (json[4] as List) .map((tag) => (tag as List).map((e) => e.toString()).toList()) .toList(), content: json[5] as String, sig: json[6] as String, ); } /// Converts the [NostrEvent] to a JSON array (Nostr event format). List toJson() { return [ id, pubkey, createdAt, kind, tags, content, sig, ]; } /// Creates an event from content and signs it with a private key. /// /// [content] - Event content. /// [kind] - Event kind (default: 1 for text note). /// [privateKey] - Private key in hex format for signing. /// [tags] - Optional tags for the event. factory NostrEvent.create({ required String content, int kind = 1, required String privateKey, List>? tags, }) { // Derive public key from private key (simplified) final privateKeyBytes = _hexToBytes(privateKey); final publicKeyBytes = sha256.convert(privateKeyBytes).bytes.sublist(0, 32); final pubkey = publicKeyBytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(); final createdAt = DateTime.now().millisecondsSinceEpoch ~/ 1000; final eventTags = tags ?? []; // Create event data for signing final eventData = [ 0, pubkey, createdAt, kind, eventTags, content, ]; // Generate event ID (hash of event data) final eventJson = jsonEncode(eventData); final idBytes = sha256.convert(utf8.encode(eventJson)).bytes.sublist(0, 32); final id = idBytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(); // Generate signature (simplified - in real Nostr, use secp256k1) final sigBytes = sha256.convert(utf8.encode(id + privateKey)).bytes.sublist(0, 32); final sig = sigBytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(); return NostrEvent( id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: eventTags, content: content, sig: sig, ); } /// Converts hex string to bytes. static List _hexToBytes(String hex) { final result = []; for (int i = 0; i < hex.length; i += 2) { result.add(int.parse(hex.substring(i, i + 2), radix: 16)); } return result; } @override String toString() { return 'NostrEvent(id: ${id.substring(0, 8)}..., kind: $kind, content: ${content.substring(0, content.length > 20 ? 20 : content.length)}...)'; } }