@twin.org/identity-service 0.9.1 → 0.9.2-next.10

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.
@@ -1,9 +1,14 @@
1
1
  // Copyright 2024 IOTA Stiftung.
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
- import { ComponentFactory, GeneralError, Guards, Is, Urn } from "@twin.org/core";
4
- import { DocumentHelper, IdentityConnectorFactory, IdentityMetricIds, IdentityMetrics } from "@twin.org/identity-models";
3
+ import { HealthCategory, HealthStatus } from "@twin.org/api-models";
4
+ import { ContextIdKeys, ContextIdStore } from "@twin.org/context";
5
+ import { BaseError, ComponentFactory, GeneralError, Guards, Is, Urn } from "@twin.org/core";
6
+ import { AccountHelper } from "@twin.org/dlt-account";
7
+ import { DocumentHelper, IdentityConnectorFactory, IdentityMetricIds, IdentitySpanAttributes, IdentitySpanNames, IdentityMetrics, IdentityResolverConnectorFactory } from "@twin.org/identity-models";
5
8
  import { DidVerificationMethodType, ProofTypes } from "@twin.org/standards-w3c-did";
6
9
  import { MetricHelper } from "@twin.org/telemetry-models";
10
+ import { TracingHelper } from "@twin.org/tracing-models";
11
+ import { VaultConnectorFactory } from "@twin.org/vault-models";
7
12
  import { Jwt } from "@twin.org/web";
8
13
  /**
9
14
  * Class which implements the identity contract.
@@ -18,11 +23,21 @@ export class IdentityService {
18
23
  * @internal
19
24
  */
20
25
  _defaultNamespace;
26
+ /**
27
+ * The vault connector type used for mnemonic migration during health check init.
28
+ * @internal
29
+ */
30
+ _vaultConnector;
21
31
  /**
22
32
  * The telemetry component.
23
33
  * @internal
24
34
  */
25
35
  _telemetryComponent;
