@twin.org/immutable-proof-service 0.0.1-next.1 → 0.0.1-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.
@@ -4,14 +4,14 @@ var core = require('@twin.org/core');
4
4
  var immutableProofModels = require('@twin.org/immutable-proof-models');
5
5
  var standardsW3cDid = require('@twin.org/standards-w3c-did');
6
6
  var web = require('@twin.org/web');
7
+ var backgroundTaskModels = require('@twin.org/background-task-models');
7
8
  var crypto = require('@twin.org/crypto');
8
9
  var dataJsonLd = require('@twin.org/data-json-ld');
9
- var dataSchemaOrg = require('@twin.org/data-schema-org');
10
- var entity = require('@twin.org/entity');
11
10
  var entityStorageModels = require('@twin.org/entity-storage-models');
12
11
  var identityModels = require('@twin.org/identity-models');
13
12
  var immutableStorageModels = require('@twin.org/immutable-storage-models');
14
13
  var vaultModels = require('@twin.org/vault-models');
14
+ var entity = require('@twin.org/entity');
15
15
 
16
16
  /**
17
17
  * The source used when communicating about these routes.
@@ -197,6 +197,8 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
197
197
  id: "immutableProofVerifyResponseExample",
198
198
  response: {
199
199
  body: {
200
+ "@context": immutableProofModels.ImmutableProofTypes.ContextRoot,
201
+ type: immutableProofModels.ImmutableProofTypes.ImmutableProofVerification,
200
202
  verified: true
201
203
  }
202
204
  }
@@ -210,6 +212,8 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
210
212
  id: "immutableProofVerifyResponseFailExample",
211
213
  response: {
212
214
  body: {
215
+ "@context": immutableProofModels.ImmutableProofTypes.ContextRoot,
216
+ type: immutableProofModels.ImmutableProofTypes.ImmutableProofVerification,
213
217
  verified: false,
214
218
  failure: immutableProofModels.ImmutableProofFailure.ProofTypeMismatch
215
219
  }
@@ -276,9 +280,13 @@ async function immutableProofVerify(httpRequestContext, componentName, request)
276
280
  core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
277
281
  core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
278
282
  core.Guards.object(ROUTES_SOURCE, "request.body.proofObject", request.body.proofObject);
283
+ const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
279
284
  const component = core.ComponentFactory.get(componentName);
280
285
  const result = await component.verify(request.pathParams.id, request.body.proofObject);
281
286
  return {
287
+ headers: {
288
+ [web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
289
+ },
282
290
  body: result
283
291
  };
284
292
  }
@@ -322,40 +330,49 @@ class ImmutableProofService {
322
330
  * @internal
323
331
  */
324
332
  _immutableStorage;
333
+ /**
334
+ * The background task connector.
335
+ * @internal
336
+ */
337
+ _backgroundTaskConnector;
325
338
  /**
326
339
  * The assertion method id to use for the proofs.
327
340
  * @internal
328
341
  */
329
342
  _assertionMethodId;
330
343
  /**
331
- * The proof config key id to use for the proofs.
344
+ * The proof hash key id to use for the proofs.
332
345
  * @internal
333
346
  */
334
- _proofConfigKeyId;
347
+ _proofHashKeyId;
335
348
  /**
336
- * Are we currently processing proofs.
349
+ * The identity connector type.
337
350
  * @internal
338
351
  */
339
- _processing;
352
+ _identityConnectorType;
340
353
  /**
341
354
  * Create a new instance of ImmutableProofService.
342
355
  * @param options The dependencies for the immutable proof connector.
343
356
  * @param options.config The configuration for the connector.
344
357
  * @param options.vaultConnectorType The vault connector type, defaults to "vault".
345
358
  * @param options.immutableProofEntityStorageType The entity storage for proofs, defaults to "immutable-proof".
346
- * @param options.immutableStorageType The immutable storage, defaults to "immutable-proof".
359
+ * @param options.immutableStorageType The immutable storage, defaults to "immutable-storage".
347
360
  * @param options.identityConnectorType The identity connector type, defaults to "identity".
361
+ * @param options.backgroundTaskConnectorType The background task connector type, defaults to "background-task".
348
362
  */
349
363
  constructor(options) {
350
364
  this._vaultConnector = vaultModels.VaultConnectorFactory.get(options?.vaultConnectorType ?? "vault");
351
365
  this._proofStorage = entityStorageModels.EntityStorageConnectorFactory.get(options?.immutableProofEntityStorageType ?? core.StringHelper.kebabCase("ImmutableProof"));
352
- this._immutableStorage = immutableStorageModels.ImmutableStorageConnectorFactory.get(options?.immutableStorageType ?? "immutable-proof");
353
- this._identityConnector = identityModels.IdentityConnectorFactory.get(options?.identityConnectorType ?? "identity");
366
+ this._immutableStorage = immutableStorageModels.ImmutableStorageConnectorFactory.get(options?.immutableStorageType ?? "immutable-storage");
367
+ this._identityConnectorType = options?.identityConnectorType ?? "identity";
368
+ this._identityConnector = identityModels.IdentityConnectorFactory.get(this._identityConnectorType);
369
+ this._backgroundTaskConnector = backgroundTaskModels.BackgroundTaskConnectorFactory.get(options?.backgroundTaskConnectorType ?? "background-task");
354
370
  this._config = options?.config ?? {};
355
- this._assertionMethodId = this._config.assertionMethodId ?? "immutable-proof";
356
- this._proofConfigKeyId = this._config.proofConfigKeyId ?? "immutable-proof";
357
- dataSchemaOrg.SchemaOrgDataTypes.registerRedirects();
358
- this._processing = false;
371
+ this._assertionMethodId = this._config.assertionMethodId ?? "immutable-proof-assertion";
372
+ this._proofHashKeyId = this._config.proofHashKeyId ?? "immutable-proof-hash";
373
+ this._backgroundTaskConnector.registerHandler("immutable-proof", "@twin.org/immutable-proof-task", "processProofTask", async (task) => {
374
+ await this.finaliseTask(task);
375
+ });
359
376
  }
