Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ class ObserverRelayNotifier extends Notifier<ObserverRelayState> {

static String _decodePrivkey(String nsec) {
try {
final privHex = nostr.Nip19.decodePrivkey(nsec);
final privHex = nostr.Nip19.decode(payload: nsec).data;
if (privHex.isEmpty) {
throw const FormatException('empty private key');
}
Expand All @@ -283,7 +283,7 @@ class ObserverRelayNotifier extends Notifier<ObserverRelayState> {

static String _derivePubkey(String privHex) {
try {
return nostr.Keychain(privHex).public;
return nostr.Keys(privHex).public;
} catch (_) {
throw const FormatException('failed to derive pubkey');
}
Expand Down
6 changes: 3 additions & 3 deletions mobile/lib/features/channels/compose_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ void _sendTypingIndicator(
final nsec = config.nsec;
if (nsec == null || nsec.isEmpty) return;

final privkeyHex = nostr.Nip19.decodePrivkey(nsec);
final privkeyHex = nostr.Nip19.decode(payload: nsec).data;
if (privkeyHex.isEmpty) return;

final tags = <List<String>>[
Expand All @@ -609,13 +609,13 @@ void _sendTypingIndicator(
kind: EventKind.typingIndicator,
content: '',
tags: tags,
privkey: privkeyHex,
secretKey: privkeyHex,
verify: false,
);

// Send directly over WebSocket — fire-and-forget, matching desktop.
final session = ref.read(relaySessionProvider.notifier);
session.sendRaw(['EVENT', event.toJson()]);
session.sendRaw(['EVENT', event.toMap()]);
} catch (_) {
// Fire-and-forget — typing indicator failure is non-fatal.
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class ReadStateCrypto {
required String pubkey,
}) {
try {
final privkeyHex = nostr.Nip19.decodePrivkey(nsec);
final privkeyHex = nostr.Nip19.decode(payload: nsec).data;
if (privkeyHex.isEmpty || pubkey.isEmpty) {
return null;
}
Expand Down
10 changes: 5 additions & 5 deletions mobile/lib/features/pairing/pairing_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ class PairingNotifier extends Notifier<PairingState> {
final relayWsUrl = qr.relays.first;

// 2. Generate ephemeral keypair.
final keychain = nostr.Keychain.generate();
_ephemeralPrivkey = keychain.private;
final keychain = nostr.Keys.generate();
_ephemeralPrivkey = keychain.secret;
_ephemeralPubkey = keychain.public;

// 3. Derive session ID and SAS immediately (we know source pubkey from QR).
Expand Down Expand Up @@ -302,7 +302,7 @@ class PairingNotifier extends Notifier<PairingState> {
// NIP-AB §Event Validation: verify event signature (NIP-01).
// The nostr package's Event.fromJson verifies id + sig on construction.
try {
final event = nostr.Event.fromJson(eventJson);
final event = nostr.Event.fromJson(jsonEncode(eventJson));
if (event.id != eventId) return; // id mismatch
} catch (_) {
return; // invalid signature or malformed event
Expand Down Expand Up @@ -507,11 +507,11 @@ class PairingNotifier extends Notifier<PairingState> {
kind: kind,
content: content,
tags: tags,
privkey: _ephemeralPrivkey!,
secretKey: _ephemeralPrivkey!,
createdAt: createdAt,
);

_socket?.publishEvent(event.toJson());
_socket?.publishEvent(event.toMap());
}

void _handleDisconnected(Object? error) {
Expand Down
4 changes: 2 additions & 2 deletions mobile/lib/features/pairing/pairing_socket.dart
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,12 @@ class PairingSocket {
kind: EventKind.auth,
content: '',
tags: tags,
privkey: _ephemeralPrivkey,
secretKey: _ephemeralPrivkey,
createdAt: DateTime.now().millisecondsSinceEpoch ~/ 1000,
);

_pendingAuthEventId = event.id;
send(['AUTH', event.toJson()]);
send(['AUTH', event.toMap()]);
} catch (e) {
_failAuth(e);
}
Expand Down
12 changes: 6 additions & 6 deletions mobile/lib/features/profile/user_status_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class UserStatusNotifier extends AsyncNotifier<UserStatus?> {

String pubkey;
try {
final privkeyHex = nostr.Nip19.decodePrivkey(nsec);
final keyPair = nostr.Keychain(privkeyHex);
final privkeyHex = nostr.Nip19.decode(payload: nsec).data;
final keyPair = nostr.Keys(privkeyHex);
pubkey = keyPair.public.toLowerCase();
} catch (_) {
return null;
Expand Down Expand Up @@ -74,18 +74,18 @@ class UserStatusNotifier extends AsyncNotifier<UserStatus?> {
tags.add(['emoji', emoji]);
}

final privkeyHex = nostr.Nip19.decodePrivkey(nsec);
final privkeyHex = nostr.Nip19.decode(payload: nsec).data;
final event = nostr.Event.from(
kind: EventKind.userStatus,
content: trimmed,
tags: tags,
privkey: privkeyHex,
secretKey: privkeyHex,
verify: false,
);

final session = ref.read(relaySessionProvider.notifier);
await session.publish(
NostrEvent.fromJson(Map<String, dynamic>.from(event.toJson())),
NostrEvent.fromJson(event.toMap()),
);

// Optimistic update: update own state immediately.
Expand All @@ -99,7 +99,7 @@ class UserStatusNotifier extends AsyncNotifier<UserStatus?> {
state = AsyncValue.data(newStatus);

// Also update the shared cache so other UI reads stay consistent.
final keyPair = nostr.Keychain(privkeyHex);
final keyPair = nostr.Keys(privkeyHex);
final pubkey = keyPair.public.toLowerCase();
ref.read(userStatusCacheProvider.notifier).updateStatus(pubkey, newStatus);
}
Expand Down
4 changes: 2 additions & 2 deletions mobile/lib/features/settings/settings_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ class SettingsPage extends HookConsumerWidget {
const SizedBox(height: Grid.xxs),
Builder(
builder: (context) {
final privHex = nostr.Nip19.decodePrivkey(config.nsec!);
final privHex = nostr.Nip19.decode(payload: config.nsec!).data;
final pubkey = privHex.isNotEmpty
? nostr.Keychain(privHex).public
? nostr.Keys(privHex).public
: 'unknown';
return ListTile(
leading: const Icon(LucideIcons.key),
Expand Down
6 changes: 3 additions & 3 deletions mobile/lib/shared/relay/media_upload.dart
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ class MediaUploadService {

String _buildUploadAuthHeader(String sha256) {
final authEvent = _buildUploadAuthEvent(sha256);
final authJson = jsonEncode(authEvent.toJson());
final authJson = authEvent.toJson();
final encoded = base64Url.encode(utf8.encode(authJson)).replaceAll('=', '');
return 'Nostr $encoded';
}
Expand All @@ -281,7 +281,7 @@ class MediaUploadService {
throw Exception('Cannot upload media: no signing key available');
}

final privkeyHex = nostr.Nip19.decodePrivkey(nsec);
final privkeyHex = nostr.Nip19.decode(payload: nsec).data;
if (privkeyHex.isEmpty) {
throw Exception('Invalid nsec');
}
Expand All @@ -300,7 +300,7 @@ class MediaUploadService {
kind: _uploadAuthKind,
content: 'Upload sprout-media',
tags: tags,
privkey: privkeyHex,
secretKey: privkeyHex,
verify: false,
);
}
Expand Down
4 changes: 2 additions & 2 deletions mobile/lib/shared/relay/relay_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ final relayConfigProvider = NotifierProvider<RelayConfigNotifier, RelayConfig>(
String? pubkeyFromNsec(String? nsec) {
if (nsec == null || nsec.isEmpty) return null;
try {
final privkeyHex = nostr.Nip19.decodePrivkey(nsec);
final privkeyHex = nostr.Nip19.decode(payload: nsec).data;
if (privkeyHex.isEmpty) return null;
return nostr.Keychain(privkeyHex).public;
return nostr.Keys(privkeyHex).public;
} catch (_) {
return null;
}
Expand Down
6 changes: 3 additions & 3 deletions mobile/lib/shared/relay/relay_socket.dart
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class RelaySocket {

try {
// Decode bech32 nsec to hex private key.
final privkeyHex = nostr.Nip19.decodePrivkey(_nsec);
final privkeyHex = nostr.Nip19.decode(payload: _nsec).data;
if (privkeyHex.isEmpty) {
_failAuth(Exception('Invalid nsec'));
return;
Expand All @@ -195,11 +195,11 @@ class RelaySocket {
kind: EventKind.auth,
content: '',
tags: tags,
privkey: privkeyHex,
secretKey: privkeyHex,
);

_pendingAuthEventId = event.id;
send(['AUTH', event.toJson()]);
send(['AUTH', event.toMap()]);
} catch (e) {
_failAuth(e);
}
Expand Down
10 changes: 5 additions & 5 deletions mobile/lib/shared/relay/signed_event_relay.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ class SignedEventRelay {
String? get pubkey {
final nsec = _nsec;
if (nsec == null || nsec.isEmpty) return null;
final privkeyHex = nostr.Nip19.decodePrivkey(nsec);
final privkeyHex = nostr.Nip19.decode(payload: nsec).data;
if (privkeyHex.isEmpty) return null;
return nostr.Keychain(privkeyHex).public;
return nostr.Keys(privkeyHex).public;
}

/// Sign and submit an event. Returns the relay's OK response as a [NostrEvent]
Expand All @@ -37,7 +37,7 @@ class SignedEventRelay {
throw Exception('Cannot submit event: no signing key available');
}

final privkeyHex = nostr.Nip19.decodePrivkey(nsec);
final privkeyHex = nostr.Nip19.decode(payload: nsec).data;
if (privkeyHex.isEmpty) {
throw Exception('Invalid nsec');
}
Expand All @@ -46,12 +46,12 @@ class SignedEventRelay {
kind: kind,
content: content,
tags: tags,
privkey: privkeyHex,
secretKey: privkeyHex,
createdAt: createdAt,
verify: false,
);

final nostrEvent = NostrEvent.fromJson(event.toJson());
final nostrEvent = NostrEvent.fromJson(event.toMap());
return _session.publish(nostrEvent);
}
}
44 changes: 22 additions & 22 deletions mobile/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ packages:
dependency: transitive
description:
name: bip340
sha256: "2a92f6ed68959f75d67c9a304c17928b9c9449587d4f75ee68f34152f7f69e87"
sha256: "4c2df9fa2409d26f1d9334b2801015ebe4dc3978191f186743e60e89a90230c4"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "0.3.1"
boolean_selector:
dependency: transitive
description:
Expand Down Expand Up @@ -249,6 +249,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.12"
elliptic:
dependency: transitive
description:
name: elliptic
sha256: "67931d408faa353bdebac9f7a1df0c3f6f828f4e8439cdf084573cd1601a2f4b"
url: "https://pub.dev"
source: hosted
version: "0.3.12"
fake_async:
dependency: transitive
description:
Expand Down Expand Up @@ -608,14 +616,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.1"
js:
dependency: transitive
description:
name: js
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
version: "0.6.7"
json_annotation:
dependency: transitive
description:
Expand Down Expand Up @@ -692,10 +692,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.17.0"
mime:
dependency: transitive
description:
Expand Down Expand Up @@ -756,10 +756,10 @@ packages:
dependency: "direct main"
description:
name: nostr
sha256: a99942e4eedd5823d16f42e6df96240488028666a329ee1047552f79db564123
sha256: "44d602199d032e40a469b8e00e3c58e1b0c206673e0edf4a4a468499f75f6298"
url: "https://pub.dev"
source: hosted
version: "1.5.0"
version: "2.0.0"
objective_c:
dependency: transitive
description:
Expand Down Expand Up @@ -884,10 +884,10 @@ packages:
dependency: "direct main"
description:
name: pointycastle
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5"
url: "https://pub.dev"
source: hosted
version: "3.9.1"
version: "4.0.0"
pool:
dependency: transitive
description:
Expand Down Expand Up @@ -1121,26 +1121,26 @@ packages:
dependency: transitive
description:
name: test
sha256: "8d9ceddbab833f180fbefed08afa76d7c03513dfdba87ffcec2718b02bbcbf20"
sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7"
url: "https://pub.dev"
source: hosted
version: "1.31.0"
version: "1.30.0"
test_api:
dependency: transitive
description:
name: test_api
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
url: "https://pub.dev"
source: hosted
version: "0.7.11"
version: "0.7.10"
test_core:
dependency: transitive
description:
name: test_core
sha256: "1991d4cfe85d5043241acac92962c3977c8d2f2add1ee73130c7b286417d1d34"
sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51"
url: "https://pub.dev"
source: hosted
version: "0.6.17"
version: "0.6.16"
tuple:
dependency: transitive
description:
Expand Down
4 changes: 2 additions & 2 deletions mobile/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ dependencies:
shared_preferences: ^2.5.5
web_socket_channel: ^3.0.1
connectivity_plus: ^7.0.0
nostr: ^1.5.0
pointycastle: ^3.7.3
nostr: ^2.0.0
pointycastle: ^4.0.0
url_launcher: ^6.3.2
gpt_markdown: ^1.1.6
intl: ^0.20.2
Expand Down
Loading
Loading