@twin.org/immutable-proof-service 0.0.1-next.3 → 0.0.1-next.31
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/cjs/index.cjs +201 -233
- package/dist/esm/index.mjs +205 -237
- package/dist/types/entities/immutableProof.d.ts +2 -2
- package/dist/types/immutableProofService.d.ts +12 -24
- package/dist/types/index.d.ts +2 -1
- package/dist/types/models/IImmutableProofServiceConfig.d.ts +3 -8
- package/dist/types/models/IImmutableProofServiceConstructorOptions.d.ts +34 -0
- package/docs/changelog.md +16 -1
- package/docs/open-api/spec.json +705 -732
- package/docs/reference/classes/ImmutableProof.md +3 -3
- package/docs/reference/classes/ImmutableProofService.md +35 -43
- package/docs/reference/functions/generateRestRoutesImmutableProof.md +8 -4
- package/docs/reference/functions/immutableProofCreate.md +9 -3
- package/docs/reference/functions/immutableProofGet.md +9 -3
- package/docs/reference/functions/immutableProofVerify.md +9 -3
- package/docs/reference/index.md +1 -0
- package/docs/reference/interfaces/IImmutableProofServiceConfig.md +4 -18
- package/docs/reference/interfaces/IImmutableProofServiceConstructorOptions.md +75 -0
- package/locales/en.json +1 -1
- package/package.json +10 -8
package/dist/esm/index.mjs
CHANGED
|
@@ -1,15 +1,81 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { property, SortDirection, entity, EntitySchemaFactory, EntitySchemaHelper } from '@twin.org/entity';
|
|
2
|
+
import { Guards, ComponentFactory, StringHelper, Is, Validation, Converter, RandomHelper, ObjectHelper, Urn, GeneralError, NotFoundError, JsonHelper } from '@twin.org/core';
|
|
3
|
+
import { ImmutableProofTypes, ImmutableProofContexts, ImmutableProofFailure, ImmutableProofTopics } from '@twin.org/immutable-proof-models';
|
|
4
|
+
import { DidCryptoSuites, ProofTypes, DidContexts } from '@twin.org/standards-w3c-did';
|
|
4
5
|
import { HttpStatusCode, HeaderTypes, MimeTypes } from '@twin.org/web';
|
|
5
|
-
import {
|
|
6
|
+
import { BackgroundTaskConnectorFactory, TaskStatus } from '@twin.org/background-task-models';
|
|
7
|
+
import { Sha256 } from '@twin.org/crypto';
|
|
6
8
|
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
9
|
import { EntityStorageConnectorFactory } from '@twin.org/entity-storage-models';
|
|
10
10
|
import { IdentityConnectorFactory } from '@twin.org/identity-models';
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import { VerifiableStorageConnectorFactory } from '@twin.org/verifiable-storage-models';
|
|
12
|
+
|
|
13
|
+
// Copyright 2024 IOTA Stiftung.
|
|
14
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
15
|
+
/**
|
|
16
|
+
* Class describing the immutable proof.
|
|
17
|
+
*/
|
|
18
|
+
let ImmutableProof = class ImmutableProof {
|
|
19
|
+
/**
|
|
20
|
+
* The id of the proof.
|
|
21
|
+
*/
|
|
22
|
+
id;
|
|
23
|
+
/**
|
|
24
|
+
* The identity of the node which controls the proof.
|
|
25
|
+
*/
|
|
26
|
+
nodeIdentity;
|
|
27
|
+
/**
|
|
28
|
+
* The identity of the user which created the proof.
|
|
29
|
+
*/
|
|
30
|
+
userIdentity;
|
|
31
|
+
/**
|
|
32
|
+
* The date/time of when the proof was created.
|
|
33
|
+
*/
|
|
34
|
+
dateCreated;
|
|
35
|
+
/**
|
|
36
|
+
* The associated id for the item.
|
|
37
|
+
*/
|
|
38
|
+
proofObjectId;
|
|
39
|
+
/**
|
|
40
|
+
* The associated hash for the item.
|
|
41
|
+
*/
|
|
42
|
+
proofObjectHash;
|
|
43
|
+
/**
|
|
44
|
+
* The verifiable storage id.
|
|
45
|
+
*/
|
|
46
|
+
verifiableStorageId;
|
|
47
|
+
};
|
|
48
|
+
__decorate([
|
|
49
|
+
property({ type: "string", isPrimary: true }),
|
|
50
|
+
__metadata("design:type", String)
|
|
51
|
+
], ImmutableProof.prototype, "id", void 0);
|
|
52
|
+
__decorate([
|
|
53
|
+
property({ type: "string" }),
|
|
54
|
+
__metadata("design:type", String)
|
|
55
|
+
], ImmutableProof.prototype, "nodeIdentity", void 0);
|
|
56
|
+
__decorate([
|
|
57
|
+
property({ type: "string" }),
|
|
58
|
+
__metadata("design:type", String)
|
|
59
|
+
], ImmutableProof.prototype, "userIdentity", void 0);
|
|
60
|
+
__decorate([
|
|
61
|
+
property({ type: "string", format: "date-time", sortDirection: SortDirection.Descending }),
|
|
62
|
+
__metadata("design:type", String)
|
|
63
|
+
], ImmutableProof.prototype, "dateCreated", void 0);
|
|
64
|
+
__decorate([
|
|
65
|
+
property({ type: "string", optional: true }),
|
|
66
|
+
__metadata("design:type", String)
|
|
67
|
+
], ImmutableProof.prototype, "proofObjectId", void 0);
|
|
68
|
+
__decorate([
|
|
69
|
+
property({ type: "string" }),
|
|
70
|
+
__metadata("design:type", String)
|
|
71
|
+
], ImmutableProof.prototype, "proofObjectHash", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
property({ type: "string", optional: true }),
|
|
74
|
+
__metadata("design:type", String)
|
|
75
|
+
], ImmutableProof.prototype, "verifiableStorageId", void 0);
|
|
76
|
+
ImmutableProof = __decorate([
|
|
77
|
+
entity()
|
|
78
|
+
], ImmutableProof);
|
|
13
79
|
|
|
14
80
|
/**
|
|
15
81
|
* The source used when communicating about these routes.
|
|
@@ -45,8 +111,8 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
|
|
|
45
111
|
id: "immutableProofCreateRequestExample",
|
|
46
112
|
request: {
|
|
47
113
|
body: {
|
|
48
|
-
|
|
49
|
-
"@context": "
|
|
114
|
+
document: {
|
|
115
|
+
"@context": "https://schema.org",
|
|
50
116
|
type: "Person",
|
|
51
117
|
name: "John Smith"
|
|
52
118
|
}
|
|
@@ -106,15 +172,19 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
|
|
|
106
172
|
id: "immutableProofGetResponseExample",
|
|
107
173
|
response: {
|
|
108
174
|
body: {
|
|
109
|
-
"@context":
|
|
175
|
+
"@context": [
|
|
176
|
+
ImmutableProofContexts.ContextRoot,
|
|
177
|
+
ImmutableProofContexts.ContextRootCommon
|
|
178
|
+
],
|
|
110
179
|
type: ImmutableProofTypes.ImmutableProof,
|
|
111
180
|
id: "ais:1234567890",
|
|
181
|
+
nodeIdentity: "node-1",
|
|
112
182
|
userIdentity: "user-1",
|
|
113
183
|
proofObjectId: "test:1234567890",
|
|
114
184
|
proofObjectHash: "EAOKyDN0mYQbBh91eMdVeroxQx1H4GfnRbmt6n/2L/Y=",
|
|
115
185
|
proof: {
|
|
116
|
-
"@context": DidContexts.
|
|
117
|
-
type:
|
|
186
|
+
"@context": DidContexts.ContextDataIntegrity,
|
|
187
|
+
type: ProofTypes.DataIntegrityProof,
|
|
118
188
|
cryptosuite: DidCryptoSuites.EdDSAJcs2022,
|
|
119
189
|
created: "2024-08-22T11:56:56.272Z",
|
|
120
190
|
proofPurpose: "assertionMethod",
|
|
@@ -136,15 +206,19 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
|
|
|
136
206
|
[HeaderTypes.ContentType]: MimeTypes.JsonLd
|
|
137
207
|
},
|
|
138
208
|
body: {
|
|
139
|
-
"@context":
|
|
209
|
+
"@context": [
|
|
210
|
+
ImmutableProofContexts.ContextRoot,
|
|
211
|
+
ImmutableProofContexts.ContextRootCommon
|
|
212
|
+
],
|
|
140
213
|
type: ImmutableProofTypes.ImmutableProof,
|
|
141
214
|
id: "ais:1234567890",
|
|
215
|
+
nodeIdentity: "node-1",
|
|
142
216
|
userIdentity: "user-1",
|
|
143
217
|
proofObjectId: "test:1234567890",
|
|
144
218
|
proofObjectHash: "EAOKyDN0mYQbBh91eMdVeroxQx1H4GfnRbmt6n/2L/Y=",
|
|
145
219
|
proof: {
|
|
146
|
-
"@context": DidContexts.
|
|
147
|
-
type:
|
|
220
|
+
"@context": DidContexts.ContextDataIntegrity,
|
|
221
|
+
type: ProofTypes.DataIntegrityProof,
|
|
148
222
|
cryptosuite: DidCryptoSuites.EdDSAJcs2022,
|
|
149
223
|
created: "2024-08-22T11:56:56.272Z",
|
|
150
224
|
proofPurpose: "assertionMethod",
|
|
@@ -164,8 +238,8 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
|
|
|
164
238
|
operationId: "immutableProofVerify",
|
|
165
239
|
summary: "Verify a proof",
|
|
166
240
|
tag: tagsImmutableProof[0].name,
|
|
167
|
-
method: "
|
|
168
|
-
path: `${baseRouteName}/:id`,
|
|
241
|
+
method: "GET",
|
|
242
|
+
path: `${baseRouteName}/:id/verify`,
|
|
169
243
|
handler: async (httpRequestContext, request) => immutableProofVerify(httpRequestContext, componentName, request),
|
|
170
244
|
requestType: {
|
|
171
245
|
type: "IImmutableProofVerifyRequest",
|
|
@@ -175,13 +249,6 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
|
|
|
175
249
|
request: {
|
|
176
250
|
pathParams: {
|
|
177
251
|
id: "ais:1234567890"
|
|
178
|
-
},
|
|
179
|
-
body: {
|
|
180
|
-
proofObject: {
|
|
181
|
-
"@context": "http://schema.org",
|
|
182
|
-
type: "Person",
|
|
183
|
-
name: "John Smith"
|
|
184
|
-
}
|
|
185
252
|
}
|
|
186
253
|
}
|
|
187
254
|
}
|
|
@@ -195,7 +262,7 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
|
|
|
195
262
|
id: "immutableProofVerifyResponseExample",
|
|
196
263
|
response: {
|
|
197
264
|
body: {
|
|
198
|
-
"@context":
|
|
265
|
+
"@context": ImmutableProofContexts.ContextRoot,
|
|
199
266
|
type: ImmutableProofTypes.ImmutableProofVerification,
|
|
200
267
|
verified: true
|
|
201
268
|
}
|
|
@@ -210,7 +277,7 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
|
|
|
210
277
|
id: "immutableProofVerifyResponseFailExample",
|
|
211
278
|
response: {
|
|
212
279
|
body: {
|
|
213
|
-
"@context":
|
|
280
|
+
"@context": ImmutableProofContexts.ContextRoot,
|
|
214
281
|
type: ImmutableProofTypes.ImmutableProofVerification,
|
|
215
282
|
verified: false,
|
|
216
283
|
failure: ImmutableProofFailure.ProofTypeMismatch
|
|
@@ -235,9 +302,9 @@ function generateRestRoutesImmutableProof(baseRouteName, componentName) {
|
|
|
235
302
|
*/
|
|
236
303
|
async function immutableProofCreate(httpRequestContext, componentName, request) {
|
|
237
304
|
Guards.object(ROUTES_SOURCE, "request", request);
|
|
238
|
-
Guards.object(ROUTES_SOURCE, "request.body.
|
|
305
|
+
Guards.object(ROUTES_SOURCE, "request.body.document", request.body.document);
|
|
239
306
|
const component = ComponentFactory.get(componentName);
|
|
240
|
-
const result = await component.create(request.body.
|
|
307
|
+
const result = await component.create(request.body.document, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
241
308
|
return {
|
|
242
309
|
statusCode: HttpStatusCode.created,
|
|
243
310
|
headers: {
|
|
@@ -277,10 +344,9 @@ async function immutableProofVerify(httpRequestContext, componentName, request)
|
|
|
277
344
|
Guards.object(ROUTES_SOURCE, "request", request);
|
|
278
345
|
Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
279
346
|
Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
|
|
280
|
-
Guards.object(ROUTES_SOURCE, "request.body.proofObject", request.body.proofObject);
|
|
281
347
|
const mimeType = request.headers?.[HeaderTypes.Accept] === MimeTypes.JsonLd ? "jsonld" : "json";
|
|
282
348
|
const component = ComponentFactory.get(componentName);
|
|
283
|
-
const result = await component.verify(request.pathParams.id
|
|
349
|
+
const result = await component.verify(request.pathParams.id);
|
|
284
350
|
return {
|
|
285
351
|
headers: {
|
|
286
352
|
[HeaderTypes.ContentType]: mimeType === "json" ? MimeTypes.Json : MimeTypes.JsonLd
|
|
@@ -308,11 +374,6 @@ class ImmutableProofService {
|
|
|
308
374
|
* @internal
|
|
309
375
|
*/
|
|
310
376
|
_config;
|
|
311
|
-
/**
|
|
312
|
-
* The vault connector.
|
|
313
|
-
* @internal
|
|
314
|
-
*/
|
|
315
|
-
_vaultConnector;
|
|
316
377
|
/**
|
|
317
378
|
* The identity connector.
|
|
318
379
|
* @internal
|
|
@@ -324,74 +385,89 @@ class ImmutableProofService {
|
|
|
324
385
|
*/
|
|
325
386
|
_proofStorage;
|
|
326
387
|
/**
|
|
327
|
-
* The
|
|
388
|
+
* The verifiable storage for the credentials.
|
|
389
|
+
* @internal
|
|
390
|
+
*/
|
|
391
|
+
_verifiableStorage;
|
|
392
|
+
/**
|
|
393
|
+
* The background task connector.
|
|
328
394
|
* @internal
|
|
329
395
|
*/
|
|
330
|
-
|
|
396
|
+
_backgroundTaskConnector;
|
|
331
397
|
/**
|
|
332
|
-
* The
|
|
398
|
+
* The event bus component.
|
|
333
399
|
* @internal
|
|
334
400
|
*/
|
|
335
|
-
|
|
401
|
+
_eventBusComponent;
|
|
336
402
|
/**
|
|
337
|
-
* The
|
|
403
|
+
* The verification method id to use for the proofs.
|
|
338
404
|
* @internal
|
|
339
405
|
*/
|
|
340
|
-
|
|
406
|
+
_verificationMethodId;
|
|
341
407
|
/**
|
|
342
|
-
*
|
|
408
|
+
* The identity connector type.
|
|
343
409
|
* @internal
|
|
344
410
|
*/
|
|
345
|
-
|
|
411
|
+
_identityConnectorType;
|
|
346
412
|
/**
|
|
347
413
|
* Create a new instance of ImmutableProofService.
|
|
348
414
|
* @param options The dependencies for the immutable proof connector.
|
|
349
|
-
* @param options.config The configuration for the connector.
|
|
350
|
-
* @param options.vaultConnectorType The vault connector type, defaults to "vault".
|
|
351
|
-
* @param options.immutableProofEntityStorageType The entity storage for proofs, defaults to "immutable-proof".
|
|
352
|
-
* @param options.immutableStorageType The immutable storage, defaults to "immutable-storage".
|
|
353
|
-
* @param options.identityConnectorType The identity connector type, defaults to "identity".
|
|
354
415
|
*/
|
|
355
416
|
constructor(options) {
|
|
356
|
-
this._vaultConnector = VaultConnectorFactory.get(options?.vaultConnectorType ?? "vault");
|
|
357
417
|
this._proofStorage = EntityStorageConnectorFactory.get(options?.immutableProofEntityStorageType ?? StringHelper.kebabCase("ImmutableProof"));
|
|
358
|
-
this.
|
|
359
|
-
this.
|
|
418
|
+
this._verifiableStorage = VerifiableStorageConnectorFactory.get(options?.verifiableStorageType ?? "verifiable-storage");
|
|
419
|
+
this._identityConnectorType = options?.identityConnectorType ?? "identity";
|
|
420
|
+
this._identityConnector = IdentityConnectorFactory.get(this._identityConnectorType);
|
|
421
|
+
this._backgroundTaskConnector = BackgroundTaskConnectorFactory.get(options?.backgroundTaskConnectorType ?? "background-task");
|
|
422
|
+
if (Is.stringValue(options?.eventBusComponentType)) {
|
|
423
|
+
this._eventBusComponent = ComponentFactory.get(options.eventBusComponentType);
|
|
424
|
+
}
|
|
360
425
|
this._config = options?.config ?? {};
|
|
361
|
-
this.
|
|
362
|
-
this.
|
|
363
|
-
|
|
364
|
-
|
|
426
|
+
this._verificationMethodId = this._config.verificationMethodId ?? "immutable-proof-assertion";
|
|
427
|
+
this._backgroundTaskConnector.registerHandler("immutable-proof", "@twin.org/immutable-proof-task", "processProofTask", async (task) => {
|
|
428
|
+
await this.finaliseTask(task);
|
|
429
|
+
});
|
|
365
430
|
}
|
|
366
431
|
/**
|
|
367
|
-
* Create a new
|
|
368
|
-
* @param
|
|
432
|
+
* Create a new proof.
|
|
433
|
+
* @param document The document to create the proof for.
|
|
369
434
|
* @param userIdentity The identity to create the immutable proof operation with.
|
|
370
435
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
371
|
-
* @returns The id of the new
|
|
436
|
+
* @returns The id of the new proof.
|
|
372
437
|
*/
|
|
373
|
-
async create(
|
|
374
|
-
Guards.object(this.CLASS_NAME, "
|
|
438
|
+
async create(document, userIdentity, nodeIdentity) {
|
|
439
|
+
Guards.object(this.CLASS_NAME, "document", document);
|
|
375
440
|
Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
376
441
|
Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
377
442
|
try {
|
|
378
443
|
const validationFailures = [];
|
|
379
|
-
await JsonLdHelper.validate(
|
|
380
|
-
Validation.asValidationError(this.CLASS_NAME, "
|
|
444
|
+
await JsonLdHelper.validate(document, validationFailures);
|
|
445
|
+
Validation.asValidationError(this.CLASS_NAME, "document", validationFailures);
|
|
381
446
|
const id = Converter.bytesToHex(RandomHelper.generate(32), false);
|
|
382
447
|
const dateCreated = new Date(Date.now()).toISOString();
|
|
383
|
-
const proofObjectId = ObjectHelper.extractProperty(
|
|
384
|
-
|
|
448
|
+
const proofObjectId = ObjectHelper.extractProperty(document, ["@id", "id"], false);
|
|
449
|
+
// We don't want to store the whole document in the immutable proof, as this could be large
|
|
450
|
+
// and also reveal information that should not be stored in the proof so we hash the document
|
|
451
|
+
// and store the hash
|
|
452
|
+
const proofObjectHash = this.calculateDocumentHash(document);
|
|
385
453
|
const proofEntity = {
|
|
386
454
|
id,
|
|
387
455
|
nodeIdentity,
|
|
388
456
|
userIdentity,
|
|
389
457
|
dateCreated,
|
|
390
458
|
proofObjectId,
|
|
391
|
-
proofObjectHash
|
|
459
|
+
proofObjectHash
|
|
392
460
|
};
|
|
393
461
|
await this._proofStorage.set(proofEntity);
|
|
394
|
-
this.
|
|
462
|
+
const immutableProof = this.proofEntityToJsonLd(proofEntity);
|
|
463
|
+
const proofTaskPayload = {
|
|
464
|
+
proofId: id,
|
|
465
|
+
nodeIdentity,
|
|
466
|
+
identityConnectorType: this._identityConnectorType,
|
|
467
|
+
verificationMethodId: this._verificationMethodId,
|
|
468
|
+
document: immutableProof
|
|
469
|
+
};
|
|
470
|
+
await this._backgroundTaskConnector.create("immutable-proof", proofTaskPayload);
|
|
395
471
|
return new Urn(ImmutableProofService.NAMESPACE, id).toString();
|
|
396
472
|
}
|
|
397
473
|
catch (error) {
|
|
@@ -399,7 +475,7 @@ class ImmutableProofService {
|
|
|
399
475
|
}
|
|
400
476
|
}
|
|
401
477
|
/**
|
|
402
|
-
* Get
|
|
478
|
+
* Get a proof.
|
|
403
479
|
* @param id The id of the proof to get.
|
|
404
480
|
* @returns The proof.
|
|
405
481
|
* @throws NotFoundError if the proof is not found.
|
|
@@ -414,22 +490,20 @@ class ImmutableProofService {
|
|
|
414
490
|
});
|
|
415
491
|
}
|
|
416
492
|
try {
|
|
417
|
-
const { immutableProof } = await this.internalGet(id);
|
|
418
|
-
|
|
419
|
-
return compacted;
|
|
493
|
+
const { immutableProof } = await this.internalGet(id, false);
|
|
494
|
+
return JsonLdProcessor.compact(immutableProof, immutableProof["@context"]);
|
|
420
495
|
}
|
|
421
496
|
catch (error) {
|
|
422
497
|
throw new GeneralError(this.CLASS_NAME, "getFailed", undefined, error);
|
|
423
498
|
}
|
|
424
499
|
}
|
|
425
500
|
/**
|
|
426
|
-
* Verify
|
|
501
|
+
* Verify a proof.
|
|
427
502
|
* @param id The id of the proof to verify.
|
|
428
|
-
* @param proofObject The object to verify as JSON-LD.
|
|
429
503
|
* @returns The result of the verification and any failures.
|
|
430
504
|
* @throws NotFoundError if the proof is not found.
|
|
431
505
|
*/
|
|
432
|
-
async verify(id
|
|
506
|
+
async verify(id) {
|
|
433
507
|
Guards.stringValue(this.CLASS_NAME, "id", id);
|
|
434
508
|
const urnParsed = Urn.fromValidString(id);
|
|
435
509
|
if (urnParsed.namespaceIdentifier() !== ImmutableProofService.NAMESPACE) {
|
|
@@ -439,9 +513,9 @@ class ImmutableProofService {
|
|
|
439
513
|
});
|
|
440
514
|
}
|
|
441
515
|
try {
|
|
442
|
-
const { verified, failure } = await this.internalGet(id,
|
|
516
|
+
const { verified, failure } = await this.internalGet(id, true);
|
|
443
517
|
return {
|
|
444
|
-
"@context":
|
|
518
|
+
"@context": ImmutableProofContexts.ContextRoot,
|
|
445
519
|
type: ImmutableProofTypes.ImmutableProofVerification,
|
|
446
520
|
verified,
|
|
447
521
|
failure
|
|
@@ -452,13 +526,13 @@ class ImmutableProofService {
|
|
|
452
526
|
}
|
|
453
527
|
}
|
|
454
528
|
/**
|
|
455
|
-
* Remove the
|
|
529
|
+
* Remove the verifiable storage for the proof.
|
|
456
530
|
* @param id The id of the proof to remove the storage from.
|
|
457
531
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
458
532
|
* @returns Nothing.
|
|
459
533
|
* @throws NotFoundError if the proof is not found.
|
|
460
534
|
*/
|
|
461
|
-
async
|
|
535
|
+
async removeVerifiable(id, nodeIdentity) {
|
|
462
536
|
Guards.stringValue(this.CLASS_NAME, "id", id);
|
|
463
537
|
Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
464
538
|
const urnParsed = Urn.fromValidString(id);
|
|
@@ -474,14 +548,14 @@ class ImmutableProofService {
|
|
|
474
548
|
if (Is.empty(streamEntity)) {
|
|
475
549
|
throw new NotFoundError(this.CLASS_NAME, "proofNotFound", id);
|
|
476
550
|
}
|
|
477
|
-
if (Is.stringValue(streamEntity.
|
|
478
|
-
await this.
|
|
479
|
-
delete streamEntity.
|
|
551
|
+
if (Is.stringValue(streamEntity.verifiableStorageId)) {
|
|
552
|
+
await this._verifiableStorage.remove(nodeIdentity, streamEntity.verifiableStorageId);
|
|
553
|
+
delete streamEntity.verifiableStorageId;
|
|
480
554
|
await this._proofStorage.set(streamEntity);
|
|
481
555
|
}
|
|
482
556
|
}
|
|
483
557
|
catch (error) {
|
|
484
|
-
throw new GeneralError(this.CLASS_NAME, "
|
|
558
|
+
throw new GeneralError(this.CLASS_NAME, "removeVerifiableFailed", undefined, error);
|
|
485
559
|
}
|
|
486
560
|
}
|
|
487
561
|
/**
|
|
@@ -490,14 +564,8 @@ class ImmutableProofService {
|
|
|
490
564
|
* @returns The hash.
|
|
491
565
|
* @internal
|
|
492
566
|
*/
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
b2b.update(Converter.utf8ToBytes(id));
|
|
496
|
-
b2b.update(Converter.utf8ToBytes(dateCreated));
|
|
497
|
-
b2b.update(Converter.utf8ToBytes(nodeIdentity));
|
|
498
|
-
b2b.update(Converter.utf8ToBytes(userIdentity));
|
|
499
|
-
b2b.update(ObjectHelper.toBytes(proofObject));
|
|
500
|
-
return b2b.digest();
|
|
567
|
+
calculateDocumentHash(nodeObject) {
|
|
568
|
+
return `sha256:${Converter.bytesToBase64(Sha256.sum256(ObjectHelper.toBytes(JsonHelper.canonicalize(nodeObject))))}`;
|
|
501
569
|
}
|
|
502
570
|
/**
|
|
503
571
|
* Map the stream entity to a model.
|
|
@@ -505,99 +573,84 @@ class ImmutableProofService {
|
|
|
505
573
|
* @returns The model.
|
|
506
574
|
* @internal
|
|
507
575
|
*/
|
|
508
|
-
|
|
509
|
-
const
|
|
510
|
-
"@context": [
|
|
511
|
-
ImmutableProofTypes.ContextRoot,
|
|
512
|
-
SchemaOrgTypes.ContextRoot,
|
|
513
|
-
DidContexts.ContextVCDataIntegrity
|
|
514
|
-
],
|
|
576
|
+
proofEntityToJsonLd(proofEntity) {
|
|
577
|
+
const jsonLd = {
|
|
578
|
+
"@context": [ImmutableProofContexts.ContextRoot, ImmutableProofContexts.ContextRootCommon],
|
|
515
579
|
type: ImmutableProofTypes.ImmutableProof,
|
|
516
580
|
id: proofEntity.id,
|
|
581
|
+
nodeIdentity: proofEntity.nodeIdentity,
|
|
517
582
|
userIdentity: proofEntity.userIdentity,
|
|
518
583
|
proofObjectId: proofEntity.proofObjectId,
|
|
519
|
-
proofObjectHash: proofEntity.proofObjectHash
|
|
584
|
+
proofObjectHash: proofEntity.proofObjectHash,
|
|
585
|
+
verifiableStorageId: proofEntity.verifiableStorageId
|
|
520
586
|
};
|
|
521
|
-
return
|
|
587
|
+
return jsonLd;
|
|
522
588
|
}
|
|
523
589
|
/**
|
|
524
|
-
*
|
|
525
|
-
* @
|
|
590
|
+
* Process a proof.
|
|
591
|
+
* @param proofEntity The proof entity to process.
|
|
526
592
|
* @internal
|
|
527
593
|
*/
|
|
528
|
-
|
|
529
|
-
if (
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
value: undefined
|
|
546
|
-
}, [
|
|
547
|
-
{
|
|
548
|
-
property: "dateCreated",
|
|
549
|
-
sortDirection: SortDirection.Ascending
|
|
594
|
+
async finaliseTask(task) {
|
|
595
|
+
if (task.status === TaskStatus.Success && Is.object(task.payload) && Is.object(task.result)) {
|
|
596
|
+
const proofEntity = await this._proofStorage.get(task.payload.proofId);
|
|
597
|
+
if (Is.object(proofEntity)) {
|
|
598
|
+
const immutableProof = this.proofEntityToJsonLd(proofEntity);
|
|
599
|
+
// As we are adding the proof to the data we update its context
|
|
600
|
+
immutableProof["@context"] = JsonLdProcessor.combineContexts([ImmutableProofContexts.ContextRoot, ImmutableProofContexts.ContextRootCommon], task.result.proof["@context"]);
|
|
601
|
+
immutableProof.proof = task.result.proof;
|
|
602
|
+
ObjectHelper.propertyDelete(immutableProof.proof, "@context");
|
|
603
|
+
if (Is.stringValue(immutableProof.proof.created)) {
|
|
604
|
+
proofEntity.dateCreated = immutableProof.proof.created;
|
|
605
|
+
}
|
|
606
|
+
const compacted = await JsonLdProcessor.compact(immutableProof, immutableProof["@context"]);
|
|
607
|
+
const verifiableCreateResult = await this._verifiableStorage.create(proofEntity.nodeIdentity, ObjectHelper.toBytes(compacted));
|
|
608
|
+
proofEntity.verifiableStorageId = verifiableCreateResult.id;
|
|
609
|
+
await this._proofStorage.set(proofEntity);
|
|
610
|
+
await this._eventBusComponent?.publish(ImmutableProofTopics.ProofCreated, { id: new Urn(ImmutableProofService.NAMESPACE, task.payload.proofId).toString() });
|
|
550
611
|
}
|
|
551
|
-
], undefined, undefined, 2);
|
|
552
|
-
if (pendingProofs.entities.length > 0) {
|
|
553
|
-
const proofEntity = pendingProofs.entities[0];
|
|
554
|
-
const immutableProof = this.proofEntityToModel(proofEntity);
|
|
555
|
-
const hashData = await this.generateHashData(proofEntity.nodeIdentity, immutableProof);
|
|
556
|
-
immutableProof.proof = await this._identityConnector.createProof(proofEntity.nodeIdentity, `${proofEntity.nodeIdentity}#${this._assertionMethodId}`, hashData);
|
|
557
|
-
proofEntity.dateCreated = immutableProof.proof.created ?? new Date(Date.now()).toISOString();
|
|
558
|
-
const compacted = await JsonLdProcessor.compact(immutableProof, immutableProof["@context"]);
|
|
559
|
-
proofEntity.immutableStorageId = await this._immutableStorage.store(proofEntity.nodeIdentity, ObjectHelper.toBytes(compacted));
|
|
560
|
-
await this._proofStorage.set(proofEntity);
|
|
561
|
-
}
|
|
562
|
-
// If there are still remaining proofs, start the timer again
|
|
563
|
-
this._processing = false;
|
|
564
|
-
if (pendingProofs.entities.length > 1) {
|
|
565
|
-
this.startProcessingProofs();
|
|
566
612
|
}
|
|
567
613
|
}
|
|
568
614
|
/**
|
|
569
|
-
* Verify
|
|
615
|
+
* Verify a proof.
|
|
570
616
|
* @param id The id of the proof to verify.
|
|
571
|
-
* @param
|
|
617
|
+
* @param verify Validate the proof.
|
|
572
618
|
* @returns The result of the verification and any failures.
|
|
573
619
|
* @throws NotFoundError if the proof is not found.
|
|
574
620
|
* @internal
|
|
575
621
|
*/
|
|
576
|
-
async internalGet(id,
|
|
622
|
+
async internalGet(id, verify) {
|
|
577
623
|
const urnParsed = Urn.fromValidString(id);
|
|
578
624
|
const proofId = urnParsed.namespaceSpecific(0);
|
|
579
625
|
const proofEntity = await this._proofStorage.get(proofId);
|
|
580
626
|
if (Is.empty(proofEntity)) {
|
|
581
627
|
throw new NotFoundError(this.CLASS_NAME, "proofNotFound", id);
|
|
582
628
|
}
|
|
583
|
-
let
|
|
629
|
+
let proofJsonLd = this.proofEntityToJsonLd(proofEntity);
|
|
584
630
|
let verified = false;
|
|
585
631
|
let failure = ImmutableProofFailure.NotIssued;
|
|
586
|
-
if (Is.stringValue(proofEntity.
|
|
632
|
+
if (Is.stringValue(proofEntity.verifiableStorageId)) {
|
|
587
633
|
failure = ImmutableProofFailure.ProofMissing;
|
|
588
|
-
const
|
|
589
|
-
if (Is.uint8Array(
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
634
|
+
const immutableResult = await this._verifiableStorage.get(proofEntity.verifiableStorageId);
|
|
635
|
+
if (Is.uint8Array(immutableResult.data)) {
|
|
636
|
+
proofJsonLd = ObjectHelper.fromBytes(immutableResult.data);
|
|
637
|
+
const unsecureDocument = ObjectHelper.clone(proofJsonLd);
|
|
638
|
+
proofJsonLd.immutableReceipt = immutableResult.receipt;
|
|
639
|
+
proofJsonLd.verifiableStorageId = proofEntity.verifiableStorageId;
|
|
640
|
+
// As we are adding the receipt to the data we update the JSON-LD context
|
|
641
|
+
const receiptContext = immutableResult.receipt["@context"];
|
|
642
|
+
if (!Is.empty(receiptContext)) {
|
|
643
|
+
proofJsonLd["@context"] = JsonLdProcessor.combineContexts(proofJsonLd["@context"], receiptContext);
|
|
644
|
+
}
|
|
645
|
+
if (verify && Is.object(proofJsonLd.proof)) {
|
|
646
|
+
if (proofJsonLd.proof.cryptosuite !== DidCryptoSuites.EdDSAJcs2022) {
|
|
593
647
|
failure = ImmutableProofFailure.CryptoSuiteMismatch;
|
|
594
648
|
}
|
|
595
|
-
else if (
|
|
649
|
+
else if (proofJsonLd.proof.type !== ProofTypes.DataIntegrityProof) {
|
|
596
650
|
failure = ImmutableProofFailure.ProofTypeMismatch;
|
|
597
651
|
}
|
|
598
652
|
else {
|
|
599
|
-
const
|
|
600
|
-
const isVerified = await this._identityConnector.verifyProof(hashData, proofModel.proof);
|
|
653
|
+
const isVerified = await this._identityConnector.verifyProof(unsecureDocument, proofJsonLd.proof);
|
|
601
654
|
if (isVerified) {
|
|
602
655
|
verified = true;
|
|
603
656
|
failure = undefined;
|
|
@@ -610,98 +663,13 @@ class ImmutableProofService {
|
|
|
610
663
|
}
|
|
611
664
|
}
|
|
612
665
|
return {
|
|
613
|
-
immutableProof:
|
|
666
|
+
immutableProof: proofJsonLd,
|
|
614
667
|
verified,
|
|
615
668
|
failure
|
|
616
669
|
};
|
|
617
670
|
}
|
|
618
|
-
/**
|
|
619
|
-
* Generate the hash data for the proof.
|
|
620
|
-
* Conforms to https://www.w3.org/TR/vc-di-eddsa/#create-proof-eddsa-jcs-2022
|
|
621
|
-
* @param nodeIdentity The node identity to use for vault operations.
|
|
622
|
-
* @param immutableProof The immutable proof to generate the hash data for.
|
|
623
|
-
* @returns The hash data.
|
|
624
|
-
* @internal
|
|
625
|
-
*/
|
|
626
|
-
async generateHashData(nodeIdentity, immutableProof) {
|
|
627
|
-
const canonicalDocument = JsonHelper.canonicalize(ObjectHelper.omit(immutableProof, ["proof"]));
|
|
628
|
-
const proofConfigKey = await this._vaultConnector.getKey(`${nodeIdentity}/${this._proofConfigKeyId}`);
|
|
629
|
-
const proofConfigHash = Sha256.sum256(proofConfigKey.privateKey);
|
|
630
|
-
const transformedDocumentHash = Sha256.sum256(Converter.utf8ToBytes(canonicalDocument));
|
|
631
|
-
const hashData = new Uint8Array(proofConfigHash.length + transformedDocumentHash.length);
|
|
632
|
-
hashData.set(proofConfigHash);
|
|
633
|
-
hashData.set(transformedDocumentHash, proofConfigHash.length);
|
|
634
|
-
return hashData;
|
|
635
|
-
}
|
|
636
671
|
}
|
|
637
672
|
|
|
638
|
-
// Copyright 2024 IOTA Stiftung.
|
|
639
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
640
|
-
/**
|
|
641
|
-
* Class describing the immutable proof.
|
|
642
|
-
*/
|
|
643
|
-
let ImmutableProof = class ImmutableProof {
|
|
644
|
-
/**
|
|
645
|
-
* The id of the proof.
|
|
646
|
-
*/
|
|
647
|
-
id;
|
|
648
|
-
/**
|
|
649
|
-
* The identity of the node which controls the proof.
|
|
650
|
-
*/
|
|
651
|
-
nodeIdentity;
|
|
652
|
-
/**
|
|
653
|
-
* The identity of the user which created the proof.
|
|
654
|
-
*/
|
|
655
|
-
userIdentity;
|
|
656
|
-
/**
|
|
657
|
-
* The date/time of when the proof was created.
|
|
658
|
-
*/
|
|
659
|
-
dateCreated;
|
|
660
|
-
/**
|
|
661
|
-
* The associated id for the item.
|
|
662
|
-
*/
|
|
663
|
-
proofObjectId;
|
|
664
|
-
/**
|
|
665
|
-
* The associated hash for the item.
|
|
666
|
-
*/
|
|
667
|
-
proofObjectHash;
|
|
668
|
-
/**
|
|
669
|
-
* The immutable storage id.
|
|
670
|
-
*/
|
|
671
|
-
immutableStorageId;
|
|
672
|
-
};
|
|
673
|
-
__decorate([
|
|
674
|
-
property({ type: "string", isPrimary: true }),
|
|
675
|
-
__metadata("design:type", String)
|
|
676
|
-
], ImmutableProof.prototype, "id", void 0);
|
|
677
|
-
__decorate([
|
|
678
|
-
property({ type: "string" }),
|
|
679
|
-
__metadata("design:type", String)
|
|
680
|
-
], ImmutableProof.prototype, "nodeIdentity", void 0);
|
|
681
|
-
__decorate([
|
|
682
|
-
property({ type: "string" }),
|
|
683
|
-
__metadata("design:type", String)
|
|
684
|
-
], ImmutableProof.prototype, "userIdentity", void 0);
|
|
685
|
-
__decorate([
|
|
686
|
-
property({ type: "string", format: "date-time", sortDirection: SortDirection.Descending }),
|
|
687
|
-
__metadata("design:type", String)
|
|
688
|
-
], ImmutableProof.prototype, "dateCreated", void 0);
|
|
689
|
-
__decorate([
|
|
690
|
-
property({ type: "string" }),
|
|
691
|
-
__metadata("design:type", String)
|
|
692
|
-
], ImmutableProof.prototype, "proofObjectId", void 0);
|
|
693
|
-
__decorate([
|
|
694
|
-
property({ type: "string" }),
|
|
695
|
-
__metadata("design:type", String)
|
|
696
|
-
], ImmutableProof.prototype, "proofObjectHash", void 0);
|
|
697
|
-
__decorate([
|
|
698
|
-
property({ type: "string" }),
|
|
699
|
-
__metadata("design:type", String)
|
|
700
|
-
], ImmutableProof.prototype, "immutableStorageId", void 0);
|
|
701
|
-
ImmutableProof = __decorate([
|
|
702
|
-
entity()
|
|
703
|
-
], ImmutableProof);
|
|
704
|
-
|
|
705
673
|
const restEntryPoints = [
|
|
706
674
|
{
|
|
707
675
|
name: "immutable-proof",
|