Skip to content

Commit

Permalink
feat: IdentityController, KeyStore
Browse files Browse the repository at this point in the history
  • Loading branch information
simonas-notcat committed Feb 17, 2020
1 parent cecffd8 commit e86fec4
Show file tree
Hide file tree
Showing 18 changed files with 399 additions and 302 deletions.
6 changes: 2 additions & 4 deletions packages/daf-cli/src/identity-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ program
])

const identity = await core.identityManager.getIdentity(answers.did)
const provider = await core.identityManager.getIdentityProvider(identity.identityProviderType)
const result = await provider.addService(identity.did, {
const result = await identity.identityController.addService({
type: answers.type,
serviceEndpoint: answers.endpoint,
id: '',
Expand Down Expand Up @@ -131,8 +130,7 @@ program
])

const identity = await core.identityManager.getIdentity(answers.did)
const provider = await core.identityManager.getIdentityProvider(identity.identityProviderType)
const result = await provider.addPublicKey(identity.did, answers.type)
const result = await identity.identityController.addPublicKey(answers.type)
console.log('Success:', result)
} catch (e) {
console.error(e)
Expand Down
4 changes: 2 additions & 2 deletions packages/daf-cli/src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ TG.ServiceController.webSocketImpl = ws

const identityProviders = [
new EthrDidFs.IdentityProvider({
store: new EthrDidFs.IdentityStore(defaultPath + '/rinkeby-identity-store.json'),
kms: new EthrDidFs.KeyManagementSystem(defaultPath + '/rinkeby-kms.json'),
identityStore: new EthrDidFs.IdentityStore(defaultPath + '/rinkeby-identity-store.json'),
kms: new EthrDidFs.KeyManagementSystem(new EthrDidFs.KeyStore(defaultPath + '/rinkeby-kms.json')),
network: 'rinkeby',
rpcUrl: 'https://rinkeby.infura.io/v3/' + infuraProjectId,
resolver: didResolver,
Expand Down
24 changes: 24 additions & 0 deletions packages/daf-core/src/identity/abstract-identity-controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export interface ServiceEndpoint {
id: string
type: string
serviceEndpoint: string
description?: string
}

export abstract class AbstractIdentityController {
addPublicKey(type: string, proofPurpose?: string[]): Promise<string> {
return Promise.reject('Method addPublicKey not implemented')
}

removePublicKey(keyId: string): Promise<boolean> {
return Promise.reject('Method removePublicKey not implemented')
}

addService(service: ServiceEndpoint): Promise<any> {
return Promise.reject('Method addService not implemented')
}

removeService(service: ServiceEndpoint): Promise<boolean> {
return Promise.reject('Method removeService not implemented')
}
}
23 changes: 0 additions & 23 deletions packages/daf-core/src/identity/abstract-identity-provider.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import { EventEmitter } from 'events'
import { AbstractIdentity } from './abstract-identity'

export interface ServiceEndpoint {
id: string
type: string
serviceEndpoint: string
description?: string
}

export abstract class AbstractIdentityProvider extends EventEmitter {
abstract type: string
abstract description: string
Expand All @@ -23,22 +16,6 @@ export abstract class AbstractIdentityProvider extends EventEmitter {
importIdentity(secret: string): Promise<AbstractIdentity> {
return Promise.reject('Method importIdentity not implemented')
}

addPublicKey(did: string, type: string, proofPurpose?: string[]): Promise<string> {
return Promise.reject('Method addPublicKey not implemented')
}

removePublicKey(did: string, keyId: string): Promise<boolean> {
return Promise.reject('Method removePublicKey not implemented')
}

addService(did: string, service: ServiceEndpoint): Promise<any> {
return Promise.reject('Method addService not implemented')
}

removeService(did: string, service: ServiceEndpoint): Promise<boolean> {
return Promise.reject('Method removeService not implemented')
}
}

type AbstractIdentityProviderClass = typeof AbstractIdentityProvider
Expand Down
4 changes: 3 additions & 1 deletion packages/daf-core/src/identity/abstract-identity.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { AbstractKey, KeyType } from './abstract-key-management-system'
import { AbstractIdentityController } from './abstract-identity-controller'
export abstract class AbstractIdentity {
abstract identityProviderType: string
abstract did: string
abstract identityProviderType: string
abstract identityController: AbstractIdentityController
abstract keyByType(type: KeyType): Promise<AbstractKey>
abstract keyById(id: string): Promise<AbstractKey>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@ interface EcdsaSignature {
}
// Placeholder:
type Signer = (data: string) => Promise<EcdsaSignature | string>
type EthSigner = (transaction: object) => string

export abstract class AbstractKey {
abstract serialized: SerializedKey
abstract encrypt(to: SerializedKey, data: string): Promise<string>
abstract decrypt(encrypted: string): Promise<string>
abstract signer(): Signer
signEthTransaction(transaction: object, callback: (error: string | null, signature: string) => void) {
throw Error('Method signTransaction not implemented')
}
}

export abstract class AbstractKeyManagementSystem {
Expand Down
7 changes: 7 additions & 0 deletions packages/daf-core/src/identity/abstract-key-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { SerializedKey } from './abstract-key-management-system'

export abstract class AbstractKeyStore {
abstract set(kid: string, serializedKey: SerializedKey): Promise<boolean>
abstract get(kid: string): Promise<SerializedKey>
abstract delete(kid: string): Promise<boolean>
}
2 changes: 2 additions & 0 deletions packages/daf-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { Core, EventTypes, Resolver } from './core'
export { AbstractActionHandler } from './action/action-handler'
export { IdentityManager } from './identity/identity-manager'
export { AbstractIdentity } from './identity/abstract-identity'
export { AbstractIdentityController } from './identity/abstract-identity-controller'
export { AbstractIdentityProvider, IdentityProviderDerived } from './identity/abstract-identity-provider'
export {
AbstractKeyManagementSystem,
Expand All @@ -10,6 +11,7 @@ export {
SerializedKey,
} from './identity/abstract-key-management-system'
export { AbstractIdentityStore, SerializedIdentity } from './identity/abstract-identity-store'
export { AbstractKeyStore } from './identity/abstract-key-store'
export { AbstractMessageValidator } from './message/abstract-message-validator'
export { Message } from './message/message'
export { ServiceManager, LastMessageTimestampForInstance, ServiceEventTypes } from './service/service-manager'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,84 +4,91 @@ import { AbstractIdentity } from '../../identity/abstract-identity'
import { Resolver } from '../../core'
import { Message } from '../../message/message'

const msg1 = new Message({ raw: 'test1', meta: { type: 'mockService', id: 'https://from-did-doc' } })
const msg2 = new Message({ raw: 'test2', meta: { type: 'mockService', id: 'https://from-did-doc' } })
describe('dummy', () => {
const a = 100
it('should run a dummy test', () => {
expect(a).toEqual(100)
})
})

export class MockServiceController extends AbstractServiceController {
static defaultServiceEndpoint: string = 'https://default.host/path'
readonly type = 'mockService'
private endPointUrl: string
// const msg1 = new Message({ raw: 'test1', meta: { type: 'mockService', id: 'https://from-did-doc' } })
// const msg2 = new Message({ raw: 'test2', meta: { type: 'mockService', id: 'https://from-did-doc' } })

public ready: Promise<boolean>
// export class MockServiceController extends AbstractServiceController {
// static defaultServiceEndpoint: string = 'https://default.host/path'
// readonly type = 'mockService'
// private endPointUrl: string

constructor(identity: AbstractIdentity, didResolver: Resolver) {
super(identity, didResolver)
this.endPointUrl = 'https://from-did-doc'
this.ready = new Promise((resolve, reject) => {
// do some async stuff
resolve(true)
})
}
// public ready: Promise<boolean>

instanceId() {
return {
did: this.identity.did,
type: this.type,
id: this.endPointUrl,
}
}
// constructor(identity: AbstractIdentity, didResolver: Resolver) {
// super(identity, didResolver)
// this.endPointUrl = 'https://from-did-doc'
// this.ready = new Promise((resolve, reject) => {
// // do some async stuff
// resolve(true)
// })
// }

async getMessagesSince(timestamp: number) {
this.emit(ServiceEventTypes.NewMessages, [msg1, msg2])
return [msg1, msg2]
}
// instanceId() {
// return {
// did: this.identity.did,
// type: this.type,
// id: this.endPointUrl,
// }
// }

async listen() {
this.emit(ServiceEventTypes.NewMessages, [msg1])
}
}
// async getMessagesSince(timestamp: number) {
// this.emit(ServiceEventTypes.NewMessages, [msg1, msg2])
// return [msg1, msg2]
// }

const mockIdentity: AbstractIdentity = {
did: 'did:test:123',
signer: (keyId?: string) => async (data: string) => data,
identityProviderType: 'mock',
didDoc: async (): Promise<any> => '',
encrypt: async (): Promise<any> => '',
decrypt: async (): Promise<any> => '',
}
// async listen() {
// this.emit(ServiceEventTypes.NewMessages, [msg1])
// }
// }

const mockResolver: Resolver = {
resolve: async (did: string) => null,
}
// const mockIdentity: AbstractIdentity = {
// did: 'did:test:123',
// signer: (keyId?: string) => async (data: string) => data,
// identityProviderType: 'mock',
// didDoc: async (): Promise<any> => '',
// encrypt: async (): Promise<any> => '',
// decrypt: async (): Promise<any> => '',
// }

it('should be possible to set configuration as a static property', async () => {
expect(MockServiceController.defaultServiceEndpoint).toEqual('https://default.host/path')
MockServiceController.defaultServiceEndpoint = 'https://custom.host/path'
expect(MockServiceController.defaultServiceEndpoint).toEqual('https://custom.host/path')
})
// const mockResolver: Resolver = {
// resolve: async (did: string) => null,
// }

it('resolves ready promise after finishing async logic in constructor', async () => {
const controller = new MockServiceController(mockIdentity, mockResolver)
const ready = await controller.ready
expect(ready).toEqual(true)
})
// it('should be possible to set configuration as a static property', async () => {
// expect(MockServiceController.defaultServiceEndpoint).toEqual('https://default.host/path')
// MockServiceController.defaultServiceEndpoint = 'https://custom.host/path'
// expect(MockServiceController.defaultServiceEndpoint).toEqual('https://custom.host/path')
// })

it('returns and emits an event with the same message array ', async () => {
const controller = new MockServiceController(mockIdentity, mockResolver)
spyOn(controller, 'emit')
const messages = await controller.getMessagesSince(0)
expect(controller.emit).toHaveBeenCalledWith(ServiceEventTypes.NewMessages, messages)
})
// it('resolves ready promise after finishing async logic in constructor', async () => {
// const controller = new MockServiceController(mockIdentity, mockResolver)
// const ready = await controller.ready
// expect(ready).toEqual(true)
// })

it('emits events on listen', async () => {
const controller = new MockServiceController(mockIdentity, mockResolver)
spyOn(controller, 'emit')
await controller.listen()
expect(controller.emit).toHaveBeenCalledWith(ServiceEventTypes.NewMessages, [msg1])
})
// it('returns and emits an event with the same message array ', async () => {
// const controller = new MockServiceController(mockIdentity, mockResolver)
// spyOn(controller, 'emit')
// const messages = await controller.getMessagesSince(0)
// expect(controller.emit).toHaveBeenCalledWith(ServiceEventTypes.NewMessages, messages)
// })

it('instanceId is generated from state', async () => {
const controller = new MockServiceController(mockIdentity, mockResolver)
const instanceId = controller.instanceId()
expect(instanceId).toEqual({ did: 'did:test:123', type: controller.type, id: 'https://from-did-doc' })
})
// it('emits events on listen', async () => {
// const controller = new MockServiceController(mockIdentity, mockResolver)
// spyOn(controller, 'emit')
// await controller.listen()
// expect(controller.emit).toHaveBeenCalledWith(ServiceEventTypes.NewMessages, [msg1])
// })

// it('instanceId is generated from state', async () => {
// const controller = new MockServiceController(mockIdentity, mockResolver)
// const instanceId = controller.instanceId()
// expect(instanceId).toEqual({ did: 'did:test:123', type: controller.type, id: 'https://from-did-doc' })
// })
1 change: 0 additions & 1 deletion packages/daf-did-comm/src/action-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export class ActionHandler extends AbstractActionHandler {
})
debug(dm)

// TODO: move this to AbstractIdentity
const key = await identity.keyByType('Ed25519')
const publicKey = didDoc?.publicKey.find(item => item.type == 'Ed25519VerificationKey2018')
if (!publicKey?.publicKeyHex) throw Error('Recipient does not have encryption publicKey')
Expand Down
Loading

0 comments on commit e86fec4

Please sign in to comment.