@cheqd/studio 3.16.0-develop.8 → 3.16.0
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/dist/app.d.ts.map +1 -1
- package/dist/app.js +11 -0
- package/dist/app.js.map +1 -1
- package/dist/controllers/api/accreditation.d.ts +2 -10
- package/dist/controllers/api/accreditation.d.ts.map +1 -1
- package/dist/controllers/api/accreditation.js +110 -369
- package/dist/controllers/api/accreditation.js.map +1 -1
- package/dist/controllers/api/credential.d.ts +1 -1
- package/dist/controllers/api/credential.d.ts.map +1 -1
- package/dist/controllers/api/credential.js +2 -1
- package/dist/controllers/api/credential.js.map +1 -1
- package/dist/controllers/api/received-credential.d.ts +375 -0
- package/dist/controllers/api/received-credential.d.ts.map +1 -0
- package/dist/controllers/api/received-credential.js +650 -0
- package/dist/controllers/api/received-credential.js.map +1 -0
- package/dist/database/entities/issued-credential.entity.d.ts +18 -2
- package/dist/database/entities/issued-credential.entity.d.ts.map +1 -1
- package/dist/database/entities/issued-credential.entity.js +29 -0
- package/dist/database/entities/issued-credential.entity.js.map +1 -1
- package/dist/database/migrations/1766408271347-studio-migrations.d.ts +7 -0
- package/dist/database/migrations/1766408271347-studio-migrations.d.ts.map +1 -0
- package/dist/database/migrations/1766408271347-studio-migrations.js +16 -0
- package/dist/database/migrations/1766408271347-studio-migrations.js.map +1 -0
- package/dist/database/types/types.d.ts.map +1 -1
- package/dist/database/types/types.js +2 -0
- package/dist/database/types/types.js.map +1 -1
- package/dist/middleware/auth/routes/api/credential-auth.d.ts.map +1 -1
- package/dist/middleware/auth/routes/api/credential-auth.js +12 -0
- package/dist/middleware/auth/routes/api/credential-auth.js.map +1 -1
- package/dist/services/api/accreditation.d.ts +17 -2
- package/dist/services/api/accreditation.d.ts.map +1 -1
- package/dist/services/api/accreditation.js +400 -7
- package/dist/services/api/accreditation.js.map +1 -1
- package/dist/services/api/credentials.d.ts.map +1 -1
- package/dist/services/api/credentials.js +38 -6
- package/dist/services/api/credentials.js.map +1 -1
- package/dist/services/api/received-credentials.d.ts +129 -0
- package/dist/services/api/received-credentials.d.ts.map +1 -0
- package/dist/services/api/received-credentials.js +498 -0
- package/dist/services/api/received-credentials.js.map +1 -0
- package/dist/services/identity/abstract.d.ts +4 -0
- package/dist/services/identity/abstract.d.ts.map +1 -1
- package/dist/services/identity/abstract.js +12 -0
- package/dist/services/identity/abstract.js.map +1 -1
- package/dist/services/identity/index.d.ts +22 -0
- package/dist/services/identity/index.d.ts.map +1 -1
- package/dist/services/identity/index.js.map +1 -1
- package/dist/services/identity/providers/studio/agent.d.ts +15 -0
- package/dist/services/identity/providers/studio/agent.d.ts.map +1 -1
- package/dist/services/identity/providers/studio/agent.js +51 -9
- package/dist/services/identity/providers/studio/agent.js.map +1 -1
- package/dist/services/identity/providers/studio/local.d.ts +4 -0
- package/dist/services/identity/providers/studio/local.d.ts.map +1 -1
- package/dist/services/identity/providers/studio/local.js +12 -0
- package/dist/services/identity/providers/studio/local.js.map +1 -1
- package/dist/services/identity/providers/studio/postgres.d.ts +7 -0
- package/dist/services/identity/providers/studio/postgres.d.ts.map +1 -1
- package/dist/services/identity/providers/studio/postgres.js +19 -0
- package/dist/services/identity/providers/studio/postgres.js.map +1 -1
- package/dist/services/track/admin/account-submitter.d.ts.map +1 -1
- package/dist/services/track/admin/account-submitter.js +1 -3
- package/dist/services/track/admin/account-submitter.js.map +1 -1
- package/dist/static/swagger-api.json +526 -1
- package/dist/types/accreditation.d.ts +1 -1
- package/dist/types/accreditation.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -5,40 +5,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { StatusCodes } from 'http-status-codes';
|
|
8
|
-
import {
|
|
9
|
-
import { AccreditationRequestType, DIDAccreditationPolicyTypes, DIDAccreditationTypes, } from '../../types/accreditation.js';
|
|
10
|
-
import { CredentialCategory, CredentialConnectors } from '../../types/credential.js';
|
|
8
|
+
import { AccreditationRequestType } from '../../types/accreditation.js';
|
|
11
9
|
import { OperationCategoryNameEnum, OperationNameEnum } from '../../types/constants.js';
|
|
12
|
-
import { IdentityServiceStrategySetup } from '../../services/identity/index.js';
|
|
13
10
|
import { AccreditationService } from '../../services/api/accreditation.js';
|
|
14
|
-
import { Credentials } from '../../services/api/credentials.js';
|
|
15
11
|
import { eventTracker } from '../../services/track/tracker.js';
|
|
16
12
|
import { body, query } from '../validator/index.js';
|
|
17
13
|
import { validate } from '../validator/decorator.js';
|
|
18
14
|
import { constructDidUrl, parseDidFromDidUrl } from '../../helpers/helpers.js';
|
|
19
|
-
import NodeCache from 'node-cache';
|
|
20
|
-
import { StatusListType } from '../../types/credential-status.js';
|
|
21
15
|
import { CheqdNetwork } from '@cheqd/sdk';
|
|
22
|
-
const ACCREDITATION_RESOLVE_CACHE_TTL_MS = 30_000;
|
|
23
|
-
const ACCREDITATION_RESOLVE_CACHE_MAX_ENTRIES = 200;
|
|
24
|
-
const ACCREDITATION_RESOLVE_CONCURRENCY = 8;
|
|
25
|
-
function buildCacheKey(url, customerId) {
|
|
26
|
-
return `${customerId ?? 'anonymous'}::${url}`;
|
|
27
|
-
}
|
|
28
|
-
const accreditationResolveCache = new NodeCache({
|
|
29
|
-
stdTTL: ACCREDITATION_RESOLVE_CACHE_TTL_MS / 1000,
|
|
30
|
-
checkperiod: 0,
|
|
31
|
-
useClones: false,
|
|
32
|
-
deleteOnExpire: true,
|
|
33
|
-
maxKeys: ACCREDITATION_RESOLVE_CACHE_MAX_ENTRIES,
|
|
34
|
-
});
|
|
35
|
-
const inFlightAccreditations = new Map();
|
|
36
|
-
function getCachedAccreditation(key) {
|
|
37
|
-
return accreditationResolveCache.get(key) ?? null;
|
|
38
|
-
}
|
|
39
|
-
function setCachedAccreditation(key, value) {
|
|
40
|
-
accreditationResolveCache.set(key, value);
|
|
41
|
-
}
|
|
42
16
|
export class AccreditationController {
|
|
43
17
|
static issueValidator = [
|
|
44
18
|
query('accreditationType')
|
|
@@ -188,10 +162,8 @@ export class AccreditationController {
|
|
|
188
162
|
* $ref: '#/components/schemas/InternalError'
|
|
189
163
|
*/
|
|
190
164
|
async issue(request, response) {
|
|
191
|
-
// Get strategy e.g. postgres or local
|
|
192
|
-
const identityServiceStrategySetup = new IdentityServiceStrategySetup();
|
|
193
|
-
// Extract did from params
|
|
194
165
|
const { accreditationType } = request.query;
|
|
166
|
+
const { schemas, issuerDid, subjectDid } = request.body;
|
|
195
167
|
// Handles string input instead of an array
|
|
196
168
|
if (typeof request.body.type === 'string') {
|
|
197
169
|
request.body.type = [request.body.type];
|
|
@@ -199,117 +171,27 @@ export class AccreditationController {
|
|
|
199
171
|
if (typeof request.body['@context'] === 'string') {
|
|
200
172
|
request.body['@context'] = [request.body['@context']];
|
|
201
173
|
}
|
|
202
|
-
const { issuerDid, subjectDid, schemas, type, parentAccreditation, rootAuthorization, trustFramework, trustFrameworkId, attributes, accreditationName, format, credentialStatus, } = request.body;
|
|
203
174
|
try {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return response.status(StatusCodes.
|
|
218
|
-
error: `${issuerDid} is deactivated`,
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
// Validate subject DID
|
|
222
|
-
if (!subjectDidRes?.didDocument) {
|
|
223
|
-
return response.status(StatusCodes.BAD_REQUEST).send({
|
|
224
|
-
error: `DID ${subjectDid} is not resolved because of error from resolver: ${body.didResolutionMetadata.error}.`,
|
|
225
|
-
});
|
|
175
|
+
const result = await AccreditationService.instance.issue_accreditation(accreditationType, issuerDid, subjectDid, schemas, request.body, response.locals.customer);
|
|
176
|
+
if (result.success) {
|
|
177
|
+
// Track operation
|
|
178
|
+
const trackInfo = {
|
|
179
|
+
category: OperationCategoryNameEnum.CREDENTIAL,
|
|
180
|
+
name: OperationNameEnum.CREDENTIAL_ISSUE,
|
|
181
|
+
customer: response.locals.customer,
|
|
182
|
+
user: response.locals.user,
|
|
183
|
+
data: {
|
|
184
|
+
did: issuerDid,
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
eventTracker.emit('track', trackInfo);
|
|
188
|
+
return response.status(StatusCodes.OK).json(result.data);
|
|
226
189
|
}
|
|
227
|
-
|
|
228
|
-
return response.status(
|
|
229
|
-
error:
|
|
190
|
+
else {
|
|
191
|
+
return response.status(result.status).json({
|
|
192
|
+
error: result.error,
|
|
230
193
|
});
|
|
231
194
|
}
|
|
232
|
-
const resourceId = v4();
|
|
233
|
-
const accreditedFor = schemas.map(({ url, types }) => ({
|
|
234
|
-
schemaId: url,
|
|
235
|
-
types: Array.isArray(types) ? types : [types],
|
|
236
|
-
}));
|
|
237
|
-
// construct credential request
|
|
238
|
-
const credentialRequest = {
|
|
239
|
-
subjectDid,
|
|
240
|
-
attributes: {
|
|
241
|
-
...attributes,
|
|
242
|
-
accreditedFor,
|
|
243
|
-
id: subjectDid,
|
|
244
|
-
},
|
|
245
|
-
issuerDid,
|
|
246
|
-
format: format || 'jwt',
|
|
247
|
-
connector: CredentialConnectors.Resource, // resource connector
|
|
248
|
-
credentialId: resourceId,
|
|
249
|
-
credentialName: accreditationName,
|
|
250
|
-
credentialStatus,
|
|
251
|
-
category: CredentialCategory.ACCREDITATION,
|
|
252
|
-
};
|
|
253
|
-
let resourceType;
|
|
254
|
-
switch (accreditationType) {
|
|
255
|
-
case AccreditationRequestType.authorize:
|
|
256
|
-
resourceType = DIDAccreditationTypes.VerifiableAuthorizationForTrustChain;
|
|
257
|
-
credentialRequest.type = [...(type || []), resourceType];
|
|
258
|
-
credentialRequest.termsOfUse = {
|
|
259
|
-
type: DIDAccreditationPolicyTypes.Authorize,
|
|
260
|
-
trustFramework,
|
|
261
|
-
trustFrameworkId,
|
|
262
|
-
};
|
|
263
|
-
break;
|
|
264
|
-
case AccreditationRequestType.accredit:
|
|
265
|
-
resourceType = DIDAccreditationTypes.VerifiableAccreditationToAccredit;
|
|
266
|
-
credentialRequest.type = [...(type || []), resourceType];
|
|
267
|
-
credentialRequest.termsOfUse = {
|
|
268
|
-
type: DIDAccreditationPolicyTypes.Accredit,
|
|
269
|
-
parentAccreditation,
|
|
270
|
-
rootAuthorization,
|
|
271
|
-
};
|
|
272
|
-
break;
|
|
273
|
-
case AccreditationRequestType.attest:
|
|
274
|
-
resourceType = DIDAccreditationTypes.VerifiableAccreditationToAttest;
|
|
275
|
-
credentialRequest.type = [...(type || []), resourceType];
|
|
276
|
-
credentialRequest.termsOfUse = {
|
|
277
|
-
type: DIDAccreditationPolicyTypes.Accredit,
|
|
278
|
-
parentAccreditation,
|
|
279
|
-
rootAuthorization,
|
|
280
|
-
};
|
|
281
|
-
break;
|
|
282
|
-
}
|
|
283
|
-
// validate parent and root accreditations
|
|
284
|
-
if (accreditationType === AccreditationRequestType.accredit ||
|
|
285
|
-
accreditationType === AccreditationRequestType.attest) {
|
|
286
|
-
const result = await AccreditationService.instance.verify_accreditation(issuerDid, parentAccreditation, accreditedFor, true, false, response.locals.customer, rootAuthorization);
|
|
287
|
-
if (result.success === false) {
|
|
288
|
-
return response.status(result.status).send({
|
|
289
|
-
error: `Invalid Request: Root Authorization or parent Accreditation is not valid: ${result.error}`,
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
// issue accreditation
|
|
294
|
-
const accreditation = await Credentials.instance.issue_credential(credentialRequest, response.locals.customer);
|
|
295
|
-
// Track operation
|
|
296
|
-
const trackInfo = {
|
|
297
|
-
category: OperationCategoryNameEnum.CREDENTIAL,
|
|
298
|
-
name: OperationNameEnum.CREDENTIAL_ISSUE,
|
|
299
|
-
customer: response.locals.customer,
|
|
300
|
-
user: response.locals.user,
|
|
301
|
-
data: {
|
|
302
|
-
did: issuerDid,
|
|
303
|
-
},
|
|
304
|
-
};
|
|
305
|
-
eventTracker.emit('track', trackInfo);
|
|
306
|
-
return response.status(StatusCodes.OK).json({
|
|
307
|
-
didUrls: [
|
|
308
|
-
`${issuerDid}/resources/${resourceId}`,
|
|
309
|
-
`${issuerDid}?resourceName=${encodeURIComponent(accreditationName)}&resourceType=${credentialRequest.type}`,
|
|
310
|
-
],
|
|
311
|
-
accreditation,
|
|
312
|
-
});
|
|
313
195
|
}
|
|
314
196
|
catch (error) {
|
|
315
197
|
return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|
|
@@ -362,7 +244,6 @@ export class AccreditationController {
|
|
|
362
244
|
* $ref: '#/components/schemas/InternalError'
|
|
363
245
|
*/
|
|
364
246
|
async verify(request, response) {
|
|
365
|
-
// Extract did from params
|
|
366
247
|
let { verifyStatus = false, allowDeactivatedDid = false } = request.query;
|
|
367
248
|
const { policies, subjectDid, schemas } = request.body;
|
|
368
249
|
// construct didUrl
|
|
@@ -442,12 +323,8 @@ export class AccreditationController {
|
|
|
442
323
|
* $ref: '#/components/schemas/InternalError'
|
|
443
324
|
*/
|
|
444
325
|
async revoke(request, response) {
|
|
445
|
-
// Get publish flag
|
|
446
326
|
const { publish } = request.query;
|
|
447
|
-
// Get symmetric key
|
|
448
327
|
const { symmetricKey, ...didUrlParams } = request.body;
|
|
449
|
-
// Get strategy e.g. postgres or local
|
|
450
|
-
const identityServiceStrategySetup = new IdentityServiceStrategySetup(response.locals.customer.customerId);
|
|
451
328
|
const didUrl = constructDidUrl(didUrlParams);
|
|
452
329
|
if (!didUrl) {
|
|
453
330
|
return response.status(StatusCodes.BAD_REQUEST).json({
|
|
@@ -455,41 +332,36 @@ export class AccreditationController {
|
|
|
455
332
|
});
|
|
456
333
|
}
|
|
457
334
|
try {
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
335
|
+
const result = await AccreditationService.instance.revoke_accreditation(didUrl, publish, symmetricKey, response.locals.customer);
|
|
336
|
+
if (result.success) {
|
|
337
|
+
// Track operation if revocation was successful and publish is true
|
|
338
|
+
// Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
|
|
339
|
+
// and it will be tracked there
|
|
340
|
+
if (result.data.resourceMetadata && publish) {
|
|
341
|
+
// get issuer did
|
|
342
|
+
const issuerDid = parseDidFromDidUrl(didUrl);
|
|
343
|
+
const trackInfo = {
|
|
344
|
+
category: OperationCategoryNameEnum.CREDENTIAL,
|
|
345
|
+
name: OperationNameEnum.CREDENTIAL_REVOKE,
|
|
346
|
+
customer: response.locals.customer,
|
|
347
|
+
user: response.locals.user,
|
|
348
|
+
data: {
|
|
349
|
+
did: issuerDid,
|
|
350
|
+
encrypted: result.data.statusList?.metadata?.encrypted,
|
|
351
|
+
resource: result.data.resourceMetadata,
|
|
352
|
+
symmetricKey: '',
|
|
353
|
+
},
|
|
354
|
+
};
|
|
355
|
+
// Track operation
|
|
356
|
+
eventTracker.emit('track', trackInfo);
|
|
357
|
+
}
|
|
358
|
+
return response.status(StatusCodes.OK).json(result.data);
|
|
464
359
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
// Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
|
|
470
|
-
// and it will be tracked there
|
|
471
|
-
if (!result.error && result.resourceMetadata && publish) {
|
|
472
|
-
// get issuer did
|
|
473
|
-
const issuerDid = typeof accreditation.issuer === 'string'
|
|
474
|
-
? accreditation.issuer
|
|
475
|
-
: accreditation.issuer.id;
|
|
476
|
-
const trackInfo = {
|
|
477
|
-
category: OperationCategoryNameEnum.CREDENTIAL,
|
|
478
|
-
name: OperationNameEnum.CREDENTIAL_REVOKE,
|
|
479
|
-
customer: response.locals.customer,
|
|
480
|
-
user: response.locals.user,
|
|
481
|
-
data: {
|
|
482
|
-
did: issuerDid,
|
|
483
|
-
encrypted: result.statusList?.metadata?.encrypted,
|
|
484
|
-
resource: result.resourceMetadata,
|
|
485
|
-
symmetricKey: '',
|
|
486
|
-
},
|
|
487
|
-
};
|
|
488
|
-
// Track operation
|
|
489
|
-
eventTracker.emit('track', trackInfo);
|
|
360
|
+
else {
|
|
361
|
+
return response.status(result.status).json({
|
|
362
|
+
error: result.error,
|
|
363
|
+
});
|
|
490
364
|
}
|
|
491
|
-
// Return Ok response
|
|
492
|
-
return response.status(StatusCodes.OK).json(result);
|
|
493
365
|
}
|
|
494
366
|
catch (error) {
|
|
495
367
|
return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|
|
@@ -537,12 +409,8 @@ export class AccreditationController {
|
|
|
537
409
|
* $ref: '#/components/schemas/InternalError'
|
|
538
410
|
*/
|
|
539
411
|
async suspend(request, response) {
|
|
540
|
-
// Get publish flag
|
|
541
412
|
const { publish } = request.query;
|
|
542
|
-
// Get symmetric key
|
|
543
413
|
const { symmetricKey, ...didUrlParams } = request.body;
|
|
544
|
-
// Get strategy e.g. postgres or local
|
|
545
|
-
const identityServiceStrategySetup = new IdentityServiceStrategySetup(response.locals.customer.customerId);
|
|
546
414
|
const didUrl = constructDidUrl(didUrlParams);
|
|
547
415
|
if (!didUrl) {
|
|
548
416
|
return response.status(StatusCodes.BAD_REQUEST).json({
|
|
@@ -550,43 +418,36 @@ export class AccreditationController {
|
|
|
550
418
|
});
|
|
551
419
|
}
|
|
552
420
|
try {
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
421
|
+
const result = await AccreditationService.instance.suspend_accreditation(didUrl, publish, symmetricKey, response.locals.customer);
|
|
422
|
+
if (result.success) {
|
|
423
|
+
// Track operation if suspension was successful and publish is true
|
|
424
|
+
// Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
|
|
425
|
+
// and it will be tracked there
|
|
426
|
+
if (result.data.resourceMetadata && publish) {
|
|
427
|
+
// get issuer did
|
|
428
|
+
const issuerDid = parseDidFromDidUrl(didUrl);
|
|
429
|
+
const trackInfo = {
|
|
430
|
+
category: OperationCategoryNameEnum.CREDENTIAL,
|
|
431
|
+
name: OperationNameEnum.CREDENTIAL_SUSPEND,
|
|
432
|
+
customer: response.locals.customer,
|
|
433
|
+
user: response.locals.user,
|
|
434
|
+
data: {
|
|
435
|
+
did: issuerDid,
|
|
436
|
+
encrypted: result.data.statusList?.metadata?.encrypted,
|
|
437
|
+
resource: result.data.resourceMetadata,
|
|
438
|
+
symmetricKey: '',
|
|
439
|
+
},
|
|
440
|
+
};
|
|
441
|
+
// Track operation
|
|
442
|
+
eventTracker.emit('track', trackInfo);
|
|
443
|
+
}
|
|
444
|
+
return response.status(StatusCodes.OK).json(result.data);
|
|
561
445
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
// Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
|
|
567
|
-
// and it will be tracked there
|
|
568
|
-
if (!result.error && result.resourceMetadata && publish) {
|
|
569
|
-
// get issuer did
|
|
570
|
-
const issuerDid = typeof accreditation.issuer === 'string'
|
|
571
|
-
? accreditation.issuer
|
|
572
|
-
: accreditation.issuer.id;
|
|
573
|
-
const trackInfo = {
|
|
574
|
-
category: OperationCategoryNameEnum.CREDENTIAL,
|
|
575
|
-
name: OperationNameEnum.CREDENTIAL_SUSPEND,
|
|
576
|
-
customer: response.locals.customer,
|
|
577
|
-
user: response.locals.user,
|
|
578
|
-
data: {
|
|
579
|
-
did: issuerDid,
|
|
580
|
-
encrypted: result.statusList?.metadata?.encrypted,
|
|
581
|
-
resource: result.resourceMetadata,
|
|
582
|
-
symmetricKey: '',
|
|
583
|
-
},
|
|
584
|
-
};
|
|
585
|
-
// Track operation
|
|
586
|
-
eventTracker.emit('track', trackInfo);
|
|
446
|
+
else {
|
|
447
|
+
return response.status(result.status).json({
|
|
448
|
+
error: result.error,
|
|
449
|
+
});
|
|
587
450
|
}
|
|
588
|
-
// Return Ok response
|
|
589
|
-
return response.status(StatusCodes.OK).json(result);
|
|
590
451
|
}
|
|
591
452
|
catch (error) {
|
|
592
453
|
return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|
|
@@ -634,12 +495,8 @@ export class AccreditationController {
|
|
|
634
495
|
* $ref: '#/components/schemas/InternalError'
|
|
635
496
|
*/
|
|
636
497
|
async reinstate(request, response) {
|
|
637
|
-
// Get publish flag
|
|
638
498
|
const { publish } = request.query;
|
|
639
|
-
// Get symmetric key
|
|
640
499
|
const { symmetricKey, ...didUrlParams } = request.body;
|
|
641
|
-
// Get strategy e.g. postgres or local
|
|
642
|
-
const identityServiceStrategySetup = new IdentityServiceStrategySetup(response.locals.customer.customerId);
|
|
643
500
|
const didUrl = constructDidUrl(didUrlParams);
|
|
644
501
|
if (!didUrl) {
|
|
645
502
|
return response.status(StatusCodes.BAD_REQUEST).json({
|
|
@@ -647,43 +504,36 @@ export class AccreditationController {
|
|
|
647
504
|
});
|
|
648
505
|
}
|
|
649
506
|
try {
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
507
|
+
const result = await AccreditationService.instance.reinstate_accreditation(didUrl, publish, symmetricKey, response.locals.customer);
|
|
508
|
+
if (result.success) {
|
|
509
|
+
// Track operation if reinstatement was successful and publish is true
|
|
510
|
+
// Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
|
|
511
|
+
// and it will be tracked there
|
|
512
|
+
if (result.data.resourceMetadata && publish) {
|
|
513
|
+
// get issuer did
|
|
514
|
+
const issuerDid = parseDidFromDidUrl(didUrl);
|
|
515
|
+
const trackInfo = {
|
|
516
|
+
category: OperationCategoryNameEnum.CREDENTIAL,
|
|
517
|
+
name: OperationNameEnum.CREDENTIAL_UNSUSPEND,
|
|
518
|
+
customer: response.locals.customer,
|
|
519
|
+
user: response.locals.user,
|
|
520
|
+
data: {
|
|
521
|
+
did: issuerDid,
|
|
522
|
+
encrypted: result.data.statusList?.metadata?.encrypted || false,
|
|
523
|
+
resource: result.data.resourceMetadata,
|
|
524
|
+
symmetricKey: '',
|
|
525
|
+
},
|
|
526
|
+
};
|
|
527
|
+
// Track operation
|
|
528
|
+
eventTracker.emit('track', trackInfo);
|
|
529
|
+
}
|
|
530
|
+
return response.status(StatusCodes.OK).json(result.data);
|
|
658
531
|
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
// Otherwise the StatusList2021 or BitstringStatusList publisher should manually publish the resource
|
|
664
|
-
// and it will be tracked there
|
|
665
|
-
if (!result.error && result.resourceMetadata && publish) {
|
|
666
|
-
// get issuer did
|
|
667
|
-
const issuerDid = typeof accreditation.issuer === 'string'
|
|
668
|
-
? accreditation.issuer
|
|
669
|
-
: accreditation.issuer.id;
|
|
670
|
-
const trackInfo = {
|
|
671
|
-
category: OperationCategoryNameEnum.CREDENTIAL,
|
|
672
|
-
name: OperationNameEnum.CREDENTIAL_UNSUSPEND,
|
|
673
|
-
customer: response.locals.customer,
|
|
674
|
-
user: response.locals.user,
|
|
675
|
-
data: {
|
|
676
|
-
did: issuerDid,
|
|
677
|
-
encrypted: result.statusList?.metadata?.encrypted || false,
|
|
678
|
-
resource: result.resourceMetadata,
|
|
679
|
-
symmetricKey: '',
|
|
680
|
-
},
|
|
681
|
-
};
|
|
682
|
-
// Track operation
|
|
683
|
-
eventTracker.emit('track', trackInfo);
|
|
532
|
+
else {
|
|
533
|
+
return response.status(result.status).json({
|
|
534
|
+
error: result.error,
|
|
535
|
+
});
|
|
684
536
|
}
|
|
685
|
-
// Return Ok response
|
|
686
|
-
return response.status(StatusCodes.OK).json(result);
|
|
687
537
|
}
|
|
688
538
|
catch (error) {
|
|
689
539
|
return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|
|
@@ -754,125 +604,16 @@ export class AccreditationController {
|
|
|
754
604
|
*/
|
|
755
605
|
async listAccreditations(request, response) {
|
|
756
606
|
const { network, accreditationType, did, page, limit } = request.query;
|
|
757
|
-
// Get strategy e.g. postgres or local
|
|
758
|
-
const identityServiceStrategySetup = response.locals.customer
|
|
759
|
-
? new IdentityServiceStrategySetup(response.locals.customer.customerId)
|
|
760
|
-
: new IdentityServiceStrategySetup();
|
|
761
|
-
let resourceType;
|
|
762
|
-
switch (accreditationType) {
|
|
763
|
-
case AccreditationRequestType.authorize:
|
|
764
|
-
resourceType = DIDAccreditationTypes.VerifiableAuthorizationForTrustChain;
|
|
765
|
-
break;
|
|
766
|
-
case AccreditationRequestType.accredit:
|
|
767
|
-
resourceType = DIDAccreditationTypes.VerifiableAccreditationToAccredit;
|
|
768
|
-
break;
|
|
769
|
-
case AccreditationRequestType.attest:
|
|
770
|
-
resourceType = DIDAccreditationTypes.VerifiableAccreditationToAttest;
|
|
771
|
-
break;
|
|
772
|
-
default:
|
|
773
|
-
return response.status(StatusCodes.BAD_REQUEST).json({
|
|
774
|
-
error: `Invalid accreditationType: ${accreditationType}. Must be one of: authorize, accredit, attest.`,
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
607
|
try {
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
const resourceUrls = resources.map((item) => `${item.did}/resources/${item.resourceId}`);
|
|
782
|
-
// No resources to resolve, return early
|
|
783
|
-
if (resourceUrls.length === 0) {
|
|
784
|
-
return response.status(StatusCodes.OK).json({
|
|
785
|
-
total: 0,
|
|
786
|
-
accreditations: [],
|
|
787
|
-
});
|
|
608
|
+
const result = await AccreditationService.instance.list_accreditations(response.locals.customer, accreditationType, network, did, page, limit);
|
|
609
|
+
if (result.success) {
|
|
610
|
+
return response.status(StatusCodes.OK).json(result.data);
|
|
788
611
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
credentialType: resourceType,
|
|
794
|
-
});
|
|
795
|
-
// 2. OPTIMIZATION: Create a Map for O(1) tracking record lookup by providerCredentialId
|
|
796
|
-
const trackingMap = new Map();
|
|
797
|
-
for (const record of trackingRecords) {
|
|
798
|
-
trackingMap.set(record.providerCredentialId, record);
|
|
612
|
+
else {
|
|
613
|
+
return response.status(result.status).json({
|
|
614
|
+
error: result.error,
|
|
615
|
+
});
|
|
799
616
|
}
|
|
800
|
-
const resolveAccreditationWithCache = async (url) => {
|
|
801
|
-
const cacheKey = buildCacheKey(url, response.locals.customer?.customerId);
|
|
802
|
-
const cached = getCachedAccreditation(cacheKey);
|
|
803
|
-
if (cached) {
|
|
804
|
-
return cached;
|
|
805
|
-
}
|
|
806
|
-
const inFlight = inFlightAccreditations.get(cacheKey);
|
|
807
|
-
if (inFlight) {
|
|
808
|
-
return inFlight;
|
|
809
|
-
}
|
|
810
|
-
const resolverPromise = (async () => {
|
|
811
|
-
try {
|
|
812
|
-
const res = await identityServiceStrategySetup.agent.resolve(url, true);
|
|
813
|
-
const credential = await res.json();
|
|
814
|
-
// Skip if the credential doesn't have contentStream
|
|
815
|
-
if (!credential.contentStream) {
|
|
816
|
-
return null;
|
|
817
|
-
}
|
|
818
|
-
const resourceId = credential.contentMetadata.resourceId;
|
|
819
|
-
const trackingRecord = trackingMap.get(resourceId);
|
|
820
|
-
if (trackingRecord) {
|
|
821
|
-
const { issuedCredentialId, providerId, providerCredentialId, status, statusUpdatedAt } = trackingRecord;
|
|
822
|
-
// Merge tracking metadata with credential
|
|
823
|
-
const accreditation = {
|
|
824
|
-
...credential.contentStream,
|
|
825
|
-
metadata: {
|
|
826
|
-
issuedCredentialId,
|
|
827
|
-
providerId,
|
|
828
|
-
providerCredentialId,
|
|
829
|
-
status,
|
|
830
|
-
statusUpdatedAt,
|
|
831
|
-
},
|
|
832
|
-
};
|
|
833
|
-
setCachedAccreditation(cacheKey, accreditation);
|
|
834
|
-
return accreditation;
|
|
835
|
-
}
|
|
836
|
-
else {
|
|
837
|
-
// No tracking record, return just the credential (legacy)
|
|
838
|
-
setCachedAccreditation(cacheKey, credential.contentStream);
|
|
839
|
-
return credential.contentStream;
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
catch (error) {
|
|
843
|
-
console.error(`Failed to process accreditation for URL: ${url}`, error);
|
|
844
|
-
return null;
|
|
845
|
-
}
|
|
846
|
-
finally {
|
|
847
|
-
inFlightAccreditations.delete(cacheKey);
|
|
848
|
-
}
|
|
849
|
-
})();
|
|
850
|
-
inFlightAccreditations.set(cacheKey, resolverPromise);
|
|
851
|
-
return resolverPromise;
|
|
852
|
-
};
|
|
853
|
-
// 3. Resolve resources and enhance with tracking metadata with bounded concurrency
|
|
854
|
-
const resolvedAccreditations = new Array(resourceUrls.length);
|
|
855
|
-
let currentIndex = 0;
|
|
856
|
-
const workers = Array.from({ length: Math.min(ACCREDITATION_RESOLVE_CONCURRENCY, resourceUrls.length) }, async () => {
|
|
857
|
-
// eslint-disable-next-line no-constant-condition
|
|
858
|
-
while (true) {
|
|
859
|
-
const index = currentIndex++;
|
|
860
|
-
if (index >= resourceUrls.length) {
|
|
861
|
-
break;
|
|
862
|
-
}
|
|
863
|
-
const accreditation = await resolveAccreditationWithCache(resourceUrls[index]);
|
|
864
|
-
if (accreditation) {
|
|
865
|
-
resolvedAccreditations[index] = accreditation;
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
});
|
|
869
|
-
// 4. Wait for all resolutions to complete and filter out any failed/skipped ones (null)
|
|
870
|
-
await Promise.all(workers);
|
|
871
|
-
const accreditations = resolvedAccreditations.filter(Boolean);
|
|
872
|
-
return response.status(StatusCodes.OK).json({
|
|
873
|
-
total: accreditations.length,
|
|
874
|
-
accreditations: accreditations,
|
|
875
|
-
});
|
|
876
617
|
}
|
|
877
618
|
catch (error) {
|
|
878
619
|
return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|