mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-06-05 21:56:42 +00:00
177 lines
5.9 KiB
JavaScript
177 lines
5.9 KiB
JavaScript
/**
|
|
* @module Identities
|
|
* @description
|
|
* Identities provides a framework for generating and managing identity
|
|
* details and providers.
|
|
*/
|
|
import Identity, { isIdentity, isEqual, decodeIdentity } from './identity.js'
|
|
import { getIdentityProvider } from './providers/index.js'
|
|
// import DIDIdentityProvider from './identity-providers/did.js'
|
|
// import EthIdentityProvider from './identity-providers/ethereum.js'
|
|
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 DefaultIdentityKeysPath = pathJoin('./orbitdb', 'identities')
|
|
|
|
/**
|
|
* Creates an instance of Identities.
|
|
* @function
|
|
* @param {Object} params One or more parameters for configuring Identities.
|
|
* @param {module:KeyStore} [params.keystore] A preconfigured KeyStore.
|
|
* A KeyStore will be created in the path defined by the path param. If neither
|
|
* Keystore nor path are defined, a new KeyStore is stored in ./orbitdb
|
|
* identities.
|
|
* @param {string} [params.path] The path to a KeyStore. If no path is
|
|
* provided, the default is ./orbitdb/identities.
|
|
* @param {module:Storage} [params.storage] An instance of a compatible storage
|
|
* module.
|
|
* @param {IPFS} [params.ipfs] An instance of IPFS. This param is not required
|
|
* if storage is provided.
|
|
* @return {module:Identities~Identities} An instance of Identities.
|
|
* @instance
|
|
*/
|
|
const Identities = async ({ keystore, path, storage, ipfs } = {}) => {
|
|
/**
|
|
* @namespace module:Identities~Identities
|
|
* @description The instance returned by {@link module:Identities}.
|
|
*/
|
|
|
|
keystore = keystore || await KeyStore({ path: path || DefaultIdentityKeysPath })
|
|
|
|
if (!storage) {
|
|
storage = ipfs
|
|
? await ComposedStorage(await LRUStorage({ size: 1000 }), await IPFSBlockStorage({ ipfs, pin: true }))
|
|
: await MemoryStorage()
|
|
}
|
|
|
|
const verifiedIdentitiesCache = await LRUStorage({ size: 1000 })
|
|
|
|
/**
|
|
* Gets an identity by hash.
|
|
* @param {string} hash An identity hash.
|
|
* @return {module:Identities~Identity} An instance of identity.
|
|
* @memberof module:Identities~Identities
|
|
* @instance
|
|
*/
|
|
const getIdentity = async (hash) => {
|
|
const bytes = await storage.get(hash)
|
|
if (bytes) {
|
|
return decodeIdentity(bytes)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates an identity, adding it to storage.
|
|
* @param {Object} options Various options for configuring a new 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 DefaultIdentityProviderType = getIdentityProvider('publickey')
|
|
const IdentityProvider = options.provider || DefaultIdentityProviderType({ keystore })
|
|
const identityProvider = IdentityProvider()
|
|
const id = await identityProvider.getId(options)
|
|
const privateKey = await keystore.getKey(id) || await keystore.createKey(id)
|
|
const publicKey = keystore.getPublic(privateKey)
|
|
const idSignature = await signMessage(privateKey, id)
|
|
const publicKeyAndIdSignature = await identityProvider.signIdentity(publicKey + idSignature, options)
|
|
const signatures = {
|
|
id: idSignature,
|
|
publicKey: publicKeyAndIdSignature
|
|
}
|
|
|
|
const identity = await Identity({ id, publicKey, signatures, type: identityProvider.type, sign, verify })
|
|
|
|
await storage.put(identity.hash, identity.bytes)
|
|
|
|
return identity
|
|
}
|
|
|
|
/**
|
|
* Verifies an identity using the identity's provider.
|
|
* @param {module:Identities~Identity} identity The identity to verify.
|
|
* @return {boolean} True the identity is valid, false otherwise.
|
|
* @memberof module:Identities~Identities
|
|
*/
|
|
const verifyIdentity = async (identity) => {
|
|
if (!isIdentity(identity)) {
|
|
return false
|
|
}
|
|
|
|
const { id, publicKey, signatures } = identity
|
|
|
|
const idSignatureVerified = await verify(signatures.id, publicKey, id)
|
|
if (!idSignatureVerified) {
|
|
return false
|
|
}
|
|
|
|
const verifiedIdentity = await verifiedIdentitiesCache.get(signatures.id)
|
|
if (verifiedIdentity) {
|
|
return isEqual(identity, verifiedIdentity)
|
|
}
|
|
|
|
const Provider = getIdentityProvider(identity.type)
|
|
|
|
const identityVerified = await Provider.verifyIdentity(identity)
|
|
if (identityVerified) {
|
|
await verifiedIdentitiesCache.put(signatures.id, identity)
|
|
}
|
|
|
|
return identityVerified
|
|
}
|
|
|
|
/**
|
|
* Signs data using an identity.
|
|
* @param {module:Identities~Identity} identity The identity to use for
|
|
* signing.
|
|
* @param {string} data The data to sign.
|
|
* @return {string} The signed data.
|
|
* @throws Private signing key not found from KeyStore when no signing key can
|
|
* be retrieved.
|
|
* @memberof module:Identities~Identities
|
|
* @instance
|
|
* @private
|
|
*/
|
|
const sign = async (identity, data) => {
|
|
const signingKey = await keystore.getKey(identity.id)
|
|
|
|
if (!signingKey) {
|
|
throw new Error('Private signing key not found from KeyStore')
|
|
}
|
|
|
|
return await signMessage(signingKey, data)
|
|
}
|
|
|
|
/**
|
|
* Verifies data using a valid signature and publicKey.
|
|
* @param {string} signature A signature.
|
|
* @param {string} publicKey A public key.
|
|
* @param {string} data The data to be verified.
|
|
* @return {boolean} True if the the data is signed by the publicKey, false
|
|
* otherwise.
|
|
* @memberof module:Identities~Identities
|
|
* @instance
|
|
* @private
|
|
*/
|
|
const verify = async (signature, publicKey, data) => {
|
|
return await verifyMessage(signature, publicKey, data)
|
|
}
|
|
|
|
return {
|
|
createIdentity,
|
|
verifyIdentity,
|
|
getIdentity,
|
|
sign,
|
|
verify,
|
|
keystore
|
|
}
|
|
}
|
|
|
|
export {
|
|
Identities as default
|
|
}
|