36
+ /**
37
+ * The optional tracing component for recording spans.
38
+ * @internal
39
+ */
40
+ _tracingComponent;
26
41
  /**
27
42
  * Create a new instance of IdentityService.
28
43
  * @param options The options for the service.
@@ -34,7 +49,9 @@ export class IdentityService {
34
49
  throw new GeneralError(IdentityService.CLASS_NAME, "noConnectors");
35
50
  }
36
51
  this._defaultNamespace = options?.config?.defaultNamespace ?? names[0];
52
+ this._vaultConnector = VaultConnectorFactory.get(options?.vaultConnectorType ?? "vault");
37
53
  this._telemetryComponent = ComponentFactory.getIfExists(options?.telemetryComponentType);
54
+ this._tracingComponent = ComponentFactory.getIfExists(options?.tracingComponentType);
38
55
  }
39
56
  /**
40
57
  * Returns the class name of the component.
@@ -53,6 +70,109 @@ export class IdentityService {
53
70
  }
54
71
  await MetricHelper.createMetrics(this._telemetryComponent, IdentityMetrics);
55
72
  }
73
+ /**
74
+ * Creates a temporary DID document for the application health check.
75
+ * @param contextIds The context IDs accumulated by prior init steps.
76
+ */
77
+ async healthApplicationInit(contextIds) {
78
+ // The wallet service has already setup a temporary controller DID mnemonic for the health check
79
+ // so we can use that to create a new document and add a verification method to it.
80
+ const controller = contextIds[ContextIdKeys.Organization];
81
+ if (!Is.stringValue(controller)) {
82
+ return;
83
+ }
84
+ try {
85
+ const connector = this.getConnectorByNamespace();
86
+ const doc = await connector.createDocument(controller);
87
+ await connector.addVerificationMethod(controller, doc.id, DidVerificationMethodType.AssertionMethod, "health-assertion");
88
+ // The original seed/mnemonic/keys were created with the temp orgId
89
+ // so we need to migrate them to the new document id so that the health check can resolve the DID.
90
+ await AccountHelper.renameAccountKeys(undefined, this._vaultConnector, controller, doc.id);
91
+ // Replace the updated contextIds with the new document id for the health check.
92
+ contextIds[ContextIdKeys.Organization] = doc.id;
93
+ }
94
+ catch { }
95
+ }
96
+ /**
97
+ * Returns the application health status of the identity service by resolving the DID created
98
+ * in healthApplicationInit.
99
+ * @param callback Callback for deferred results.
100
+ * @returns The health status of the service.
101
+ */
102
+ async healthApplication(callback) {
103
+ const contextIds = (await ContextIdStore.getContextIds()) ?? {};
104
+ const orgDid = contextIds[ContextIdKeys.Organization];
105
+ if (!Is.stringValue(orgDid)) {
106
+ return [
107
+ {
108
+ source: IdentityService.CLASS_NAME,
109
+ category: HealthCategory.Application,
110
+ status: HealthStatus.Error,
111
+ description: "healthDescription",
112
+ message: "createDocumentFailed",
113
+ data: {
114
+ did: orgDid
115
+ }
116
+ }
117
+ ];
118
+ }
119
+ try {
120
+ const resolverConnector = IdentityResolverConnectorFactory.getIfExists(this._defaultNamespace);
121
+ if (!Is.undefined(resolverConnector)) {
122
+ const resolved = await resolverConnector.resolveDocument(orgDid);
123
+ return [
124
+ {
125
+ source: IdentityService.CLASS_NAME,
126
+ category: HealthCategory.Application,
127
+ status: Is.object(resolved) ? HealthStatus.Ok : HealthStatus.Error,
128
+ description: "healthDescription",
129
+ message: Is.object(resolved) ? undefined : "resolveDocumentFailed",
130
+ data: { did: orgDid }
131
+ }
132
+ ];
133
+ }
134
+ return [
135
+ {
136
+ source: IdentityService.CLASS_NAME,
137
+ category: HealthCategory.Application,
138
+ status: HealthStatus.Ok,
139
+ description: "healthDescription",
140
+ data: { did: orgDid }
141
+ }
142
+ ];
143
+ }
144
+ catch (error) {
145
+ return [
146
+ {
147
+ source: IdentityService.CLASS_NAME,
148
+ category: HealthCategory.Application,
149
+ status: HealthStatus.Error,
150
+ description: "healthDescription",
151
+ message: "resolveDocumentFailed",
152
+ data: { did: orgDid },
153
+ error: BaseError.fromError(error)
154
+ }
155
+ ];
156
+ }
157
+ }
158
+ /**
159
+ * Removes the DID document created in healthApplicationInit.
160
+ */
161
+ async healthApplicationTeardown() {
162
+ const contextIds = await ContextIdStore.getContextIds();
163
+ const orgId = contextIds?.[ContextIdKeys.Organization];
164
+ if (!Is.stringValue(orgId)) {
165
+ return;
166
+ }
167
+ try {
168
+ const connector = this.getConnectorByNamespace();
169
+ await connector.removeVerificationMethod(orgId, `${orgId}#health-assertion`, {
170
+ removeKeys: true
171
+ });
172
+ await connector.removeDocument(orgId, orgId);
173
+ }
174
+ catch { }
175
+ }
56
176
  /**
57
177
  * Create a new identity.
58
178
  * @param namespace The namespace of the connector to use for the identity, defaults to service configured namespace.
@@ -61,36 +181,42 @@ export class IdentityService {
61
181
  */
62
182
  async identityCreate(namespace, controller) {
63
183
  Guards.stringValue(IdentityService.CLASS_NAME, "controller", controller);
64
- try {
65
- const identityConnector = this.getConnectorByNamespace(namespace);
66
- const result = await identityConnector.createDocument(controller);
67
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.DidsCreated, {
68
- namespace: namespace ?? this._defaultNamespace
69
- });
70
- return result;
71
- }
72
- catch (error) {
73
- throw new GeneralError(IdentityService.CLASS_NAME, "identityCreateFailed", undefined, error);
74
- }
184
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.Create, undefined, async () => {
185
+ try {
186
+ const identityConnector = this.getConnectorByNamespace(namespace);
187
+ const result = await identityConnector.createDocument(controller);
188
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.DidsCreated, {
189
+ namespace: namespace ?? this._defaultNamespace
190
+ });
191
+ return result;
192
+ }
193
+ catch (error) {
194
+ throw new GeneralError(IdentityService.CLASS_NAME, "identityCreateFailed", undefined, error);
195
+ }
196
+ });
75
197
  }
