Skip to content

Commit

Permalink
feat: ActionSendDIDComm
Browse files Browse the repository at this point in the history
  • Loading branch information
simonas-notcat committed Apr 1, 2020
1 parent c00b5c1 commit 49e6841
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 82 deletions.
7 changes: 4 additions & 3 deletions examples/rest-api/setup.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import * as Daf from 'daf-core'
import * as DafEthr from 'daf-ethr-did'
import * as DafLibSodium from 'daf-libsodium'
import { W3cActionHandler, W3cMessageHandler} from 'daf-w3c'
import { W3cActionHandler, W3cMessageHandler } from 'daf-w3c'
import { JwtMessageHandler } from 'daf-did-jwt'
import { DIDCommActionHandler, DIDCommMessageHandler} from 'daf-did-comm'
import { DIDCommActionHandler, DIDCommMessageHandler } from 'daf-did-comm'
import { DafResolver } from 'daf-resolver'

import Debug from 'debug'
Debug.enable('*')

const messageHandler = new JwtMessageHandler()
const messageHandler = new DIDCommMessageHandler()
messageHandler.setNext(new JwtMessageHandler())
messageHandler.setNext(new W3cMessageHandler())

const actionHandler = new DIDCommActionHandler()
Expand Down
11 changes: 6 additions & 5 deletions examples/send-vc/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AbstractIdentity, EventTypes, Entities, Message } from 'daf-core'
import { ActionSendJWT } from 'daf-did-comm'
import { ActionSendDIDComm, ActionTypes } from 'daf-did-comm'
import { ActionSignW3cVc } from 'daf-w3c'
import { agent } from './setup'
import { createConnection } from 'typeorm'
Expand Down Expand Up @@ -40,15 +40,16 @@ async function main() {
},
} as ActionSignW3cVc)

// Send verifiable credential using DIDComm or TrustGraph
// Send verifiable credential using DIDComm
await agent.handleAction({
type: 'action.sendJwt',
type: ActionTypes.sendMessageDIDCommAlpha1,
data: {
from: identity.did,
to: 'did:web:uport.me',
jwt: vcJwt,
type: 'jwt',
body: vcJwt,
},
} as ActionSendJWT)
} as ActionSendDIDComm)
}