360
377
  /**
361
378
  * Create a new authentication proof.
@@ -385,7 +402,16 @@ class ImmutableProofService {
385
402
  proofObjectHash: core.Converter.bytesToBase64(hash)
386
403
  };
387
404
  await this._proofStorage.set(proofEntity);
388
- this.startProcessingProofs();
405
+ const immutableProof = this.proofEntityToJsonLd(proofEntity);
406
+ const hashData = await this.generateHashData(proofEntity.nodeIdentity, immutableProof);
407
+ const proofTaskPayload = {
408
+ proofId: id,
409
+ nodeIdentity,
410
+ identityConnectorType: this._identityConnectorType,
411
+ assertionMethodId: this._assertionMethodId,
412
+ hashData: core.Converter.bytesToHex(hashData)
413
+ };
414
+ await this._backgroundTaskConnector.create("immutable-proof", proofTaskPayload);
389
415
  return new core.Urn(ImmutableProofService.NAMESPACE, id).toString();
390
416
  }
391
417
  catch (error) {
@@ -435,6 +461,8 @@ class ImmutableProofService {
435
461
  try {
436
462
  const { verified, failure } = await this.internalGet(id, proofObject);
437
463
  return {
464
+ "@context": immutableProofModels.ImmutableProofTypes.ContextRoot,
465
+ type: immutableProofModels.ImmutableProofTypes.ImmutableProofVerification,
438
466
  verified,
439
467
  failure
440
468
  };
@@ -497,13 +525,9 @@ class ImmutableProofService {
497
525
  * @returns The model.
498
526
  * @internal
499
527
  */
