nostr-tools 0.12.1 → 0.13.0
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/.eslintrc.json +1 -0
- package/event.js +4 -4
- package/index.js +1 -0
- package/keys.js +3 -3
- package/nip06.js +0 -1
- package/package.json +6 -3
- package/pool.js +72 -37
- package/relay.js +21 -14
package/.eslintrc.json
CHANGED
package/event.js
CHANGED
|
@@ -34,13 +34,13 @@ export function verifySignature(event) {
|
|
|
34
34
|
if (event.id !== getEventHash(event)) return false
|
|
35
35
|
return verifySchnorr(
|
|
36
36
|
Buffer.from(event.id, 'hex'),
|
|
37
|
-
Buffer.from(event.pubkey, 'hex')
|
|
38
|
-
Buffer.from(event.sig, 'hex')
|
|
37
|
+
Buffer.from(event.pubkey, 'hex'),
|
|
38
|
+
Buffer.from(event.sig, 'hex')
|
|
39
39
|
)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export function signEvent(event, key) {
|
|
43
43
|
let eventHash = Buffer.from(getEventHash(event), 'hex')
|
|
44
|
-
let
|
|
45
|
-
return Buffer.from(signSchnorr(eventHash,
|
|
44
|
+
let keyB = Buffer.from(key, 'hex')
|
|
45
|
+
return Buffer.from(signSchnorr(eventHash, keyB)).toString('hex')
|
|
46
46
|
}
|
package/index.js
CHANGED
package/keys.js
CHANGED
|
@@ -13,7 +13,7 @@ export function generatePrivateKey() {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function getPublicKey(privateKey) {
|
|
16
|
-
return Buffer.from(
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
return Buffer.from(pointFromScalar(Buffer.from(privateKey, 'hex'), true))
|
|
17
|
+
.toString('hex')
|
|
18
|
+
.slice(2)
|
|
19
19
|
}
|
package/nip06.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nostr-tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Tools for making a Nostr client.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"browserify-cipher": ">=1",
|
|
13
13
|
"buffer": ">=5",
|
|
14
14
|
"create-hash": "^1.2.0",
|
|
15
|
-
"create-hmac": ">=1",
|
|
16
15
|
"dns-packet": "^5.2.4",
|
|
17
16
|
"micro-bip39": "^0.1.3",
|
|
18
17
|
"randombytes": ">=2",
|
|
@@ -30,5 +29,9 @@
|
|
|
30
29
|
"censorship",
|
|
31
30
|
"censorship-resistance",
|
|
32
31
|
"client"
|
|
33
|
-
]
|
|
32
|
+
],
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"eslint": "^8.5.0",
|
|
35
|
+
"eslint-plugin-babel": "^5.3.1"
|
|
36
|
+
}
|
|
34
37
|
}
|
package/pool.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import {getEventHash, signEvent} from './event'
|
|
2
2
|
import {relayConnect, normalizeRelayURL} from './relay'
|
|
3
3
|
|
|
4
|
-
export function relayPool(
|
|
4
|
+
export function relayPool() {
|
|
5
|
+
var globalPrivateKey
|
|
6
|
+
const poolPolicy = {
|
|
7
|
+
// setting this to a number will cause events to be published to a random
|
|
8
|
+
// set of relays only, instead of publishing to all relays all the time
|
|
9
|
+
randomChoice: null
|
|
10
|
+
}
|
|
5
11
|
const relays = {}
|
|
6
|
-
const globalSub = []
|
|
7
12
|
const noticeCallbacks = []
|
|
8
13
|
|
|
9
14
|
function propagateNotice(notice, relayURL) {
|
|
@@ -28,29 +33,34 @@ export function relayPool(globalPrivateKey) {
|
|
|
28
33
|
const activeCallback = cb
|
|
29
34
|
const activeFilters = filter
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
unsub: () => {
|
|
51
|
-
Object.values(subControllers).forEach(sub => sub.unsub())
|
|
52
|
-
delete activeSubscriptions[id]
|
|
36
|
+
const unsub = () => {
|
|
37
|
+
Object.values(subControllers).forEach(sub => sub.unsub())
|
|
38
|
+
delete activeSubscriptions[id]
|
|
39
|
+
}
|
|
40
|
+
const sub = ({cb = activeCallback, filter = activeFilters}) => {
|
|
41
|
+
Object.entries(subControllers).map(([relayURL, sub]) => [
|
|
42
|
+
relayURL,
|
|
43
|
+
sub.sub({cb, filter}, id)
|
|
44
|
+
])
|
|
45
|
+
return activeSubscriptions[id]
|
|
46
|
+
}
|
|
47
|
+
const addRelay = relay => {
|
|
48
|
+
subControllers[relay.url] = relay.sub({cb, filter}, id)
|
|
49
|
+
return activeSubscriptions[id]
|
|
50
|
+
}
|
|
51
|
+
const removeRelay = relayURL => {
|
|
52
|
+
if (relayURL in subControllers) {
|
|
53
|
+
subControllers[relayURL].unsub()
|
|
54
|
+
if (Object.keys(subControllers).length === 0) unsub()
|
|
53
55
|
}
|
|
56
|
+
return activeSubscriptions[id]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
activeSubscriptions[id] = {
|
|
60
|
+
sub,
|
|
61
|
+
unsub,
|
|
62
|
+
addRelay,
|
|
63
|
+
removeRelay
|
|
54
64
|
}
|
|
55
65
|
|
|
56
66
|
return activeSubscriptions[id]
|
|
@@ -62,11 +72,14 @@ export function relayPool(globalPrivateKey) {
|
|
|
62
72
|
setPrivateKey(privateKey) {
|
|
63
73
|
globalPrivateKey = privateKey
|
|
64
74
|
},
|
|
65
|
-
|
|
75
|
+
setPolicy(key, value) {
|
|
76
|
+
poolPolicy[key] = value
|
|
77
|
+
},
|
|
78
|
+
addRelay(url, policy = {read: true, write: true}) {
|
|
66
79
|
let relayURL = normalizeRelayURL(url)
|
|
67
80
|
if (relayURL in relays) return
|
|
68
81
|
|
|
69
|
-
let relay =
|
|
82
|
+
let relay = relayConnect(url, notice => {
|
|
70
83
|
propagateNotice(notice, relayURL)
|
|
71
84
|
})
|
|
72
85
|
relays[relayURL] = {relay, policy}
|
|
@@ -95,13 +108,13 @@ export function relayPool(globalPrivateKey) {
|
|
|
95
108
|
if (index !== -1) noticeCallbacks.splice(index, 1)
|
|
96
109
|
},
|
|
97
110
|
async publish(event, statusCallback = (status, relayURL) => {}) {
|
|
98
|
-
event.id =
|
|
111
|
+
event.id = getEventHash(event)
|
|
99
112
|
|
|
100
113
|
if (!event.sig) {
|
|
101
114
|
event.tags = event.tags || []
|
|
102
115
|
|
|
103
116
|
if (globalPrivateKey) {
|
|
104
|
-
event.sig =
|
|
117
|
+
event.sig = signEvent(event, globalPrivateKey)
|
|
105
118
|
} else {
|
|
106
119
|
throw new Error(
|
|
107
120
|
"can't publish unsigned event. either sign this event beforehand or pass a private key while initializing this relay pool so it can be signed automatically."
|
|
@@ -109,17 +122,39 @@ export function relayPool(globalPrivateKey) {
|
|
|
109
122
|
}
|
|
110
123
|
}
|
|
111
124
|
|
|
112
|
-
Object.values(relays)
|
|
125
|
+
let writeable = Object.values(relays)
|
|
113
126
|
.filter(({policy}) => policy.write)
|
|
114
|
-
.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
127
|
+
.sort(() => Math.random() - 0.5) // random
|
|
128
|
+
|
|
129
|
+
let maxTargets = poolPolicy.randomChoice
|
|
130
|
+
? poolPolicy.randomChoice
|
|
131
|
+
: writeable.length
|
|
132
|
+
|
|
133
|
+
let successes = 0
|
|
134
|
+
|
|
135
|
+
for (let i = 0; i < writeable.length; i++) {
|
|
136
|
+
let {relay} = writeable[i]
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
await new Promise(async (resolve, reject) => {
|
|
140
|
+
try {
|
|
141
|
+
await relay.publish(event, status => {
|
|
142
|
+
statusCallback(status, relay.url)
|
|
143
|
+
resolve()
|
|
144
|
+
})
|
|
145
|
+
} catch (err) {
|
|
146
|
+
statusCallback(-1, relay.url)
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
successes++
|
|
151
|
+
if (successes >= maxTargets) {
|
|
152
|
+
break
|
|
121
153
|
}
|
|
122
|
-
})
|
|
154
|
+
} catch (err) {
|
|
155
|
+
/***/
|
|
156
|
+
}
|
|
157
|
+
}
|
|
123
158
|
|
|
124
159
|
return event
|
|
125
160
|
}
|
package/relay.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/* global WebSocket */
|
|
2
|
+
|
|
1
3
|
import 'websocket-polyfill'
|
|
2
4
|
|
|
3
5
|
import {verifySignature} from './event'
|
|
@@ -11,7 +13,7 @@ export function normalizeRelayURL(url) {
|
|
|
11
13
|
return [host, ...qs].join('?')
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
export function relayConnect(url, onNotice) {
|
|
16
|
+
export function relayConnect(url, onNotice = () => {}, onError = () => {}) {
|
|
15
17
|
url = normalizeRelayURL(url)
|
|
16
18
|
|
|
17
19
|
var ws, resolveOpen, untilOpen, wasClosed
|
|
@@ -44,8 +46,9 @@ export function relayConnect(url, onNotice) {
|
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
|
-
ws.onerror = () => {
|
|
49
|
+
ws.onerror = (err) => {
|
|
48
50
|
console.log('error connecting to relay', url)
|
|
51
|
+
onError(err)
|
|
49
52
|
}
|
|
50
53
|
ws.onclose = () => {
|
|
51
54
|
resetOpenState()
|
|
@@ -144,22 +147,26 @@ export function relayConnect(url, onNotice) {
|
|
|
144
147
|
return {
|
|
145
148
|
url,
|
|
146
149
|
sub,
|
|
147
|
-
async publish(event, statusCallback
|
|
150
|
+
async publish(event, statusCallback) {
|
|
148
151
|
try {
|
|
149
152
|
await trySend(['EVENT', event])
|
|
150
|
-
statusCallback
|
|
151
|
-
|
|
152
|
-
{
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
if (statusCallback) {
|
|
154
|
+
statusCallback(0)
|
|
155
|
+
let {unsub} = sub(
|
|
156
|
+
{
|
|
157
|
+
cb: () => {
|
|
158
|
+
statusCallback(1)
|
|
159
|
+
unsub()
|
|
160
|
+
clearTimeout(willUnsub)
|
|
161
|
+
},
|
|
162
|
+
filter: {id: event.id}
|
|
155
163
|
},
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
setTimeout(unsub, 5000)
|
|
164
|
+
`monitor-${event.id.slice(0, 5)}`
|
|
165
|
+
)
|
|
166
|
+
let willUnsub = setTimeout(unsub, 5000)
|
|
167
|
+
}
|
|
161
168
|
} catch (err) {
|
|
162
|
-
statusCallback(-1)
|
|
169
|
+
if (statusCallback) statusCallback(-1)
|
|
163
170
|
}
|
|
164
171
|
},
|
|
165
172
|
close() {
|