mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-03-30 15:08:28 +00:00
Merge pull request #7 from orbitdb/refactor/identities
refactor: Identities
This commit is contained in:
commit
1272084449
190
package-lock.json
generated
190
package-lock.json
generated
@ -44,6 +44,8 @@
|
|||||||
"go-ipfs": "^0.17.0",
|
"go-ipfs": "^0.17.0",
|
||||||
"ipfs": "^0.66.0",
|
"ipfs": "^0.66.0",
|
||||||
"ipfsd-ctl": "^13.0.0",
|
"ipfsd-ctl": "^13.0.0",
|
||||||
|
"key-did-provider-ed25519": "^2.0.1",
|
||||||
|
"key-did-resolver": "^2.3.0",
|
||||||
"localstorage-down": "^0.6.7",
|
"localstorage-down": "^0.6.7",
|
||||||
"localstorage-level-migration": "^0.2.0",
|
"localstorage-level-migration": "^0.2.0",
|
||||||
"markdown-toc": "^1.2.0",
|
"markdown-toc": "^1.2.0",
|
||||||
@ -5733,6 +5735,15 @@
|
|||||||
"platform": "^1.3.3"
|
"platform": "^1.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bigint-mod-arith": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bigint-mod-arith/-/bigint-mod-arith-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-nx8J8bBeiRR+NlsROFH9jHswW5HO8mgfOSqW0AmjicMMvaONDa8AO+5ViKDUUNytBPWiwfvZP4/Bj4Y3lUfvgQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/bignumber.js": {
|
"node_modules/bignumber.js": {
|
||||||
"version": "9.1.1",
|
"version": "9.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz",
|
||||||
@ -15582,6 +15593,66 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/key-did-provider-ed25519": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/key-did-provider-ed25519/-/key-did-provider-ed25519-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-FaB2g7zUAeN/bLaFl2YSNQx9NsxgDd/3TR1YGvoXLhENsvZBdyA2V7hX8/MZhZ5jm82wL5lRw3O4UXuz/pJANQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@stablelib/ed25519": "^1.0.2",
|
||||||
|
"did-jwt": "^6.0.0",
|
||||||
|
"fast-json-stable-stringify": "^2.1.0",
|
||||||
|
"rpc-utils": "^0.6.2",
|
||||||
|
"uint8arrays": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/key-did-provider-ed25519/node_modules/multiformats": {
|
||||||
|
"version": "9.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz",
|
||||||
|
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/key-did-provider-ed25519/node_modules/uint8arrays": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"multiformats": "^9.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/key-did-resolver": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/key-did-resolver/-/key-did-resolver-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-q3ChQILPe+u8qkpWP196fEoxsygEyjM3K25qrGaMSolVaUdfgj7qwMz2DE/GRIlfNK2HgKW6KXA8RZMy8aL4MA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@stablelib/ed25519": "^1.0.2",
|
||||||
|
"bigint-mod-arith": "^3.1.0",
|
||||||
|
"multiformats": "^9.5.2",
|
||||||
|
"nist-weierstrauss": "^1.3.0",
|
||||||
|
"uint8arrays": "^3.0.0",
|
||||||
|
"varint": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/key-did-resolver/node_modules/multiformats": {
|
||||||
|
"version": "9.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz",
|
||||||
|
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/key-did-resolver/node_modules/uint8arrays": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"multiformats": "^9.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.2",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz",
|
||||||
@ -18157,6 +18228,31 @@
|
|||||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/nist-weierstrauss": {
|
||||||
|
"version": "1.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/nist-weierstrauss/-/nist-weierstrauss-1.6.1.tgz",
|
||||||
|
"integrity": "sha512-FpjCOnPV/s3ZVIkeldCVSml2K4lruabPbBgoEitpCK1JL0KTVoWb56CFTU6rZn5i6VqAjdwcOp0FDwJACPmeFA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"multiformats": "^9.6.5",
|
||||||
|
"uint8arrays": "^2.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nist-weierstrauss/node_modules/multiformats": {
|
||||||
|
"version": "9.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz",
|
||||||
|
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/nist-weierstrauss/node_modules/uint8arrays": {
|
||||||
|
"version": "2.1.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-2.1.10.tgz",
|
||||||
|
"integrity": "sha512-Q9/hhJa2836nQfEJSZTmr+pg9+cDJS9XEAp7N2Vg5MzL3bK/mkMVfjscRGYruP9jNda6MAdf4QD/y78gSzkp6A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"multiformats": "^9.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/no-case": {
|
"node_modules/no-case": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
||||||
@ -32199,6 +32295,12 @@
|
|||||||
"platform": "^1.3.3"
|
"platform": "^1.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"bigint-mod-arith": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bigint-mod-arith/-/bigint-mod-arith-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-nx8J8bBeiRR+NlsROFH9jHswW5HO8mgfOSqW0AmjicMMvaONDa8AO+5ViKDUUNytBPWiwfvZP4/Bj4Y3lUfvgQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"bignumber.js": {
|
"bignumber.js": {
|
||||||
"version": "9.1.1",
|
"version": "9.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz",
|
||||||
@ -39821,6 +39923,67 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"key-did-provider-ed25519": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/key-did-provider-ed25519/-/key-did-provider-ed25519-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-FaB2g7zUAeN/bLaFl2YSNQx9NsxgDd/3TR1YGvoXLhENsvZBdyA2V7hX8/MZhZ5jm82wL5lRw3O4UXuz/pJANQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@stablelib/ed25519": "^1.0.2",
|
||||||
|
"did-jwt": "^6.0.0",
|
||||||
|
"fast-json-stable-stringify": "^2.1.0",
|
||||||
|
"rpc-utils": "^0.6.2",
|
||||||
|
"uint8arrays": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"multiformats": {
|
||||||
|
"version": "9.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz",
|
||||||
|
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"uint8arrays": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"multiformats": "^9.4.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"key-did-resolver": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/key-did-resolver/-/key-did-resolver-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-q3ChQILPe+u8qkpWP196fEoxsygEyjM3K25qrGaMSolVaUdfgj7qwMz2DE/GRIlfNK2HgKW6KXA8RZMy8aL4MA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@stablelib/ed25519": "^1.0.2",
|
||||||
|
"bigint-mod-arith": "^3.1.0",
|
||||||
|
"multiformats": "^9.5.2",
|
||||||
|
"nist-weierstrauss": "^1.3.0",
|
||||||
|
"uint8arrays": "^3.0.0",
|
||||||
|
"varint": "^6.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"multiformats": {
|
||||||
|
"version": "9.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz",
|
||||||
|
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"uint8arrays": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"multiformats": "^9.4.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"keyv": {
|
"keyv": {
|
||||||
"version": "4.5.2",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz",
|
||||||
@ -41710,6 +41873,33 @@
|
|||||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"nist-weierstrauss": {
|
||||||
|
"version": "1.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/nist-weierstrauss/-/nist-weierstrauss-1.6.1.tgz",
|
||||||
|
"integrity": "sha512-FpjCOnPV/s3ZVIkeldCVSml2K4lruabPbBgoEitpCK1JL0KTVoWb56CFTU6rZn5i6VqAjdwcOp0FDwJACPmeFA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"multiformats": "^9.6.5",
|
||||||
|
"uint8arrays": "^2.1.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"multiformats": {
|
||||||
|
"version": "9.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz",
|
||||||
|
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"uint8arrays": {
|
||||||
|
"version": "2.1.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-2.1.10.tgz",
|
||||||
|
"integrity": "sha512-Q9/hhJa2836nQfEJSZTmr+pg9+cDJS9XEAp7N2Vg5MzL3bK/mkMVfjscRGYruP9jNda6MAdf4QD/y78gSzkp6A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"multiformats": "^9.4.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"no-case": {
|
"no-case": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
||||||
|
@ -53,8 +53,8 @@
|
|||||||
"go-ipfs": "^0.17.0",
|
"go-ipfs": "^0.17.0",
|
||||||
"ipfs": "^0.66.0",
|
"ipfs": "^0.66.0",
|
||||||
"ipfsd-ctl": "^13.0.0",
|
"ipfsd-ctl": "^13.0.0",
|
||||||
"localstorage-down": "^0.6.7",
|
"key-did-provider-ed25519": "^2.0.1",
|
||||||
"localstorage-level-migration": "^0.2.0",
|
"key-did-resolver": "^2.3.0",
|
||||||
"markdown-toc": "^1.2.0",
|
"markdown-toc": "^1.2.0",
|
||||||
"mkdirp": "^2.1.1",
|
"mkdirp": "^2.1.1",
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
|
177
src/identities/identity-provider.js
Normal file
177
src/identities/identity-provider.js
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import Identity from './identity.js'
|
||||||
|
import IdentityProvider from './providers/interface.js'
|
||||||
|
import OrbitDBIdentityProvider from './providers/orbitdb.js'
|
||||||
|
// import DIDIdentityProvider from './identity-providers/did.js'
|
||||||
|
// import EthIdentityProvider from './identity-providers/ethereum.js'
|
||||||
|
import KeyStore from '../key-store.js'
|
||||||
|
import IdentityStorage from '../storage/identity.js'
|
||||||
|
import LRU from 'lru'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
const defaultType = 'orbitdb'
|
||||||
|
const identityKeysPath = path.join('./orbitdb', 'identity', 'identitykeys')
|
||||||
|
|
||||||
|
const supportedTypes = {
|
||||||
|
orbitdb: OrbitDBIdentityProvider
|
||||||
|
// [DIDIdentityProvider.type]: DIDIdentityProvider,
|
||||||
|
// [EthIdentityProvider.type]: EthIdentityProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
const getHandlerFor = (type) => {
|
||||||
|
if (!Identities.isSupported(type)) {
|
||||||
|
throw new Error(`IdentityProvider type '${type}' is not supported`)
|
||||||
|
}
|
||||||
|
return supportedTypes[type]
|
||||||
|
}
|
||||||
|
|
||||||
|
class Identities {
|
||||||
|
constructor (options) {
|
||||||
|
this._keystore = options.keystore
|
||||||
|
this._signingKeyStore = options.signingKeyStore || this._keystore
|
||||||
|
this._knownIdentities = options.cache || new LRU(options.cacheSize || 100)
|
||||||
|
this._storage = options.identityStore
|
||||||
|
}
|
||||||
|
|
||||||
|
static get IdentityProvider () { return IdentityProvider }
|
||||||
|
|
||||||
|
get keystore () { return this._keystore }
|
||||||
|
|
||||||
|
get signingKeyStore () { return this._signingKeyStore }
|
||||||
|
|
||||||
|
async sign (identity, data) {
|
||||||
|
const signingKey = await this.keystore.getKey(identity.id)
|
||||||
|
if (!signingKey) {
|
||||||
|
throw new Error('Private signing key not found from KeyStore')
|
||||||
|
}
|
||||||
|
const sig = await this.keystore.sign(signingKey, data)
|
||||||
|
return sig
|
||||||
|
}
|
||||||
|
|
||||||
|
async verify (signature, publicKey, data, verifier = 'v1') {
|
||||||
|
return this.keystore.verify(signature, publicKey, data, verifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
async createIdentity (options = {}) {
|
||||||
|
const keystore = options.keystore || this.keystore
|
||||||
|
const type = options.type || defaultType
|
||||||
|
const identityProvider = type === defaultType ? new OrbitDBIdentityProvider(options.signingKeyStore || keystore) : new (getHandlerFor(type))(options)
|
||||||
|
const id = await identityProvider.getId(options)
|
||||||
|
|
||||||
|
const { publicKey, idSignature } = await this.signId(id)
|
||||||
|
const pubKeyIdSignature = await identityProvider.signIdentity(publicKey + idSignature, options)
|
||||||
|
// return new Identity(id, publicKey, idSignature, pubKeyIdSignature, type, this)
|
||||||
|
const identity = new Identity(id, publicKey, idSignature, pubKeyIdSignature, type, this)
|
||||||
|
await identity.store()
|
||||||
|
// const hash = options.identityStore.put(identity.toJSON())
|
||||||
|
return identity
|
||||||
|
}
|
||||||
|
|
||||||
|
async get (hash) {
|
||||||
|
return this._storage.get(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
async signId (id) {
|
||||||
|
const keystore = this.keystore
|
||||||
|
const key = await keystore.getKey(id) || await keystore.createKey(id)
|
||||||
|
const publicKey = keystore.getPublic(key)
|
||||||
|
const idSignature = await keystore.sign(key, id)
|
||||||
|
return { publicKey, idSignature }
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyIdentity (identity) {
|
||||||
|
if (!Identity.isIdentity(identity)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const knownID = this._knownIdentities.get(identity.signatures.id)
|
||||||
|
if (knownID) {
|
||||||
|
return identity.id === knownID.id &&
|
||||||
|
identity.publicKey === knownID.publicKey &&
|
||||||
|
identity.signatures.id === knownID.signatures.id &&
|
||||||
|
identity.signatures.publicKey === knownID.signatures.publicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
const verifyIdSig = await this.keystore.verify(
|
||||||
|
identity.signatures.id,
|
||||||
|
identity.publicKey,
|
||||||
|
identity.id
|
||||||
|
)
|
||||||
|
if (!verifyIdSig) return false
|
||||||
|
|
||||||
|
const IdentityProvider = getHandlerFor(identity.type)
|
||||||
|
const verified = await IdentityProvider.verifyIdentity(identity)
|
||||||
|
if (verified) {
|
||||||
|
this._knownIdentities.set(identity.signatures.id, Identity.toJSON(identity))
|
||||||
|
}
|
||||||
|
|
||||||
|
return verified
|
||||||
|
}
|
||||||
|
|
||||||
|
static async verifyIdentity (identity) {
|
||||||
|
if (!Identity.isIdentity(identity)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const verifyIdSig = await KeyStore.verify(
|
||||||
|
identity.signatures.id,
|
||||||
|
identity.publicKey,
|
||||||
|
identity.id
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!verifyIdSig) return false
|
||||||
|
|
||||||
|
const IdentityProvider = getHandlerFor(identity.type)
|
||||||
|
return IdentityProvider.verifyIdentity(identity)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async createIdentity (options = {}) {
|
||||||
|
if (!options.keystore) {
|
||||||
|
options.keystore = new KeyStore(options.identityKeysPath || identityKeysPath)
|
||||||
|
}
|
||||||
|
if (!options.signingKeyStore) {
|
||||||
|
if (options.signingKeysPath) {
|
||||||
|
options.signingKeyStore = new KeyStore(options.signingKeysPath)
|
||||||
|
} else {
|
||||||
|
options.signingKeyStore = options.keystore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await options.keystore.open()
|
||||||
|
await options.signingKeyStore.open()
|
||||||
|
|
||||||
|
let identityStore
|
||||||
|
if (options.storage) {
|
||||||
|
identityStore = await IdentityStorage({ storage: options.storage })
|
||||||
|
} else if (options.ipfs) {
|
||||||
|
identityStore = await IdentityStorage({ ipfs: options.ipfs })
|
||||||
|
} else {
|
||||||
|
identityStore = await IdentityStorage()
|
||||||
|
}
|
||||||
|
|
||||||
|
options = Object.assign({}, { type: defaultType, identityStore }, options)
|
||||||
|
const identities = new Identities(options)
|
||||||
|
return identities.createIdentity(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
static isSupported (type) {
|
||||||
|
return Object.keys(supportedTypes).includes(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
static addIdentityProvider (IdentityProvider) {
|
||||||
|
if (!IdentityProvider) {
|
||||||
|
throw new Error('IdentityProvider class needs to be given as an option')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IdentityProvider.type ||
|
||||||
|
typeof IdentityProvider.type !== 'string') {
|
||||||
|
throw new Error('Given IdentityProvider class needs to implement: static get type() { /* return a string */ }.')
|
||||||
|
}
|
||||||
|
|
||||||
|
supportedTypes[IdentityProvider.type] = IdentityProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
static removeIdentityProvider (type) {
|
||||||
|
delete supportedTypes[type]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Identities as default, Identity }
|
@ -1,180 +1,2 @@
|
|||||||
import Identity from './identity.js'
|
export { default as IdentityProvider } from './identity-provider.js'
|
||||||
import IdentityProvider from './providers/interface.js'
|
export { default as Identity } from './identity.js'
|
||||||
import OrbitDBIdentityProvider from './providers/orbitdb.js'
|
|
||||||
// import DIDIdentityProvider from './identity-providers/did.js'
|
|
||||||
// import EthIdentityProvider from './identity-providers/ethereum.js'
|
|
||||||
import KeyStore from '../key-store.js'
|
|
||||||
import IdentityStorage from '../storage/identity.js'
|
|
||||||
import LRU from 'lru'
|
|
||||||
import path from 'path'
|
|
||||||
|
|
||||||
const defaultType = 'orbitdb'
|
|
||||||
const identityKeysPath = path.join('./orbitdb', 'identity', 'identitykeys')
|
|
||||||
|
|
||||||
const supportedTypes = {
|
|
||||||
orbitdb: OrbitDBIdentityProvider
|
|
||||||
// [DIDIdentityProvider.type]: DIDIdentityProvider,
|
|
||||||
// [EthIdentityProvider.type]: EthIdentityProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
const getHandlerFor = (type) => {
|
|
||||||
if (!Identities.isSupported(type)) {
|
|
||||||
throw new Error(`IdentityProvider type '${type}' is not supported`)
|
|
||||||
}
|
|
||||||
return supportedTypes[type]
|
|
||||||
}
|
|
||||||
|
|
||||||
class Identities {
|
|
||||||
constructor (options) {
|
|
||||||
this._keystore = options.keystore
|
|
||||||
this._signingKeyStore = options.signingKeyStore || this._keystore
|
|
||||||
this._knownIdentities = options.cache || new LRU(options.cacheSize || 100)
|
|
||||||
this._storage = options.identityStore
|
|
||||||
}
|
|
||||||
|
|
||||||
static get IdentityProvider () { return IdentityProvider }
|
|
||||||
|
|
||||||
get keystore () { return this._keystore }
|
|
||||||
|
|
||||||
get signingKeyStore () { return this._signingKeyStore }
|
|
||||||
|
|
||||||
async sign (identity, data) {
|
|
||||||
const signingKey = await this.keystore.getKey(identity.id)
|
|
||||||
if (!signingKey) {
|
|
||||||
throw new Error('Private signing key not found from KeyStore')
|
|
||||||
}
|
|
||||||
const sig = await this.keystore.sign(signingKey, data)
|
|
||||||
return sig
|
|
||||||
}
|
|
||||||
|
|
||||||
async verify (signature, publicKey, data, verifier = 'v1') {
|
|
||||||
return this.keystore.verify(signature, publicKey, data, verifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
async createIdentity (options = {}) {
|
|
||||||
const keystore = options.keystore || this.keystore
|
|
||||||
const type = options.type || defaultType
|
|
||||||
const identityProvider = type === defaultType ? new OrbitDBIdentityProvider(options.signingKeyStore || keystore) : new (getHandlerFor(type))(options)
|
|
||||||
const id = await identityProvider.getId(options)
|
|
||||||
|
|
||||||
if (options.migrate) {
|
|
||||||
await options.migrate({ targetStore: keystore._store, targetId: id })
|
|
||||||
}
|
|
||||||
const { publicKey, idSignature } = await this.signId(id)
|
|
||||||
const pubKeyIdSignature = await identityProvider.signIdentity(publicKey + idSignature, options)
|
|
||||||
// return new Identity(id, publicKey, idSignature, pubKeyIdSignature, type, this)
|
|
||||||
const identity = new Identity(id, publicKey, idSignature, pubKeyIdSignature, type, this)
|
|
||||||
await identity.store()
|
|
||||||
// const hash = options.identityStore.put(identity.toJSON())
|
|
||||||
return identity
|
|
||||||
}
|
|
||||||
|
|
||||||
async get (hash) {
|
|
||||||
return this._storage.get(hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
async signId (id) {
|
|
||||||
const keystore = this.keystore
|
|
||||||
const key = await keystore.getKey(id) || await keystore.createKey(id)
|
|
||||||
const publicKey = keystore.getPublic(key)
|
|
||||||
const idSignature = await keystore.sign(key, id)
|
|
||||||
return { publicKey, idSignature }
|
|
||||||
}
|
|
||||||
|
|
||||||
async verifyIdentity (identity) {
|
|
||||||
if (!Identity.isIdentity(identity)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const knownID = this._knownIdentities.get(identity.signatures.id)
|
|
||||||
if (knownID) {
|
|
||||||
return identity.id === knownID.id &&
|
|
||||||
identity.publicKey === knownID.publicKey &&
|
|
||||||
identity.signatures.id === knownID.signatures.id &&
|
|
||||||
identity.signatures.publicKey === knownID.signatures.publicKey
|
|
||||||
}
|
|
||||||
|
|
||||||
const verifyIdSig = await this.keystore.verify(
|
|
||||||
identity.signatures.id,
|
|
||||||
identity.publicKey,
|
|
||||||
identity.id
|
|
||||||
)
|
|
||||||
if (!verifyIdSig) return false
|
|
||||||
|
|
||||||
const IdentityProvider = getHandlerFor(identity.type)
|
|
||||||
const verified = await IdentityProvider.verifyIdentity(identity)
|
|
||||||
if (verified) {
|
|
||||||
this._knownIdentities.set(identity.signatures.id, Identity.toJSON(identity))
|
|
||||||
}
|
|
||||||
|
|
||||||
return verified
|
|
||||||
}
|
|
||||||
|
|
||||||
static async verifyIdentity (identity) {
|
|
||||||
if (!Identity.isIdentity(identity)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const verifyIdSig = await KeyStore.verify(
|
|
||||||
identity.signatures.id,
|
|
||||||
identity.publicKey,
|
|
||||||
identity.id
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!verifyIdSig) return false
|
|
||||||
|
|
||||||
const IdentityProvider = getHandlerFor(identity.type)
|
|
||||||
return IdentityProvider.verifyIdentity(identity)
|
|
||||||
}
|
|
||||||
|
|
||||||
static async createIdentity (options = {}) {
|
|
||||||
if (!options.keystore) {
|
|
||||||
options.keystore = new KeyStore(options.identityKeysPath || identityKeysPath)
|
|
||||||
}
|
|
||||||
if (!options.signingKeyStore) {
|
|
||||||
if (options.signingKeysPath) {
|
|
||||||
options.signingKeyStore = new KeyStore(options.signingKeysPath)
|
|
||||||
} else {
|
|
||||||
options.signingKeyStore = options.keystore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await options.keystore.open()
|
|
||||||
await options.signingKeyStore.open()
|
|
||||||
|
|
||||||
let identityStore
|
|
||||||
if (options.storage) {
|
|
||||||
identityStore = await IdentityStorage({ storage: options.storage })
|
|
||||||
} else if (options.ipfs) {
|
|
||||||
identityStore = await IdentityStorage({ ipfs: options.ipfs })
|
|
||||||
} else {
|
|
||||||
identityStore = await IdentityStorage()
|
|
||||||
}
|
|
||||||
|
|
||||||
options = Object.assign({}, { type: defaultType, identityStore }, options)
|
|
||||||
const identities = new Identities(options)
|
|
||||||
return identities.createIdentity(options)
|
|
||||||
}
|
|
||||||
|
|
||||||
static isSupported (type) {
|
|
||||||
return Object.keys(supportedTypes).includes(type)
|
|
||||||
}
|
|
||||||
|
|
||||||
static addIdentityProvider (IdentityProvider) {
|
|
||||||
if (!IdentityProvider) {
|
|
||||||
throw new Error('IdentityProvider class needs to be given as an option')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IdentityProvider.type ||
|
|
||||||
typeof IdentityProvider.type !== 'string') {
|
|
||||||
throw new Error('Given IdentityProvider class needs to implement: static get type() { /* return a string */ }.')
|
|
||||||
}
|
|
||||||
|
|
||||||
supportedTypes[IdentityProvider.type] = IdentityProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
static removeIdentityProvider (type) {
|
|
||||||
delete supportedTypes[type]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { Identities as default, Identity }
|
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
export { Log, DefaultAccessController, Entry } from './oplog/index.js'
|
export { Log, DefaultAccessController, Entry } from './oplog/index.js'
|
||||||
export { default as KeyStore } from './key-store.js'
|
export { default as KeyStore } from './key-store.js'
|
||||||
|
export { IdentityProvider } from './identities/index.js'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { deepStrictEqual, strictEqual } from 'assert'
|
import { deepStrictEqual, strictEqual } from 'assert'
|
||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { Log, Entry } from '../src/oplog/index.js'
|
import { Log, Entry } from '../src/oplog/index.js'
|
||||||
import IdentityProvider from '../src/identities/index.js'
|
import { IdentityProvider } from '../src/identities/index.js'
|
||||||
import KeyStore from '../src/key-store.js'
|
import KeyStore from '../src/key-store.js'
|
||||||
import { DocumentStore, Database } from '../src/db/index.js'
|
import { DocumentStore, Database } from '../src/db/index.js'
|
||||||
import { IPFSBlockStorage, LevelStorage } from '../src/storage/index.js'
|
import { IPFSBlockStorage, LevelStorage } from '../src/storage/index.js'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { deepStrictEqual, strictEqual } from 'assert'
|
import { deepStrictEqual, strictEqual } from 'assert'
|
||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { Log, Entry } from '../src/oplog/index.js'
|
import { Log, Entry } from '../src/oplog/index.js'
|
||||||
import IdentityProvider from '../src/identities/index.js'
|
import { IdentityProvider } from '../src/identities/index.js'
|
||||||
import KeyStore from '../src/key-store.js'
|
import KeyStore from '../src/key-store.js'
|
||||||
import { EventStore, Database } from '../src/db/index.js'
|
import { EventStore, Database } from '../src/db/index.js'
|
||||||
import { IPFSBlockStorage, LevelStorage } from '../src/storage/index.js'
|
import { IPFSBlockStorage, LevelStorage } from '../src/storage/index.js'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { deepStrictEqual, strictEqual } from 'assert'
|
import { deepStrictEqual, strictEqual } from 'assert'
|
||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { Log, Entry } from '../src/oplog/index.js'
|
import { Log, Entry } from '../src/oplog/index.js'
|
||||||
import IdentityProvider from '../src/identities/index.js'
|
import { IdentityProvider } from '../src/identities/index.js'
|
||||||
import KeyStore from '../src/key-store.js'
|
import KeyStore from '../src/key-store.js'
|
||||||
import { Feed, Database } from '../src/db/index.js'
|
import { Feed, Database } from '../src/db/index.js'
|
||||||
import { IPFSBlockStorage, LevelStorage } from '../src/storage/index.js'
|
import { IPFSBlockStorage, LevelStorage } from '../src/storage/index.js'
|
||||||
|
2
test/fixtures/orbit-db-identity-keys.js
vendored
2
test/fixtures/orbit-db-identity-keys.js
vendored
@ -1,5 +1,5 @@
|
|||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
|
|
||||||
const { createIdentity } = IdentityProvider
|
const { createIdentity } = IdentityProvider
|
||||||
|
BIN
test/identies/fixtures/keys/000005.ldb
Normal file
BIN
test/identies/fixtures/keys/000005.ldb
Normal file
Binary file not shown.
0
test/identies/fixtures/keys/000032.log
Normal file
0
test/identies/fixtures/keys/000032.log
Normal file
1
test/identies/fixtures/keys/CURRENT
Normal file
1
test/identies/fixtures/keys/CURRENT
Normal file
@ -0,0 +1 @@
|
|||||||
|
MANIFEST-000031
|
0
test/identies/fixtures/keys/LOCK
Normal file
0
test/identies/fixtures/keys/LOCK
Normal file
3
test/identies/fixtures/keys/LOG
Normal file
3
test/identies/fixtures/keys/LOG
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
2023/02/16-14:47:21.736625 171233000 Recovering log #30
|
||||||
|
2023/02/16-14:47:21.737020 171233000 Delete type=3 #29
|
||||||
|
2023/02/16-14:47:21.737069 171233000 Delete type=0 #30
|
3
test/identies/fixtures/keys/LOG.old
Normal file
3
test/identies/fixtures/keys/LOG.old
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
2023/02/16-14:46:59.857680 16e03b000 Recovering log #28
|
||||||
|
2023/02/16-14:46:59.858826 16e03b000 Delete type=0 #28
|
||||||
|
2023/02/16-14:46:59.858852 16e03b000 Delete type=3 #27
|
BIN
test/identies/fixtures/keys/MANIFEST-000031
Normal file
BIN
test/identies/fixtures/keys/MANIFEST-000031
Normal file
Binary file not shown.
28
test/identities/browser.spec.js
Normal file
28
test/identities/browser.spec.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// import path from 'path'
|
||||||
|
// import isNode from 'is-node'
|
||||||
|
|
||||||
|
// // This file will be picked up by webpack into the
|
||||||
|
// // tests bundle and the code here gets run when imported
|
||||||
|
// // into the browser tests index through browser/run.js
|
||||||
|
// if (!isNode) {
|
||||||
|
// const existingKey = (await import('./fixtures/keys/existing.json')).default
|
||||||
|
// const testKey1 = (await import('./fixtures/keys/QmPhnEjVkYE1Ym7F5MkRUfkD6NtuSptE7ugu1Ggr149W2X.json')).default
|
||||||
|
// const testKey2 = (await import('./fixtures/keys/0260baeaffa1de1e4135e5b395e0380563a622b9599d1b8e012a0f7603f516bdaa.json')).default
|
||||||
|
|
||||||
|
// // If in browser, put the fixture keys in local storage
|
||||||
|
// // so that Keystore can find them
|
||||||
|
// const levelup = (await import('levelup')).default
|
||||||
|
// const level = (await import('level-js')).default
|
||||||
|
// const storagePath = path.resolve('./test/fixtures/savedKeys')
|
||||||
|
// const signingStore = levelup(level(storagePath))
|
||||||
|
|
||||||
|
// const copyFixtures = []
|
||||||
|
// copyFixtures.push(signingStore)
|
||||||
|
|
||||||
|
// /* global localStorage */
|
||||||
|
// copyFixtures.push(localStorage.setItem('existing.json', JSON.stringify(existingKey)))
|
||||||
|
// copyFixtures.push(signingStore.put('QmPhnEjVkYE1Ym7F5MkRUfkD6NtuSptE7ugu1Ggr149W2X', JSON.stringify(testKey1)))
|
||||||
|
// copyFixtures.push(signingStore.put('0260baeaffa1de1e4135e5b395e0380563a622b9599d1b8e012a0f7603f516bdaa', JSON.stringify(testKey2)))
|
||||||
|
|
||||||
|
// Promise.all(copyFixtures)
|
||||||
|
// }
|
21
test/identities/browser/index.html
Normal file
21
test/identities/browser/index.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Mocha Tests</title>
|
||||||
|
<link href="https://unpkg.com/mocha@4.0.1/mocha.css" rel="stylesheet" />
|
||||||
|
<script src="https://unpkg.com/mocha@5.2.0/mocha.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="mocha"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
mocha.setup("bdd");
|
||||||
|
</script>
|
||||||
|
<script src="./bundle.js"></script>
|
||||||
|
<script>
|
||||||
|
mocha.checkLeaks()
|
||||||
|
mocha.run();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
138
test/identities/did-identity-provider.spec.js
Normal file
138
test/identities/did-identity-provider.spec.js
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import assert from 'assert'
|
||||||
|
import path from 'path'
|
||||||
|
import rmrf from 'rimraf'
|
||||||
|
import { KeyStore, IdentityProvider } from '../../src/index.js'
|
||||||
|
import { Identity } from '../../src/identities/index.js'
|
||||||
|
import { Ed25519Provider } from 'key-did-provider-ed25519'
|
||||||
|
import KeyDidResolver from 'key-did-resolver'
|
||||||
|
import DIDIdentityProvider from '../../src/identities/providers/did.js'
|
||||||
|
const keypath = path.resolve('./test/identies/fixtures/keys')
|
||||||
|
let keystore
|
||||||
|
|
||||||
|
const seed = new Uint8Array([157, 94, 116, 198, 19, 248, 93, 239, 173, 82, 245, 222, 199, 7, 183, 177, 123, 238, 83, 240, 143, 188, 87, 191, 33, 95, 58, 136, 46, 218, 219, 245])
|
||||||
|
const didStr = 'did:key:z6MkpnTJwrrVuphNh1uKb5DB7eRxvqniVaSDUHU6jtGVmn3r'
|
||||||
|
|
||||||
|
const type = DIDIdentityProvider.type
|
||||||
|
describe('DID Identity Provider', function () {
|
||||||
|
before(async () => {
|
||||||
|
DIDIdentityProvider.setDIDResolver(KeyDidResolver.getResolver())
|
||||||
|
IdentityProvider.addIdentityProvider(DIDIdentityProvider)
|
||||||
|
keystore = new KeyStore(keypath)
|
||||||
|
await keystore.open()
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await keystore.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('create an DID identity', () => {
|
||||||
|
let identity
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
const didProvider = new Ed25519Provider(seed)
|
||||||
|
identity = await IdentityProvider.createIdentity({ type, keystore, didProvider })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct id', async () => {
|
||||||
|
assert.strictEqual(identity.id, didStr)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('created a key for id in keystore', async () => {
|
||||||
|
const key = await keystore.getKey(didStr)
|
||||||
|
assert.notStrictEqual(key, undefined)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct public key', async () => {
|
||||||
|
const signingKey = await keystore.getKey(didStr)
|
||||||
|
assert.notStrictEqual(signingKey, undefined)
|
||||||
|
assert.strictEqual(identity.publicKey, keystore.getPublic(signingKey))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a signature for the id', async () => {
|
||||||
|
const signingKey = await keystore.getKey(didStr)
|
||||||
|
const idSignature = await keystore.sign(signingKey, didStr)
|
||||||
|
const verifies = await KeyStore.verify(idSignature, identity.publicKey, didStr)
|
||||||
|
assert.strictEqual(verifies, true)
|
||||||
|
assert.strictEqual(identity.signatures.id, idSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a signature for the publicKey', async () => {
|
||||||
|
const signingKey = await keystore.getKey(didStr)
|
||||||
|
const idSignature = await keystore.sign(signingKey, didStr)
|
||||||
|
assert.notStrictEqual(idSignature, undefined)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('verify identity', () => {
|
||||||
|
let identity
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
const didProvider = new Ed25519Provider(seed)
|
||||||
|
identity = await IdentityProvider.createIdentity({ type, keystore, didProvider })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('DID identity verifies', async () => {
|
||||||
|
const verified = await IdentityProvider.verifyIdentity(identity)
|
||||||
|
assert.strictEqual(verified, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('DID identity with incorrect id does not verify', async () => {
|
||||||
|
const identity2 = new Identity('NotAnId', identity.publicKey, identity.signatures.id, identity.signatures.publicKey, identity.type, identity.provider)
|
||||||
|
const verified = await IdentityProvider.verifyIdentity(identity2)
|
||||||
|
assert.strictEqual(verified, false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('sign data with an identity', () => {
|
||||||
|
let identity
|
||||||
|
const data = 'hello friend'
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
const didProvider = new Ed25519Provider(seed)
|
||||||
|
identity = await IdentityProvider.createIdentity({ type, keystore, didProvider })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sign data', async () => {
|
||||||
|
const signingKey = await keystore.getKey(identity.id)
|
||||||
|
const expectedSignature = await keystore.sign(signingKey, data)
|
||||||
|
const signature = await identity.provider.sign(identity, data, keystore)
|
||||||
|
assert.strictEqual(signature, expectedSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an error if private key is not found from keystore', async () => {
|
||||||
|
// Remove the key from the keystore (we're using a mock storage in these tests)
|
||||||
|
const modifiedIdentity = new Identity('this id does not exist', identity.publicKey, '<sig>', identity.signatures, identity.type, identity.provider)
|
||||||
|
let signature
|
||||||
|
let err
|
||||||
|
try {
|
||||||
|
signature = await identity.provider.sign(modifiedIdentity, data, keystore)
|
||||||
|
} catch (e) {
|
||||||
|
err = e.toString()
|
||||||
|
}
|
||||||
|
assert.strictEqual(signature, undefined)
|
||||||
|
assert.strictEqual(err, 'Error: Private signing key not found from KeyStore')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('verify data signed by an identity', () => {
|
||||||
|
const data = 'hello friend'
|
||||||
|
let identity
|
||||||
|
let signature
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
const didProvider = new Ed25519Provider(seed)
|
||||||
|
identity = await IdentityProvider.createIdentity({ type, keystore, didProvider })
|
||||||
|
signature = await identity.provider.sign(identity, data, keystore)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('verifies that the signature is valid', async () => {
|
||||||
|
const verified = await identity.provider.verify(signature, identity.publicKey, data)
|
||||||
|
assert.strictEqual(verified, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('doesn\'t verify invalid signature', async () => {
|
||||||
|
const verified = await identity.provider.verify('invalid', identity.publicKey, data)
|
||||||
|
assert.strictEqual(verified, false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
133
test/identities/ethereum-identity-provider.spec.js
Normal file
133
test/identities/ethereum-identity-provider.spec.js
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import assert from 'assert'
|
||||||
|
import path from 'path'
|
||||||
|
import rmrf from 'rimraf'
|
||||||
|
import { KeyStore, IdentityProvider } from '../../src/index.js'
|
||||||
|
import { Identity } from '../../src/identities/index.js'
|
||||||
|
import EthIdentityProvider from '../../src/identities/providers/ethereum.js'
|
||||||
|
|
||||||
|
const keypath = path.resolve('./test/identities/fixtures/keys')
|
||||||
|
let keystore
|
||||||
|
|
||||||
|
const type = EthIdentityProvider.type
|
||||||
|
describe('Ethereum Identity Provider', function () {
|
||||||
|
before(async () => {
|
||||||
|
IdentityProvider.addIdentityProvider(EthIdentityProvider)
|
||||||
|
keystore = new KeyStore(keypath)
|
||||||
|
await keystore.open()
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await keystore.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('create an ethereum identity', () => {
|
||||||
|
let identity
|
||||||
|
let wallet
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
const ethIdentityProvider = new EthIdentityProvider()
|
||||||
|
wallet = await ethIdentityProvider._createWallet()
|
||||||
|
identity = await IdentityProvider.createIdentity({ type, keystore, wallet })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct id', async () => {
|
||||||
|
assert.strictEqual(identity.id, wallet.address)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('created a key for id in keystore', async () => {
|
||||||
|
const key = await keystore.getKey(wallet.address)
|
||||||
|
assert.notStrictEqual(key, undefined)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct public key', async () => {
|
||||||
|
const signingKey = await keystore.getKey(wallet.address)
|
||||||
|
assert.notStrictEqual(signingKey, undefined)
|
||||||
|
assert.strictEqual(identity.publicKey, keystore.getPublic(signingKey))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a signature for the id', async () => {
|
||||||
|
const signingKey = await keystore.getKey(wallet.address)
|
||||||
|
const idSignature = await keystore.sign(signingKey, wallet.address)
|
||||||
|
const verifies = await KeyStore.verify(idSignature, Buffer.from(signingKey.public.marshal()).toString('hex'), wallet.address)
|
||||||
|
assert.strictEqual(verifies, true)
|
||||||
|
assert.strictEqual(identity.signatures.id, idSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a signature for the publicKey', async () => {
|
||||||
|
const signingKey = await keystore.getKey(wallet.address)
|
||||||
|
const idSignature = await keystore.sign(signingKey, wallet.address)
|
||||||
|
const publicKeyAndIdSignature = await wallet.signMessage(identity.publicKey + idSignature)
|
||||||
|
assert.strictEqual(identity.signatures.publicKey, publicKeyAndIdSignature)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('verify identity', () => {
|
||||||
|
let identity
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
identity = await IdentityProvider.createIdentity({ keystore, type })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('ethereum identity verifies', async () => {
|
||||||
|
const verified = await IdentityProvider.verifyIdentity(identity)
|
||||||
|
assert.strictEqual(verified, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('ethereum identity with incorrect id does not verify', async () => {
|
||||||
|
const identity2 = new Identity('NotAnId', identity.publicKey, identity.signatures.id, identity.signatures.publicKey, identity.type, identity.provider)
|
||||||
|
const verified = await IdentityProvider.verifyIdentity(identity2)
|
||||||
|
assert.strictEqual(verified, false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('sign data with an identity', () => {
|
||||||
|
let identity
|
||||||
|
const data = 'hello friend'
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
identity = await IdentityProvider.createIdentity({ keystore, type })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sign data', async () => {
|
||||||
|
const signingKey = await keystore.getKey(identity.id)
|
||||||
|
const expectedSignature = await keystore.sign(signingKey, data)
|
||||||
|
const signature = await identity.provider.sign(identity, data, keystore)
|
||||||
|
assert.strictEqual(signature, expectedSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an error if private key is not found from keystore', async () => {
|
||||||
|
// Remove the key from the keystore (we're using a mock storage in these tests)
|
||||||
|
const modifiedIdentity = new Identity('this id does not exist', identity.publicKey, '<sig>', identity.signatures, identity.type, identity.provider)
|
||||||
|
let signature
|
||||||
|
let err
|
||||||
|
try {
|
||||||
|
signature = await identity.provider.sign(modifiedIdentity, data, keystore)
|
||||||
|
} catch (e) {
|
||||||
|
err = e.toString()
|
||||||
|
}
|
||||||
|
assert.strictEqual(signature, undefined)
|
||||||
|
assert.strictEqual(err, 'Error: Private signing key not found from KeyStore')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('verify data signed by an identity', () => {
|
||||||
|
const data = 'hello friend'
|
||||||
|
let identity
|
||||||
|
let signature
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
identity = await IdentityProvider.createIdentity({ type, keystore })
|
||||||
|
signature = await identity.provider.sign(identity, data, keystore)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('verifies that the signature is valid', async () => {
|
||||||
|
const verified = await identity.provider.verify(signature, identity.publicKey, data)
|
||||||
|
assert.strictEqual(verified, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('doesn\'t verify invalid signature', async () => {
|
||||||
|
const verified = await identity.provider.verify('invalid', identity.publicKey, data)
|
||||||
|
assert.strictEqual(verified, false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
BIN
test/identities/fixtures/keys/000046.ldb
Normal file
BIN
test/identities/fixtures/keys/000046.ldb
Normal file
Binary file not shown.
BIN
test/identities/fixtures/keys/000048.ldb
Normal file
BIN
test/identities/fixtures/keys/000048.ldb
Normal file
Binary file not shown.
BIN
test/identities/fixtures/keys/000051.ldb
Normal file
BIN
test/identities/fixtures/keys/000051.ldb
Normal file
Binary file not shown.
BIN
test/identities/fixtures/keys/000054.ldb
Normal file
BIN
test/identities/fixtures/keys/000054.ldb
Normal file
Binary file not shown.
BIN
test/identities/fixtures/keys/000055.log
Normal file
BIN
test/identities/fixtures/keys/000055.log
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
{"publicKey":"030d78ff62afb656ac62db1aae3b1536a614991e28bb4d721498898b7d41943396","privateKey":"6657f74ad8223ed8a169b12d4afbf1d368175e3f08b295d511131ee93c6cceeb"}
|
1
test/identities/fixtures/keys/CURRENT
Normal file
1
test/identities/fixtures/keys/CURRENT
Normal file
@ -0,0 +1 @@
|
|||||||
|
MANIFEST-000053
|
0
test/identities/fixtures/keys/LOCK
Normal file
0
test/identities/fixtures/keys/LOCK
Normal file
5
test/identities/fixtures/keys/LOG
Normal file
5
test/identities/fixtures/keys/LOG
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
2023/02/16-14:47:21.828619 170a2b000 Recovering log #52
|
||||||
|
2023/02/16-14:47:21.828667 170a2b000 Level-0 table #54: started
|
||||||
|
2023/02/16-14:47:21.828864 170a2b000 Level-0 table #54: 1279 bytes OK
|
||||||
|
2023/02/16-14:47:21.829422 170a2b000 Delete type=0 #52
|
||||||
|
2023/02/16-14:47:21.829490 170a2b000 Delete type=3 #50
|
5
test/identities/fixtures/keys/LOG.old
Normal file
5
test/identities/fixtures/keys/LOG.old
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
2023/02/16-14:46:59.958708 16e843000 Recovering log #49
|
||||||
|
2023/02/16-14:46:59.958747 16e843000 Level-0 table #51: started
|
||||||
|
2023/02/16-14:46:59.958926 16e843000 Level-0 table #51: 1279 bytes OK
|
||||||
|
2023/02/16-14:46:59.959275 16e843000 Delete type=3 #47
|
||||||
|
2023/02/16-14:46:59.959309 16e843000 Delete type=0 #49
|
BIN
test/identities/fixtures/keys/MANIFEST-000053
Normal file
BIN
test/identities/fixtures/keys/MANIFEST-000053
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
{"publicKey":"0260baeaffa1de1e4135e5b395e0380563a622b9599d1b8e012a0f7603f516bdaa","privateKey":"198594a8de39fd97017d11996d619b3746211605a9d290964badf58bc79bdb33"}
|
1
test/identities/fixtures/keys/existing.json
Normal file
1
test/identities/fixtures/keys/existing.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"publicKey":"045756c20f03ec494d07e8dd8456f67d6bd97ca175e6c4882435fe364392f131406db3a37eebe1d634b105a57b55e4f17247c1ec8ffe04d6a95d1e0ee8bed7cfbd","privateKey":"3928a45bc5642ddef4938d30b899563e7e142b1947c3bd02c313621e311dd07e"}
|
311
test/identities/identity-provider.spec.js
Normal file
311
test/identities/identity-provider.spec.js
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
import assert from 'assert'
|
||||||
|
import path from 'path'
|
||||||
|
import rmrf from 'rimraf'
|
||||||
|
import { KeyStore, IdentityProvider } from '../../src/index.js'
|
||||||
|
import { Identity } from '../../src/identities/index.js'
|
||||||
|
import fs from 'fs-extra'
|
||||||
|
const fixturesPath = path.resolve('./test/identities/fixtures/keys')
|
||||||
|
const savedKeysPath = path.resolve('./test/identities/fixtures/savedKeys')
|
||||||
|
const signingKeysPath = path.resolve('./test/identities/signingKeys')
|
||||||
|
const identityKeysPath = path.resolve('./test/identities/identityKeys')
|
||||||
|
const type = 'orbitdb'
|
||||||
|
|
||||||
|
describe('Identity Provider', function () {
|
||||||
|
before(async () => {
|
||||||
|
rmrf.sync(signingKeysPath)
|
||||||
|
rmrf.sync(identityKeysPath)
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
rmrf.sync(signingKeysPath)
|
||||||
|
rmrf.sync(identityKeysPath)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Creating IdentityProvider', () => {
|
||||||
|
const id = 'A'
|
||||||
|
let identity
|
||||||
|
|
||||||
|
it('identityKeysPath only - has the correct id', async () => {
|
||||||
|
identity = await IdentityProvider.createIdentity({ id, identityKeysPath })
|
||||||
|
const key = await identity.provider.keystore.getKey(id)
|
||||||
|
const externalId = Buffer.from(key.public.marshal()).toString('hex')
|
||||||
|
assert.strictEqual(identity.id, externalId)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('identityKeysPath and signingKeysPath - has a different id', async () => {
|
||||||
|
identity = await IdentityProvider.createIdentity({ id, identityKeysPath, signingKeysPath })
|
||||||
|
const key = await identity.provider.keystore.getKey(id)
|
||||||
|
const externalId = Buffer.from(key.public.marshal()).toString('hex')
|
||||||
|
assert.notStrictEqual(identity.id, externalId)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await identity.provider.keystore.close()
|
||||||
|
await identity.provider.signingKeyStore.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Passing in custom keystore', async () => {
|
||||||
|
const id = 'B'; let identity; let keystore; let signingKeyStore
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
keystore = new KeyStore(identityKeysPath)
|
||||||
|
await keystore.open()
|
||||||
|
signingKeyStore = new KeyStore(signingKeysPath)
|
||||||
|
await signingKeyStore.open()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct id', async () => {
|
||||||
|
identity = await IdentityProvider.createIdentity({ id, keystore })
|
||||||
|
keystore = identity.provider._keystore
|
||||||
|
const key = await keystore.getKey(id)
|
||||||
|
const externalId = Buffer.from(key.public.marshal()).toString('hex')
|
||||||
|
assert.strictEqual(identity.id, externalId)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it('created a key for id in identity-keystore', async () => {
|
||||||
|
const key = await keystore.getKey(id)
|
||||||
|
assert.notStrictEqual(key, undefined)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct public key', async () => {
|
||||||
|
const key = await keystore.getKey(id)
|
||||||
|
const externalId = Buffer.from(key.public.marshal()).toString('hex')
|
||||||
|
const signingKey = await keystore.getKey(externalId)
|
||||||
|
assert.notStrictEqual(signingKey, undefined)
|
||||||
|
assert.strictEqual(identity.publicKey, keystore.getPublic(signingKey))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a signature for the id', async () => {
|
||||||
|
const key = await keystore.getKey(id)
|
||||||
|
const externalId = Buffer.from(key.public.marshal()).toString('hex')
|
||||||
|
const signingKey = await keystore.getKey(externalId)
|
||||||
|
const idSignature = await keystore.sign(signingKey, externalId)
|
||||||
|
const publicKey = Buffer.from(signingKey.public.marshal()).toString('hex')
|
||||||
|
const verifies = await KeyStore.verify(idSignature, publicKey, externalId)
|
||||||
|
assert.strictEqual(verifies, true)
|
||||||
|
assert.strictEqual(identity.signatures.id, idSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a signature for the publicKey', async () => {
|
||||||
|
const key = await keystore.getKey(id)
|
||||||
|
const externalId = Buffer.from(key.public.marshal()).toString('hex')
|
||||||
|
const signingKey = await keystore.getKey(externalId)
|
||||||
|
const idSignature = await keystore.sign(signingKey, externalId)
|
||||||
|
const externalKey = await keystore.getKey(id)
|
||||||
|
const publicKeyAndIdSignature = await keystore.sign(externalKey, identity.publicKey + idSignature)
|
||||||
|
assert.strictEqual(identity.signatures.publicKey, publicKeyAndIdSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await keystore.close()
|
||||||
|
await signingKeyStore.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('create an identity with saved keys', () => {
|
||||||
|
let keystore, signingKeyStore
|
||||||
|
|
||||||
|
let savedKeysKeyStore, identity
|
||||||
|
const id = 'QmPhnEjVkYE1Ym7F5MkRUfkD6NtuSptE7ugu1Ggr149W2X'
|
||||||
|
|
||||||
|
const expectedPublicKey = '040d78ff62afb656ac62db1aae3b1536a614991e28bb4d721498898b7d4194339640cd18c37b259e2c77738de0d6f9a5d52e0b936611de6b6ba78891a8b2a38317'
|
||||||
|
const expectedIdSignature = '30450221009de7b91952d73f577e85962aa6301350865212e3956862f80f4ebb626ffc126b022027d57415fb145b7e06cf06320fbfa63ea98a958b065726fe86eaab809a6bf607'
|
||||||
|
const expectedPkIdSignature = '304402202806e7c2406ca1f35961d38adc3997c179e142d54e1ca838ace373fae27124fd02200d6ca3aea6e1341bf5e4e0b84b559bbeefecfade34115de266a69d04d924905e'
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
keystore = new KeyStore(identityKeysPath)
|
||||||
|
await keystore.open()
|
||||||
|
signingKeyStore = new KeyStore(signingKeysPath)
|
||||||
|
await signingKeyStore.open()
|
||||||
|
|
||||||
|
await fs.copy(fixturesPath, savedKeysPath)
|
||||||
|
savedKeysKeyStore = new KeyStore(savedKeysPath)
|
||||||
|
await savedKeysKeyStore.open()
|
||||||
|
identity = await IdentityProvider.createIdentity({ id, keystore: savedKeysKeyStore })
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
rmrf.sync(savedKeysPath)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct id', async () => {
|
||||||
|
const key = await savedKeysKeyStore.getKey(id)
|
||||||
|
assert.strictEqual(identity.id, Buffer.from(key.public.marshal()).toString('hex'))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct public key', async () => {
|
||||||
|
assert.strictEqual(identity.publicKey, expectedPublicKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct identity type', async () => {
|
||||||
|
assert.strictEqual(identity.type, type)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct idSignature', async () => {
|
||||||
|
assert.strictEqual(identity.signatures.id, expectedIdSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a pubKeyIdSignature for the publicKey', async () => {
|
||||||
|
assert.strictEqual(identity.signatures.publicKey, expectedPkIdSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct signatures', async () => {
|
||||||
|
const internalSigningKey = await savedKeysKeyStore.getKey(identity.id)
|
||||||
|
const externalSigningKey = await savedKeysKeyStore.getKey(id)
|
||||||
|
const idSignature = await savedKeysKeyStore.sign(internalSigningKey, identity.id)
|
||||||
|
const pubKeyIdSignature = await savedKeysKeyStore.sign(externalSigningKey, identity.publicKey + idSignature)
|
||||||
|
const expectedSignature = { id: idSignature, publicKey: pubKeyIdSignature }
|
||||||
|
assert.deepStrictEqual(identity.signatures, expectedSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await keystore.close()
|
||||||
|
await signingKeyStore.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('verify identity\'s signature', () => {
|
||||||
|
const id = 'QmFoo'
|
||||||
|
let identity, keystore, signingKeyStore
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
keystore = new KeyStore(identityKeysPath)
|
||||||
|
await keystore.open()
|
||||||
|
signingKeyStore = new KeyStore(signingKeysPath)
|
||||||
|
await signingKeyStore.open()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('identity pkSignature verifies', async () => {
|
||||||
|
identity = await IdentityProvider.createIdentity({ id, type, keystore, signingKeyStore })
|
||||||
|
const verified = await KeyStore.verify(identity.signatures.id, identity.publicKey, identity.id)
|
||||||
|
assert.strictEqual(verified, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('identity signature verifies', async () => {
|
||||||
|
identity = await IdentityProvider.createIdentity({ id, type, keystore, signingKeyStore })
|
||||||
|
const verified = await KeyStore.verify(identity.signatures.publicKey, identity.id, identity.publicKey + identity.signatures.id)
|
||||||
|
assert.strictEqual(verified, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('false signature doesn\'t verify', async () => {
|
||||||
|
class IP {
|
||||||
|
async getId () { return 'pubKey' }
|
||||||
|
|
||||||
|
async signIdentity (data) { return `false signature '${data}'` }
|
||||||
|
|
||||||
|
static async verifyIdentity (data) { return false }
|
||||||
|
|
||||||
|
static get type () { return 'fake' }
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentityProvider.addIdentityProvider(IP)
|
||||||
|
identity = await IdentityProvider.createIdentity({ type: IP.type, keystore, signingKeyStore })
|
||||||
|
const verified = await IdentityProvider.verifyIdentity(identity)
|
||||||
|
assert.strictEqual(verified, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await keystore.close()
|
||||||
|
await signingKeyStore.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('verify identity', () => {
|
||||||
|
const id = 'QmFoo'
|
||||||
|
let identity, keystore, signingKeyStore
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
keystore = new KeyStore(identityKeysPath)
|
||||||
|
await keystore.open()
|
||||||
|
signingKeyStore = new KeyStore(signingKeysPath)
|
||||||
|
await signingKeyStore.open()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('identity verifies', async () => {
|
||||||
|
identity = await IdentityProvider.createIdentity({ id, type, keystore, signingKeyStore })
|
||||||
|
const verified = await identity.provider.verifyIdentity(identity)
|
||||||
|
assert.strictEqual(verified, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await keystore.close()
|
||||||
|
await signingKeyStore.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('sign data with an identity', () => {
|
||||||
|
const id = '0x01234567890abcdefghijklmnopqrstuvwxyz'
|
||||||
|
const data = 'hello friend'
|
||||||
|
let identity, keystore, signingKeyStore
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
keystore = new KeyStore(identityKeysPath)
|
||||||
|
await keystore.open()
|
||||||
|
signingKeyStore = new KeyStore(signingKeysPath)
|
||||||
|
await signingKeyStore.open()
|
||||||
|
identity = await IdentityProvider.createIdentity({ id, keystore, signingKeyStore })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sign data', async () => {
|
||||||
|
const signingKey = await keystore.getKey(identity.id)
|
||||||
|
const expectedSignature = await keystore.sign(signingKey, data)
|
||||||
|
const signature = await identity.provider.sign(identity, data, keystore)
|
||||||
|
assert.strictEqual(signature, expectedSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an error if private key is not found from keystore', async () => {
|
||||||
|
// Remove the key from the keystore (we're using a mock storage in these tests)
|
||||||
|
const modifiedIdentity = new Identity('this id does not exist', identity.publicKey, '<sig>', identity.signatures, identity.type, identity.provider)
|
||||||
|
let signature
|
||||||
|
let err
|
||||||
|
try {
|
||||||
|
signature = await identity.provider.sign(modifiedIdentity, data, keystore)
|
||||||
|
} catch (e) {
|
||||||
|
err = e.toString()
|
||||||
|
}
|
||||||
|
assert.strictEqual(signature, undefined)
|
||||||
|
assert.strictEqual(err, 'Error: Private signing key not found from KeyStore')
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await keystore.close()
|
||||||
|
await signingKeyStore.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('verify data signed by an identity', () => {
|
||||||
|
const id = '03602a3da3eb35f1148e8028f141ec415ef7f6d4103443edbfec2a0711d716f53f'
|
||||||
|
const data = 'hello friend'
|
||||||
|
let identity, keystore, signingKeyStore
|
||||||
|
let signature
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
keystore = new KeyStore(identityKeysPath)
|
||||||
|
await keystore.open()
|
||||||
|
signingKeyStore = new KeyStore(signingKeysPath)
|
||||||
|
await signingKeyStore.open()
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
identity = await IdentityProvider.createIdentity({ id, type, keystore, signingKeyStore })
|
||||||
|
signature = await identity.provider.sign(identity, data, keystore)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('verifies that the signature is valid', async () => {
|
||||||
|
const verified = await identity.provider.verify(signature, identity.publicKey, data)
|
||||||
|
assert.strictEqual(verified, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('doesn\'t verify invalid signature', async () => {
|
||||||
|
const verified = await identity.provider.verify('invalid', identity.publicKey, data)
|
||||||
|
assert.strictEqual(verified, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await keystore.close()
|
||||||
|
await signingKeyStore.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
109
test/identities/identity.spec.js
Normal file
109
test/identities/identity.spec.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import assert from 'assert'
|
||||||
|
import { Identity } from '../../src/identities/index.js'
|
||||||
|
|
||||||
|
describe('Identity', function () {
|
||||||
|
const id = '0x01234567890abcdefghijklmnopqrstuvwxyz'
|
||||||
|
const publicKey = '<pubkey>'
|
||||||
|
const idSignature = 'signature for <id>'
|
||||||
|
const publicKeyAndIdSignature = 'signature for <publicKey + idSignature>'
|
||||||
|
const type = 'orbitdb'
|
||||||
|
const provider = 'IdentityProviderInstance'
|
||||||
|
|
||||||
|
let identity
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
identity = new Identity(id, publicKey, idSignature, publicKeyAndIdSignature, type, provider)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct id', async () => {
|
||||||
|
assert.strictEqual(identity.id, id)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct publicKey', async () => {
|
||||||
|
assert.strictEqual(identity.publicKey, publicKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct idSignature', async () => {
|
||||||
|
assert.strictEqual(identity.signatures.id, idSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct publicKeyAndIdSignature', async () => {
|
||||||
|
assert.strictEqual(identity.signatures.publicKey, publicKeyAndIdSignature)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct provider', async () => {
|
||||||
|
assert.deepStrictEqual(identity.provider, provider)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('converts identity to a JSON object', async () => {
|
||||||
|
const expected = {
|
||||||
|
id,
|
||||||
|
publicKey,
|
||||||
|
signatures: { id: idSignature, publicKey: publicKeyAndIdSignature },
|
||||||
|
type
|
||||||
|
}
|
||||||
|
assert.deepStrictEqual(identity.toJSON(), expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Constructor inputs', () => {
|
||||||
|
it('throws and error if id was not given in constructor', async () => {
|
||||||
|
let err
|
||||||
|
try {
|
||||||
|
identity = new Identity()
|
||||||
|
} catch (e) {
|
||||||
|
err = e.toString()
|
||||||
|
}
|
||||||
|
assert.strictEqual(err, 'Error: Identity id is required')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws and error if publicKey was not given in constructor', async () => {
|
||||||
|
let err
|
||||||
|
try {
|
||||||
|
identity = new Identity('abc')
|
||||||
|
} catch (e) {
|
||||||
|
err = e.toString()
|
||||||
|
}
|
||||||
|
assert.strictEqual(err, 'Error: Invalid public key')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws and error if identity signature was not given in constructor', async () => {
|
||||||
|
let err
|
||||||
|
try {
|
||||||
|
identity = new Identity('abc', publicKey)
|
||||||
|
} catch (e) {
|
||||||
|
err = e.toString()
|
||||||
|
}
|
||||||
|
assert.strictEqual(err, 'Error: Signature of the id (idSignature) is required')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws and error if identity signature was not given in constructor', async () => {
|
||||||
|
let err
|
||||||
|
try {
|
||||||
|
identity = new Identity('abc', publicKey, idSignature)
|
||||||
|
} catch (e) {
|
||||||
|
err = e.toString()
|
||||||
|
}
|
||||||
|
assert.strictEqual(err, 'Error: Signature of (publicKey + idSignature) is required')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws and error if identity provider was not given in constructor', async () => {
|
||||||
|
let err
|
||||||
|
try {
|
||||||
|
identity = new Identity('abc', publicKey, idSignature, publicKeyAndIdSignature, type)
|
||||||
|
} catch (e) {
|
||||||
|
err = e.toString()
|
||||||
|
}
|
||||||
|
assert.strictEqual(err, 'Error: Identity provider is required')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws and error if identity type was not given in constructor', async () => {
|
||||||
|
let err
|
||||||
|
try {
|
||||||
|
identity = new Identity('abc', publicKey, idSignature, publicKeyAndIdSignature, null, provider)
|
||||||
|
} catch (e) {
|
||||||
|
err = e.toString()
|
||||||
|
}
|
||||||
|
assert.strictEqual(err, 'Error: Identity type is required')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -1,7 +1,7 @@
|
|||||||
import { deepStrictEqual, strictEqual } from 'assert'
|
import { deepStrictEqual, strictEqual } from 'assert'
|
||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { Log, Entry } from '../src/oplog/index.js'
|
import { Log, Entry } from '../src/oplog/index.js'
|
||||||
import IdentityProvider from '../src/identities/index.js'
|
import { IdentityProvider } from '../src/identities/index.js'
|
||||||
import KeyStore from '../src/key-store.js'
|
import KeyStore from '../src/key-store.js'
|
||||||
import { KeyValue, KeyValuePersisted, Database } from '../src/db/index.js'
|
import { KeyValue, KeyValuePersisted, Database } from '../src/db/index.js'
|
||||||
import { IPFSBlockStorage, LevelStorage } from '../src/storage/index.js'
|
import { IPFSBlockStorage, LevelStorage } from '../src/storage/index.js'
|
||||||
|
@ -3,7 +3,7 @@ import rimraf from 'rimraf'
|
|||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
import { Log } from '../../src/oplog/index.js'
|
import { Log } from '../../src/oplog/index.js'
|
||||||
import MemoryStorage from '../../src/storage/memory.js'
|
import MemoryStorage from '../../src/storage/memory.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
|
|
||||||
// Test utils
|
// Test utils
|
||||||
|
@ -2,7 +2,7 @@ import { strictEqual, deepStrictEqual } from 'assert'
|
|||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
import { Log } from '../../src/oplog/index.js'
|
import { Log } from '../../src/oplog/index.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
import MemoryStorage from '../../src/storage/memory.js'
|
import MemoryStorage from '../../src/storage/memory.js'
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { strictEqual, deepStrictEqual } from 'assert'
|
|||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
import { Entry } from '../../src/oplog/index.js'
|
import { Entry } from '../../src/oplog/index.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
import { config, testAPIs, startIpfs, stopIpfs } from 'orbit-db-test-utils'
|
import { config, testAPIs, startIpfs, stopIpfs } from 'orbit-db-test-utils'
|
||||||
// import IdentityStorage from '../src/identity-storage.js'
|
// import IdentityStorage from '../src/identity-storage.js'
|
||||||
|
@ -2,7 +2,7 @@ import { strictEqual, deepStrictEqual } from 'assert'
|
|||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
import { Log } from '../../src/oplog/index.js'
|
import { Log } from '../../src/oplog/index.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
import MemoryStorage from '../../src/storage/memory.js'
|
import MemoryStorage from '../../src/storage/memory.js'
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { strictEqual, deepStrictEqual } from 'assert'
|
import { strictEqual, deepStrictEqual } from 'assert'
|
||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { Log } from '../../src/oplog/index.js'
|
import { Log } from '../../src/oplog/index.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
import LogCreator from './utils/log-creator.js'
|
import LogCreator from './utils/log-creator.js'
|
||||||
import all from 'it-all'
|
import all from 'it-all'
|
||||||
|
@ -2,7 +2,7 @@ import { strictEqual, deepStrictEqual } from 'assert'
|
|||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
import { Log } from '../../src/oplog/index.js'
|
import { Log } from '../../src/oplog/index.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
import MemoryStorage from '../../src/storage/memory.js'
|
import MemoryStorage from '../../src/storage/memory.js'
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { strictEqual, notStrictEqual, deepStrictEqual } from 'assert'
|
import { strictEqual, notStrictEqual, deepStrictEqual } from 'assert'
|
||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { Log, Clock } from '../../src/oplog/index.js'
|
import { Log, Clock } from '../../src/oplog/index.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
import MemoryStorage from '../../src/storage/memory.js'
|
import MemoryStorage from '../../src/storage/memory.js'
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import rimraf from 'rimraf'
|
|||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
import { Log, Entry, Sorting } from '../../src/oplog/index.js'
|
import { Log, Entry, Sorting } from '../../src/oplog/index.js'
|
||||||
import bigLogString from '../fixtures/big-log.fixture.js'
|
import bigLogString from '../fixtures/big-log.fixture.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
import LogCreator from './utils/log-creator.js'
|
import LogCreator from './utils/log-creator.js'
|
||||||
import MemoryStorage from '../../src/storage/memory.js'
|
import MemoryStorage from '../../src/storage/memory.js'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { notStrictEqual, deepStrictEqual, strictEqual } from 'assert'
|
import { notStrictEqual, deepStrictEqual, strictEqual } from 'assert'
|
||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { Log, Entry } from '../../src/oplog/index.js'
|
import { Log, Entry } from '../../src/oplog/index.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
import MemoryStorage from '../../src/storage/memory.js'
|
import MemoryStorage from '../../src/storage/memory.js'
|
||||||
|
@ -2,7 +2,7 @@ import { strictEqual } from 'assert'
|
|||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
import { Log } from '../../src/oplog/index.js'
|
import { Log } from '../../src/oplog/index.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
import MemoryStorage from '../../src/storage/memory.js'
|
import MemoryStorage from '../../src/storage/memory.js'
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import rimraf from 'rimraf'
|
|||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
import { Log, Entry } from '../../src/index.js'
|
import { Log, Entry } from '../../src/index.js'
|
||||||
import { MemoryStorage, IPFSBlockStorage } from '../../src/storage/index.js'
|
import { MemoryStorage, IPFSBlockStorage } from '../../src/storage/index.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
|
|
||||||
// Test utils
|
// Test utils
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { notStrictEqual, strictEqual, deepStrictEqual } from 'assert'
|
import { notStrictEqual, strictEqual, deepStrictEqual } from 'assert'
|
||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { Log } from '../../src/oplog/index.js'
|
import { Log } from '../../src/oplog/index.js'
|
||||||
import IdentityProvider from '../../src/identities/index.js'
|
import { IdentityProvider } from '../../src/identities/index.js'
|
||||||
import KeyStore from '../../src/key-store.js'
|
import KeyStore from '../../src/key-store.js'
|
||||||
|
|
||||||
// Test utils
|
// Test utils
|
||||||
|
@ -2,7 +2,7 @@ import * as IPFS from 'ipfs'
|
|||||||
import { strictEqual, notStrictEqual } from 'assert'
|
import { strictEqual, notStrictEqual } from 'assert'
|
||||||
import rimraf from 'rimraf'
|
import rimraf from 'rimraf'
|
||||||
import { Log } from '../src/oplog/index.js'
|
import { Log } from '../src/oplog/index.js'
|
||||||
import IdentityProvider from '../src/identities/index.js'
|
import { IdentityProvider } from '../src/identities/index.js'
|
||||||
import KeyStore from '../src/key-store.js'
|
import KeyStore from '../src/key-store.js'
|
||||||
import { IPFSBlockStorage, MemoryStorage, LRUStorage, ComposedStorage } from '../src/storage/index.js'
|
import { IPFSBlockStorage, MemoryStorage, LRUStorage, ComposedStorage } from '../src/storage/index.js'
|
||||||
import { copy } from 'fs-extra'
|
import { copy } from 'fs-extra'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user