500
- proofEntityToModel(proofEntity) {
528
+ proofEntityToJsonLd(proofEntity) {
501
529
  const model = {
502
- "@context": [
503
- immutableProofModels.ImmutableProofTypes.ContextRoot,
504
- dataSchemaOrg.SchemaOrgTypes.ContextRoot,
505
- standardsW3cDid.DidContexts.ContextVCDataIntegrity
506
- ],
530
+ "@context": immutableProofModels.ImmutableProofTypes.ContextRoot,
507
531
  type: immutableProofModels.ImmutableProofTypes.ImmutableProof,
508
532
  id: proofEntity.id,
509
533
  userIdentity: proofEntity.userIdentity,
@@ -513,48 +537,29 @@ class ImmutableProofService {
513
537
  return model;
514
538
  }
515
539
  /**
516
- * Start processing proofs.
517
- * @returns Nothing.
540
+ * Process a proof.
541
+ * @param proofEntity The proof entity to process.
518
542
  * @internal
519
543
  */
520
- startProcessingProofs() {
521
- if (!this._processing) {
522
- setTimeout(async () => {
523
- await this.processProofs();
524
- }, 0);
525
- }
526
- }
527
- /**
528
- * Process the proofs.
529
- * @internal
530
- */
531
- async processProofs() {
532
- // Get the oldest pending proof, plus one more, we can then determine whether to
533
- // trigger another process after this one
534
- const pendingProofs = await this._proofStorage.query({
535
- property: "immutableStorageId",
536
- comparison: entity.ComparisonOperator.Equals,
537
- value: undefined
538
- }, [
539
- {
540
- property: "dateCreated",
541
- sortDirection: entity.SortDirection.Ascending
544
+ async finaliseTask(task) {
545
+ if (task.status === backgroundTaskModels.TaskStatus.Success && core.Is.object(task.payload) && core.Is.object(task.result)) {
546
+ const proofEntity = await this._proofStorage.get(task.payload.proofId);
547
+ if (core.Is.object(proofEntity)) {
548
+ const immutableProof = this.proofEntityToJsonLd(proofEntity);
549
+ // As we are adding the proof to the data we update its context
550
+ immutableProof["@context"] = [
551
+ immutableProofModels.ImmutableProofTypes.ContextRoot,
552
+ standardsW3cDid.DidContexts.ContextVCDataIntegrity
553
+ ];
554
+ immutableProof.proof = task.result.proof;
555
+ if (core.Is.stringValue(immutableProof.proof.created)) {
556
+ proofEntity.dateCreated = immutableProof.proof.created;
557
+ }
558
+ const compacted = await dataJsonLd.JsonLdProcessor.compact(immutableProof, immutableProof["@context"]);
559
+ const immutableStoreResult = await this._immutableStorage.store(proofEntity.nodeIdentity, core.ObjectHelper.toBytes(compacted));
560
+ proofEntity.immutableStorageId = immutableStoreResult.id;
561
+ await this._proofStorage.set(proofEntity);
542
562
  }
543
- ], undefined, undefined, 2);
544
- if (pendingProofs.entities.length > 0) {
545
- const proofEntity = pendingProofs.entities[0];
546
- const immutableProof = this.proofEntityToModel(proofEntity);
547
- const hashData = await this.generateHashData(proofEntity.nodeIdentity, immutableProof);
548
- immutableProof.proof = await this._identityConnector.createProof(proofEntity.nodeIdentity, `${proofEntity.nodeIdentity}#${this._assertionMethodId}`, hashData);
549
- proofEntity.dateCreated = immutableProof.proof.created ?? new Date(Date.now()).toISOString();
550
- const compacted = await dataJsonLd.JsonLdProcessor.compact(immutableProof, immutableProof["@context"]);
551
- proofEntity.immutableStorageId = await this._immutableStorage.store(proofEntity.nodeIdentity, core.ObjectHelper.toBytes(compacted));
552
- await this._proofStorage.set(proofEntity);
553
- }
554
- // If there are still remaining proofs, start the timer again
555
- this._processing = false;
556
- if (pendingProofs.entities.length > 1) {
557
- this.startProcessingProofs();
558
563
  }
559
564
  }
560
565
  /**
@@ -572,14 +577,19 @@ class ImmutableProofService {
572
577
  if (core.Is.empty(proofEntity)) {
573
578
  throw new core.NotFoundError(this.CLASS_NAME, "proofNotFound", id);
574
579
  }
575
- let proofModel = await this.proofEntityToModel(proofEntity);
580
+ let proofModel = await this.proofEntityToJsonLd(proofEntity);
576
581
  let verified = false;
577
582
  let failure = immutableProofModels.ImmutableProofFailure.NotIssued;
578
583
  if (core.Is.stringValue(proofEntity.immutableStorageId)) {
579
584
  failure = immutableProofModels.ImmutableProofFailure.ProofMissing;
580
- const immutableData = await this._immutableStorage.get(proofEntity.immutableStorageId);
581
- if (core.Is.uint8Array(immutableData)) {
582
- proofModel = core.ObjectHelper.fromBytes(immutableData);
585
+ const immutableResult = await this._immutableStorage.get(proofEntity.immutableStorageId);
586
+ if (core.Is.uint8Array(immutableResult.data)) {
587
+ proofModel = core.ObjectHelper.fromBytes(immutableResult.data);
588
+ proofModel.immutableReceipt = immutableResult.receipt;
589
+ // As we are adding the receipt to the data we update its context
590
+ if (core.Is.array(proofModel["@context"])) {
591
+ proofModel["@context"].push(immutableStorageModels.ImmutableStorageTypes.ContextRoot);
592
+ }
583
593
  if (core.Is.object(proofModel.proof) && core.Is.object(proofObject)) {
584
594
  if (proofModel.proof.cryptosuite !== standardsW3cDid.DidCryptoSuites.EdDSAJcs2022) {
585
595
  failure = immutableProofModels.ImmutableProofFailure.CryptoSuiteMismatch;
@@ -616,13 +626,17 @@ class ImmutableProofService {
616
626
  * @internal
617
627
  */
618
628
  async generateHashData(nodeIdentity, immutableProof) {
619
- const canonicalDocument = core.JsonHelper.canonicalize(core.ObjectHelper.omit(immutableProof, ["proof"]));
620
- const proofConfigKey = await this._vaultConnector.getKey(`${nodeIdentity}/${this._proofConfigKeyId}`);
621
- const proofConfigHash = crypto.Sha256.sum256(proofConfigKey.privateKey);
629
+ // We hash the data for the proof without the the proof or immutable receipt for the proof
630
+ // without these objects we can simplify the context
631
+ const object = core.ObjectHelper.omit(immutableProof, ["proof", "immutableReceipt"]);
632
+ object["@context"] = immutableProofModels.ImmutableProofTypes.ContextRoot;
633
+ const canonicalDocument = core.JsonHelper.canonicalize(object);
634
+ const proofKey = await this._vaultConnector.getKey(`${nodeIdentity}/${this._proofHashKeyId}`);
635
+ const proofHash = crypto.Sha256.sum256(proofKey.privateKey);
622
636
  const transformedDocumentHash = crypto.Sha256.sum256(core.Converter.utf8ToBytes(canonicalDocument));
623
- const hashData = new Uint8Array(proofConfigHash.length + transformedDocumentHash.length);
624
- hashData.set(proofConfigHash);
625
- hashData.set(transformedDocumentHash, proofConfigHash.length);
637
+ const hashData = new Uint8Array(proofHash.length + transformedDocumentHash.length);
638
+ hashData.set(proofHash);
639
+ hashData.set(transformedDocumentHash, proofHash.length);
626
640
  return hashData;
627
641
  }
628
642
  }
@@ -2,14 +2,14 @@ import { Guards, ComponentFactory, StringHelper, Validation, Converter, RandomHe
2
2
  import { ImmutableProofTypes, ImmutableProofFailure } from '@twin.org/immutable-proof-models';
3
3
  import { DidContexts, DidTypes, DidCryptoSuites } from '@twin.org/standards-w3c-did';
4
4
  import { HttpStatusCode, HeaderTypes, MimeTypes } from '@twin.org/web';
5
+ import { BackgroundTaskConnectorFactory, TaskStatus } from '@twin.org/background-task-models';
5
6
  import { Blake2b, Sha256 } from '@twin.org/crypto';
6
7
  import { JsonLdHelper, JsonLdProcessor } from '@twin.org/data-json-ld';
7
- import { SchemaOrgDataTypes, SchemaOrgTypes } from '@twin.org/data-schema-org';
8
- import { ComparisonOperator, SortDirection, property, entity, EntitySchemaFactory, EntitySchemaHelper } from '@twin.org/entity';
9
8
  import { EntityStorageConnectorFactory } from '@twin.org/entity-storage-models';
10
9
  import { IdentityConnectorFactory } from '@twin.org/identity-models';
11
- import { ImmutableStorageConnectorFactory } from '@twin.org/immutable-storage-models';
10
+ import { ImmutableStorageConnectorFactory, ImmutableStorageTypes } from '@twin.org/immutable-storage-models';
12
11
  import { VaultConnectorFactory } from '@twin.org/vault-models';
12
+ import { property, SortDirection, entity, EntitySchemaFactory, EntitySchemaHelper } from '@twin.org/entity';
13
13
 
14
14
  /**
15
15
  * The source used when communicating about these routes.
@@ -195,6 +195,8 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
195
195
  id: "immutableProofVerifyResponseExample",
196
196
  response: {
197
197
  body: {
198
+ "@context": ImmutableProofTypes.ContextRoot,
199
+ type: ImmutableProofTypes.ImmutableProofVerification,
198
200
  verified: true
199
201
  }
200
202
  }
@@ -208,6 +210,8 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
208
210
  id: "immutableProofVerifyResponseFailExample",
209
211
  response: {
210
212
  body: {
213
+ "@context": ImmutableProofTypes.ContextRoot,
214
+ type: ImmutableProofTypes.ImmutableProofVerification,
211
215
  verified: false,
212
216
  failure: ImmutableProofFailure.ProofTypeMismatch
213
217
  }
@@ -274,9 +278,13 @@ async function immutableProofVerify(httpRequestContext, componentName, request)
274
278
  Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
275
279
  Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
276
280
  Guards.object(ROUTES_SOURCE, "request.body.proofObject", request.body.proofObject);
281
+ const mimeType = request.headers?.[HeaderTypes.Accept] === MimeTypes.JsonLd ? "jsonld" : "json";
277
282
  const component = ComponentFactory.get(componentName);
278
283
  const result = await component.verify(request.pathParams.id, request.body.proofObject);
279
284
  return {
285
+ headers: {
286
+ [HeaderTypes.ContentType]: mimeType === "json" ? MimeTypes.Json : MimeTypes.JsonLd
287
+ },
280
288
  body: result
281
289
  };
282
290
  }
@@ -320,40 +328,49 @@ class ImmutableProofService {
320
328
  * @internal
321
329
  */
322
330
  _immutableStorage;
331
+ /**
332
+ * The background task connector.
333
+ * @internal
334
+ */
335
+ _backgroundTaskConnector;
323
336
  /**
324
337
  * The assertion method id to use for the proofs.
325
338
  * @internal
326
339
  */
327
340
  _assertionMethodId;
328
341
  /**
329
- * The proof config key id to use for the proofs.
342
+ * The proof hash key id to use for the proofs.
330
343
  * @internal
331
344
  */
332
- _proofConfigKeyId;
345
+ _proofHashKeyId;
333
346
  /**
334
- * Are we currently processing proofs.
347
+ * The identity connector type.
335
348
  * @internal
336
349
  */
337
- _processing;
350
+ _identityConnectorType;
338
351
  /**
339
352
  * Create a new instance of ImmutableProofService.
340
353
  * @param options The dependencies for the immutable proof connector.
341
354
  * @param options.config The configuration for the connector.
342
355
  * @param options.vaultConnectorType The vault connector type, defaults to "vault".
343
356
  * @param options.immutableProofEntityStorageType The entity storage for proofs, defaults to "immutable-proof".
344
- * @param options.immutableStorageType The immutable storage, defaults to "immutable-proof".
357
+ * @param options.immutableStorageType The immutable storage, defaults to "immutable-storage".
345
358
  * @param options.identityConnectorType The identity connector type, defaults to "identity".
359
+ * @param options.backgroundTaskConnectorType The background task connector type, defaults to "background-task".
346
360
  */
347
361
  constructor(options) {
348
362
  this._vaultConnector = VaultConnectorFactory.get(options?.vaultConnectorType ?? "vault");
349
363
  this._proofStorage = EntityStorageConnectorFactory.get(options?.immutableProofEntityStorageType ?? StringHelper.kebabCase("ImmutableProof"));
350
- this._immutableStorage = ImmutableStorageConnectorFactory.get(options?.immutableStorageType ?? "immutable-proof");
351
- this._identityConnector = IdentityConnectorFactory.get(options?.identityConnectorType ?? "identity");
364
+ this._immutableStorage = ImmutableStorageConnectorFactory.get(options?.immutableStorageType ?? "immutable-storage");
365
+ this._identityConnectorType = options?.identityConnectorType ?? "identity";
366
+ this._identityConnector = IdentityConnectorFactory.get(this._identityConnectorType);
367
+ this._backgroundTaskConnector = BackgroundTaskConnectorFactory.get(options?.backgroundTaskConnectorType ?? "background-task");
352
368
  this._config = options?.config ?? {};
353
- this._assertionMethodId = this._config.assertionMethodId ?? "immutable-proof";
354
- this._proofConfigKeyId = this._config.proofConfigKeyId ?? "immutable-proof";
355
- SchemaOrgDataTypes.registerRedirects();
356
- this._processing = false;
369
+ this._assertionMethodId = this._config.assertionMethodId ?? "immutable-proof-assertion";
370
+ this._proofHashKeyId = this._config.proofHashKeyId ?? "immutable-proof-hash";
371
+ this._backgroundTaskConnector.registerHandler("immutable-proof", "@twin.org/immutable-proof-task", "processProofTask", async (task) => {
372
+ await this.finaliseTask(task);
373
+ });
357
374
  }
358
375
  /**
359
376
  * Create a new authentication proof.
@@ -383,7 +400,16 @@ class ImmutableProofService {
383
400
  proofObjectHash: Converter.bytesToBase64(hash)
384
401
  };
385
402
  await this._proofStorage.set(proofEntity);
386
- this.startProcessingProofs();
403
+ const immutableProof = this.proofEntityToJsonLd(proofEntity);
404
+ const hashData = await this.generateHashData(proofEntity.nodeIdentity, immutableProof);
405
+ const proofTaskPayload = {
406
+ proofId: id,
407
+ nodeIdentity,
408
+ identityConnectorType: this._identityConnectorType,
409
+ assertionMethodId: this._assertionMethodId,
410
+ hashData: Converter.bytesToHex(hashData)
411
+ };
412
+ await this._backgroundTaskConnector.create("immutable-proof", proofTaskPayload);
387
413
  return new Urn(ImmutableProofService.NAMESPACE, id).toString();
388
414
  }
389
415
  catch (error) {
@@ -433,6 +459,8 @@ class ImmutableProofService {
433
459
  try {
434
460
  const { verified, failure } = await this.internalGet(id, proofObject);
435
461
  return {
462
+ "@context": ImmutableProofTypes.ContextRoot,
463
+ type: ImmutableProofTypes.ImmutableProofVerification,
436
464
  verified,
437
465
  failure
438
466
  };
@@ -495,13 +523,9 @@ class ImmutableProofService {
495
523
  * @returns The model.
496
524
  * @internal
497
525
  */
498
- proofEntityToModel(proofEntity) {
526
+ proofEntityToJsonLd(proofEntity) {
499
527
  const model = {
500
- "@context": [
501
- ImmutableProofTypes.ContextRoot,
502
- SchemaOrgTypes.ContextRoot,
503
- DidContexts.ContextVCDataIntegrity
504
- ],
528
+ "@context": ImmutableProofTypes.ContextRoot,
505
529
  type: ImmutableProofTypes.ImmutableProof,
506
530
  id: proofEntity.id,
507
531
  userIdentity: proofEntity.userIdentity,
@@ -511,48 +535,29 @@ class ImmutableProofService {
511
535
  return model;
512
536
  }
513
537
  /**
514
- * Start processing proofs.
515
- * @returns Nothing.
538
+ * Process a proof.
539
+ * @param proofEntity The proof entity to process.
516
540
  * @internal
517
541
  */
518
- startProcessingProofs() {
519
- if (!this._processing) {
520
- setTimeout(async () => {
521
- await this.processProofs();
522
- }, 0);
523
- }
524
- }
525
- /**
526
- * Process the proofs.
527
- * @internal
528
- */
529
- async processProofs() {
530
- // Get the oldest pending proof, plus one more, we can then determine whether to
531
- // trigger another process after this one
532
- const pendingProofs = await this._proofStorage.query({
533
- property: "immutableStorageId",
534
- comparison: ComparisonOperator.Equals,
535
- value: undefined
536
- }, [
537
- {
538
- property: "dateCreated",
539
- sortDirection: SortDirection.Ascending
542
+ async finaliseTask(task) {
543
+ if (task.status === TaskStatus.Success && Is.object(task.payload) && Is.object(task.result)) {
544
+ const proofEntity = await this._proofStorage.get(task.payload.proofId);
545
+ if (Is.object(proofEntity)) {
546
+ const immutableProof = this.proofEntityToJsonLd(proofEntity);
547
+ // As we are adding the proof to the data we update its context
548
+ immutableProof["@context"] = [
549
+ ImmutableProofTypes.ContextRoot,
550
+ DidContexts.ContextVCDataIntegrity
551
+ ];
552
+ immutableProof.proof = task.result.proof;
553
+ if (Is.stringValue(immutableProof.proof.created)) {
554
+ proofEntity.dateCreated = immutableProof.proof.created;
555
+ }
556
+ const compacted = await JsonLdProcessor.compact(immutableProof, immutableProof["@context"]);
557
+ const immutableStoreResult = await this._immutableStorage.store(proofEntity.nodeIdentity, ObjectHelper.toBytes(compacted));
558
+ proofEntity.immutableStorageId = immutableStoreResult.id;
559
+ await this._proofStorage.set(proofEntity);
540
560
  }
541
- ], undefined, undefined, 2);
542
- if (pendingProofs.entities.length > 0) {
543
- const proofEntity = pendingProofs.entities[0];
544
- const immutableProof = this.proofEntityToModel(proofEntity);
545
- const hashData = await this.generateHashData(proofEntity.nodeIdentity, immutableProof);
546
- immutableProof.proof = await this._identityConnector.createProof(proofEntity.nodeIdentity, `${proofEntity.nodeIdentity}#${this._assertionMethodId}`, hashData);
547
- proofEntity.dateCreated = immutableProof.proof.created ?? new Date(Date.now()).toISOString();
548
- const compacted = await JsonLdProcessor.compact(immutableProof, immutableProof["@context"]);
549
- proofEntity.immutableStorageId = await this._immutableStorage.store(proofEntity.nodeIdentity, ObjectHelper.toBytes(compacted));
550
- await this._proofStorage.set(proofEntity);
551
- }
552
- // If there are still remaining proofs, start the timer again
553
- this._processing = false;
554
- if (pendingProofs.entities.length > 1) {
555
- this.startProcessingProofs();
556
561
  }
557
562
  }
558
563
  /**
@@ -570,14 +575,19 @@ class ImmutableProofService {
570
575
  if (Is.empty(proofEntity)) {
571
576
  throw new NotFoundError(this.CLASS_NAME, "proofNotFound", id);
572
577
  }
573
- let proofModel = await this.proofEntityToModel(proofEntity);
578
+ let proofModel = await this.proofEntityToJsonLd(proofEntity);
574
579
  let verified = false;
575
580
  let failure = ImmutableProofFailure.NotIssued;
576
581
  if (Is.stringValue(proofEntity.immutableStorageId)) {
577
582
  failure = ImmutableProofFailure.ProofMissing;
578
- const immutableData = await this._immutableStorage.get(proofEntity.immutableStorageId);
579
- if (Is.uint8Array(immutableData)) {
580
- proofModel = ObjectHelper.fromBytes(immutableData);
583
+ const immutableResult = await this._immutableStorage.get(proofEntity.immutableStorageId);
584
+ if (Is.uint8Array(immutableResult.data)) {
585
+ proofModel = ObjectHelper.fromBytes(immutableResult.data);
586
+ proofModel.immutableReceipt = immutableResult.receipt;
587
+ // As we are adding the receipt to the data we update its context
588
+ if (Is.array(proofModel["@context"])) {
589
+ proofModel["@context"].push(ImmutableStorageTypes.ContextRoot);
590
+ }
581
591
  if (Is.object(proofModel.proof) && Is.object(proofObject)) {
582
592
  if (proofModel.proof.cryptosuite !== DidCryptoSuites.EdDSAJcs2022) {
583
593
  failure = ImmutableProofFailure.CryptoSuiteMismatch;
@@ -614,13 +624,17 @@ class ImmutableProofService {
614
624
  * @internal
615
625
  */
616
626
  async generateHashData(nodeIdentity, immutableProof) {
617
- const canonicalDocument = JsonHelper.canonicalize(ObjectHelper.omit(immutableProof, ["proof"]));
618
- const proofConfigKey = await this._vaultConnector.getKey(`${nodeIdentity}/${this._proofConfigKeyId}`);
619
- const proofConfigHash = Sha256.sum256(proofConfigKey.privateKey);
627
+ // We hash the data for the proof without the the proof or immutable receipt for the proof
628
+ // without these objects we can simplify the context
629
+ const object = ObjectHelper.omit(immutableProof, ["proof", "immutableReceipt"]);
630
+ object["@context"] = ImmutableProofTypes.ContextRoot;
631
+ const canonicalDocument = JsonHelper.canonicalize(object);
632
+ const proofKey = await this._vaultConnector.getKey(`${nodeIdentity}/${this._proofHashKeyId}`);
633
+ const proofHash = Sha256.sum256(proofKey.privateKey);
620
634
  const transformedDocumentHash = Sha256.sum256(Converter.utf8ToBytes(canonicalDocument));
621
- const hashData = new Uint8Array(proofConfigHash.length + transformedDocumentHash.length);
622
- hashData.set(proofConfigHash);
623
- hashData.set(transformedDocumentHash, proofConfigHash.length);
635
+ const hashData = new Uint8Array(proofHash.length + transformedDocumentHash.length);
636
+ hashData.set(proofHash);
637
+ hashData.set(transformedDocumentHash, proofHash.length);
624
638
  return hashData;
625
639
  }
626
640
  }
@@ -1,5 +1,5 @@
1
1
  import { type IJsonLdNodeObject } from "@twin.org/data-json-ld";
2
- import { ImmutableProofFailure, type IImmutableProof, type IImmutableProofComponent } from "@twin.org/immutable-proof-models";
2
+ import { type IImmutableProof, type IImmutableProofComponent, type IImmutableProofVerification } from "@twin.org/immutable-proof-models";
3
3
  import type { IImmutableProofServiceConfig } from "./models/IImmutableProofServiceConfig";
4
4
  /**
5
5
  * Class for performing immutable proof operations.
@@ -19,15 +19,17 @@ export declare class ImmutableProofService implements IImmutableProofComponent {
19
19
  * @param options.config The configuration for the connector.
20
20
  * @param options.vaultConnectorType The vault connector type, defaults to "vault".
21
21
  * @param options.immutableProofEntityStorageType The entity storage for proofs, defaults to "immutable-proof".
22
- * @param options.immutableStorageType The immutable storage, defaults to "immutable-proof".
22
+ * @param options.immutableStorageType The immutable storage, defaults to "immutable-storage".
23
23
  * @param options.identityConnectorType The identity connector type, defaults to "identity".
24
+ * @param options.backgroundTaskConnectorType The background task connector type, defaults to "background-task".
24
25
  */
25
26
  constructor(options?: {
26
27
  vaultConnectorType?: string;
27
28
  immutableProofEntityStorageType?: string;
28
29
  immutableStorageType?: string;
29
- config?: IImmutableProofServiceConfig;
30
30
  identityConnectorType?: string;
31
+ backgroundTaskConnectorType?: string;
32
+ config?: IImmutableProofServiceConfig;
31
33
  });
32
34
  /**
33
35
  * Create a new authentication proof.
@@ -51,10 +53,7 @@ export declare class ImmutableProofService implements IImmutableProofComponent {
51
53
  * @returns The result of the verification and any failures.
52
54
  * @throws NotFoundError if the proof is not found.
53
55
  */
54
- verify(id: string, proofObject: IJsonLdNodeObject): Promise<{
55
- verified: boolean;
56
- failure?: ImmutableProofFailure;
57
- }>;
56
+ verify(id: string, proofObject: IJsonLdNodeObject): Promise<IImmutableProofVerification>;
58
57
  /**
59
58
  * Remove the immutable storage for the proof.
60
59
  * @param id The id of the proof to remove the storage from.
@@ -4,12 +4,12 @@
4
4
  export interface IImmutableProofServiceConfig {
5
5
  /**
6
6
  * The assertion method id to use for the stream.
7
- * @default immutable-proof
7
+ * @default immutable-proof-assertion
8
8
  */
9
9
  assertionMethodId?: string;
10
10
  /**
11
- * The key to use in the proof config.
12
- * @default immutable-proof
11
+ * The key to use in the proof hash.
12
+ * @default immutable-proof-hash
13
13
  */
14
- proofConfigKeyId?: string;
14
+ proofHashKeyId?: string;
15
15
  }
package/docs/changelog.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # @twin.org/immutable-proof-service - Changelog
2
2
 
3
- ## v0.0.1-next.1
3
+ ## v0.0.1-next.10
4
4
 
5
5
  - Initial Release
@@ -189,7 +189,7 @@
189
189
  "content": {
190
190
  "application/json": {
191
191
  "schema": {
192
- "$ref": "#/components/schemas/ImmutableProof"
192
+ "$ref": "https://schema.twindev.org/immutable-proof/ImmutableProof"
193
193
  },
194
194
  "examples": {
195
195
  "immutableProofGetResponseExample": {
@@ -214,7 +214,7 @@
214
214
  },
215
215
  "application/ld+json": {
216
216
  "schema": {
217
- "$ref": "#/components/schemas/ImmutableProof"
217
+ "$ref": "https://schema.twindev.org/immutable-proof/ImmutableProof"
218
218
  },
219
219
  "examples": {
220
220
  "immutableProofJsonLdGetResponseExample": {
@@ -344,6 +344,15 @@
344
344
  },
345
345
  "style": "simple",
346
346
  "example": "ais:1234567890"
347
+ },
348
+ {
349
+ "name": "accept",
350
+ "in": "header",
351
+ "required": true,
352
+ "schema": {
353
+ "type": "string"
354
+ },
355
+ "style": "simple"
347
356
  }
348
357
  ],
349
358
  "security": [
@@ -379,16 +388,20 @@
379
388
  "content": {
380
389
  "application/json": {
381
390
  "schema": {
382
- "$ref": "#/components/schemas/ImmutableProofVerifyResponse"
391
+ "$ref": "https://schema.twindev.org/immutable-proof/ImmutableProofVerification"
383
392
  },
384
393
  "examples": {
385
394
  "immutableProofVerifyResponseExample": {
386
395
  "value": {
396
+ "@context": "https://schema.twindev.org/immutable-proof/",
397
+ "type": "ImmutableProofVerification",
387
398
  "verified": true
388
399
  }
389
400
  },
390
401
  "immutableProofVerifyResponseFailExample": {
391
402
  "value": {
403
+ "@context": "https://schema.twindev.org/immutable-proof/",
404
+ "type": "ImmutableProofVerification",
392
405
  "verified": false,
393
406
  "failure": "proofTypeMismatch"
394
407
  }
@@ -643,66 +656,6 @@
643
656
  "additionalProperties": false,
644
657
  "description": "Model to describe serialized error."
645
658
  },
646
- "ImmutableProof": {
647
- "type": "object",
648
- "properties": {
649
- "@context": {
650
- "anyOf": [
651
- {
652
- "type": "string",
653
- "const": "https://schema.twindev.org/immutable-proof/"
654
- },
655
- {
656
- "type": "array",
657
- "minItems": 1,
658
- "items": [
659
- {
660
- "type": "string",
661
- "const": "https://schema.twindev.org/immutable-proof/"
662
- }
663
- ],
664
- "additionalItems": {
665
- "type": "string"
666
- }
667
- }
668
- ],
669
- "description": "JSON-LD Context."
670
- },
671
- "type": {
672
- "type": "string",
673
- "const": "ImmutableProof",
674
- "description": "JSON-LD Type."
675
- },
676
- "id": {
677
- "type": "string",
678
- "description": "The id of the proof."
679
- },
680
- "userIdentity": {
681
- "type": "string",
682
- "description": "The id of the user who created the proof."
683
- },
684
- "proofObjectId": {
685
- "type": "string",
686
- "description": "The id of the object associated with the proof."
687
- },
688
- "proofObjectHash": {
689
- "type": "string",
690
- "description": "The hash of the object associated with the proof."
691
- },
692
- "proof": {
693
- "$ref": "#/components/schemas/DidProof"
694
- }
695
- },
696
- "required": [
697
- "@context",
698
- "type",
699
- "id",
700
- "userIdentity",
701
- "proofObjectHash"
702
- ],
703
- "additionalProperties": false,
704
- "description": "Interface describing an immutable proof state."
705
- },
706
659
  "ImmutableProofCreateRequest": {
707
660
  "type": "object",
708
661
  "properties": {
@@ -716,36 +669,6 @@
716
669
  "additionalProperties": false,
717
670
  "description": "The parameters from the body."
718
671
  },
719
- "ImmutableProofFailure": {
720
- "anyOf": [
721
- {
722
- "type": "string",
723
- "const": "notIssued",
724
- "description": "Proof not yes issued."
725
- },
726
- {
727
- "type": "string",
728
- "const": "proofMissing",
729
- "description": "Proof missing."
730
- },
731
- {
732
- "type": "string",
733
- "const": "cryptoSuiteMismatch",
734
- "description": "Crypto suite mismatch."
735
- },
736
- {
737
- "type": "string",
738
- "const": "proofTypeMismatch",
739
- "description": "Proof type."
740
- },
741
- {
742
- "type": "string",
743
- "const": "signatureMismatch",
744
- "description": "Signature mismatch."
745
- }
746
- ],
747
- "description": "The failure reason of the proof."
748
- },
749
672
  "ImmutableProofVerifyRequest": {
750
673
  "type": "object",
751
674
  "properties": {
@@ -759,23 +682,6 @@
759
682
  "additionalProperties": false,
760
683
  "description": "The parameters from the body."
761
684
  },
762
- "ImmutableProofVerifyResponse": {
763
- "type": "object",
764
- "properties": {
765
- "verified": {
766
- "type": "boolean",
767
- "description": "Was the proof verified."
768
- },
769
- "failure": {
770
- "$ref": "#/components/schemas/ImmutableProofFailure"
771
- }
772
- },
773
- "required": [
774
- "verified"
775
- ],
776
- "additionalProperties": false,
777
- "description": "The response body."
778
- },
779
685
  "NotFoundResponse": {
780
686
  "type": "object",
781
687
  "additionalProperties": false,
@@ -30,16 +30,20 @@ The entity storage for proofs, defaults to "immutable-proof".
30
30
 
31
31
  • **options.immutableStorageType?**: `string`
32
32
 
33
- The immutable storage, defaults to "immutable-proof".
34
-
35
- • **options.config?**: [`IImmutableProofServiceConfig`](../interfaces/IImmutableProofServiceConfig.md)
36
-
37
- The configuration for the connector.
33
+ The immutable storage, defaults to "immutable-storage".
38
34
 
39
35
  • **options.identityConnectorType?**: `string`
40
36
 
41
37
  The identity connector type, defaults to "identity".
42
38
 
39
+ • **options.backgroundTaskConnectorType?**: `string`
40
+
41
+ The background task connector type, defaults to "background-task".
42
+
43
+ • **options.config?**: [`IImmutableProofServiceConfig`](../interfaces/IImmutableProofServiceConfig.md)
44
+
45
+ The configuration for the connector.
46
+
43
47
  #### Returns
44
48
 
45
49
  [`ImmutableProofService`](ImmutableProofService.md)
@@ -128,7 +132,7 @@ NotFoundError if the proof is not found.
128
132
 
129
133
  ### verify()
130
134
 
131
- > **verify**(`id`, `proofObject`): `Promise`\<`object`\>
135
+ > **verify**(`id`, `proofObject`): `Promise`\<`IImmutableProofVerification`\>
132
136
 
133
137
  Verify an authentication proof.
134
138
 
@@ -144,18 +148,10 @@ The object to verify as JSON-LD.
144
148
 
145
149
  #### Returns
146
150
 
147
- `Promise`\<`object`\>
151
+ `Promise`\<`IImmutableProofVerification`\>
148
152
 
149
153
  The result of the verification and any failures.
150
154
 
151
- ##### verified
152
-
153
- > **verified**: `boolean`
154
-
155
- ##### failure?
156
-
157
- > `optional` **failure**: `ImmutableProofFailure`
158
-
159
155
  #### Throws
160
156
 
161
157
  NotFoundError if the proof is not found.
@@ -13,19 +13,19 @@ The assertion method id to use for the stream.
13
13
  #### Default
14
14
 
15
15
  ```ts
16
- immutable-proof
16
+ immutable-proof-assertion
17
17
  ```
18
18
 
19
19
  ***
20
20
 
21
- ### proofConfigKeyId?
21
+ ### proofHashKeyId?
22
22
 
23
- > `optional` **proofConfigKeyId**: `string`
23
+ > `optional` **proofHashKeyId**: `string`
24
24
 
25
- The key to use in the proof config.
25
+ The key to use in the proof hash.
26
26
 
27
27
  #### Default
28
28
 
29
29
  ```ts
30
- immutable-proof
30
+ immutable-proof-hash
31
31
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/immutable-proof-service",
3
- "version": "0.0.1-next.1",
3
+ "version": "0.0.1-next.10",
4
4
  "description": "Immutable proof contract implementation and REST endpoint definitions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,6 +15,7 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@twin.org/api-models": "next",
18
+ "@twin.org/background-task-models": "next",
18
19
  "@twin.org/core": "next",
19
20
  "@twin.org/crypto": "next",
20
21
  "@twin.org/data-json-ld": "next",
@@ -22,7 +23,8 @@
22
23
  "@twin.org/entity": "next",
23
24
  "@twin.org/entity-storage-models": "next",
24
25
  "@twin.org/identity-models": "next",
25
- "@twin.org/immutable-proof-models": "0.0.1-next.1",
26
+ "@twin.org/immutable-proof-models": "0.0.1-next.10",
27
+ "@twin.org/immutable-proof-task": "0.0.1-next.10",
26
28
  "@twin.org/immutable-storage-models": "next",
27
29
  "@twin.org/nameof": "next",
28
30
  "@twin.org/standards-w3c-did": "next",
@@ -39,7 +41,7 @@
39
41
  "import": "./dist/esm/index.mjs",
40
42
  "types": "./dist/types/index.d.ts"
41
43
  },
42
- "./locales": "./locales"
44
+ "./locales/*.json": "./locales/*.json"
43
45
  },
44
46
  "files": [
45
47
  "dist/cjs",