Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support newer did-communication service type #233

Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions src/agent/AgentConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ export class AgentConfig {

public getEndpoint() {
// If a mediator is used, always return that as endpoint
const mediatorEndpoint = this.inboundConnection?.connection?.theirDidDoc?.service[0].serviceEndpoint
if (mediatorEndpoint) return mediatorEndpoint
const didCommServices = this.inboundConnection?.connection?.theirDidDoc?.didCommServices
if (didCommServices && didCommServices?.length > 0) return didCommServices[0].serviceEndpoint

// Otherwise we check if an endpoint is set
if (this.initConfig.endpoint) return `${this.initConfig.endpoint}/msg`
Expand Down
4 changes: 2 additions & 2 deletions src/agent/__tests__/AgentConfig.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type Indy from 'indy-sdk'
import { getMockConnection } from '../../modules/connections/__tests__/ConnectionService.test'
import { DidDoc, IndyAgentService } from '../../modules/connections'
import { DIDCommService, DidDoc } from '../../modules/connections'
TimoGlastra marked this conversation as resolved.
Show resolved Hide resolved
import { AgentConfig } from '../AgentConfig'

const indy = {} as typeof Indy
Expand All @@ -24,7 +24,7 @@ describe('AgentConfig', () => {
publicKey: [],
authentication: [],
service: [
new IndyAgentService({
new DIDCommService({
id: `test;indy`,
serviceEndpoint: endpoint,
recipientKeys: [],
Expand Down
3 changes: 1 addition & 2 deletions src/agent/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ConnectionRecord } from '../modules/connections'
import { AgentMessage } from './AgentMessage'
import { OutboundMessage } from '../types'
import { ConnectionInvitationMessage } from '../modules/connections'
import { IndyAgentService } from '../modules/connections'

export function createOutboundMessage<T extends AgentMessage = AgentMessage>(
connection: ConnectionRecord,
Expand All @@ -28,7 +27,7 @@ export function createOutboundMessage<T extends AgentMessage = AgentMessage>(
throw new Error(`DidDoc for connection with verkey ${connection.verkey} not found!`)
}

const [service] = theirDidDoc.getServicesByClassType(IndyAgentService)
const [service] = theirDidDoc.didCommServices

return {
connection,
Expand Down
12 changes: 6 additions & 6 deletions src/modules/connections/__tests__/ConnectionService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Wallet } from '../../../wallet/Wallet'
import { ConnectionService } from '../services/ConnectionService'
import { ConnectionRecord, ConnectionStorageProps } from '../repository/ConnectionRecord'
import { AgentConfig } from '../../../agent/AgentConfig'
import { Connection, ConnectionState, ConnectionRole, DidDoc, IndyAgentService } from '../models'
import { Connection, ConnectionState, ConnectionRole, DidDoc, DIDCommService } from '../models'
import { InitConfig } from '../../../types'
import {
ConnectionInvitationMessage,
Expand Down Expand Up @@ -35,7 +35,7 @@ export function getMockConnection({
publicKey: [],
authentication: [],
service: [
new IndyAgentService({
new DIDCommService({
id: `${did};indy`,
serviceEndpoint: 'https://endpoint.com',
recipientKeys: [verkey],
Expand All @@ -54,7 +54,7 @@ export function getMockConnection({
publicKey: [],
authentication: [],
service: [
new IndyAgentService({
new DIDCommService({
id: `${did};indy`,
serviceEndpoint: 'https://endpoint.com',
recipientKeys: [verkey],
Expand Down Expand Up @@ -317,7 +317,7 @@ describe('ConnectionService', () => {
publicKey: [],
authentication: [],
service: [
new IndyAgentService({
new DIDCommService({
id: `${theirDid};indy`,
serviceEndpoint: 'https://endpoint.com',
recipientKeys: [theirVerkey],
Expand Down Expand Up @@ -518,7 +518,7 @@ describe('ConnectionService', () => {
publicKey: [],
authentication: [],
service: [
new IndyAgentService({
new DIDCommService({
id: `${did};indy`,
serviceEndpoint: 'https://endpoint.com',
recipientKeys: [theirVerkey],
Expand Down Expand Up @@ -587,7 +587,7 @@ describe('ConnectionService', () => {
publicKey: [],
authentication: [],
service: [
new IndyAgentService({
new DIDCommService({
id: `${did};indy`,
serviceEndpoint: 'https://endpoint.com',
recipientKeys: [theirVerkey],
Expand Down
16 changes: 15 additions & 1 deletion src/modules/connections/models/did/DidDoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Equals, IsArray, IsString, ValidateNested } from 'class-validator'

import { AuthenticationTransformer, Authentication } from './authentication'
import { PublicKey, PublicKeyTransformer } from './publicKey'
import { Service, ServiceTransformer } from './service'
import { DIDCommService, IndyAgentService, Service, ServiceTransformer } from './service'

type DidDocOptions = Pick<DidDoc, 'id' | 'publicKey' | 'service' | 'authentication'>

Expand Down Expand Up @@ -65,4 +65,18 @@ export class DidDoc {
public getServicesByClassType<S extends Service = Service>(classType: new (...args: never[]) => S): S[] {
return this.service.filter((service) => service instanceof classType) as S[]
}

/**
* Get all DIDComm services ordered by priority descending. This means the highest
* priority will be the first entry.
*/
public get didCommServices(): Array<IndyAgentService | DIDCommService> {
const didCommServiceClasses = [IndyAgentService.type, DIDCommService.type]
TimoGlastra marked this conversation as resolved.
Show resolved Hide resolved
const services = this.service.filter((service) => didCommServiceClasses.includes(service.type)) as Array<
IndyAgentService | DIDCommService
>

// Sort services based on indicated priority
return services.sort((a, b) => b.priority - a.priority)
}
}
30 changes: 28 additions & 2 deletions src/modules/connections/models/did/__tests__/DidDoc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { classToPlain, plainToClass } from 'class-transformer'
import { ReferencedAuthentication, EmbeddedAuthentication } from '../authentication'
import { DidDoc } from '../DidDoc'
import { Ed25119Sig2018, EddsaSaSigSecp256k1, RsaSig2018 } from '../publicKey'
import { Service, IndyAgentService } from '../service'
import { Service, IndyAgentService, DIDCommService } from '../service'

import diddoc from './diddoc.json'

Expand Down Expand Up @@ -56,6 +56,13 @@ const didDoc = new DidDoc({
routingKeys: ['Q4zqM7aXqm7gDQkUVLng9h'],
priority: 5,
}),
new DIDCommService({
id: '7',
serviceEndpoint: 'https://agent.com/did-comm',
recipientKeys: ['DADEajsDSaksLng9h'],
routingKeys: ['DADEajsDSaksLng9h'],
priority: 10,
}),
],
})

Expand All @@ -82,6 +89,7 @@ describe('Did | DidDoc', () => {
// Check Service
expect(didDoc.service[0]).toBeInstanceOf(Service)
expect(didDoc.service[1]).toBeInstanceOf(IndyAgentService)
expect(didDoc.service[2]).toBeInstanceOf(DIDCommService)

// Check Authentication
expect(didDoc.authentication[0]).toBeInstanceOf(ReferencedAuthentication)
Expand Down Expand Up @@ -134,6 +142,14 @@ describe('Did | DidDoc', () => {
routingKeys: ['Q4zqM7aXqm7gDQkUVLng9h'],
priority: 5,
})
expect(json.service[2]).toMatchObject({
id: '7',
type: 'did-communication',
serviceEndpoint: 'https://agent.com/did-comm',
recipientKeys: ['DADEajsDSaksLng9h'],
routingKeys: ['DADEajsDSaksLng9h'],
priority: 10,
})

// Check Authentication
expect(json.authentication[0]).toMatchObject({
Expand Down Expand Up @@ -162,11 +178,21 @@ describe('Did | DidDoc', () => {
})
})

describe('getServicesByType', () => {
describe('getServicesByClassType', () => {
it('returns all services with specified class', async () => {
expect(didDoc.getServicesByClassType(IndyAgentService)).toEqual(
didDoc.service.filter((service) => service instanceof IndyAgentService)
)
})
})

describe('didCommServices', () => {
it('returns all IndyAgentService and DIDCommService instances', async () => {
expect(didDoc.didCommServices).toEqual(expect.arrayContaining([didDoc.service[1], didDoc.service[2]]))
})

it('returns all IndyAgentService and DIDCommService instances sorted by priority', async () => {
expect(didDoc.didCommServices).toEqual([didDoc.service[2], didDoc.service[1]])
})
})
})
60 changes: 58 additions & 2 deletions src/modules/connections/models/did/__tests__/Service.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { classToPlain, plainToClass } from 'class-transformer'
import { Service, ServiceTransformer, serviceTypes, IndyAgentService } from '../service'
import { Service, ServiceTransformer, serviceTypes, IndyAgentService, DIDCommService } from '../service'

describe('Did | Service', () => {
it('should correctly transform Json to Service class', async () => {
Expand Down Expand Up @@ -31,7 +31,6 @@ describe('Did | Service', () => {
expect(transformed).toEqual(json)
})

// TODO: make more generic like in PublicKey.test.ts
describe('IndyAgentService', () => {
it('should correctly transform Json to IndyAgentService class', async () => {
const json = {
Expand Down Expand Up @@ -86,6 +85,63 @@ describe('Did | Service', () => {
})
})

describe('DIDCommService', () => {
it('should correctly transform Json to DIDCommService class', async () => {
const json = {
id: 'test-id',
type: 'did-communication',
recipientKeys: ['917a109d-eae3-42bc-9436-b02426d3ce2c', '348d5200-0f8f-42cc-aad9-61e0d082a674'],
routingKeys: ['0094df0b-7b6d-4ebb-82de-234a621fb615'],
accept: ['media-type'],
priority: 10,
serviceEndpoint: 'https://example.com',
}
const service = plainToClass(DIDCommService, json)

expect(service).toMatchObject(json)
})

it('should correctly transform DIDCommService class to Json', async () => {
const json = {
id: 'test-id',
type: 'did-communication',
recipientKeys: ['917a109d-eae3-42bc-9436-b02426d3ce2c', '348d5200-0f8f-42cc-aad9-61e0d082a674'],
routingKeys: ['0094df0b-7b6d-4ebb-82de-234a621fb615'],
accept: ['media-type'],
priority: 10,
serviceEndpoint: 'https://example.com',
}

const service = new DIDCommService({
...json,
})

const transformed = classToPlain(service)

expect(transformed).toEqual(json)
})

it("should set 'priority' to default (0) when not present in constructor or during transformation", async () => {
const json = {
id: 'test-id',
type: 'did-communication',
recipientKeys: ['917a109d-eae3-42bc-9436-b02426d3ce2c', '348d5200-0f8f-42cc-aad9-61e0d082a674'],
routingKeys: ['0094df0b-7b6d-4ebb-82de-234a621fb615'],
accept: ['media-type'],
serviceEndpoint: 'https://example.com',
}

const transformService = plainToClass(DIDCommService, json)
const constructorService = new DIDCommService({ ...json })

expect(transformService.priority).toBe(0)
expect(constructorService.priority).toBe(0)

expect(classToPlain(transformService).priority).toBe(0)
expect(classToPlain(constructorService).priority).toBe(0)
})
})

describe('ServiceTransformer', () => {
class ServiceTransformerTest {
@ServiceTransformer()
Expand Down
8 changes: 8 additions & 0 deletions src/modules/connections/models/did/__tests__/diddoc.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@
"recipientKeys": ["Q4zqM7aXqm7gDQkUVLng9h"],
"routingKeys": ["Q4zqM7aXqm7gDQkUVLng9h"],
"priority": 5
},
{
"id": "7",
"type": "did-communication",
"serviceEndpoint": "https://agent.com/did-comm",
"recipientKeys": ["DADEajsDSaksLng9h"],
"routingKeys": ["DADEajsDSaksLng9h"],
"priority": 10
}
],
"authentication": [
Expand Down
38 changes: 38 additions & 0 deletions src/modules/connections/models/did/service/DIDCommService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ArrayNotEmpty, IsOptional, IsString } from 'class-validator'
import { Service } from './Service'

export class DIDCommService extends Service {
public constructor(options: {
id: string
serviceEndpoint: string
recipientKeys: string[]
routingKeys?: string[]
accept?: string[]
priority?: number
}) {
super({ ...options, type: DIDCommService.type })

if (options) {
this.recipientKeys = options.recipientKeys
this.routingKeys = options.routingKeys
this.accept = options.accept
if (options.priority) this.priority = options.priority
}
}

public static type = 'did-communication'

@ArrayNotEmpty()
@IsString({ each: true })
public recipientKeys!: string[]

@IsString({ each: true })
@IsOptional()
public routingKeys?: string[]

@IsString({ each: true })
@IsOptional()
public accept?: string[]

public priority = 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export class IndyAgentService extends Service {
routingKeys?: string[]
priority?: number
}) {
super({ ...options, type: 'IndyAgent' })
super({ ...options, type: IndyAgentService.type })

if (options) {
this.recipientKeys = options.recipientKeys
Expand All @@ -18,7 +18,7 @@ export class IndyAgentService extends Service {
}
}

public type = 'IndyAgent'
public static type = 'IndyAgent'

@ArrayNotEmpty()
@IsString({ each: true })
Expand Down
6 changes: 4 additions & 2 deletions src/modules/connections/models/did/service/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Transform, ClassConstructor, plainToClass } from 'class-transformer'

import { IndyAgentService } from './IndyAgentService'
import { DIDCommService } from './DIDCommService'
import { Service } from './Service'

export const serviceTypes: { [key: string]: unknown | undefined } = {
IndyAgent: IndyAgentService,
[IndyAgentService.type]: IndyAgentService,
[DIDCommService.type]: DIDCommService,
}

/**
Expand Down Expand Up @@ -32,4 +34,4 @@ export function ServiceTransformer() {
)
}

export { IndyAgentService, Service }
export { IndyAgentService, DIDCommService, Service }
4 changes: 2 additions & 2 deletions src/modules/connections/repository/ConnectionRecord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export class ConnectionRecord extends BaseRecord implements ConnectionStoragePro
}

public get myKey() {
const [service] = this.didDoc?.getServicesByClassType(IndyAgentService) ?? []
const [service] = this.didDoc?.didCommServices ?? []

if (!service) {
return null
Expand All @@ -128,7 +128,7 @@ export class ConnectionRecord extends BaseRecord implements ConnectionStoragePro
}

public get theirKey() {
const [service] = this.theirDidDoc?.getServicesByClassType(IndyAgentService) ?? []
const [service] = this.theirDidDoc?.didCommServices ?? []

if (!service) {
return null
Expand Down
Loading