mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-03-30 15:08:28 +00:00

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
337 lines
11 KiB
JavaScript
337 lines
11 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 OrbitDBAccessController from 'orbit-db-access-controllers/orbitdb'
|
|
import AccessControllers from 'orbit-db-access-controllers'
|
|
|
|
// Include test utilities
|
|
import {
|
|
config,
|
|
startIpfs,
|
|
stopIpfs,
|
|
testAPIs
|
|
} from 'orbit-db-test-utils'
|
|
|
|
const dbPath1 = './orbitdb/tests/orbitdb-access-controller/1'
|
|
const dbPath2 = './orbitdb/tests/orbitdb-access-controller/2'
|
|
|
|
Object.keys(testAPIs).forEach(API => {
|
|
describe(`orbit-db - OrbitDBAccessController (${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
|
|
|
|
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('Constructor', function () {
|
|
let accessController
|
|
|
|
before(async () => {
|
|
accessController = await OrbitDBAccessController.create(orbitdb1)
|
|
})
|
|
|
|
it('creates an access controller', () => {
|
|
assert.notStrictEqual(accessController, null)
|
|
assert.notStrictEqual(accessController, undefined)
|
|
})
|
|
|
|
it('sets the controller type', () => {
|
|
assert.strictEqual(accessController.type, 'orbitdb')
|
|
})
|
|
|
|
it('has OrbitDB instance', async () => {
|
|
assert.notStrictEqual(accessController._orbitdb, null)
|
|
assert.strictEqual(accessController._orbitdb.id, orbitdb1.id)
|
|
})
|
|
|
|
it('has IPFS instance', async () => {
|
|
const peerId1 = await accessController._orbitdb._ipfs.id()
|
|
const peerId2 = await ipfs1.id()
|
|
assert.strictEqual(String(peerId1.id), String(peerId2.id))
|
|
})
|
|
|
|
it('sets default capabilities', async () => {
|
|
assert.deepStrictEqual(accessController.capabilities, {
|
|
admin: new Set([id1.id])
|
|
})
|
|
})
|
|
|
|
it('allows owner to append after creation', async () => {
|
|
const mockEntry = {
|
|
identity: id1
|
|
// ...
|
|
// doesn't matter what we put here, only identity is used for the check
|
|
}
|
|
const canAppend = await accessController.canAppend(mockEntry, id1.provider)
|
|
assert.strictEqual(canAppend, true)
|
|
})
|
|
})
|
|
|
|
describe('grant', function () {
|
|
let accessController
|
|
|
|
before(async () => {
|
|
accessController = new OrbitDBAccessController(orbitdb1)
|
|
await accessController.load('testdb/add')
|
|
})
|
|
|
|
it('loads the root access controller from IPFS', () => {
|
|
assert.strictEqual(accessController._db.access.type, 'ipfs')
|
|
assert.deepStrictEqual(accessController._db.access.write, [id1.id])
|
|
})
|
|
|
|
it('adds a capability', async () => {
|
|
try {
|
|
await accessController.grant('write', id1.id)
|
|
} catch (e) {
|
|
assert(e, null)
|
|
}
|
|
assert.deepStrictEqual(accessController.capabilities, {
|
|
admin: new Set([id1.id]),
|
|
write: new Set([id1.id])
|
|
})
|
|
})
|
|
|
|
it('adds more capabilities', async () => {
|
|
try {
|
|
await accessController.grant('read', 'ABCD')
|
|
await accessController.grant('delete', 'ABCD')
|
|
} catch (e) {
|
|
assert.strictEqual(e, null)
|
|
}
|
|
assert.deepStrictEqual(accessController.capabilities, {
|
|
admin: new Set([id1.id]),
|
|
write: new Set([id1.id]),
|
|
read: new Set(['ABCD']),
|
|
delete: new Set(['ABCD'])
|
|
})
|
|
})
|
|
|
|
it('emit \'updated\' event when a capability was added', async () => {
|
|
return new Promise((resolve, reject) => {
|
|
accessController.on('updated', () => {
|
|
try {
|
|
assert.deepStrictEqual(accessController.capabilities, {
|
|
admin: new Set([id1.id]),
|
|
write: new Set([id1.id]),
|
|
read: new Set(['ABCD', 'AXES']),
|
|
delete: new Set(['ABCD'])
|
|
})
|
|
resolve()
|
|
} catch (e) {
|
|
reject(e)
|
|
}
|
|
})
|
|
accessController.grant('read', 'AXES')
|
|
})
|
|
})
|
|
|
|
it('can append after acquiring capability', async () => {
|
|
try {
|
|
await accessController.grant('write', id1.id)
|
|
await accessController.grant('write', id2.id)
|
|
} catch (e) {
|
|
assert(e, null)
|
|
}
|
|
const mockEntry1 = {
|
|
identity: id1
|
|
}
|
|
const mockEntry2 = {
|
|
identity: id2
|
|
}
|
|
const canAppend1 = await accessController.canAppend(mockEntry1, id1.provider)
|
|
const canAppend2 = await accessController.canAppend(mockEntry2, id2.provider)
|
|
assert.strictEqual(canAppend1, true)
|
|
assert.strictEqual(canAppend2, true)
|
|
})
|
|
})
|
|
|
|
describe('revoke', function () {
|
|
let accessController
|
|
|
|
before(async () => {
|
|
accessController = new OrbitDBAccessController(orbitdb1)
|
|
await accessController.load('testdb/remove')
|
|
})
|
|
|
|
it('removes a capability', async () => {
|
|
try {
|
|
await accessController.grant('write', id1.id)
|
|
await accessController.grant('write', 'AABB')
|
|
await accessController.revoke('write', 'AABB')
|
|
} catch (e) {
|
|
assert.strictEqual(e, null)
|
|
}
|
|
assert.deepStrictEqual(accessController.capabilities, {
|
|
admin: new Set([id1.id]),
|
|
write: new Set([id1.id])
|
|
})
|
|
})
|
|
|
|
it('can remove the creator\'s write access', async () => {
|
|
try {
|
|
await accessController.revoke('write', id1.id)
|
|
} catch (e) {
|
|
assert.strictEqual(e, null)
|
|
}
|
|
assert.deepStrictEqual(accessController.capabilities, {
|
|
admin: new Set([id1.id])
|
|
})
|
|
})
|
|
|
|
it('can\'t remove the creator\'s admin access', async () => {
|
|
try {
|
|
await accessController.revoke('admin', id1.id)
|
|
} catch (e) {
|
|
assert.strictEqual(e, null)
|
|
}
|
|
assert.deepStrictEqual(accessController.capabilities, {
|
|
admin: new Set([id1.id])
|
|
})
|
|
})
|
|
|
|
it('removes more capabilities', async () => {
|
|
try {
|
|
await accessController.grant('read', 'ABCD')
|
|
await accessController.grant('delete', 'ABCD')
|
|
await accessController.grant('write', id1.id)
|
|
await accessController.revoke('read', 'ABCDE')
|
|
await accessController.revoke('delete', 'ABCDE')
|
|
} catch (e) {
|
|
assert.strictEqual(e, null)
|
|
}
|
|
assert.deepStrictEqual(accessController.capabilities, {
|
|
admin: new Set([id1.id]),
|
|
delete: new Set(['ABCD']),
|
|
read: new Set(['ABCD']),
|
|
write: new Set([id1.id])
|
|
})
|
|
})
|
|
|
|
it('can\'t append after revoking capability', async () => {
|
|
try {
|
|
await accessController.grant('write', id2.id)
|
|
await accessController.revoke('write', id2.id)
|
|
} catch (e) {
|
|
assert(e, null)
|
|
}
|
|
const mockEntry1 = {
|
|
identity: id1
|
|
}
|
|
const mockEntry2 = {
|
|
identity: id2
|
|
}
|
|
const canAppend = await accessController.canAppend(mockEntry1, id1.provider)
|
|
const noAppend = await accessController.canAppend(mockEntry2, id2.provider)
|
|
assert.strictEqual(canAppend, true)
|
|
assert.strictEqual(noAppend, false)
|
|
})
|
|
|
|
it('emits \'updated\' event when a capability was removed', async () => {
|
|
await accessController.grant('admin', 'cats')
|
|
await accessController.grant('admin', 'dogs')
|
|
|
|
return new Promise((resolve, reject) => {
|
|
accessController.on('updated', () => {
|
|
try {
|
|
assert.deepStrictEqual(accessController.capabilities, {
|
|
admin: new Set([id1.id, 'dogs']),
|
|
delete: new Set(['ABCD']),
|
|
read: new Set(['ABCD']),
|
|
write: new Set([id1.id])
|
|
})
|
|
resolve()
|
|
} catch (e) {
|
|
reject(e)
|
|
}
|
|
})
|
|
accessController.revoke('admin', 'cats')
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('save and load', function () {
|
|
let accessController, dbName
|
|
|
|
before(async () => {
|
|
dbName = 'testdb-load-' + new Date().getTime()
|
|
accessController = new OrbitDBAccessController(orbitdb1)
|
|
await accessController.load(dbName)
|
|
await accessController.grant('write', 'A')
|
|
await accessController.grant('write', 'B')
|
|
await accessController.grant('write', 'C')
|
|
await accessController.grant('write', 'C') // double entry
|
|
await accessController.grant('another', 'AA')
|
|
await accessController.grant('another', 'BB')
|
|
await accessController.revoke('another', 'AA')
|
|
await accessController.grant('admin', id1.id)
|
|
return new Promise((resolve) => {
|
|
// Test that the access controller emits 'updated' after it was loaded
|
|
accessController.on('updated', () => resolve())
|
|
accessController.load(accessController.address)
|
|
})
|
|
})
|
|
|
|
it('has the correct database address for the internal db', async () => {
|
|
const addr = accessController._db.address.toString().split('/')
|
|
assert.strictEqual(addr[addr.length - 1], '_access')
|
|
assert.strictEqual(addr[addr.length - 2], dbName)
|
|
})
|
|
|
|
it('has correct capabalities', async () => {
|
|
assert.deepStrictEqual(accessController.get('admin'), new Set([id1.id]))
|
|
assert.deepStrictEqual(accessController.get('write'), new Set(['A', 'B', 'C']))
|
|
assert.deepStrictEqual(accessController.get('another'), new Set(['BB']))
|
|
})
|
|
})
|
|
})
|
|
// TODO: use two separate peers for testing the AC
|
|
// TODO: add tests for revocation correctness with a database (integration tests)
|
|
})
|