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 CHANGED
@@ -1,4 +1,5 @@
1
1
  {
2
+ "root": true,
2
3
  "parserOptions": {
3
4
  "ecmaVersion": 9,
4
5
  "ecmaFeatures": {
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 key = Buffer.from(key, 'hex')
45
- return Buffer.from(signSchnorr(eventHash, key)).toString('hex')
44
+ let keyB = Buffer.from(key, 'hex')
45
+ return Buffer.from(signSchnorr(eventHash, keyB)).toString('hex')
46
46
  }
package/index.js CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  import {matchFilter, matchFilters} from './filter'
12
12
 
13
13
  export {
14
+ generatePrivateKey,
14
15
  relayConnect,
15
16
  relayPool,
16
17
  signEvent,
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
- pointFromScalar(Buffer.from(privateKey, 'hex'), true)
18
- ).toString('hex')
16
+ return Buffer.from(pointFromScalar(Buffer.from(privateKey, 'hex'), true))
17
+ .toString('hex')
18
+ .slice(2)
19
19
  }
package/nip06.js CHANGED
@@ -1,4 +1,3 @@
1
- import createHmac from 'create-hmac'
2
1
  import {wordlist} from 'micro-bip39/wordlists/english'
3
2
  import {
4
3
  generateMnemonic,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nostr-tools",
3
- "version": "0.12.1",
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(globalPrivateKey) {
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
- activeSubscriptions[id] = {
32
- sub: ({cb = activeCallback, filter = activeFilters}) => {
33
- Object.entries(subControllers).map(([relayURL, sub]) => [
34
- relayURL,
35
- sub.sub({cb, filter}, id)
36
- ])
37
- return activeSubscriptions[id]
38
- },
39
- addRelay: relay => {
40
- subControllers[relay.url] = relay.sub({cb, filter}, id)
41
- return activeSubscriptions[id]
42
- },
43
- removeRelay: relayURL => {
44
- if (relayURL in subControllers) {
45
- subControllers[relayURL].unsub()
46
- if (Object.keys(subControllers).length === 0) unsub()
47
- }
48
- return activeSubscriptions[id]
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
- async addRelay(url, policy = {read: true, write: true}) {
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 = await relayConnect(url, notice => {
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 = await getEventHash(event)
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 = await signEvent(event, globalPrivateKey)
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
- .map(async ({relay}) => {
115
- try {
116
- await relay.publish(event, status =>
117
- statusCallback(status, relay.url)
118
- )
119
- } catch (err) {
120
- statusCallback(-1, relay.url)
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 = status => {}) {
150
+ async publish(event, statusCallback) {
148
151
  try {
149
152
  await trySend(['EVENT', event])
150
- statusCallback(0)
151
- let {unsub} = relay.sub(
152
- {
153
- cb: () => {
154
- statusCallback(1)
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
- filter: {id: event.id}
157
- },
158
- `monitor-${event.id.slice(0, 5)}`
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() {