UNPKG

@orbitdb/core

Version:

Distributed p2p database on IPFS

194 lines (173 loc) 5.95 kB
/** * @namespace AccessControllers-OrbitDB * @memberof module:AccessControllers */ import IPFSAccessController from './ipfs.js' import { createId } from '../utils/index.js' const type = 'orbitdb' /** * Creates an instance of OrbitDBAccessController. * @callback OrbitDBAccessController * @param {Object} params Various parameters for configuring the access * controller. * @param {module:OrbitDB} params.orbitdb An OrbitDB instance. * @param {module:Identities} params.identities An Identities instance. * @param {string} [params.address] The address of the database. * @function * @instance * @async * @memberof module:AccessControllers.AccessControllers-OrbitDB * @private */ /** * Defines an OrbitDB access controller. * @param {Object} options Various options for configuring the * IPFSAccessController. * @param {Array} [params.write] An array of ids of identities who can write to the * database. * @return {module:AccessControllers.AccessControllers-OrbitDB} An * IPFSAccessController function. * @memberof module:AccessControllers */ const OrbitDBAccessController = ({ write } = {}) => async ({ orbitdb, identities, address, name }) => { address = address || name || await createId(64) write = write || [orbitdb.identity.id] // Open the database used for access information const db = await orbitdb.open(address, { type: 'keyvalue', AccessController: IPFSAccessController({ write }) }) address = db.address /** * Verifies the write permission of an entry. * @param {module:Log~Entry} entry An entry to verify. * @return {boolean} True if the entry's identity has write permission, * false otherwise. * @memberof module:AccessControllers.AccessControllers-OrbitDB * @instance */ const canAppend = async (entry) => { const writerIdentity = await identities.getIdentity(entry.identity) if (!writerIdentity) { return false } const { id } = writerIdentity // If the ACL contains the writer's public key or it contains '*' const hasWriteAccess = await hasCapability('write', id) || await hasCapability('admin', id) if (hasWriteAccess) { return await identities.verifyIdentity(writerIdentity) } return false } /** * Gets the access capabilities of the OrbitDB access controller. * * The returned capabilities will be a mixture of admin and write access * addresses. * @return {Array} A list of ids of identities with admin and write access. * @memberof module:AccessControllers.AccessControllers-OrbitDB * @instance */ const capabilities = async () => { const _capabilities = [] for await (const entry of db.iterator()) { _capabilities[entry.key] = entry.value } const toSet = (e) => { const key = e[0] _capabilities[key] = new Set([...(_capabilities[key] || []), ...e[1]]) } // Merge with the access controller of the database // and make sure all values are Sets Object.entries({ ..._capabilities, // Add the root access controller's 'write' access list // as admins on this controller ...{ admin: new Set([...(_capabilities.admin || []), ...db.access.write]) } }).forEach(toSet) return _capabilities } /** * Gets a list of identities with the specified capability. * @param {string} capability A capability (e.g. write). * @return {Array} One or more addresses with the spcified capability. * @memberof module:AccessControllers.AccessControllers-OrbitDB * @instance */ const get = async (capability) => { const _capabilities = await capabilities() return _capabilities[capability] || new Set([]) } /** * Close the underlying access control database. * @memberof module:AccessControllers.AccessControllers-OrbitDB * @instance */ const close = async () => { await db.close() } /** * Drop the underlying access control database. * @memberof module:AccessControllers.AccessControllers-OrbitDB * @instance */ const drop = async () => { await db.drop() } /** * Checks whether an identity has a capability. * @param {string} capability A capability (e.g. write). * @param {string} key An id of an identity. * @return {boolean} True if the identity has the capability, false * otherwise. * @memberof module:AccessControllers.AccessControllers-OrbitDB * @instance */ const hasCapability = async (capability, key) => { // Write keys and admins keys are allowed const access = new Set(await get(capability)) return access.has(key) || access.has('*') } /** * Grants a capability to an identity, storing it to the access control * database. * @param {string} capability A capability (e.g. write). * @param {string} key An id of an identity. * @memberof module:AccessControllers.AccessControllers-OrbitDB * @instance */ const grant = async (capability, key) => { // Merge current keys with the new key const capabilities = new Set([...(await db.get(capability) || []), ...[key]]) await db.put(capability, Array.from(capabilities.values())) } /** * Revokes a capability from an identity, removing it from the access control * database. * @param {string} capability A capability (e.g. write). * @param {string} key An id of an identity. * @memberof module:AccessControllers.AccessControllers-OrbitDB * @instance */ const revoke = async (capability, key) => { const capabilities = new Set(await db.get(capability) || []) capabilities.delete(key) if (capabilities.size > 0) { await db.put(capability, Array.from(capabilities.values())) } else { await db.del(capability) } } return { type, address, write, canAppend, capabilities, get, grant, revoke, close, drop, events: db.events } } OrbitDBAccessController.type = type export default OrbitDBAccessController