hypercore 10.22.3 → 10.24.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/index.js CHANGED
@@ -8,6 +8,7 @@ const Xache = require('xache')
8
8
  const NoiseSecretStream = require('@hyperswarm/secret-stream')
9
9
  const Protomux = require('protomux')
10
10
  const z32 = require('z32')
11
+ const id = require('hypercore-id-encoding')
11
12
 
12
13
  const Replicator = require('./lib/replicator')
13
14
  const Core = require('./lib/core')
@@ -15,6 +16,7 @@ const BlockEncryption = require('./lib/block-encryption')
15
16
  const Info = require('./lib/info')
16
17
  const Download = require('./lib/download')
17
18
  const Batch = require('./lib/batch')
19
+ const { manifestHash, defaultSignerManifest, createVerifier, createManifest, isCompat } = require('./lib/manifest')
18
20
  const { ReadStream, WriteStream, ByteStream } = require('./lib/streams')
19
21
  const {
20
22
  BAD_ARGUMENT,
@@ -41,16 +43,9 @@ module.exports = class Hypercore extends EventEmitter {
41
43
  key = opts.key || null
42
44
  }
43
45
 
44
- if (key && typeof key === 'string') {
45
- key = b4a.from(key, 'hex')
46
- }
47
-
46
+ if (key && typeof key === 'string') key = id.decode(key)
48
47
  if (!opts) opts = {}
49
48
 
50
- if (!opts.crypto && key && key.byteLength !== 32) {
51
- throw BAD_ARGUMENT('Hypercore key should be 32 bytes')
52
- }
53
-
54
49
  if (!storage) storage = opts.storage
55
50
 
56
51
  this[promises] = true
@@ -69,7 +64,7 @@ module.exports = class Hypercore extends EventEmitter {
69
64
 
70
65
  this.id = null
71
66
  this.key = key || null
72
- this.keyPair = null
67
+ this.keyPair = opts.keyPair || null
73
68
  this.readable = true
74
69
  this.writable = false
75
70
  this.opened = false
@@ -77,22 +72,22 @@ module.exports = class Hypercore extends EventEmitter {
77
72
  this.snapshotted = !!opts.snapshot
78
73
  this.sparse = opts.sparse !== false
79
74
  this.sessions = opts._sessions || [this]
80
- this.auth = opts.auth || null
81
75
  this.autoClose = !!opts.autoClose
82
76
  this.onwait = opts.onwait || null
83
77
  this.wait = opts.wait !== false
84
78
  this.timeout = opts.timeout || 0
85
- this._clone = opts.clone || null
86
- this._readonly = opts.writable === false
87
-
88
79
  this.closing = null
89
- this.opening = this._openSession(key, storage, opts)
90
- this.opening.catch(noop)
80
+ this.opening = null
91
81
 
82
+ this._clone = opts.clone || null
83
+ this._readonly = opts.writable === false
92
84
  this._preappend = preappend.bind(this)
93
85
  this._snapshot = null
94
86
  this._batch = opts._batch || null
95
87
  this._findingPeers = 0
88
+
89
+ this.opening = this._openSession(key, storage, opts)
90
+ this.opening.catch(noop)
96
91
  }
97
92
 
98
93
  [inspect] (depth, opts) {
@@ -139,6 +134,14 @@ module.exports = class Hypercore extends EventEmitter {
139
134
  indent + ')'
140
135
  }
141
136
 
137
+ static key (manifest, { compat } = {}) {
138
+ return compat ? manifest.signer.publicKey : manifestHash(manifest)
139
+ }
140
+
141
+ static discoveryKey (key) {
142
+ return hypercoreCrypto.discoveryKey(key)
143
+ }
144
+
142
145
  static getProtocolMuxer (stream) {
143
146
  return stream.noiseStream.userData
144
147
  }
@@ -245,20 +248,19 @@ module.exports = class Hypercore extends EventEmitter {
245
248
  }
246
249
 
247
250
  setKeyPair (keyPair) {
248
- this.auth = Core.createAuth(this.crypto, { keyPair })
249
- this.writable = !this._readonly && !!this.auth && !!this.auth.sign
251
+ this.keyPair = keyPair
252
+ this.writable = this._isWritable()
250
253
  }
251
254
 
252
255
  _passCapabilities (o) {
253
- if (!this.auth) this.auth = o.auth
254
-
256
+ if (!this.keyPair) this.keyPair = o.keyPair
255
257
  this.crypto = o.crypto
256
258
  this.id = o.id
257
259
  this.key = o.key
258
260
  this.core = o.core
259
261
  this.replicator = o.replicator
260
262
  this.encryption = o.encryption
261
- this.writable = !this._readonly && !!this.auth && !!this.auth.sign
263
+ this.writable = this._isWritable()
262
264
  this.autoClose = o.autoClose
263
265
 
264
266
  if (this.snapshotted && this.core && !this._snapshot) this._updateSnapshot()
@@ -288,14 +290,6 @@ module.exports = class Hypercore extends EventEmitter {
288
290
  if (!isFirst) await opts._opening
289
291
  if (opts.preload) opts = { ...opts, ...(await this._retryPreload(opts.preload)) }
290
292
 
291
- const keyPair = opts.keyPair
292
-
293
- if (opts.auth) {
294
- this.auth = opts.auth
295
- } else if (keyPair && keyPair.secretKey) {
296
- this.setKeyPair(keyPair)
297
- }
298
-
299
293
  if (isFirst) {
300
294
  await this._openCapabilities(key, storage, opts)
301
295
  // Only the root session should pass capabilities to other sessions.
@@ -306,15 +300,14 @@ module.exports = class Hypercore extends EventEmitter {
306
300
 
307
301
  // copy state over
308
302
  if (this._clone) {
309
- const { from, upgrade } = this._clone
303
+ const { from, signature } = this._clone
310
304
  await from.opening
311
- await this.core.copyFrom(from.core, upgrade)
305
+ await this.core.copyFrom(from.core, signature)
312
306
  this._clone = null
313
307
  }
314
308
  }
315
309
 
316
- if (!this.auth) this.auth = this.core.defaultAuth
317
- this.writable = !this._readonly && !!this.auth && !!this.auth.sign
310
+ this.writable = this._isWritable()
318
311
 
319
312
  if (opts.valueEncoding) {
320
313
  this.valueEncoding = c.from(opts.valueEncoding)
@@ -353,7 +346,7 @@ module.exports = class Hypercore extends EventEmitter {
353
346
  this.storage = Hypercore.defaultStorage(opts.storage || storage, { unlocked, writable: !unlocked })
354
347
 
355
348
  this.core = await Core.open(this.storage, {
356
- compat: opts.compat !== false, // default to true for now
349
+ compat: opts.compat,
357
350
  force: opts.force,
358
351
  createIfMissing: opts.createIfMissing,
359
352
  readonly: unlocked,
@@ -362,7 +355,7 @@ module.exports = class Hypercore extends EventEmitter {
362
355
  keyPair: opts.keyPair,
363
356
  crypto: this.crypto,
364
357
  legacy: opts.legacy,
365
- auth: opts.auth,
358
+ manifest: opts.manifest,
366
359
  onupdate: this._oncoreupdate.bind(this),
367
360
  onconflict: this._oncoreconflict.bind(this)
368
361
  })
@@ -417,6 +410,10 @@ module.exports = class Hypercore extends EventEmitter {
417
410
  return prev.length !== next.length || prev.fork !== next.fork
418
411
  }
419
412
 
413
+ _isWritable () {
414
+ return !this._readonly && !!(this.keyPair && this.keyPair.secretKey)
415
+ }
416
+
420
417
  close (err) {
421
418
  if (this.closing) return this.closing
422
419
  this.closing = this._close(err || null)
@@ -465,23 +462,22 @@ module.exports = class Hypercore extends EventEmitter {
465
462
  this.emit('close', true)
466
463
  }
467
464
 
468
- clone (storage, opts = {}) {
465
+ clone (keyPair, storage, opts = {}) {
469
466
  // TODO: current limitation is no forking
470
467
  if ((opts.fork && opts.fork !== 0) || this.fork !== 0) {
471
468
  throw BAD_ARGUMENT('Cannot clone a fork')
472
469
  }
473
470
 
474
- const key = opts.key === undefined ? opts.keyPair ? null : this.key : opts.key
475
- const keyPair = (opts.auth || opts.keyPair === undefined) ? null : opts.keyPair
471
+ const manifest = opts.manifest || defaultSignerManifest(keyPair.publicKey)
472
+ const key = opts.key || (opts.compat !== false ? manifest.signer.publicKey : manifestHash(manifest))
476
473
 
477
- let auth = this.core.defaultAuth
478
- if (opts.auth) {
479
- auth = opts.auth
480
- } else if (keyPair && keyPair.secretKey) {
481
- auth = Core.createAuth(this.crypto, { keyPair, manifest: { signer: { publicKey: keyPair.publicKey } } })
474
+ if (b4a.equals(key, this.key)) {
475
+ throw BAD_ARGUMENT('Clone cannot share verification information')
482
476
  }
483
477
 
484
- const upgrade = opts.upgrade === undefined ? null : opts.upgrade
478
+ const signature = opts.signature === undefined
479
+ ? createVerifier(createManifest(manifest), { compat: isCompat(key, manifest) }).sign(this.core.tree.batch(), keyPair)
480
+ : opts.signature
485
481
 
486
482
  const sparse = opts.sparse === false ? false : this.sparse
487
483
  const wait = opts.wait === false ? false : this.wait
@@ -497,11 +493,11 @@ module.exports = class Hypercore extends EventEmitter {
497
493
  wait,
498
494
  onwait,
499
495
  timeout,
500
- auth,
496
+ manifest,
501
497
  overwrite: true,
502
498
  clone: {
503
499
  from: this,
504
- upgrade
500
+ signature
505
501
  }
506
502
  })
507
503
  }
@@ -542,6 +538,10 @@ module.exports = class Hypercore extends EventEmitter {
542
538
  return this.replicator === null ? null : this.replicator.discoveryKey
543
539
  }
544
540
 
541
+ get manifest () {
542
+ return this.core === null ? null : this.core.header.manifest
543
+ }
544
+
545
545
  get length () {
546
546
  if (this._snapshot) return this._snapshot.length
547
547
  if (this.core === null) return 0
@@ -633,6 +633,12 @@ module.exports = class Hypercore extends EventEmitter {
633
633
  this.replicator.onupgrade()
634
634
  }
635
635
 
636
+ if (status & 0b10000) {
637
+ for (let i = 0; i < this.sessions.length; i++) {
638
+ this.sessions[i].emit('manifest')
639
+ }
640
+ }
641
+
636
642
  for (let i = 0; i < this.sessions.length; i++) {
637
643
  const s = this.sessions[i]
638
644
 
@@ -932,22 +938,34 @@ module.exports = class Hypercore extends EventEmitter {
932
938
 
933
939
  async truncate (newLength = 0, opts = {}) {
934
940
  if (this.opened === false) await this.opening
935
- if (this.writable === false) throw SESSION_NOT_WRITABLE()
936
941
 
937
- const { fork = this.core.tree.fork + 1, force = false } = typeof opts === 'number' ? { fork: opts } : opts
942
+ const {
943
+ fork = this.core.tree.fork + 1,
944
+ force = false,
945
+ keyPair = this.keyPair,
946
+ signature = null
947
+ } = typeof opts === 'number' ? { fork: opts } : opts
948
+
949
+ const writable = !this._readonly && !!(signature || (keyPair && keyPair.secretKey))
950
+
951
+ if (writable === false) throw SESSION_NOT_WRITABLE()
938
952
  if (this._batch && !force) throw BATCH_UNFLUSHED()
939
953
 
940
- await this.core.truncate(newLength, fork, this.auth)
954
+ await this.core.truncate(newLength, fork, { keyPair, signature })
941
955
 
942
956
  // TODO: Should propagate from an event triggered by the oplog
943
957
  this.replicator.updateAll()
944
958
  }
945
959
 
946
- async append (blocks, opts) {
960
+ async append (blocks, opts = {}) {
947
961
  if (this._batch && this !== this._batch.session) throw BATCH_UNFLUSHED()
948
962
 
949
963
  if (this.opened === false) await this.opening
950
- if (this.writable === false) throw SESSION_NOT_WRITABLE()
964
+
965
+ const { keyPair = this.keyPair, signature = null } = opts
966
+ const writable = !this._readonly && !!(signature || (keyPair && keyPair.secretKey))
967
+
968
+ if (writable === false) throw SESSION_NOT_WRITABLE()
951
969
 
952
970
  blocks = Array.isArray(blocks) ? blocks : [blocks]
953
971
 
@@ -961,7 +979,7 @@ module.exports = class Hypercore extends EventEmitter {
961
979
  }
962
980
  }
963
981
 
964
- return this.core.append(buffers, (opts && opts.auth) || this.auth, { preappend })
982
+ return this.core.append(buffers, { keyPair, signature, preappend })
965
983
  }
966
984
 
967
985
  async treeHash (length) {
package/lib/batch.js CHANGED
@@ -1,4 +1,4 @@
1
- const { SESSION_NOT_WRITABLE, BLOCK_NOT_AVAILABLE, SESSION_CLOSED } = require('hypercore-errors')
1
+ const { BLOCK_NOT_AVAILABLE, SESSION_CLOSED } = require('hypercore-errors')
2
2
  const EventEmitter = require('events')
3
3
  const c = require('compact-encoding')
4
4
 
@@ -11,6 +11,7 @@ module.exports = class HypercoreBatch extends EventEmitter {
11
11
  this.closed = false
12
12
  this.opening = null
13
13
  this.closing = null
14
+ this.writable = true // always writable...
14
15
  this.autoClose = autoClose
15
16
  this.fork = 0
16
17
 
@@ -51,16 +52,12 @@ module.exports = class HypercoreBatch extends EventEmitter {
51
52
  return this._sessionByteLength + this._byteLength
52
53
  }
53
54
 
54
- get writable () {
55
- return this.session.writable
56
- }
57
-
58
55
  get core () {
59
56
  return this.session.core
60
57
  }
61
58
 
62
- get auth () {
63
- return this.session.auth
59
+ get manifest () {
60
+ return this.session.manifest
64
61
  }
65
62
 
66
63
  async ready () {
@@ -172,20 +169,20 @@ module.exports = class HypercoreBatch extends EventEmitter {
172
169
 
173
170
  async truncate (newLength = 0, opts = {}) {
174
171
  if (this.opened === false) await this.opening
175
- if (this.writable === false) throw SESSION_NOT_WRITABLE()
176
172
  if (this.closing) throw SESSION_CLOSED()
177
173
 
178
174
  // wait for any pending flush... (prop needs a lock)
179
175
  await this._waitForFlush()
180
176
 
181
- const { fork = this.fork + 1, force = false } = typeof opts === 'number' ? { fork: opts } : opts
177
+ if (typeof opts === 'number') opts = { fork: opts }
178
+ const { fork = this.fork + 1, force = false } = opts
182
179
 
183
180
  const length = this._sessionLength
184
181
  if (newLength < length) {
185
182
  if (!force) throw new Error('Cannot truncate committed blocks')
186
183
  this._appends.length = 0
187
184
  this._byteLength = 0
188
- await this.session.truncate(newLength, { fork, force: true })
185
+ await this.session.truncate(newLength, { fork, force: true, ...opts })
189
186
  this._sessionLength = this.session.length
190
187
  this._sessionByteLength = this.session.byteLength
191
188
  } else {
@@ -202,7 +199,6 @@ module.exports = class HypercoreBatch extends EventEmitter {
202
199
  const session = this.session
203
200
 
204
201
  if (this.opened === false) await this.opening
205
- if (this.writable === false) throw SESSION_NOT_WRITABLE()
206
202
  if (this.closing) throw SESSION_CLOSED()
207
203
 
208
204
  // wait for any pending flush... (prop needs a lock)
@@ -230,12 +226,14 @@ module.exports = class HypercoreBatch extends EventEmitter {
230
226
  return info
231
227
  }
232
228
 
233
- async flush (length = this._appends.length, auth) {
229
+ async flush (opts = {}) {
234
230
  if (this.opened === false) await this.opening
235
231
  if (this.closing) throw SESSION_CLOSED()
236
232
 
233
+ const { length = this._appends.length, keyPair = this.session.keyPair, signature = null } = opts
234
+
237
235
  while (this._flushing) await this._flushing
238
- this._flushing = this._flush(length, auth)
236
+ this._flushing = this._flush(length, keyPair, signature)
239
237
 
240
238
  try {
241
239
  await this._flushing
@@ -246,11 +244,12 @@ module.exports = class HypercoreBatch extends EventEmitter {
246
244
  if (this.autoClose) await this.close()
247
245
  }
248
246
 
249
- async _flush (length, auth) { // TODO: make this safe to interact with a parallel truncate...
247
+ async _flush (length, keyPair, signature) { // TODO: make this safe to interact with a parallel truncate...
250
248
  if (this._appends.length === 0) return
251
249
 
252
250
  const flushingLength = Math.min(length, this._appends.length)
253
- const info = await this.session.append(flushingLength < this._appends.length ? this._appends.slice(0, flushingLength) : this._appends, { auth })
251
+ const blocks = flushingLength < this._appends.length ? this._appends.slice(0, flushingLength) : this._appends
252
+ const info = await this.session.append(blocks, { keyPair, signature })
254
253
  const delta = info.byteLength - this._sessionByteLength
255
254
 
256
255
  this._sessionLength = info.length
package/lib/caps.js CHANGED
@@ -8,6 +8,7 @@ const c = require('compact-encoding')
8
8
 
9
9
  const [TREE, REPLICATE_INITIATOR, REPLICATE_RESPONDER, MANIFEST, DEFAULT_NAMESPACE] = crypto.namespace('hypercore', 5)
10
10
 
11
+ exports.MANIFEST = MANIFEST
11
12
  exports.DEFAULT_NAMESPACE = DEFAULT_NAMESPACE
12
13
 
13
14
  exports.replicate = function (isInitiator, key, handshakeHash) {
@@ -16,27 +17,20 @@ exports.replicate = function (isInitiator, key, handshakeHash) {
16
17
  return out
17
18
  }
18
19
 
19
- exports.manifestHash = function (manifest) {
20
- const state = { start: 0, end: 32 + manifest.byteLength, buffer: null }
21
- state.buffer = b4a.allocUnsafe(state.end)
22
- c.raw.encode(state, MANIFEST)
23
- c.raw.encode(state, manifest)
24
- const out = b4a.allocUnsafe(32)
25
- sodium.crypto_generichash(out, state.buffer)
26
- return out
27
- }
28
-
29
- exports.treeSignable = function (hash, length, fork) {
30
- const state = { start: 0, end: 80, buffer: b4a.allocUnsafe(80) }
20
+ exports.treeSignable = function (namespace, hash, length, fork) {
21
+ const state = { start: 0, end: 112, buffer: b4a.allocUnsafe(112) }
31
22
  c.raw.encode(state, TREE)
23
+ c.raw.encode(state, namespace)
32
24
  c.raw.encode(state, hash)
33
25
  c.uint64.encode(state, length)
34
26
  c.uint64.encode(state, fork)
35
27
  return state.buffer
36
28
  }
37
29
 
38
- exports.treeSignableLegacy = function (hash, length, fork) {
39
- const state = { start: 0, end: 48, buffer: b4a.allocUnsafe(48) }
30
+ exports.treeSignableCompat = function (hash, length, fork, noHeader) {
31
+ const end = noHeader ? 48 : 80
32
+ const state = { start: 0, end, buffer: b4a.allocUnsafe(end) }
33
+ if (!noHeader) c.raw.encode(state, TREE) // ultra legacy mode, kill in future major
40
34
  c.raw.encode(state, hash)
41
35
  c.uint64.encode(state, length)
42
36
  c.uint64.encode(state, fork)