Skip to content

Commit

Permalink
fix(routing): add connection type on mediation grant (#1147)
Browse files Browse the repository at this point in the history
Signed-off-by: Ariel Gentile <[email protected]>
  • Loading branch information
genaris authored Dec 12, 2022
1 parent bf4ceef commit 979c695
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 55 deletions.
23 changes: 10 additions & 13 deletions packages/core/src/modules/connections/ConnectionsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,11 @@ export class ConnectionsApi {
public async addConnectionType(connectionId: string, type: ConnectionType | string) {
const record = await this.getById(connectionId)

const tags = (record.getTag('connectionType') as string[]) || ([] as string[])
record.setTag('connectionType', [type, ...tags])
await this.connectionService.update(this.agentContext, record)
await this.connectionService.addConnectionType(this.agentContext, record, type)

return record
}

/**
* Removes the given tag from the given record found by connectionId, if the tag exists otherwise does nothing
* @param connectionId
Expand All @@ -266,15 +267,11 @@ export class ConnectionsApi {
public async removeConnectionType(connectionId: string, type: ConnectionType | string) {
const record = await this.getById(connectionId)

const tags = (record.getTag('connectionType') as string[]) || ([] as string[])

const newTags = tags.filter((value: string) => {
if (value != type) return value
})
record.setTag('connectionType', [...newTags])
await this.connectionService.removeConnectionType(this.agentContext, record, type)

await this.connectionService.update(this.agentContext, record)
return record
}

/**
* Gets the known connection types for the record matching the given connectionId
* @param connectionId
Expand All @@ -283,16 +280,16 @@ export class ConnectionsApi {
*/
public async getConnectionTypes(connectionId: string) {
const record = await this.getById(connectionId)
const tags = record.getTag('connectionType') as string[]
return tags || null

return this.connectionService.getConnectionTypes(record)
}

/**
*
* @param connectionTypes An array of connection types to query for a match for
* @returns a promise of ab array of connection records
*/
public async findAllByConnectionType(connectionTypes: [ConnectionType | string]) {
public async findAllByConnectionType(connectionTypes: Array<ConnectionType | string>) {
return this.connectionService.findAllByConnectionType(this.agentContext, connectionTypes)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -968,4 +968,55 @@ describe('ConnectionService', () => {
expect(result).toEqual(expect.arrayContaining(expected))
})
})

describe('connectionType', () => {
it('addConnectionType', async () => {
const connection = getMockConnection()

await connectionService.addConnectionType(agentContext, connection, 'type-1')
let connectionTypes = await connectionService.getConnectionTypes(connection)
expect(connectionTypes).toMatchObject(['type-1'])

await connectionService.addConnectionType(agentContext, connection, 'type-2')
await connectionService.addConnectionType(agentContext, connection, 'type-3')

connectionTypes = await connectionService.getConnectionTypes(connection)
expect(connectionTypes.sort()).toMatchObject(['type-1', 'type-2', 'type-3'].sort())
})

it('removeConnectionType - existing type', async () => {
const connection = getMockConnection()

connection.setTag('connectionType', ['type-1', 'type-2', 'type-3'])
let connectionTypes = await connectionService.getConnectionTypes(connection)
expect(connectionTypes).toMatchObject(['type-1', 'type-2', 'type-3'])

await connectionService.removeConnectionType(agentContext, connection, 'type-2')
connectionTypes = await connectionService.getConnectionTypes(connection)
expect(connectionTypes.sort()).toMatchObject(['type-1', 'type-3'].sort())
})

it('removeConnectionType - type not existent', async () => {
const connection = getMockConnection()

connection.setTag('connectionType', ['type-1', 'type-2', 'type-3'])
let connectionTypes = await connectionService.getConnectionTypes(connection)
expect(connectionTypes).toMatchObject(['type-1', 'type-2', 'type-3'])

await connectionService.removeConnectionType(agentContext, connection, 'type-4')
connectionTypes = await connectionService.getConnectionTypes(connection)
expect(connectionTypes.sort()).toMatchObject(['type-1', 'type-2', 'type-3'].sort())
})

it('removeConnectionType - no previous types', async () => {
const connection = getMockConnection()

let connectionTypes = await connectionService.getConnectionTypes(connection)
expect(connectionTypes).toMatchObject([])

await connectionService.removeConnectionType(agentContext, connection, 'type-4')
connectionTypes = await connectionService.getConnectionTypes(connection)
expect(connectionTypes).toMatchObject([])
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export type DefaultConnectionTags = {
theirDid?: string
outOfBandId?: string
invitationDid?: string
connectionType?: [ConnectionType | string]
connectionType?: Array<ConnectionType | string>
}

export class ConnectionRecord
Expand Down Expand Up @@ -91,7 +91,7 @@ export class ConnectionRecord
}
}

public getTags() {
public getTags(): DefaultConnectionTags & CustomConnectionTags {
return {
...this._tags,
state: this.state,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -601,8 +601,8 @@ export class ConnectionService {
return this.connectionRepository.findByQuery(agentContext, { outOfBandId })
}

public async findAllByConnectionType(agentContext: AgentContext, connectionType: [ConnectionType | string]) {
return this.connectionRepository.findByQuery(agentContext, { connectionType })
public async findAllByConnectionType(agentContext: AgentContext, connectionTypes: Array<ConnectionType | string>) {
return this.connectionRepository.findByQuery(agentContext, { connectionType: connectionTypes })
}

public async findByInvitationDid(agentContext: AgentContext, invitationDid: string) {
Expand Down Expand Up @@ -642,6 +642,26 @@ export class ConnectionService {
return connectionRecord
}

public async addConnectionType(agentContext: AgentContext, connectionRecord: ConnectionRecord, type: string) {
const tags = connectionRecord.getTags().connectionType || []
connectionRecord.setTag('connectionType', [type, ...tags])
await this.update(agentContext, connectionRecord)
}

public async removeConnectionType(agentContext: AgentContext, connectionRecord: ConnectionRecord, type: string) {
const tags = connectionRecord.getTags().connectionType || []

const newTags = tags.filter((value: string) => value !== type)
connectionRecord.setTag('connectionType', [...newTags])

await this.update(agentContext, connectionRecord)
}

public async getConnectionTypes(connectionRecord: ConnectionRecord) {
const tags = connectionRecord.getTags().connectionType
return tags || []
}

private async createDid(agentContext: AgentContext, { role, didDoc }: { role: DidDocumentRole; didDoc: DidDoc }) {
// Convert the legacy did doc to a new did document
const didDocument = convertToNewDidDocument(didDoc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ export class MediationRecipientService {
role: MediationRole.Recipient,
connectionId: connection.id,
})
connection.setTag('connectionType', [ConnectionType.Mediator])
await this.connectionService.update(agentContext, connection)

await this.connectionService.addConnectionType(agentContext, connection, ConnectionType.Mediator)

await this.mediationRepository.save(agentContext, mediationRecord)
this.emitStateChangedEvent(agentContext, mediationRecord, null)
Expand Down
77 changes: 49 additions & 28 deletions packages/core/tests/connections.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,7 @@ describe('connections', () => {
let aliceAgent: Agent
let acmeAgent: Agent

afterEach(async () => {
await faberAgent.shutdown()
await faberAgent.wallet.delete()
await aliceAgent.shutdown()
await aliceAgent.wallet.delete()
await acmeAgent.shutdown()
await acmeAgent.wallet.delete()
})

it('one should be able to make multiple connections using a multi use invite', async () => {
beforeEach(async () => {
const faberAgentOptions = getAgentOptions('Faber Agent Connections', {
endpoints: ['rxjs:faber'],
})
Expand Down Expand Up @@ -59,7 +50,18 @@ describe('connections', () => {
acmeAgent.registerInboundTransport(new SubjectInboundTransport(acmeMessages))
acmeAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap))
await acmeAgent.initialize()
})

afterEach(async () => {
await faberAgent.shutdown()
await faberAgent.wallet.delete()
await aliceAgent.shutdown()
await aliceAgent.wallet.delete()
await acmeAgent.shutdown()
await acmeAgent.wallet.delete()
})

it('one should be able to make multiple connections using a multi use invite', async () => {
const faberOutOfBandRecord = await faberAgent.oob.createInvitation({
handshakeProtocols: [HandshakeProtocol.Connections],
multiUseInvitation: true,
Expand Down Expand Up @@ -94,28 +96,47 @@ describe('connections', () => {
return expect(faberOutOfBandRecord.state).toBe(OutOfBandState.AwaitResponse)
})

xit('should be able to make multiple connections using a multi use invite', async () => {
const faberMessages = new Subject<SubjectMessage>()
const subjectMap = {
'rxjs:faber': faberMessages,
}

const faberAgentOptions = getAgentOptions('Faber Agent Connections 2', {
endpoints: ['rxjs:faber'],
it('tag connections with multiple types and query them', async () => {
const faberOutOfBandRecord = await faberAgent.oob.createInvitation({
handshakeProtocols: [HandshakeProtocol.Connections],
multiUseInvitation: true,
})
const aliceAgentOptions = getAgentOptions('Alice Agent Connections 2')

// Faber defines both inbound and outbound transports
faberAgent = new Agent(faberAgentOptions)
faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages))
faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap))
await faberAgent.initialize()
const invitation = faberOutOfBandRecord.outOfBandInvitation
const invitationUrl = invitation.toUrl({ domain: 'https://example.com' })

// Alice only has outbound transport
aliceAgent = new Agent(aliceAgentOptions)
aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap))
await aliceAgent.initialize()
// Receive invitation first time with alice agent
let { connectionRecord: aliceFaberConnection } = await aliceAgent.oob.receiveInvitationFromUrl(invitationUrl)
aliceFaberConnection = await aliceAgent.connections.returnWhenIsConnected(aliceFaberConnection!.id)
expect(aliceFaberConnection.state).toBe(DidExchangeState.Completed)

// Mark connection with three different types
aliceFaberConnection = await aliceAgent.connections.addConnectionType(aliceFaberConnection.id, 'alice-faber-1')
aliceFaberConnection = await aliceAgent.connections.addConnectionType(aliceFaberConnection.id, 'alice-faber-2')
aliceFaberConnection = await aliceAgent.connections.addConnectionType(aliceFaberConnection.id, 'alice-faber-3')

// Now search for them
let connectionsFound = await aliceAgent.connections.findAllByConnectionType(['alice-faber-4'])
expect(connectionsFound).toEqual([])
connectionsFound = await aliceAgent.connections.findAllByConnectionType(['alice-faber-1'])
expect(connectionsFound.map((item) => item.id)).toMatchObject([aliceFaberConnection.id])
connectionsFound = await aliceAgent.connections.findAllByConnectionType(['alice-faber-2'])
expect(connectionsFound.map((item) => item.id)).toMatchObject([aliceFaberConnection.id])
connectionsFound = await aliceAgent.connections.findAllByConnectionType(['alice-faber-3'])
expect(connectionsFound.map((item) => item.id)).toMatchObject([aliceFaberConnection.id])
connectionsFound = await aliceAgent.connections.findAllByConnectionType(['alice-faber-1', 'alice-faber-3'])
expect(connectionsFound.map((item) => item.id)).toMatchObject([aliceFaberConnection.id])
connectionsFound = await aliceAgent.connections.findAllByConnectionType([
'alice-faber-1',
'alice-faber-2',
'alice-faber-3',
])
expect(connectionsFound.map((item) => item.id)).toMatchObject([aliceFaberConnection.id])
connectionsFound = await aliceAgent.connections.findAllByConnectionType(['alice-faber-1', 'alice-faber-4'])
expect(connectionsFound).toEqual([])
})

xit('should be able to make multiple connections using a multi use invite', async () => {
const faberOutOfBandRecord = await faberAgent.oob.createInvitation({
handshakeProtocols: [HandshakeProtocol.Connections],
multiUseInvitation: true,
Expand Down
19 changes: 11 additions & 8 deletions packages/core/tests/oob-mediation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,23 @@ describe('out of band with mediation', () => {
aliceMediatorConnection = await aliceAgent.connections.returnWhenIsConnected(aliceMediatorConnection!.id)
expect(aliceMediatorConnection.state).toBe(DidExchangeState.Completed)

// Tag the connection with an initial type
aliceMediatorConnection = await aliceAgent.connections.addConnectionType(aliceMediatorConnection.id, 'initial-type')

let [mediatorAliceConnection] = await mediatorAgent.connections.findAllByOutOfBandId(mediationOutOfBandRecord.id)
mediatorAliceConnection = await mediatorAgent.connections.returnWhenIsConnected(mediatorAliceConnection!.id)
expect(mediatorAliceConnection.state).toBe(DidExchangeState.Completed)

// ========== Set mediation between Alice and Mediator agents ==========
let connectionTypes = await aliceAgent.connections.getConnectionTypes(aliceMediatorConnection.id)
expect(connectionTypes).toMatchObject(['initial-type'])

const mediationRecord = await aliceAgent.mediationRecipient.requestAndAwaitGrant(aliceMediatorConnection)
const connectonTypes = await aliceAgent.connections.getConnectionTypes(mediationRecord.connectionId)
expect(connectonTypes).toContain(ConnectionType.Mediator)
await aliceAgent.connections.addConnectionType(mediationRecord.connectionId, 'test')
expect(await aliceAgent.connections.getConnectionTypes(mediationRecord.connectionId)).toContain('test')
await aliceAgent.connections.removeConnectionType(mediationRecord.connectionId, 'test')
expect(await aliceAgent.connections.getConnectionTypes(mediationRecord.connectionId)).toEqual([
ConnectionType.Mediator,
])
connectionTypes = await aliceAgent.connections.getConnectionTypes(mediationRecord.connectionId)
expect(connectionTypes.sort()).toMatchObject(['initial-type', ConnectionType.Mediator].sort())
await aliceAgent.connections.removeConnectionType(mediationRecord.connectionId, 'initial-type')
connectionTypes = await aliceAgent.connections.getConnectionTypes(mediationRecord.connectionId)
expect(connectionTypes).toMatchObject([ConnectionType.Mediator])
expect(mediationRecord.state).toBe(MediationState.Granted)

await aliceAgent.mediationRecipient.setDefaultMediator(mediationRecord)
Expand Down

0 comments on commit 979c695

Please sign in to comment.