@verii/server-credentialagent 1.1.0-pre.1765441856 → 1.1.0-pre.1765745740

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verii/server-credentialagent",
3
- "version": "1.1.0-pre.1765441856",
3
+ "version": "1.1.0-pre.1765745740",
4
4
  "description": "Credential Agent application",
5
5
  "main": "src/index.js",
6
6
  "repository": "https://github.com/LFDT-Verii/core",
@@ -40,31 +40,31 @@
40
40
  "@fastify/view": "^11.0.0",
41
41
  "@spencejs/spence-factories": "^0.10.2",
42
42
  "@spencejs/spence-mongo-repos": "^0.10.2",
43
- "@verii/auth": "1.1.0-pre.1765441856",
44
- "@verii/base-contract-io": "1.1.0-pre.1765441856",
45
- "@verii/blockchain-functions": "1.1.0-pre.1765441856",
46
- "@verii/common-fetchers": "1.1.0-pre.1765441856",
47
- "@verii/common-functions": "1.1.0-pre.1765441856",
48
- "@verii/common-schemas": "1.1.0-pre.1765441856",
49
- "@verii/config": "1.1.0-pre.1765441856",
50
- "@verii/contract-permissions": "1.1.0-pre.1765441856",
51
- "@verii/crypto": "1.1.0-pre.1765441856",
52
- "@verii/csv-parser": "1.1.0-pre.1765441856",
53
- "@verii/db-kms": "1.1.0-pre.1765441856",
54
- "@verii/did-doc": "1.1.0-pre.1765441856",
55
- "@verii/fastify-plugins": "1.1.0-pre.1765441856",
56
- "@verii/http-client": "1.1.0-pre.1765441856",
57
- "@verii/jwt": "1.1.0-pre.1765441856",
58
- "@verii/metadata-registration": "1.1.0-pre.1765441856",
59
- "@verii/organizations-registry": "1.1.0-pre.1765441856",
60
- "@verii/rest-queries": "1.1.0-pre.1765441856",
61
- "@verii/server-provider": "1.1.0-pre.1765441856",
62
- "@verii/spencer-mongo-extensions": "1.1.0-pre.1765441856",
63
- "@verii/test-regexes": "1.1.0-pre.1765441856",
64
- "@verii/validation": "1.1.0-pre.1765441856",
65
- "@verii/vc-checks": "1.1.0-pre.1765441856",
66
- "@verii/verii-issuing": "1.1.0-pre.1765441856",
67
- "@verii/verii-verification": "1.1.0-pre.1765441856",
43
+ "@verii/auth": "1.1.0-pre.1765745740",
44
+ "@verii/base-contract-io": "1.1.0-pre.1765745740",
45
+ "@verii/blockchain-functions": "1.1.0-pre.1765745740",
46
+ "@verii/common-fetchers": "1.1.0-pre.1765745740",
47
+ "@verii/common-functions": "1.1.0-pre.1765745740",
48
+ "@verii/common-schemas": "1.1.0-pre.1765745740",
49
+ "@verii/config": "1.1.0-pre.1765745740",
50
+ "@verii/contract-permissions": "1.1.0-pre.1765745740",
51
+ "@verii/crypto": "1.1.0-pre.1765745740",
52
+ "@verii/csv-parser": "1.1.0-pre.1765745740",
53
+ "@verii/db-kms": "1.1.0-pre.1765745740",
54
+ "@verii/did-doc": "1.1.0-pre.1765745740",
55
+ "@verii/fastify-plugins": "1.1.0-pre.1765745740",
56
+ "@verii/http-client": "1.1.0-pre.1765745740",
57
+ "@verii/jwt": "1.1.0-pre.1765745740",
58
+ "@verii/metadata-registration": "1.1.0-pre.1765745740",
59
+ "@verii/organizations-registry": "1.1.0-pre.1765745740",
60
+ "@verii/rest-queries": "1.1.0-pre.1765745740",
61
+ "@verii/server-provider": "1.1.0-pre.1765745740",
62
+ "@verii/spencer-mongo-extensions": "1.1.0-pre.1765745740",
63
+ "@verii/test-regexes": "1.1.0-pre.1765745740",
64
+ "@verii/validation": "1.1.0-pre.1765745740",
65
+ "@verii/vc-checks": "1.1.0-pre.1765745740",
66
+ "@verii/verii-issuing": "1.1.0-pre.1765745740",
67
+ "@verii/verii-verification": "1.1.0-pre.1765745740",
68
68
  "ajv": "8.17.1",
