orbitdb/test/access-controllers/orbit-db-access-controller-integration.test.js
haad a063b3fb4a Refactor OrbitDB
Fix sync
Fix linter
Fix tests
Clean up
Set default references count to 0
Fix sync
Use address instead of databaseId
Sync protocol
Keep references to open databases in OrbitDB
Fix append benchmark
Initial version of heads exchange
Remove Feed
Fix KeyValuePersisted iterator
Refactor OrbitDBAddress a bit more
Add rest of the database types
Refactor OrbitDB addresses
Initial version for the full circle
Initial structure and tests for new OrbitDB
Make sure KeyStore is open when a Database is created
Re-organize OrbitDB
Use new databases and Log
More clean up
Add 'drop' event to Database
Clean up OrbitDB
Remove id from OrbitDB
Use new KeyStore and Identities
Remove storage from OrbitDB
Remove migrations from OrbitDB
Remove caches from OrbitDB
Remove pubsub from OrbitDB
2023-03-01 16:21:07 +02:00

232 lines
7.5 KiB
JavaScript

import assert from 'assert'
import rmrf from 'rimraf'
import OrbitDB from '../../src/OrbitDB.js'
import IdentityProvider from 'orbit-db-identity-provider'
import Keystore from 'orbit-db-keystore'
import AccessControllers from 'orbit-db-access-controllers'
import * as io from 'orbit-db-io'
// Include test utilities
import {
config,
startIpfs,
stopIpfs,
testAPIs,
connectPeers
} from 'orbit-db-test-utils'
const dbPath1 = './orbitdb/tests/orbitdb-access-controller-integration/1'
const dbPath2 = './orbitdb/tests/orbitdb-access-controller-integration/2'
Object.keys(testAPIs).forEach(API => {
describe(`orbit-db - OrbitDBAccessController Integration (${API})`, function () {
this.timeout(config.timeout)
let ipfsd1, ipfsd2, ipfs1, ipfs2, id1, id2
let orbitdb1, orbitdb2
before(async () => {
rmrf.sync(dbPath1)
rmrf.sync(dbPath2)
ipfsd1 = await startIpfs(API, config.daemon1)
ipfsd2 = await startIpfs(API, config.daemon2)
ipfs1 = ipfsd1.api
ipfs2 = ipfsd2.api
// Connect the peers manually to speed up test times
const isLocalhostAddress = (addr) => addr.toString().includes('127.0.0.1')
await connectPeers(ipfs1, ipfs2, { filter: isLocalhostAddress })
const keystore1 = new Keystore(dbPath1 + '/keys')
const keystore2 = new Keystore(dbPath2 + '/keys')
id1 = await IdentityProvider.createIdentity({ id: 'A', keystore: keystore1 })
id2 = await IdentityProvider.createIdentity({ id: 'B', keystore: keystore2 })
orbitdb1 = await OrbitDB.createInstance(ipfs1, {
AccessControllers,
directory: dbPath1,
identity: id1
})
orbitdb2 = await OrbitDB.createInstance(ipfs2, {
AccessControllers,
directory: dbPath2,
identity: id2
})
})
after(async () => {
if (orbitdb1) {
await orbitdb1.stop()
}
if (orbitdb2) {
await orbitdb2.stop()
}
if (ipfsd1) {
await stopIpfs(ipfsd1)
}
if (ipfsd2) {
await stopIpfs(ipfsd2)
}
})
describe('OrbitDB Integration', function () {
let db, db2
let dbManifest, acManifest
before(async () => {
db = await orbitdb1.feed('AABB', {
identity: id1,
accessController: {
type: 'orbitdb',
write: [id1.id]
}
})
db2 = await orbitdb2.feed(db.address, { identity: id2 })
await db2.load()
dbManifest = await io.read(ipfs1, db.address.root)
const hash = dbManifest.accessController.split('/').pop()
acManifest = await io.read(ipfs1, hash)
})
it('has the correct access rights after creating the database', async () => {
assert.deepStrictEqual(db.access.capabilities, {
admin: new Set([id1.id]),
write: new Set([id1.id])
})
})
it('makes database use the correct access controller', async () => {
assert.strictEqual(acManifest.params.address, db.access._db.address.toString())
})
it('saves database manifest file locally', async () => {
assert.notStrictEqual(dbManifest, null)
})
it('saves access controller manifest file locally', async () => {
assert.notStrictEqual(acManifest, null)
})
describe('database manifest', () => {
it('has correct name', async () => {
assert.strictEqual(dbManifest.name, 'AABB')
})
it('has correct type', async () => {
assert.strictEqual(dbManifest.type, 'feed')
})
it('has correct address', async () => {
assert.notStrictEqual(dbManifest.accessController, null)
assert.strictEqual(dbManifest.accessController.indexOf('/ipfs'), 0)
})
})
describe('access controller manifest', () => {
it('has correct type', async () => {
assert.strictEqual(acManifest.type, 'orbitdb')
})
it('has correct address', async () => {
assert.strictEqual(acManifest.params.address.indexOf('/orbitdb'), 0)
assert.strictEqual(acManifest.params.address.split('/').pop(), '_access')
})
})
describe('access controls', () => {
it('granting access enables to write to the database', async () => {
let err
try {
await db2.add('hello?')
assert.strictEqual('Should not end here', false)
} catch (e) {
err = e.toString()
}
assert.strictEqual(err, `Error: Could not append entry, key "${db2.identity.id}" is not allowed to write to the log`)
const doChanges = () => {
return new Promise((resolve, reject) => {
try {
// Wait for the second user's AC to notify it was updated
db2.access.once('updated', async () => {
// Wait for the first user's db to replicate the update
db.events.once('replicated', () => {
// FIXME: timeout to get rid of the "libp2p node not started yet" errors
setTimeout(() => resolve(), 1000)
})
// Try adding something again
await db2.add('hello!')
})
// Give access to the second user
db.access.grant('write', id2.id)
} catch (e) {
reject(e)
}
})
}
await doChanges()
const res1 = await db.iterator().collect().map(e => e.payload.value)
const res2 = await db2.iterator().collect().map(e => e.payload.value)
assert.deepStrictEqual(res1, ['hello!'])
assert.deepStrictEqual(res2, ['hello!'])
})
it('can\'t grant access if doesn\'t have write access', async () => {
let err
try {
await db2.access.grant('write', id2.id)
} catch (e) {
err = e.toString()
}
assert.strictEqual(err, `Error: Could not append entry, key "${db2.identity.id}" is not allowed to write to the log`)
})
it('can\'t revoke access if doesn\'t have write access', async () => {
let err
try {
await db2.access.revoke('write', id1.id)
} catch (e) {
err = e.toString()
}
assert.strictEqual(err, `Error: Could not append entry, key "${db2.identity.id}" is not allowed to write to the log`)
})
it('revoking access disables ability to write to the database', async () => {
const getError = () => {
return new Promise((resolve, reject) => {
try {
// Wait for the second user's AC to notify it was updated
db2.access.once('updated', async () => {
let err
try {
// Try adding something again
await db2.add('hello?')
} catch (e) {
err = e.toString()
}
resolve(err)
})
// Revoke user's access
db.access.revoke('write', id2.id)
} catch (e) {
reject(e)
}
})
}
const err = await getError()
assert.strictEqual(err, `Error: Could not append entry, key "${db2.identity.id}" is not allowed to write to the log`)
})
})
})
})
// TODO: use two separate peers for testing the AC
// TODO: add tests for revocation correctness with a database (integration tests)
})