hypercore 11.2.0 → 11.4.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/README.md +2 -0
- package/index.js +44 -49
- package/lib/caps.js +2 -2
- package/lib/default-encryption.js +116 -0
- package/lib/messages.js +23 -13
- package/lib/verifier.js +11 -4
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -68,6 +68,8 @@ You can also set valueEncoding to any [compact-encoding](https://github.com/comp
|
|
|
68
68
|
|
|
69
69
|
valueEncodings will be applied to individual blocks, even if you append batches. If you want to control encoding at the batch-level, you can use the `encodeBatch` option, which is a function that takes a batch and returns a binary-encoded batch. If you provide a custom valueEncoding, it will not be applied prior to `encodeBatch`.
|
|
70
70
|
|
|
71
|
+
The user may provide a custom encryption module as `opts.encryption`, which should satisfy the [HypercoreEncryption](https://github.com/holepunchto/hypercore-encryption) interface.
|
|
72
|
+
|
|
71
73
|
#### `const { length, byteLength } = await core.append(block)`
|
|
72
74
|
|
|
73
75
|
Append a block of data (or an array of blocks) to the core.
|
package/index.js
CHANGED
|
@@ -3,10 +3,8 @@ const isOptions = require('is-options')
|
|
|
3
3
|
const crypto = require('hypercore-crypto')
|
|
4
4
|
const CoreStorage = require('hypercore-storage')
|
|
5
5
|
const c = require('compact-encoding')
|
|
6
|
-
const sodium = require('sodium-universal')
|
|
7
6
|
const b4a = require('b4a')
|
|
8
7
|
const NoiseSecretStream = require('@hyperswarm/secret-stream')
|
|
9
|
-
const HypercoreEncryption = require('hypercore-encryption')
|
|
10
8
|
const Protomux = require('protomux')
|
|
11
9
|
const id = require('hypercore-id-encoding')
|
|
12
10
|
const safetyCatch = require('safety-catch')
|
|
@@ -15,6 +13,7 @@ const unslab = require('unslab')
|
|
|
15
13
|
const Core = require('./lib/core')
|
|
16
14
|
const Info = require('./lib/info')
|
|
17
15
|
const Download = require('./lib/download')
|
|
16
|
+
const DefaultEncryption = require('./lib/default-encryption')
|
|
18
17
|
const caps = require('./lib/caps')
|
|
19
18
|
const { manifestHash, createManifest } = require('./lib/verifier')
|
|
20
19
|
const { ReadStream, WriteStream, ByteStream } = require('./lib/streams')
|
|
@@ -140,6 +139,8 @@ class Hypercore extends EventEmitter {
|
|
|
140
139
|
|
|
141
140
|
static MAX_SUGGESTED_BLOCK_SIZE = MAX_SUGGESTED_BLOCK_SIZE
|
|
142
141
|
|
|
142
|
+
static DefaultEncryption = DefaultEncryption
|
|
143
|
+
|
|
143
144
|
static key (manifest, { compat, version, namespace } = {}) {
|
|
144
145
|
if (b4a.isBuffer(manifest)) manifest = { version, signers: [{ publicKey: manifest, namespace }] }
|
|
145
146
|
return compat ? manifest.signers[0].publicKey : manifestHash(createManifest(manifest))
|
|
@@ -150,7 +151,7 @@ class Hypercore extends EventEmitter {
|
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
static blockEncryptionKey (key, encryptionKey) {
|
|
153
|
-
return
|
|
154
|
+
return DefaultEncryption.blockEncryptionKey(key, encryptionKey)
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
static getProtocolMuxer (stream) {
|
|
@@ -235,7 +236,7 @@ class Hypercore extends EventEmitter {
|
|
|
235
236
|
}
|
|
236
237
|
|
|
237
238
|
setEncryptionKey (encryptionKey, opts) {
|
|
238
|
-
const encryption = this.
|
|
239
|
+
const encryption = this._getEncryptionProvider(encryptionKey, !!(opts && opts.block))
|
|
239
240
|
return this.setEncryption(encryption, opts)
|
|
240
241
|
}
|
|
241
242
|
|
|
@@ -247,8 +248,8 @@ class Hypercore extends EventEmitter {
|
|
|
247
248
|
return
|
|
248
249
|
}
|
|
249
250
|
|
|
250
|
-
if (!
|
|
251
|
-
throw new Error('
|
|
251
|
+
if (!isEncryptionProvider(encryption)) {
|
|
252
|
+
throw new Error('Provider does not satisfy HypercoreEncryption interface')
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
this.encryption = encryption
|
|
@@ -328,13 +329,12 @@ class Hypercore extends EventEmitter {
|
|
|
328
329
|
|
|
329
330
|
if (this.keyPair === null) this.keyPair = opts.keyPair || this.core.header.keyPair
|
|
330
331
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (HypercoreEncryption.isHypercoreEncryption(e)) {
|
|
332
|
+
const e = getEncryptionOption(opts)
|
|
333
|
+
if (!this.core.encryption && e) {
|
|
334
|
+
if (isEncryptionProvider(e)) {
|
|
335
335
|
this.core.encryption = e
|
|
336
|
-
} else
|
|
337
|
-
this.core.encryption = this.
|
|
336
|
+
} else {
|
|
337
|
+
this.core.encryption = this._getEncryptionProvider(e.key, e.block)
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
|
|
@@ -592,12 +592,16 @@ class Hypercore extends EventEmitter {
|
|
|
592
592
|
return this.state.fork
|
|
593
593
|
}
|
|
594
594
|
|
|
595
|
-
get
|
|
596
|
-
|
|
595
|
+
get padding () {
|
|
596
|
+
if (this.encryption && this.key && this.manifest) {
|
|
597
|
+
return this.encryption.padding(this.core, this.length)
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return 0
|
|
597
601
|
}
|
|
598
602
|
|
|
599
|
-
get
|
|
600
|
-
return this.
|
|
603
|
+
get peers () {
|
|
604
|
+
return this.opened === false ? [] : this.core.replicator.peers
|
|
601
605
|
}
|
|
602
606
|
|
|
603
607
|
get globalCache () {
|
|
@@ -700,6 +704,18 @@ class Hypercore extends EventEmitter {
|
|
|
700
704
|
if (this.opened === false) await this.opening
|
|
701
705
|
if (!isValidIndex(bytes)) throw ASSERTION('seek is invalid')
|
|
702
706
|
|
|
707
|
+
const activeRequests = (opts && opts.activeRequests) || this.activeRequests
|
|
708
|
+
|
|
709
|
+
if (this.encryption && !this.core.manifest) {
|
|
710
|
+
const req = this.replicator.addUpgrade(activeRequests)
|
|
711
|
+
try {
|
|
712
|
+
await req.promise
|
|
713
|
+
} catch (err) {
|
|
714
|
+
if (isSessionMoved(err)) return this.seek(bytes, opts)
|
|
715
|
+
throw err
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
703
719
|
const s = MerkleTree.seek(this.state, bytes, this.padding)
|
|
704
720
|
|
|
705
721
|
const offset = await s.update()
|
|
@@ -709,7 +725,6 @@ class Hypercore extends EventEmitter {
|
|
|
709
725
|
|
|
710
726
|
if (!this._shouldWait(opts, this.wait)) return null
|
|
711
727
|
|
|
712
|
-
const activeRequests = (opts && opts.activeRequests) || this.activeRequests
|
|
713
728
|
const req = this.core.replicator.addSeek(activeRequests, s)
|
|
714
729
|
|
|
715
730
|
const timeout = opts && opts.timeout !== undefined ? opts.timeout : this.timeout
|
|
@@ -772,12 +787,10 @@ class Hypercore extends EventEmitter {
|
|
|
772
787
|
// Copy the block as it might be shared with other sessions.
|
|
773
788
|
block = b4a.from(block)
|
|
774
789
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
await this.encryption.decrypt(index, block)
|
|
790
|
+
await this.encryption.decrypt(index, block, this.core)
|
|
778
791
|
}
|
|
779
792
|
|
|
780
|
-
return this._decode(encoding, block)
|
|
793
|
+
return this._decode(encoding, block, index)
|
|
781
794
|
}
|
|
782
795
|
|
|
783
796
|
async clear (start, end = start + 1, opts) {
|
|
@@ -923,7 +936,6 @@ class Hypercore extends EventEmitter {
|
|
|
923
936
|
blocks = Array.isArray(blocks) ? blocks : [blocks]
|
|
924
937
|
|
|
925
938
|
const preappend = this.encryption && this._preappend
|
|
926
|
-
if (preappend) await this.encryption.ready()
|
|
927
939
|
|
|
928
940
|
const buffers = this.encodeBatch !== null ? this.encodeBatch(blocks) : new Array(blocks.length)
|
|
929
941
|
|
|
@@ -1042,8 +1054,8 @@ class Hypercore extends EventEmitter {
|
|
|
1042
1054
|
return state.buffer
|
|
1043
1055
|
}
|
|
1044
1056
|
|
|
1045
|
-
_decode (enc, block) {
|
|
1046
|
-
if (this.
|
|
1057
|
+
_decode (enc, block, index) {
|
|
1058
|
+
if (this.encryption) block = block.subarray(this.encryption.padding(this.core, index))
|
|
1047
1059
|
try {
|
|
1048
1060
|
if (enc) return c.decode(enc, block)
|
|
1049
1061
|
} catch {
|
|
@@ -1052,23 +1064,9 @@ class Hypercore extends EventEmitter {
|
|
|
1052
1064
|
return block
|
|
1053
1065
|
}
|
|
1054
1066
|
|
|
1055
|
-
|
|
1056
|
-
const e = this.encryption
|
|
1057
|
-
if (HypercoreEncryption.isHypercoreEncryption(e)) return
|
|
1058
|
-
|
|
1059
|
-
this.encryption = this._getLegacyEncryption(e.key, e.block)
|
|
1060
|
-
|
|
1061
|
-
if (e === this.core.encryption) this.core.encryption = this.encryption
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
_getLegacyEncryption (encryptionKey, block) {
|
|
1067
|
+
_getEncryptionProvider (encryptionKey, block) {
|
|
1065
1068
|
if (!encryptionKey) return null
|
|
1066
|
-
|
|
1067
|
-
const blockKey = block
|
|
1068
|
-
? encryptionKey
|
|
1069
|
-
: getLegacyBlockKey(this.key, encryptionKey, this.core.compat)
|
|
1070
|
-
|
|
1071
|
-
return HypercoreEncryption.createLegacyProvider(blockKey)
|
|
1069
|
+
return new DefaultEncryption(encryptionKey, this.key, { block, compat: this.core.compat })
|
|
1072
1070
|
}
|
|
1073
1071
|
}
|
|
1074
1072
|
|
|
@@ -1086,10 +1084,8 @@ async function preappend (blocks) {
|
|
|
1086
1084
|
const offset = this.state.length
|
|
1087
1085
|
const fork = this.state.encryptionFork
|
|
1088
1086
|
|
|
1089
|
-
if (this.encryption.compat !== this.core.compat) this._updateEncryption()
|
|
1090
|
-
|
|
1091
1087
|
for (let i = 0; i < blocks.length; i++) {
|
|
1092
|
-
await this.encryption.encrypt(offset + i, blocks[i], fork)
|
|
1088
|
+
await this.encryption.encrypt(offset + i, blocks[i], fork, this.core)
|
|
1093
1089
|
}
|
|
1094
1090
|
}
|
|
1095
1091
|
|
|
@@ -1157,11 +1153,10 @@ function getEncryptionOption (opts) {
|
|
|
1157
1153
|
return b4a.isBuffer(opts.encryption) ? { key: opts.encryption } : opts.encryption
|
|
1158
1154
|
}
|
|
1159
1155
|
|
|
1160
|
-
function
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
if (compat) sodium.crypto_generichash_batch(key, [encryptionKey], hypercoreKey)
|
|
1164
|
-
else sodium.crypto_generichash_batch(key, [caps.LEGACY_BLOCK_ENCRYPTION, hypercoreKey, encryptionKey])
|
|
1156
|
+
function isEncryptionProvider (e) {
|
|
1157
|
+
return e && isFunction(e.padding) && isFunction(e.encrypt) && isFunction(e.decrypt)
|
|
1158
|
+
}
|
|
1165
1159
|
|
|
1166
|
-
|
|
1160
|
+
function isFunction (fn) {
|
|
1161
|
+
return !!fn && typeof fn === 'function'
|
|
1167
1162
|
}
|
package/lib/caps.js
CHANGED
|
@@ -12,12 +12,12 @@ const [
|
|
|
12
12
|
REPLICATE_RESPONDER,
|
|
13
13
|
MANIFEST,
|
|
14
14
|
DEFAULT_NAMESPACE,
|
|
15
|
-
|
|
15
|
+
DEFAULT_ENCRYPTION
|
|
16
16
|
] = crypto.namespace('hypercore', 6)
|
|
17
17
|
|
|
18
18
|
exports.MANIFEST = MANIFEST
|
|
19
19
|
exports.DEFAULT_NAMESPACE = DEFAULT_NAMESPACE
|
|
20
|
-
exports.
|
|
20
|
+
exports.DEFAULT_ENCRYPTION = DEFAULT_ENCRYPTION
|
|
21
21
|
|
|
22
22
|
exports.replicate = function (isInitiator, key, handshakeHash) {
|
|
23
23
|
const out = b4a.allocUnsafe(32)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
const sodium = require('sodium-universal')
|
|
2
|
+
const c = require('compact-encoding')
|
|
3
|
+
const b4a = require('b4a')
|
|
4
|
+
const { DEFAULT_ENCRYPTION } = require('./caps')
|
|
5
|
+
|
|
6
|
+
const nonce = b4a.alloc(sodium.crypto_stream_NONCEBYTES)
|
|
7
|
+
|
|
8
|
+
module.exports = class DefaultEncryption {
|
|
9
|
+
static PADDING = 8
|
|
10
|
+
|
|
11
|
+
constructor (encryptionKey, hypercoreKey, { block = false, compat = true } = {}) {
|
|
12
|
+
this.key = encryptionKey
|
|
13
|
+
this.compat = compat
|
|
14
|
+
|
|
15
|
+
const keys = DefaultEncryption.deriveKeys(encryptionKey, hypercoreKey, block, compat)
|
|
16
|
+
|
|
17
|
+
this.blockKey = keys.block
|
|
18
|
+
this.blindingKey = keys.blinding
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static deriveKeys (encryptionKey, hypercoreKey, block, compat) {
|
|
22
|
+
const subKeys = b4a.alloc(2 * sodium.crypto_stream_KEYBYTES)
|
|
23
|
+
|
|
24
|
+
const blockKey = block ? encryptionKey : subKeys.subarray(0, sodium.crypto_stream_KEYBYTES)
|
|
25
|
+
const blindingKey = subKeys.subarray(sodium.crypto_stream_KEYBYTES)
|
|
26
|
+
|
|
27
|
+
if (!block) {
|
|
28
|
+
if (compat) sodium.crypto_generichash_batch(blockKey, [encryptionKey], hypercoreKey)
|
|
29
|
+
else sodium.crypto_generichash_batch(blockKey, [DEFAULT_ENCRYPTION, hypercoreKey, encryptionKey])
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
sodium.crypto_generichash(blindingKey, blockKey)
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
blinding: blindingKey,
|
|
36
|
+
block: blockKey
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static blockEncryptionKey (hypercoreKey, encryptionKey) {
|
|
41
|
+
const blockKey = b4a.alloc(sodium.crypto_stream_KEYBYTES)
|
|
42
|
+
sodium.crypto_generichash_batch(blockKey, [DEFAULT_ENCRYPTION, hypercoreKey, encryptionKey])
|
|
43
|
+
return blockKey
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static encrypt (index, block, fork, blockKey, blindingKey) {
|
|
47
|
+
const padding = block.subarray(0, DefaultEncryption.PADDING)
|
|
48
|
+
block = block.subarray(DefaultEncryption.PADDING)
|
|
49
|
+
|
|
50
|
+
c.uint64.encode({ start: 0, end: 8, buffer: padding }, fork)
|
|
51
|
+
c.uint64.encode({ start: 0, end: 8, buffer: nonce }, index)
|
|
52
|
+
|
|
53
|
+
// Zero out any previous padding.
|
|
54
|
+
nonce.fill(0, 8, 8 + padding.byteLength)
|
|
55
|
+
|
|
56
|
+
// Blind the fork ID, possibly risking reusing the nonce on a reorg of the
|
|
57
|
+
// Hypercore. This is fine as the blinding is best-effort and the latest
|
|
58
|
+
// fork ID shared on replication anyway.
|
|
59
|
+
sodium.crypto_stream_xor(
|
|
60
|
+
padding,
|
|
61
|
+
padding,
|
|
62
|
+
nonce,
|
|
63
|
+
blindingKey
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
nonce.set(padding, 8)
|
|
67
|
+
|
|
68
|
+
// The combination of a (blinded) fork ID and a block index is unique for a
|
|
69
|
+
// given Hypercore and is therefore a valid nonce for encrypting the block.
|
|
70
|
+
sodium.crypto_stream_xor(
|
|
71
|
+
block,
|
|
72
|
+
block,
|
|
73
|
+
nonce,
|
|
74
|
+
blockKey
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static decrypt (index, block, blockKey) {
|
|
79
|
+
const padding = block.subarray(0, DefaultEncryption.PADDING)
|
|
80
|
+
block = block.subarray(DefaultEncryption.PADDING)
|
|
81
|
+
|
|
82
|
+
c.uint64.encode({ start: 0, end: 8, buffer: nonce }, index)
|
|
83
|
+
|
|
84
|
+
nonce.set(padding, 8)
|
|
85
|
+
|
|
86
|
+
// Decrypt the block using the blinded fork ID.
|
|
87
|
+
sodium.crypto_stream_xor(
|
|
88
|
+
block,
|
|
89
|
+
block,
|
|
90
|
+
nonce,
|
|
91
|
+
blockKey
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
encrypt (index, block, fork, core) {
|
|
96
|
+
if (core.compat !== this.compat) this._reload(core)
|
|
97
|
+
return DefaultEncryption.encrypt(index, block, fork, this.blockKey, this.blindingKey)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
decrypt (index, block, core) {
|
|
101
|
+
if (core.compat !== this.compat) this._reload(core)
|
|
102
|
+
return DefaultEncryption.decrypt(index, block, this.blockKey)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
padding () {
|
|
106
|
+
return DefaultEncryption.PADDING
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
_reload (core) {
|
|
110
|
+
const block = b4a.equals(this.key, this.blockKey)
|
|
111
|
+
const keys = DefaultEncryption.deriveKeys(this.key, core.key, { block, compat: core.compat })
|
|
112
|
+
|
|
113
|
+
this.blockKey = keys.blockKey
|
|
114
|
+
this.blindingKey = keys.blindingKey
|
|
115
|
+
}
|
|
116
|
+
}
|
package/lib/messages.js
CHANGED
|
@@ -9,6 +9,7 @@ const EMPTY = b4a.alloc(0)
|
|
|
9
9
|
const MANIFEST_PATCH = 0b00000001
|
|
10
10
|
const MANIFEST_PROLOGUE = 0b00000010
|
|
11
11
|
const MANIFEST_LINKED = 0b00000100
|
|
12
|
+
const MANIFEST_USER_DATA = 0b00001000
|
|
12
13
|
|
|
13
14
|
const hashes = {
|
|
14
15
|
preencode (state, m) {
|
|
@@ -141,7 +142,8 @@ const manifestv0 = {
|
|
|
141
142
|
hash: c.fixed32.decode(state),
|
|
142
143
|
length: 0
|
|
143
144
|
},
|
|
144
|
-
linked: null
|
|
145
|
+
linked: null,
|
|
146
|
+
userData: null
|
|
145
147
|
}
|
|
146
148
|
}
|
|
147
149
|
|
|
@@ -153,7 +155,8 @@ const manifestv0 = {
|
|
|
153
155
|
quorum: 1,
|
|
154
156
|
signers: [signer.decode(state)],
|
|
155
157
|
prologue: null,
|
|
156
|
-
linked: null
|
|
158
|
+
linked: null,
|
|
159
|
+
userData: null
|
|
157
160
|
}
|
|
158
161
|
}
|
|
159
162
|
|
|
@@ -166,7 +169,8 @@ const manifestv0 = {
|
|
|
166
169
|
quorum: c.uint.decode(state),
|
|
167
170
|
signers: signerArray.decode(state),
|
|
168
171
|
prologue: null,
|
|
169
|
-
linked: null
|
|
172
|
+
linked: null,
|
|
173
|
+
userData: null
|
|
170
174
|
}
|
|
171
175
|
}
|
|
172
176
|
}
|
|
@@ -176,6 +180,7 @@ const fixed32Array = c.array(c.fixed32)
|
|
|
176
180
|
const manifest = exports.manifest = {
|
|
177
181
|
preencode (state, m) {
|
|
178
182
|
state.end++ // version
|
|
183
|
+
|
|
179
184
|
if (m.version === 0) return manifestv0.preencode(state, m)
|
|
180
185
|
|
|
181
186
|
state.end++ // flags
|
|
@@ -183,34 +188,35 @@ const manifest = exports.manifest = {
|
|
|
183
188
|
|
|
184
189
|
c.uint.preencode(state, m.quorum)
|
|
185
190
|
signerArray.preencode(state, m.signers)
|
|
186
|
-
if (m.prologue) prologue.preencode(state, m.prologue)
|
|
187
191
|
|
|
188
|
-
if (m.
|
|
189
|
-
|
|
190
|
-
|
|
192
|
+
if (m.prologue) prologue.preencode(state, m.prologue)
|
|
193
|
+
if (m.linked) fixed32Array.preencode(state, m.linked)
|
|
194
|
+
if (m.userData) c.buffer.preencode(state, m.userData)
|
|
191
195
|
},
|
|
192
196
|
encode (state, m) {
|
|
193
197
|
c.uint.encode(state, m.version)
|
|
198
|
+
|
|
194
199
|
if (m.version === 0) return manifestv0.encode(state, m)
|
|
195
200
|
|
|
196
201
|
let flags = 0
|
|
197
202
|
if (m.allowPatch) flags |= MANIFEST_PATCH
|
|
198
203
|
if (m.prologue) flags |= MANIFEST_PROLOGUE
|
|
199
204
|
if (m.linked) flags |= MANIFEST_LINKED
|
|
205
|
+
if (m.userData) flags |= MANIFEST_USER_DATA
|
|
200
206
|
|
|
201
207
|
c.uint.encode(state, flags)
|
|
202
208
|
hashes.encode(state, m.hash)
|
|
203
209
|
|
|
204
210
|
c.uint.encode(state, m.quorum)
|
|
205
211
|
signerArray.encode(state, m.signers)
|
|
206
|
-
if (m.prologue) prologue.encode(state, m.prologue)
|
|
207
212
|
|
|
208
|
-
if (m.
|
|
209
|
-
|
|
210
|
-
|
|
213
|
+
if (m.prologue) prologue.encode(state, m.prologue)
|
|
214
|
+
if (m.linked) fixed32Array.encode(state, m.linked)
|
|
215
|
+
if (m.userData) c.buffer.encode(state, m.userData)
|
|
211
216
|
},
|
|
212
217
|
decode (state) {
|
|
213
218
|
const version = c.uint.decode(state)
|
|
219
|
+
|
|
214
220
|
if (version === 0) return manifestv0.decode(state)
|
|
215
221
|
if (version > 2) throw new Error('Unknown version: ' + version)
|
|
216
222
|
|
|
@@ -222,6 +228,7 @@ const manifest = exports.manifest = {
|
|
|
222
228
|
const hasPatch = (flags & MANIFEST_PATCH) !== 0
|
|
223
229
|
const hasPrologue = (flags & MANIFEST_PROLOGUE) !== 0
|
|
224
230
|
const hasLinked = (flags & MANIFEST_LINKED) !== 0
|
|
231
|
+
const hasUserData = (flags & MANIFEST_USER_DATA) !== 0
|
|
225
232
|
|
|
226
233
|
return {
|
|
227
234
|
version,
|
|
@@ -230,7 +237,8 @@ const manifest = exports.manifest = {
|
|
|
230
237
|
quorum,
|
|
231
238
|
signers,
|
|
232
239
|
prologue: hasPrologue ? prologue.decode(state) : null,
|
|
233
|
-
linked: hasLinked ? fixed32Array.decode(state) : null
|
|
240
|
+
linked: hasLinked ? fixed32Array.decode(state) : null,
|
|
241
|
+
userData: hasUserData ? c.buffer.decode(state) : null
|
|
234
242
|
}
|
|
235
243
|
}
|
|
236
244
|
}
|
|
@@ -936,7 +944,9 @@ oplog.header = {
|
|
|
936
944
|
namespace: DEFAULT_NAMESPACE,
|
|
937
945
|
publicKey: old.signer.publicKey
|
|
938
946
|
}],
|
|
939
|
-
prologue: null
|
|
947
|
+
prologue: null,
|
|
948
|
+
linked: null,
|
|
949
|
+
userData: null
|
|
940
950
|
},
|
|
941
951
|
keyPair: old.signer.secretKey ? old.signer : null,
|
|
942
952
|
userData: old.userData,
|
package/lib/verifier.js
CHANGED
|
@@ -183,7 +183,8 @@ module.exports = class Verifier {
|
|
|
183
183
|
publicKey
|
|
184
184
|
}],
|
|
185
185
|
prologue: null,
|
|
186
|
-
linked: null
|
|
186
|
+
linked: null,
|
|
187
|
+
userData: null
|
|
187
188
|
}
|
|
188
189
|
}
|
|
189
190
|
|
|
@@ -196,13 +197,14 @@ module.exports = class Verifier {
|
|
|
196
197
|
if (!inp) return null
|
|
197
198
|
|
|
198
199
|
const manifest = {
|
|
199
|
-
version: getManifestVersion(inp), //
|
|
200
|
+
version: getManifestVersion(inp), // defaults to v1
|
|
200
201
|
hash: 'blake2b',
|
|
201
202
|
allowPatch: !!inp.allowPatch,
|
|
202
203
|
quorum: defaultQuorum(inp),
|
|
203
204
|
signers: inp.signers ? inp.signers.map(parseSigner) : [],
|
|
204
205
|
prologue: null,
|
|
205
|
-
linked: null
|
|
206
|
+
linked: null,
|
|
207
|
+
userData: inp.userData || null
|
|
206
208
|
}
|
|
207
209
|
|
|
208
210
|
if (inp.hash && inp.hash !== 'blake2b') throw BAD_ARGUMENT('Only Blake2b hashes are supported')
|
|
@@ -216,8 +218,12 @@ module.exports = class Verifier {
|
|
|
216
218
|
manifest.prologue.hash = unslab(manifest.prologue.hash)
|
|
217
219
|
}
|
|
218
220
|
|
|
221
|
+
if (manifest.userData !== null && manifest.version < 2) {
|
|
222
|
+
throw BAD_ARGUMENT('Invalid field: userData')
|
|
223
|
+
}
|
|
224
|
+
|
|
219
225
|
if (inp.linked && inp.linked.length) {
|
|
220
|
-
if (manifest.version < 2) throw BAD_ARGUMENT('Invalid field')
|
|
226
|
+
if (manifest.version < 2) throw BAD_ARGUMENT('Invalid field: linked')
|
|
221
227
|
|
|
222
228
|
for (const key of inp.linked) {
|
|
223
229
|
if (!(b4a.isBuffer(key) && key.byteLength === 32)) {
|
|
@@ -328,5 +334,6 @@ function proofToVersion1 (proof) {
|
|
|
328
334
|
function getManifestVersion (inp) {
|
|
329
335
|
if (typeof inp.version === 'number') return inp.version
|
|
330
336
|
if (inp.linked && inp.linked.length) return 2
|
|
337
|
+
if (inp.userData !== null) return 2
|
|
331
338
|
return 1
|
|
332
339
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypercore",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.4.0",
|
|
4
4
|
"description": "Hypercore is a secure, distributed append-only log",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -50,7 +50,6 @@
|
|
|
50
50
|
"fast-fifo": "^1.3.0",
|
|
51
51
|
"flat-tree": "^1.9.0",
|
|
52
52
|
"hypercore-crypto": "^3.2.1",
|
|
53
|
-
"hypercore-encryption": "^1.0.0",
|
|
54
53
|
"hypercore-errors": "^1.2.0",
|
|
55
54
|
"hypercore-id-encoding": "^1.2.0",
|
|
56
55
|
"hypercore-storage": "^1.0.0",
|