1
1
import type { Logger } from '../logger'
2
2
import type { ConnectionRecord } from '../modules/connections'
3
3
import type { InboundTransport } from '../transport'
4
- import type { UnpackedMessageContext , UnpackedMessage , WireMessage } from '../types'
4
+ import type { DecryptedMessageContext , PlaintextMessage , EncryptedMessage } from '../types'
5
5
import type { AgentMessage } from './AgentMessage'
6
6
import type { TransportSession } from './TransportService'
7
7
@@ -59,21 +59,29 @@ export class MessageReceiver {
59
59
}
60
60
61
61
/**
62
- * Receive and handle an inbound DIDComm message. It will unpack the message, transform it
62
+ * Receive and handle an inbound DIDComm message. It will decrypt the message, transform it
63
63
* to it's corresponding message class and finally dispatch it to the dispatcher.
64
64
*
65
- * @param inboundPackedMessage the message to receive and handle
65
+ * @param inboundMessage the message to receive and handle
66
66
*/
67
- public async receiveMessage ( inboundPackedMessage : unknown , session ?: TransportSession ) {
68
- if ( typeof inboundPackedMessage !== 'object' || inboundPackedMessage == null ) {
69
- throw new AriesFrameworkError ( 'Invalid message received. Message should be object' )
67
+ public async receiveMessage ( inboundMessage : unknown , session ?: TransportSession ) {
68
+ this . logger . debug ( `Agent ${ this . config . label } received message` )
69
+
70
+ if ( this . isPlaintextMessage ( inboundMessage ) ) {
71
+ await this . receivePlaintextMessage ( inboundMessage )
72
+ } else {
73
+ await this . receiveEncryptedMessage ( inboundMessage as EncryptedMessage , session )
70
74
}
75
+ }
71
76
72
- this . logger . debug ( `Agent ${ this . config . label } received message` )
77
+ private async receivePlaintextMessage ( plaintextMessage : PlaintextMessage ) {
78
+ const message = await this . transformAndValidate ( plaintextMessage )
79
+ const messageContext = new InboundMessageContext ( message , { } )
80
+ await this . dispatcher . dispatch ( messageContext )
81
+ }
73
82
74
- const unpackedMessage = await this . unpackMessage ( inboundPackedMessage as WireMessage )
75
- const senderKey = unpackedMessage . senderVerkey
76
- const recipientKey = unpackedMessage . recipientVerkey
83
+ private async receiveEncryptedMessage ( encryptedMessage : EncryptedMessage , session ?: TransportSession ) {
84
+ const { plaintextMessage, senderKey, recipientKey } = await this . decryptMessage ( encryptedMessage )
77
85
78
86
let connection : ConnectionRecord | null = null
79
87
@@ -90,27 +98,11 @@ export class MessageReceiver {
90
98
}
91
99
92
100
this . logger . info (
93
- `Received message with type '${ unpackedMessage . message [ '@type' ] } ' from connection ${ connection ?. id } (${ connection ?. theirLabel } )` ,
94
- unpackedMessage . message
101
+ `Received message with type '${ plaintextMessage [ '@type' ] } ' from connection ${ connection ?. id } (${ connection ?. theirLabel } )` ,
102
+ plaintextMessage
95
103
)
96
104
97
- let message : AgentMessage | null = null
98
- try {
99
- message = await this . transformMessage ( unpackedMessage )
100
- await this . validateMessage ( message )
101
- } catch ( error ) {
102
- if ( connection ) await this . sendProblemReportMessage ( error . message , connection , unpackedMessage )
103
- throw error
104
- }
105
-
106
- const messageContext = new InboundMessageContext ( message , {
107
- // Only make the connection available in message context if the connection is ready
108
- // To prevent unwanted usage of unready connections. Connections can still be retrieved from
109
- // Storage if the specific protocol allows an unready connection to be used.
110
- connection : connection ?. isReady ? connection : undefined ,
111
- senderVerkey : senderKey ,
112
- recipientVerkey : recipientKey ,
113
- } )
105
+ const message = await this . transformAndValidate ( plaintextMessage , connection )
114
106
115
107
// We want to save a session if there is a chance of returning outbound message via inbound transport.
116
108
// That can happen when inbound message has `return_route` set to `all` or `thread`.
@@ -131,53 +123,68 @@ export class MessageReceiver {
131
123
this . transportService . saveSession ( session )
132
124
}
133
125
126
+ const messageContext = new InboundMessageContext ( message , {
127
+ // Only make the connection available in message context if the connection is ready
128
+ // To prevent unwanted usage of unready connections. Connections can still be retrieved from
129
+ // Storage if the specific protocol allows an unready connection to be used.
130
+ connection : connection ?. isReady ? connection : undefined ,
131
+ senderVerkey : senderKey ,
132
+ recipientVerkey : recipientKey ,
133
+ } )
134
134
await this . dispatcher . dispatch ( messageContext )
135
135
}
136
136
137
137
/**
138
- * Unpack a message using the envelope service.
139
- * If message is not packed, it will be returned as is, but in the unpacked message structure
138
+ * Decrypt a message using the envelope service.
140
139
*
141
- * @param packedMessage the received, probably packed, message to unpack
140
+ * @param message the received inbound message to decrypt
142
141
*/
143
- private async unpackMessage ( packedMessage : WireMessage ) : Promise < UnpackedMessageContext > {
144
- // If the inbound message has no @type field we assume
145
- // the message is packed and must be unpacked first
146
- if ( ! this . isUnpackedMessage ( packedMessage ) ) {
147
- try {
148
- return await this . envelopeService . unpackMessage ( packedMessage )
149
- } catch ( error ) {
150
- this . logger . error ( 'error while unpacking message' , {
151
- error,
152
- packedMessage,
153
- errorMessage : error instanceof Error ? error . message : error ,
154
- } )
155
- throw error
156
- }
142
+ private async decryptMessage ( message : EncryptedMessage ) : Promise < DecryptedMessageContext > {
143
+ try {
144
+ return await this . envelopeService . unpackMessage ( message )
145
+ } catch ( error ) {
146
+ this . logger . error ( 'Error while decrypting message' , {
147
+ error,
148
+ encryptedMessage : message ,
149
+ errorMessage : error instanceof Error ? error . message : error ,
150
+ } )
151
+ throw error
157
152
}
153
+ }
158
154
159
- // If the message does have an @type field we assume
160
- // the message is already unpacked an use it directly
161
- else {
162
- const unpackedMessage : UnpackedMessageContext = { message : packedMessage }
163
- return unpackedMessage
155
+ private isPlaintextMessage ( message : unknown ) : message is PlaintextMessage {
156
+ if ( typeof message !== 'object' || message == null ) {
157
+ throw new AriesFrameworkError ( 'Invalid message received. Message should be object' )
164
158
}
159
+ // If the message does have an @type field we assume the message is in plaintext and it is not encrypted.
160
+ return '@type' in message
165
161
}
166
162
167
- private isUnpackedMessage ( message : Record < string , unknown > ) : message is UnpackedMessage {
168
- return '@type' in message
163
+ private async transformAndValidate (
164
+ plaintextMessage : PlaintextMessage ,
165
+ connection ?: ConnectionRecord | null
166
+ ) : Promise < AgentMessage > {
167
+ let message : AgentMessage
168
+ try {
169
+ message = await this . transformMessage ( plaintextMessage )
170
+ await this . validateMessage ( message )
171
+ } catch ( error ) {
172
+ if ( connection ) await this . sendProblemReportMessage ( error . message , connection , plaintextMessage )
173
+ throw error
174
+ }
175
+ return message
169
176
}
170
177
171
178
/**
172
- * Transform an unpacked DIDComm message into it's corresponding message class. Will look at all message types in the registered handlers.
179
+ * Transform an plaintext DIDComm message into it's corresponding message class. Will look at all message types in the registered handlers.
173
180
*
174
- * @param unpackedMessage the unpacked message for which to transform the message in to a class instance
181
+ * @param message the plaintext message for which to transform the message in to a class instance
175
182
*/
176
- private async transformMessage ( unpackedMessage : UnpackedMessageContext ) : Promise < AgentMessage > {
183
+ private async transformMessage ( message : PlaintextMessage ) : Promise < AgentMessage > {
177
184
// replace did:sov:BzCbsNYhMrjHiqZDTUASHg;spec prefix for message type with https://didcomm.org
178
- replaceLegacyDidSovPrefixOnMessage ( unpackedMessage . message )
185
+ replaceLegacyDidSovPrefixOnMessage ( message )
179
186
180
- const messageType = unpackedMessage . message [ '@type' ]
187
+ const messageType = message [ '@type' ]
181
188
const MessageClass = this . dispatcher . getMessageClassForType ( messageType )
182
189
183
190
if ( ! MessageClass ) {
@@ -187,9 +194,7 @@ export class MessageReceiver {
187
194
}
188
195
189
196
// Cast the plain JSON object to specific instance of Message extended from AgentMessage
190
- const message = JsonTransformer . fromJSON ( unpackedMessage . message , MessageClass )
191
-
192
- return message
197
+ return JsonTransformer . fromJSON ( message , MessageClass )
193
198
}
194
199
195
200
/**
@@ -214,14 +219,14 @@ export class MessageReceiver {
214
219
* Send the problem report message (https://didcomm.org/notification/1.0/problem-report) to the recipient.
215
220
* @param message error message to send
216
221
* @param connection connection to send the message to
217
- * @param unpackedMessage received unpackedMessage
222
+ * @param plaintextMessage received inbound message
218
223
*/
219
224
private async sendProblemReportMessage (
220
225
message : string ,
221
226
connection : ConnectionRecord ,
222
- unpackedMessage : UnpackedMessageContext
227
+ plaintextMessage : PlaintextMessage
223
228
) {
224
- if ( unpackedMessage . message [ '@type' ] === CommonMessageType . ProblemReport ) {
229
+ if ( plaintextMessage [ '@type' ] === CommonMessageType . ProblemReport ) {
225
230
throw new AriesFrameworkError ( message )
226
231
}
227
232
const problemReportMessage = new ProblemReportMessage ( {
@@ -231,7 +236,7 @@ export class MessageReceiver {
231
236
} ,
232
237
} )
233
238
problemReportMessage . setThread ( {
234
- threadId : unpackedMessage . message [ '@id' ] ,
239
+ threadId : plaintextMessage [ '@id' ] ,
235
240
} )
236
241
const outboundMessage = createOutboundMessage ( connection , problemReportMessage )
237
242
if ( outboundMessage ) {
0 commit comments