From 5032415e0191bc87feef833f574756b9c1d08739 Mon Sep 17 00:00:00 2001 From: haad Date: Sat, 29 Jul 2023 08:41:13 +0300 Subject: [PATCH] Fix OrbitDBAccessController address and return values --- src/access-controllers/orbitdb.js | 22 +++++--- src/database.js | 6 +++ src/orbitdb.js | 5 +- src/utils/ensure-ac-address.js | 8 --- test/orbitdb-write-access.test.js | 85 +++++++++++++++++++++++++++++-- 5 files changed, 105 insertions(+), 21 deletions(-) delete mode 100644 src/utils/ensure-ac-address.js diff --git a/src/access-controllers/orbitdb.js b/src/access-controllers/orbitdb.js index baf62ca..1bb108b 100644 --- a/src/access-controllers/orbitdb.js +++ b/src/access-controllers/orbitdb.js @@ -2,8 +2,8 @@ * @namespace AccessControllers-OrbitDB * @memberof module:AccessControllers */ -import ensureACAddress from '../utils/ensure-ac-address.js' import IPFSAccessController from './ipfs.js' +import { createId } from '../utils/index.js' const type = 'orbitdb' @@ -32,12 +32,12 @@ const type = 'orbitdb' * IPFSAccessController function. * @memberof module:AccessControllers */ -const OrbitDBAccessController = ({ write } = {}) => async ({ orbitdb, identities, address }) => { - address = address || 'default-access-controller' +const OrbitDBAccessController = ({ write } = {}) => async ({ orbitdb, identities, address, name }) => { + address = address || name || await createId(64) write = write || [orbitdb.identity.id] - // Force '
/_access' naming for the database - const db = await orbitdb.open(ensureACAddress(address), { type: 'keyvalue', AccessController: IPFSAccessController({ write }) }) + // Open the database used for access information + const db = await orbitdb.open(address, { type: 'keyvalue', AccessController: IPFSAccessController({ write }) }) address = db.address /** @@ -90,7 +90,7 @@ const OrbitDBAccessController = ({ write } = {}) => async ({ orbitdb, identities ..._capabilities, // Add the root access controller's 'write' access list // as admins on this controller - ...{ admin: new Set([...(_capabilities.admin || []), ...write]) } + ...{ admin: new Set([...(_capabilities.admin || []), ...db.access.write]) } }).forEach(toSet) return _capabilities @@ -117,6 +117,15 @@ const OrbitDBAccessController = ({ write } = {}) => async ({ orbitdb, identities 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). @@ -174,6 +183,7 @@ const OrbitDBAccessController = ({ write } = {}) => async ({ orbitdb, identities grant, revoke, close, + drop, events: db.events } } diff --git a/src/database.js b/src/database.js index ef4196a..6496a5c 100644 --- a/src/database.js +++ b/src/database.js @@ -164,6 +164,9 @@ const Database = async ({ ipfs, identity, address, name, access, directory, meta await sync.stop() await queue.onIdle() await log.close() + if (access && access.close) { + await access.close() + } events.emit('close') } @@ -176,6 +179,9 @@ const Database = async ({ ipfs, identity, address, name, access, directory, meta const drop = async () => { await queue.onIdle() await log.clear() + if (access && access.drop) { + await access.drop() + } events.emit('drop') } diff --git a/src/orbitdb.js b/src/orbitdb.js index b1a1f81..1df7d36 100644 --- a/src/orbitdb.js +++ b/src/orbitdb.js @@ -116,9 +116,8 @@ const OrbitDB = async ({ ipfs, id, identities, directory } = {}) => { const addr = OrbitDBAddress(address) manifest = await manifestStore.get(addr.hash) const acType = manifest.accessController.split('/', 2).pop() - const acAddress = manifest.accessController.replaceAll(`/${acType}/`, '') AccessController = getAccessController(acType)() - accessController = await AccessController({ orbitdb: { open, identity, ipfs }, identities, address: acAddress }) + accessController = await AccessController({ orbitdb: { open, identity, ipfs }, identities, address: manifest.accessController }) name = manifest.name type = type || manifest.type meta = manifest.meta @@ -126,7 +125,7 @@ const OrbitDB = async ({ ipfs, id, identities, directory } = {}) => { // If the address given was not valid, eg. just the name of the database type = type || DefaultDatabaseType AccessController = AccessController || DefaultAccessController() - accessController = await AccessController({ orbitdb: { open, identity, ipfs }, identities }) + accessController = await AccessController({ orbitdb: { open, identity, ipfs }, identities, name: address }) const m = await manifestStore.create({ name: address, type, accessController: accessController.address, meta }) manifest = m.manifest address = OrbitDBAddress(m.hash) diff --git a/src/utils/ensure-ac-address.js b/src/utils/ensure-ac-address.js deleted file mode 100644 index 6602a48..0000000 --- a/src/utils/ensure-ac-address.js +++ /dev/null @@ -1,8 +0,0 @@ -import pathJoin from './path-join.js' - -export default address => { - const suffix = address.toString().split('/').pop() - return suffix === '_access' - ? address - : pathJoin(address, '/_access') -} diff --git a/test/orbitdb-write-access.test.js b/test/orbitdb-write-access.test.js index 3fd61db..72cb229 100644 --- a/test/orbitdb-write-access.test.js +++ b/test/orbitdb-write-access.test.js @@ -1,4 +1,4 @@ -import { strictEqual } from 'assert' +import { strictEqual, notStrictEqual } from 'assert' import rmrf from 'rimraf' import path from 'path' import * as IPFS from 'ipfs-core' @@ -185,7 +185,7 @@ describe('Write Permissions', function () { await db2.close() }) - it('uses an OrbitDB access controller to manage access', async () => { + it('uses an OrbitDB access controller to manage access - one writer', async () => { let connected = false let updateCount = 0 @@ -198,7 +198,48 @@ describe('Write Permissions', function () { } const db1 = await orbitdb1.open('write-test', { AccessController: OrbitDBAccessController() }) - const db2 = await orbitdb2.open(db1.address, { AccessController: OrbitDBAccessController() }) + const db2 = await orbitdb2.open(db1.address) + + db2.events.on('join', onConnected) + db2.events.on('update', onUpdate) + + await waitFor(() => connected, () => true) + + await db1.add('record 1') + + let err + + try { + await db2.add('record 2') + } catch (e) { + err = e + } + + await waitFor(() => updateCount === 1, () => true) + + strictEqual((await db1.all()).length, (await db2.all()).length) + + notStrictEqual(err, undefined) + strictEqual(err.toString().endsWith('is not allowed to write to the log'), true) + + await db1.close() + await db2.close() + }) + + it('uses an OrbitDB access controller to manage access - two writers', async () => { + let connected = false + let updateCount = 0 + + const onConnected = async (peerId, heads) => { + connected = true + } + + const onUpdate = async (entry) => { + ++updateCount + } + + const db1 = await orbitdb1.open('write-test', { AccessController: OrbitDBAccessController() }) + const db2 = await orbitdb2.open(db1.address) db2.events.on('join', onConnected) db2.events.on('update', onUpdate) @@ -206,7 +247,6 @@ describe('Write Permissions', function () { await waitFor(() => connected, () => true) await db1.access.grant('write', db2.identity.id) - await db2.access.grant('write', db1.identity.id) await db1.add('record 1') await db2.add('record 2') @@ -218,4 +258,41 @@ describe('Write Permissions', function () { await db1.close() await db2.close() }) + + it('OrbitDB access controller address is deterministic', async () => { + let connected = false + let updateCount = 0 + + const onConnected = async (peerId, heads) => { + connected = true + } + + const onUpdate = async (entry) => { + ++updateCount + } + + let db1 = await orbitdb1.open('write-test', { AccessController: OrbitDBAccessController() }) + let db2 = await orbitdb2.open(db1.address) + + const addr = db1.address + + db2.events.on('join', onConnected) + db2.events.on('update', onUpdate) + + await waitFor(() => connected, () => true) + + await db1.add('record 1') + + await waitFor(() => updateCount === 1, () => true) + + strictEqual((await db1.all()).length, (await db2.all()).length) + + await db1.close() + await db2.close() + + db1 = await orbitdb1.open('write-test', { AccessController: OrbitDBAccessController() }) + db2 = await orbitdb2.open(db1.address) + + strictEqual(db1.address, addr) + }) })