corestore 6.0.1-alpha.14 → 6.0.1-alpha.15
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 +89 -28
- package/package.json +2 -4
- package/test/all.js +22 -0
- package/lib/keys.js +0 -110
- package/test/keys.js +0 -68
package/index.js
CHANGED
|
@@ -5,31 +5,36 @@ const sodium = require('sodium-universal')
|
|
|
5
5
|
const Hypercore = require('hypercore')
|
|
6
6
|
const b4a = require('b4a')
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const [NS] = crypto.namespace('corestore', 1)
|
|
9
|
+
const DEFAULT_NAMESPACE = b4a.alloc(32) // This is meant to be 32 0-bytes
|
|
9
10
|
|
|
10
11
|
const CORES_DIR = 'cores'
|
|
11
|
-
const
|
|
12
|
-
const USERDATA_NAME_KEY = '
|
|
13
|
-
const USERDATA_NAMESPACE_KEY = '
|
|
14
|
-
const DEFAULT_NAMESPACE = generateNamespace('@corestore/default')
|
|
12
|
+
const PRIMARY_KEY_FILE_NAME = 'primary-key'
|
|
13
|
+
const USERDATA_NAME_KEY = 'corestore/name'
|
|
14
|
+
const USERDATA_NAMESPACE_KEY = 'corestore/namespace'
|
|
15
15
|
|
|
16
16
|
module.exports = class Corestore extends EventEmitter {
|
|
17
17
|
constructor (storage, opts = {}) {
|
|
18
18
|
super()
|
|
19
19
|
|
|
20
|
-
this.storage = Hypercore.defaultStorage(storage, { lock:
|
|
21
|
-
|
|
20
|
+
this.storage = Hypercore.defaultStorage(storage, { lock: PRIMARY_KEY_FILE_NAME })
|
|
22
21
|
this.cores = opts._cores || new Map()
|
|
23
|
-
this.
|
|
22
|
+
this.primaryKey = null
|
|
24
23
|
|
|
25
|
-
this.
|
|
24
|
+
this._keyStorage = null
|
|
25
|
+
this._primaryKey = opts.primaryKey
|
|
26
|
+
this._namespace = opts.namespace || DEFAULT_NAMESPACE
|
|
26
27
|
this._replicationStreams = opts._streams || []
|
|
28
|
+
this._overwrite = opts.overwrite === true
|
|
29
|
+
|
|
27
30
|
this._streamSessions = opts._streamSessions || new Map()
|
|
28
31
|
this._sessions = new Set() // sessions for THIS namespace
|
|
29
32
|
|
|
30
33
|
this._findingPeersCount = 0
|
|
31
34
|
this._findingPeers = []
|
|
32
35
|
|
|
36
|
+
if (this._namespace.byteLength !== 32) throw new Error('Namespace must be a 32-byte Buffer or Uint8Array')
|
|
37
|
+
|
|
33
38
|
this._opening = opts._opening ? opts._opening.then(() => this._open()) : this._open()
|
|
34
39
|
this._opening.catch(safetyCatch)
|
|
35
40
|
this.ready = () => this._opening
|
|
@@ -63,11 +68,28 @@ module.exports = class Corestore extends EventEmitter {
|
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
async _open () {
|
|
66
|
-
if (this.
|
|
67
|
-
this.
|
|
68
|
-
|
|
69
|
-
this.keys = await KeyManager.fromStorage(p => this.storage(PROFILES_DIR + '/' + p))
|
|
71
|
+
if (this._primaryKey) {
|
|
72
|
+
this.primaryKey = await this._primaryKey
|
|
73
|
+
return this.primaryKey
|
|
70
74
|
}
|
|
75
|
+
this._keyStorage = this.storage(PRIMARY_KEY_FILE_NAME)
|
|
76
|
+
this.primaryKey = await new Promise((resolve, reject) => {
|
|
77
|
+
this._keyStorage.stat((err, st) => {
|
|
78
|
+
if (err && err.code !== 'ENOENT') return reject(err)
|
|
79
|
+
if (err || st.size < 32 || this._overwrite) {
|
|
80
|
+
const key = crypto.randomBytes(32)
|
|
81
|
+
return this._keyStorage.write(0, key, err => {
|
|
82
|
+
if (err) return reject(err)
|
|
83
|
+
return resolve(key)
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
this._keyStorage.read(0, 32, (err, key) => {
|
|
87
|
+
if (err) return reject(err)
|
|
88
|
+
return resolve(key)
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
return this.primaryKey
|
|
71
93
|
}
|
|
72
94
|
|
|
73
95
|
async _generateKeys (opts) {
|
|
@@ -89,7 +111,7 @@ module.exports = class Corestore extends EventEmitter {
|
|
|
89
111
|
discoveryKey: crypto.discoveryKey(opts.publicKey)
|
|
90
112
|
}
|
|
91
113
|
}
|
|
92
|
-
const { publicKey, auth } = await this.
|
|
114
|
+
const { publicKey, auth } = await this.createKeyPair(opts.name)
|
|
93
115
|
return {
|
|
94
116
|
keyPair: {
|
|
95
117
|
publicKey,
|
|
@@ -101,6 +123,7 @@ module.exports = class Corestore extends EventEmitter {
|
|
|
101
123
|
}
|
|
102
124
|
|
|
103
125
|
_getPrereadyUserData (core, key) {
|
|
126
|
+
// Need to manually read the header values before the Hypercore is ready, hence the ugliness.
|
|
104
127
|
for (const { key: savedKey, value } of core.core.header.userData) {
|
|
105
128
|
if (key === savedKey) return value
|
|
106
129
|
}
|
|
@@ -112,7 +135,7 @@ module.exports = class Corestore extends EventEmitter {
|
|
|
112
135
|
if (!name) return
|
|
113
136
|
|
|
114
137
|
const namespace = this._getPrereadyUserData(core, USERDATA_NAMESPACE_KEY)
|
|
115
|
-
const { publicKey, auth } = await this.
|
|
138
|
+
const { publicKey, auth } = await this.createKeyPair(b4a.toString(name), namespace)
|
|
116
139
|
if (!b4a.equals(publicKey, core.key)) throw new Error('Stored core key does not match the provided name')
|
|
117
140
|
|
|
118
141
|
// TODO: Should Hypercore expose a helper for this, or should preready return keypair/auth?
|
|
@@ -179,6 +202,26 @@ module.exports = class Corestore extends EventEmitter {
|
|
|
179
202
|
return { from: core, keyPair, auth }
|
|
180
203
|
}
|
|
181
204
|
|
|
205
|
+
async createKeyPair (name) {
|
|
206
|
+
if (!this.primaryKey) await this._opening
|
|
207
|
+
|
|
208
|
+
const keyPair = {
|
|
209
|
+
publicKey: b4a.allocUnsafe(sodium.crypto_sign_PUBLICKEYBYTES),
|
|
210
|
+
secretKey: b4a.alloc(sodium.crypto_sign_SECRETKEYBYTES),
|
|
211
|
+
auth: {
|
|
212
|
+
sign: (msg) => sign(keyPair, msg),
|
|
213
|
+
verify: (signable, signature) => {
|
|
214
|
+
return sodium.crypto_sign_detached(signature, signable, keyPair.publicKey)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const seed = deriveSeed(this.primaryKey, this._namespace, name)
|
|
220
|
+
sodium.crypto_sign_seed_keypair(keyPair.publicKey, keyPair.secretKey, seed)
|
|
221
|
+
|
|
222
|
+
return keyPair
|
|
223
|
+
}
|
|
224
|
+
|
|
182
225
|
get (opts = {}) {
|
|
183
226
|
opts = validateGetOptions(opts)
|
|
184
227
|
const core = new Hypercore(null, {
|
|
@@ -233,20 +276,23 @@ module.exports = class Corestore extends EventEmitter {
|
|
|
233
276
|
}
|
|
234
277
|
|
|
235
278
|
namespace (name) {
|
|
236
|
-
if (!b4a.isBuffer(name)) name = b4a.from(name)
|
|
237
279
|
return new Corestore(this.storage, {
|
|
238
|
-
|
|
280
|
+
primaryKey: this._opening.then(() => this.primaryKey),
|
|
281
|
+
namespace: generateNamespace(this._namespace, name),
|
|
239
282
|
_opening: this._opening,
|
|
240
283
|
_cores: this.cores,
|
|
241
284
|
_streams: this._replicationStreams,
|
|
242
|
-
_streamSessions: this._streamSessions
|
|
243
|
-
keys: this._opening.then(() => this.keys)
|
|
285
|
+
_streamSessions: this._streamSessions
|
|
244
286
|
})
|
|
245
287
|
}
|
|
246
288
|
|
|
247
289
|
async _close () {
|
|
248
290
|
await this._opening
|
|
249
|
-
if (!b4a.equals(this._namespace, DEFAULT_NAMESPACE))
|
|
291
|
+
if (!b4a.equals(this._namespace, DEFAULT_NAMESPACE)) {
|
|
292
|
+
// namespaces should not release resources on close
|
|
293
|
+
// TODO: Refactor the namespace close logic to actually close sessions with ref counting
|
|
294
|
+
return
|
|
295
|
+
}
|
|
250
296
|
const closePromises = []
|
|
251
297
|
for (const core of this.cores.values()) {
|
|
252
298
|
closePromises.push(core.close())
|
|
@@ -256,7 +302,13 @@ module.exports = class Corestore extends EventEmitter {
|
|
|
256
302
|
// Only close streams that were created by the Corestore
|
|
257
303
|
if (!isExternal) stream.destroy()
|
|
258
304
|
}
|
|
259
|
-
|
|
305
|
+
if (!this._keyStorage) return
|
|
306
|
+
await new Promise((resolve, reject) => {
|
|
307
|
+
this._keyStorage.close(err => {
|
|
308
|
+
if (err) return reject(err)
|
|
309
|
+
return resolve(null)
|
|
310
|
+
})
|
|
311
|
+
})
|
|
260
312
|
}
|
|
261
313
|
|
|
262
314
|
close () {
|
|
@@ -265,10 +317,13 @@ module.exports = class Corestore extends EventEmitter {
|
|
|
265
317
|
this._closing.catch(safetyCatch)
|
|
266
318
|
return this._closing
|
|
267
319
|
}
|
|
320
|
+
}
|
|
268
321
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
322
|
+
function sign (keyPair, message) {
|
|
323
|
+
if (!keyPair.secretKey) throw new Error('Invalid key pair')
|
|
324
|
+
const signature = b4a.allocUnsafe(sodium.crypto_sign_BYTES)
|
|
325
|
+
sodium.crypto_sign_detached(signature, message, keyPair.secretKey)
|
|
326
|
+
return signature
|
|
272
327
|
}
|
|
273
328
|
|
|
274
329
|
function validateGetOptions (opts) {
|
|
@@ -288,11 +343,17 @@ function validateGetOptions (opts) {
|
|
|
288
343
|
return opts
|
|
289
344
|
}
|
|
290
345
|
|
|
291
|
-
function generateNamespace (
|
|
292
|
-
if (!b4a.isBuffer(
|
|
293
|
-
if (second && !b4a.isBuffer(second)) second = b4a.from(second)
|
|
346
|
+
function generateNamespace (namespace, name) {
|
|
347
|
+
if (!b4a.isBuffer(name)) name = b4a.from(name)
|
|
294
348
|
const out = b4a.allocUnsafe(32)
|
|
295
|
-
sodium.
|
|
349
|
+
sodium.crypto_generichash_batch(out, [namespace, name])
|
|
350
|
+
return out
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function deriveSeed (primaryKey, namespace, name) {
|
|
354
|
+
if (!b4a.isBuffer(name)) name = b4a.from(name)
|
|
355
|
+
const out = b4a.alloc(32)
|
|
356
|
+
sodium.crypto_generichash_batch(out, [NS, namespace, name], primaryKey)
|
|
296
357
|
return out
|
|
297
358
|
}
|
|
298
359
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "corestore",
|
|
3
|
-
"version": "6.0.1-alpha.
|
|
3
|
+
"version": "6.0.1-alpha.15",
|
|
4
4
|
"description": "A Hypercore factory that simplifies managing collections of cores.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -20,15 +20,13 @@
|
|
|
20
20
|
},
|
|
21
21
|
"homepage": "https://github.com/hypercore-protocol/corestore#readme",
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"brittle": "^
|
|
23
|
+
"brittle": "^2.2.10",
|
|
24
24
|
"random-access-file": "^2.2.0",
|
|
25
25
|
"random-access-memory": "^4.0.0",
|
|
26
26
|
"standardx": "^7.0.0"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"b4a": "^1.3.1",
|
|
30
|
-
"blake2b-universal": "^1.0.1",
|
|
31
|
-
"derive-key": "^1.0.1",
|
|
32
30
|
"hypercore": "next",
|
|
33
31
|
"hypercore-crypto": "^3.2.1",
|
|
34
32
|
"safety-catch": "^1.0.1",
|
package/test/all.js
CHANGED
|
@@ -3,6 +3,8 @@ const crypto = require('hypercore-crypto')
|
|
|
3
3
|
const ram = require('random-access-memory')
|
|
4
4
|
const os = require('os')
|
|
5
5
|
const path = require('path')
|
|
6
|
+
const b4a = require('b4a')
|
|
7
|
+
const sodium = require('sodium-universal')
|
|
6
8
|
|
|
7
9
|
const Corestore = require('..')
|
|
8
10
|
|
|
@@ -247,6 +249,26 @@ test('findingPeers', async function (t) {
|
|
|
247
249
|
t.is(cUpdated, true)
|
|
248
250
|
})
|
|
249
251
|
|
|
252
|
+
test('different primary keys yield different keypairs', async function (t) {
|
|
253
|
+
const pk1 = randomBytes(32)
|
|
254
|
+
const pk2 = randomBytes(32)
|
|
255
|
+
t.unlike(pk1, pk2)
|
|
256
|
+
|
|
257
|
+
const store1 = new Corestore(ram, { primaryKey: pk1 })
|
|
258
|
+
const store2 = new Corestore(ram, { primaryKey: pk2 })
|
|
259
|
+
|
|
260
|
+
const kp1 = await store1.createKeyPair('hello')
|
|
261
|
+
const kp2 = await store2.createKeyPair('hello')
|
|
262
|
+
|
|
263
|
+
t.unlike(kp1.publicKey, kp2.publicKey)
|
|
264
|
+
})
|
|
265
|
+
|
|
250
266
|
function tmpdir () {
|
|
251
267
|
return path.join(os.tmpdir(), 'corestore-' + Math.random().toString(16).slice(2))
|
|
252
268
|
}
|
|
269
|
+
|
|
270
|
+
function randomBytes (n) {
|
|
271
|
+
const buf = b4a.allocUnsafe(n)
|
|
272
|
+
sodium.randombytes_buf(buf)
|
|
273
|
+
return buf
|
|
274
|
+
}
|
package/lib/keys.js
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
// TODO: Extract this into a standalone module
|
|
2
|
-
|
|
3
|
-
const sodium = require('sodium-universal')
|
|
4
|
-
const blake2b = require('blake2b-universal')
|
|
5
|
-
const b4a = require('b4a')
|
|
6
|
-
|
|
7
|
-
const DEFAULT_TOKEN = b4a.alloc(0)
|
|
8
|
-
const NAMESPACE = b4a.from('@hyperspace/key-manager')
|
|
9
|
-
|
|
10
|
-
module.exports = class KeyManager {
|
|
11
|
-
constructor (storage, profile, opts = {}) {
|
|
12
|
-
this.storage = storage
|
|
13
|
-
this.profile = profile
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
_sign (keyPair, message) {
|
|
17
|
-
if (!keyPair._secretKey) throw new Error('Invalid key pair')
|
|
18
|
-
const signature = b4a.allocUnsafe(sodium.crypto_sign_BYTES)
|
|
19
|
-
sodium.crypto_sign_detached(signature, message, keyPair._secretKey)
|
|
20
|
-
return signature
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
createSecret (name, token) {
|
|
24
|
-
return deriveSeed(this.profile, token, name)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
createHypercoreKeyPair (name, token) {
|
|
28
|
-
const keyPair = {
|
|
29
|
-
publicKey: b4a.allocUnsafe(sodium.crypto_sign_PUBLICKEYBYTES),
|
|
30
|
-
_secretKey: b4a.alloc(sodium.crypto_sign_SECRETKEYBYTES),
|
|
31
|
-
auth: {
|
|
32
|
-
sign: (msg) => this._sign(keyPair, msg),
|
|
33
|
-
verify: (signable, signature) => {
|
|
34
|
-
return sodium.crypto_sign_detached(signature, signable, keyPair.publicKey)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
sodium.crypto_sign_seed_keypair(keyPair.publicKey, keyPair._secretKey, this.createSecret(name, token))
|
|
40
|
-
|
|
41
|
-
return keyPair
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
createNetworkIdentity (name, token) {
|
|
45
|
-
const keyPair = {
|
|
46
|
-
publicKey: b4a.alloc(32),
|
|
47
|
-
secretKey: b4a.alloc(64)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
sodium.crypto_sign_seed_keypair(keyPair.publicKey, keyPair.secretKey, this.createSecret(name, token))
|
|
51
|
-
|
|
52
|
-
return keyPair
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
close () {
|
|
56
|
-
return new Promise((resolve, reject) => {
|
|
57
|
-
this.storage.close(err => {
|
|
58
|
-
if (err) return reject(err)
|
|
59
|
-
return resolve()
|
|
60
|
-
})
|
|
61
|
-
})
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
static createToken () {
|
|
65
|
-
return randomBytes(32)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
static async fromStorage (storage, opts = {}) {
|
|
69
|
-
const profileStorage = storage(opts.name || 'default')
|
|
70
|
-
|
|
71
|
-
const profile = await new Promise((resolve, reject) => {
|
|
72
|
-
profileStorage.stat((err, st) => {
|
|
73
|
-
if (err && err.code !== 'ENOENT') return reject(err)
|
|
74
|
-
if (err || st.size < 32 || opts.overwrite) {
|
|
75
|
-
const key = randomBytes(32)
|
|
76
|
-
return profileStorage.write(0, key, err => {
|
|
77
|
-
if (err) return reject(err)
|
|
78
|
-
return resolve(key)
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
profileStorage.read(0, 32, (err, key) => {
|
|
82
|
-
if (err) return reject(err)
|
|
83
|
-
return resolve(key)
|
|
84
|
-
})
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
return new this(profileStorage, profile, opts)
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function deriveSeed (profile, token, name, output) {
|
|
93
|
-
if (token && token.length < 32) throw new Error('Token must be a Buffer with length >= 32')
|
|
94
|
-
if (!name || typeof name !== 'string') throw new Error('name must be a String')
|
|
95
|
-
if (!output) output = b4a.alloc(32)
|
|
96
|
-
|
|
97
|
-
blake2b.batch(output, [
|
|
98
|
-
NAMESPACE,
|
|
99
|
-
token || DEFAULT_TOKEN,
|
|
100
|
-
b4a.from(b4a.byteLength(name, 'ascii') + '\n' + name, 'ascii')
|
|
101
|
-
], profile)
|
|
102
|
-
|
|
103
|
-
return output
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function randomBytes (n) {
|
|
107
|
-
const buf = b4a.allocUnsafe(n)
|
|
108
|
-
sodium.randombytes_buf(buf)
|
|
109
|
-
return buf
|
|
110
|
-
}
|
package/test/keys.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
const p = require('path')
|
|
2
|
-
const fs = require('fs')
|
|
3
|
-
|
|
4
|
-
const test = require('brittle')
|
|
5
|
-
const ram = require('random-access-memory')
|
|
6
|
-
const raf = require('random-access-file')
|
|
7
|
-
|
|
8
|
-
const KeyManager = require('../lib/keys')
|
|
9
|
-
|
|
10
|
-
test('can create hypercore keypairs', async t => {
|
|
11
|
-
const keys = await KeyManager.fromStorage(ram)
|
|
12
|
-
|
|
13
|
-
const kp1 = await keys.createHypercoreKeyPair('core1')
|
|
14
|
-
const kp2 = await keys.createHypercoreKeyPair('core2')
|
|
15
|
-
|
|
16
|
-
t.is(kp1.publicKey.length, 32)
|
|
17
|
-
t.is(kp2.publicKey.length, 32)
|
|
18
|
-
t.unlike(kp1.publicKey, kp2.publicKey)
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test('distinct tokens create distinct hypercore keypairs', async t => {
|
|
22
|
-
const keys = await KeyManager.fromStorage(ram)
|
|
23
|
-
const token1 = KeyManager.createToken()
|
|
24
|
-
const token2 = KeyManager.createToken()
|
|
25
|
-
|
|
26
|
-
const kp1 = await keys.createHypercoreKeyPair('core1', token1)
|
|
27
|
-
const kp2 = await keys.createHypercoreKeyPair('core1', token2)
|
|
28
|
-
|
|
29
|
-
t.unlike(kp1.publicKey, kp2.publicKey)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('short user-provided token will throw', async t => {
|
|
33
|
-
const keys = await KeyManager.fromStorage(ram)
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
await keys.createHypercoreKeyPair('core1', Buffer.from('hello'))
|
|
37
|
-
t.fail('did not throw')
|
|
38
|
-
} catch {
|
|
39
|
-
t.pass('threw correctly')
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
test('persistent storage regenerates keys correctly', async t => {
|
|
44
|
-
const testPath = p.join(__dirname, 'test-data')
|
|
45
|
-
|
|
46
|
-
const keys1 = await KeyManager.fromStorage((name) => raf(testPath, { directory: testPath }))
|
|
47
|
-
const kp1 = await keys1.createHypercoreKeyPair('core1')
|
|
48
|
-
|
|
49
|
-
const keys2 = await KeyManager.fromStorage((name) => raf(testPath, { directory: testPath }))
|
|
50
|
-
const kp2 = await keys2.createHypercoreKeyPair('core1')
|
|
51
|
-
|
|
52
|
-
t.alike(kp1.publicKey, kp2.publicKey)
|
|
53
|
-
|
|
54
|
-
await keys1.close()
|
|
55
|
-
await keys2.close()
|
|
56
|
-
|
|
57
|
-
await fs.promises.rm(testPath, { recursive: true })
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
test('different master keys -> different keys', async t => {
|
|
61
|
-
const keys1 = await KeyManager.fromStorage(ram)
|
|
62
|
-
const keys2 = await KeyManager.fromStorage(ram)
|
|
63
|
-
|
|
64
|
-
const kp1 = await keys1.createHypercoreKeyPair('core1')
|
|
65
|
-
const kp2 = await keys2.createHypercoreKeyPair('core1')
|
|
66
|
-
|
|
67
|
-
t.unlike(kp1.publicKey, kp2.publicKey)
|
|
68
|
-
})
|