mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-03-30 15:08:28 +00:00
Merge pull request #1090 from orbitdb/identity-provider-partials
refactor: Identity provider can be passed as partially instantiated f…
This commit is contained in:
commit
249e999cad
@ -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) })
|
||||
```
|
@ -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' })
|
||||
```
|
||||
|
||||
|
@ -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
4
package-lock.json
generated
@ -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",
|
||||
|
@ -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
|
||||
|
@ -97,4 +97,6 @@ const IPFSAccessController = ({ write, storage } = {}) => async ({ orbitdb, iden
|
||||
}
|
||||
}
|
||||
|
||||
IPFSAccessController.type = type
|
||||
|
||||
export default IPFSAccessController
|
||||
|
@ -188,4 +188,6 @@ const OrbitDBAccessController = ({ write } = {}) => async ({ orbitdb, identities
|
||||
}
|
||||
}
|
||||
|
||||
OrbitDBAccessController.type = type
|
||||
|
||||
export default OrbitDBAccessController
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 }
|
||||
|
@ -119,4 +119,6 @@ const KeyValueIndexed = ({ storage } = {}) => async ({ ipfs, identity, address,
|
||||
}
|
||||
}
|
||||
|
||||
KeyValueIndexed.type = 'keyvalue'
|
||||
|
||||
export default KeyValueIndexed
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -7,7 +7,7 @@ export {
|
||||
} from './identity.js'
|
||||
|
||||
export {
|
||||
addIdentityProvider,
|
||||
useIdentityProvider,
|
||||
getIdentityProvider,
|
||||
PublicKeyIdentityProvider
|
||||
} from './providers/index.js'
|
||||
|
@ -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 }
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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,
|
||||
|
4
test/fixtures/providers.js
vendored
4
test/fixtures/providers.js
vendored
@ -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
20
test/fixtures/providers/custom.js
vendored
Normal 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
20
test/fixtures/providers/fake.js
vendored
Normal 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
5
test/fixtures/providers/no-type.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
const NoTypeIdentityProvider = () => async () => {
|
||||
|
||||
}
|
||||
|
||||
export default NoTypeIdentityProvider
|
11
test/fixtures/providers/no-verify-identity.js
vendored
Normal file
11
test/fixtures/providers/no-verify-identity.js
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
const type = 'no-verify-identity'
|
||||
|
||||
const NoVerifyIdentityIdentityProvider = () => async () => {
|
||||
return {
|
||||
type
|
||||
}
|
||||
}
|
||||
|
||||
NoVerifyIdentityIdentityProvider.type = type
|
||||
|
||||
export default NoVerifyIdentityIdentityProvider
|
@ -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\'.')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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 () => {
|
||||
|
@ -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)
|
||||
})
|
||||
|
60
test/orbitdb-custom-identity-providers.test.js
Normal file
60
test/orbitdb-custom-identity-providers.test.js
Normal 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')
|
||||
})
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user