69
69
  "canonicalize": "^2.1.0",
70
70
  "date-fns": "~4.1.0",
@@ -83,10 +83,10 @@
83
83
  },
84
84
  "devDependencies": {
85
85
  "@spencejs/spence-config": "0.10.2",
86
- "@verii/endpoints-organizations-registrar": "1.1.0-pre.1765441856",
87
- "@verii/sample-data": "1.1.0-pre.1765441856",
86
+ "@verii/endpoints-organizations-registrar": "1.1.0-pre.1765745740",
87
+ "@verii/sample-data": "1.1.0-pre.1765745740",
88
88
  "@verii/test-regexes": "0.5.0-build",
89
- "@verii/tests-helpers": "1.1.0-pre.1765441856",
89
+ "@verii/tests-helpers": "1.1.0-pre.1765745740",
90
90
  "cheerio": "1.1.2",
91
91
  "dotenv": "16.6.1",
92
92
  "eslint": "8.57.1",
@@ -107,5 +107,5 @@
107
107
  "prettier": "2.8.8",
108
108
  "qs": "6.14.0"
109
109
  },
110
- "gitHead": "65907afa06a773fbe9c544abc54c6e7fb807a427"
110
+ "gitHead": "46b3c80a3277ce91fff1e698ac201602b6141d18"
111
111
  }
