Skip to content

Commit 4800700

Browse files
authored
feat(oob): allow to append attachments to invitations (#926)
Signed-off-by: Ariel Gentile <gentilester@gmail.com>
1 parent 95f90a5 commit 4800700

9 files changed

Lines changed: 139 additions & 2 deletions

File tree

packages/core/src/decorators/attachment/AttachmentExtension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Attachment } from './Attachment'
88
export function AttachmentDecorated<T extends BaseMessageConstructor>(Base: T) {
99
class AttachmentDecoratorExtension extends Base {
1010
/**
11-
* The ~attach decorator is required for appending attachments to a preview
11+
* The ~attach decorator is required for appending attachments to a message
1212
*/
1313
@Expose({ name: '~attach' })
1414
@Type(() => Attachment)

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export { InjectionSymbols } from './constants'
2323
export type { Wallet } from './wallet/Wallet'
2424
export type { TransportSession } from './agent/TransportService'
2525
export { TransportService } from './agent/TransportService'
26+
export { Attachment } from './decorators/attachment/Attachment'
2627

2728
import { parseInvitationUrl } from './utils/parseInvitation'
2829
import { uuid } from './utils/uuid'

packages/core/src/modules/connections/__tests__/ConnectionInvitationMessage.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { validateOrReject } from 'class-validator'
22
import { parseUrl } from 'query-string'
33

4+
import { Attachment } from '../../../decorators/attachment/Attachment'
45
import { ClassValidationError } from '../../../error/ClassValidationError'
56
import { JsonEncoder } from '../../../utils/JsonEncoder'
67
import { JsonTransformer } from '../../../utils/JsonTransformer'
@@ -71,6 +72,16 @@ describe('ConnectionInvitationMessage', () => {
7172
serviceEndpoint: 'https://example.com',
7273
label: 'test',
7374
imageUrl: 'test-image-path',
75+
appendedAttachments: [
76+
new Attachment({
77+
id: 'test-attachment',
78+
data: {
79+
json: {
80+
value: 'test',
81+
},
82+
},
83+
}),
84+
],
7485
})
7586

7687
const invitationUrl = invitation.toUrl({

packages/core/src/modules/connections/messages/ConnectionInvitationMessage.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { Attachment } from '../../../decorators/attachment/Attachment'
2+
13
import { Transform } from 'class-transformer'
24
import { ArrayNotEmpty, IsArray, IsOptional, IsString, IsUrl, ValidateIf } from 'class-validator'
35
import { parseUrl } from 'query-string'
@@ -12,6 +14,7 @@ export interface BaseInvitationOptions {
1214
id?: string
1315
label: string
1416
imageUrl?: string
17+
appendedAttachments?: Attachment[]
1518
}
1619

1720
export interface InlineInvitationOptions {
@@ -41,6 +44,7 @@ export class ConnectionInvitationMessage extends AgentMessage {
4144
this.id = options.id || this.generateId()
4245
this.label = options.label
4346
this.imageUrl = options.imageUrl
47+
this.appendedAttachments = options.appendedAttachments
4448

4549
if (isDidInvitation(options)) {
4650
this.did = options.did

packages/core/src/modules/oob/OutOfBandModule.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { AgentMessage } from '../../agent/AgentMessage'
22
import type { AgentMessageReceivedEvent } from '../../agent/Events'
3+
import type { Attachment } from '../../decorators/attachment/Attachment'
34
import type { Logger } from '../../logger'
45
import type { ConnectionRecord, Routing, ConnectionInvitationMessage } from '../../modules/connections'
56
import type { DependencyManager } from '../../plugins'
@@ -54,6 +55,7 @@ export interface CreateOutOfBandInvitationConfig {
5455
multiUseInvitation?: boolean
5556
autoAcceptConnection?: boolean
5657
routing?: Routing
58+
appendedAttachments?: Attachment[]
5759
}
5860

5961
export interface CreateLegacyInvitationConfig {
@@ -134,6 +136,8 @@ export class OutOfBandModule {
134136
const messages = config.messages && config.messages.length > 0 ? config.messages : undefined
135137
const label = config.label ?? this.agentConfig.label
136138
const imageUrl = config.imageUrl ?? this.agentConfig.connectionImageUrl
139+
const appendedAttachments =
140+
config.appendedAttachments && config.appendedAttachments.length > 0 ? config.appendedAttachments : undefined
137141

138142
if (!handshake && !messages) {
139143
throw new AriesFrameworkError(
@@ -182,6 +186,7 @@ export class OutOfBandModule {
182186
accept: didCommProfiles,
183187
services,
184188
handshakeProtocols,
189+
appendedAttachments,
185190
}
186191
const outOfBandInvitation = new OutOfBandInvitation(options)
187192

packages/core/src/modules/oob/__tests__/OutOfBandInvitation.test.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { ClassValidationError } from '../../../error/ClassValidationError'
22

3+
import { Attachment } from '../../../decorators/attachment/Attachment'
34
import { JsonEncoder } from '../../../utils/JsonEncoder'
45
import { JsonTransformer } from '../../../utils/JsonTransformer'
56
import { OutOfBandInvitation } from '../messages/OutOfBandInvitation'
@@ -86,6 +87,70 @@ describe('OutOfBandInvitation', () => {
8687
expect(invitation).toBeInstanceOf(OutOfBandInvitation)
8788
})
8889

90+
test('create an instance of `OutOfBandInvitation` from JSON object with appended attachments', () => {
91+
const json = {
92+
'@type': 'https://didcomm.org/out-of-band/1.1/invitation',
93+
'@id': '69212a3a-d068-4f9d-a2dd-4741bca89af3',
94+
label: 'Faber College',
95+
goal_code: 'issue-vc',
96+
goal: 'To issue a Faber College Graduate credential',
97+
handshake_protocols: ['https://didcomm.org/didexchange/1.0', 'https://didcomm.org/connections/1.0'],
98+
services: ['did:sov:LjgpST2rjsoxYegQDRm7EL'],
99+
'~attach': [
100+
{
101+
'@id': 'view-1',
102+
'mime-type': 'image/png',
103+
filename: 'IMG1092348.png',
104+
lastmod_time: '2018-12-24 18:24:07Z',
105+
description: 'view from doorway, facing east, with lights off',
106+
data: {
107+
base64: 'dmlldyBmcm9tIGRvb3J3YXksIGZhY2luZyBlYXN0LCB3aXRoIGxpZ2h0cyBvZmY=',
108+
},
109+
},
110+
{
111+
'@id': 'view-2',
112+
'mime-type': 'image/png',
113+
filename: 'IMG1092349.png',
114+
lastmod_time: '2018-12-24 18:25:49Z',
115+
description: 'view with lamp in the background',
116+
data: {
117+
base64: 'dmlldyB3aXRoIGxhbXAgaW4gdGhlIGJhY2tncm91bmQ=',
118+
},
119+
},
120+
],
121+
}
122+
123+
const invitation = OutOfBandInvitation.fromJson(json)
124+
expect(invitation).toBeDefined()
125+
expect(invitation).toBeInstanceOf(OutOfBandInvitation)
126+
expect(invitation.appendedAttachments).toBeDefined()
127+
expect(invitation.appendedAttachments?.length).toEqual(2)
128+
expect(invitation.getAppendedAttachmentById('view-1')).toEqual(
129+
new Attachment({
130+
id: 'view-1',
131+
mimeType: 'image/png',
132+
filename: 'IMG1092348.png',
133+
lastmodTime: new Date('2018-12-24 18:24:07Z'),
134+
description: 'view from doorway, facing east, with lights off',
135+
data: {
136+
base64: 'dmlldyBmcm9tIGRvb3J3YXksIGZhY2luZyBlYXN0LCB3aXRoIGxpZ2h0cyBvZmY=',
137+
},
138+
})
139+
)
140+
expect(invitation.getAppendedAttachmentById('view-2')).toEqual(
141+
new Attachment({
142+
id: 'view-2',
143+
mimeType: 'image/png',
144+
filename: 'IMG1092349.png',
145+
lastmodTime: new Date('2018-12-24 18:25:49Z'),
146+
description: 'view with lamp in the background',
147+
data: {
148+
base64: 'dmlldyB3aXRoIGxhbXAgaW4gdGhlIGJhY2tncm91bmQ=',
149+
},
150+
})
151+
)
152+
})
153+
89154
test('throw validation error when services attribute is empty', () => {
90155
const json = {
91156
'@type': 'https://didcomm.org/out-of-band/1.1/invitation',

packages/core/src/modules/oob/__tests__/helpers.test.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Attachment } from '../../../decorators/attachment/Attachment'
12
import { JsonTransformer } from '../../../utils'
23
import { ConnectionInvitationMessage } from '../../connections'
34
import { DidCommV1Service } from '../../dids'
@@ -13,10 +14,23 @@ describe('convertToNewInvitation', () => {
1314
recipientKeys: ['8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K'],
1415
serviceEndpoint: 'https://my-agent.com',
1516
routingKeys: ['6fioC1zcDPyPEL19pXRS2E4iJ46zH7xP6uSgAaPdwDrx'],
17+
appendedAttachments: [
18+
new Attachment({
19+
id: 'attachment-1',
20+
mimeType: 'text/plain',
21+
description: 'attachment description',
22+
filename: 'test.jpg',
23+
data: {
24+
json: {
25+
text: 'sample',
26+
value: 1,
27+
},
28+
},
29+
}),
30+
],
1631
})
1732

1833
const oobInvitation = convertToNewInvitation(connectionInvitation)
19-
2034
expect(oobInvitation).toMatchObject({
2135
id: 'd88ff8fd-6c43-4683-969e-11a87a572cf2',
2236
imageUrl: 'https://my-image.com',
@@ -29,6 +43,15 @@ describe('convertToNewInvitation', () => {
2943
serviceEndpoint: 'https://my-agent.com',
3044
},
3145
],
46+
appendedAttachments: [
47+
{
48+
id: 'attachment-1',
49+
description: 'attachment description',
50+
filename: 'test.jpg',
51+
mimeType: 'text/plain',
52+
data: { json: { text: 'sample', value: 1 } },
53+
},
54+
],
3255
})
3356
})
3457

@@ -38,6 +61,20 @@ describe('convertToNewInvitation', () => {
3861
imageUrl: 'https://my-image.com',
3962
label: 'a-label',
4063
did: 'did:sov:a-did',
64+
appendedAttachments: [
65+
new Attachment({
66+
id: 'attachment-1',
67+
mimeType: 'text/plain',
68+
description: 'attachment description',
69+
filename: 'test.jpg',
70+
data: {
71+
json: {
72+
text: 'sample',
73+
value: 1,
74+
},
75+
},
76+
}),
77+
],
4178
})
4279

4380
const oobInvitation = convertToNewInvitation(connectionInvitation)
@@ -47,6 +84,15 @@ describe('convertToNewInvitation', () => {
4784
imageUrl: 'https://my-image.com',
4885
label: 'a-label',
4986
services: ['did:sov:a-did'],
87+
appendedAttachments: [
88+
{
89+
id: 'attachment-1',
90+
description: 'attachment description',
91+
filename: 'test.jpg',
92+
mimeType: 'text/plain',
93+
data: { json: { text: 'sample', value: 1 } },
94+
},
95+
],
5096
})
5197
})
5298

packages/core/src/modules/oob/helpers.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export function convertToNewInvitation(oldInvitation: ConnectionInvitationMessag
2626
id: oldInvitation.id,
2727
label: oldInvitation.label,
2828
imageUrl: oldInvitation.imageUrl,
29+
appendedAttachments: oldInvitation.appendedAttachments,
2930
accept: ['didcomm/aip1', 'didcomm/aip2;env=rfc19'],
3031
services: [service],
3132
handshakeProtocols: [HandshakeProtocol.Connections],
@@ -45,6 +46,7 @@ export function convertToOldInvitation(newInvitation: OutOfBandInvitation) {
4546
label: newInvitation.label,
4647
did: service,
4748
imageUrl: newInvitation.imageUrl,
49+
appendedAttachments: newInvitation.appendedAttachments,
4850
}
4951
} else {
5052
options = {
@@ -54,6 +56,7 @@ export function convertToOldInvitation(newInvitation: OutOfBandInvitation) {
5456
routingKeys: service.routingKeys?.map(didKeyToVerkey),
5557
serviceEndpoint: service.serviceEndpoint,
5658
imageUrl: newInvitation.imageUrl,
59+
appendedAttachments: newInvitation.appendedAttachments,
5760
}
5861
}
5962

packages/core/src/modules/oob/messages/OutOfBandInvitation.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export interface OutOfBandInvitationOptions {
2626
handshakeProtocols?: HandshakeProtocol[]
2727
services: Array<OutOfBandDidCommService | string>
2828
imageUrl?: string
29+
appendedAttachments?: Attachment[]
2930
}
3031

3132
export class OutOfBandInvitation extends AgentMessage {
@@ -41,6 +42,7 @@ export class OutOfBandInvitation extends AgentMessage {
4142
this.handshakeProtocols = options.handshakeProtocols
4243
this.services = options.services
4344
this.imageUrl = options.imageUrl
45+
this.appendedAttachments = options.appendedAttachments
4446
}
4547
}
4648

0 commit comments

Comments
 (0)