@docknetwork/wallet-sdk-relay-service 0.4.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ {
2
+ "ignore_dirs": [
3
+ "node_modules"
4
+ ]
5
+ }
@@ -0,0 +1,13 @@
1
+ module.exports = {
2
+ presets: [
3
+ [
4
+ '@babel/preset-env',
5
+
6
+ ],
7
+ ],
8
+ plugins: [
9
+ '@babel/plugin-proposal-class-properties',
10
+ '@babel/plugin-transform-flow-strip-types',
11
+ ],
12
+ };
13
+
package/index.js ADDED
File without changes
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@docknetwork/wallet-sdk-relay-service",
3
+ "version": "0.4.19",
4
+ "license": "https://github.com/docknetwork/react-native-sdk/LICENSE",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/docknetwork/react-native-sdk.git",
8
+ "directory": "packages/relay-service"
9
+ },
10
+ "scripts": {
11
+ "build": "rm -rf lib && rollup -c"
12
+ },
13
+ "dependencies": {
14
+ "uuid": "^9.0.0",
15
+ "@docknetwork/minimal-cipher": "^5.2.1",
16
+ "@docknetwork/sdk": "8.0.0",
17
+ "@docknetwork/wallet-sdk-wasm": "0.4.3"
18
+ },
19
+ "devDependencies": {
20
+ "jest": "29.1.0",
21
+ "ts-jest": "29.1.0",
22
+ "ts-node": "^10.9.1",
23
+ "typescript": "^5.0.4"
24
+ }
25
+ }
@@ -0,0 +1,30 @@
1
+ import json from '@rollup/plugin-json';
2
+ import multiInput from 'rollup-plugin-multi-input';
3
+ import commonjs from '@rollup/plugin-commonjs';
4
+ import {terser} from 'rollup-plugin-terser';
5
+ import flow from 'rollup-plugin-flow';
6
+ import {babel} from '@rollup/plugin-babel';
7
+
8
+ const presets = ['@babel/preset-env'];
9
+
10
+ export default async function () {
11
+ return [
12
+ {
13
+ presets,
14
+ plugins: [multiInput.default(), json(), babel({ babelHelpers: 'bundled' }), flow({all: true}), commonjs()],
15
+ input: ['src/**/*.js', '!src/**/*.test.js'],
16
+ output: [
17
+ {
18
+ dir: 'lib',
19
+ format: 'cjs',
20
+ entryFileNames: '[name].js',
21
+ },
22
+ {
23
+ dir: 'lib',
24
+ format: 'esm',
25
+ entryFileNames: '[name].mjs',
26
+ },
27
+ ],
28
+ },
29
+ ];
30
+ }
@@ -0,0 +1,35 @@
1
+ import {
2
+ DockResolver,
3
+ DIDKeyResolver,
4
+ WildcardMultiResolver,
5
+ UniversalResolver,
6
+ } from '@docknetwork/sdk/resolver';
7
+ import dock from '@docknetwork/sdk';
8
+
9
+ // Create a resolver in order to lookup DIDs for verifying
10
+ export const universalResolverUrl = 'https://uniresolver.io';
11
+
12
+ // class WalletSDKResolver extends WildcardMultiResolver {
13
+ // static PREFIX = WILDCARD;
14
+ // static METHOD = WILDCARD;
15
+
16
+ // async resolve(did) {
17
+ // const trimmedDID = did.split('#')[0];
18
+ // const document = await super.resolve(trimmedDID);
19
+ // return document;
20
+ // }
21
+ // }
22
+
23
+ export const resolver = new WildcardMultiResolver(
24
+ // {
25
+ // dock: new DockResolver(dock), // Prebuilt resolver
26
+ // key: new DIDKeyResolver(), // did:key resolution
27
+ // },
28
+ [
29
+ new DockResolver(dock),
30
+ new DIDKeyResolver(),
31
+ new UniversalResolver(universalResolverUrl),
32
+ ],
33
+ );
34
+
35
+ export {dock};
@@ -0,0 +1,18 @@
1
+ import {hexDIDToQualified} from '@docknetwork/sdk/utils/did';
2
+ import {dockService} from '@docknetwork/wallet-sdk-wasm/src/services/dock/service';
3
+
4
+ export async function resolveDID(did, disableCache = false) {
5
+ // Check if string has no qualifier, if so assume its hex format
6
+ let qualifiedDID = did;
7
+ if (did.substr(0, 4) !== 'did:') {
8
+ if (did.substr(0, 2) !== '0x') {
9
+ // Ensure to prepend 0x to hex string
10
+ qualifiedDID = hexDIDToQualified(`0x${did}`);
11
+ } else {
12
+ // Resolve hex DIDs to qualified (did:dock:xyz)
13
+ qualifiedDID = hexDIDToQualified(did);
14
+ }
15
+ }
16
+
17
+ return await dockService.resolver.resolve(qualifiedDID, disableCache);
18
+ }
package/src/didcomm.js ADDED
@@ -0,0 +1,366 @@
1
+ import {X25519KeyAgreementKey2020} from '@digitalbazaar/x25519-key-agreement-key-2020';
2
+ import {Ed25519VerificationKey2020} from '@digitalbazaar/ed25519-verification-key-2020';
3
+
4
+ import {Cipher} from '@docknetwork/minimal-cipher';
5
+ import {v1 as uuidv1} from 'uuid';
6
+ import base64url from 'base64url';
7
+
8
+ import {resolveDID} from './did/dids';
9
+
10
+ export const DIDCOMM_TYPE_BASIC =
11
+ 'https://didcomm.org/basicmessage/1.0/message';
12
+
13
+ export const DIDCOMM_TYPE_ISSUE_DIRECT =
14
+ 'https://didcomm.org/issue-credential/2.0/issue-credential';
15
+
16
+ export const DIDCOMM_TYPE_REQUEST_ISSUE_WITH_DATA =
17
+ 'https://didcomm.org/issue-credential/2.0/offer-credential';
18
+
19
+ export const userFriendlyTypeMap = {
20
+ issue: DIDCOMM_TYPE_ISSUE_DIRECT,
21
+ 'request-data': DIDCOMM_TYPE_REQUEST_ISSUE_WITH_DATA,
22
+ };
23
+
24
+ const cipher = new Cipher({version: 'recommended'});
25
+
26
+ function decodeBase64Url(string) {
27
+ const buffer = base64url.toBuffer(string);
28
+ return new Uint8Array(buffer.buffer, buffer.offset, buffer.length);
29
+ }
30
+
31
+ function potentialToArray(a) {
32
+ return a ? (Array.isArray(a) ? a : [a]) : [];
33
+ }
34
+
35
+ export async function getKeydocFromDID(didUrl) {
36
+ const didDocument = await resolveDID(didUrl);
37
+ const possibleKeys = [
38
+ ...potentialToArray(didDocument.verificationMethod),
39
+ ...potentialToArray(didDocument.keyAgreement),
40
+ ...potentialToArray(didDocument.publicKey),
41
+ ];
42
+
43
+ const keyDoc = possibleKeys.filter(key => key.id === didUrl)[0];
44
+ return keyDoc;
45
+ }
46
+
47
+ export function isValidDID(did) {
48
+ const didSplit = did.split(':');
49
+ return didSplit[0] === 'did' && didSplit.length > 2;
50
+ }
51
+
52
+ export async function defaultKaKResolver(keyId) {
53
+ const keyIdStr = keyId.id || keyId;
54
+ const keyDoc = await getAgreementKeydocFromDID(keyIdStr);
55
+ if (!keyDoc) {
56
+ throw new Error(`Cannot find key document with ID: ${keyIdStr}`);
57
+ }
58
+ return await getKaKInstanceFromDocument(keyDoc);
59
+ }
60
+
61
+ export async function defaultVerificationKeyResolver(keyId) {
62
+ const keyIdStr = keyId.id || keyId;
63
+ const keyDoc = await getKeydocFromDID(keyIdStr);
64
+ if (!keyDoc) {
65
+ throw new Error(`Cannot find key document with ID: ${keyIdStr}`);
66
+ }
67
+ return await Ed25519VerificationKey2020.from({...keyDoc, keyPair: keyDoc});
68
+ }
69
+
70
+ export async function didcommCreateSignedJWT(
71
+ payload,
72
+ privateKeyDoc,
73
+ generateJWK = false,
74
+ ) {
75
+ const privateKey = await Ed25519VerificationKey2020.from({
76
+ ...privateKeyDoc,
77
+ keyPair: privateKeyDoc,
78
+ });
79
+
80
+ const {sign} = privateKey.signer();
81
+ const header = {
82
+ alg: 'EdDSA',
83
+ kid: privateKeyDoc.id,
84
+ };
85
+ const sub_jwk = generateJWK ? privateKey.toJwk() : undefined;
86
+ const newPayload = {...payload, ...(sub_jwk ? {sub_jwk} : {})};
87
+ const headerBase64URL = base64url(JSON.stringify(header));
88
+ const payloadBase64URL = base64url(JSON.stringify(newPayload));
89
+ const headerAndPayloadBase64URL = `${headerBase64URL}.${payloadBase64URL}`;
90
+ const signPayload = Buffer.from(headerAndPayloadBase64URL);
91
+ const signature = await sign({data: signPayload});
92
+
93
+ return `${headerAndPayloadBase64URL}.${base64url.encode(signature)}`;
94
+ }
95
+
96
+ export async function didcommDecodeSignedJWT(jwt, keyResolver) {
97
+ const resolveKey = keyResolver || defaultVerificationKeyResolver;
98
+ const jwtSplit = jwt.split('.').map(s => s.trim());
99
+ if (jwtSplit.length !== 3) {
100
+ throw new Error(`Malformed JWT, got split length: ${jwtSplit.length}`);
101
+ }
102
+
103
+ const header = JSON.parse(base64url.decode(jwtSplit[0]));
104
+ const {alg, kid: keyId} = header;
105
+ if (!alg || !keyId) {
106
+ throw new Error('Malformed JWT header, expected alg and kid');
107
+ }
108
+
109
+ const publicKey = await resolveKey(keyId);
110
+ const {verify} = publicKey.verifier();
111
+
112
+ const signature = decodeBase64Url(jwtSplit[2]);
113
+ const signPayload = Buffer.from(`${jwtSplit[0]}.${jwtSplit[1]}`);
114
+
115
+ const isVerified = await verify({data: signPayload, signature});
116
+ if (!isVerified) {
117
+ throw new Error('JWT cannot be verified');
118
+ }
119
+
120
+ const body = JSON.parse(base64url.decode(jwtSplit[1]));
121
+ return body;
122
+ }
123
+
124
+ export async function didcommEncrypt(obj, recipients, keyResolver, senderKey) {
125
+ // If ed25519 is supplied, derive X25519 from it
126
+ let keyAgreementKey = senderKey;
127
+ if (senderKey.type !== 'X25519KeyAgreementKey2020') {
128
+ keyAgreementKey = await getDerivedAgreementKey(senderKey);
129
+ }
130
+
131
+ const encryptedJWE = await cipher.encryptObject({
132
+ obj,
133
+ recipients,
134
+ keyResolver: keyResolver || defaultKaKResolver,
135
+ keyAgreementKey,
136
+ });
137
+ return {
138
+ typ: 'application/didcomm-encrypted+json',
139
+ ...encryptedJWE,
140
+ };
141
+ }
142
+
143
+ export async function didcommDecrypt(jwe, keyAgreementKey, keyResolver) {
144
+ return cipher.decryptObject({
145
+ jwe,
146
+ keyAgreementKey,
147
+ keyResolver: keyResolver || defaultKaKResolver,
148
+ });
149
+ }
150
+
151
+ export async function didcommSendMessage(to, message) {
152
+ if (!message.typ || !message.typ.startsWith('application/didcomm')) {
153
+ throw new Error('Only DIDComm messages can be sent with this service');
154
+ }
155
+
156
+ // TODO: did doc lookup for "to" and get service endpoint to send to
157
+ // if exists then send there too. this is pretty low priority and
158
+ // should be addressed as tech debt when theres time and its testable
159
+
160
+ // const relayResult = await RelayService.sendUnauthedMessage({
161
+ // recipientDid: to,
162
+ // message,
163
+ // });
164
+
165
+ // return relayResult.id;
166
+ }
167
+
168
+ export function isValidKeyAgreementDoc(keyDoc) {
169
+ return (
170
+ keyDoc.type === 'X25519KeyAgreementKey2019' ||
171
+ keyDoc.type === 'X25519KeyAgreementKey2020'
172
+ );
173
+ }
174
+
175
+ export function isDerivableKey(keyDoc) {
176
+ return (
177
+ keyDoc.type === 'Ed25519VerificationKey2018' ||
178
+ keyDoc.type === 'Ed25519VerificationKey2019' ||
179
+ keyDoc.type === 'Ed25519VerificationKey2020'
180
+ );
181
+ }
182
+
183
+ export async function getAgreementKeydocFromDID(did) {
184
+ if (!did) {
185
+ return undefined;
186
+ }
187
+
188
+ // Resolve actual DID document and get key agreement keys
189
+ const isDIDUrl = did.indexOf('#') !== -1;
190
+ const didDocument = await resolveDID(did);
191
+
192
+ const keyAgreements = didDocument.keyAgreement
193
+ ? Array.isArray(didDocument.keyAgreement)
194
+ ? didDocument.keyAgreement
195
+ : [didDocument.keyAgreement]
196
+ : [];
197
+
198
+ // User supplied full URL, use that if possible
199
+ // if not it may still require derivation to be valid (such as dock DIDs)
200
+ if (isDIDUrl) {
201
+ const foundDoc = keyAgreements.filter(
202
+ keyDoc => keyDoc.id === did && isValidKeyAgreementDoc(keyDoc),
203
+ )[0];
204
+
205
+ if (foundDoc) {
206
+ return foundDoc;
207
+ }
208
+ }
209
+
210
+ // User supplied DID, find first supported keyagreement document
211
+ const firstKeyAgreement = keyAgreements.filter(isValidKeyAgreementDoc)[0];
212
+ if (firstKeyAgreement) {
213
+ return firstKeyAgreement;
214
+ }
215
+
216
+ // No valid key agreement found on resolution, lets derive one from a ED25519 key if we can
217
+ const publicKeys = didDocument.publicKey
218
+ ? Array.isArray(didDocument.publicKey)
219
+ ? didDocument.publicKey
220
+ : [didDocument.publicKey]
221
+ : [];
222
+
223
+ // See if DID document has any derivable keys
224
+ const derivableKey = publicKeys.filter(isDerivableKey)[0];
225
+ if (derivableKey) {
226
+ return getDerivedAgreementKey(derivableKey);
227
+ }
228
+
229
+ throw new Error(
230
+ `Unable to find or derive X25519 key agreement for DID: ${did}`,
231
+ );
232
+ }
233
+
234
+ export async function getDerivedAgreementKey(derivableKey) {
235
+ if (!isDerivableKey(derivableKey)) {
236
+ throw new Error(`Cannot derive X25519 KAK from type: ${derivableKey.type}`);
237
+ }
238
+
239
+ if (!derivableKey.publicKeyMultibase) {
240
+ derivableKey.publicKeyMultibase = derivableKey.publicKeyBase58;
241
+ }
242
+
243
+ // Convert derivable key into latest 2020 format
244
+ const ed2020VerificationKey = await Ed25519VerificationKey2020.from({
245
+ keyPair: derivableKey,
246
+ ...derivableKey,
247
+ });
248
+
249
+ // Convert ed25519 2020 verification key into a key agreement key
250
+ const derivedKeyAgreement =
251
+ X25519KeyAgreementKey2020.fromEd25519VerificationKey2020({
252
+ keyPair: ed2020VerificationKey,
253
+ ...ed2020VerificationKey,
254
+ });
255
+ return derivedKeyAgreement;
256
+ }
257
+
258
+ export async function getKaKInstanceFromDocument(keyDoc) {
259
+ if (!isValidKeyAgreementDoc(keyDoc)) {
260
+ throw new Error(
261
+ `Invalid key document type for key agreement key: ${keyDoc.type}`,
262
+ );
263
+ }
264
+ return await X25519KeyAgreementKey2020.from(keyDoc);
265
+ }
266
+
267
+ export function getJWERecipientFromDocument(keyDoc, algorithm) {
268
+ return {
269
+ header: {
270
+ kid: keyDoc.id,
271
+ alg: algorithm || 'ECDH-1PU+A256KW',
272
+ },
273
+ };
274
+ }
275
+
276
+ // Defined here: https://identity.foundation/didcomm-messaging/spec/#plaintext-message-structure
277
+ export function formatPayloadToDIDComm(
278
+ to,
279
+ msgType,
280
+ from,
281
+ body,
282
+ replyUrl,
283
+ replyTo,
284
+ ) {
285
+ const msg = {
286
+ id: uuidv1(),
287
+ type: userFriendlyTypeMap[msgType] || msgType || DIDCOMM_TYPE_BASIC,
288
+ created_time: Math.floor(Date.now() / 1000), // Unix timestamp, seconds
289
+ from,
290
+ body,
291
+ };
292
+ if (to) {
293
+ msg.to = to;
294
+ }
295
+ if (replyUrl) {
296
+ msg.reply_url = replyUrl;
297
+ }
298
+ if (replyTo) {
299
+ msg.reply_to = [replyTo];
300
+ }
301
+ return msg;
302
+ }
303
+
304
+ export async function didcommCreateEncrypted({
305
+ senderDid,
306
+ recipientDids = [],
307
+ payload,
308
+ type,
309
+ keyAgreementKey,
310
+ algorithm,
311
+ }) {
312
+ if (!payload) {
313
+ throw new Error('Requires payload to create encrypted didcomm message');
314
+ }
315
+
316
+ if (recipientDids.length === 0) {
317
+ throw new Error('Must supply atleast 1 recipient DID');
318
+ }
319
+
320
+ if (!isValidDID(senderDid)) {
321
+ throw new Error('Sender DID must be a valid DID');
322
+ }
323
+
324
+ if (!recipientDids.every(isValidDID)) {
325
+ throw new Error('Recipient DID is invalid');
326
+ }
327
+
328
+ const recipientKeyDocuments = await Promise.all(
329
+ recipientDids.map(getAgreementKeydocFromDID),
330
+ );
331
+ const recipients = recipientKeyDocuments.map(keyDoc =>
332
+ getJWERecipientFromDocument(keyDoc, algorithm),
333
+ );
334
+
335
+ const keyResolver = async keyId => {
336
+ const keyIdStr = keyId.id || keyId;
337
+ const keyDoc = recipientKeyDocuments.filter(k => k.id === keyIdStr)[0];
338
+ if (!keyDoc) {
339
+ throw new Error(`Cannot find key document with ID: ${keyIdStr}`);
340
+ }
341
+
342
+ const result = await getKaKInstanceFromDocument(keyDoc);
343
+
344
+ return result;
345
+ };
346
+
347
+ const didcommMessage = formatPayloadToDIDComm(
348
+ recipientDids,
349
+ type,
350
+ senderDid,
351
+ payload,
352
+ );
353
+
354
+ try {
355
+ const jweDoc = await didcommEncrypt(
356
+ didcommMessage,
357
+ recipients,
358
+ keyResolver,
359
+ keyAgreementKey,
360
+ );
361
+ return jweDoc;
362
+ } catch (e) {
363
+ console.error(e);
364
+ throw new Error('Error encrypting message');
365
+ }
366
+ }
package/src/index.js ADDED
@@ -0,0 +1,270 @@
1
+ import {isBase64} from '@polkadot/util-crypto';
2
+ import assert from 'assert';
3
+ import axios from 'axios';
4
+ import {Logger} from '@docknetwork/wallet-sdk-wasm/src/core/logger';
5
+ import {
6
+ didcommCreateEncrypted,
7
+ didcommDecrypt,
8
+ didcommCreateSignedJWT,
9
+ DIDCOMM_TYPE_ISSUE_DIRECT,
10
+ getDerivedAgreementKey,
11
+ } from './didcomm';
12
+ import {
13
+ fromBase64,
14
+ generateSignedPayload,
15
+ generateSignedPayloadFromList,
16
+ toBase64,
17
+ } from './payloads';
18
+ import jwtDecode from 'jwt-decode';
19
+ import {dockService} from '@docknetwork/wallet-sdk-wasm/src/services/dock/service';
20
+
21
+ let serviceURL = process.env.RELAY_SERVICE_URL || 'https://relay.dock.io';
22
+
23
+ export const didcomm = {
24
+ encrypt: didcommCreateEncrypted,
25
+ decrypt: didcommDecrypt,
26
+ };
27
+
28
+ const sendMessage = async ({keyPairDoc, recipientDid, message, type}) => {
29
+ assert(!!keyPairDoc, 'keyPairDoc is required');
30
+ assert(!!recipientDid, 'recipientDid is required');
31
+ assert(!!message, 'message is required');
32
+
33
+ const keyAgreementKey = await getDerivedAgreementKey(keyPairDoc);
34
+ const jweMessage = await didcomm.encrypt({
35
+ recipientDids: [recipientDid],
36
+ type: type || DIDCOMM_TYPE_ISSUE_DIRECT,
37
+ senderDid: keyPairDoc.controller,
38
+ payload: message,
39
+ keyAgreementKey,
40
+ });
41
+
42
+ const {payload, did} = await generateSignedPayload(keyPairDoc, {
43
+ to: recipientDid,
44
+ msg: toBase64(jweMessage),
45
+ });
46
+
47
+ try {
48
+ const result = await axios.post(
49
+ `${serviceURL}/messages/${encodeURIComponent(did)}`,
50
+ {
51
+ payload: toBase64(payload),
52
+ },
53
+ );
54
+
55
+ return result.data;
56
+ } catch (err) {
57
+ console.error(err.response);
58
+ return err;
59
+ }
60
+ };
61
+
62
+ const getMessages = async ({
63
+ keyPairDocs,
64
+ limit = 20,
65
+ skipMessageResolution = false,
66
+ }) => {
67
+ assert(!!keyPairDocs, 'keyPairDoc is required');
68
+ assert(Array.isArray(keyPairDocs), 'keyPairDocs must be an array');
69
+ assert(!!keyPairDocs.length, 'keyPairDocs must not be empty');
70
+
71
+ await dockService.waitDockReady();
72
+
73
+ const {payload, dids} = await generateSignedPayloadFromList(keyPairDocs, {
74
+ limit,
75
+ });
76
+
77
+ try {
78
+ const result = await axios.get(
79
+ `${serviceURL}/messages/batch-dids?dids=${encodeURIComponent(
80
+ JSON.stringify(dids),
81
+ )}&payload=${toBase64(payload)}`,
82
+ );
83
+
84
+ const data = result.data;
85
+
86
+ if (skipMessageResolution) {
87
+ return data;
88
+ }
89
+
90
+ const messages = await Promise.all(
91
+ data.map(async message => {
92
+ const didCommMessage = await resolveDidcommMessage({
93
+ message,
94
+ keyPairDocs,
95
+ });
96
+
97
+ return {
98
+ ...message,
99
+ ...didCommMessage,
100
+ msg: didCommMessage.body,
101
+ };
102
+ }),
103
+ );
104
+
105
+ return messages.filter(item => !!item);
106
+ } catch (err) {
107
+ console.error(err.response);
108
+ return err;
109
+ }
110
+ };
111
+
112
+ const registerDIDPushNotification = async ({keyPairDocs, token}) => {
113
+ assert(!!keyPairDocs, 'keyPairDoc is required');
114
+ assert(Array.isArray(keyPairDocs), 'keyPairDocs must be an array');
115
+ assert(!!keyPairDocs.length, 'keyPairDocs must not be empty');
116
+ assert(!!token, 'token is required');
117
+
118
+ const {payload, dids} = await generateSignedPayloadFromList(keyPairDocs, {
119
+ token,
120
+ });
121
+
122
+ try {
123
+ const result = await axios.post(
124
+ `${serviceURL}/register/batch-dids?dids=${encodeURIComponent(
125
+ JSON.stringify(dids),
126
+ )}&payload=${toBase64(payload)}`,
127
+ );
128
+
129
+ return result.data;
130
+ } catch (err) {
131
+ console.error(err.response);
132
+ return err;
133
+ }
134
+ };
135
+
136
+ async function jwtHandler(message) {
137
+ try {
138
+ const jwt = await jwtDecode(message);
139
+ return jwt;
140
+ } catch (err) {
141
+ return false;
142
+ }
143
+ }
144
+
145
+ async function base64Handler(message) {
146
+ if (!isBase64(message)) {
147
+ return false;
148
+ }
149
+
150
+ return fromBase64(message);
151
+ }
152
+
153
+ async function jsonHandler(message) {
154
+ try {
155
+ const json = JSON.parse(message);
156
+ return json;
157
+ } catch (err) {
158
+ return false;
159
+ }
160
+ }
161
+
162
+ const messageHandlers = [base64Handler, jwtHandler, jsonHandler];
163
+
164
+ async function resolveJweString(message) {
165
+ let resolvedMessage = message;
166
+
167
+ try {
168
+ for (const handler of messageHandlers) {
169
+ let _result = await handler(resolvedMessage);
170
+ if (_result) {
171
+ resolvedMessage = _result;
172
+ }
173
+ }
174
+ } catch (e) {
175
+ Logger.debug(`Invalid JWE message received: ${message}`);
176
+ console.error(e);
177
+ return null;
178
+ }
179
+
180
+ return resolvedMessage;
181
+ }
182
+
183
+ function isURL(str) {
184
+ try {
185
+ // eslint-disable-next-line no-new
186
+ new URL(str);
187
+ return true;
188
+ } catch (err) {
189
+ return false;
190
+ }
191
+ }
192
+
193
+ export async function resolveDidcommMessage({keyPairDocs, message}) {
194
+ assert(!!keyPairDocs, 'keyPairDoc is required');
195
+ assert(Array.isArray(keyPairDocs), 'keyPairDocs must be an array');
196
+ assert(!!keyPairDocs.length, 'keyPairDocs must not be empty');
197
+
198
+ let jwe = message.msg || message;
199
+
200
+ if (jwe && jwe.indexOf('didcomm://') > -1) {
201
+ jwe = jwe.replace('didcomm://', '');
202
+ }
203
+
204
+ if (isURL(jwe)) {
205
+ try {
206
+ const {data} = await axios.get(jwe);
207
+ jwe = data;
208
+ } catch (err) {
209
+ console.error(err);
210
+ return null;
211
+ }
212
+ }
213
+
214
+ try {
215
+ // Parse JSON strings
216
+ jwe = JSON.parse(jwe);
217
+ } catch (_err) {}
218
+
219
+ if (typeof jwe === 'string') {
220
+ jwe = await resolveJweString(jwe);
221
+ }
222
+
223
+ let result = jwe;
224
+
225
+ let didCommRecipients = jwe?.recipients?.map(
226
+ recipient => recipient.header.kid,
227
+ );
228
+
229
+ // if no recipients, the message is not encrypted
230
+ if (didCommRecipients) {
231
+ const keyPairDoc = keyPairDocs.find(doc =>
232
+ didCommRecipients.find(did => did.indexOf(doc.controller) > -1),
233
+ );
234
+
235
+ assert(
236
+ !!keyPairDoc,
237
+ `keyPairDoc not found for recipients ${JSON.stringify(
238
+ didCommRecipients,
239
+ )}`,
240
+ );
241
+ const keyAgreementKey = await getDerivedAgreementKey(keyPairDoc);
242
+ result = await didcommDecrypt(jwe, keyAgreementKey);
243
+ }
244
+
245
+ if (!result.body && result.payload) {
246
+ result.body = result.payload;
247
+ }
248
+
249
+ return result;
250
+ }
251
+
252
+ async function signJwt({keyPairDocs, message}) {
253
+ return await didcommCreateSignedJWT(message, keyPairDocs, true);
254
+ }
255
+
256
+ const setServiceURL = ({url}) => {
257
+ assert(!!url, 'url is required');
258
+
259
+ serviceURL = url;
260
+ };
261
+
262
+ export const RelayService = {
263
+ sendMessage,
264
+ getMessages,
265
+ resolveDidcommMessage,
266
+ registerDIDPushNotification,
267
+ setServiceURL,
268
+ serviceURL,
269
+ signJwt,
270
+ };
@@ -0,0 +1,95 @@
1
+ import VerifiableCredential from '@docknetwork/sdk/verifiable-credential';
2
+ import {cryptoWaitReady} from '@polkadot/util-crypto';
3
+ import {getSuiteFromKeyDoc} from '@docknetwork/sdk/utils/vc/helpers';
4
+ import {getKeypairFromDoc} from '@docknetwork/universal-wallet/methods/keypairs';
5
+ import assert from 'assert';
6
+ import base64url from 'base64url';
7
+
8
+ // 1 year
9
+ const DEFAULT_EXPIRATION = 86400 * 1000 * 365;
10
+
11
+ const isDIDDockRegex = /did:dock/gi;
12
+
13
+ export function ensureDIDDockFragment(keyDoc) {
14
+ if (!isDIDDockRegex.test(keyDoc.id)) {
15
+ return keyDoc;
16
+ }
17
+
18
+ keyDoc.id = keyDoc.id.replace(/#.+/, '');
19
+ keyDoc.id = `${keyDoc.id}#keys-1`;
20
+
21
+ return keyDoc;
22
+ }
23
+
24
+ export async function generateSignedPayload(keyPairDoc, subject) {
25
+ assert(!!keyPairDoc, 'keyPairDoc is required');
26
+ assert(!!subject, 'subject is required');
27
+
28
+ await cryptoWaitReady();
29
+
30
+ keyPairDoc = ensureDIDDockFragment(keyPairDoc);
31
+
32
+ const cred = new VerifiableCredential('dock:relay');
33
+ cred.setContext([
34
+ 'https://www.w3.org/2018/credentials/v1',
35
+ {
36
+ dk: 'https://ld.dock.io/credentials#',
37
+ RelayAuthCredential: 'dk:RelayAuthCredential',
38
+ token: 'dk:token',
39
+ limit: 'dk:limit',
40
+ to: 'dk:to',
41
+ msg: 'dk:msg',
42
+ },
43
+ ]);
44
+
45
+ cred.setIssuanceDate(new Date().toISOString());
46
+ cred.setExpirationDate(
47
+ new Date(Date.now() + DEFAULT_EXPIRATION).toISOString(),
48
+ );
49
+ cred.setSubject(subject);
50
+ cred.setIssuer(keyPairDoc.controller);
51
+ cred.addType('RelayAuthCredential');
52
+
53
+ const keyPair = getKeypairFromDoc(keyPairDoc);
54
+ keyPair.signer = keyPair.signer();
55
+ const suite = await getSuiteFromKeyDoc(keyPair);
56
+
57
+ await cred.sign(suite);
58
+
59
+ return {
60
+ payload: [
61
+ subject,
62
+ cred.issuanceDate,
63
+ cred.expirationDate,
64
+ cred.toJSON().proof,
65
+ ],
66
+ did: keyPairDoc.controller,
67
+ };
68
+ }
69
+
70
+ export async function generateSignedPayloadFromList(keyPairDocs, subject) {
71
+ const payload = [];
72
+ const dids = [];
73
+
74
+ for (const keyPairDoc of keyPairDocs) {
75
+ const {payload: signedPayload, did} = await generateSignedPayload(
76
+ keyPairDoc,
77
+ subject,
78
+ );
79
+ payload.push(signedPayload);
80
+ dids.push(did);
81
+ }
82
+
83
+ return {
84
+ payload,
85
+ dids,
86
+ };
87
+ }
88
+
89
+ export function toBase64(payload) {
90
+ return base64url.encode(JSON.stringify(payload));
91
+ }
92
+
93
+ export function fromBase64(payload) {
94
+ return JSON.parse(base64url.decode(payload));
95
+ }
@@ -0,0 +1,65 @@
1
+ import {
2
+ didcommCreateEncrypted,
3
+ didcommDecrypt,
4
+ DIDCOMM_TYPE_ISSUE_DIRECT,
5
+ getDerivedAgreementKey,
6
+ } from '../lib/didcomm';
7
+ import {ALICE_KEY_PAIR_DOC, BOB_KEY_PAIR_DOC} from './mock-data';
8
+ import {dockService} from '@docknetwork/wallet-sdk-wasm/src/services/dock/service';
9
+ import {WildcardMultiResolver} from '@docknetwork/sdk/resolver';
10
+
11
+ const didList = [ALICE_KEY_PAIR_DOC, BOB_KEY_PAIR_DOC];
12
+
13
+ class WalletSDKResolver extends WildcardMultiResolver {
14
+ static PREFIX = WildcardMultiResolver.PREFIX;
15
+ static METHOD = WildcardMultiResolver.METHOD;
16
+
17
+ async resolve(did) {
18
+ const trimmedDID = did.split('#')[0];
19
+ const document = didList.find(
20
+ doc => doc.controller === trimmedDID,
21
+ )?.didResolution;
22
+
23
+ if (!document) {
24
+ throw new Error(`Mock document not found for did: ${trimmedDID}`);
25
+ }
26
+
27
+ return document;
28
+ }
29
+ }
30
+
31
+ const mockDIDResolver = new WalletSDKResolver([
32
+ // new DockResolver(dock),
33
+ // new DIDKeyResolver(),
34
+ // new UniversalResolver(universalResolverUrl),
35
+ ]);
36
+
37
+ dockService.createDIDResolver = () => mockDIDResolver;
38
+ dockService.resolver = mockDIDResolver;
39
+
40
+ describe('DIDComm', () => {
41
+ it('expect to decrypt didcomm message', async () => {
42
+ dockService.resolver = mockDIDResolver;
43
+
44
+ const keyAgreementKey = await getDerivedAgreementKey(ALICE_KEY_PAIR_DOC);
45
+
46
+ const payload = {domain: 'api.dock.io', message: 'test'};
47
+ const jwe = await didcommCreateEncrypted({
48
+ recipientDids: [BOB_KEY_PAIR_DOC.id],
49
+ type: DIDCOMM_TYPE_ISSUE_DIRECT,
50
+ senderDid: ALICE_KEY_PAIR_DOC.controller,
51
+ payload,
52
+ keyAgreementKey,
53
+ });
54
+
55
+ expect(jwe.typ).toBe('application/didcomm-encrypted+json');
56
+ expect(jwe.ciphertext).toBeDefined();
57
+
58
+ const decrypted = await didcommDecrypt(
59
+ jwe,
60
+ await getDerivedAgreementKey(BOB_KEY_PAIR_DOC),
61
+ );
62
+
63
+ expect(decrypted.body).toStrictEqual(payload);
64
+ });
65
+ });
@@ -0,0 +1,148 @@
1
+ export const ALICE_KEY_PAIR_DOC = {
2
+ id: 'did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB#keys-1',
3
+ controller: 'did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB',
4
+ type: 'Ed25519VerificationKey2018',
5
+ publicKeyBase58: '7JkQbHvaAvGtng6yvBe98WVw3N9dWzXQ4qfqXenoJbyV',
6
+ privateKeyBase58:
7
+ '18CdvQzxTetKhpisG3ZiFrurTHDXPuCP9zMSokyJ9Ex8JRmAGDksx96uWSV8Jo8pDG3cw3GbBhPndCs4aZz43ib',
8
+ publicKeyMultibase: 'z7JkQbHvaAvGtng6yvBe98WVw3N9dWzXQ4qfqXenoJbyV',
9
+ privateKeyMultibase:
10
+ 'z18CdvQzxTetKhpisG3ZiFrurTHDXPuCP9zMSokyJ9Ex8JRmAGDksx96uWSV8Jo8pDG3cw3GbBhPndCs4aZz43ib',
11
+ '@context': ['https://w3id.org/wallet/v1'],
12
+ didResolution: {
13
+ '@context': ['https://www.w3.org/ns/did/v1'],
14
+ id: 'did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB',
15
+ controller: ['did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB'],
16
+ publicKey: [
17
+ {
18
+ id: 'did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB#keys-1',
19
+ type: 'Ed25519VerificationKey2018',
20
+ controller: 'did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB',
21
+ publicKeyBase58: '7JkQbHvaAvGtng6yvBe98WVw3N9dWzXQ4qfqXenoJbyV',
22
+ },
23
+ {
24
+ id: 'did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB#keys-2',
25
+ type: 'Bls12381G2VerificationKeyDock2022',
26
+ controller: 'did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB',
27
+ publicKeyBase58:
28
+ 'R1sacExW4V7fDmWKkyy4tdD3Xm4K2qxL4MZiD4Sz2QL3cAtozDBZY8UX1kw8bCe1sEwUDtcwvU8ArcjxiezmFoDKSkQhYgLcXJYfFFEVMicoteAykFZVikV7ZbyP2YKGKuf',
29
+ },
30
+ ],
31
+ authentication: [
32
+ 'did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB#keys-1',
33
+ ],
34
+ assertionMethod: [
35
+ 'did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB#keys-1',
36
+ 'did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB#keys-2',
37
+ ],
38
+ capabilityInvocation: [
39
+ 'did:dock:5GyESjfvJnQoukNrFuXvkAtsJUs1y5Zee39Sr7eGcAcMmWnB#keys-1',
40
+ ],
41
+ },
42
+ };
43
+
44
+ export const BOB_KEY_PAIR_DOC = {
45
+ id: 'did:key:z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ#z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ',
46
+ controller: 'did:key:z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ',
47
+ type: 'Ed25519VerificationKey2018',
48
+ publicKeyBase58: '3urLbVGF6ouYwgotxFy6637VcLqugU2s9i2XVY2yGU4v',
49
+ privateKeyBase58:
50
+ '3rF4Jhp7vF6tavGZCSgkdMM3ANLB7YpmzfRcB5FTs1Q7EgN6u5cCwzCaHCDYcestRSEHzjF82TvJUaj3mdqcbGnS',
51
+ publicKeyMultibase: 'z3urLbVGF6ouYwgotxFy6637VcLqugU2s9i2XVY2yGU4v',
52
+ privateKeyMultibase:
53
+ 'z3rF4Jhp7vF6tavGZCSgkdMM3ANLB7YpmzfRcB5FTs1Q7EgN6u5cCwzCaHCDYcestRSEHzjF82TvJUaj3mdqcbGnS',
54
+ didResolution: {
55
+ '@context': 'https://www.w3.org/ns/did/v1',
56
+ id: 'did:key:z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ',
57
+ verificationMethod: [
58
+ {
59
+ id: 'did:key:z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ#z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ',
60
+ type: 'Ed25519VerificationKey2018',
61
+ controller: 'did:key:z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ',
62
+ publicKeyBase58: '3urLbVGF6ouYwgotxFy6637VcLqugU2s9i2XVY2yGU4v',
63
+ },
64
+ ],
65
+ authentication: [
66
+ 'did:key:z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ#z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ',
67
+ ],
68
+ assertionMethod: [
69
+ 'did:key:z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ#z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ',
70
+ ],
71
+ capabilityDelegation: [
72
+ 'did:key:z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ#z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ',
73
+ ],
74
+ capabilityInvocation: [
75
+ 'did:key:z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ#z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ',
76
+ ],
77
+ keyAgreement: [
78
+ {
79
+ id: 'did:key:z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ#z6LSoj9zjZhAp7MPQcRwC2ynuBXuy9bEgVK5h3sTZ9sMg1Gm',
80
+ type: 'X25519KeyAgreementKey2019',
81
+ controller: 'did:key:z6MkhN7PBjWgSMQ24Bebdpvvw8fVRv7m6MHDqiwTKozzBgrJ',
82
+ publicKeyBase58: 'D3yqDFtJiedeKE4AfPTqabKS8147yt8vp59n4hDpxdW1',
83
+ },
84
+ ],
85
+ },
86
+ };
87
+
88
+ export const PresentationSubmission = {
89
+ presentation_submission: {
90
+ '@context': ['https://www.w3.org/2018/credentials/v1'],
91
+ verifiableCredential: [
92
+ {
93
+ '@context': [
94
+ 'https://www.w3.org/2018/credentials/v1',
95
+ {
96
+ dk: 'https://ld.dock.io/credentials#',
97
+ BasicCredential: 'dk:BasicCredential',
98
+ subjectName: 'dk:subjectName',
99
+ title: 'dk:title',
100
+ name: 'dk:name',
101
+ logo: 'dk:logo',
102
+ description: 'dk:description',
103
+ },
104
+ ],
105
+ credentialStatus: {
106
+ id: 'rev-reg:dock:0xeb9af88d712412dbd2c5c7e7e5e734641215ab8b1423fb7174e088f012985acf',
107
+ type: 'CredentialStatusList2017',
108
+ },
109
+ id: 'https://creds.dock.io/1d28317eb63495340414fb11346d5b7f5fd50b65aa06c8064d88ec3ec993a29b',
110
+ type: ['VerifiableCredential', 'BasicCredential'],
111
+ credentialSubject: {
112
+ id: 'test-id',
113
+ subjectName: 'Maycon Mellos',
114
+ title: 'Credential title',
115
+ },
116
+ issuanceDate: '2022-03-25T10:28:18.848Z',
117
+ proof: {
118
+ type: 'Sr25519Signature2020',
119
+ created: '2022-03-25T10:29:16Z',
120
+ verificationMethod:
121
+ 'did:dock:5Ey2GDHLnX4tgyU4vBoKP2umWaQSCpNLPrVGQMVhaixdqTNB#keys-1',
122
+ proofPurpose: 'assertionMethod',
123
+ proofValue:
124
+ 'z5mXoaeQBRLPZpVioixesWKWa7KZsUYDqVhtatX7rdFqP7cuAG3BeP8ExYQQjarwuAwJPrdvYuJfKFFiB4JR3bm1h',
125
+ },
126
+ issuer: {
127
+ name: 'Maycon Test',
128
+ logo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAEYCAIAAAAI7H7bAAAWF0lEQVR4nOzdd1wUd/7H8VmXsnRQmqCyiA3QVaRYwZJT7zSHJBqTU/A0GiypYPK7JOZOjTlrpKM0QYO9oZzRlBMVYnLGiCWC2CCxAVKVIruLy++RmEeS41DK97PM7M77+W+Y73we3L3c2WGKgdxVwQEAmy58DwCgDxASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAGEBEAAIQEQQEgABBASAAEDvgcAgTIyMgoIGDl8uK+He/9eLj0szM1lMllNTU1VVfXVqzfy8wuOZWUXFFzle0yhkMhdFXzPAILj5aVIToru1q3r03/s9OmzCxeFVVff76y5hAuHdtCcu3u/lOSYViviOG7YMO/4uPUSiaRT5hI0qbWNA98zgIA4ONjt2plqZ2fbxp/v2bOHWq0+cyZXy3MJHT6R4DcSiWRj/AYHB/t2bRUWtlih8NTaULoBIcFvJk+eOHTo4PZuJZVKw8Ne1c5EOgMhwW/eeD20YxuOGTOqf/++1OPoEoQEvxg0yKNfvz4d3jwoaArpODoGIcEvxo31Z9k8wH8k3Sy6ByHBL9pyvlt7m+s6hCQ4pqYmJiayzt9v1642bJtb082ie3CJkCC4D+g3ecqEMQGj3dzkpqamHMdVVFSezP46K+vkZ58de/ToUSfMYGhoyOPmug4h8axLly7vvRc+7+XgZtcHdOvW9fnnnn3+uWd/+OHmxxtiP/30C/5mhNbh0I5PNtZWaanx8+eFPOUqG7m8V1zs+g8/fN/AAP/qCRdC4o1C4XnkyN6AgDad7AoJfvHQwe09ejhpfy7oCITED0dH+x3bkx0d23Gho4fHgKTEaGNjY23OBR2EkPjx2quhZmZm7d3q8XXZMhlaEhyExANra6sZM4I6tu3o0cPRkgAhJB4EBIxiOVk8atTwlJRYmYyHvzXBkyAkHgwf7sO4wqiRwzanxPLyd1toEULiQbvOMTzJyJF+P7dkQjERsEJIPLC0MCdZZ8QIv0MHt7u49CRZDVggJB6UlZVTLdW3r1tyUrSpKT6XeIaQeFBY+CPhan37uqWlbXx8hR7wBSHxIDvna9oF/XyHbknbaGaGlniDkHhw9uz50tJ7tGv6+npt2YKWeIOQeNDY2LgpIZV8WR9vr61bNpm3/4IJYIeQ+LFz5/5r126QL+vtPWTLlk3m5mipsyEkfqhUqpDZC7//Pp98ZW/vwZmHdrr1lpOvDE+BkHhTWnrvhRl/zc4mPvHAcZyrq0tySowF0V+roC0QEp+USlXogjcvX6Z/p4Or3CX9kwQLCwvylaFFCIlnSqXqnXf+rlKpyFcePHhQ+icJlpZoqTMgJP7l5RcsXBimnZYGpqcnoqVOgJAE4fiJrxYtCtdGS4pBntvSE62sLMlXht9DSEKRdTxn0eIl2mhpEFrSPoQkIFlZ2dOmz75y5Rr5ygMHemRm7mJ5tDc8HULimbm5mavcxcNjgJeXYvhwX2trq483xJWWlpHvqFdP55SUGGtrK/KVAQ+I7FSGhoaDFZ4KhWefvm5uveUODvb29radeWdezx7O27clB4eEVlVVd9pORQIhaZeRkaGvr7ef31Bf36FeQwbx/qAFD4/+27clzZz1Ct6gTAshacuIEX5/een5sWP9hXaFgbt7/+ioNXPmLm5qauJ7Fv2BkIhZWJhPnTp55l+mu7v353uWJwoIGPnq4vlx8cl8D6I/EBIZubzXgtA5gYGTdeLG74ULX96+Yy++LFHBWTtWXbp0CQz8057dacf+feill6bpREUcx5mZmS5Z8hrfU+gPhMRk5Ei/I5/uiY5a4+s7tEsXHftlBk2dbGiIQxIa+D12UPfuDsuWvTtp4ni+B+k4MzOzfv365OUV8D2IPkBIHTHjhaAPPnhbD25SsLOz5XsEPYGQ2sfKyjIychXjC8CFAzelU0FI7SCTyRITIocNY31yt3BUVuKsHQ0d+37MI1dXl4wD2/SpIo7jiouL+R5BT+ATqXUymfGCBXMXhM7Vs7c/5OcXFBXd5HsKPYGQWuHgYJ+WGifkyxQ6LGVzOt8j6A+E9DQ9ezrv3LHZ2bk734PQu3698NChI3xPoT/wHemJuna12bkjRS8rUqnUf3t3uUaj4XsQ/YGQnmjF8vecnfXzdfz/WLYqN/cC31PoFYTUspDgF599dhLfU2jFqtURu3cf4HsKfYOQWjBu7Ohly/7G9xRasXpNZHLyVr6n0EM42dDc9GmBK1d+IJVKO2d3VVXVly9fuXrtRmnpvdLSsuqq+6NHD589+yUDA/r/adatj05K2kK+LCCk5iZOGLd+/Upt70Wj0Zw5k/vZ58eys78uLPzh9//pjTcWvvxysDZ2unZtVEJimjZWBoT0X5ydndat+1Cru6ioqNy8OX3/gX/du9fCc4Jef31B2FuLtLHftetQkXYhpF9IpdK42HXae4piff3DHTv2xsUn37//oMUfeP210PCwxdrY9dp10QkJqEi7ENIvQkPnDBkySBsrq9Xqbdv3xMYmPeW+7tdeeyU8/FVt7H3d+pgELbwdEJpBSD+xt7d7840F2lg5J+ebZctXFxU97TXmf5z0zJJwrdz1vX59zKZNm7WxMjSDkH4SHDzD2NiYds26uvply1bvP5D59B9z6u64cuVS2l0/tn59zEZU1FnwdySue3eH2SEv0a753Xfnp7/w11YrGj/O/9ChHba23Wj3znHchog4VNSZ8InErVr1D8JzDBqN5uOPY9vy0vIA/5FJSdHa+IPVhoi4uDg8s65TiT2kAP+RY8eMplpNpVKFhb9/5MiXrf6kmZlpRMQ/tVNRPCrqfKIOSSKRvPtuGNVqSqVy4cLwEye/assPz50zq1u3rlS7/lXETxUlkS8LrRJ1SM9OmeTu3o9kKZVKHRr6VnZOW19RHhzyIsl+fy8ycmMsKuKJeE82SKXSMKI/gDY1Nb3zf39ve0WeHgMc7O1Idv2rqKhNMbGJtGtC24k3pGnT/uzq6kKyVGbm0czMo23/eS8vBcl+fxUVtSk6JoF2TWgXkYZkYW4e9hbNx9GNG0Uf/fPjdm3S3cmRZNePRUejIv6JNKS5L89ydHRgX+fBg5rgkAXl5RXt2orwxUTRMYlR0aiIf2IMydDQYNbMF0iWWrFibUlJaXu3Ki9rX3hPEhObGBW1kWQpYCTGkMaNC7Cn+K6flZV9IONfHdgw/zLBc+tjY5MiI1GRUIgxpMDAP7EvolSqVny4tmPb5uZeqKmpZdl7bFxSRGQ8ywpAS3QhyYyNnxk/hn2d5JStN2/e7ti2jY2PMjM7/ky5uPjkiAhUJCyiC0kxeKBMxnqhd3X1/cREpocfxG/crFKpOrJhfPKGDXEsuwZtEF1IJE/BX75iTW0t07FZcXHJm2+997ChoV1bxcUlfYyKBEl0IXl7D2Zc4dy5CyQP+/3ss38vXrykvr6+LT+s0WgiIuI34IhOqEQXkgfz4/C3bt1FNAt34sRX06b/tay1s+FVVdXz57+B6+iETFwhOTk5Mr7ssba29sjRL+gm4goKrgY9N/Pzz481Njb+73+tqKjcEBEfMGby8RM5hDsFcuK6+nuwYiDjCufOXVSrW/h/PIu7d0sWLgq3sDD39x/Rt6+bna2tRCK5c/fuqVOnL17MI7wMArRHXCEpFJ6MK3x39jzRLM3V1NT+fEdg6zcFggCJ69COPaQLFy4RzQJ6RUQhSaXSIUOY7l9QqxvPnbtINxHoDxGF5OLS09TUhGWF3NzzDx7U0E0E+kNEIcnlPRlXOK/Xx3WOjvZ8j6DDRBSSi0svxhUu6nVIJSX3+B5Bh4koJCcn1rfBXi64SjQL6BsRhdStqw3L5o2Njbdu3aEbB/SKiELqyhbS7dt3W7z4AEBcITmwfZnu8N1HIAYiCsna2opl8w48mwHEQ0QhGRkasmxeVX2fbhYhkkj4nkCXiSkkIyOWzZUNSrpZQN+IKiSmTySVuiN3husQCT6SGIgoJAMDpkvdGxsf0c0iRFIDpnfMaDQaull0j4hCUqnULJszfsUSPsaXNTH+enWdiEJSKtv3pJFmjJmfPSRwJjIZy+aMv15dJ6KQHj5kOltgTfd6TGEytzBn2bxB3CdjRBXSQ5bNtfGCPUExMzVl2fzhQ3wiiUNFRSXL5tp497igMN6sVVHJ9OvVdSIKqb0vX2nG2dmJbhYhMjMzY9m8ohwhiUM52yeSo6O9iQnT13EhMzc3Z/xEYvz16joxhcT2ViKJRCKXs94aKFjOzqwvEWT8wNd1IgrpypVrjCsM8yN4brgwsb9O99q1G0Sz6CQRhZSXf4VxhZEjhxHNIjhyOWtI+cy/Xp0mopDu3LmrVDJdL+fjM0RfL0jr08eVZfPGxkaR368lopA0Gk1hYRHLCjY21r169aCbSEAGDvRg2fzmzdsiv31YRCFxHHf+/PeMK7gzv8xCgMzNzfq4MX0i4QG04grpHHNIQ72YntUqTH5+3oxXrLL/YnWduEI6f571gcPePkOIZhGQ0aOHM67A/ovVdeIK6fr1ojK2P3coBnm6sR0FCY2xsXHQ1CksK9y7V5afX0A3kU4SV0hNTU1nvzvHsoKBgcFbby2im4h/w/y8bWysWVY4/Onnjx6J+q4+0YXEcVxeHuu/nX+c9Ez37g5E4/DP338E4wonTnxFNIsOE11Il5hDMjAwWLx4PtE4/BszdjTL5kql8vTps3Tj6CrRhXThwvfsTxeY8cJzzs6sTxIXguHDffr26c2yQl5+gUql54+FaQvRhVRVVf3tmVzGRYyMDN95+3WiifgUHvYq4wrffsv6y9QPoguJ47iMjMPsiwQGTvbx8aIYhzdTpkzy9R3KuMi33+K4jhNpSJmZR4uLWZ8/LJFIIiNW6e4BXr9+fT5auZRxkcrKqm++OUM0kW4TY0gNDQ2xcUns6/To4ZSYEMX4uDxeWFpabEmLZ3wYOsdxCQlpDQ2iflTDr8QY0s9Hd/+qqqpmX8fTc0B4OOvXjM638sOl3buz3slXW1u3a/d+ool0nkhDamhQbt+xl2SphQvmDhzoTrJU55gzZ1Zg4J/Y19m950BNTS3FRPpApCFxHPfJJ7tIDkskEsnbunMGb9gwn6Xvh7Ovo1KpU1O3U0ykJ6TWNvrzR/p2qa+vt7Cw8PEmuAhV7tKrrq4+N/cCxVxa5Ohov2vnZlO259c9lp6++/DhzyiG0hPi/UT6+btyKtXByXvvhk2dOplkKe35YOnb7CcYOI6rq6uLozhbo0/E+4n0+JtScUnpHyc9w76URCKZOHG8laXlmTPnBHivqKWlxcqVHwQFMV3l/at331uRe07s9000I+qQOI4rKLjWw9nJw2MA+1ISicTLSzFx4ris49mC+hZuZ2e7Z88Wf+abjh7bt+9QTGwiyVL6RNSHdo+tXhNZV1dHtVrfvm4H9qd7CeZGWi8vxcGMbYx3kv+qqqp69ZpIkqX0DELiKiurMg5+Srigvb3d7l2p48cHEK7ZARKJZP68kN27Up2cyC6/WLMmsrKyimo1fSL2Q7vHbt26EzxrBuGjtqRS6cQJ48rKK9hvf+oYOzvblOTYmTOnMz6M4fcKCq4u/eAjqtX0DELiHn8oyYxlvr6UF6EaGhpO+MNYb+8hubkX7t9/QLhyqzw8+qelxg8axPSErf/10UfrC5ifVquvJHJXoRzN88vQ0GD//vRBbI93a5FKpUpN2x4fl1xL903sSeztbZeEvzZ9+tQuXYgP2i9duhz03KxHj/T8RbodhpB+42Bvl5ISw/ioxCepq6s/fiJnz+6MU1//R6Npol3cyan7mDGjJk0cP2KEH+PL21t06dLl+a+8XlpaRr6y3kBI/8XCwjzjwDatPieopKR03/7Mo0e/ZH9YtlQq9fHxmvdy8IQJ44ima0FR0Y9Tg2bV1NRobxd6ACE117u3/GDGdgu2F6q2xZ07d0+cPHX2u3PZOd+0/W2CEomkT5/ePj5efr5Dx4wZxfgAoFbV1tY+93zw9etMj3oWA4TUAv/RI1JSYrVxjNQijUZz69adGzeKbt68XVZeXl5WUVtX1/CwQd3YaGxsbGRkZGlpYWfXzc622wD3/gM9B5iYML0RrO3UavUrr7x5MvtU5+xOpyGklk2ZMjEmei35V3YdotFowsLfz8w8yvcgugGnv1t27doNRwd78jPIOmTFh2v37MngewqdId5/cVu1Zm3U1avX+Z6CHwcPfrp1606+p9Al+ER6IqVSlZFx2MTERKHwFM8xnkaj2bFj3/IVqwV4DbuQIaSnUavVJ7NP5eUXPPPMmE4798AjpVIZvmRpQmIaKmovsfxDy+LYsZPTp8++dfsO34NoV1lZ+Ut/mXf48Od8D6KTEFKbFFy5FhQ06/Tp7/geRFvy8gqmBs1kf6OhaCGktqqsrAoOCT169Eu+B6G3Y+e+6S/MZn9oppjhO1I7aDRNX3x53MbGWqHw5HsWMlHRm1atimhsxNWoTBBS+2g0muPHc76/mO/rN7QTLiPSqgcPapYvX7N5czrfg+gDXNnQQUZGRlOmTJw1a4b30MF8z9JuP/xwc9u2PXv3HXzwAJei0kBIrEaM8F29apmLS0++B2mTktJ7kRHxe/cdamoivpVD5HBox+r27bsZBw9bWVu5D+gv8L/b7t17cM6cxRcuXuJ7ED2ETyQycnmvefNCpj0faGIi43uW5k6d+k9i0pacnG/4HkRvISRiNjbWwcEvhgTPsLOz5XsWTq1WHzn6ZXLS1jzRv75f2xCSVkil0mnP/zl0wVy33nJeBrh163Zq6rZDmUdJ3l4DrUJI2jV48MAJfxg3fry/u3v/TthdVVX1iZNfZWXlfPFFFt6R3JkQUiextrby9Bzg6enu7t7P1dWlV88e7HeJK5XK4uKS/MtXL1++Ulj4Y0HB1aKiH3E6jhcIiTempqa9e7v07i3v28fNydnR1rabnW03SytLYyMjY2MjmUwmkUhUKpVSqVKpVPX1D8vLK4qLS4uLS+7eLblRWFRY+AMu6hEOhARAQNB/9wDQFQgJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAIICQAAggJgABCAiCAkAAI/H8AAAD//4dsMsblw47YAAAAAElFTkSuQmCC',
129
+ description: 'Testing ',
130
+ id: 'did:dock:5Ey2GDHLnX4tgyU4vBoKP2umWaQSCpNLPrVGQMVhaixdqTNB',
131
+ },
132
+ },
133
+ ],
134
+ id: 'did:key:z6MkuFV745LpuAytwrUd9KjxqMrSG3TZiSUqqtVrQsU2gvhe#z6MkuFV745LpuAytwrUd9KjxqMrSG3TZiSUqqtVrQsU2gvhe',
135
+ type: ['VerifiablePresentation'],
136
+ proof: {
137
+ type: 'Ed25519Signature2018',
138
+ created: '2022-12-15T14:08:51Z',
139
+ verificationMethod:
140
+ 'did:key:z6MkuFV745LpuAytwrUd9KjxqMrSG3TZiSUqqtVrQsU2gvhe#z6MkuFV745LpuAytwrUd9KjxqMrSG3TZiSUqqtVrQsU2gvhe',
141
+ proofPurpose: 'authentication',
142
+ challenge: 'b0f0a3ac-5672-48e7-b9b8-4d94e46f3e0a',
143
+ proofValue:
144
+ 'z8VxfnZy7voYzfzSD3Y7fwhssJJvbzcPrGqEev5oHAvQSdDrYW9Epmr36T7ynafwQov6a5KD1Zs4SurHm7MHkbVh',
145
+ },
146
+ holder: 'did:key:z6MkuFV745LpuAytwrUd9KjxqMrSG3TZiSUqqtVrQsU2gvhe',
147
+ },
148
+ };
@@ -0,0 +1,37 @@
1
+ import {RelayService} from '../lib';
2
+ import {dock} from '../lib/did/did-resolver';
3
+ import {ALICE_KEY_PAIR_DOC, BOB_KEY_PAIR_DOC} from './mock-data';
4
+
5
+ describe('Relay service', () => {
6
+ const messageContent = `Test message ${Date.now()}`;
7
+
8
+ beforeAll(async () => {
9
+ await dock.init({
10
+ address: 'wss://knox-1.dock.io',
11
+ });
12
+ });
13
+
14
+ test('Alice can send BOB a message', async () => {
15
+ const result = await RelayService.sendMessage({
16
+ keyPairDoc: ALICE_KEY_PAIR_DOC,
17
+ message: messageContent,
18
+ recipientDid: BOB_KEY_PAIR_DOC.controller,
19
+ });
20
+
21
+ expect(result.success).toBeTruthy();
22
+ });
23
+
24
+ test('BOB can fetch message sent by Alice', async () => {
25
+ const messages = await RelayService.getMessages({
26
+ keyPairDocs: [BOB_KEY_PAIR_DOC, ALICE_KEY_PAIR_DOC],
27
+ limit: 40,
28
+ });
29
+
30
+ const message = messages[0];
31
+
32
+ expect(message._id).toBeDefined();
33
+ expect(message.to).toBe(BOB_KEY_PAIR_DOC.controller);
34
+ expect(message.from).toBe(ALICE_KEY_PAIR_DOC.controller);
35
+ expect(message.msg).toBe(messageContent);
36
+ });
37
+ });
@@ -0,0 +1,186 @@
1
+ import axios from 'axios';
2
+ import {didcomm, RelayService, resolveDidcommMessage} from '../lib';
3
+ import {generateSignedPayload, toBase64} from '../lib/payloads';
4
+ import {ALICE_KEY_PAIR_DOC, BOB_KEY_PAIR_DOC} from './mock-data';
5
+ import {didcommCreateEncrypted} from '../lib/didcomm';
6
+ import {getDerivedAgreementKey} from '../lib/didcomm';
7
+
8
+ describe('Relay service', () => {
9
+ beforeEach(() => {
10
+ jest.spyOn(didcomm, 'encrypt').mockImplementationOnce(msg => msg);
11
+ jest.spyOn(didcomm, 'decrypt').mockImplementationOnce(msg => msg);
12
+ });
13
+
14
+ describe('generateSignedPayload', () => {
15
+ it('expect to assert parameters', async () => {
16
+ const error = await generateSignedPayload(null, null).catch(err => err);
17
+
18
+ expect(error.toString()).toContain('AssertionError');
19
+ });
20
+
21
+ it('expect to generate signed payload for did:dock', async () => {
22
+ const result = await generateSignedPayload(ALICE_KEY_PAIR_DOC, {
23
+ limit: 20,
24
+ });
25
+
26
+ expect(result).toBeDefined();
27
+ });
28
+
29
+ it('expect to generate signed payload for did:key', async () => {
30
+ const result = await generateSignedPayload(BOB_KEY_PAIR_DOC, {limit: 20});
31
+
32
+ expect(result).toBeDefined();
33
+ });
34
+ });
35
+
36
+ describe('sendMessage', () => {
37
+ it('expect to assert parameters', async () => {
38
+ const error = await RelayService.sendMessage({
39
+ keyPairDoc: null,
40
+ message: null,
41
+ recipientDid: null,
42
+ }).catch(err => err);
43
+
44
+ expect(error.toString()).toContain('AssertionError');
45
+ });
46
+
47
+ it('expect to send message', async () => {
48
+ const result = await RelayService.sendMessage({
49
+ keyPairDoc: BOB_KEY_PAIR_DOC,
50
+ message: 'Test',
51
+ recipientDid: ALICE_KEY_PAIR_DOC.controller,
52
+ });
53
+
54
+ expect(result).toBeDefined();
55
+ });
56
+ });
57
+
58
+ describe('getMessages', () => {
59
+ it('expect to assert parameters', async () => {
60
+ const error = await RelayService.getMessages({
61
+ keyPairDocs: null,
62
+ }).catch(err => err);
63
+
64
+ expect(error.toString()).toContain('AssertionError');
65
+ });
66
+
67
+ it('expect to get messages', async () => {
68
+ jest.spyOn(axios, 'get').mockReturnValueOnce({
69
+ data: [
70
+ {
71
+ to: BOB_KEY_PAIR_DOC.controller,
72
+ msg: toBase64(JSON.stringify({test: 'test'})),
73
+ },
74
+ ],
75
+ });
76
+
77
+ const result = await RelayService.getMessages({
78
+ keyPairDocs: [BOB_KEY_PAIR_DOC],
79
+ limit: 20,
80
+ });
81
+
82
+ expect(result.length).toBeGreaterThanOrEqual(1);
83
+ });
84
+ });
85
+
86
+ describe('registerDIDPushNotification', () => {
87
+ it('expect to registerDIDPushNotification', async () => {
88
+ jest.spyOn(axios, 'post').mockReturnValueOnce({data: ['test']});
89
+
90
+ const result = await RelayService.registerDIDPushNotification({
91
+ keyPairDocs: [BOB_KEY_PAIR_DOC],
92
+ token: 'test',
93
+ });
94
+
95
+ expect(result.length).toBeGreaterThanOrEqual(1);
96
+ });
97
+ });
98
+
99
+ describe('resolveDidcommMessage', () => {
100
+ let didCommMessage;
101
+ let payload;
102
+ const jwtMessage =
103
+ 'eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpkb2NrOjVHNW42TkQ2djUyTDNXVVR1VEI5eGZwbWZUcnNFdlAyRHZRZTlmTkI1aU56cjNyWCNrZXlzLTEifQ.eyJ0eXBlIjoiaHR0cHM6Ly9kaWRjb21tLm9yZy9pc3N1ZS1jcmVkZW50aWFsLzIuMC9pc3N1ZS1jcmVkZW50aWFsIiwic2VuZGVyRGlkIjoiZGlkOmRvY2s6NUc1bjZORDZ2NTJMM1dVVHVUQjl4ZnBtZlRyc0V2UDJEdlFlOWZOQjVpTnpyM3JYIiwicGF5bG9hZCI6eyJkb21haW4iOiJhcGkuZG9jay5pbyIsImNyZWRlbnRpYWxzIjpbeyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIseyJkayI6Imh0dHBzOi8vbGQuZG9jay5pby9jcmVkZW50aWFscyMiLCJCYXNpY0NyZWRlbnRpYWwiOiJkazpCYXNpY0NyZWRlbnRpYWwiLCJuYW1lIjoiZGs6bmFtZSIsImRlc2NyaXB0aW9uIjoiZGs6ZGVzY3JpcHRpb24iLCJsb2dvIjoiZGs6bG9nbyJ9XSwiaWQiOiJodHRwczovL2NyZWRzLXN0YWdpbmcuZG9jay5pby82MzU3Y2ZkZjI0NWNhNmJmYTdiODA1MDg4OGNmOGIwNzczZDc2NjkzYWU1YjBjYjIyZGIwYmI3ZWRlYWE2YjAxIiwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIkJhc2ljQ3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJuYW1lIjoidGVzdCJ9LCJpc3N1YW5jZURhdGUiOiIyMDIzLTA0LTI3VDE2OjA5OjUzLjI2NVoiLCJuYW1lIjoiQmFzaWMgQ3JlZGVudGlhbCIsImlzc3VlciI6eyJuYW1lIjoidGVzdCBzdGFnaW5nIiwiZGVzY3JpcHRpb24iOiIiLCJsb2dvIjoiIiwiaWQiOiJkaWQ6ZG9jazo1RzVuNk5ENnY1MkwzV1VUdVRCOXhmcG1mVHJzRXZQMkR2UWU5Zk5CNWlOenIzclgifSwicHJvb2YiOnsidHlwZSI6IkVkMjU1MTlTaWduYXR1cmUyMDE4IiwiY3JlYXRlZCI6IjIwMjMtMDQtMjdUMTY6Mjg6NDlaIiwidmVyaWZpY2F0aW9uTWV0aG9kIjoiZGlkOmRvY2s6NUc1bjZORDZ2NTJMM1dVVHVUQjl4ZnBtZlRyc0V2UDJEdlFlOWZOQjVpTnpyM3JYI2tleXMtMSIsInByb29mUHVycG9zZSI6ImFzc2VydGlvbk1ldGhvZCIsImp3cyI6ImV5SmhiR2NpT2lKRlpFUlRRU0lzSW1JMk5DSTZabUZzYzJVc0ltTnlhWFFpT2xzaVlqWTBJbDE5Li5EYVJWSXZwYnN0R1dHdUxhc0l4M0REUzZ4dUdETFl1OWd4NHQxTExsTUFYXzZLSEdhdms5eHRGUVhlOWxhU2RyQXkzYWE1ZWE5UWtwWGQxdE9LeFVCUSJ9fV19fQ.v-xtRg9US1RDO9HfgJSa-UxIm5Zd2w-81IihtOyOyyaH713mUIa9FI34Yu1qfliFfklsQ1E7YCg_6bNKmoIzAg';
104
+ const base64Message = JSON.stringify(
105
+ 'eyJwcm90ZWN0ZWQiOiJleUpoYkdjaU9pSllRekl3VUNKOSIsInJlY2lwaWVudHMiOlt7ImhlYWRlciI6eyJhbGciOiJFQ0RILTFQVStBMjU2S1ciLCJraWQiOiJkaWQ6a2V5Ono2TWtoTjdQQmpXZ1NNUTI0QmViZHB2dnc4ZlZSdjdtNk1IRHFpd1RLb3p6QmdySiN6NkxTb2o5empaaEFwN01QUWNSd0MyeW51Qlh1eTliRWdWSzVoM3NUWjlzTWcxR20iLCJlcGsiOnsia3R5IjoiT0tQIiwiY3J2IjoiWDI1NTE5IiwieCI6IkxzQnRaa3VaTFBITFU5YWpXaER4NGRNbWxJd3k3d295SnNFTlFFbkpiaXMifSwic2tpZCI6ImRpZDprZXk6ejZNa285OGJHdnpLRHZHYlJhZm5TTm5KWVNoU1hWcXJCZlp1ZFBaTXZYaGZYM0ZTI3o2TFNwcW50cG5aZFdKaERucDZiY3ZRM3B5SlZtU0VYdEtlUUI2SENxS29xQ0FtRSJ9LCJlbmNyeXB0ZWRfa2V5IjoidzRWajN3Y04zQVhMcmlEUkZ5MjFEelkwanI1bFFiN3l3dEpfZml3ZXR4cHptZ0ZtSFBJTE5RIn1dLCJjaXBoZXJ0ZXh0IjoiaGE1U0FxLU81Wks5YWtHSVlhQmpEWXNBVHdSWkJ5QmJHR1NQQ3RtVU52SGw4STlYbzFVQzdyR2Z4a1pPRG5PdHNwZWFaSENYSjl1T1N6Mjh4a0sxTUk2STkxRFZ3dUNHTVQycWlnT1laM3Mtd1JvZnRCU19TRVpLeUlXREN0cGZ2TzdWdXl2RWR3M240N2JOalRSaVR2VFg5VGEzbFdFRk1UVVFodUNLUE44dHJ5NjFsTWRIMjkxeTYzZ2ZyNzNPdGljX2pTY1E5eF93Y01Ield3WmtBLUdhSGFiaDJjYlVEQ2MwVC15LVFINkJBTzRXbllGbV9DNWl3ajJXY2tNclVVck1GVzQxRTNQeGVQSWo0anlYc3I3SDAzbnVBSEVWY2dFY3lOV01aSVI0VDRaaUNoNkd0dnBHcUFjdGpsbDhxd3Y5OGFQTkgxVENEa3BfTWNNUG1jekRhcGxlMzRCNFd3clFpNklDVnRhTWxCTEVKMGswMzVHSFR3bm9PWXV5TGdDYVJPQ1ItQkU4bWI3ekMtblZvZ2tIMHhXYVphYy1aUllmOVNNaWxXNGMtWGRTLVBFaFZKSTVGN1BYZS1BMVRvZ1RRWUt4cGd6LXd1cF9LaWRSSURuQW5nb2tpT0ZiVFNSalFxODFuNjM1bjZnSUEycWVHcWkzVFZMSFVsbkhicVpwMjlZbUhIVnQxNkM0MHFuWEJJVmZjdkxZdHl2VHlFQWRjbnQyYXE2VTdVck9NVWk4Q2xLUngzd2ZqbXN6MHVGa0tPTjE3Wmp6ZG1oTUZoQ1ZHSDJvUmc0eXFpTWE1MmFUd1JYeWh3dWpVS2gwNGtKRTVoU19sX0hxSlFKWlQ0QXpkaS1ZY1N3MnU5bXZ0WXpyLU9qY2pzVTI0aGpjSmZjRUdZWURRNTZoem5yWGZnY2xKbGZtX2YwSGpjWVNSaGFnUmFNSkstNkdRdUMzNHRWb0pSblFRUUlBSENRVTFnb05fMG9DdjVUVV9sdThCQ3pXdlU4NGh5T2xwS3BuRUtYc2RaMm5zbUcxLTlTRUhNYjQzUDhEQ0Q2T1NyRl9pN2dEVENzeG5TSHczbWJSUUdhcmhQSnNDNWNrdHZ1emRwSFE1UzAxaWc2UDNRVUc4Mjl1dmo5OFF5d0RHcUp1T1ZBQmlyS2F6QmpxaEE1aHhoaVVEVURPWEczU09faDVNZEZ4UFBBZGdjTV9hMHk0ZE1aelFlRDRzb1hLZ2dRTnpxT1dtNWJHTWo1aWp5R2N5bVJoWWI5UWdNdjlPbGhsOWs3ZEpudXNmQk04dEpJRGtKV3NWRjI0WThiZ3F6ZHhSUjdtZTFuendIYVZHVjN5X05ZbnQycERoTEJwN0dqSXBfckNaTEJVSnlfakpHaVZ5VVhHUTNZUDI4N1plTEtpSXJBWTB4Y2hDby1ZbHpaVVZ1eVNVUEdfSVpWUG44bjM1Z19uTXpUdTB0ZDViUmc5RTNsTWJjV3dIbWh2ejlramdFM0hDelU0WlJnUmQtMGF5dWxQZWRiWjJpeXVzYkpWY3BueDRwbElTbDVkSW80QlBEVkUwV1R4ZDI5cGQ1WVdEMTd1R0psbmExVXltakpGSUFpamVyVm1SZk41eEJFRXYxc1RUSjNMVC1iTEUyWGJVcHAzOUpLNURoZndBS2VMTHBaV2xxbXNJczRrTzVnUVlfVGF6bmFpWTZQWEVFMW5LWXpqUzBUX09UUWUzLVI4ZWlvV2RVY3JiR1FDZi0wN0NqMm1CUHFVbk5LNHAtRFFMMWIwN0NpYk5RODlBZlhsajg4bmxCZE1GT3k5SzNuOGhjVlJjcVA2MGxXVENKNkJtbTliV2NJMW5pU0Jxd3dQQWNzZzZ6N2ZRbUM3Sl9SNEFpM0c5d2x4akNlY1FIR2dwRlF4T2VpZ2JHSlhpWHJpSUZNd0QzNGpTTXlUSU9PTFB0MlVGckp5QVhPVFZMSWNKNERhYy1icllLNjQydUpsRGFPMnhtdVJaN2VFTlJKQ21GSVZCNThZRVZmOFhZNXRmUm1hQXE0djBDYlppQzlJZ0FUTnN0U3lzRFVVS245blpvd05HVV9Cak4zSXZQbU1rNWVqSG9BaXdNV3RXRWZObXN2azd4aVAtdldvbk5vRUpyeWQ5OFVkbmdFdDlGcy1HQkc3T01EemlBQUZlREw1V1RoaFVkTUNKRkZ2Ykk4NTAzcWFhQVItWE44NVRENEwybzZkbFcxS090ZlpUSFVxSmc9PSIsIml2IjoiX3d1VzVDZkVaZ3ZJWFc2MVcwMjBXRVQzd01ha1FZVnQiLCJ0YWciOiJVWXNqT0hwa3JGSjVuRVVBSnc0ei13PT0ifQ==',
106
+ );
107
+ const messageURL = 'https://relay.dock.io/read/644aa2c2c67d9c3566f30c86';
108
+
109
+ beforeAll(async () => {
110
+ payload = {test: 'test'};
111
+ const keyAgreementKey = await getDerivedAgreementKey(BOB_KEY_PAIR_DOC);
112
+ didCommMessage = await didcommCreateEncrypted({
113
+ recipientDids: [BOB_KEY_PAIR_DOC.controller],
114
+ type: 'test',
115
+ senderDid: ALICE_KEY_PAIR_DOC.controller,
116
+ payload,
117
+ keyAgreementKey,
118
+ });
119
+ });
120
+
121
+ it('expect to resolve JSON message', async () => {
122
+ const result = await resolveDidcommMessage({
123
+ message: {
124
+ to: BOB_KEY_PAIR_DOC.controller,
125
+ msg: toBase64(didCommMessage),
126
+ },
127
+ keyPairDocs: [BOB_KEY_PAIR_DOC],
128
+ });
129
+
130
+ expect(result.body).toStrictEqual(payload);
131
+ });
132
+
133
+ it('expect to handle JWT', async () => {
134
+ const result = await resolveDidcommMessage({
135
+ message: `${jwtMessage}`,
136
+ keyPairDocs: [BOB_KEY_PAIR_DOC],
137
+ });
138
+
139
+ expect(result.body.credentials).toBeDefined();
140
+ });
141
+
142
+ it('expect to handle JWT with didcomm prefix', async () => {
143
+ const result = await resolveDidcommMessage({
144
+ message: `didcomm://${jwtMessage}`,
145
+ keyPairDocs: [BOB_KEY_PAIR_DOC],
146
+ });
147
+
148
+ expect(result.body.credentials).toBeDefined();
149
+ });
150
+
151
+ it('expect to handle base64 message', async () => {
152
+ const result = await resolveDidcommMessage({
153
+ message: `${base64Message}`,
154
+ keyPairDocs: [BOB_KEY_PAIR_DOC],
155
+ });
156
+
157
+ expect(result.body.credentials).toBeDefined();
158
+ });
159
+
160
+ it('expect to handle URL', async () => {
161
+ const axiosMock = jest.spyOn(axios, 'get').mockImplementation(() => {
162
+ return Promise.resolve({
163
+ data: jwtMessage,
164
+ });
165
+ });
166
+
167
+ const result = await RelayService.resolveDidcommMessage({
168
+ message: `didcomm://${messageURL}`,
169
+ keyPairDocs: [BOB_KEY_PAIR_DOC],
170
+ });
171
+
172
+ expect(result.body.credentials).toBeDefined();
173
+
174
+ axiosMock.mockRestore();
175
+ });
176
+
177
+ it('expect to handle base64 JSON', async () => {
178
+ const result = await RelayService.resolveDidcommMessage({
179
+ message: `didcomm://${toBase64(didCommMessage)}`,
180
+ keyPairDocs: [BOB_KEY_PAIR_DOC],
181
+ });
182
+
183
+ expect(result.body).toStrictEqual(payload);
184
+ });
185
+ });
186
+ });