@@ -1,14 +1,14 @@
1
1
  /**
2
2
  * Copyright 2023 Velocity Team
3
3
  *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * Licensed under the Apache License, Version 2.0 (the 'License');
5
5
  * you may not use this file except in compliance with the License.
6
6
  * You may obtain a copy of the License at
7
7
  *
8
8
  * http://www.apache.org/licenses/LICENSE-2.0
9
9
  *
10
10
  * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * distributed under the License is distributed on an 'AS IS' BASIS,
12
12
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
@@ -84,16 +84,7 @@ const appRedirectController = async (fastify) => {
84
84
  inspectorDid: { type: 'array', items: { type: 'string' } },
85
85
  providers: {
86
86
  type: 'array',
87
- items: {
88
- type: 'object',
89
- properties: {
90
- name: { type: 'string' },
91
- logo: { type: 'string' },
92
- category: { type: 'string' },
93
- id: { type: 'string' },
94
- },
95
- required: ['name', 'id', 'logo', 'category'],
96
- },
87
+ items: { type: 'string' },
97
88
  },
98
89
  },
99
90
  required: ['request_uri', 'exchange_type'],
@@ -165,13 +156,15 @@ const processingLinks = (context) => {
165
156
  },
166
157
  } = context;
167
158
 
159
+ const parsedProviders = parseProviders(providersItems, exchangeType);
160
+
168
161
  const parsedLinks = flow(
169
162
  (items) => zip(items, range(0, items.length)),
170
163
  map(([value, index]) => ({
171
164
  requestUri: value,
172
165
  vendorOriginContext: vendorOriginContextItems[index],
173
166
  inspectorDid: inspectorDidItems[index],
174
- ...(providersItems ? { providers: providersItems } : {}),
167
+ ...(parsedProviders ? { providers: parsedProviders } : {}),
175
168
  }))
176
169
  )(requestUriItems);
177
170
 
@@ -187,7 +180,9 @@ const processingLinks = (context) => {
187
180
  appendSearchParam('request_uri', requestUri),
188
181
  appendSearchParam('inspectorDid', inspectorDid),
189
182
  appendSearchParam('vendorOriginContext', vendorOriginContext),
190
- providersItem ? appendSearchParam('providers', providersItem) : identity
183
+ providersItem
184
+ ? appendSearchParam('providers', JSON.stringify(providersItem))
185
+ : identity
191
186
  );
192
187
 
193
188
  appendParams(deeplink);
@@ -198,6 +193,60 @@ const processingLinks = (context) => {
198
193
  return { deeplink };
199
194
  };
200
195
 
196
+ const parseProviders = (providersItems, exchangeType) => {
197
+ if (exchangeType !== EXCHANGE_TYPE.claim) {
198
+ return null;
199
+ }
200
+
201
+ if (!providersItems) {
202
+ throw new Error.BadRequest(
203
+ 'providers parameter is required for exchange_type = "claim.wizard"'
204
+ );
205
+ }
206
+
207
+ const normalizedProviders = Array.isArray(providersItems)
208
+ ? providersItems
209
+ : [providersItems];
210
+
211
+ let parsedProviders;
212
+
213
+ try {
214
+ parsedProviders = normalizedProviders.map((provider) => {
215
+ if (typeof provider === 'string') {
216
+ return JSON.parse(provider);
217
+ }
218
+ return provider;
219
+ });
220
+ } catch (error) {
221
+ throw new Error.BadRequest('Invalid JSON format for providers parameter');
222
+ }
223
+
224
+ const PROVIDERS_REQUIRED_PROPS = ['name', 'id', 'logo', 'category'];
225
+
226
+ return parsedProviders.map((item, index) => {
227
+ if (!item || typeof item !== 'object') {
228
+ throw new Error.BadRequest(
229
+ `Provider at index ${index} must be an object`
230
+ );
231
+ }
232
+
233
+ for (const prop of PROVIDERS_REQUIRED_PROPS) {
234
+ if (!item[prop] || typeof item[prop] !== 'string') {
235
+ throw new Error.BadRequest(
236
+ `Provider at index ${index} missing required property: ${prop}`
237
+ );
238
+ }
239
+ }
240
+
241
+ return {
242
+ name: item.name,
243
+ logo: item.logo,
244
+ category: item.category,
245
+ id: item.id,
246
+ };
247
+ });
248
+ };
249
+
201
250
  // eslint-disable-next-line better-mutation/no-mutation
202
251
  appRedirectController.prefixOverride = '';
203
252
 
@@ -218,7 +218,7 @@ describe('app redirect controller test', () => {
218
218
  expect(scriptTag.attr('data-automode')).toEqual('');
219
219
  });
220
220
 
221
- it('should include vnf wallet selection mount point if claim.wizard', async () => {
221
+ it('should include vnf wallet selection mount point if claim.wizard with one provider', async () => {
222
222
  setupNock();
223
223
  const url =
224
224
  // eslint-disable-next-line max-len
@@ -226,7 +226,7 @@ describe('app redirect controller test', () => {
226
226
  const response = await fastify.injectJson({
227
227
  method: 'GET',
228
228
  // eslint-disable-next-line max-len
229
- url: `${appRedirectUrl}?request_uri=${url}&exchange_type=claim.wizard&inspectorDid=321123providers=%5B%7B%22logo%22%3A%22https%3A//upload.wikimedia.org/wikipedia/commons/a/aa/LinkedIn_2021.svg%22%2C%22name%22%3A%22LinkedIn%22%2C%22category%22%3A%22Personal%20Records%22%2C%22id%22%3A%22a9f1063c-06b7-476a-8410-9ff6e427e637%22%7D%2C%7B%22logo%22%3A%22https%3A//logos-world.net/wp-content/uploads/2020/11/GitHub-Emblem.png%22%2C%22name%22%3A%22GitHub%22%2C%22category%22%3A%22User%20Profile%22%2C%22id%22%3A%226d3f6753-7ee6-49ee-a545-62f1b1822ae5%22%7D%5D`,
229
+ url: `${appRedirectUrl}?request_uri=${url}&exchange_type=claim.wizard&inspectorDid=321123&providers=%7B%22logo%22%3A%22https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fa%2Faa%2FLinkedIn_2021.svg%22%2C%22name%22%3A%22LinkedIn%22%2C%22category%22%3A%22Personal%20Records%22%2C%22id%22%3A%22a9f1063c-06b7-476a-8410-9ff6e427e637%22%7D`,
230
230
  });
231
231
 
232
232
  expect(response.statusCode).toEqual(200);
@@ -235,8 +235,98 @@ describe('app redirect controller test', () => {
235
235
  const scriptTag = $('html > body > #vnf-wallet-selection');
236
236
  const deeplink =
237
237
  // eslint-disable-next-line max-len
238
- 'velocity-test://claim.wizard?request_uri=http%3A%2F%2Flocalhost.test%2Fapi%2Fholder%2Fv0.6%2Forg%2Fdid%3Aion%3A4131209321321323123e%2Fissue%2Fget-credential-manifest%3Fexchange_id%3D5f123eab4362bb2e%26credential_types%3DPastEmploymentPosition%26id%3DsecretId&inspectorDid=321123providers%3D%5B%7B%22logo%22%3A%22https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fa%2Faa%2FLinkedIn_2021.svg%22%2C%22name%22%3A%22LinkedIn%22%2C%22category%22%3A%22Personal+Records%22%2C%22id%22%3A%22a9f1063c-06b7-476a-8410-9ff6e427e637%22%7D%2C%7B%22logo%22%3A%22https%3A%2F%2Flogos-world.net%2Fwp-content%2Fuploads%2F2020%2F11%2FGitHub-Emblem.png%22%2C%22name%22%3A%22GitHub%22%2C%22category%22%3A%22User+Profile%22%2C%22id%22%3A%226d3f6753-7ee6-49ee-a545-62f1b1822ae5%22%7D%5D';
238
+ 'velocity-test://claim.wizard?request_uri=http%3A%2F%2Flocalhost.test%2Fapi%2Fholder%2Fv0.6%2Forg%2Fdid%3Aion%3A4131209321321323123e%2Fissue%2Fget-credential-manifest%3Fexchange_id%3D5f123eab4362bb2e%26credential_types%3DPastEmploymentPosition%26id%3DsecretId&inspectorDid=321123&providers=%5B%7B%22name%22%3A%22LinkedIn%22%2C%22logo%22%3A%22https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fa%2Faa%2FLinkedIn_2021.svg%22%2C%22category%22%3A%22Personal+Records%22%2C%22id%22%3A%22a9f1063c-06b7-476a-8410-9ff6e427e637%22%7D%5D';
239
239
  expect(scriptTag.attr('data-deeplink')).toEqual(deeplink);
240
240
  expect(scriptTag.attr('data-automode')).toEqual('');
241
241
  });
242
+
243
+ it('should throw if claim.wizard and provider is missing required properties: id', async () => {
244
+ setupNock();
245
+ const url =
246
+ // eslint-disable-next-line max-len
247
+ 'http%3A%2F%2Flocalhost.test%2Fapi%2Fholder%2Fv0.6%2Forg%2Fdid%3Aion%3A4131209321321323123e%2Fissue%2Fget-credential-manifest%3Fexchange_id%3D5f123eab4362bb2e%26credential_types%3DPastEmploymentPosition%26id%3DsecretId';
248
+ const response = await fastify.injectJson({
249
+ method: 'GET',
250
+ // eslint-disable-next-line max-len
251
+ url: `${appRedirectUrl}?request_uri=${url}&exchange_type=claim.wizard&inspectorDid=321123&providers=%7B%22logo%22%3A%22https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fa%2Faa%2FLinkedIn_2021.svg%22%2C%22name%22%3A%22LinkedIn%22%7D`,
252
+ });
253
+
254
+ expect(response.statusCode).toEqual(400);
255
+ expect(response.json.message).toEqual(
256
+ 'Provider at index 0 missing required property: id'
257
+ );
258
+ });
259
+
260
+ it('should throw if claim.wizard and provider is missing required properties: name', async () => {
261
+ setupNock();
262
+ const url =
263
+ // eslint-disable-next-line max-len
264
+ 'http%3A%2F%2Flocalhost.test%2Fapi%2Fholder%2Fv0.6%2Forg%2Fdid%3Aion%3A4131209321321323123e%2Fissue%2Fget-credential-manifest%3Fexchange_id%3D5f123eab4362bb2e%26credential_types%3DPastEmploymentPosition%26id%3DsecretId';
265
+ const response = await fastify.injectJson({
266
+ method: 'GET',
267
+ // eslint-disable-next-line max-len
268
+ url: `${appRedirectUrl}?request_uri=${url}&exchange_type=claim.wizard&inspectorDid=321123&providers=%7B%22logo%22%3A%22https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fa%2Faa%2FLinkedIn_2021.svg%22%2C%22id%22%3A%22LinkedIn%22%7D`,
269
+ });
270
+
271
+ expect(response.statusCode).toEqual(400);
272
+ expect(response.json.message).toEqual(
273
+ 'Provider at index 0 missing required property: name'
274
+ );
275
+ });
276
+
277
+ it('should throw if claim.wizard and provider is missing required properties: logo', async () => {
278
+ setupNock();
279
+ const url =
280
+ // eslint-disable-next-line max-len
281
+ 'http%3A%2F%2Flocalhost.test%2Fapi%2Fholder%2Fv0.6%2Forg%2Fdid%3Aion%3A4131209321321323123e%2Fissue%2Fget-credential-manifest%3Fexchange_id%3D5f123eab4362bb2e%26credential_types%3DPastEmploymentPosition%26id%3DsecretId';
282
+ const response = await fastify.injectJson({
283
+ method: 'GET',
284
+ // eslint-disable-next-line max-len
285
+ url: `${appRedirectUrl}?request_uri=${url}&exchange_type=claim.wizard&inspectorDid=321123&providers=%7B%22name%22%3A%22LinkedIn%22%2C%22category%22%3A%22Personal%20Records%22%2C%22id%22%3A%22a9f1063c-06b7-476a-8410-9ff6e427e637%22%7D`,
286
+ });
287
+
288
+ expect(response.statusCode).toEqual(400);
289
+ expect(response.json.message).toEqual(
290
+ 'Provider at index 0 missing required property: logo'
291
+ );
292
+ });
293
+
294
+ it('should include vnf wallet selection mount point if claim.wizard with multiple providers', async () => {
295
+ setupNock();
296
+ const url =
297
+ // eslint-disable-next-line max-len
298
+ 'http%3A%2F%2Flocalhost.test%2Fapi%2Fholder%2Fv0.6%2Forg%2Fdid%3Aion%3A4131209321321323123e%2Fissue%2Fget-credential-manifest%3Fexchange_id%3D5f123eab4362bb2e%26credential_types%3DPastEmploymentPosition%26id%3DsecretId';
299
+ const response = await fastify.injectJson({
300
+ method: 'GET',
301
+ // eslint-disable-next-line max-len
302
+ url: `${appRedirectUrl}?request_uri=${url}&exchange_type=claim.wizard&inspectorDid=321123&providers=%7B%22logo%22%3A%22https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fa%2Faa%2FLinkedIn_2021.svg%22%2C%22name%22%3A%22LinkedIn%22%2C%22category%22%3A%22Personal%20Records%22%2C%22id%22%3A%22a9f1063c-06b7-476a-8410-9ff6e427e637%22%7D&providers=%7B%22logo%22%3A%22https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fa%2Faa%2FLinkedIn_2021.svg%22%2C%22name%22%3A%22LinkedIn%22%2C%22category%22%3A%22Personal%20Records%22%2C%22id%22%3A%22a9f1063c-06b7-476a-8410-9ff6e427e637%22%7D`,
303
+ });
304
+
305
+ expect(response.statusCode).toEqual(200);
306
+ const $ = cheerio.load(response.body);
307
+
308
+ const scriptTag = $('html > body > #vnf-wallet-selection');
309
+ const deeplink =
310
+ // eslint-disable-next-line max-len
311
+ 'velocity-test://claim.wizard?request_uri=http%3A%2F%2Flocalhost.test%2Fapi%2Fholder%2Fv0.6%2Forg%2Fdid%3Aion%3A4131209321321323123e%2Fissue%2Fget-credential-manifest%3Fexchange_id%3D5f123eab4362bb2e%26credential_types%3DPastEmploymentPosition%26id%3DsecretId&inspectorDid=321123&providers=%5B%7B%22name%22%3A%22LinkedIn%22%2C%22logo%22%3A%22https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fa%2Faa%2FLinkedIn_2021.svg%22%2C%22category%22%3A%22Personal+Records%22%2C%22id%22%3A%22a9f1063c-06b7-476a-8410-9ff6e427e637%22%7D%2C%7B%22name%22%3A%22LinkedIn%22%2C%22logo%22%3A%22https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fa%2Faa%2FLinkedIn_2021.svg%22%2C%22category%22%3A%22Personal+Records%22%2C%22id%22%3A%22a9f1063c-06b7-476a-8410-9ff6e427e637%22%7D%5D';
312
+ expect(scriptTag.attr('data-deeplink')).toEqual(deeplink);
313
+ expect(scriptTag.attr('data-automode')).toEqual('');
314
+ });
315
+
316
+ it('should throw an error if claim.wizard and empty providers', async () => {
317
+ setupNock();
318
+ const url =
319
+ // eslint-disable-next-line max-len
320
+ 'http%3A%2F%2Flocalhost.test%2Fapi%2Fholder%2Fv0.6%2Forg%2Fdid%3Aion%3A4131209321321323123e%2Fissue%2Fget-credential-manifest%3Fexchange_id%3D5f123eab4362bb2e%26credential_types%3DPastEmploymentPosition%26id%3DsecretId';
321
+ const response = await fastify.injectJson({
322
+ method: 'GET',
323
+ // eslint-disable-next-line max-len
324
+ url: `${appRedirectUrl}?request_uri=${url}&exchange_type=claim.wizard&inspectorDid=321123`,
325
+ });
326
+
327
+ expect(response.statusCode).toEqual(400);
328
+ expect(response.json.message).toEqual(
329
+ 'providers parameter is required for exchange_type = "claim.wizard"'
330
+ );
331
+ });
242
332
  });