76
198
  /**
77
199
  * Remove an identity.
78
200
  * @param identity The id of the document to remove.
201
+ * @param options Optional settings.
202
+ * @param options.removeKeys Also remove any associated private keys from the vault.
79
203
  * @param controller The controller of the identity who can make changes.
80
204
  * @returns A promise that resolves when the identity has been removed.
81
205
  */
82
- async identityRemove(identity, controller) {
206
+ async identityRemove(identity, options, controller) {
83
207
  Guards.stringValue(IdentityService.CLASS_NAME, "identity", identity);
84
208
  Guards.stringValue(IdentityService.CLASS_NAME, "controller", controller);
85
- try {
86
- const identityConnector = this.getConnectorByUri(identity);
87
- const result = await identityConnector.removeDocument(controller, identity);
88
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.DidsRemoved);
89
- return result;
90
- }
91
- catch (error) {
92
- throw new GeneralError(IdentityService.CLASS_NAME, "identityRemoveFailed", { identity }, error);
93
- }
209
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.Remove, { attributes: { [IdentitySpanAttributes.Id]: identity } }, async () => {
210
+ try {
211
+ const identityConnector = this.getConnectorByUri(identity);
212
+ const result = await identityConnector.removeDocument(controller, identity, options);
213
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.DidsRemoved);
214
+ return result;
215
+ }
216
+ catch (error) {
217
+ throw new GeneralError(IdentityService.CLASS_NAME, "identityRemoveFailed", { identity }, error);
218
+ }
219
+ });
94
220
  }
95
221
  /**
96
222
  * Add a verification method to the document in JSON Web key Format.
@@ -106,34 +232,40 @@ export class IdentityService {
106
232
  Guards.stringValue(IdentityService.CLASS_NAME, "controller", controller);
107
233
  Urn.guard(IdentityService.CLASS_NAME, "identity", identity);
108
234
  Guards.arrayOneOf(IdentityService.CLASS_NAME, "verificationMethodType", verificationMethodType, Object.values(DidVerificationMethodType));
109
- try {
110
- const identityConnector = this.getConnectorByUri(identity);
111
- const verificationMethod = await identityConnector.addVerificationMethod(controller, identity, verificationMethodType, verificationMethodId);
112
- return verificationMethod;
113
- }
114
- catch (error) {
115
- throw new GeneralError(IdentityService.CLASS_NAME, "verificationMethodCreateFailed", { identity }, error);
116
- }
235
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.VerificationMethodCreate, { attributes: { [IdentitySpanAttributes.Id]: identity } }, async () => {
236
+ try {
237
+ const identityConnector = this.getConnectorByUri(identity);
238
+ const verificationMethod = await identityConnector.addVerificationMethod(controller, identity, verificationMethodType, verificationMethodId);
239
+ return verificationMethod;
240
+ }
241
+ catch (error) {
242
+ throw new GeneralError(IdentityService.CLASS_NAME, "verificationMethodCreateFailed", { identity }, error);
243
+ }
244
+ });
117
245
  }
118
246
  /**
119
247
  * Remove a verification method from the document.
120
248
  * @param verificationMethodId The id of the verification method.
249
+ * @param options Optional settings.
250
+ * @param options.removeKeys Also remove any associated private key from the vault.
121
251
  * @param controller The controller of the identity who can make changes.
122
252
  * @returns A promise that resolves when the verification method has been removed.
123
253
  * @throws NotFoundError if the id can not be resolved.
124
254
  * @throws NotSupportedError if the platform does not support multiple revocable keys.
125
255
  */
126
- async verificationMethodRemove(verificationMethodId, controller) {
256
+ async verificationMethodRemove(verificationMethodId, options, controller) {
127
257
  Guards.stringValue(IdentityService.CLASS_NAME, "controller", controller);
128
258
  Urn.guard(IdentityService.CLASS_NAME, "verificationMethodId", verificationMethodId);
129
- try {
130
- const idParts = DocumentHelper.parseId(verificationMethodId);
131
- const identityConnector = this.getConnectorByUri(idParts.id);
132
- await identityConnector.removeVerificationMethod(controller, verificationMethodId);
133
- }
134
- catch (error) {
135
- throw new GeneralError(IdentityService.CLASS_NAME, "verificationMethodRemoveFailed", { verificationMethodId }, error);
136
- }
259
+ await TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.VerificationMethodRemove, { attributes: { [IdentitySpanAttributes.VerificationMethodId]: verificationMethodId } }, async () => {
260
+ try {
261
+ const idParts = DocumentHelper.parseId(verificationMethodId);
262
+ const identityConnector = this.getConnectorByUri(idParts.id);
263
+ await identityConnector.removeVerificationMethod(controller, verificationMethodId, options);
264
+ }
265
+ catch (error) {
266
+ throw new GeneralError(IdentityService.CLASS_NAME, "verificationMethodRemoveFailed", { verificationMethodId }, error);
267
+ }
268
+ });
137
269
  }
