Skip to content
This repository was archived by the owner on Sep 30, 2023. It is now read-only.

feat: remove provider #52

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ The `Identity` object contains signatures proving possession of some external id
### Creating an identity
```js
const Identities = require('orbit-db-identity-provider')
const identities = new Identities()
const options = { id: 'local-id'}
const identity = await Identities.createIdentity(options)
const identity = await identities.createIdentity(options)

console.log(identity.toJSON())
// prints
Expand All @@ -58,18 +59,17 @@ If `options.type` is not specified, Identities will default to creating an ident

To use an existing keystore, you can pass it as an argument in the options as follows:
```js
const identity = await Identities.createIdentity({ id: 'local-id', keystore: existingKeystore })
const identity = await identities.createIdentity({ id: 'local-id', keystore: existingKeystore })
```

### Create identity using existing keys

To create an identity using existing keys, you need to install `localstorage-level-migration`

```js
const Identities = require('orbit-db-identity-provider')
const migrate = require('localstorage-level-migration')
const options = { id: 'new-id', migrate: migrate('/path/to/keys') }
const identity = await Identities.createIdentity(options)
const identities = new Identities({ keystore: existingKeystore })
const options = { id: 'new-id', migrate: '/path/to/keys' }
const identity = await identities.createIdentity(options)

