wireweave 0.3.44 → 0.3.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/dm.js +39 -27
package/package.json
CHANGED
package/src/dm.js
CHANGED
|
@@ -1,41 +1,53 @@
|
|
|
1
|
+
const GIFT_WRAP_KIND = 1059;
|
|
2
|
+
|
|
1
3
|
export class DM extends EventTarget {
|
|
2
4
|
constructor({ relayPool, auth, nostrTools }) {
|
|
3
5
|
super();
|
|
4
6
|
if (!relayPool || !auth || !nostrTools) throw new Error('DM: deps required');
|
|
5
7
|
if (!nostrTools.nip44) throw new Error('nostr-tools nip44 missing');
|
|
8
|
+
if (!nostrTools.nip59) throw new Error('nostr-tools nip59 missing');
|
|
6
9
|
this.pool = relayPool;
|
|
7
10
|
this.auth = auth;
|
|
8
11
|
this.NT = nostrTools;
|
|
9
12
|
this.subId = null;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
// NIP-17: send is a real kind:14 rumor, gift-wrapped (NIP-59) once per
|
|
16
|
+
// recipient and once more for ourselves (self-copy), each wrap signed by
|
|
17
|
+
// a fresh single-use random key so no relay observer can attribute the
|
|
18
|
+
// wrap's outer envelope to either the sender or the recipient — only the
|
|
19
|
+
// holder of the recipient's (or our own) private key can even see it's a
|
|
20
|
+
// DM at all, let alone read it or learn who sent it.
|
|
19
21
|
async send(peerPubkey, plaintext) {
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
const signed = await this.auth.sign({
|
|
22
|
+
if (!this.auth.privkey) throw new Error('DM: privkey required (extension signing not supported for nip17)');
|
|
23
|
+
const rumor = {
|
|
23
24
|
kind: 14,
|
|
24
25
|
created_at: Math.floor(Date.now() / 1000),
|
|
25
26
|
tags: [['p', peerPubkey]],
|
|
26
|
-
content:
|
|
27
|
-
}
|
|
28
|
-
this.
|
|
29
|
-
|
|
27
|
+
content: plaintext
|
|
28
|
+
};
|
|
29
|
+
const wrapForPeer = this.NT.nip59.wrapEvent(rumor, this.auth.privkey, peerPubkey);
|
|
30
|
+
const wrapForSelf = this.NT.nip59.wrapEvent(rumor, this.auth.privkey, this.auth.pubkey);
|
|
31
|
+
this.pool.publish(wrapForPeer);
|
|
32
|
+
this.pool.publish(wrapForSelf);
|
|
33
|
+
return wrapForPeer;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Unwrap a gift-wrap (kind 1059) down to its rumor and return the
|
|
37
|
+
// plaintext. Requires our own privkey — only the wrap's addressed
|
|
38
|
+
// recipient (the 'p' tag on the outer event) can unwrap it.
|
|
39
|
+
decrypt(wrap) {
|
|
40
|
+
if (!this.auth.privkey) throw new Error('DM: privkey required (extension signing not supported for nip17)');
|
|
41
|
+
const rumor = this.NT.nip59.unwrapEvent(wrap, this.auth.privkey);
|
|
42
|
+
return rumor.content;
|
|
30
43
|
}
|
|
31
44
|
|
|
32
|
-
decrypt(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (!
|
|
37
|
-
|
|
38
|
-
return this.NT.nip44.v2.decrypt(event.content, key);
|
|
45
|
+
// Same as decrypt() but returns the full unwrapped rumor (sender pubkey,
|
|
46
|
+
// created_at, tags) alongside the plaintext, for callers that need the
|
|
47
|
+
// real (rumor-level) sender identity rather than the wrap's throwaway key.
|
|
48
|
+
unwrap(wrap) {
|
|
49
|
+
if (!this.auth.privkey) throw new Error('DM: privkey required (extension signing not supported for nip17)');
|
|
50
|
+
return this.NT.nip59.unwrapEvent(wrap, this.auth.privkey);
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
subscribe(onMessage) {
|
|
@@ -43,14 +55,14 @@ export class DM extends EventTarget {
|
|
|
43
55
|
const subId = 'dm-' + this.auth.pubkey.slice(0, 16);
|
|
44
56
|
this.subId = subId;
|
|
45
57
|
this.pool.subscribe(subId, [
|
|
46
|
-
{ kinds: [
|
|
47
|
-
{ kinds: [14], authors: [this.auth.pubkey] }
|
|
58
|
+
{ kinds: [GIFT_WRAP_KIND], '#p': [this.auth.pubkey] }
|
|
48
59
|
], (event) => {
|
|
49
60
|
try {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
? (
|
|
53
|
-
:
|
|
61
|
+
const rumor = this.unwrap(event);
|
|
62
|
+
const peer = rumor.pubkey === this.auth.pubkey
|
|
63
|
+
? (rumor.tags.find(t => t[0] === 'p')?.[1] || '')
|
|
64
|
+
: rumor.pubkey;
|
|
65
|
+
onMessage({ event, rumor, plaintext: rumor.content, peer });
|
|
54
66
|
} catch (e) {
|
|
55
67
|
this._emit('error', { event, error: e.message });
|
|
56
68
|
}
|