feat: Pass encrypt configuration as a hierarchical list of params.

This commit is contained in:
Hayden Young 2024-05-22 17:05:51 +01:00
parent ac3011c873
commit 90f66cfe5d
10 changed files with 65 additions and 55 deletions

View File

@ -44,7 +44,7 @@ const defaultCacheSize = 1000
* @return {module:Databases~Database} An instance of Database.
* @instance
*/
const Database = async ({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, encryptFn, decryptFn }) => {
const Database = async ({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate }) => {
/**
* @namespace module:Databases~Database
* @description The instance returned by {@link module:Database~Database}.
@ -110,7 +110,7 @@ const Database = async ({ ipfs, identity, address, name, access, directory, meta
await LevelStorage({ path: pathJoin(directory, '/log/_index/') })
)
const log = await Log(identity, { logId: address, access, entryStorage, headsStorage, indexStorage, encryptFn, decryptFn })
const log = await Log(identity, { logId: address, access, entryStorage, headsStorage, indexStorage })
const events = new EventEmitter()

View File

@ -25,8 +25,8 @@ const DefaultOptions = { indexBy: '_id' }
* @return {module:Databases.Databases-Documents} A Documents function.
* @memberof module:Databases
*/
const Documents = ({ indexBy } = DefaultOptions) => async ({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, encryptFn, decryptFn }) => {
const database = await Database({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, encryptFn, decryptFn })
const Documents = ({ indexBy } = DefaultOptions) => async ({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, encrypt }) => {
const database = await Database({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically })
const { addOperation, log } = database

View File

@ -7,8 +7,7 @@
* @augments module:Databases~Database
*/
import Database from '../database.js'
import { Operation } from './utils/operation.js'
import { Payload } from './utils/payload.js'
import { toPayload, fromPayload } from './utils/payload.js'
const type = 'events'
@ -17,8 +16,8 @@ const type = 'events'
* @return {module:Databases.Databases-Events} A Events function.
* @memberof module:Databases
*/
const Events = () => async ({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, encryptFn, decryptFn }) => {
const database = await Database({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, encryptFn, decryptFn })
const Events = () => async ({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, encrypt }) => {
const database = await Database({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate })
const { addOperation, log } = database
@ -31,8 +30,8 @@ const Events = () => async ({ ipfs, identity, address, name, access, directory,
* @instance
*/
const add = async (value) => {
const op = await Operation('ADD', null, value, { encryptFn, encryptValue: true, encryptOp: false })
return addOperation(op)
const payload = await toPayload('ADD', null, value, { encrypt })
return addOperation(payload)
}
/**
@ -45,7 +44,7 @@ const Events = () => async ({ ipfs, identity, address, name, access, directory,
*/
const get = async (hash) => {
const entry = await log.get(hash)
const { value } = await Payload(entry.payload, { decryptFn, decryptValue: true, decryptOp: false })
const { value } = await fromPayload(entry.payload, { encrypt })
return value
}
@ -71,7 +70,8 @@ const Events = () => async ({ ipfs, identity, address, name, access, directory,
const it = log.iterator({ gt, gte, lt, lte, amount })
for await (const event of it) {
const hash = event.hash
const value = event.payload.value
const payload = await fromPayload(event.payload, { encrypt })
const value = payload.value
yield { hash, value }
}
}

View File

@ -109,7 +109,7 @@ const Index = ({ directory } = {}) => async () => {
* function.
* @memberof module:Databases
*/
const KeyValueIndexed = () => async ({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, encryptFn, decryptFn }) => {
const KeyValueIndexed = () => async ({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate }) => {
// Set up the directory for an index
directory = pathJoin(directory || './orbitdb', `./${address}/_index/`)
@ -117,7 +117,7 @@ const KeyValueIndexed = () => async ({ ipfs, identity, address, name, access, di
const index = await Index({ directory })()
// Set up the underlying KeyValue database
const keyValueStore = await KeyValue()({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate: index.update, encryptFn, decryptFn })
const keyValueStore = await KeyValue()({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate: index.update })
/**
* Gets a value from the store by key.

View File

@ -16,7 +16,7 @@ const type = 'keyvalue'
* @memberof module:Databases
*/
const KeyValue = () => async ({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, encryptFn, decryptFn }) => {
const database = await Database({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate, encryptFn, decryptFn })
const database = await Database({ ipfs, identity, address, name, access, directory, meta, headsStorage, entryStorage, indexStorage, referencesCount, syncAutomatically, onUpdate })
const { addOperation, log } = database

View File

@ -1,15 +0,0 @@
export const Operation = async (op, key, value, { encryptFn, encryptValue, encryptOp } = {}) => {
let operation = { op, key, value }
if (encryptFn) {
if (encryptValue) {
operation.value = await encryptFn(value)
}
if (encryptOp) {
operation = await encryptFn(JSON.stringify(operation))
}
}
return operation
}

View File

@ -1,11 +1,30 @@
export const Payload = async (payload, { decryptFn, decryptValue, decryptOp }) => {
if (decryptFn) {
if (decryptOp) {
payload = JSON.parse(await decryptFn(payload))
/**
*/
const toPayload = async (op, key, value, { encrypt }) => {
let payload = { op, key, value }
if (encrypt) {
if (encrypt.data) {
payload.value = await encrypt.data.encryptFn(value)
}
if (decryptValue) {
payload.value = await decryptFn(payload.value)
if (encrypt.op) {
payload = await encrypt.op.encryptFn(JSON.stringify(payload))
}
}
return payload
}
const fromPayload = async (payload, { encrypt }) => {
if (encrypt) {
if (encrypt.op) {
payload = JSON.parse(await encrypt.op.decryptFn(payload))
}
if (encrypt.data) {
payload.value = await encrypt.data.decryptFn(payload.value)
}
}
@ -13,3 +32,8 @@ export const Payload = async (payload, { decryptFn, decryptValue, decryptOp }) =
return { op, key, value }
}
export {
toPayload,
fromPayload
}

View File

@ -104,6 +104,7 @@ const OrbitDB = async ({ ipfs, id, identity, identities, directory } = {}) => {
* @param {module:Storage} [params.indexStorage=[ComposedStorage]{@link module:Storage.Storage-Composed}] A compatible storage instance for storing an " index of log entries. Defaults to ComposedStorage(LRUStorage, LevelStorage).
* @param {number} [params.referencesCount] The number of references to
* use for [Log]{@link module:Log} entries.
* @param {number} [params.encrypt] Options for encrypting database operations and entries. If provided, the encrypt object must take the form { data: { encryptFn, decryptFn }, op: { encryptFn, decryptFn } }. To encrypt the operation data value only, pass the "data" option. To encrypt the op, pass the "op" option. To encrypt "data" and "op", pass both options.
* @memberof module:OrbitDB
* @return {module:Database} A database instance.
* @throws "Unsupported database type" if the type specified is not in the list
@ -112,7 +113,7 @@ const OrbitDB = async ({ ipfs, id, identity, identities, directory } = {}) => {
* @instance
* @async
*/
const open = async (address, { type, meta, sync, Database, AccessController, headsStorage, entryStorage, indexStorage, referencesCount, encryptFn, decryptFn } = {}) => {
const open = async (address, { type, meta, sync, Database, AccessController, headsStorage, entryStorage, indexStorage, referencesCount, encrypt } = {}) => {
let name, manifest, accessController
if (databases[address]) {
@ -153,7 +154,7 @@ const OrbitDB = async ({ ipfs, id, identity, identities, directory } = {}) => {
address = address.toString()
const db = await Database({ ipfs, identity, address, name, access: accessController, directory, meta, syncAutomatically: sync, headsStorage, entryStorage, indexStorage, referencesCount, encryptFn, decryptFn })
const db = await Database({ ipfs, identity, address, name, access: accessController, directory, meta, syncAutomatically: sync, headsStorage, entryStorage, indexStorage, referencesCount, encrypt })
db.events.on('close', onDatabaseClosed(address))

View File

@ -3,7 +3,6 @@ import { rimraf } from 'rimraf'
import { copy } from 'fs-extra'
import { Log, Entry, Identities, KeyStore, MemoryStorage } from '../../src/index.js'
import testKeysPath from '../fixtures/test-keys-path.js'
import { encrypt, decrypt } from '../utils/encrypt.js'
const { create } = Entry
@ -143,19 +142,5 @@ describe('Log', function () {
strictEqual(values[1].payload, 'hello2')
strictEqual(values[2].payload, 'hello3')
})
it('encrypts the value of an entry in the log', async () => {
const keys = await keystore.createKey('hello1')
const privateKey = await keystore.getKey('hello1')
const publicKey = await keystore.getPublic(keys)
const encryptFn = encrypt({ publicKey })
const decryptFn = decrypt({ privateKey })
const log = await Log(testIdentity, { encryptFn, decryptFn })
const entry = await log.append('hello1')
const value = await log.get(entry.hash)
strictEqual(value.payload, 'hello1')
})
})
})

View File

@ -56,7 +56,7 @@ describe('Encryption/Decryption', function () {
// await db2.close()
})
it('can encrypt/decrypt data', async () => {
it('encrypts/decrypts data', async () => {
const keystore = orbitdb1.keystore
const keys = await keystore.createKey('encryption-test')
@ -65,7 +65,22 @@ describe('Encryption/Decryption', function () {
const encryptFn = encrypt({ publicKey })
const decryptFn = decrypt({ privateKey })
db1 = await orbitdb1.open('encryption-test-1', { encryptFn, decryptFn })
db1 = await orbitdb1.open('encryption-test-1', { encrypt: { data: { encryptFn, decryptFn } } })
const hash = await db1.add('record 1')
strictEqual(await db1.get(hash), 'record 1')
})
it('encrypts/decrypts op', async () => {
const keystore = orbitdb1.keystore
const keys = await keystore.createKey('encryption-test')
const privateKey = await keystore.getKey('encryption-test')
const publicKey = await keystore.getPublic(keys)
const encryptFn = encrypt({ publicKey })
const decryptFn = decrypt({ privateKey })
db1 = await orbitdb1.open('encryption-test-1', { encrypt: { op: { encryptFn, decryptFn } } })
const hash = await db1.add('record 1')
strictEqual(await db1.get(hash), 'record 1')