autobee 2.11.0 → 2.11.2
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 +15 -14
- package/lib/encoding.js +2 -2
- package/lib/encryption.js +259 -0
- package/lib/migrations.js +1 -1
- package/lib/writers.js +1 -1
- package/package.json +3 -4
package/index.js
CHANGED
|
@@ -6,7 +6,6 @@ const Hyperbee = require('hyperbee2')
|
|
|
6
6
|
const ID = require('hypercore-id-encoding')
|
|
7
7
|
const rrp = require('resolve-reject-promise')
|
|
8
8
|
const Signal = require('signal-promise')
|
|
9
|
-
const { AutobeeEncryption, WriterEncryption, ViewEncryption } = require('autobee-encryption')
|
|
10
9
|
const AutobeeWakeup = require('autobee-wakeup')
|
|
11
10
|
const Hypercore = require('hypercore')
|
|
12
11
|
const crypto = require('hypercore-crypto')
|
|
@@ -16,6 +15,7 @@ const boot = require('./lib/boot.js')
|
|
|
16
15
|
const { DEFAULT_MANIFEST_VERSION } = require('./lib/constants.js')
|
|
17
16
|
const { resolveWeight, currentWeight } = require('./lib/witness.js')
|
|
18
17
|
const encoding = require('./lib/encoding.js')
|
|
18
|
+
const { AutobeeEncryption, WriterEncryption, ViewEncryption } = require('./lib/encryption.js')
|
|
19
19
|
const FastForward = require('./lib/fast-forward.js')
|
|
20
20
|
const System = require('./lib/system.js')
|
|
21
21
|
const ApplyCalls = require('./lib/apply-calls.js')
|
|
@@ -684,18 +684,14 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
684
684
|
}
|
|
685
685
|
|
|
686
686
|
async compactMaybe() {
|
|
687
|
-
if (
|
|
687
|
+
if (await this._isReindexed()) return
|
|
688
688
|
|
|
689
|
-
|
|
689
|
+
await this._reindexBee(this._workingBee)
|
|
690
|
+
this.bee.move(this._workingBee.head())
|
|
690
691
|
|
|
691
|
-
|
|
692
|
-
if (view > 0) this.bee.move(this._workingBee.head())
|
|
692
|
+
await this._reindexBee(this.system.bee)
|
|
693
693
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
if (view + system > 0) this._reindexed = true
|
|
697
|
-
|
|
698
|
-
return view + system
|
|
694
|
+
this._reindexed = true
|
|
699
695
|
}
|
|
700
696
|
|
|
701
697
|
async _isReindexed() {
|
|
@@ -711,11 +707,15 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
711
707
|
async _reindexBee(bee) {
|
|
712
708
|
const head = bee.head()
|
|
713
709
|
const local = bee.context.local
|
|
714
|
-
if (head === null) return
|
|
715
|
-
if ((await this._shouldReindex(
|
|
716
|
-
|
|
710
|
+
if (head === null) return
|
|
711
|
+
if (!(await this._shouldReindex(head.key))) return
|
|
712
|
+
|
|
713
|
+
// a non-empty local core is a completed reindex whose head was never stored
|
|
714
|
+
if (local.length === 0) {
|
|
715
|
+
await bee.reindex(async (change) => !(await this._shouldReindex(change.head.key)))
|
|
716
|
+
}
|
|
717
717
|
|
|
718
|
-
|
|
718
|
+
bee.move({ key: local.key, length: local.length })
|
|
719
719
|
}
|
|
720
720
|
|
|
721
721
|
async _shouldReindex(key, { unknown = false, length = 0, timeout = 0 } = {}) {
|
|
@@ -790,6 +790,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
790
790
|
|
|
791
791
|
if (this.fastForwardTo !== null) {
|
|
792
792
|
await this._applyFastForward()
|
|
793
|
+
await this.compactMaybe()
|
|
793
794
|
if (changes) changes.track()
|
|
794
795
|
this._needsUpdate = false
|
|
795
796
|
break // revaluate conditions...
|
package/lib/encoding.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const b4a = require('b4a')
|
|
2
2
|
const c = require('compact-encoding')
|
|
3
3
|
const crypto = require('hypercore-crypto')
|
|
4
|
-
const { AutobeeEncryption, WriterEncryption } = require('autobee-encryption')
|
|
5
4
|
|
|
6
5
|
const { getEncoding } = require('../encoding/spec/autobee')
|
|
7
|
-
const { LEGACY_OPLOG_VERSION, OPLOG_VERSION } = require('./constants')
|
|
6
|
+
const { LEGACY_OPLOG_VERSION, OPLOG_VERSION } = require('./constants.js')
|
|
7
|
+
const { AutobeeEncryption, WriterEncryption } = require('./encryption.js')
|
|
8
8
|
|
|
9
9
|
const Oplog = getEncoding('@autobee/oplog')
|
|
10
10
|
const Link = getEncoding('@autobee/link')
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
const HypercoreEncryption = require('hypercore/lib/default-encryption.js')
|
|
2
|
+
const sodium = require('sodium-native')
|
|
3
|
+
const crypto = require('hypercore-crypto')
|
|
4
|
+
const c = require('compact-encoding')
|
|
5
|
+
const b4a = require('b4a')
|
|
6
|
+
|
|
7
|
+
const { DEFAULT_MANIFEST_VERSION } = require('./constants.js')
|
|
8
|
+
|
|
9
|
+
const ManifestData = {
|
|
10
|
+
preencode(state, m) {
|
|
11
|
+
c.uint.preencode(state, m.version)
|
|
12
|
+
state.end++ // max flag is 2 so always one byte
|
|
13
|
+
|
|
14
|
+
if (m.legacyBlocks) c.uint.preencode(state, m.legacyBlocks)
|
|
15
|
+
if (m.namespace) c.fixed32.preencode(state, m.namespace)
|
|
16
|
+
},
|
|
17
|
+
encode(state, m) {
|
|
18
|
+
const flags = (m.legacyBlocks ? 1 : 0) | (m.namespace ? 2 : 0)
|
|
19
|
+
|
|
20
|
+
c.uint.encode(state, m.version)
|
|
21
|
+
c.uint.encode(state, flags)
|
|
22
|
+
|
|
23
|
+
if (m.legacyBlocks) c.uint.encode(state, m.legacyBlocks)
|
|
24
|
+
if (m.namespace) c.fixed32.encode(state, m.namespace)
|
|
25
|
+
},
|
|
26
|
+
decode(state) {
|
|
27
|
+
const r0 = c.uint.decode(state)
|
|
28
|
+
const flags = c.uint.decode(state)
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
version: r0,
|
|
32
|
+
legacyBlocks: (flags & 1) !== 0 ? c.uint.decode(state) : 0,
|
|
33
|
+
namespace: (flags & 2) !== 0 ? c.fixed32.decode(state) : null
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const [, NS_VIEW_BLOCK_KEY, NS_HASH_KEY] = crypto.namespace('autobase', 4)
|
|
39
|
+
|
|
40
|
+
const [GENESIS_ENTROPY] = crypto.namespace('autobase/entropy', 2)
|
|
41
|
+
|
|
42
|
+
const nonce = b4a.alloc(sodium.crypto_stream_NONCEBYTES)
|
|
43
|
+
const hash = nonce.subarray(0, sodium.crypto_generichash_BYTES_MIN)
|
|
44
|
+
|
|
45
|
+
class AutobeeEncryption {
|
|
46
|
+
static PADDING = 8
|
|
47
|
+
|
|
48
|
+
constructor(auto) {
|
|
49
|
+
this.auto = auto
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
padding() {
|
|
53
|
+
return AutobeeEncryption.PADDING
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
isCompat(ctx) {
|
|
57
|
+
return ctx.manifest.version <= 1
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async getKeys(id, ctx) {
|
|
61
|
+
if (!this.auto.encryptionKey) return null
|
|
62
|
+
|
|
63
|
+
const entropy = GENESIS_ENTROPY
|
|
64
|
+
const block = this.blockKey(entropy, ctx)
|
|
65
|
+
const hash = crypto.hash([NS_HASH_KEY, block])
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
id,
|
|
69
|
+
block,
|
|
70
|
+
hash
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
blockKey(entropy, ctx) {
|
|
75
|
+
return getBlockKey(this.auto.key, this.auto.encryptionKey, entropy, ctx.key)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
compatKeys() {
|
|
79
|
+
throw new Error('Compatibility method is not specified')
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async encrypt(index, block, fork, ctx) {
|
|
83
|
+
// writer cores are long lasting, but view cores should be up to date
|
|
84
|
+
if (this instanceof ViewEncryption && ctx.manifest.version < DEFAULT_MANIFEST_VERSION) {
|
|
85
|
+
throw new Error(`Unexpected manifest: version < ${DEFAULT_MANIFEST_VERSION}`)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (this.isCompat(ctx, index)) {
|
|
89
|
+
const compat = this.compatKeys(ctx)
|
|
90
|
+
return HypercoreEncryption.encrypt(index, block, fork, compat.block, compat.blinding)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const keys = await this.getKeys(0, ctx)
|
|
94
|
+
|
|
95
|
+
encryptBlock(index, block, keys.id, keys.block, keys.hash)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async decrypt(index, block, ctx) {
|
|
99
|
+
if (this.isCompat(ctx, index)) {
|
|
100
|
+
return HypercoreEncryption.decrypt(index, block, this.compatKeys(ctx).block)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const padding = block.subarray(0, AutobeeEncryption.PADDING)
|
|
104
|
+
block = block.subarray(AutobeeEncryption.PADDING)
|
|
105
|
+
|
|
106
|
+
const type = padding[0]
|
|
107
|
+
switch (type) {
|
|
108
|
+
case 0:
|
|
109
|
+
return block // unencrypted
|
|
110
|
+
|
|
111
|
+
case 1:
|
|
112
|
+
break
|
|
113
|
+
|
|
114
|
+
default:
|
|
115
|
+
throw new Error('Unrecognised encryption type')
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const id = c.uint32.decode({ start: 4, end: 8, buffer: padding })
|
|
119
|
+
|
|
120
|
+
const keys = await this.getKeys(id, ctx)
|
|
121
|
+
|
|
122
|
+
c.uint64.encode({ start: 0, end: 8, buffer: nonce }, index)
|
|
123
|
+
nonce.set(padding, 8, 16)
|
|
124
|
+
|
|
125
|
+
// Decrypt the block using the full nonce
|
|
126
|
+
decrypt(block, nonce, keys.block)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static encryptAnchor(block, bootstrap, encryptionKey, namespace) {
|
|
130
|
+
const entropy = GENESIS_ENTROPY
|
|
131
|
+
|
|
132
|
+
const blockKey = getBlockKey(bootstrap, encryptionKey, entropy, namespace)
|
|
133
|
+
const hashKey = crypto.hash([NS_HASH_KEY, block])
|
|
134
|
+
|
|
135
|
+
encryptBlock(0, block, 0, blockKey, hashKey)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static async setSystemEncryption(bootstrap, encryptionKey, core, opts) {
|
|
139
|
+
await core.ready()
|
|
140
|
+
if (core.manifest.version === 1) {
|
|
141
|
+
const key = getCompatBlockKey(bootstrap, encryptionKey, '_system')
|
|
142
|
+
core.setEncryptionKey(key, { block: true })
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const info = {
|
|
147
|
+
key: bootstrap,
|
|
148
|
+
encryptionKey
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return core.setEncryption(new ViewEncryption(info, '_system'))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
static getSystemEncryption(bootstrap, encryptionKey) {
|
|
155
|
+
return AutobeeEncryption.getViewEncryption(bootstrap, encryptionKey, '_system')
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
static getViewEncryption(bootstrap, encryptionKey, name) {
|
|
159
|
+
const info = { key: bootstrap, encryptionKey }
|
|
160
|
+
return new ViewEncryption(info, name)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
static getWriterEncryption(bootstrap, encryptionKey) {
|
|
164
|
+
return new WriterEncryption({ key: bootstrap, encryptionKey })
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
class ViewEncryption extends AutobeeEncryption {
|
|
169
|
+
constructor(auto, name) {
|
|
170
|
+
super(auto)
|
|
171
|
+
this.name = name
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
compatKeys() {
|
|
175
|
+
const block = getCompatBlockKey(this.auto.key, this.auto.encryptionKey, this.name)
|
|
176
|
+
return {
|
|
177
|
+
block,
|
|
178
|
+
blinding: crypto.hash(block)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
blockKey(entropy, ctx) {
|
|
183
|
+
// compat encryption
|
|
184
|
+
if (ctx.manifest.version < DEFAULT_MANIFEST_VERSION) {
|
|
185
|
+
return getCompatBlockKey(this.auto.key, entropy, this.name)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return getBlockKey(this.auto.key, this.auto.encryptionKey, entropy, ctx.key)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
class WriterEncryption extends AutobeeEncryption {
|
|
193
|
+
compatKeys(ctx) {
|
|
194
|
+
return HypercoreEncryption.deriveKeys(this.auto.encryptionKey, ctx.key)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
blockKey(entropy, ctx) {
|
|
198
|
+
// used for anchors
|
|
199
|
+
if (ctx.manifest.userData) {
|
|
200
|
+
const userData = c.decode(ManifestData, ctx.manifest.userData)
|
|
201
|
+
if (userData.namespace !== null) {
|
|
202
|
+
const b = getBlockKey(this.auto.key, this.auto.encryptionKey, entropy, userData.namespace)
|
|
203
|
+
return b
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return getBlockKey(this.auto.key, this.auto.encryptionKey, entropy, ctx.key)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = {
|
|
212
|
+
AutobeeEncryption,
|
|
213
|
+
WriterEncryption,
|
|
214
|
+
ViewEncryption
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function encrypt(block, nonce, key) {
|
|
218
|
+
sodium.crypto_stream_xor(block, block, nonce, key)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function decrypt(block, nonce, key) {
|
|
222
|
+
return encrypt(block, nonce, key) // symmetric
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function getBlockKey(bootstrap, encryptionKey, entropy, hypercoreKey) {
|
|
226
|
+
return (
|
|
227
|
+
encryptionKey &&
|
|
228
|
+
crypto.hash([NS_VIEW_BLOCK_KEY, bootstrap, encryptionKey, entropy, hypercoreKey])
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function getCompatBlockKey(bootstrap, encryptionKey, name) {
|
|
233
|
+
if (typeof name === 'string') return getCompatBlockKey(bootstrap, encryptionKey, b4a.from(name))
|
|
234
|
+
return encryptionKey && crypto.hash([NS_VIEW_BLOCK_KEY, bootstrap, encryptionKey, name])
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function blockhash(block, padding, hashKey) {
|
|
238
|
+
sodium.crypto_generichash(hash, block, hashKey)
|
|
239
|
+
padding.set(hash.subarray(0, 8)) // copy first 8 bytes of hash
|
|
240
|
+
hash.fill(0) // clear nonce buffer
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function encryptBlock(index, block, id, blockKey, hashKey) {
|
|
244
|
+
const padding = block.subarray(0, AutobeeEncryption.PADDING)
|
|
245
|
+
block = block.subarray(AutobeeEncryption.PADDING)
|
|
246
|
+
|
|
247
|
+
blockhash(block, padding, hashKey)
|
|
248
|
+
c.uint32.encode({ start: 4, end: 8, buffer: padding }, id)
|
|
249
|
+
|
|
250
|
+
c.uint64.encode({ start: 0, end: 8, buffer: nonce }, index)
|
|
251
|
+
|
|
252
|
+
padding[0] = 1 // version in plaintext
|
|
253
|
+
|
|
254
|
+
nonce.set(padding, 8, 16)
|
|
255
|
+
|
|
256
|
+
// The combination of index, key id, fork id and block hash is very likely
|
|
257
|
+
// to be unique for a given Hypercore and therefore our nonce is suitable
|
|
258
|
+
encrypt(block, nonce, blockKey)
|
|
259
|
+
}
|
package/lib/migrations.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
const c = require('compact-encoding')
|
|
2
2
|
const b4a = require('b4a')
|
|
3
3
|
const crypto = require('hypercore-crypto')
|
|
4
|
-
const { AutobeeEncryption } = require('autobee-encryption')
|
|
5
4
|
const { decodeBlock } = require('hyperbee2/lib/encoding.js')
|
|
6
5
|
|
|
6
|
+
const { AutobeeEncryption } = require('./encryption.js')
|
|
7
7
|
const encoding = require('./encoding.js')
|
|
8
8
|
const { assert, bail } = require('./asserts.js')
|
|
9
9
|
|
package/lib/writers.js
CHANGED
|
@@ -3,7 +3,7 @@ const encoding = require('./encoding.js')
|
|
|
3
3
|
const Triggers = require('./triggers.js')
|
|
4
4
|
const { LEGACY_OPLOG_VERSION } = require('./constants.js')
|
|
5
5
|
const { resolveWeight } = require('./witness.js')
|
|
6
|
-
const { WriterEncryption } = require('
|
|
6
|
+
const { WriterEncryption } = require('./encryption.js')
|
|
7
7
|
const ReadWriteLock = require('read-write-mutexify')
|
|
8
8
|
|
|
9
9
|
const WRITER_PREFETCH = 10
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autobee",
|
|
3
|
-
"version": "2.11.
|
|
3
|
+
"version": "2.11.2",
|
|
4
4
|
"description": "Bee based autobase",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Holepunch Inc.",
|
|
@@ -23,11 +23,10 @@
|
|
|
23
23
|
"test:generate": "brittle -r test/all.js test/*.js"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"autobee-encryption": "^0.1.2",
|
|
27
26
|
"autobee-wakeup": "^1.1.3",
|
|
28
27
|
"b4a": "^1.8.0",
|
|
29
|
-
"compact-encoding": "^3.
|
|
30
|
-
"hyperbee2": "^2.17.
|
|
28
|
+
"compact-encoding": "^3.4.0",
|
|
29
|
+
"hyperbee2": "^2.17.1",
|
|
31
30
|
"hypercore": "^11.37.0",
|
|
32
31
|
"hypercore-id-encoding": "^1.3.0",
|
|
33
32
|
"hyperschema": "^1.26.2",
|