hypercore 11.6.3 → 11.8.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 +2 -2
- package/lib/fully-remote-proof.js +126 -0
- package/lib/session-state.js +6 -1
- package/lib/streams.js +1 -1
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -213,7 +213,7 @@ class Hypercore extends EventEmitter {
|
|
|
213
213
|
throw SESSION_CLOSED('Cannot make sessions on a closing core')
|
|
214
214
|
}
|
|
215
215
|
if (opts.checkout !== undefined && !opts.name && !opts.atom) {
|
|
216
|
-
throw
|
|
216
|
+
throw ASSERTION('Checkouts are only supported on atoms or named sessions')
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
const wait = opts.wait === false ? false : this.wait
|
|
@@ -249,7 +249,7 @@ class Hypercore extends EventEmitter {
|
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
if (!isEncryptionProvider(encryption)) {
|
|
252
|
-
throw
|
|
252
|
+
throw ASSERTION('Provider does not satisfy HypercoreEncryption interface')
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
this.encryption = encryption
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// this helper is for fully remote proofs, is like in a push notification where no other context exists
|
|
2
|
+
|
|
3
|
+
const { MerkleTree } = require('./merkle-tree.js')
|
|
4
|
+
const messages = require('./messages.js')
|
|
5
|
+
const b4a = require('b4a')
|
|
6
|
+
const c = require('compact-encoding')
|
|
7
|
+
const crypto = require('hypercore-crypto')
|
|
8
|
+
const flat = require('flat-tree')
|
|
9
|
+
|
|
10
|
+
class SlimSession {
|
|
11
|
+
constructor (storage, auth, head, roots) {
|
|
12
|
+
this.fork = head ? head.fork : 0
|
|
13
|
+
this.roots = roots
|
|
14
|
+
this.length = head ? head.length : 0
|
|
15
|
+
this.signature = head ? head.signature : null
|
|
16
|
+
this.ancestors = this.length
|
|
17
|
+
this.byteLength = 0
|
|
18
|
+
this.prologue = auth.manifest.prologue
|
|
19
|
+
this.storage = storage
|
|
20
|
+
|
|
21
|
+
for (let i = 0; i < roots.length; i++) this.byteLength += roots[i].size
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = { verify, proof }
|
|
26
|
+
|
|
27
|
+
async function verify (storage, buffer, { referrer = null } = {}) {
|
|
28
|
+
const state = { buffer, start: 0, end: buffer.byteLength }
|
|
29
|
+
|
|
30
|
+
const discoveryKey = c.fixed32.decode(state)
|
|
31
|
+
const proof = messages.wire.data.decode(state)
|
|
32
|
+
|
|
33
|
+
const result = {
|
|
34
|
+
key: null,
|
|
35
|
+
discoveryKey,
|
|
36
|
+
newer: true,
|
|
37
|
+
length: 0,
|
|
38
|
+
proof,
|
|
39
|
+
block: null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const core = await storage.resume(discoveryKey)
|
|
43
|
+
if (core === null) return null
|
|
44
|
+
|
|
45
|
+
let rx = core.read()
|
|
46
|
+
const authPromise = rx.getAuth()
|
|
47
|
+
const headPromise = rx.getHead()
|
|
48
|
+
const referrerPromise = rx.getUserData('referrer')
|
|
49
|
+
|
|
50
|
+
rx.tryFlush()
|
|
51
|
+
|
|
52
|
+
const [auth, head, ref] = await Promise.all([authPromise, headPromise, referrerPromise])
|
|
53
|
+
|
|
54
|
+
if (auth === null) return null
|
|
55
|
+
|
|
56
|
+
if (referrer && (!ref || !b4a.equals(ref, referrer))) return null
|
|
57
|
+
|
|
58
|
+
rx = core.read()
|
|
59
|
+
|
|
60
|
+
const rootPromises = []
|
|
61
|
+
|
|
62
|
+
for (const index of flat.fullRoots(head ? 2 * head.length : 0)) {
|
|
63
|
+
rootPromises.push(rx.getTreeNode(index))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
rx.tryFlush()
|
|
67
|
+
|
|
68
|
+
const roots = await Promise.all(rootPromises)
|
|
69
|
+
const length = head ? head.length : 0
|
|
70
|
+
|
|
71
|
+
if (!auth.manifest || !auth.manifest.signers.length) return null
|
|
72
|
+
|
|
73
|
+
const batch = await MerkleTree.verifyFullyRemote(new SlimSession(core, auth, head, roots), proof)
|
|
74
|
+
const publicKey = auth.manifest.signers[0].publicKey
|
|
75
|
+
|
|
76
|
+
let signable = null
|
|
77
|
+
let signature = null
|
|
78
|
+
|
|
79
|
+
if (auth.manifest.version === 0) {
|
|
80
|
+
signable = batch.signable(auth.manifest.signers[0].namespace)
|
|
81
|
+
signature = batch.signature
|
|
82
|
+
} else {
|
|
83
|
+
if (batch.signature[0] !== 1) return null
|
|
84
|
+
if (batch.signature[1] !== 0) return null
|
|
85
|
+
|
|
86
|
+
signable = batch.signable(auth.key)
|
|
87
|
+
signature = batch.signature.subarray(2)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!crypto.verify(signable, signature, publicKey)) {
|
|
91
|
+
return null
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
result.key = auth.key
|
|
95
|
+
result.discoveryKey = discoveryKey
|
|
96
|
+
result.newer = batch.length > length
|
|
97
|
+
result.length = batch.length
|
|
98
|
+
result.block = proof.block
|
|
99
|
+
|
|
100
|
+
return result
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function proof (sender, { index, block = null } = {}) {
|
|
104
|
+
const treeProof = await sender.proof({
|
|
105
|
+
block: block ? { index, nodes: 0 } : null,
|
|
106
|
+
upgrade: { start: 0, length: sender.length }
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const proof = await treeProof.settle()
|
|
110
|
+
|
|
111
|
+
if (block) proof.block.value = block
|
|
112
|
+
proof.manifest = sender.core.header.manifest
|
|
113
|
+
|
|
114
|
+
const state = { buffer: null, start: 0, end: 0 }
|
|
115
|
+
const data = { request: 0, ...proof }
|
|
116
|
+
|
|
117
|
+
c.fixed32.preencode(state, sender.discoveryKey)
|
|
118
|
+
messages.wire.data.preencode(state, data)
|
|
119
|
+
|
|
120
|
+
state.buffer = b4a.allocUnsafe(state.end)
|
|
121
|
+
|
|
122
|
+
c.fixed32.encode(state, sender.discoveryKey)
|
|
123
|
+
messages.wire.data.encode(state, data)
|
|
124
|
+
|
|
125
|
+
return state.buffer
|
|
126
|
+
}
|
package/lib/session-state.js
CHANGED
|
@@ -543,7 +543,12 @@ module.exports = class SessionState {
|
|
|
543
543
|
|
|
544
544
|
tx.setHead(tree)
|
|
545
545
|
|
|
546
|
-
if (this.isDefault())
|
|
546
|
+
if (this.isDefault()) {
|
|
547
|
+
await storeBitfieldRange(this.storage, tx, batch.ancestors, batch.length, true)
|
|
548
|
+
if (this.length === this.core.header.hints.contiguousLength) {
|
|
549
|
+
tx.setHints({ contiguousLength: this.length + values.length })
|
|
550
|
+
}
|
|
551
|
+
}
|
|
547
552
|
|
|
548
553
|
for (let i = 0; i < values.length; i++) {
|
|
549
554
|
tx.putBlock(this.length + i, values[i])
|
package/lib/streams.js
CHANGED
|
@@ -8,7 +8,7 @@ class ReadStream extends Readable {
|
|
|
8
8
|
this.start = opts.start || 0
|
|
9
9
|
this.end = typeof opts.end === 'number' ? opts.end : -1
|
|
10
10
|
this.snapshot = !opts.live && opts.snapshot !== false
|
|
11
|
-
this.live = !!opts.live
|
|
11
|
+
this.live = this.end === -1 ? !!opts.live : false
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
_open (cb) {
|