6.0 KiB
Identities
An identity is a cryptographically signed public key which can be used to sign and verify various data. Within OrbitDB, the main objective of an identity is verify write access to a database's log and, if allowed, to sign each entry as it is added to the log.
Identities
provides methods to manage one or more identities and includes functionality for creating, retrieving, signing and verifying an identity as well as signing and verifying messages using an existing identity.
Creating an identity
An identity can be created by using the createIdentity
function.
A root key is used to create a new key with the "id" of the root key's public key, Using the derived private key, the root public key is signed. This is known as the "signed message".
A new identity is signed using the root key's private key. The identity is consists of the signed message and the derived public key concatenated together ("signed identity")
A "signatures object" is then created to hold both the signed message and signed identity.
Finally, a new identity consisting of the root public key and derived public key plus the signatures object is generated and stored to the Identities storage.
import { Identities } from 'orbit-db'
const id = 'userA'
const identities = await Identities()
const identity = identities.createIdentity({ id })
The id
parameter that is passed to createIdentity is used to reference the root key pair in the PublicKeyIdentityProvider. The id can be any arbitrary text, e.g. 'bob', 'My-Key-123', etc.
The PublicKeyIdentityProvider stores the id and the root keys as a key/value pair in the key store. Other providers may not store root keys in the same manner and so the id
parameter may not always be required.
Once created, identities
and the associated id
can be passed to OrbitDB:
const orbitdb = await OrbitDB({ identities, id: 'userA' })
This identity can now be used by OrbitDB to control access to database actions such as write.
Key Store
The key store is a local key manager for OrbitDB and is used to store the private keys generated by Identities.createIdentity
.
PublicKeyIdentityProvider also uses key store to store the root key which is used to sign the identities created with Identities.createIdentity
.
Specifying a keystore
An existing keystore can be passed to Identities
:
import { Identities, KeyStore } from 'orbit-db'
const keystore = await KeyStore()
const id = 'userA'
const identities = await Identities({ keystore })
const identity = identities.createIdentity({ id })
Customizing the key store path
There are different ways to customize the location of the key store.
To change the keystore using OrbitDB
, pass a custom directory:
// This will create a key store under ./different-path/key-store
const orbitdb = await OrbitDB({ directory: './different-path' })
// Be aware that this will change the base path to the database as well.
To change the keystore using the KeyStore function, pass a custom path to the KeyStore
function:
// This will create a key store under ./different-key-store.
const path = ./different-key-store
const keystore = await KeyStore({ path })
// keystore can now be used with other functions, for example:
const identities = await Identities({ keystore })
To specify a different keystore path using Identities
, pass a custom path to the Identities
function:
/// This will create a KeyStore under ./different-identities-path
const path = ./different-identities-path
const identities = await Identities({ path })
Identity as a linked data object
The identity object is stored just like any other IPLD data structure and can therefore be retrieved from IPFS using the identity's hash:
import { create } from 'ipfs-core'
import * as Block from 'multiformats/block'
import { Identities } from 'orbit-db'
import * as dagCbor from '@ipld/dag-cbor'
import { sha256 } from 'multiformats/hashes/sha2'
import { base58btc } from 'multiformats/bases/base58'
import { CID } from 'multiformats/cid'
const ipfs = await create()
const identities = await Identities({ ipfs })
const identity = await identities.createIdentity({ id: 'me'})
const cid = CID.parse(identity.hash, base58btc)
// Extract the hash from the full db path.
const bytes = await ipfs.block.get(cid)
// Defines how we serialize/hash the data.
const codec = dagCbor
const hasher = sha256
// Retrieve the block data, decoding it to human-readable JSON text.
const { value } = await Block.decode({ bytes, codec, hasher })
console.log('identity', value)
The resulting output is a JSON object containing the identity information:
{
id: '031a7bf5f233ad9dccb2a305edfd939f0c54f0ed2e270c4ac390d91ecd33d0c28f',
type: 'publickey',
publicKey: '02343cbdd3a5deaacc115f8f241db979f59864aad5b4fbf1561e19d5d04d7b1d14',
signatures: {
id: '30440220492ed7bc2945bd6859e96fa929870343bcda188b481248dfa51c7dd7a1eb59ef022049542399338e66454f523dc4033723bc4ff4365f17537171361e128f10703be1',
publicKey: '30450221008291e9e12d586129de2882e731f286b4168cbed43d2ecf90d8ae9c53e15c56110220204ac640b22e75bf6083a6715a7e6c988659fc08f79022fab8af62563e9fdd67'
}
}
Custom identity providers
A custom identity provider can be used provided the module takes the following form:
// A unique name for the identity provider
const type = 'custom'
// check whether the identity was signed by the identity's id.
const verifyIdentity = identity => {
}
// The identity provider.
const MyCustomIdentityProvider = ({ keystore }) => {
const getId = async ({ id } = {}) => {
}
const signIdentity = async (data, { id } = {}) => {
}
return {
getId,
signIdentity
}
}
export { MyCustomIdentityProvider as default, verifyIdentity, type }
To use it, add it to the list of known identity providers:
import as MyCustomIdentityProvider from 'my-custom-identity-provider'
addIdentityProvider(MyCustomIdentityProvider)
where my-custom-identity-provider is the custom module.