Merge pull request #1090 from orbitdb/identity-provider-partials

refactor: Identity provider can be passed as partially instantiated f…
This commit is contained in:
Hayden Young 2023-09-08 16:45:47 +08:00 committed by GitHub
commit 249e999cad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 324 additions and 112 deletions

View File

@ -123,6 +123,8 @@ const CustomAccessController = () => async ({ orbitdb, identities, address }) =>
}
CustomAccessController.type = type
export default CustomAccessController
```
Additional configuration can be passed to the access controller by adding one or more parameters to the `CustomAccessController` function. For example, passing a configurable object parameter with the variable `write`:
@ -164,9 +166,9 @@ Before passing the custom access controller to the `open` function, it must be a
```js
import { create } from 'ipfs-core'
import { createOrbitDB, addAccessController } from '@orbitdb/core'
import { createOrbitDB, useAccessController } from '@orbitdb/core'
addAccessController(CustomAccessController)
useAccessController(CustomAccessController)
const orbitdb = await createOrbitDB({ ipfs })
const db = await orbitdb.open('my-db', { AccessController: CustomAccessController(params) })
```

View File

@ -205,11 +205,13 @@ db2.events.on('update', async (entry) => {
To learn more, check out [OrbitDB's sychronization protocol](https://orbitdb.org/api/module-Sync.html) and the [OrbitDB replication documentation](./REPLICATION.md).
## Building a custom database
## Custom databases
OrbitDB can be extended to use custom data models and database types. To implement a custom database, ensure the Database object is extended and that the OrbitDB database interface is implement. The database will also require a unique type.
```js
const type = 'customdb'
const CustomDB = async ({ OpLog, Database, ipfs, identity, address, name, access, directory, storage, meta, syncAutomatically }) => {
const database = await Database({ OpLog, ipfs, identity, address, name, access, directory, storage, meta, syncAutomatically })
@ -244,13 +246,29 @@ const CustomDB = async ({ OpLog, Database, ipfs, identity, address, name, access
return {
...database,
type: 'customdb',
type,
put,
del,
get,
iterator
}
}
CustomDB.type = type
export default CustomDB
```
[Documents](../src/db/documents.js), [Events](../src/db/events.js) and [KeyValue](../src/db/keyvalue.js) provide good examples of how a database is implemented in OrbitDB and how to add the logic for returning records from the database (the state of the database).
To use a custom database, add it to the list of supported database types:
```js
import { createOrbitDB, useDatabaseType } from '@orbitdb/core'
import CustomDB from './custom-db.js'
useDatabaseType(CustomDB)
const orbitdb = await createOrbitDB()
await orbitdb.open('my-custom-db', { type: 'customdb' })
```

View File

@ -143,7 +143,7 @@ const verifyIdentity = identity => {
}
// The identity provider.
const MyCustomIdentityProvider = ({ keystore }) => {
const MyCustomIdentityProvider = ({ keystore }) => async () => {
const getId = async ({ id } = {}) => {
// return the "root" identity managed by the custom identity provider,
// eg. a public key or a wallet address
@ -154,12 +154,16 @@ const MyCustomIdentityProvider = ({ keystore }) => {
}
return {
type,
getId,
signIdentity
}
}
export { MyCustomIdentityProvider as default, verifyIdentity, type }
MyCustomIdentityProvider.verifyIdentity = verifyIdentity
MyCustomIdentityProvider.type = type
export default MyCustomIdentityProvider
```
To use it, add it to the list of known identity providers:
@ -168,7 +172,7 @@ To use it, add it to the list of known identity providers:
import { addIdentityProvider } from '@orbitdb/core'
import MyCustomIdentityProvider from 'my-custom-identity-provider'
addIdentityProvider(MyCustomIdentityProvider)
const identity = await createIdentity({ id: 'some id', type: 'custom' })
const identity = await createIdentity({ provider: MyCustomIdentityProvider(options) })
```
where my-custom-identity-provider is the custom module.

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "@orbitdb/core",
"version": "0.30.0",
"version": "0.30.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@orbitdb/core",
"version": "0.30.0",
"version": "0.30.1",
"license": "MIT",
"dependencies": {
"@ipld/dag-cbor": "^9.0.0",

View File

@ -8,10 +8,7 @@
import IPFSAccessController from './ipfs.js'
import OrbitDBAccessController from './orbitdb.js'
const accessControllers = {
ipfs: IPFSAccessController,
orbitdb: OrbitDBAccessController
}
const accessControllers = {}
/**
* Gets an access controller module specified by type.
@ -30,19 +27,13 @@ const getAccessController = (type) => {
* Adds an access controller module to the list of supported access controller.
* @param {AccessController} accessController A compatible access controller
* module.
* @throws Access controller `type` already added if the access controller is
* already supported.
* @throws Given AccessController class needs to implement: type if the access
* controller module does not implement a type property.
* @throws AccessController does not contain required field \'type\'.
* @throws AccessController '${accessController.type}' already added.
* @static
*/
const addAccessController = (accessController) => {
const useAccessController = (accessController) => {
if (!accessController.type) {
throw new Error('Access controller does not contain required field \'type\'')
}
if (accessControllers[accessController.type]) {
throw new Error(`Access controller '${accessController.type}' already added.`)
throw new Error('AccessController does not contain required field \'type\'.')
}
accessControllers[accessController.type] = accessController
@ -57,9 +48,12 @@ const removeAccessController = type => {
delete accessControllers[type]
}
useAccessController(IPFSAccessController)
useAccessController(OrbitDBAccessController)
export {
getAccessController,
addAccessController,
useAccessController,
removeAccessController,
IPFSAccessController,
OrbitDBAccessController

View File

@ -97,4 +97,6 @@ const IPFSAccessController = ({ write, storage } = {}) => async ({ orbitdb, iden
}
}
IPFSAccessController.type = type
export default IPFSAccessController

View File

@ -188,4 +188,6 @@ const OrbitDBAccessController = ({ write } = {}) => async ({ orbitdb, identities
}
}
OrbitDBAccessController.type = type
export default OrbitDBAccessController

View File

@ -14,6 +14,8 @@
*/
import Database from '../database.js'
const type = 'documents'
const DefaultOptions = { indexBy: '_id' }
/**
@ -145,7 +147,7 @@ const Documents = ({ indexBy } = DefaultOptions) => async ({ ipfs, identity, add
return {
...database,
type: 'documents',
type,
put,
del,
get,
@ -156,4 +158,6 @@ const Documents = ({ indexBy } = DefaultOptions) => async ({ ipfs, identity, add
}
}
Documents.type = type
export default Documents

View File

@ -8,6 +8,8 @@
*/
import Database from '../database.js'
const type = 'events'
/**
* Defines an Events database.
* @return {module:Databases.Databases-Events} A Events function.
@ -86,7 +88,7 @@ const Events = () => async ({ ipfs, identity, address, name, access, directory,
return {
...database,
type: 'events',
type,
add,
get,
iterator,
@ -94,4 +96,6 @@ const Events = () => async ({ ipfs, identity, address, name, access, directory,
}
}
Events.type = type
export default Events

View File

@ -15,32 +15,29 @@ import KeyValueIndexed from './keyvalue-indexed.js'
* @return [] An array of database types.
* @memberof module:Databases
*/
const databaseTypes = {
events: Events,
documents: Documents,
keyvalue: KeyValue,
keyvalueindexed: KeyValueIndexed
}
const databaseTypes = {}
/**
* Add a new database type.
* @example
* import { addDatabaseType } from 'orbitdb'
* import { useDatabaseType } from 'orbitdb'
* const CustomDBTypeModule = async (params) => {
* const database = await Database(...params)
* ...
* }
* addDatabaseType('customDBType', CustomDBTypeModule)
* @function addDatabaseType
* @param {string} type The database type.
* @param {module:Databases} store A Database-compatible module.
* useDatabaseType(CustomDBTypeModule)
* @function useDatabaseType
* @param {module:Databases} database A Database-compatible module.
* @throws Database type does not contain required field \'type\'.
* @throws Database type '${store.type}' already added.
* @memberof module:Databases
*/
const addDatabaseType = (type, store) => {
if (databaseTypes[type]) {
throw new Error(`Type already exists: ${type}`)
const useDatabaseType = (database) => {
if (!database.type) {
throw new Error('Database type does not contain required field \'type\'.')
}
databaseTypes[type] = store
databaseTypes[database.type] = database
}
const getDatabaseType = (type) => {
@ -55,4 +52,8 @@ const getDatabaseType = (type) => {
return databaseTypes[type]
}
export { addDatabaseType, getDatabaseType, Documents, Events, KeyValue, KeyValueIndexed }
useDatabaseType(Events)
useDatabaseType(Documents)
useDatabaseType(KeyValue)
export { useDatabaseType, getDatabaseType, Documents, Events, KeyValue, KeyValueIndexed }

View File

@ -119,4 +119,6 @@ const KeyValueIndexed = ({ storage } = {}) => async ({ ipfs, identity, address,
}
}
KeyValueIndexed.type = 'keyvalue'
export default KeyValueIndexed

View File

@ -8,6 +8,8 @@
*/
import Database from '../database.js'
const type = 'keyvalue'
/**
* Defines an KeyValue database.
* @return {module:Databases.Databases-KeyValue} A KeyValue function.
@ -107,7 +109,7 @@ const KeyValue = () => async ({ ipfs, identity, address, name, access, directory
return {
...database,
type: 'keyvalue',
type,
put,
set: put, // Alias for put()
del,
@ -117,4 +119,6 @@ const KeyValue = () => async ({ ipfs, identity, address, name, access, directory
}
}
KeyValue.type = type
export default KeyValue

View File

@ -12,8 +12,6 @@ import KeyStore, { signMessage, verifyMessage } from '../key-store.js'
import { LRUStorage, IPFSBlockStorage, MemoryStorage, ComposedStorage } from '../storage/index.js'
import pathJoin from '../utils/path-join.js'
const DefaultProviderType = 'publickey'
const DefaultIdentityKeysPath = pathJoin('./orbitdb', 'identities')
/**
@ -66,17 +64,22 @@ const Identities = async ({ keystore, path, storage, ipfs } = {}) => {
/**
* Creates an identity, adding it to storage.
* @param {Object} options Various options for configuring a new identity.
* @param {string} [options.type=publickey] The type of provider to use for generating an identity.
* @param {Function} [options.provider=PublicKeyIdentityProvider()] An instance of the Provider to use for generating an identity, e.g. PublicKeyIdentityProvider({ keystore })
* @return {module:Identities~Identity} An instance of identity.
* @memberof module:Identities~Identities
* @instance
*/
const createIdentity = async (options = {}) => {
options.keystore = keystore
const DefaultIdentityProvider = getIdentityProvider('publickey')
const identityProviderInit = options.provider || DefaultIdentityProvider({ keystore })
const identityProvider = await identityProviderInit()
if (!getIdentityProvider(identityProvider.type)) {
throw new Error('Identity provider is unknown. Use useIdentityProvider(provider) to register the identity provider')
}
const type = options.type || DefaultProviderType
const Provider = getIdentityProvider(type).default
const identityProvider = Provider(options)
const id = await identityProvider.getId(options)
const privateKey = await keystore.getKey(id) || await keystore.createKey(id)
const publicKey = keystore.getPublic(privateKey)
@ -87,7 +90,7 @@ const Identities = async ({ keystore, path, storage, ipfs } = {}) => {
publicKey: publicKeyAndIdSignature
}
const identity = await Identity({ id, publicKey, signatures, type, sign, verify })
const identity = await Identity({ id, publicKey, signatures, type: identityProvider.type, sign, verify })
await storage.put(identity.hash, identity.bytes)

View File

@ -7,7 +7,7 @@ export {
} from './identity.js'
export {
addIdentityProvider,
useIdentityProvider,
getIdentityProvider,
PublicKeyIdentityProvider
} from './providers/index.js'

View File

@ -1,8 +1,6 @@
import * as PublicKeyIdentityProvider from './publickey.js'
import PublicKeyIdentityProvider from './publickey.js'
const identityProviders = {
publickey: PublicKeyIdentityProvider
}
const identityProviders = {}
const isProviderSupported = (type) => {
return Object.keys(identityProviders).includes(type)
@ -18,29 +16,26 @@ const getIdentityProvider = (type) => {
/**
* Adds an identity provider.
* @param {IdentityProvider} IdentityProvider The identity provider to add.
* @throws IdentityProvider must be given as an argument if no module is
* provided.
* @throws 'Given IdentityProvider doesn't have a field 'type' if the
* IdentityProvider does not include a type property.
* @param {IdentityProvider} identityProvider The identity provider to add.
* @throws Given IdentityProvider doesn\'t have a field \'type\'.
* @throws Given IdentityProvider doesn\'t have a function \'verifyIdentity\'.
* @throws IdentityProvider ${IdentityProvider.type} already added.
* @static
* @memberof module:Identities
*/
const addIdentityProvider = (IdentityProvider) => {
if (!IdentityProvider) {
throw new Error('IdentityProvider must be given as an argument')
const useIdentityProvider = (identityProvider) => {
if (!identityProvider.type ||
typeof identityProvider.type !== 'string') {
throw new Error('Given IdentityProvider doesn\'t have a field \'type\'.')
}
if (!IdentityProvider.type ||
typeof IdentityProvider.type !== 'string') {
throw new Error('Given IdentityProvider doesn\'t have a field \'type\'')
if (!identityProvider.verifyIdentity) {
throw new Error('Given IdentityProvider doesn\'t have a function \'verifyIdentity\'.')
}
if (identityProviders[IdentityProvider.type]) {
throw new Error(`Type already added: ${IdentityProvider.type}`)
}
identityProviders[IdentityProvider.type] = IdentityProvider
identityProviders[identityProvider.type] = identityProvider
}
export { addIdentityProvider, getIdentityProvider, PublicKeyIdentityProvider }
useIdentityProvider(PublicKeyIdentityProvider)
export { useIdentityProvider, getIdentityProvider, PublicKeyIdentityProvider }

View File

@ -16,7 +16,7 @@ const type = 'publickey'
* @static
* @private
*/
const verifyIdentity = identity => {
const verifyIdentity = async identity => {
const { id, publicKey, signatures } = identity
return verifyMessage(signatures.publicKey, id, publicKey + signatures.id)
}
@ -27,7 +27,7 @@ const verifyIdentity = identity => {
* identity provider function.
* @private
*/
const PublicKeyIdentityProvider = ({ keystore }) => {
const PublicKeyIdentityProvider = ({ keystore }) => async () => {
/**
* @namespace module:IdentityProviders.IdentityProvider-PublicKey
* @memberof module:IdentityProviders
@ -78,9 +78,13 @@ const PublicKeyIdentityProvider = ({ keystore }) => {
}
return {
type,
getId,
signIdentity
}
}
export { PublicKeyIdentityProvider as default, verifyIdentity, type }
PublicKeyIdentityProvider.verifyIdentity = verifyIdentity
PublicKeyIdentityProvider.type = type
export default PublicKeyIdentityProvider

View File

@ -7,7 +7,7 @@ export {
Events,
KeyValue,
KeyValueIndexed,
addDatabaseType
useDatabaseType
} from './databases/index.js'
export {
@ -22,8 +22,7 @@ export { default as Database } from './database.js'
export { default as KeyStore } from './key-store.js'
export {
addAccessController,
removeAccessController,
useAccessController,
IPFSAccessController,
OrbitDBAccessController
} from './access-controllers/index.js'
@ -31,7 +30,7 @@ export {
export {
Identities,
isIdentity,
addIdentityProvider,
useIdentityProvider,
PublicKeyIdentityProvider
} from './identities/index.js'

View File

@ -21,14 +21,16 @@ const DefaultAccessController = IPFSAccessController
* @function
* @param {Object} params One or more parameters for configuring OrbitDB.
* @param {IPFS} params.ipfs An IPFS instance.
* @param {string} [params.id] The id of the user to use for this OrbitDB instance.
* @param {string} [params.id] The id of the identity to use for this OrbitDB instance.
* @param {module:Identity|Object} [params.identity] An identity instance or an object containing an Identity Provider instance and any additional params required to create the identity using the specified provider.
* @param {Function} [params.identity.provider] An initialized identity provider.
* @param {module:Identities} [params.identities] An Identities system instance.
* @param {string} [params.directory] A location for storing OrbitDB data.
* @return {module:OrbitDB~OrbitDB} An instance of OrbitDB.
* @throws "IPFS instance is required argument" if no IPFS instance is provided.
* @instance
*/
const OrbitDB = async ({ ipfs, id, identities, directory } = {}) => {
const OrbitDB = async ({ ipfs, id, identity, identities, directory } = {}) => {
/**
* @namespace module:OrbitDB~OrbitDB
* @description The instance returned by {@link module:OrbitDB}.
@ -51,7 +53,13 @@ const OrbitDB = async ({ ipfs, id, identities, directory } = {}) => {
identities = await Identities({ ipfs, keystore })
}
const identity = await identities.createIdentity({ id })
if (identity) {
if (identity.provider) {
identity = await identities.createIdentity({ ...identity })
}
} else {
identity = await identities.createIdentity({ id })
}
const manifestStore = await ManifestStore({ ipfs })
@ -176,6 +184,7 @@ const OrbitDB = async ({ ipfs, id, identities, directory } = {}) => {
}
return {
id,
open,
stop,
ipfs,

View File

@ -1,7 +1,7 @@
const customIdentityProvider = () => {
const verifyIdentity = async (data) => { return true }
const CustomIdentityProvider = () => {
const CustomIdentityProvider = () => () => {
const getId = () => { return 'custom' }
const signIdentity = (data) => { return `signature '${data}'` }
@ -23,7 +23,7 @@ const customIdentityProvider = () => {
const fakeIdentityProvider = () => {
const verifyIdentity = async (data) => { return false }
const FakeIdentityProvider = () => {
const FakeIdentityProvider = () => () => {
const getId = () => { return 'pubKey' }
const signIdentity = (data) => { return `false signature '${data}'` }

20
test/fixtures/providers/custom.js vendored Normal file
View File

@ -0,0 +1,20 @@
const type = 'custom'
const verifyIdentity = async (data) => { return true }
const CustomIdentityProvider = () => async () => {
const getId = () => { return 'custom' }
const signIdentity = (data) => { return `signature '${data}'` }
return {
getId,
signIdentity,
type
}
}
CustomIdentityProvider.verifyIdentity = verifyIdentity
CustomIdentityProvider.type = type
export default CustomIdentityProvider

20
test/fixtures/providers/fake.js vendored Normal file
View File

@ -0,0 +1,20 @@
const type = 'fake'
const verifyIdentity = async (data) => { return false }
const FakeIdentityProvider = () => async () => {
const getId = () => { return 'pubKey' }
const signIdentity = (data) => { return `false signature '${data}'` }
return {
getId,
signIdentity,
type
}
}
FakeIdentityProvider.verifyIdentity = verifyIdentity
FakeIdentityProvider.type = type
export default FakeIdentityProvider

5
test/fixtures/providers/no-type.js vendored Normal file
View File

@ -0,0 +1,5 @@
const NoTypeIdentityProvider = () => async () => {
}
export default NoTypeIdentityProvider

View File

@ -0,0 +1,11 @@
const type = 'no-verify-identity'
const NoVerifyIdentityIdentityProvider = () => async () => {
return {
type
}
}
NoVerifyIdentityIdentityProvider.type = type
export default NoVerifyIdentityIdentityProvider

View File

@ -3,9 +3,12 @@ import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import KeyStore, { signMessage, verifyMessage } from '../../src/key-store.js'
import { Identities, addIdentityProvider, getIdentityProvider, Identity } from '../../src/identities/index.js'
import { Identities, useIdentityProvider, getIdentityProvider, Identity, PublicKeyIdentityProvider } from '../../src/identities/index.js'
import testKeysPath from '../fixtures/test-keys-path.js'
import { CustomIdentityProvider, FakeIdentityProvider } from '../fixtures/providers.js'
import CustomIdentityProvider from '../fixtures/providers/custom.js'
import FakeIdentityProvider from '../fixtures/providers/fake.js'
import NoTypeIdentityProvider from '../fixtures/providers/no-type.js'
import NoVerifyIdentityIdentityProvider from '../fixtures/providers/no-verify-identity.js'
const type = 'publickey'
const keysPath = './testkeys'
@ -64,6 +67,21 @@ describe('Identities', function () {
assert.strictEqual(result.sign, undefined)
assert.strictEqual(result.verify, undefined)
})
it('Passes in an identity provider', async () => {
const keystore = await KeyStore({ path: keysPath })
identities = await Identities({ keystore })
const provider = PublicKeyIdentityProvider({ keystore })
identity = await identities.createIdentity({ id, provider })
const result = await identities.getIdentity(identity.hash)
assert.strictEqual(result.id, identity.id)
assert.strictEqual(result.hash, identity.hash)
assert.strictEqual(result.publicKey, identity.publicKey)
assert.strictEqual(result.type, identity.type)
assert.deepStrictEqual(result.signatures, identity.signatures)
assert.strictEqual(result.sign, undefined)
assert.strictEqual(result.verify, undefined)
})
})
describe('Passing in custom keystore', async () => {
@ -201,21 +219,21 @@ describe('Identities', function () {
it('identity pkSignature verifies', async () => {
identities = await Identities({ keystore })
identity = await identities.createIdentity({ id, type })
identity = await identities.createIdentity({ id })
const verified = await verifyMessage(identity.signatures.id, identity.publicKey, identity.id)
assert.strictEqual(verified, true)
})
it('identity signature verifies', async () => {
identities = await Identities({ keystore })
identity = await identities.createIdentity({ id, type })
identity = await identities.createIdentity({ id })
const verified = await verifyMessage(identity.signatures.publicKey, identity.id, identity.publicKey + identity.signatures.id)
assert.strictEqual(verified, true)
})
it('false signature doesn\'t verify', async () => {
addIdentityProvider(FakeIdentityProvider)
identity = await identities.createIdentity({ type: FakeIdentityProvider.type })
useIdentityProvider(FakeIdentityProvider)
identity = await identities.createIdentity({ provider: FakeIdentityProvider() })
const verified = await identities.verifyIdentity(identity)
assert.strictEqual(verified, false)
})
@ -240,7 +258,7 @@ describe('Identities', function () {
})
it('identity verifies', async () => {
identity = await identities.createIdentity({ id, type })
identity = await identities.createIdentity({ id })
const verified = await identities.verifyIdentity(identity)
assert.strictEqual(verified, true)
})
@ -310,7 +328,7 @@ describe('Identities', function () {
beforeEach(async () => {
identities = await Identities({ keystore })
identity = await identities.createIdentity({ id, type })
identity = await identities.createIdentity({ id })
signature = await identities.sign(identity, data, keystore)
})
@ -327,9 +345,33 @@ describe('Identities', function () {
describe('manage identity providers', () => {
it('can add an identity provider', () => {
addIdentityProvider(CustomIdentityProvider)
useIdentityProvider(CustomIdentityProvider)
assert.deepStrictEqual(getIdentityProvider('custom'), CustomIdentityProvider)
})
it('cannot add an identity provider with missing type', () => {
let err
try {
useIdentityProvider(NoTypeIdentityProvider)
} catch (e) {
err = e.toString()
}
assert.strictEqual(err, 'Error: Given IdentityProvider doesn\'t have a field \'type\'.')
})
it('cannot add an identity provider with missing verifyIdentity', async () => {
let err
try {
useIdentityProvider(NoVerifyIdentityIdentityProvider)
} catch (e) {
err = e.toString()
}
assert.strictEqual(err, 'Error: Given IdentityProvider doesn\'t have a function \'verifyIdentity\'.')
})
})
})

View File

@ -2,7 +2,7 @@ import { strictEqual, deepStrictEqual, notStrictEqual } from 'assert'
import rmrf from 'rimraf'
import * as IPFS from 'ipfs-core'
import OrbitDB from '../src/orbitdb.js'
import { IPFSAccessController, OrbitDBAccessController, addAccessController, getAccessController, removeAccessController } from '../src/access-controllers/index.js'
import { IPFSAccessController, OrbitDBAccessController, useAccessController, getAccessController, removeAccessController } from '../src/access-controllers/index.js'
import config from './config.js'
import pathJoin from '../src/utils/path-join.js'
@ -68,7 +68,7 @@ describe('Add a custom access controller', function () {
describe('Custom access controller', function () {
before(() => {
addAccessController(CustomAccessController)
useAccessController(CustomAccessController)
})
it('create a database with the custom access controller', async () => {
@ -77,15 +77,18 @@ describe('Add a custom access controller', function () {
strictEqual(db.access.address, '/custom!/controller')
})
it('throws and error if custom access controller already exists', async () => {
it('throws and error if custom access controller has no type', async () => {
const NoTypeCustomAccessController = () => async () => {
}
let err
try {
addAccessController(CustomAccessController)
useAccessController(NoTypeCustomAccessController)
} catch (e) {
err = e.toString()
}
strictEqual(err, 'Error: Access controller \'custom!\' already added.')
strictEqual(err, 'Error: AccessController does not contain required field \'type\'.')
})
it('returns custom access controller after adding it', async () => {

View File

@ -1,8 +1,10 @@
import { strictEqual, deepStrictEqual, notStrictEqual } from 'assert'
import rmrf from 'rimraf'
import { existsSync } from 'fs'
import * as IPFS from 'ipfs-core'
import { getDatabaseType } from '../src/databases/index.js'
import { createOrbitDB, addDatabaseType, Database } from '../src/index.js'
import { createOrbitDB, useDatabaseType, Database, KeyValueIndexed } from '../src/index.js'
import pathJoin from '../src/utils/path-join.js'
import config from './config.js'
const type = 'custom!'
@ -16,6 +18,8 @@ const CustomStore = () => async ({ ipfs, identity, address, name, access, direct
}
}
CustomStore.type = type
describe('Add a custom database type', function () {
this.timeout(5000)
@ -53,9 +57,21 @@ describe('Add a custom database type', function () {
})
})
describe('KeyValue Indexed database type', function () {
it('replace keyvalue with keyvalue-indexed', async () => {
useDatabaseType(KeyValueIndexed)
const name = 'hello keyvalue-indexed database'
const db = await orbitdb.open(name, { type: 'keyvalue' })
const indexDirectory = pathJoin('./orbitdb', `./${db.address}/_index/`)
strictEqual(await existsSync(indexDirectory), true)
})
})
describe('Custom database type', function () {
before(() => {
addDatabaseType(type, CustomStore)
useDatabaseType(CustomStore)
})
it('create a database with the custom database type', async () => {
@ -65,18 +81,6 @@ describe('Add a custom database type', function () {
strictEqual(db.name, name)
})
it('throws and error if custom database type already exists', async () => {
let err
try {
addDatabaseType(type, CustomStore)
throw new Error('This should not run.')
} catch (e) {
err = e
}
notStrictEqual(err, undefined)
strictEqual(err.message.indexOf('already exists') !== -1, true)
})
it('returns custom database type after adding it', async () => {
deepStrictEqual(getDatabaseType(type), CustomStore)
})

View File

@ -0,0 +1,60 @@
import { deepStrictEqual } from 'assert'
import rmrf from 'rimraf'
import * as IPFS from 'ipfs-core'
import { createOrbitDB, Identities, useIdentityProvider } from '../src/index.js'
import config from './config.js'
// import pathJoin from '../src/utils/path-join.js'
import CustomIdentityProvider from './fixtures/providers/custom.js'
describe('Add a custom identity provider', function () {
this.timeout(5000)
let ipfs
before(async () => {
ipfs = await IPFS.create({ ...config.daemon1, repo: './ipfs1' })
})
it('creates an identity using an id and default pubkey provider', async () => {
useIdentityProvider(CustomIdentityProvider)
const identities = await Identities()
const identity = await identities.createIdentity({ id: 'abc' })
const orbitdb = await createOrbitDB({ ipfs, identities, id: 'abc' })
deepStrictEqual(orbitdb.identity, identity)
await orbitdb.stop()
})
it('creates an identity using a custom provider', async () => {
useIdentityProvider(CustomIdentityProvider)
const identities = await Identities()
const identity = { provider: CustomIdentityProvider() }
const expectedIdentity = await identities.createIdentity(identity)
const orbitdb = await createOrbitDB({ ipfs, identities, identity })
deepStrictEqual(orbitdb.identity, expectedIdentity)
await orbitdb.stop()
})
it('uses an existing identity created with a custom provider', async () => {
useIdentityProvider(CustomIdentityProvider)
const identities = await Identities()
const identity = await identities.createIdentity({ provider: CustomIdentityProvider() })
const orbitdb = await createOrbitDB({ ipfs, identities, identity })
deepStrictEqual(orbitdb.identity, identity)
await orbitdb.stop()
})
after(async () => {
if (ipfs) {
await ipfs.stop()
}
await rmrf('./orbitdb')
await rmrf('./ipfs1')
})
})