// This is triggered when DAF successfully saves a new message
Expand Down
14 changes: 8 additions & 6 deletions packages/daf-cli/src/credential.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,13 @@ program
if (!cmd.send) {
await agent.handleMessage({ raw: jwt, metaData: [{ type: 'cli' }] })
} else {
const sendAction: DIDComm.ActionSendJWT = {
type: DIDComm.ActionTypes.sendJwt,
const sendAction: DIDComm.ActionSendDIDComm = {
type: DIDComm.ActionTypes.sendMessageDIDCommAlpha1,
data: {
from: answers.iss,
to: answers.sub,
jwt,
type: 'jwt',
body: jwt,
},
}
try {
Expand Down Expand Up @@ -210,12 +211,13 @@ program
if (!cmd.send) {
await agent.handleMessage({ raw: jwt, metaData: [{ type: 'cli' }] })
} else {
const sendAction: DIDComm.ActionSendJWT = {
type: DIDComm.ActionTypes.sendJwt,
const sendAction: DIDComm.ActionSendDIDComm = {
type: DIDComm.ActionTypes.sendMessageDIDCommAlpha1,
data: {
from: answers.iss,
to: aud,
jwt,
type: 'jwt',
body: jwt,
},
}
try {
Expand Down
3 changes: 3 additions & 0 deletions packages/daf-cli/src/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import program from 'commander'
import { Gql } from 'daf-core'
import { W3cGql } from 'daf-w3c'
import { TrustGraphGql } from 'daf-trust-graph'
import { DIDCommGql } from 'daf-did-comm'
import { SdrGql } from 'daf-selective-disclosure'
import merge from 'lodash.merge'
import { agent, dataStore } from './setup'
Expand All @@ -20,13 +21,15 @@ program
Gql.Core.typeDefs,
Gql.IdentityManager.typeDefs,
TrustGraphGql.typeDefs,
DIDCommGql.typeDefs,
W3cGql.typeDefs,
SdrGql.typeDefs,
],
resolvers: merge(
Gql.Core.resolvers,
Gql.IdentityManager.resolvers,
TrustGraphGql.resolvers,
DIDCommGql.resolvers,
W3cGql.resolvers,
SdrGql.resolvers,
),
Expand Down
7 changes: 4 additions & 3 deletions packages/daf-cli/src/sdr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,13 @@ program
if (!cmd.send) {
await agent.handleMessage({ raw: jwt, metaData: [{ type: 'cli' }] })
} else if (answers.sub !== '') {
const sendAction: DIDComm.ActionSendJWT = {
type: DIDComm.ActionTypes.sendJwt,
const sendAction: DIDComm.ActionSendDIDComm = {
type: DIDComm.ActionTypes.sendMessageDIDCommAlpha1,
data: {
from: answers.iss,
to: answers.sub,
jwt,
type: 'jwt',
body: jwt,
},
}
try {
Expand Down
53 changes: 30 additions & 23 deletions packages/daf-core/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,38 +87,45 @@ export class Agent extends EventEmitter {
return result
}

public async handleMessage({ raw, metaData, save = true}:
{ raw: string, metaData?: MetaData[], save?: boolean}): Promise<Message> {

debug('Handle message %o', { raw, metaData, save, })
if (!this.messageHandler) {
return Promise.reject('Message handler not provided')
public async handleMessage({
raw,
metaData,
save = true,
}: {
raw: string
metaData?: MetaData[]
save?: boolean
}): Promise<Message> {
debug('Handle message %o', { raw, metaData, save })
if (!this.messageHandler) {
return Promise.reject('Message handler not provided')
}

try {
const message = await this.messageHandler.handle(new Message({ raw, metaData }), this)
if (message.isValid()) {
debug('Emitting event', EventTypes.validatedMessage)
this.emit(EventTypes.validatedMessage, message)
}

try {
const message = await this.messageHandler.handle(new Message({ raw, metaData }), this)
if (message.isValid()) {
debug('Emitting event', EventTypes.validatedMessage)
this.emit(EventTypes.validatedMessage, message)
}

debug('Validated message %o', message)
if (save) {
await message.save()
debug('Emitting event', EventTypes.savedMessage)
this.emit(EventTypes.savedMessage, message)
}
return message
} catch (error) {
this.emit(EventTypes.error, error)
return Promise.reject(error)
debug('Validated message %o', message)
if (save) {
await message.save()
debug('Emitting event', EventTypes.savedMessage)
this.emit(EventTypes.savedMessage, message)
}
return message
} catch (error) {
this.emit(EventTypes.error, error)
return Promise.reject(error)
}
}

public async handleAction(action: Action): Promise<any> {
if (!this.actionHandler) {
return Promise.reject('Action handler not provided')
}
debug('Handle action %o', action)
return this.actionHandler.handleAction(action, this)
}
}
49 changes: 26 additions & 23 deletions packages/daf-did-comm/src/action-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import Debug from 'debug'
const debug = Debug('daf:did-comm:action-handler')

export const ActionTypes = {
sendJwt: 'action.sendJwt',
sendMessageDIDCommAlpha1: 'send.message.didcomm-alpha-1',
}

export interface ActionSendJWT extends Action {
export interface ActionSendDIDComm extends Action {
url?: string
save?: boolean
data: {
id?: string
from: string
to: string
jwt: string
type: string
body: any
}
}

Expand All @@ -22,51 +26,50 @@ export class DIDCommActionHandler extends AbstractActionHandler {
}

public async handleAction(action: Action, agent: Agent) {
if (action.type === ActionTypes.sendJwt) {
const { data } = action as ActionSendJWT
if (action.type === ActionTypes.sendMessageDIDCommAlpha1) {
const { data, url, save = true } = action as ActionSendDIDComm

debug('Resolving didDoc')
const didDoc = await agent.didResolver.resolve(data.to)
const service = didDoc && didDoc.service && didDoc.service.find(item => item.type == 'Messaging')
let serviceEndpoint
if (url) {
serviceEndpoint = url
} else {
const service = didDoc && didDoc.service && didDoc.service.find(item => item.type == 'Messaging')
serviceEndpoint = service?.serviceEndpoint
}

if (service) {
if (serviceEndpoint) {
try {
let body = data.jwt

data.id = data.id || uuid.v4()
let postPayload = JSON.stringify(data)
try {
const identity = await agent.identityManager.getIdentity(data.from)
const dm = JSON.stringify({
'@type': 'JWT',
id: uuid.v4(),
data: data.jwt,
})
debug(dm)

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')

body = await key.encrypt(
postPayload = await key.encrypt(
{
type: 'Ed25519',
publicKeyHex: publicKey?.publicKeyHex,
kid: publicKey?.publicKeyHex,
},
dm,
postPayload,
)

debug('Encrypted:', body)
debug('Encrypted:', postPayload)
} catch (e) {}

debug('Sending to %s', service.serviceEndpoint)
const res = await fetch(service.serviceEndpoint, {
debug('Sending to %s', serviceEndpoint)
const res = await fetch(serviceEndpoint, {
method: 'POST',
body,
body: postPayload,
})
debug('Status', res.status, res.statusText)

if (res.status == 200) {
return agent.handleMessage({ raw: data.jwt, metaData: [{ type: 'DIDComm-sent' }] })
return agent.handleMessage({ raw: data.body, metaData: [{ type: 'DIDComm-sent' }], save })
}

return res.status == 200
Expand Down
37 changes: 23 additions & 14 deletions packages/daf-did-comm/src/graphql.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,47 @@
import { Agent } from 'daf-core'
import { ActionTypes } from './action-handler'
import { ActionTypes, ActionSendDIDComm } from './action-handler'

interface Context {
agent: Agent
}

const actionSendJwt = async (
const sendMessageDidCommAlpha1 = async (
_: any,
args: {
from: string
to: string
jwt: string
save: boolean
url?: string
data: {
from: string
to: string
body: string
type: string
}
},
ctx: Context,
) => {
return await ctx.agent.handleAction({
type: ActionTypes.sendJwt,
data: {
from: args.from,
to: args.to,
jwt: args.jwt,
},
})
type: ActionTypes.sendMessageDIDCommAlpha1,
save: args.save,
url: args.url,
data: args.data,
} as ActionSendDIDComm)
}

export const resolvers = {
Mutation: {
actionSendJwt,
sendMessageDidCommAlpha1,
},
}

export const typeDefs = `
input SendMessageDidCommAlpha1Input {
from: String!
to: String!
type: String!
body: String!
}
extend type Mutation {
actionSendJwt(from: String!, to: String!, jwt: String!): Boolean
sendMessageDidCommAlpha1(data: SendMessageDidCommAlpha1Input!, url: String, save: Boolean = true): Message
}
`
export default {
Expand Down
2 changes: 1 addition & 1 deletion packages/daf-did-comm/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { DIDCommActionHandler, ActionSendJWT, ActionTypes } from './action-handler'
export { DIDCommActionHandler, ActionSendDIDComm, ActionTypes } from './action-handler'
export { DIDCommMessageHandler } from './message-handler'
import DIDCommGql from './graphql'
export { DIDCommGql }
19 changes: 15 additions & 4 deletions packages/daf-did-comm/src/message-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ export class DIDCommMessageHandler extends AbstractMessageHandler {

try {
const json = JSON.parse(decrypted)
if (json['@type'] === 'JWT') {
message.raw = json.data
if (json['type'] === 'jwt') {
message.raw = json.body
message.addMetaData({ type: 'DIDComm' })
} else {
if (json['@id']) message.id = json['@id']
if (json['@type']) message.type = json['@type']
if (json['id']) message.id = json['id']
if (json['type']) message.type = json['type']
message.raw = decrypted
message.data = json
message.addMetaData({ type: 'DIDComm' })
Expand All @@ -45,6 +45,17 @@ export class DIDCommMessageHandler extends AbstractMessageHandler {
return super.handle(message, agent)
}
}
} else if (parsed.type === 'jwt') {
message.raw = parsed.body
if (parsed['id']) message.id = parsed['id']
message.addMetaData({ type: 'DIDComm' })
return super.handle(message, agent)
} else {
message.data = parsed.body
if (parsed['id']) message.id = parsed['id']
if (parsed['type']) message.type = parsed['type']
message.addMetaData({ type: 'DIDComm' })
return super.handle(message, agent)
}
} catch (e) {
// not a JSON string
Expand Down

0 comments on commit 49e6841

Please sign in to comment.