Skip to content

Commit 0fe7dc9

Browse files
committed
feat: NIP17
1 parent a9c671a commit 0fe7dc9

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ flutter pub add nostr
2222
- [x] [NIP 10 Conventions for clients' use of e and p tags in text events](https://github.com/nostr-protocol/nips/blob/master/10.md)
2323
- [x] [NIP 13 Proof of Work](https://github.com/nostr-protocol/nips/blob/master/13.md)
2424
- [x] [NIP 15 End of Stored Events Notice](https://github.com/nostr-protocol/nips/blob/master/15.md)
25+
- [x] [NIP 17 Private Direct Messages (Partial)](https://github.com/nostr-protocol/nips/blob/master/17.md)
2526
- [x] [NIP 19 bech32-encoded entities](https://github.com/nostr-protocol/nips/blob/master/19.md)
2627
- [x] [NIP 20 Command Results](https://github.com/nostr-protocol/nips/blob/master/20.md)
2728
- [x] [NIP 21 nostr: URI scheme](https://github.com/nostr-protocol/nips/blob/master/21.md)

lib/nostr.dart

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export 'src/nips/nip_005.dart';
1818
export 'src/nips/nip_009.dart';
1919
export 'src/nips/nip_010.dart';
2020
export 'src/nips/nip_013.dart';
21+
export 'src/nips/nip_017.dart';
2122
export 'src/nips/nip_019.dart';
2223
export 'src/nips/nip_020.dart';
2324
export 'src/nips/nip_021.dart';

lib/src/nips/nip_017.dart

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import 'package:nostr/nostr.dart';
2+
3+
class Nip17 {
4+
static Future<Event> encode({
5+
required String message,
6+
required String authorPrivkey,
7+
required String receiverPubkey,
8+
}) async {
9+
final authorPubkey = Keychain(authorPrivkey).public;
10+
11+
final rumor = Event.partial(
12+
pubkey: authorPubkey,
13+
kind: 14,
14+
content: message,
15+
);
16+
rumor.id = rumor.getEventId();
17+
// Kind 14s MUST never be signed.
18+
// If it is signed, the message might leak to relays and become fully public.
19+
rumor.sig = '';
20+
21+
return await Nip59.wrap(
22+
rumor: rumor,
23+
authorPrivkey: authorPrivkey,
24+
recipientPubkey: receiverPubkey,
25+
);
26+
}
27+
28+
static Future<Event> decode({
29+
required Event giftWrap,
30+
required String receiverPrivkey,
31+
}) async {
32+
final dm = await Nip59.unwrap(
33+
giftWrap: giftWrap,
34+
recipientPrivkey: receiverPrivkey,
35+
);
36+
37+
if (dm.kind != 14) {
38+
throw Exception('NIP-17 define private direct messages with kind=14');
39+
}
40+
41+
return dm;
42+
}
43+
}

test/nips/nip_017_test.dart

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import 'package:nostr/src/nips/nip_017.dart';
2+
import 'package:test/test.dart';
3+
import 'package:nostr/nostr.dart';
4+
5+
void main() async {
6+
final authorNsec =
7+
'nsec1w8udu59ydjvedgs3yv5qccshcj8k05fh3l60k9x57asjrqdpa00qkmr89m';
8+
final authorPrivkey = Nip19.decodePrivkey(authorNsec);
9+
final author = Keychain(authorPrivkey);
10+
11+
final recipientNsec =
12+
'nsec12ywtkplvyq5t6twdqwwygavp5lm4fhuang89c943nf2z92eez43szvn4dt';
13+
final recipientPrivkey = Nip19.decodePrivkey(recipientNsec);
14+
final recipient = Keychain(recipientPrivkey);
15+
16+
final message = 'Hola, que tal?';
17+
18+
final dm = await Nip17.encode(
19+
authorPrivkey: author.private,
20+
receiverPubkey: recipient.public,
21+
message: message,
22+
);
23+
24+
group('NIP-17 Direct Message', () {
25+
test('encode a direct message', () async {
26+
expect(dm.kind, 1059);
27+
expect(dm.tags, [
28+
[
29+
"p",
30+
"918e2da906df4ccd12c8ac672d8335add131a4cf9d27ce42b3bb3625755f0788"
31+
]
32+
]);
33+
});
34+
35+
test('decode a direct message', () async {
36+
final x = await Nip17.decode(
37+
giftWrap: dm,
38+
receiverPrivkey: recipient.private,
39+
);
40+
41+
expect(x.kind, 14);
42+
expect(x.pubkey, author.public);
43+
expect(x.sig, isEmpty);
44+
});
45+
});
46+
}

0 commit comments

Comments
 (0)