|
@@ -2,6 +2,8 @@ const { describe } = require('tape-plus')
|
2
|
2
|
const ram = require('random-access-memory')
|
3
|
3
|
const crypto = require('hypercore-crypto')
|
4
|
4
|
const fs = require('fs')
|
|
5
|
+const sodium = require('sodium-native')
|
|
6
|
+const hypercore = require('hypercore')
|
5
|
7
|
|
6
|
8
|
const KappaDrive = require('../')
|
7
|
9
|
|
|
@@ -307,8 +309,10 @@ describe('basic', (context) => {
|
307
|
309
|
|
308
|
310
|
describe('multiwriter', (context) => {
|
309
|
311
|
context('replicate to empty drive', (assert, next) => {
|
310
|
|
- var drive = KappaDrive(tmp())
|
311
|
|
- var drive2 = KappaDrive(tmp())
|
|
312
|
+ var storage1 = tmp()
|
|
313
|
+ var storage2 = tmp()
|
|
314
|
+ var drive = KappaDrive(storage1)
|
|
315
|
+ var drive2 = KappaDrive(storage2)
|
312
|
316
|
|
313
|
317
|
drive.ready((err) => {
|
314
|
318
|
assert.error(err, 'No error on drive.ready')
|
|
@@ -326,7 +330,7 @@ describe('multiwriter', (context) => {
|
326
|
330
|
drive2.readFile('/hello.txt', 'utf-8', (err, data) => {
|
327
|
331
|
assert.error(err, 'no error')
|
328
|
332
|
assert.same(data, 'world', 'gets latest value')
|
329
|
|
- next()
|
|
333
|
+ cleanup([storage1, storage2], next)
|
330
|
334
|
})
|
331
|
335
|
})
|
332
|
336
|
})
|
|
@@ -334,8 +338,10 @@ describe('multiwriter', (context) => {
|
334
|
338
|
})
|
335
|
339
|
|
336
|
340
|
context('defaults to latest value', (assert, next) => {
|
337
|
|
- var drive = KappaDrive(tmp())
|
338
|
|
- var drive2 = KappaDrive(tmp())
|
|
341
|
+ var storage1 = tmp()
|
|
342
|
+ var storage2 = tmp()
|
|
343
|
+ var drive = KappaDrive(storage1)
|
|
344
|
+ var drive2 = KappaDrive(storage2)
|
339
|
345
|
|
340
|
346
|
drive.ready((err) => {
|
341
|
347
|
assert.error(err, 'No error on drive.ready')
|
|
@@ -367,7 +373,7 @@ describe('multiwriter', (context) => {
|
367
|
373
|
drive.readFile('/hello.txt', (err, data) => {
|
368
|
374
|
assert.error(err, 'no error')
|
369
|
375
|
assert.same(data, Buffer.from('verden'), 'gets latest value')
|
370
|
|
- next()
|
|
376
|
+ cleanup([storage1, storage2], next)
|
371
|
377
|
})
|
372
|
378
|
})
|
373
|
379
|
})
|
|
@@ -378,8 +384,10 @@ describe('multiwriter', (context) => {
|
378
|
384
|
})
|
379
|
385
|
|
380
|
386
|
context('defalts to latest value with file descriptors', (assert, next) => {
|
381
|
|
- var drive = KappaDrive(tmp())
|
382
|
|
- var drive2 = KappaDrive(tmp())
|
|
387
|
+ var storage1 = tmp()
|
|
388
|
+ var storage2 = tmp()
|
|
389
|
+ var drive = KappaDrive(storage1)
|
|
390
|
+ var drive2 = KappaDrive(storage2)
|
383
|
391
|
|
384
|
392
|
drive.ready((err) => {
|
385
|
393
|
assert.error(err, 'No error on drive.ready')
|
|
@@ -412,7 +420,7 @@ describe('multiwriter', (context) => {
|
412
|
420
|
drive2.read(fd, data, 0, 5, null, (err, bytesRead, readData) => {
|
413
|
421
|
assert.error(err, 'no error')
|
414
|
422
|
assert.same(readData, Buffer.from('world'), 'gets latest value')
|
415
|
|
- next()
|
|
423
|
+ cleanup([storage1, storage2], next)
|
416
|
424
|
})
|
417
|
425
|
})
|
418
|
426
|
})
|
|
@@ -459,14 +467,9 @@ describe('multiwriter', (context) => {
|
459
|
467
|
|
460
|
468
|
// TODO: figure out why this resolves incorrectly when in memory
|
461
|
469
|
describe('conflict', (context) => {
|
462
|
|
- var storage1, storage2
|
463
|
|
-
|
464
|
|
- context.beforeEach((c) => {
|
465
|
|
- storage1 = tmp()
|
466
|
|
- storage2 = tmp()
|
467
|
|
- })
|
468
|
|
-
|
469
|
470
|
context('fork', (assert, next) => {
|
|
471
|
+ var storage1 = tmp()
|
|
472
|
+ var storage2 = tmp()
|
470
|
473
|
var drive = KappaDrive(storage1)
|
471
|
474
|
var drive2 = KappaDrive(storage2)
|
472
|
475
|
|
|
@@ -500,7 +503,7 @@ describe('conflict', (context) => {
|
500
|
503
|
drive.readFile('/hello.txt', 'utf-8', (err, data) => {
|
501
|
504
|
assert.error(err, 'no error')
|
502
|
505
|
assert.same(data, 'whateverr', 'forked values')
|
503
|
|
- cleanup('./tmp', next)
|
|
506
|
+ cleanup([storage1, storage1], next)
|
504
|
507
|
})
|
505
|
508
|
})
|
506
|
509
|
})
|
|
@@ -530,3 +533,98 @@ describe('read access', (context) => {
|
530
|
533
|
})
|
531
|
534
|
})
|
532
|
535
|
})
|
|
536
|
+
|
|
537
|
+describe('replicate with derived keypair', (context) => {
|
|
538
|
+ context('regular hypercore using derived keypair', (assert, next) => {
|
|
539
|
+ var storage1 = tmp()
|
|
540
|
+ var storage2 = tmp()
|
|
541
|
+ var master = masterKey()
|
|
542
|
+ var keys = keyPair(master, 0)
|
|
543
|
+
|
|
544
|
+ assert.ok(keys, 'generates keys')
|
|
545
|
+
|
|
546
|
+ var core1 = hypercore(storage1, keys.publicKey, { secretKey: keys.secretKey })
|
|
547
|
+ var core2 = hypercore(storage2, keys.publicKey)
|
|
548
|
+
|
|
549
|
+ var dog = 'dog'
|
|
550
|
+ core1.append(dog, (err, seq) => {
|
|
551
|
+ assert.error(err, 'no error')
|
|
552
|
+ replicate(core1, core2, (err) => {
|
|
553
|
+ assert.error(err, 'no error')
|
|
554
|
+
|
|
555
|
+ core2.get(0, (err, msg) => {
|
|
556
|
+ assert.error(err, 'no error')
|
|
557
|
+ assert.same(msg.toString(), dog, 'gets the dog')
|
|
558
|
+ cleanup([storage1, storage2], next)
|
|
559
|
+ })
|
|
560
|
+ })
|
|
561
|
+ })
|
|
562
|
+ })
|
|
563
|
+
|
|
564
|
+ context('using a master key, defaults to latest value', (assert, next) => {
|
|
565
|
+ var storage1 = tmp()
|
|
566
|
+ var storage2 = tmp()
|
|
567
|
+
|
|
568
|
+ var master1 = masterKey()
|
|
569
|
+ var master2 = masterKey()
|
|
570
|
+
|
|
571
|
+ var keyPair1 = keyPair.bind(null, master1)
|
|
572
|
+ var keyPair2 = keyPair.bind(null, master2)
|
|
573
|
+
|
|
574
|
+ var drive = KappaDrive(storage1, { keyPair: keyPair1 })
|
|
575
|
+ var drive2 = KappaDrive(storage2, { keyPair: keyPair2 })
|
|
576
|
+
|
|
577
|
+ drive.ready((err) => {
|
|
578
|
+ assert.error(err, 'No error on drive.ready')
|
|
579
|
+ drive.writeFile('/hello.txt', 'world', (err) => {
|
|
580
|
+ assert.error(err, 'no error')
|
|
581
|
+ drive.writeFile('/hello.txt', 'mundo', (err) => {
|
|
582
|
+ assert.error(err, 'no error')
|
|
583
|
+ sync()
|
|
584
|
+ })
|
|
585
|
+ })
|
|
586
|
+ })
|
|
587
|
+
|
|
588
|
+ function writeSecond (cb) {
|
|
589
|
+ drive2.writeFile('/hello.txt', 'verden', (err) => {
|
|
590
|
+ assert.error(err, 'no error')
|
|
591
|
+ cb()
|
|
592
|
+ })
|
|
593
|
+ }
|
|
594
|
+
|
|
595
|
+ function sync () {
|
|
596
|
+ drive2.ready(() => {
|
|
597
|
+ drive2.writeFile('test.txt', 'testing', (err) => {
|
|
598
|
+ assert.error(err, 'no error')
|
|
599
|
+ replicate(drive, drive2, (err) => {
|
|
600
|
+ assert.error(err, 'no error')
|
|
601
|
+ writeSecond(() => {
|
|
602
|
+ replicate(drive, drive2, (err) => {
|
|
603
|
+ assert.error(err, 'no error')
|
|
604
|
+ drive.readFile('/hello.txt', (err, data) => {
|
|
605
|
+ assert.error(err, 'no error')
|
|
606
|
+ assert.same(data, Buffer.from('verden'), 'gets latest value')
|
|
607
|
+ cleanup([storage1, storage2], next)
|
|
608
|
+ })
|
|
609
|
+ })
|
|
610
|
+ })
|
|
611
|
+ })
|
|
612
|
+ })
|
|
613
|
+ })
|
|
614
|
+ }
|
|
615
|
+ })
|
|
616
|
+})
|
|
617
|
+
|
|
618
|
+function masterKey () {
|
|
619
|
+ const key = sodium.sodium_malloc(sodium.crypto_kdf_KEYBYTES)
|
|
620
|
+ sodium.crypto_kdf_keygen(key)
|
|
621
|
+ return key
|
|
622
|
+}
|
|
623
|
+
|
|
624
|
+function keyPair (masterKey, id, ctxt = 'kappadrive') {
|
|
625
|
+ const context = sodium.sodium_malloc(sodium.crypto_hash_sha256_BYTES)
|
|
626
|
+ sodium.crypto_hash_sha256(context, Buffer.from(ctxt))
|
|
627
|
+ const seed = sodium.sodium_malloc(sodium.crypto_kdf_KEYBYTES)
|
|
628
|
+ sodium.crypto_kdf_derive_from_key(seed, id, context, masterKey)
|
|
629
|
+ return crypto.keyPair(seed)
|
|
630
|
+}
|