138
270
  /**
139
271
  * Add a service to the document.
@@ -161,14 +293,16 @@ export class IdentityService {
161
293
  else {
162
294
  Guards.stringValue(IdentityService.CLASS_NAME, "serviceEndpoint", serviceEndpoint);
163
295
  }
164
- try {
165
- const identityConnector = this.getConnectorByUri(identity);
166
- const service = await identityConnector.addService(controller, identity, serviceId, serviceType, serviceEndpoint);
167
- return service;
168
- }
169
- catch (error) {
170
- throw new GeneralError(IdentityService.CLASS_NAME, "serviceCreateFailed", { identity, serviceId }, error);
171
- }
296
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.ServiceCreate, { attributes: { [IdentitySpanAttributes.Id]: identity } }, async () => {
297
+ try {
298
+ const identityConnector = this.getConnectorByUri(identity);
299
+ const service = await identityConnector.addService(controller, identity, serviceId, serviceType, serviceEndpoint);
300
+ return service;
301
+ }
302
+ catch (error) {
303
+ throw new GeneralError(IdentityService.CLASS_NAME, "serviceCreateFailed", { identity, serviceId }, error);
304
+ }
305
+ });
172
306
  }
173
307
  /**
174
308
  * Remove a service from the document.
@@ -180,14 +314,16 @@ export class IdentityService {
180
314
  async serviceRemove(serviceId, controller) {
181
315
  Guards.stringValue(IdentityService.CLASS_NAME, "controller", controller);
182
316
  Urn.guard(IdentityService.CLASS_NAME, "serviceId", serviceId);
183
- try {
184
- const idParts = DocumentHelper.parseId(serviceId);
185
- const identityConnector = this.getConnectorByUri(idParts.id);
186
- await identityConnector.removeService(controller, serviceId);
187
- }
188
- catch (error) {
189
- throw new GeneralError(IdentityService.CLASS_NAME, "serviceRemoveFailed", { serviceId }, error);
190
- }
317
+ await TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.ServiceRemove, { attributes: { [IdentitySpanAttributes.ServiceId]: serviceId } }, async () => {
318
+ try {
319
+ const idParts = DocumentHelper.parseId(serviceId);
320
+ const identityConnector = this.getConnectorByUri(idParts.id);
321
+ await identityConnector.removeService(controller, serviceId);
322
+ }
323
+ catch (error) {
324
+ throw new GeneralError(IdentityService.CLASS_NAME, "serviceRemoveFailed", { serviceId }, error);
325
+ }
326
+ });
191
327
  }
192
328
  /**
193
329
  * Add an alias to the alsoKnownAs property on the document.
@@ -203,14 +339,16 @@ export class IdentityService {
203
339
  Guards.stringValue(IdentityService.CLASS_NAME, "controller", controller);
204
340
  Guards.stringValue(IdentityService.CLASS_NAME, "documentId", documentId);
205
341
  Guards.stringValue(IdentityService.CLASS_NAME, "alias", alias);
206
- try {
207
- const idParts = DocumentHelper.parseId(documentId);
208
- const identityConnector = this.getConnectorByUri(idParts.id);
209
- await identityConnector.addAlsoKnownAs(controller, documentId, alias);
210
- }
211
- catch (error) {
212
- throw new GeneralError(IdentityService.CLASS_NAME, "alsoKnownAsAddFailed", { identity: documentId, alias }, error);
213
- }
342
+ await TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.AlsoKnownAsAdd, { attributes: { [IdentitySpanAttributes.Id]: documentId } }, async () => {
343
+ try {
344
+ const idParts = DocumentHelper.parseId(documentId);
345
+ const identityConnector = this.getConnectorByUri(idParts.id);
346
+ await identityConnector.addAlsoKnownAs(controller, documentId, alias);
347
+ }
348
+ catch (error) {
349
+ throw new GeneralError(IdentityService.CLASS_NAME, "alsoKnownAsAddFailed", { identity: documentId, alias }, error);
350
+ }
351
+ });
214
352
  }
215
353
  /**
216
354
  * Remove an alias from the alsoKnownAs property on the document.
@@ -226,14 +364,16 @@ export class IdentityService {
226
364
  Guards.stringValue(IdentityService.CLASS_NAME, "controller", controller);
227
365
  Guards.stringValue(IdentityService.CLASS_NAME, "documentId", documentId);
228
366
  Guards.stringValue(IdentityService.CLASS_NAME, "alias", alias);
229
- try {
230
- const idParts = DocumentHelper.parseId(documentId);
231
- const identityConnector = this.getConnectorByUri(idParts.id);
232
- await identityConnector.removeAlsoKnownAs(controller, documentId, alias);
233
- }
234
- catch (error) {
235
- throw new GeneralError(IdentityService.CLASS_NAME, "alsoKnownAsRemoveFailed", { identity: documentId, alias }, error);
236
- }
367
+ await TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.AlsoKnownAsRemove, { attributes: { [IdentitySpanAttributes.Id]: documentId } }, async () => {
368
+ try {
369
+ const idParts = DocumentHelper.parseId(documentId);
370
+ const identityConnector = this.getConnectorByUri(idParts.id);
371
+ await identityConnector.removeAlsoKnownAs(controller, documentId, alias);
372
+ }
373
+ catch (error) {
374
+ throw new GeneralError(IdentityService.CLASS_NAME, "alsoKnownAsRemoveFailed", { identity: documentId, alias }, error);
375
+ }
376
+ });
237
377
  }
238
378
  /**
239
379
  * Create a verifiable credential for a verification method.
@@ -253,19 +393,21 @@ export class IdentityService {
253
393
  Guards.stringValue(IdentityService.CLASS_NAME, "controller", controller);
254
394
  Urn.guard(IdentityService.CLASS_NAME, "verificationMethodId", verificationMethodId);
255
395
  Guards.object(IdentityService.CLASS_NAME, "subject", subject);
256
- try {
257
- const idParts = DocumentHelper.parseId(verificationMethodId);
258
- const identityConnector = this.getConnectorByUri(idParts.id);
259
- const service = await identityConnector.createVerifiableCredential(controller, verificationMethodId, id, subject, options);
260
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsCreated, {
261
- hasRevocation: Is.number(options?.revocationIndex),
262
- hasExpiration: Is.date(options?.expirationDate)
263
- });
264
- return service;
265
- }
266
- catch (error) {
267
- throw new GeneralError(IdentityService.CLASS_NAME, "verifiableCredentialCreateFailed", { verificationMethodId }, error);
268
- }
396
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.VerifiableCredentialCreate, { attributes: { [IdentitySpanAttributes.VerificationMethodId]: verificationMethodId } }, async () => {
397
+ try {
398
+ const idParts = DocumentHelper.parseId(verificationMethodId);
399
+ const identityConnector = this.getConnectorByUri(idParts.id);
400
+ const service = await identityConnector.createVerifiableCredential(controller, verificationMethodId, id, subject, options);
401
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsCreated, {
402
+ hasRevocation: Is.number(options?.revocationIndex),
403
+ hasExpiration: Is.date(options?.expirationDate)
404
+ });
405
+ return service;
406
+ }
407
+ catch (error) {
408
+ throw new GeneralError(IdentityService.CLASS_NAME, "verifiableCredentialCreateFailed", { verificationMethodId }, error);
409
+ }
410
+ });
269
411
  }
270
412
  /**
271
413
  * Verify a verifiable credential is valid.
@@ -277,20 +419,24 @@ export class IdentityService {
277
419
  Guards.objectValue(IdentityService.CLASS_NAME, "credential", credential);
278
420
  Guards.stringValue(IdentityService.CLASS_NAME, "credential.issuer", credential.issuer);
279
421
  Guards.objectValue(IdentityService.CLASS_NAME, "credential.proof", credential.proof);
280
- try {
281
- const identityConnector = this.getConnectorByUri(credential.issuer);
282
- const service = await identityConnector.checkVerifiableCredential(credential);
283
- if (service.revoked) {
284
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsVerificationFailed, { failureReason: "revoked" });
422
+ const issuer = credential.issuer;
423
+ const verifiableCredential = credential;
424
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.VerifiableCredentialVerify, undefined, async () => {
425
+ try {
426
+ const identityConnector = this.getConnectorByUri(issuer);
427
+ const service = await identityConnector.checkVerifiableCredential(verifiableCredential);
428
+ if (service.revoked) {
429
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsVerificationFailed, { failureReason: "revoked" });
430
+ }
431
+ else {
432
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsVerified);
433
+ }
434
+ return service;
285
435
  }
286
- else {
287
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsVerified);
436
+ catch (error) {
437
+ throw new GeneralError(IdentityService.CLASS_NAME, "verifiableCredentialVerifyFailed", undefined, error);
288
438
  }
289
- return service;
290
- }
291
- catch (error) {
292
- throw new GeneralError(IdentityService.CLASS_NAME, "verifiableCredentialVerifyFailed", undefined, error);
293
- }
439
+ });
294
440
  }
295
441
  Guards.stringValue(IdentityService.CLASS_NAME, "credential", credential);
296
442
  const jwtDecoded = await Jwt.decode(credential);
@@ -303,20 +449,23 @@ export class IdentityService {
303
449
  Is.undefined(jwtSignature)) {
304
450
  throw new GeneralError(IdentityService.CLASS_NAME, "jwtDecodeFailed");
305
451
  }
306
- try {
307
- const identityConnector = this.getConnectorByUri(jwtPayload.iss);
308
- const service = await identityConnector.checkVerifiableCredential(credential);
309
- if (service.revoked) {
310
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsVerificationFailed, { failureReason: "revoked" });
452
+ const issuer = jwtPayload.iss;
453
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.VerifiableCredentialVerify, undefined, async () => {
454
+ try {
455
+ const identityConnector = this.getConnectorByUri(issuer);
456
+ const service = await identityConnector.checkVerifiableCredential(credential);
457
+ if (service.revoked) {
458
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsVerificationFailed, { failureReason: "revoked" });
459
+ }
460
+ else {
461
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsVerified);
462
+ }
463
+ return service;
311
464
  }
312
- else {
313
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsVerified);
465
+ catch (error) {
466
+ throw new GeneralError(IdentityService.CLASS_NAME, "verifiableCredentialVerifyFailed", undefined, error);
314
467
  }
315
- return service;
316
- }
317
- catch (error) {
318
- throw new GeneralError(IdentityService.CLASS_NAME, "verifiableCredentialVerifyFailed", undefined, error);
319
- }
468
+ });
320
469
  }
321
470
  /**
322
471
  * Revoke verifiable credential.
@@ -329,16 +478,18 @@ export class IdentityService {
329
478
  Guards.stringValue(IdentityService.CLASS_NAME, "controller", controller);
330
479
  Guards.stringValue(IdentityService.CLASS_NAME, "issuerIdentity", issuerIdentity);
331
480
  Guards.number(IdentityService.CLASS_NAME, "credentialIndex", credentialIndex);
332
- try {
333
- const idParts = DocumentHelper.parseId(issuerIdentity);
334
- const identityConnector = this.getConnectorByUri(idParts.id);
335
- const result = await identityConnector.revokeVerifiableCredentials(controller, issuerIdentity, [credentialIndex]);
336
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsRevoked);
337
- return result;
338
- }
339
- catch (error) {
340
- throw new GeneralError(IdentityService.CLASS_NAME, "verifiableCredentialRevokeFailed", { issuerIdentity, credentialIndex }, error);
341
- }
481
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.VerifiableCredentialRevoke, { attributes: { [IdentitySpanAttributes.Id]: issuerIdentity } }, async () => {
482
+ try {
483
+ const idParts = DocumentHelper.parseId(issuerIdentity);
484
+ const identityConnector = this.getConnectorByUri(idParts.id);
485
+ const result = await identityConnector.revokeVerifiableCredentials(controller, issuerIdentity, [credentialIndex]);
486
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsRevoked);
487
+ return result;
488
+ }
489
+ catch (error) {
490
+ throw new GeneralError(IdentityService.CLASS_NAME, "verifiableCredentialRevokeFailed", { issuerIdentity, credentialIndex }, error);
491
+ }
492
+ });
342
493
  }
343
494
  /**
344
495
  * Unrevoke verifiable credential.
@@ -351,16 +502,18 @@ export class IdentityService {
351
502
  Guards.stringValue(IdentityService.CLASS_NAME, "controller", controller);
352
503
  Guards.stringValue(IdentityService.CLASS_NAME, "issuerIdentity", issuerIdentity);
353
504
  Guards.number(IdentityService.CLASS_NAME, "credentialIndex", credentialIndex);
354
- try {
355
- const idParts = DocumentHelper.parseId(issuerIdentity);
356
- const identityConnector = this.getConnectorByUri(idParts.id);
357
- const result = await identityConnector.unrevokeVerifiableCredentials(controller, issuerIdentity, [credentialIndex]);
358
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsUnrevoked);
359
- return result;
360
- }
361
- catch (error) {
362
- throw new GeneralError(IdentityService.CLASS_NAME, "verifiableCredentialUnrevokeFailed", { issuerIdentity, credentialIndex }, error);
363
- }
505
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.VerifiableCredentialUnrevoke, { attributes: { [IdentitySpanAttributes.Id]: issuerIdentity } }, async () => {
506
+ try {
507
+ const idParts = DocumentHelper.parseId(issuerIdentity);
508
+ const identityConnector = this.getConnectorByUri(idParts.id);
509
+ const result = await identityConnector.unrevokeVerifiableCredentials(controller, issuerIdentity, [credentialIndex]);
510
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VcsUnrevoked);
511
+ return result;
512
+ }
513
+ catch (error) {
514
+ throw new GeneralError(IdentityService.CLASS_NAME, "verifiableCredentialUnrevokeFailed", { issuerIdentity, credentialIndex }, error);
515
+ }
516
+ });
364
517
  }
365
518
  /**
366
519
  * Create a verifiable presentation from the supplied verifiable credentials.
@@ -380,18 +533,20 @@ export class IdentityService {
380
533
  async verifiablePresentationCreate(verificationMethodId, presentationId, contexts, types, verifiableCredentials, options, controller) {
381
534
  Guards.stringValue(IdentityService.CLASS_NAME, "controller", controller);
382
535
  Guards.stringValue(IdentityService.CLASS_NAME, "verificationMethodId", verificationMethodId);
383
- try {
384
- const idParts = DocumentHelper.parseId(verificationMethodId);
385
- const identityConnector = this.getConnectorByUri(idParts.id);
386
- const result = await identityConnector.createVerifiablePresentation(controller, verificationMethodId, presentationId, contexts, types, verifiableCredentials, options);
387
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VpsCreated, {
388
- credentialCount: verifiableCredentials.length
389
- });
390
- return result;
391
- }
392
- catch (error) {
393
- throw new GeneralError(IdentityService.CLASS_NAME, "verifiablePresentationCreateFailed", { verificationMethodId }, error);
394
- }
536
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.VerifiablePresentationCreate, { attributes: { [IdentitySpanAttributes.VerificationMethodId]: verificationMethodId } }, async () => {
537
+ try {
538
+ const idParts = DocumentHelper.parseId(verificationMethodId);
539
+ const identityConnector = this.getConnectorByUri(idParts.id);
540
+ const result = await identityConnector.createVerifiablePresentation(controller, verificationMethodId, presentationId, contexts, types, verifiableCredentials, options);
541
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VpsCreated, {
542
+ credentialCount: verifiableCredentials.length
543
+ });
544
+ return result;
545
+ }
546
+ catch (error) {
547
+ throw new GeneralError(IdentityService.CLASS_NAME, "verifiablePresentationCreateFailed", { verificationMethodId }, error);
548
+ }
549
+ });
395
550
  }
396
551
  /**
397
552
  * Verify a verifiable presentation is valid.
@@ -418,20 +573,22 @@ export class IdentityService {
418
573
  holder = presentation.holder;
419
574
  }
420
575
  Guards.stringValue(IdentityService.CLASS_NAME, "holder", holder);
421
- try {
422
- const identityConnector = this.getConnectorByUri(holder);
423
- const service = await identityConnector.checkVerifiablePresentation(presentation);
424
- if (service.revoked) {
425
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VpsVerificationFailed, { failureReason: "revoked" });
576
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.VerifiablePresentationVerify, undefined, async () => {
577
+ try {
578
+ const identityConnector = this.getConnectorByUri(holder);
579
+ const service = await identityConnector.checkVerifiablePresentation(presentation);
580
+ if (service.revoked) {
581
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VpsVerificationFailed, { failureReason: "revoked" });
582
+ }
583
+ else {
584
+ await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VpsVerified);
585
+ }
586
+ return service;
426
587
  }
427
- else {
428
- await MetricHelper.metricIncrement(this._telemetryComponent, IdentityMetricIds.VpsVerified);
588
+ catch (error) {
589
+ throw new GeneralError(IdentityService.CLASS_NAME, "verifiablePresentationVerifyFailed", undefined, error);
429
590
  }
430
- return service;
431
- }
432
- catch (error) {
433
- throw new GeneralError(IdentityService.CLASS_NAME, "verifiablePresentationVerifyFailed", undefined, error);
434
- }
591
+ });
435
592
  }
436
593
  /**
437
594
  * Create a proof for a document with the specified verification method.
@@ -446,15 +603,17 @@ export class IdentityService {
446
603
  Guards.stringValue(IdentityService.CLASS_NAME, "verificationMethodId", verificationMethodId);
447
604
  Guards.arrayOneOf(IdentityService.CLASS_NAME, "proofType", proofType, Object.values(ProofTypes));
448
605
  Guards.object(IdentityService.CLASS_NAME, "unsecureDocument", unsecureDocument);
449
- try {
450
- const idParts = DocumentHelper.parseId(verificationMethodId);
451
- const identityConnector = this.getConnectorByUri(idParts.id);
452
- const result = await identityConnector.createProof(controller, verificationMethodId, proofType, unsecureDocument);
453
- return result;
454
- }
455
- catch (error) {
456
- throw new GeneralError(IdentityService.CLASS_NAME, "proofCreateFailed", { verificationMethodId }, error);
457
- }
606
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.ProofCreate, { attributes: { [IdentitySpanAttributes.VerificationMethodId]: verificationMethodId } }, async () => {
607
+ try {
608
+ const idParts = DocumentHelper.parseId(verificationMethodId);
609
+ const identityConnector = this.getConnectorByUri(idParts.id);
610
+ const result = await identityConnector.createProof(controller, verificationMethodId, proofType, unsecureDocument);
611
+ return result;
612
+ }
613
+ catch (error) {
614
+ throw new GeneralError(IdentityService.CLASS_NAME, "proofCreateFailed", { verificationMethodId }, error);
615
+ }
616
+ });
458
617
  }
459
618
  /**
460
619
  * Verify proof for a document with the specified verification method.
@@ -466,15 +625,18 @@ export class IdentityService {
466
625
  Guards.object(IdentityService.CLASS_NAME, "document", document);
467
626
  Guards.object(IdentityService.CLASS_NAME, "proof", proof);
468
627
  Guards.stringValue(IdentityService.CLASS_NAME, "proof.verificationMethod", proof.verificationMethod);
469
- try {
470
- const idParts = DocumentHelper.parseId(proof.verificationMethod);
471
- const identityConnector = this.getConnectorByUri(idParts.id);
472
- const result = await identityConnector.verifyProof(document, proof);
473
- return result;
474
- }
475
- catch (error) {
476
- throw new GeneralError(IdentityService.CLASS_NAME, "proofVerifyFailed", undefined, error);
477
- }
628
+ const verificationMethod = proof.verificationMethod;
629
+ return TracingHelper.withSpan(this._tracingComponent, IdentitySpanNames.ProofVerify, undefined, async () => {
630
+ try {
631
+ const idParts = DocumentHelper.parseId(verificationMethod);
632
+ const identityConnector = this.getConnectorByUri(idParts.id);
633
+ const result = await identityConnector.verifyProof(document, proof);
634
+ return result;
635
+ }
636
+ catch (error) {
637
+ throw new GeneralError(IdentityService.CLASS_NAME, "proofVerifyFailed", undefined, error);
638
+ }
639
+ });
478
640
  }
479
641
  /**
480
642
  * Get the connector from the namespace.