Skip to content

Commit

Permalink
feat: New Identity TS and GraphQL interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
simonas-notcat committed Jan 28, 2020
1 parent e43335e commit 3f8ff1c
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 128 deletions.
47 changes: 25 additions & 22 deletions packages/daf-core/src/graphql/graphql-identity-manager.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { Core } from '../core'
import { Issuer } from '../identity/identity-manager'
import { AbstractIdentity } from '../identity/abstract-identity'

export interface Context {
core: Core
}

const managedIdentityTypes = async (_: any, args: any, ctx: Context) => {
return await ctx.core.identityManager.listTypes()
const identityProviders = async (_: any, args: any, ctx: Context) => {
return await ctx.core.identityManager.getIdentityProviderTypes()
}

const managedIdentities = async (_: any, args: any, ctx: Context) => {
const list = await ctx.core.identityManager.listIssuers()
return list.map((issuer: Issuer) => ({
did: issuer.did,
type: issuer.type,
const list = await ctx.core.identityManager.getIdentities()
return list.map((identity: AbstractIdentity) => ({
did: identity.did,
type: identity.identityProviderType,
__typename: 'Identity',
}))
}

const isManaged = async (identity: any, args: any, ctx: Context) => {
const list = await ctx.core.identityManager.listDids()
return list.indexOf(identity.did) > -1
const list = await ctx.core.identityManager.getIdentities()
return list.map(item => item.did).indexOf(identity.did) > -1
}

const createIdentity = async (
Expand All @@ -30,22 +30,22 @@ const createIdentity = async (
},
ctx: Context,
) => {
const did = await ctx.core.identityManager.create(args.type)
const identity = await ctx.core.identityManager.createIdentity(args.type)
return {
did,
did: identity.did,
type: identity.identityProviderType,
__typename: 'Identity',
}
}

const deleteIdentity = async (
_: any,
args: {
type: string
did: string
},
ctx: Context,
) => {
return await ctx.core.identityManager.delete(args.type, args.did)
return await ctx.core.identityManager.deleteIdentity(args.did)
}

const importIdentity = async (
Expand All @@ -56,10 +56,10 @@ const importIdentity = async (
},
ctx: Context,
) => {
const issuer = await ctx.core.identityManager.import(args.type, args.secret)
const identity = await ctx.core.identityManager.importIdentity(args.type, args.secret)
return {
did: issuer.did,
type: issuer.type,
did: identity.did,
type: identity.identityProviderType,
__typename: 'Identity',
}
}
Expand All @@ -68,12 +68,11 @@ const importIdentity = async (
const managedIdentitySecret = async (
_: any,
args: {
type: string
did: string
},
ctx: Context,
) => {
return await ctx.core.identityManager.export(args.type, args.did)
return await ctx.core.identityManager.exportIdentity(args.did)
}

// Actions
Expand All @@ -83,7 +82,7 @@ export const resolvers = {
isManaged,
},
Query: {
managedIdentityTypes,
identityProviders,
managedIdentities,
managedIdentitySecret,
},
Expand All @@ -95,15 +94,19 @@ export const resolvers = {
}

export const typeDefs = `
type IdentityProvider {
type: String!
description: String
}
extend type Query {
identityProviders: [IdentityProvider]
managedIdentities: [Identity]
managedIdentityTypes: [String]
managedIdentitySecret(type: String, did: String): String
managedIdentitySecret(did: String): String
}
extend type Mutation {
createIdentity(type: String): Identity!
deleteIdentity(type: String, did: String): Boolean!
deleteIdentity(did: String): Boolean!
importIdentity(type: String, secret: String): Identity!
}
Expand Down
16 changes: 16 additions & 0 deletions packages/daf-core/src/identity/abstract-identity-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { EventEmitter } from 'events'
import { AbstractIdentity } from './abstract-identity'

export abstract class AbstractIdentityProvider extends EventEmitter {
abstract type: string
abstract description: string
abstract createIdentity: () => Promise<AbstractIdentity>
abstract importIdentity: (secret: string) => Promise<AbstractIdentity>
abstract exportIdentity: (did: string) => Promise<string>
abstract deleteIdentity: (did: string) => Promise<boolean>
abstract getIdentities: () => Promise<AbstractIdentity[]>
abstract getIdentity: (did: string) => Promise<AbstractIdentity>
}

type AbstractIdentityProviderClass = typeof AbstractIdentityProvider
export interface IdentityProviderDerived extends AbstractIdentityProviderClass {}
38 changes: 38 additions & 0 deletions packages/daf-core/src/identity/abstract-identity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export interface DIDDocument {
'@context': 'https://w3id.org/did/v1'
id: string
publicKey: PublicKey[]
service?: ServiceEndpoint[]
}
export interface PublicKey {
id: string
type: string
owner: string
ethereumAddress?: string
publicKeyBase64?: string
publicKeyBase58?: string
publicKeyHex?: string
publicKeyPem?: string
}
export interface ServiceEndpoint {
id: string
type: string
serviceEndpoint: string
description?: string
}

export abstract class AbstractIdentity {
abstract identityProviderType: string
abstract did: string
abstract didDoc: () => Promise<DIDDocument>
abstract sign: (data: string, keyId?: string) => Promise<any>
abstract encrypt: (to: string, data: string | Uint8Array) => Promise<any>
abstract decrypt: (encrypted: any) => Promise<string>
abstract addPublicKey: (type: string, proofPurpose?: string[]) => Promise<PublicKey>
abstract removePublicKey: (keyId: string) => Promise<boolean>
abstract addService: (service: ServiceEndpoint) => Promise<boolean>
abstract removeService: (service: ServiceEndpoint) => Promise<boolean>
}

type AbstractIdentityClass = typeof AbstractIdentity
export interface IdentityDerived extends AbstractIdentityClass {}
136 changes: 47 additions & 89 deletions packages/daf-core/src/identity/identity-manager.ts
Original file line number Diff line number Diff line change
@@ -1,122 +1,80 @@
export interface EcdsaSignature {
r: string
s: string
recoveryParam?: number
}

export type Signer = (data: string) => Promise<EcdsaSignature | string>

export interface Issuer {
// did-jwt-vc
type: string
did: string
signer: Signer
ethereumAddress?: string
}

export interface IdentityController {
type: string
create: () => Promise<string>
delete: (did: string) => Promise<boolean>
listDids: () => Promise<string[]>
listIssuers: () => Promise<Issuer[]>
issuer: (did: string) => Promise<Issuer>
export?: (did: string) => Promise<string>
import?: (secret: string) => Promise<Issuer>
}
import { AbstractIdentity } from './abstract-identity'
import { AbstractIdentityProvider } from './abstract-identity-provider'

interface Options {
identityControllers: IdentityController[]
identityProviders: AbstractIdentityProvider[]
}

export class IdentityManager {
private identityControllers: IdentityController[]
private identityProviders: AbstractIdentityProvider[]

constructor(options: Options) {
this.identityControllers = options.identityControllers
this.identityProviders = options.identityProviders
}

async listDids(): Promise<string[]> {
let allDids: string[] = []

for (const identityController of this.identityControllers) {
const dids = await identityController.listDids()
allDids = allDids.concat(dids)
}

return allDids
async getIdentityProviderTypes(): Promise<{ type: string; description: string }[]> {
return this.identityProviders.map(provider => ({
type: provider.type,
description: provider.description,
}))
}

async listIssuers(): Promise<Issuer[]> {
let allIssuers: Issuer[] = []

for (const identityController of this.identityControllers) {
const issuers = await identityController.listIssuers()
allIssuers = allIssuers.concat(issuers)
async createIdentity(identityProviderType: string): Promise<AbstractIdentity> {
for (const identityProvider of this.identityProviders) {
if (identityProvider.type === identityProviderType) {
return identityProvider.createIdentity()
}
}

return allIssuers
return Promise.reject('IdentityProvider not found for type: ' + identityProviderType)
}

async issuer(did: string): Promise<Issuer> {
const issuers = await this.listIssuers()
const issuer = issuers.find(item => item.did === did)
if (issuer) {
return issuer
} else {
return Promise.reject('No issuer for did: ' + did)
async importIdentity(identityProviderType: string, secret: string): Promise<AbstractIdentity> {
for (const identityProvider of this.identityProviders) {
if (identityProvider.type === identityProviderType) {
return identityProvider.importIdentity(secret)
}
}
}

listTypes(): string[] {
return this.identityControllers.map(identityController => identityController.type)
return Promise.reject('IdentityProvider not found for type: ' + identityProviderType)
}

create(type: string): Promise<string> {
for (const identityController of this.identityControllers) {
if (identityController.type === type) {
return identityController.create()
}
async getIdentities(): Promise<AbstractIdentity[]> {
let allIdentities: AbstractIdentity[] = []
for (const identityProvider of this.identityProviders) {
const identities = await identityProvider.getIdentities()
allIdentities = allIdentities.concat(identities)
}

return Promise.reject('IdentityController not found for type: ' + type)
return allIdentities
}

delete(type: string, did: string): Promise<boolean> {
for (const identityController of this.identityControllers) {
if (identityController.type === type) {
return identityController.delete(did)
}
async getIdentity(did: string): Promise<AbstractIdentity> {
const identities = await this.getIdentities()
const identity = identities.find(item => item.did === did)
if (identity) {
return identity
} else {
return Promise.reject('No identity: ' + did)
}

return Promise.reject('IdentityController not found for type: ' + type)
}

import(type: string, secret: string): Promise<Issuer> {
for (const identityController of this.identityControllers) {
if (identityController.type === type) {
if (identityController.import) {
return identityController.import(secret)
} else {
return Promise.reject(type + ' does not support import')
}
async exportIdentity(did: string): Promise<string> {
const identity = await this.getIdentity(did)
for (const identityProvider of this.identityProviders) {
if (identityProvider.type === identity.identityProviderType) {
return identityProvider.exportIdentity(identity.did)
}
}

return Promise.reject('IdentityController not found for type: ' + type)
return Promise.reject()
}

export(type: string, did: string): Promise<string> {
for (const identityController of this.identityControllers) {
if (identityController.type === type) {
if (identityController.export) {
return identityController.export(did)
} else {
return Promise.reject(type + ' does not support export')
}
async deleteIdentity(did: string): Promise<boolean> {
const identity = await this.getIdentity(did)
for (const identityProvider of this.identityProviders) {
if (identityProvider.type === identity.identityProviderType) {
return identityProvider.deleteIdentity(identity.did)
}
}

return Promise.reject('IdentityController not found for type: ' + type)
return Promise.reject()
}
}
Loading

0 comments on commit 3f8ff1c

Please sign in to comment.