Skip to content

Commit

Permalink
feat(did-comm): add trust ping protocol (#1080)
Browse files Browse the repository at this point in the history
* feat(did-comm): add trust ping protocol

* chore: cleanup

* chore: more test

* chore: cleanup

* chore: refactor test slightly

* chore: stash test scratch work

* fix: update jsonld resolution

* chore: cleanup and fixing tests

* chore: cleanup

* chore: cleanup

* chore: cleanup

* chore: remove jsonld resolution

* chore: update README

* chore: PR feedback

* chore: update default agent config

Co-authored-by: Nick Reynolds <nick@joincivil.com>
  • Loading branch information
nickreynolds and Nick Reynolds authored Dec 6, 2022
1 parent 24da47c commit fb22e63
Show file tree
Hide file tree
Showing 10 changed files with 841 additions and 177 deletions.
3 changes: 2 additions & 1 deletion __tests__/shared/didCommPacking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default (testContext: {
afterAll(testContext.tearDown)

it('should pack and unpack a plaintext message', async () => {
expect.assertions(1)
expect.assertions(2)
const message = {
type: 'test',
to: receiver.did,
Expand All @@ -68,6 +68,7 @@ export default (testContext: {
packing: 'none',
message,
})
expect(JSON.parse(packedMessage.message).typ).toEqual('application/didcomm-plain+json')
const unpackedMessage = await agent.unpackDIDCommMessage(packedMessage)
expect(unpackedMessage).toEqual({
message: {
Expand Down
1 change: 1 addition & 0 deletions packages/cli/default/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ messageHandler:
$args:
- messageHandlers:
- $require: '@veramo/did-comm#DIDCommMessageHandler'
- $require: '@veramo/did-comm#TrustPingMessageHandler'
- $require: '@veramo/did-jwt#JwtMessageHandler'
- $require: '@veramo/credential-w3c#W3cMessageHandler'
- $require: '@veramo/selective-disclosure#SdrMessageHandler'
Expand Down
19 changes: 18 additions & 1 deletion packages/did-comm/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# Veramo DIDComm

Veramo messaging plugin implementing DIDComm v2.
Veramo messaging plugin implementing DIDComm v2, as specified by the [DIDComm v2 Spec](https://identity.foundation/didcomm-messaging/spec/) as well as certain "DIDComm Protocols"

## Spec Compliance

### [Message Formats](https://identity.foundation/didcomm-messaging/spec/#message-formats)

Message Envelopes:

| Envelope | Veramo 'packing' | IANA type (`typ`) | packDIDCommMessage | unpackDIDCommMessage | notes |
| -------- | ---------------- | ----------------- | ------------------ | -------------------- | |
| plaintext | 'none' | `application/didcomm-plain+json` | [X] | [X] | |
| signed(plaintext) | 'jws' | `application/didcomm-signed+json` | [X] | [X] | |
| anoncrypt(plaintext) | 'anoncrypt' | `application/didcomm-encrypted+json` | [X] | [X] | |
| authcrypt(plaintext) | 'authcrypt' | `application/didcomm-encrypted+json` | [X] | [X] | |
| anoncrypt(sign(plaintext)) | 'anoncrypt+jws' | `application/didcomm-encrypted+json` | [ ] | [ ] | |
| authcrypt(sign(plaintext)) | 'authcrypt+jws' | `application/didcomm-encrypted+json` | [ ] | [ ] | SHOULD NOT be emitted, but MAY be accepted |
| anoncryptauthcrypt((sign(plaintext))) | '' | `application/didcomm-encrypted+json` | [ ] | [ ] | |

225 changes: 225 additions & 0 deletions packages/did-comm/src/__tests__/message-handler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
import { DIDComm } from "../didcomm"
import {
createAgent,
IDIDManager,
IEventListener,
IIdentifier,
IKeyManager,
IMessageHandler,
IResolver,
TAgent,
} from '../../../core/src'
import { DIDManager, MemoryDIDStore } from '../../../did-manager/src'
import { KeyManager, MemoryKeyStore, MemoryPrivateKeyStore } from '../../../key-manager/src'
import { KeyManagementSystem } from '../../../kms-local/src'
import { DIDResolverPlugin } from '../../../did-resolver/src'
import { Resolver } from 'did-resolver'
import { DIDCommHttpTransport } from "../transports/transports"
import { IDIDComm } from "../types/IDIDComm"
import { MessageHandler } from "../../../message-handler/src"
import { FakeDidProvider, FakeDidResolver } from "../../../test-utils/src"
import { MessagingRouter, RequestWithAgentRouter } from '../../../remote-server/src'
import { Entities, IDataStore, migrations } from '../../../data-store/src'
import express from 'express'
import { Server } from 'http'
import { DIDCommMessageHandler } from "../message-handler"
import { DataStore, DataStoreORM } from "../../../data-store/src"
import { DataSource } from 'typeorm'
import { v4 } from "uuid"


const DIDCommEventSniffer: IEventListener = {
eventTypes: ['DIDCommV2Message-sent', 'DIDCommV2Message-received'],
onEvent: jest.fn(),
}

const databaseFile = `./tmp/local-database2-${Math.random().toPrecision(5)}.sqlite`


describe('did-comm-message-handler', () => {
let sender: IIdentifier
let recipient: IIdentifier
let agent: TAgent<IResolver & IKeyManager & IDIDManager & IDIDComm & IMessageHandler & IDataStore>
let didCommEndpointServer: Server
let listeningPort = Math.round(Math.random() * 32000 + 2048)
let dbConnection: DataSource

beforeAll(async () => {
dbConnection = new DataSource({
name: 'test',
type: 'sqlite',
database: databaseFile,
synchronize: false,
migrations: migrations,
migrationsRun: true,
logging: false,
entities: Entities,
})
agent = createAgent({
plugins: [
new KeyManager({
store: new MemoryKeyStore(),
kms: {
// @ts-ignore
local: new KeyManagementSystem(new MemoryPrivateKeyStore()),
},
}),
new DIDManager({
providers: {
'did:fake': new FakeDidProvider(),
// 'did:web': new WebDIDProvider({ defaultKms: 'local' })
},
store: new MemoryDIDStore(),
defaultProvider: 'did:fake',
}),
new DIDResolverPlugin({
resolver: new Resolver({
...new FakeDidResolver(() => agent).getDidFakeResolver(),
})
}),
// @ts-ignore
new DIDComm([new DIDCommHttpTransport()]),
new MessageHandler({
messageHandlers: [
// @ts-ignore
new DIDCommMessageHandler(),
]
}),
new DataStore(dbConnection),
new DataStoreORM(dbConnection),
DIDCommEventSniffer
],
})

sender = await agent.didManagerImport({
did: 'did:fake:z6MkgbqNU4uF9NKSz5BqJQ4XKVHuQZYcUZP8pXGsJC8nTHwo',
keys: [
{
type: 'Ed25519',
kid: 'didcomm-senderKey-1',
publicKeyHex: '1fe9b397c196ab33549041b29cf93be29b9f2bdd27322f05844112fad97ff92a',
privateKeyHex:
'b57103882f7c66512dc96777cbafbeb2d48eca1e7a867f5a17a84e9a6740f7dc1fe9b397c196ab33549041b29cf93be29b9f2bdd27322f05844112fad97ff92a',
kms: 'local',
},
],
services: [
{
id: 'msg1',
type: 'DIDCommMessaging',
serviceEndpoint: `http://localhost:${listeningPort}/messaging`,
},
],
provider: 'did:fake',
alias: 'sender',
})

recipient = await agent.didManagerImport({
did: 'did:fake:z6MkrPhffVLBZpxH7xvKNyD4sRVZeZsNTWJkLdHdgWbfgNu3',
keys: [
{
type: 'Ed25519',
kid: 'didcomm-receiverKey-1',
publicKeyHex: 'b162e405b6485eff8a57932429b192ec4de13c06813e9028a7cdadf0e2703636',
privateKeyHex:
'19ed9b6949cfd0f9a57e30f0927839a985fa699491886ebcdda6a954d869732ab162e405b6485eff8a57932429b192ec4de13c06813e9028a7cdadf0e2703636',
kms: 'local',
},
],
services: [
{
id: 'msg2',
type: 'DIDCommMessaging',
serviceEndpoint: `http://localhost:${listeningPort}/messaging`,
},
],
provider: 'did:fake',
alias: 'receiver',
})
// console.log("sender: ", sender)
// console.log("recipient: ", recipient)

const requestWithAgent = RequestWithAgentRouter({ agent })

await new Promise((resolve) => {
//setup a server to receive HTTP messages and forward them to this agent to be processed as DIDComm messages
const app = express()
// app.use(requestWithAgent)
app.use(
'/messaging',
requestWithAgent,
MessagingRouter({
metaData: { type: 'DIDComm', value: 'integration test' },
}),
)
didCommEndpointServer = app.listen(listeningPort, () => {
resolve(true)
})
})
})

afterAll(async () => {
try {
await new Promise((resolve, reject) => didCommEndpointServer?.close(resolve))
} catch (e) {
//nop
}
})

const expectMessageReceived = (id: string, packing: string) => {
// recipient sends response
// expect(DIDCommEventSniffer.onEvent).toHaveBeenCalledWith(
// {
// data: `${id}`,
// type: 'DIDCommV2Message-sent'
// },
// expect.anything(),
// )

// original sender receives response
expect(DIDCommEventSniffer.onEvent).toHaveBeenCalledWith(
{
data: {
message: {
body: {
hello: 'world'
},
from: sender.did,
id: `${id}`,
to: recipient.did,
type: 'fake'
},
metaData: { packing },
},
type: 'DIDCommV2Message-received'
},
expect.anything(),
)
}

const getRegularMessage = () => {
return { id: v4(), type: 'fake', to: recipient.did, from: sender.did, body: { hello: 'world' }}
}

it('should pack and unpack message with none packing', async () => {
const anyMessage = getRegularMessage()
const packedMessage = await agent.packDIDCommMessage({ message: anyMessage, packing: 'none'})
const unpackedMessage = await agent.unpackDIDCommMessage(packedMessage)
expect(unpackedMessage.message).toEqual({...anyMessage, typ: 'application/didcomm-plain+json'})
})

it('should pack and unpack message with authcrypt packing', async () => {
const anyMessage = getRegularMessage()
const packedMessage = await agent.packDIDCommMessage({ message: anyMessage, packing: 'authcrypt'})
const unpackedMessage = await agent.unpackDIDCommMessage(packedMessage)
expect(unpackedMessage.message).toEqual(anyMessage)
})

it('should handle packed (with authcrypt) message directly', async () => {
const anyMessage = getRegularMessage()
const packedMessage = await agent.packDIDCommMessage({ message: anyMessage, packing: 'authcrypt'})
const id = anyMessage.id
await agent.handleMessage({raw: packedMessage.message})
expectMessageReceived(id, 'authcrypt')
})
})
Loading

0 comments on commit fb22e63

Please sign in to comment.