mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-10-07 22:57:07 +00:00
Refactor and add separate PasswordEncryption module
This commit is contained in:
parent
383420750e
commit
d83bfa9fc8
@ -1,41 +1,22 @@
|
|||||||
import crypto from 'crypto'
|
|
||||||
|
|
||||||
// From:
|
|
||||||
// https://github.com/libp2p/js-libp2p/blob/0b55625d146940994a306101650a55ee58e32f6c/packages/crypto/src/ciphers/aes-gcm.browser.ts
|
|
||||||
|
|
||||||
import { concat } from 'uint8arrays/concat'
|
|
||||||
import { fromString } from 'uint8arrays/from-string'
|
|
||||||
// import { create } from '@libp2p/crypto/ciphers/aes-gcm'
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Sources:
|
Source:
|
||||||
|
https://github.com/libp2p/js-libp2p/blob/0b55625d146940994a306101650a55ee58e32f6c/packages/crypto/src/ciphers/aes-gcm.browser.ts
|
||||||
|
|
||||||
|
More information:
|
||||||
- https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto
|
- https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto
|
||||||
- https://github.com/bradyjoslin/webcrypto-example/blob/master/script.js
|
- https://github.com/bradyjoslin/webcrypto-example/blob/master/script.js
|
||||||
- https://github.com/mdn/dom-examples/blob/main/web-crypto/encrypt-decrypt/aes-gcm.js
|
- https://github.com/mdn/dom-examples/blob/main/web-crypto/encrypt-decrypt/aes-gcm.js
|
||||||
- https://github.com/libp2p/js-libp2p/blob/0b55625d146940994a306101650a55ee58e32f6c/packages/crypto/src/ciphers/aes-gcm.browser.ts
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const cipher = createAes()
|
// import crypto from 'crypto'
|
||||||
|
import { concat } from 'uint8arrays/concat'
|
||||||
|
import { fromString } from 'uint8arrays/from-string'
|
||||||
|
|
||||||
const encrypt = ({ password }) => async (value) => {
|
// Polyfill fix for browsers
|
||||||
return cipher.encrypt(value, password)
|
const getCrypto = () => {
|
||||||
|
return global.crypto
|
||||||
}
|
}
|
||||||
|
|
||||||
const decrypt = ({ password }) => async (value) => {
|
|
||||||
return cipher.decrypt(value, password)
|
|
||||||
}
|
|
||||||
|
|
||||||
const generatePassword = async (length = 256) => {
|
|
||||||
return crypto.getRandomValues(new Uint8Array(length))
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
encrypt,
|
|
||||||
decrypt,
|
|
||||||
generatePassword
|
|
||||||
}
|
|
||||||
// import webcrypto from '../webcrypto.js';
|
|
||||||
|
|
||||||
// WebKit on Linux does not support deriving a key from an empty PBKDF2 key.
|
// WebKit on Linux does not support deriving a key from an empty PBKDF2 key.
|
||||||
// So, as a workaround, we provide the generated key as a constant. We test that
|
// So, as a workaround, we provide the generated key as a constant. We test that
|
||||||
// this generated key is accurate in test/workaround.spec.ts
|
// this generated key is accurate in test/workaround.spec.ts
|
||||||
@ -50,7 +31,7 @@ export const derivedEmptyPasswordKey = { alg: 'A128GCM', ext: true, k: 'scm9jmO_
|
|||||||
|
|
||||||
// Based off of code from https://github.com/luke-park/SecureCompatibleEncryptionExamples
|
// Based off of code from https://github.com/luke-park/SecureCompatibleEncryptionExamples
|
||||||
|
|
||||||
export function createAes (opts) {
|
export function AES (opts) {
|
||||||
const algorithm = opts?.algorithm ?? 'AES-GCM'
|
const algorithm = opts?.algorithm ?? 'AES-GCM'
|
||||||
let keyLength = opts?.keyLength ?? 16
|
let keyLength = opts?.keyLength ?? 16
|
||||||
const nonceLength = opts?.nonceLength ?? 12
|
const nonceLength = opts?.nonceLength ?? 12
|
||||||
@ -58,6 +39,7 @@ export function createAes (opts) {
|
|||||||
const saltLength = opts?.saltLength ?? 16
|
const saltLength = opts?.saltLength ?? 16
|
||||||
const iterations = opts?.iterations ?? 32767
|
const iterations = opts?.iterations ?? 32767
|
||||||
// const crypto = webcrypto.get();
|
// const crypto = webcrypto.get();
|
||||||
|
const crypto = getCrypto()
|
||||||
keyLength *= 8 // Browser crypto uses bits instead of bytes
|
keyLength *= 8 // Browser crypto uses bits instead of bytes
|
||||||
/**
|
/**
|
||||||
* Uses the provided password to derive a pbkdf2 key. The key
|
* Uses the provided password to derive a pbkdf2 key. The key
|
||||||
6
src/encryption/index.js
Normal file
6
src/encryption/index.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* @module Encryption
|
||||||
|
* @description
|
||||||
|
* Encryption modules for OrbitDB.
|
||||||
|
*/
|
||||||
|
export { default as PasswordEncryption } from './password.js'
|
||||||
29
src/encryption/password.js
Normal file
29
src/encryption/password.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* @namespace Encryption-Password
|
||||||
|
* @memberof module:Encryption
|
||||||
|
* @description
|
||||||
|
* Password encryption module encrypts data using AES-GCM PBKDF2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AES } from './aes-gcm-pbkdf2.js'
|
||||||
|
|
||||||
|
const PasswordEncryption = async ({ password, aesOptions }) => {
|
||||||
|
aesOptions = aesOptions || {}
|
||||||
|
|
||||||
|
const aes = AES(aesOptions)
|
||||||
|
|
||||||
|
const encrypt = (value) => {
|
||||||
|
return aes.encrypt(value, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
const decrypt = (value) => {
|
||||||
|
return aes.decrypt(value, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
encrypt,
|
||||||
|
decrypt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PasswordEncryption
|
||||||
@ -41,3 +41,7 @@ export {
|
|||||||
MemoryStorage,
|
MemoryStorage,
|
||||||
ComposedStorage
|
ComposedStorage
|
||||||
} from './storage/index.js'
|
} from './storage/index.js'
|
||||||
|
|
||||||
|
export {
|
||||||
|
PasswordEncryption
|
||||||
|
} from './encryption/index.js'
|
||||||
|
|||||||
@ -86,7 +86,10 @@ const create = async (identity, id, payload, encryptPayloadFn, clock = null, nex
|
|||||||
entry.identity = identity.hash
|
entry.identity = identity.hash
|
||||||
entry.sig = signature
|
entry.sig = signature
|
||||||
entry.payload = payload
|
entry.payload = payload
|
||||||
entry._payload = encryptedPayload
|
|
||||||
|
if (encryptPayloadFn) {
|
||||||
|
entry._payload = encryptedPayload
|
||||||
|
}
|
||||||
|
|
||||||
return entry
|
return entry
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,7 +70,7 @@ const Log = async (identity, { logId, logHeads, access, entryStorage, headsStora
|
|||||||
|
|
||||||
// Encryption of entries and payloads
|
// Encryption of entries and payloads
|
||||||
encryption = encryption || {}
|
encryption = encryption || {}
|
||||||
const { encryptPayloadFn } = encryption
|
const encryptPayloadFn = encryption.data?.encrypt
|
||||||
|
|
||||||
// Access Controller
|
// Access Controller
|
||||||
access = access || await DefaultAccessController()
|
access = access || await DefaultAccessController()
|
||||||
|
|||||||
@ -6,9 +6,11 @@ import MemoryStorage from '../storage/memory.js'
|
|||||||
const DefaultStorage = MemoryStorage
|
const DefaultStorage = MemoryStorage
|
||||||
|
|
||||||
const OplogIndex = async ({ logHeads, entryStorage, headsStorage, indexStorage, encryption }) => {
|
const OplogIndex = async ({ logHeads, entryStorage, headsStorage, indexStorage, encryption }) => {
|
||||||
encryption = encryption || {}
|
// Setup encryption and decryption functions
|
||||||
const { encryptPayloadFn, decryptPayloadFn, encryptEntryFn, decryptEntryFn } = encryption
|
const encryptEntryFn = encryption?.replication?.encrypt
|
||||||
|
const decryptEntryFn = encryption?.replication?.decrypt
|
||||||
|
const encryptPayloadFn = encryption?.data?.encrypt
|
||||||
|
const decryptPayloadFn = encryption?.data?.decrypt
|
||||||
// Oplog entry storage
|
// Oplog entry storage
|
||||||
const _entries = entryStorage || await DefaultStorage()
|
const _entries = entryStorage || await DefaultStorage()
|
||||||
// Entry index for keeping track which entries are already in the log
|
// Entry index for keeping track which entries are already in the log
|
||||||
|
|||||||
@ -158,7 +158,7 @@ const Sync = async ({ ipfs, log, events, onSynced, start, timeout }) => {
|
|||||||
for await (const value of source) {
|
for await (const value of source) {
|
||||||
const headBytes = value.subarray()
|
const headBytes = value.subarray()
|
||||||
if (headBytes && onSynced) {
|
if (headBytes && onSynced) {
|
||||||
const entry = await Entry.decode(headBytes, log.encryption.decryptEntryFn, log.encryption.decryptPayloadFn)
|
const entry = await Entry.decode(headBytes, log.encryption.replication?.decrypt, log.encryption.data?.decrypt)
|
||||||
await onSynced(entry)
|
await onSynced(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -223,7 +223,7 @@ const Sync = async ({ ipfs, log, events, onSynced, start, timeout }) => {
|
|||||||
const task = async () => {
|
const task = async () => {
|
||||||
try {
|
try {
|
||||||
if (data && onSynced) {
|
if (data && onSynced) {
|
||||||
const entry = await Entry.decode(data, log.encryption.decryptEntryFn, log.encryption.decryptPayloadFn)
|
const entry = await Entry.decode(data, log.encryption.replication?.decrypt, log.encryption.data?.decrypt)
|
||||||
await onSynced(entry)
|
await onSynced(entry)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { strictEqual, deepStrictEqual } from 'assert'
|
import { strictEqual, deepStrictEqual, notEqual } from 'assert'
|
||||||
import { rimraf } from 'rimraf'
|
import { rimraf } from 'rimraf'
|
||||||
import { existsSync } from 'fs'
|
import { existsSync } from 'fs'
|
||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
import Path from 'path'
|
import Path from 'path'
|
||||||
import { Database, Entry, KeyStore, Identities } from '../src/index.js'
|
import { Database, KeyStore, Identities } from '../src/index.js'
|
||||||
import LevelStorage from '../src/storage/level.js'
|
import LevelStorage from '../src/storage/level.js'
|
||||||
import MemoryStorage from '../src/storage/memory.js'
|
import MemoryStorage from '../src/storage/memory.js'
|
||||||
import testKeysPath from './fixtures/test-keys-path.js'
|
import testKeysPath from './fixtures/test-keys-path.js'
|
||||||
@ -68,8 +68,12 @@ describe('Database', function () {
|
|||||||
describe('Options', () => {
|
describe('Options', () => {
|
||||||
it('uses default directory for headsStorage', async () => {
|
it('uses default directory for headsStorage', async () => {
|
||||||
db = await Database({ ipfs, identity: testIdentity, address: databaseId, accessController })
|
db = await Database({ ipfs, identity: testIdentity, address: databaseId, accessController })
|
||||||
const op = { op: 'PUT', key: 1, value: 'record 1 on db 1' }
|
|
||||||
const hash = await db.addOperation(op)
|
const op1 = { op: 'PUT', key: 1, value: 'record 1 on db 1 version 1' }
|
||||||
|
const op2 = { op: 'PUT', key: 1, value: 'record 1 on db 1 version 2' }
|
||||||
|
|
||||||
|
await db.addOperation(op1)
|
||||||
|
const hash = await db.addOperation(op2)
|
||||||
|
|
||||||
const headsPath = Path.join('./orbitdb/', `${databaseId}/`, '/log/_heads/')
|
const headsPath = Path.join('./orbitdb/', `${databaseId}/`, '/log/_heads/')
|
||||||
|
|
||||||
@ -79,7 +83,9 @@ describe('Database', function () {
|
|||||||
|
|
||||||
const headsStorage = await LevelStorage({ path: headsPath })
|
const headsStorage = await LevelStorage({ path: headsPath })
|
||||||
|
|
||||||
deepStrictEqual((await Entry.decode(await headsStorage.get(hash))).payload, op)
|
const bytes = Uint8Array.from(await headsStorage.get(hash))
|
||||||
|
|
||||||
|
notEqual(bytes.length, 0)
|
||||||
|
|
||||||
await headsStorage.close()
|
await headsStorage.close()
|
||||||
|
|
||||||
@ -88,8 +94,11 @@ describe('Database', function () {
|
|||||||
|
|
||||||
it('uses given directory for headsStorage', async () => {
|
it('uses given directory for headsStorage', async () => {
|
||||||
db = await Database({ ipfs, identity: testIdentity, address: databaseId, accessController, directory: './custom-directory' })
|
db = await Database({ ipfs, identity: testIdentity, address: databaseId, accessController, directory: './custom-directory' })
|
||||||
const op = { op: 'PUT', key: 1, value: 'record 1 on db 1' }
|
const op1 = { op: 'PUT', key: 1, value: 'record 1 on db 1 version 1' }
|
||||||
const hash = await db.addOperation(op)
|
const op2 = { op: 'PUT', key: 1, value: 'record 1 on db 1 version 2' }
|
||||||
|
|
||||||
|
await db.addOperation(op1)
|
||||||
|
const hash = await db.addOperation(op2)
|
||||||
|
|
||||||
const headsPath = Path.join('./custom-directory/', `${databaseId}/`, '/log/_heads/')
|
const headsPath = Path.join('./custom-directory/', `${databaseId}/`, '/log/_heads/')
|
||||||
|
|
||||||
@ -99,7 +108,9 @@ describe('Database', function () {
|
|||||||
|
|
||||||
const headsStorage = await LevelStorage({ path: headsPath })
|
const headsStorage = await LevelStorage({ path: headsPath })
|
||||||
|
|
||||||
deepStrictEqual((await Entry.decode(await headsStorage.get(hash))).payload, op)
|
const bytes = Uint8Array.from(await headsStorage.get(hash))
|
||||||
|
|
||||||
|
notEqual(bytes.length, 0)
|
||||||
|
|
||||||
await headsStorage.close()
|
await headsStorage.close()
|
||||||
|
|
||||||
@ -110,23 +121,41 @@ describe('Database', function () {
|
|||||||
it('uses given MemoryStorage for headsStorage', async () => {
|
it('uses given MemoryStorage for headsStorage', async () => {
|
||||||
const headsStorage = await MemoryStorage()
|
const headsStorage = await MemoryStorage()
|
||||||
db = await Database({ ipfs, identity: testIdentity, address: databaseId, accessController, directory: './orbitdb', headsStorage })
|
db = await Database({ ipfs, identity: testIdentity, address: databaseId, accessController, directory: './orbitdb', headsStorage })
|
||||||
const op = { op: 'PUT', key: 1, value: 'record 1 on db 1' }
|
const op1 = { op: 'PUT', key: 1, value: 'record 1 on db 1 version 1' }
|
||||||
const hash = await db.addOperation(op)
|
const op2 = { op: 'PUT', key: 1, value: 'record 1 on db 1 version 2' }
|
||||||
|
|
||||||
deepStrictEqual((await Entry.decode(await headsStorage.get(hash))).payload, op)
|
await db.addOperation(op1)
|
||||||
|
const hash = await db.addOperation(op2)
|
||||||
|
|
||||||
|
const bytes = Uint8Array.from(await headsStorage.get(hash))
|
||||||
|
|
||||||
|
notEqual(bytes.length, 0)
|
||||||
|
|
||||||
await db.close()
|
await db.close()
|
||||||
|
|
||||||
|
await headsStorage.close()
|
||||||
|
await rimraf('./orbitdb')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('uses given MemoryStorage for entryStorage', async () => {
|
it('uses given MemoryStorage for entryStorage', async () => {
|
||||||
const entryStorage = await MemoryStorage()
|
const entryStorage = await MemoryStorage()
|
||||||
db = await Database({ ipfs, identity: testIdentity, address: databaseId, accessController, directory: './orbitdb', entryStorage })
|
const headsStorage = await MemoryStorage()
|
||||||
const op = { op: 'PUT', key: 1, value: 'record 1 on db 1' }
|
db = await Database({ ipfs, identity: testIdentity, address: databaseId, accessController, directory: './orbitdb', headsStorage, entryStorage })
|
||||||
const hash = await db.addOperation(op)
|
const op1 = { op: 'PUT', key: 1, value: 'record 1 on db 1 version 1' }
|
||||||
|
const op2 = { op: 'PUT', key: 1, value: 'record 1 on db 1 version 2' }
|
||||||
|
|
||||||
deepStrictEqual((await Entry.decode(await entryStorage.get(hash))).payload, op)
|
await db.addOperation(op1)
|
||||||
|
const hash = await db.addOperation(op2)
|
||||||
|
|
||||||
|
const e = await entryStorage.get(hash)
|
||||||
|
const bytes = Uint8Array.from(e)
|
||||||
|
notEqual(bytes.length, 0)
|
||||||
|
|
||||||
await db.close()
|
await db.close()
|
||||||
|
|
||||||
|
await entryStorage.close()
|
||||||
|
await headsStorage.close()
|
||||||
|
await rimraf('./orbitdb')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,8 @@ describe('Entry', function () {
|
|||||||
it('creates a an empty entry', async () => {
|
it('creates a an empty entry', async () => {
|
||||||
const expectedHash = 'zdpuAsKzwUEa8cz9pkJxxFMxLuP3cutA9PDGoLZytrg4RSVEa'
|
const expectedHash = 'zdpuAsKzwUEa8cz9pkJxxFMxLuP3cutA9PDGoLZytrg4RSVEa'
|
||||||
const entry = await create(testIdentity, 'A', 'hello')
|
const entry = await create(testIdentity, 'A', 'hello')
|
||||||
strictEqual(entry.hash, expectedHash)
|
const { hash } = await Entry.encode(entry)
|
||||||
|
strictEqual(hash, expectedHash)
|
||||||
strictEqual(entry.id, 'A')
|
strictEqual(entry.id, 'A')
|
||||||
strictEqual(entry.clock.id, testIdentity.publicKey)
|
strictEqual(entry.clock.id, testIdentity.publicKey)
|
||||||
strictEqual(entry.clock.time, 0)
|
strictEqual(entry.clock.time, 0)
|
||||||
@ -47,7 +48,8 @@ describe('Entry', function () {
|
|||||||
const expectedHash = 'zdpuAmthfqpHRQjdSpKN5etr1GrreJb7QcU1Hshm6pERnzsxi'
|
const expectedHash = 'zdpuAmthfqpHRQjdSpKN5etr1GrreJb7QcU1Hshm6pERnzsxi'
|
||||||
const payload = 'hello world'
|
const payload = 'hello world'
|
||||||
const entry = await create(testIdentity, 'A', payload)
|
const entry = await create(testIdentity, 'A', payload)
|
||||||
strictEqual(entry.hash, expectedHash)
|
const { hash } = await Entry.encode(entry)
|
||||||
|
strictEqual(hash, expectedHash)
|
||||||
strictEqual(entry.payload, payload)
|
strictEqual(entry.payload, payload)
|
||||||
strictEqual(entry.id, 'A')
|
strictEqual(entry.id, 'A')
|
||||||
strictEqual(entry.clock.id, testIdentity.publicKey)
|
strictEqual(entry.clock.id, testIdentity.publicKey)
|
||||||
@ -81,7 +83,7 @@ describe('Entry', function () {
|
|||||||
const payload2 = 'hello again'
|
const payload2 = 'hello again'
|
||||||
const entry1 = await create(testIdentity, 'A', payload1)
|
const entry1 = await create(testIdentity, 'A', payload1)
|
||||||
entry1.clock = tickClock(entry1.clock)
|
entry1.clock = tickClock(entry1.clock)
|
||||||
const entry2 = await create(testIdentity, 'A', payload2, entry1.clock, [entry1])
|
const entry2 = await create(testIdentity, 'A', payload2, null, entry1.clock, [entry1])
|
||||||
strictEqual(entry2.payload, payload2)
|
strictEqual(entry2.payload, payload2)
|
||||||
strictEqual(entry2.next.length, 1)
|
strictEqual(entry2.next.length, 1)
|
||||||
// strictEqual(entry2.hash, expectedHash)
|
// strictEqual(entry2.hash, expectedHash)
|
||||||
@ -91,7 +93,8 @@ describe('Entry', function () {
|
|||||||
|
|
||||||
it('`next` parameter can be an array of strings', async () => {
|
it('`next` parameter can be an array of strings', async () => {
|
||||||
const entry1 = await create(testIdentity, 'A', 'hello1')
|
const entry1 = await create(testIdentity, 'A', 'hello1')
|
||||||
const entry2 = await create(testIdentity, 'A', 'hello2', null, [entry1.hash])
|
const { hash } = await Entry.encode(entry1)
|
||||||
|
const entry2 = await create(testIdentity, 'A', 'hello2', null, null, [hash])
|
||||||
strictEqual(typeof entry2.next[0] === 'string', true)
|
strictEqual(typeof entry2.next[0] === 'string', true)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -138,7 +141,7 @@ describe('Entry', function () {
|
|||||||
it('throws an error if next is not an array', async () => {
|
it('throws an error if next is not an array', async () => {
|
||||||
let err
|
let err
|
||||||
try {
|
try {
|
||||||
await create(testIdentity, 'A', 'hello', null, {})
|
await create(testIdentity, 'A', 'hello', null, null, {})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
err = e
|
err = e
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { rimraf } from 'rimraf'
|
|||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
import { Log, Entry, Identities, KeyStore, MemoryStorage } from '../../src/index.js'
|
import { Log, Entry, Identities, KeyStore, MemoryStorage } from '../../src/index.js'
|
||||||
import testKeysPath from '../fixtures/test-keys-path.js'
|
import testKeysPath from '../fixtures/test-keys-path.js'
|
||||||
import { encrypt, decrypt } from '../utils/encrypt.js'
|
|
||||||
|
|
||||||
const { create } = Entry
|
const { create } = Entry
|
||||||
|
|
||||||
@ -61,15 +60,21 @@ describe('Log', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('sets one head if multiple are given as params', async () => {
|
it('sets one head if multiple are given as params', async () => {
|
||||||
const one = await create(testIdentity, 'A', 'entryA', null, [])
|
const one = await create(testIdentity, 'A', 'entryA', null, null, [])
|
||||||
const two = await create(testIdentity, 'A', 'entryB', null, [one.hash])
|
const { hash: hash1, bytes: bytes1 } = await Entry.encode(one)
|
||||||
const three = await create(testIdentity, 'A', 'entryC', null, [two.hash])
|
const two = await create(testIdentity, 'A', 'entryB', null, null, [hash1])
|
||||||
const four = await create(testIdentity, 'A', 'entryD', null, [two.hash])
|
const { hash: hash2, bytes: bytes2 } = await Entry.encode(two)
|
||||||
|
const three = await create(testIdentity, 'A', 'entryC', null, null, [hash2])
|
||||||
|
const { hash: hash3, bytes: bytes3 } = await Entry.encode(three)
|
||||||
|
const four = await create(testIdentity, 'A', 'entryD', null, null, [hash3])
|
||||||
|
const { hash: hash4, bytes: bytes4 } = await Entry.encode(four)
|
||||||
const entryStorage = await MemoryStorage()
|
const entryStorage = await MemoryStorage()
|
||||||
await entryStorage.put(one.hash, one.bytes)
|
await entryStorage.put(hash1, bytes1)
|
||||||
await entryStorage.put(two.hash, two.bytes)
|
await entryStorage.put(hash2, bytes2)
|
||||||
await entryStorage.put(three.hash, three.bytes)
|
await entryStorage.put(hash3, bytes3)
|
||||||
await entryStorage.put(four.hash, four.bytes)
|
await entryStorage.put(hash4, bytes4)
|
||||||
|
three.hash = hash3
|
||||||
|
two.hash = hash2
|
||||||
const log = await Log(testIdentity, { logId: 'A', logHeads: [three, three, two, two], entryStorage })
|
const log = await Log(testIdentity, { logId: 'A', logHeads: [three, three, two, two], entryStorage })
|
||||||
const values = await log.values()
|
const values = await log.values()
|
||||||
const heads = await log.heads()
|
const heads = await log.heads()
|
||||||
@ -79,15 +84,22 @@ describe('Log', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('sets two heads if two given as params', async () => {
|
it('sets two heads if two given as params', async () => {
|
||||||
const one = await create(testIdentity, 'A', 'entryA', null, [])
|
const one = await create(testIdentity, 'A', 'entryA', null, null, [])
|
||||||
const two = await create(testIdentity, 'A', 'entryB', null, [one.hash])
|
const { hash: hash1, bytes: bytes1 } = await Entry.encode(one)
|
||||||
const three = await create(testIdentity, 'A', 'entryC', null, [two.hash])
|
const two = await create(testIdentity, 'A', 'entryB', null, null, [hash1])
|
||||||
const four = await create(testIdentity, 'A', 'entryD', null, [two.hash])
|
const { hash: hash2, bytes: bytes2 } = await Entry.encode(two)
|
||||||
|
const three = await create(testIdentity, 'A', 'entryC', null, null, [hash2])
|
||||||
|
const { hash: hash3, bytes: bytes3 } = await Entry.encode(three)
|
||||||
|
const four = await create(testIdentity, 'A', 'entryD', null, null, [hash2])
|
||||||
|
const { hash: hash4, bytes: bytes4 } = await Entry.encode(four)
|
||||||
const entryStorage = await MemoryStorage()
|
const entryStorage = await MemoryStorage()
|
||||||
await entryStorage.put(one.hash, one.bytes)
|
await entryStorage.put(hash1, bytes1)
|
||||||
await entryStorage.put(two.hash, two.bytes)
|
await entryStorage.put(hash2, bytes2)
|
||||||
await entryStorage.put(three.hash, three.bytes)
|
await entryStorage.put(hash3, bytes3)
|
||||||
await entryStorage.put(four.hash, four.bytes)
|
await entryStorage.put(hash4, bytes4)
|
||||||
|
three.hash = hash3
|
||||||
|
four.hash = hash4
|
||||||
|
two.hash = hash2
|
||||||
const log = await Log(testIdentity, { logId: 'A', logHeads: [three, four, two], entryStorage })
|
const log = await Log(testIdentity, { logId: 'A', logHeads: [three, four, two], entryStorage })
|
||||||
const values = await log.values()
|
const values = await log.values()
|
||||||
const heads = await log.heads()
|
const heads = await log.heads()
|
||||||
@ -143,34 +155,5 @@ describe('Log', function () {
|
|||||||
strictEqual(values[1].payload, 'hello2')
|
strictEqual(values[1].payload, 'hello2')
|
||||||
strictEqual(values[2].payload, 'hello3')
|
strictEqual(values[2].payload, 'hello3')
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('encrypts a log entry when the payload is a string', async () => {
|
|
||||||
// const keys = await keystore.createKey('hello1')
|
|
||||||
|
|
||||||
// const privateKey = await keystore.getKey('hello1')
|
|
||||||
// const publicKey = await keystore.getPublic(keys)
|
|
||||||
|
|
||||||
const encryptPayloadFn = encrypt({ password: 'hello world' })
|
|
||||||
const decryptPayloadFn = decrypt({ password: 'hello world' })
|
|
||||||
const log = await Log(testIdentity, { encryption: { encryptPayloadFn, decryptPayloadFn } })
|
|
||||||
const entry = await log.append('hello1')
|
|
||||||
const value = await log.get(entry.hash)
|
|
||||||
strictEqual(value.payload, 'hello1')
|
|
||||||
})
|
|
||||||
|
|
||||||
it.skip('encrypts a log entry when the payload is an object', async () => {
|
|
||||||
// const keys = await keystore.createKey('hello1')
|
|
||||||
|
|
||||||
// const privateKey = await keystore.getKey('hello1')
|
|
||||||
// const publicKey = await keystore.getPublic(keys)
|
|
||||||
|
|
||||||
const encryptPayloadFn = encrypt({ password: 'hello world' })
|
|
||||||
const decryptPayloadFn = decrypt({ password: 'hello world' })
|
|
||||||
const log = await Log(testIdentity, { encryption: { encryptPayloadFn, decryptPayloadFn } })
|
|
||||||
const entry = await log.append({ test: 'hello1' })
|
|
||||||
const value = await log.get(entry.hash)
|
|
||||||
|
|
||||||
deepStrictEqual(value.payload, { test: 'hello1' })
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import createHelia from '../utils/create-helia.js'
|
|||||||
|
|
||||||
const keysPath = './testkeys'
|
const keysPath = './testkeys'
|
||||||
|
|
||||||
describe.only('Log - Replication', function () {
|
describe('Log - Replication', function () {
|
||||||
let ipfs1, ipfs2
|
let ipfs1, ipfs2
|
||||||
let id1, id2
|
let id1, id2
|
||||||
let keystore
|
let keystore
|
||||||
|
|||||||
@ -1,24 +1,30 @@
|
|||||||
import { strictEqual } from 'assert'
|
import { strictEqual, notEqual } from 'assert'
|
||||||
import { rimraf } from 'rimraf'
|
import { rimraf } from 'rimraf'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import OrbitDB from '../src/orbitdb.js'
|
import { createOrbitDB, PasswordEncryption } from '../src/index.js'
|
||||||
// import waitFor from './utils/wait-for.js'
|
// import { encrypt, decrypt, generatePassword } from './utils/encrypt.js'
|
||||||
import connectPeers from './utils/connect-nodes.js'
|
import connectPeers from './utils/connect-nodes.js'
|
||||||
import waitFor from './utils/wait-for.js'
|
import waitFor from './utils/wait-for.js'
|
||||||
// import IPFSAccessController from '../src/access-controllers/ipfs.js'
|
|
||||||
// import OrbitDBAccessController from '../src/access-controllers/orbitdb.js'
|
|
||||||
import createHelia from './utils/create-helia.js'
|
import createHelia from './utils/create-helia.js'
|
||||||
import { encrypt, decrypt, generatePassword } from './utils/encrypt.js'
|
|
||||||
|
import * as Block from 'multiformats/block'
|
||||||
|
import * as dagCbor from '@ipld/dag-cbor'
|
||||||
|
import { sha256 } from 'multiformats/hashes/sha2'
|
||||||
|
|
||||||
|
const codec = dagCbor
|
||||||
|
const hasher = sha256
|
||||||
|
|
||||||
const dbPath = './orbitdb/tests/write-permissions'
|
const dbPath = './orbitdb/tests/write-permissions'
|
||||||
|
|
||||||
describe.only('Encryption/Decryption', function () {
|
describe('Encryption', function () {
|
||||||
this.timeout(5000)
|
this.timeout(5000)
|
||||||
|
|
||||||
let ipfs1, ipfs2
|
let ipfs1, ipfs2
|
||||||
let orbitdb1, orbitdb2
|
let orbitdb1, orbitdb2
|
||||||
let db1, db2
|
let db1, db2
|
||||||
let encryptionPassword
|
|
||||||
|
let replicationEncryption
|
||||||
|
let dataEncryption
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
[ipfs1, ipfs2] = await Promise.all([createHelia(), createHelia()])
|
[ipfs1, ipfs2] = await Promise.all([createHelia(), createHelia()])
|
||||||
@ -26,10 +32,11 @@ describe.only('Encryption/Decryption', function () {
|
|||||||
|
|
||||||
await rimraf('./orbitdb')
|
await rimraf('./orbitdb')
|
||||||
|
|
||||||
orbitdb1 = await OrbitDB({ ipfs: ipfs1, id: 'user1', directory: path.join(dbPath, '1') })
|
orbitdb1 = await createOrbitDB({ ipfs: ipfs1, id: 'user1', directory: path.join(dbPath, '1') })
|
||||||
orbitdb2 = await OrbitDB({ ipfs: ipfs2, id: 'user2', directory: path.join(dbPath, '2') })
|
orbitdb2 = await createOrbitDB({ ipfs: ipfs2, id: 'user2', directory: path.join(dbPath, '2') })
|
||||||
|
|
||||||
encryptionPassword = await generatePassword()
|
replicationEncryption = await PasswordEncryption({ password: 'hello' })
|
||||||
|
dataEncryption = await PasswordEncryption({ password: 'world' })
|
||||||
})
|
})
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
@ -54,90 +61,315 @@ describe.only('Encryption/Decryption', function () {
|
|||||||
await rimraf('./ipfs2')
|
await rimraf('./ipfs2')
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
describe('Data is encrypted when replicated to peers', async () => {
|
||||||
await db1.drop()
|
afterEach(async () => {
|
||||||
await db1.close()
|
if (db1) {
|
||||||
await db2.drop()
|
await db1.drop()
|
||||||
await db2.close()
|
await db1.close()
|
||||||
|
}
|
||||||
|
if (db2) {
|
||||||
|
await db2.drop()
|
||||||
|
await db2.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encrypts/decrypts data', async () => {
|
||||||
|
let connected = false
|
||||||
|
let updated = false
|
||||||
|
let error = false
|
||||||
|
|
||||||
|
const encryption = {
|
||||||
|
data: dataEncryption
|
||||||
|
}
|
||||||
|
|
||||||
|
db1 = await orbitdb1.open('encryption-test-1', { encryption })
|
||||||
|
db2 = await orbitdb2.open(db1.address, { encryption })
|
||||||
|
|
||||||
|
const onJoin = async (peerId, heads) => {
|
||||||
|
connected = true
|
||||||
|
}
|
||||||
|
db2.events.on('join', onJoin)
|
||||||
|
|
||||||
|
await waitFor(() => connected, () => true)
|
||||||
|
|
||||||
|
const onUpdate = async (peerId, heads) => {
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
db2.events.on('update', onUpdate)
|
||||||
|
|
||||||
|
const onError = async (err) => {
|
||||||
|
// Catch "Could not decrypt entry" errors
|
||||||
|
console.log(err)
|
||||||
|
error = true
|
||||||
|
}
|
||||||
|
db2.events.on('error', onError)
|
||||||
|
|
||||||
|
const hash1 = await db1.add('record 1')
|
||||||
|
const hash2 = await db1.add('record 2')
|
||||||
|
|
||||||
|
strictEqual(await db1.get(hash1), 'record 1')
|
||||||
|
strictEqual(await db1.get(hash2), 'record 2')
|
||||||
|
|
||||||
|
await waitFor(() => updated || error, () => true)
|
||||||
|
|
||||||
|
const all = await db2.all()
|
||||||
|
|
||||||
|
strictEqual(all.length, 2)
|
||||||
|
strictEqual(all[0].value, 'record 1')
|
||||||
|
strictEqual(all[1].value, 'record 2')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encrypts/decrypts log', async () => {
|
||||||
|
let connected = false
|
||||||
|
let updated = false
|
||||||
|
let error = false
|
||||||
|
|
||||||
|
const encryption = {
|
||||||
|
replication: replicationEncryption
|
||||||
|
}
|
||||||
|
|
||||||
|
db1 = await orbitdb1.open('encryption-test-1', { encryption })
|
||||||
|
db2 = await orbitdb2.open(db1.address, { encryption })
|
||||||
|
|
||||||
|
const onJoin = async (peerId, heads) => {
|
||||||
|
connected = true
|
||||||
|
}
|
||||||
|
db2.events.on('join', onJoin)
|
||||||
|
|
||||||
|
await waitFor(() => connected, () => true)
|
||||||
|
|
||||||
|
const onUpdate = async (peerId, heads) => {
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
db2.events.on('update', onUpdate)
|
||||||
|
|
||||||
|
const onError = async (err) => {
|
||||||
|
// Catch "Could not decrypt entry" errors
|
||||||
|
console.log(err)
|
||||||
|
error = true
|
||||||
|
}
|
||||||
|
db2.events.on('error', onError)
|
||||||
|
|
||||||
|
const hash1 = await db1.add('record 1')
|
||||||
|
const hash2 = await db1.add('record 2')
|
||||||
|
|
||||||
|
strictEqual(await db1.get(hash1), 'record 1')
|
||||||
|
strictEqual(await db1.get(hash2), 'record 2')
|
||||||
|
|
||||||
|
await waitFor(() => updated || error, () => true)
|
||||||
|
|
||||||
|
const all = await db2.all()
|
||||||
|
|
||||||
|
strictEqual(all.length, 2)
|
||||||
|
strictEqual(all[0].value, 'record 1')
|
||||||
|
strictEqual(all[1].value, 'record 2')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encrypts/decrypts log and data', async () => {
|
||||||
|
let connected = false
|
||||||
|
let updated = false
|
||||||
|
let error = false
|
||||||
|
|
||||||
|
const encryption = {
|
||||||
|
replication: replicationEncryption,
|
||||||
|
data: dataEncryption
|
||||||
|
}
|
||||||
|
|
||||||
|
db1 = await orbitdb1.open('encryption-test-1', { encryption })
|
||||||
|
db2 = await orbitdb2.open(db1.address, { encryption })
|
||||||
|
|
||||||
|
const onJoin = async (peerId, heads) => {
|
||||||
|
connected = true
|
||||||
|
}
|
||||||
|
db2.events.on('join', onJoin)
|
||||||
|
|
||||||
|
await waitFor(() => connected, () => true)
|
||||||
|
|
||||||
|
const onUpdate = async (peerId, heads) => {
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
db2.events.on('update', onUpdate)
|
||||||
|
|
||||||
|
const onError = async (err) => {
|
||||||
|
// Catch "Could not decrypt entry" errors
|
||||||
|
console.log(err)
|
||||||
|
error = true
|
||||||
|
}
|
||||||
|
db2.events.on('error', onError)
|
||||||
|
|
||||||
|
const hash1 = await db1.add('record 1')
|
||||||
|
const hash2 = await db1.add('record 2')
|
||||||
|
|
||||||
|
strictEqual(await db1.get(hash1), 'record 1')
|
||||||
|
strictEqual(await db1.get(hash2), 'record 2')
|
||||||
|
|
||||||
|
await waitFor(() => updated || error, () => true)
|
||||||
|
|
||||||
|
const all = await db2.all()
|
||||||
|
|
||||||
|
strictEqual(all.length, 2)
|
||||||
|
strictEqual(all[0].value, 'record 1')
|
||||||
|
strictEqual(all[1].value, 'record 2')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an error if log can\'t be decrypted', async () => {
|
||||||
|
let connected = false
|
||||||
|
let hasError = false
|
||||||
|
let error
|
||||||
|
|
||||||
|
const replicationEncryptionWithWrongPassword = await PasswordEncryption({ password: 'olleh' })
|
||||||
|
|
||||||
|
const encryption = {
|
||||||
|
replication: replicationEncryption
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptionWithWrongPassword = {
|
||||||
|
replication: replicationEncryptionWithWrongPassword
|
||||||
|
}
|
||||||
|
|
||||||
|
db1 = await orbitdb1.open('encryption-test-1', { encryption })
|
||||||
|
db2 = await orbitdb2.open(db1.address, { encryption: encryptionWithWrongPassword })
|
||||||
|
|
||||||
|
const onJoin = async (peerId, heads) => {
|
||||||
|
connected = true
|
||||||
|
}
|
||||||
|
db2.events.on('join', onJoin)
|
||||||
|
|
||||||
|
await waitFor(() => connected, () => true)
|
||||||
|
|
||||||
|
const onError = async (err) => {
|
||||||
|
// Catch "Could not decrypt entry" errors
|
||||||
|
error = err
|
||||||
|
hasError = true
|
||||||
|
}
|
||||||
|
db2.events.on('error', onError)
|
||||||
|
|
||||||
|
await db1.add('record 1')
|
||||||
|
|
||||||
|
await waitFor(() => hasError, () => true)
|
||||||
|
|
||||||
|
strictEqual(error.message, 'Could not decrypt entry')
|
||||||
|
|
||||||
|
const all = await db2.all()
|
||||||
|
|
||||||
|
strictEqual(all.length, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an error if data can\'t be decrypted', async () => {
|
||||||
|
let connected = false
|
||||||
|
let hasError = false
|
||||||
|
let error
|
||||||
|
|
||||||
|
const dataEncryptionWithWrongPassword = await PasswordEncryption({ password: 'olleh' })
|
||||||
|
|
||||||
|
const encryption = {
|
||||||
|
data: dataEncryption
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptionWithWrongPassword = {
|
||||||
|
data: dataEncryptionWithWrongPassword
|
||||||
|
}
|
||||||
|
|
||||||
|
db1 = await orbitdb1.open('encryption-test-1', { encryption })
|
||||||
|
db2 = await orbitdb2.open(db1.address, { encryption: encryptionWithWrongPassword })
|
||||||
|
|
||||||
|
const onJoin = async (peerId, heads) => {
|
||||||
|
connected = true
|
||||||
|
}
|
||||||
|
db2.events.on('join', onJoin)
|
||||||
|
|
||||||
|
await waitFor(() => connected, () => true)
|
||||||
|
|
||||||
|
const onError = async (err) => {
|
||||||
|
// Catch "Could not decrypt entry" errors
|
||||||
|
error = err
|
||||||
|
hasError = true
|
||||||
|
}
|
||||||
|
db2.events.on('error', onError)
|
||||||
|
|
||||||
|
await db1.add('record 1')
|
||||||
|
|
||||||
|
await waitFor(() => hasError, () => true)
|
||||||
|
|
||||||
|
strictEqual(error.message, 'Could not decrypt payload')
|
||||||
|
|
||||||
|
const all = await db2.all()
|
||||||
|
|
||||||
|
strictEqual(all.length, 0)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('encrypts/decrypts payload', async () => {
|
describe('Data is encrypted in storage', async () => {
|
||||||
const encryptPayloadFn = encrypt({ password: encryptionPassword })
|
afterEach(async () => {
|
||||||
const decryptPayloadFn = decrypt({ password: encryptionPassword })
|
if (db1) {
|
||||||
|
await db1.drop()
|
||||||
|
await db1.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
db1 = await orbitdb1.open('encryption-test-1', { encryption: { encryptPayloadFn, decryptPayloadFn } })
|
it('payload bytes are encrypted in storage', async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
const hash = await db1.add('record 1')
|
const encryption = {
|
||||||
|
data: dataEncryption
|
||||||
|
}
|
||||||
|
|
||||||
for await (const e of db1.log.iterator()) {
|
db1 = await orbitdb1.open('encryption-test-1', { encryption })
|
||||||
console.log('>', e)
|
|
||||||
}
|
|
||||||
|
|
||||||
strictEqual(await db1.get(hash), 'record 1')
|
const onError = async (err) => {
|
||||||
})
|
// Catch "Could not decrypt entry" errors
|
||||||
|
console.log(err)
|
||||||
|
error = true
|
||||||
|
}
|
||||||
|
db1.events.on('error', onError)
|
||||||
|
|
||||||
it('encrypts/decrypts entry', async () => {
|
const hash1 = await db1.add('record 1')
|
||||||
let connected = false
|
|
||||||
let updated = false
|
|
||||||
let error = false
|
|
||||||
|
|
||||||
const encryptPayloadFn = encrypt({ password: encryptionPassword })
|
const bytes = await db1.log.storage.get(hash1)
|
||||||
const decryptPayloadFn = decrypt({ password: encryptionPassword })
|
const { value } = await Block.decode({ bytes, codec, hasher })
|
||||||
|
const payload = value.payload
|
||||||
|
|
||||||
const encryptEntryFn = encrypt({ password: encryptionPassword })
|
strictEqual(payload.constructor, Uint8Array)
|
||||||
const decryptEntryFn = decrypt({ password: encryptionPassword })
|
|
||||||
|
|
||||||
// const decryptPayloadFn2 = encrypt({ password: encryptionPassword + '1' })
|
try {
|
||||||
// const decryptEntryFn2 = decrypt({ password: encryptionPassword + '2' })
|
await Block.decode({ bytes: payload, codec, hasher })
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
db1 = await orbitdb1.open('encryption-test-1', { encryption: { encryptEntryFn, decryptEntryFn, encryptPayloadFn, decryptPayloadFn } })
|
strictEqual(error.message.startsWith('CBOR decode error'), true)
|
||||||
db2 = await orbitdb2.open(db1.address, { encryption: { encryptEntryFn, decryptEntryFn, encryptPayloadFn, decryptPayloadFn } })
|
})
|
||||||
// db1 = await orbitdb1.open('encryption-test-1', { encryption: { encryptEntryFn, decryptEntryFn } })
|
|
||||||
// db2 = await orbitdb2.open(db1.address, { encryption: { encryptEntryFn, decryptEntryFn } })
|
|
||||||
// db1 = await orbitdb1.open('encryption-test-1', { encryption: { encryptPayloadFn, decryptPayloadFn } })
|
|
||||||
// db2 = await orbitdb2.open(db1.address, { encryption: { encryptPayloadFn, decryptPayloadFn } })
|
|
||||||
// db1 = await orbitdb1.open('encryption-test-1')
|
|
||||||
// db2 = await orbitdb2.open(db1.address)
|
|
||||||
|
|
||||||
console.log('connect')
|
it('entry bytes are encrypted in storage', async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
const onJoin = async (peerId, heads) => {
|
const encryption = {
|
||||||
console.log('connected')
|
replication: replicationEncryption
|
||||||
connected = true
|
}
|
||||||
}
|
|
||||||
db2.events.on('join', onJoin)
|
|
||||||
|
|
||||||
await waitFor(() => connected, () => true)
|
db1 = await orbitdb1.open('encryption-test-1', { encryption })
|
||||||
|
|
||||||
const onUpdate = async (peerId, heads) => {
|
const onError = async (err) => {
|
||||||
console.log('updated')
|
// Catch "Could not decrypt entry" errors
|
||||||
updated = true
|
console.log(err)
|
||||||
}
|
error = true
|
||||||
db2.events.on('update', onUpdate)
|
}
|
||||||
|
db1.events.on('error', onError)
|
||||||
|
|
||||||
const onError = async (err) => {
|
const hash1 = await db1.add('record 1')
|
||||||
// Catch "Could not decrypt entry" errors
|
let decodedBytes
|
||||||
console.log(err)
|
|
||||||
error = true
|
|
||||||
}
|
|
||||||
db2.events.on('error', onError)
|
|
||||||
|
|
||||||
console.log('write')
|
try {
|
||||||
const hash1 = await db1.add('record 1')
|
const bytes = await db1.log.storage.get(hash1)
|
||||||
console.log('hash1', hash1)
|
decodedBytes = await Block.decode({ bytes, codec, hasher })
|
||||||
const hash2 = await db1.add('record 2')
|
await Block.decode({ bytes: decodedBytes, codec, hasher })
|
||||||
console.log('hash2', hash2)
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
strictEqual(await db1.get(hash1), 'record 1')
|
notEqual(error, undefined)
|
||||||
strictEqual(await db1.get(hash2), 'record 2')
|
strictEqual(error.message.startsWith('CBOR decode error'), true)
|
||||||
|
strictEqual(decodedBytes.value.constructor, Uint8Array)
|
||||||
await waitFor(() => updated || error, () => true)
|
})
|
||||||
|
|
||||||
const all = await db2.all()
|
|
||||||
console.log('all', all)
|
|
||||||
|
|
||||||
strictEqual(all.length, 2)
|
|
||||||
strictEqual(all[0].value, 'record 1')
|
|
||||||
strictEqual(all[1].value, 'record 2')
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -139,8 +139,7 @@ describe('Sync protocol', function () {
|
|||||||
log1 = await Log(testIdentity1, { logId: 'synclog111', entryStorage: entryStorage1 })
|
log1 = await Log(testIdentity1, { logId: 'synclog111', entryStorage: entryStorage1 })
|
||||||
log2 = await Log(testIdentity2, { logId: 'synclog111', entryStorage: entryStorage2 })
|
log2 = await Log(testIdentity2, { logId: 'synclog111', entryStorage: entryStorage2 })
|
||||||
|
|
||||||
const onSynced = async (bytes) => {
|
const onSynced = async (entry) => {
|
||||||
const entry = await Entry.decode(bytes)
|
|
||||||
if (await log2.joinEntry(entry)) {
|
if (await log2.joinEntry(entry)) {
|
||||||
syncedHead = entry
|
syncedHead = entry
|
||||||
syncedEventFired = true
|
syncedEventFired = true
|
||||||
@ -207,8 +206,7 @@ describe('Sync protocol', function () {
|
|||||||
log1 = await Log(testIdentity1, { logId: 'synclog7', entryStorage: entryStorage1 })
|
log1 = await Log(testIdentity1, { logId: 'synclog7', entryStorage: entryStorage1 })
|
||||||
log2 = await Log(testIdentity2, { logId: 'synclog7', entryStorage: entryStorage2 })
|
log2 = await Log(testIdentity2, { logId: 'synclog7', entryStorage: entryStorage2 })
|
||||||
|
|
||||||
const onSynced = async (bytes) => {
|
const onSynced = async (entry) => {
|
||||||
const entry = await Entry.decode(bytes)
|
|
||||||
if (await log2.joinEntry(entry)) {
|
if (await log2.joinEntry(entry)) {
|
||||||
syncedHead = entry
|
syncedHead = entry
|
||||||
}
|
}
|
||||||
@ -291,8 +289,8 @@ describe('Sync protocol', function () {
|
|||||||
log1 = await Log(testIdentity1, { logId: 'synclog1' })
|
log1 = await Log(testIdentity1, { logId: 'synclog1' })
|
||||||
log2 = await Log(testIdentity2, { logId: 'synclog1' })
|
log2 = await Log(testIdentity2, { logId: 'synclog1' })
|
||||||
|
|
||||||
const onSynced = async (bytes) => {
|
const onSynced = async (entry) => {
|
||||||
syncedHead = await Entry.decode(bytes)
|
syncedHead = entry
|
||||||
syncedEventFired = expectedEntry.hash === syncedHead.hash
|
syncedEventFired = expectedEntry.hash === syncedHead.hash
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,8 +346,8 @@ describe('Sync protocol', function () {
|
|||||||
log1 = await Log(testIdentity1, { logId: 'synclog1' })
|
log1 = await Log(testIdentity1, { logId: 'synclog1' })
|
||||||
log2 = await Log(testIdentity2, { logId: 'synclog1' })
|
log2 = await Log(testIdentity2, { logId: 'synclog1' })
|
||||||
|
|
||||||
const onSynced = async (bytes) => {
|
const onSynced = async (entry) => {
|
||||||
syncedHead = await Entry.decode(bytes)
|
syncedHead = entry
|
||||||
if (expectedEntry) {
|
if (expectedEntry) {
|
||||||
syncedEventFired = expectedEntry.hash === syncedHead.hash
|
syncedEventFired = expectedEntry.hash === syncedHead.hash
|
||||||
}
|
}
|
||||||
@ -434,9 +432,9 @@ describe('Sync protocol', function () {
|
|||||||
log1 = await Log(testIdentity1, { logId: 'synclog1' })
|
log1 = await Log(testIdentity1, { logId: 'synclog1' })
|
||||||
log2 = await Log(testIdentity2, { logId: 'synclog1' })
|
log2 = await Log(testIdentity2, { logId: 'synclog1' })
|
||||||
|
|
||||||
const onSynced = async (bytes) => {
|
const onSynced = async (entry) => {
|
||||||
if (expectedEntry && !syncedEventFired) {
|
if (expectedEntry && !syncedEventFired) {
|
||||||
syncedHead = await Entry.decode(bytes)
|
syncedHead = entry
|
||||||
syncedEventFired = expectedEntry.hash === syncedHead.hash
|
syncedEventFired = expectedEntry.hash === syncedHead.hash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,8 +516,8 @@ describe('Sync protocol', function () {
|
|||||||
log1 = await Log(testIdentity1, { logId: 'synclog2' })
|
log1 = await Log(testIdentity1, { logId: 'synclog2' })
|
||||||
log2 = await Log(testIdentity2, { logId: 'synclog2' })
|
log2 = await Log(testIdentity2, { logId: 'synclog2' })
|
||||||
|
|
||||||
const onSynced = async (bytes) => {
|
const onSynced = async (entry) => {
|
||||||
syncedHead = await Entry.decode(bytes)
|
syncedHead = entry
|
||||||
if (expectedEntry) {
|
if (expectedEntry) {
|
||||||
syncedEventFired = expectedEntry ? expectedEntry.hash === syncedHead.hash : false
|
syncedEventFired = expectedEntry ? expectedEntry.hash === syncedHead.hash : false
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user