console.log(identity.toJSON())
// prints
Expand Down Expand Up @@ -100,7 +100,7 @@ class MyIdentityProvider extends IdentityProvider {
Identities.addIdentityProvider(MyIdentityProvider)

// to create an identity of type `MyIdentityType`
const identity = await Identities.createIdentity({ type: `MyIdentityType`})
const identity = await identities.createIdentity({ type: `MyIdentityType`})

```

Expand Down
16 changes: 8 additions & 8 deletions dist/index-browser.min.js

Large diffs are not rendered by default.

1,115 changes: 553 additions & 562 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
},
"dependencies": {
"ethers": "^4.0.20",
"orbit-db-keystore": "~0.3.0"
"orbit-db-keystore": "orbitdb/orbit-db-keystore"
},
"localMaintainers": [
"haad <haad@haja.io>",
Expand Down
90 changes: 49 additions & 41 deletions src/identities.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ const Identity = require('./identity')
const IdentityProvider = require('./identity-provider-interface.js')
const OrbitDBIdentityProvider = require('./orbit-db-identity-provider')
const Keystore = require('orbit-db-keystore')
const LRU = require('lru')
const path = require('path')

const type = 'orbitdb'
const identityKeysPath = './orbitdb/identity/identitykeys'
const identityKeysPath = path.join('./orbitdb', 'identity', 'identitykeys')
const defaultType = 'orbitdb'
const supportedTypes = {
orbitdb: OrbitDBIdentityProvider
}
Expand All @@ -18,79 +20,85 @@ const getHandlerFor = (type) => {
}

class Identities {
constructor (options) {
this._keystore = options.keystore
this._signingKeystore = options.signingKeystore || this._keystore
constructor (options = {}) {
this._keystore = options.keystore || new Keystore(options.identityKeysPath || identityKeysPath)
this._knownIdentities = options.cache || new LRU(options.cacheSize || 1000)
}

static get IdentityProvider () { return IdentityProvider }

get keystore () { return this._keystore }

get signingKeystore () { return this._signingKeystore }
async close () {
if (this.keystore.close) {
await this.keystore.close()
}
}

async sign (identity, data) {
const signingKey = await this._keystore.getKey(identity.id)
const keystore = this.keystore
const signingKey = await 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
return keystore.sign(signingKey, data)
}

async verify (signature, publicKey, data, verifier = 'v1') {
return this._keystore.verify(signature, publicKey, data, verifier)
async verify (sig, key, data, version) {
return this.keystore.verify(sig, key, data, version)
}

async createIdentity (options = {}) {
const IdentityProvider = getHandlerFor(options.type)
const identityProvider = new IdentityProvider(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: this._keystore._store, targetId: id })
await options.migrate({ targetStore: keystore._store, targetId: id })
}
const { publicKey, idSignature } = await this.signId(id)
const { publicKey, idSignature } = await this.signId(id, keystore)
const pubKeyIdSignature = await identityProvider.signIdentity(publicKey + idSignature, options)
return new Identity(id, publicKey, idSignature, pubKeyIdSignature, IdentityProvider.type, this)
return new Identity(id, publicKey, idSignature, pubKeyIdSignature, type)
}

async signId (id) {
const keystore = this._keystore
async signId (id, 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) {
const verified = await this._keystore.verify(
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 verified = await Identities.verifyIdentity(identity, this.keystore)
if (verified) {
this._knownIdentities.set(identity.signatures.id, identity)
}
return verified
}

static async verifyIdentity (identity, keystore) {
if (!Identity.isIdentity(identity)) {
return false
}

const verifyId = await keystore.verify(
identity.signatures.id,
identity.publicKey,
identity.id
)
return verified && Identities.verifyIdentity(identity)
}

static async verifyIdentity (identity) {
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
}
}
options = Object.assign({}, { type }, options)
const identities = new Identities(options)
return identities.createIdentity(options)
return verifyId && IdentityProvider.verifyIdentity(identity)
}

static isSupported (type) {
Expand Down
19 changes: 9 additions & 10 deletions src/identity.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
const isDefined = require('./is-defined')

class Identity {
constructor (id, publicKey, idSignature, pubKeyIdSignature, type, provider) {
constructor (id, publicKey, idSignature, pubKeyIdSignature, type) {
if (!isDefined(id)) {
throw new Error('Identity id is required')
}
Expand All @@ -23,15 +23,18 @@ class Identity {
throw new Error('Identity type is required')
}

if (!isDefined(provider)) {
throw new Error('Identity provider is required')
}

this._id = id
this._publicKey = publicKey
this._signatures = Object.assign({}, { id: idSignature }, { publicKey: pubKeyIdSignature })
this._type = type
this._provider = provider
}

static isIdentity (identity) {
return identity.id !== undefined &&
identity.publicKey !== undefined &&
identity.signatures.id !== undefined &&
identity.signatures.publicKey !== undefined &&
identity.type !== undefined
}

/**
Expand All @@ -54,10 +57,6 @@ class Identity {
return this._type
}

get provider () {
return this._provider
}

toJSON () {
return {
id: this._id,
Expand Down
9 changes: 3 additions & 6 deletions src/orbit-db-identity-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@ const Keystore = require('orbit-db-keystore')
const type = 'orbitdb'

class OrbitDBIdentityProvider extends IdentityProvider {
constructor (options = {}) {
constructor (keystore) {
super()
if (!options.keystore) {
if (!keystore) {
throw new Error('IdentityProvider.createIdentity requires options.keystore')
}
if (!options.signingKeystore) {
options.signingKeystore = options.keystore
}
this._keystore = options.signingKeystore
this._keystore = keystore
}

// Returns the type of the identity provider
Expand Down
41 changes: 20 additions & 21 deletions test/ethereum-identity-provider.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ describe('Ethereum Identity Provider', function () {
})

describe('create an ethereum identity', () => {
let identity
let identityProvider, identity
let wallet

before(async () => {
const ethIdentityProvider = new EthIdentityProvider()
wallet = await ethIdentityProvider._createWallet()
identity = await Identities.createIdentity({ type, keystore, wallet })
identityProvider = new Identities({ keystore })
identity = await identityProvider.createIdentity({ type, wallet })
})

it('has the correct id', async () => {
Expand Down Expand Up @@ -72,46 +73,48 @@ describe('Ethereum Identity Provider', function () {
})

describe('verify identity', () => {
let identity
let identityProvider, identity

before(async () => {
identity = await Identities.createIdentity({ keystore, type })
identityProvider = new Identities({ keystore })
identity = await identityProvider.createIdentity({ type })
})

it('ethereum identity verifies', async () => {
const verified = await Identities.verifyIdentity(identity)
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 Identities.verifyIdentity(identity2)
const identity2 = new Identity('NotAnId', identity.publicKey, identity.signatures.id, identity.signatures.publicKey, identity.type)
const verified = await Identities.verifyIdentity(identity2, keystore)
assert.strictEqual(verified, false)
})
})

describe('sign data with an identity', () => {
let identity
let identityProvider, identity
const data = 'hello friend'

before(async () => {
identity = await Identities.createIdentity({ keystore, type })
identityProvider = new Identities({ keystore })
identity = await identityProvider.createIdentity({ 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)
const signature = await identityProvider.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)
const modifiedIdentity = new Identity('this id does not exist', identity.publicKey, '<sig>', identity.signatures, identity.type)
let signature
let err
try {
signature = await identity.provider.sign(modifiedIdentity, data, keystore)
signature = await identityProvider.sign(modifiedIdentity, data)
} catch (e) {
err = e.toString()
}
Expand All @@ -121,23 +124,19 @@ describe('Ethereum Identity Provider', function () {

describe('verify data signed by an identity', () => {
const data = 'hello friend'
let identity
let identityProvider, identity
let signature

before(async () => {
identity = await Identities.createIdentity({ type, keystore })
signature = await identity.provider.sign(identity, data, keystore)
identityProvider = new Identities({ keystore })
identity = await identityProvider.createIdentity({ type })
signature = await identityProvider.sign(identity, data)
})

it('verifies that the signature is valid', async () => {
const verified = await identity.provider.verify(signature, identity.publicKey, data)
const verified = await keystore.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)
})
})
})
})
Loading