@twin.org/immutable-proof-service 0.0.1-next.9 → 0.0.2-next.1
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 +202 -216
- package/dist/esm/index.mjs +207 -221
- package/dist/types/entities/immutableProof.d.ts +2 -2
- package/dist/types/immutableProofService.d.ts +11 -29
- package/dist/types/index.d.ts +2 -1
- package/dist/types/models/IImmutableProofServiceConfig.d.ts +2 -7
- package/dist/types/models/IImmutableProofServiceConstructorOptions.d.ts +34 -0
- package/docs/changelog.md +115 -1
- package/docs/open-api/spec.json +711 -732
- package/docs/reference/classes/ImmutableProof.md +6 -6
- package/docs/reference/classes/ImmutableProofService.md +38 -58
- 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 +3 -17
- package/docs/reference/interfaces/IImmutableProofServiceConstructorOptions.md +75 -0
- package/locales/en.json +1 -1
- package/package.json +8 -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 { BackgroundTaskConnectorFactory } from '@twin.org/background-task-models';
|
|
6
|
-
import {
|
|
6
|
+
import { BackgroundTaskConnectorFactory, TaskStatus } from '@twin.org/background-task-models';
|
|
7
|
+
import { Sha256 } from '@twin.org/crypto';
|
|
7
8
|
import { JsonLdHelper, JsonLdProcessor } from '@twin.org/data-json-ld';
|
|
8
9
|
import { EntityStorageConnectorFactory } from '@twin.org/entity-storage-models';
|
|
9
10
|
import { IdentityConnectorFactory } from '@twin.org/identity-models';
|
|
10
|
-
import {
|
|
11
|
-
|
|
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
|
|
@@ -297,8 +363,9 @@ async function immutableProofVerify(httpRequestContext, componentName, request)
|
|
|
297
363
|
class ImmutableProofService {
|
|
298
364
|
/**
|
|
299
365
|
* The namespace for the service.
|
|
366
|
+
* @internal
|
|
300
367
|
*/
|
|
301
|
-
static
|
|
368
|
+
static _NAMESPACE = "immutable-proof";
|
|
302
369
|
/**
|
|
303
370
|
* Runtime name for the class.
|
|
304
371
|
*/
|
|
@@ -308,11 +375,6 @@ class ImmutableProofService {
|
|
|
308
375
|
* @internal
|
|
309
376
|
*/
|
|
310
377
|
_config;
|
|
311
|
-
/**
|
|
312
|
-
* The vault connector.
|
|
313
|
-
* @internal
|
|
314
|
-
*/
|
|
315
|
-
_vaultConnector;
|
|
316
378
|
/**
|
|
317
379
|
* The identity connector.
|
|
318
380
|
* @internal
|
|
@@ -324,83 +386,97 @@ class ImmutableProofService {
|
|
|
324
386
|
*/
|
|
325
387
|
_proofStorage;
|
|
326
388
|
/**
|
|
327
|
-
* The
|
|
389
|
+
* The verifiable storage for the credentials.
|
|
328
390
|
* @internal
|
|
329
391
|
*/
|
|
330
|
-
|
|
392
|
+
_verifiableStorage;
|
|
331
393
|
/**
|
|
332
394
|
* The background task connector.
|
|
333
395
|
* @internal
|
|
334
396
|
*/
|
|
335
397
|
_backgroundTaskConnector;
|
|
336
398
|
/**
|
|
337
|
-
* The
|
|
399
|
+
* The event bus component.
|
|
338
400
|
* @internal
|
|
339
401
|
*/
|
|
340
|
-
|
|
402
|
+
_eventBusComponent;
|
|
341
403
|
/**
|
|
342
|
-
* The
|
|
404
|
+
* The verification method id to use for the proofs.
|
|
343
405
|
* @internal
|
|
344
406
|
*/
|
|
345
|
-
|
|
407
|
+
_verificationMethodId;
|
|
408
|
+
/**
|
|
409
|
+
* The identity connector type.
|
|
410
|
+
* @internal
|
|
411
|
+
*/
|
|
412
|
+
_identityConnectorType;
|
|
346
413
|
/**
|
|
347
414
|
* Create a new instance of ImmutableProofService.
|
|
348
415
|
* @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
|
-
* @param options.backgroundTaskConnectorType The background task connector type, defaults to "background-task".
|
|
355
416
|
*/
|
|
356
417
|
constructor(options) {
|
|
357
|
-
this._vaultConnector = VaultConnectorFactory.get(options?.vaultConnectorType ?? "vault");
|
|
358
418
|
this._proofStorage = EntityStorageConnectorFactory.get(options?.immutableProofEntityStorageType ?? StringHelper.kebabCase("ImmutableProof"));
|
|
359
|
-
this.
|
|
360
|
-
this.
|
|
419
|
+
this._verifiableStorage = VerifiableStorageConnectorFactory.get(options?.verifiableStorageType ?? "verifiable-storage");
|
|
420
|
+
this._identityConnectorType = options?.identityConnectorType ?? "identity";
|
|
421
|
+
this._identityConnector = IdentityConnectorFactory.get(this._identityConnectorType);
|
|
361
422
|
this._backgroundTaskConnector = BackgroundTaskConnectorFactory.get(options?.backgroundTaskConnectorType ?? "background-task");
|
|
423
|
+
if (Is.stringValue(options?.eventBusComponentType)) {
|
|
424
|
+
this._eventBusComponent = ComponentFactory.get(options.eventBusComponentType);
|
|
425
|
+
}
|
|
362
426
|
this._config = options?.config ?? {};
|
|
363
|
-
this.
|
|
364
|
-
this.
|
|
365
|
-
|
|
427
|
+
this._verificationMethodId = this._config.verificationMethodId ?? "immutable-proof-assertion";
|
|
428
|
+
this._backgroundTaskConnector.registerHandler("immutable-proof", "@twin.org/immutable-proof-task", "processProofTask", async (task) => {
|
|
429
|
+
await this.finaliseTask(task);
|
|
430
|
+
});
|
|
366
431
|
}
|
|
367
432
|
/**
|
|
368
|
-
* Create a new
|
|
369
|
-
* @param
|
|
433
|
+
* Create a new proof.
|
|
434
|
+
* @param document The document to create the proof for.
|
|
370
435
|
* @param userIdentity The identity to create the immutable proof operation with.
|
|
371
436
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
372
|
-
* @returns The id of the new
|
|
437
|
+
* @returns The id of the new proof.
|
|
373
438
|
*/
|
|
374
|
-
async create(
|
|
375
|
-
Guards.object(this.CLASS_NAME, "
|
|
439
|
+
async create(document, userIdentity, nodeIdentity) {
|
|
440
|
+
Guards.object(this.CLASS_NAME, "document", document);
|
|
376
441
|
Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
377
442
|
Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
378
443
|
try {
|
|
379
444
|
const validationFailures = [];
|
|
380
|
-
await JsonLdHelper.validate(
|
|
381
|
-
Validation.asValidationError(this.CLASS_NAME, "
|
|
445
|
+
await JsonLdHelper.validate(document, validationFailures);
|
|
446
|
+
Validation.asValidationError(this.CLASS_NAME, "document", validationFailures);
|
|
382
447
|
const id = Converter.bytesToHex(RandomHelper.generate(32), false);
|
|
383
448
|
const dateCreated = new Date(Date.now()).toISOString();
|
|
384
|
-
const proofObjectId = ObjectHelper.extractProperty(
|
|
385
|
-
|
|
449
|
+
const proofObjectId = ObjectHelper.extractProperty(document, ["@id", "id"], false);
|
|
450
|
+
// We don't want to store the whole document in the immutable proof, as this could be large
|
|
451
|
+
// and also reveal information that should not be stored in the proof so we hash the document
|
|
452
|
+
// and store the hash
|
|
453
|
+
const proofObjectHash = this.calculateDocumentHash(document);
|
|
386
454
|
const proofEntity = {
|
|
387
455
|
id,
|
|
388
456
|
nodeIdentity,
|
|
389
457
|
userIdentity,
|
|
390
458
|
dateCreated,
|
|
391
459
|
proofObjectId,
|
|
392
|
-
proofObjectHash
|
|
460
|
+
proofObjectHash
|
|
393
461
|
};
|
|
394
462
|
await this._proofStorage.set(proofEntity);
|
|
395
|
-
|
|
396
|
-
|
|
463
|
+
const immutableProof = this.proofEntityToJsonLd(proofEntity);
|
|
464
|
+
const proofTaskPayload = {
|
|
465
|
+
proofId: id,
|
|
466
|
+
nodeIdentity,
|
|
467
|
+
identityConnectorType: this._identityConnectorType,
|
|
468
|
+
verificationMethodId: this._verificationMethodId,
|
|
469
|
+
document: immutableProof
|
|
470
|
+
};
|
|
471
|
+
await this._backgroundTaskConnector.create("immutable-proof", proofTaskPayload);
|
|
472
|
+
return new Urn(ImmutableProofService._NAMESPACE, id).toString();
|
|
397
473
|
}
|
|
398
474
|
catch (error) {
|
|
399
475
|
throw new GeneralError(this.CLASS_NAME, "createFailed", undefined, error);
|
|
400
476
|
}
|
|
401
477
|
}
|
|
402
478
|
/**
|
|
403
|
-
* Get
|
|
479
|
+
* Get a proof.
|
|
404
480
|
* @param id The id of the proof to get.
|
|
405
481
|
* @returns The proof.
|
|
406
482
|
* @throws NotFoundError if the proof is not found.
|
|
@@ -408,41 +484,39 @@ class ImmutableProofService {
|
|
|
408
484
|
async get(id) {
|
|
409
485
|
Guards.stringValue(this.CLASS_NAME, "id", id);
|
|
410
486
|
const urnParsed = Urn.fromValidString(id);
|
|
411
|
-
if (urnParsed.namespaceIdentifier() !== ImmutableProofService.
|
|
487
|
+
if (urnParsed.namespaceIdentifier() !== ImmutableProofService._NAMESPACE) {
|
|
412
488
|
throw new GeneralError(this.CLASS_NAME, "namespaceMismatch", {
|
|
413
|
-
namespace: ImmutableProofService.
|
|
489
|
+
namespace: ImmutableProofService._NAMESPACE,
|
|
414
490
|
id
|
|
415
491
|
});
|
|
416
492
|
}
|
|
417
493
|
try {
|
|
418
|
-
const { immutableProof } = await this.internalGet(id);
|
|
419
|
-
|
|
420
|
-
return compacted;
|
|
494
|
+
const { immutableProof } = await this.internalGet(id, false);
|
|
495
|
+
return JsonLdProcessor.compact(immutableProof, immutableProof["@context"]);
|
|
421
496
|
}
|
|
422
497
|
catch (error) {
|
|
423
498
|
throw new GeneralError(this.CLASS_NAME, "getFailed", undefined, error);
|
|
424
499
|
}
|
|
425
500
|
}
|
|
426
501
|
/**
|
|
427
|
-
* Verify
|
|
502
|
+
* Verify a proof.
|
|
428
503
|
* @param id The id of the proof to verify.
|
|
429
|
-
* @param proofObject The object to verify as JSON-LD.
|
|
430
504
|
* @returns The result of the verification and any failures.
|
|
431
505
|
* @throws NotFoundError if the proof is not found.
|
|
432
506
|
*/
|
|
433
|
-
async verify(id
|
|
507
|
+
async verify(id) {
|
|
434
508
|
Guards.stringValue(this.CLASS_NAME, "id", id);
|
|
435
509
|
const urnParsed = Urn.fromValidString(id);
|
|
436
|
-
if (urnParsed.namespaceIdentifier() !== ImmutableProofService.
|
|
510
|
+
if (urnParsed.namespaceIdentifier() !== ImmutableProofService._NAMESPACE) {
|
|
437
511
|
throw new GeneralError(this.CLASS_NAME, "namespaceMismatch", {
|
|
438
|
-
namespace: ImmutableProofService.
|
|
512
|
+
namespace: ImmutableProofService._NAMESPACE,
|
|
439
513
|
id
|
|
440
514
|
});
|
|
441
515
|
}
|
|
442
516
|
try {
|
|
443
|
-
const { verified, failure } = await this.internalGet(id,
|
|
517
|
+
const { verified, failure } = await this.internalGet(id, true);
|
|
444
518
|
return {
|
|
445
|
-
"@context":
|
|
519
|
+
"@context": ImmutableProofContexts.ContextRoot,
|
|
446
520
|
type: ImmutableProofTypes.ImmutableProofVerification,
|
|
447
521
|
verified,
|
|
448
522
|
failure
|
|
@@ -453,19 +527,19 @@ class ImmutableProofService {
|
|
|
453
527
|
}
|
|
454
528
|
}
|
|
455
529
|
/**
|
|
456
|
-
* Remove the
|
|
530
|
+
* Remove the verifiable storage for the proof.
|
|
457
531
|
* @param id The id of the proof to remove the storage from.
|
|
458
532
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
459
533
|
* @returns Nothing.
|
|
460
534
|
* @throws NotFoundError if the proof is not found.
|
|
461
535
|
*/
|
|
462
|
-
async
|
|
536
|
+
async removeVerifiable(id, nodeIdentity) {
|
|
463
537
|
Guards.stringValue(this.CLASS_NAME, "id", id);
|
|
464
538
|
Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
465
539
|
const urnParsed = Urn.fromValidString(id);
|
|
466
|
-
if (urnParsed.namespaceIdentifier() !== ImmutableProofService.
|
|
540
|
+
if (urnParsed.namespaceIdentifier() !== ImmutableProofService._NAMESPACE) {
|
|
467
541
|
throw new GeneralError(this.CLASS_NAME, "namespaceMismatch", {
|
|
468
|
-
namespace: ImmutableProofService.
|
|
542
|
+
namespace: ImmutableProofService._NAMESPACE,
|
|
469
543
|
id
|
|
470
544
|
});
|
|
471
545
|
}
|
|
@@ -475,14 +549,14 @@ class ImmutableProofService {
|
|
|
475
549
|
if (Is.empty(streamEntity)) {
|
|
476
550
|
throw new NotFoundError(this.CLASS_NAME, "proofNotFound", id);
|
|
477
551
|
}
|
|
478
|
-
if (Is.stringValue(streamEntity.
|
|
479
|
-
await this.
|
|
480
|
-
delete streamEntity.
|
|
552
|
+
if (Is.stringValue(streamEntity.verifiableStorageId)) {
|
|
553
|
+
await this._verifiableStorage.remove(nodeIdentity, streamEntity.verifiableStorageId);
|
|
554
|
+
delete streamEntity.verifiableStorageId;
|
|
481
555
|
await this._proofStorage.set(streamEntity);
|
|
482
556
|
}
|
|
483
557
|
}
|
|
484
558
|
catch (error) {
|
|
485
|
-
throw new GeneralError(this.CLASS_NAME, "
|
|
559
|
+
throw new GeneralError(this.CLASS_NAME, "removeVerifiableFailed", undefined, error);
|
|
486
560
|
}
|
|
487
561
|
}
|
|
488
562
|
/**
|
|
@@ -491,14 +565,8 @@ class ImmutableProofService {
|
|
|
491
565
|
* @returns The hash.
|
|
492
566
|
* @internal
|
|
493
567
|
*/
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
b2b.update(Converter.utf8ToBytes(id));
|
|
497
|
-
b2b.update(Converter.utf8ToBytes(dateCreated));
|
|
498
|
-
b2b.update(Converter.utf8ToBytes(nodeIdentity));
|
|
499
|
-
b2b.update(Converter.utf8ToBytes(userIdentity));
|
|
500
|
-
b2b.update(ObjectHelper.toBytes(proofObject));
|
|
501
|
-
return b2b.digest();
|
|
568
|
+
calculateDocumentHash(nodeObject) {
|
|
569
|
+
return `sha256:${Converter.bytesToBase64(Sha256.sum256(ObjectHelper.toBytes(JsonHelper.canonicalize(nodeObject))))}`;
|
|
502
570
|
}
|
|
503
571
|
/**
|
|
504
572
|
* Map the stream entity to a model.
|
|
@@ -507,76 +575,83 @@ class ImmutableProofService {
|
|
|
507
575
|
* @internal
|
|
508
576
|
*/
|
|
509
577
|
proofEntityToJsonLd(proofEntity) {
|
|
510
|
-
const
|
|
511
|
-
"@context":
|
|
578
|
+
const jsonLd = {
|
|
579
|
+
"@context": [ImmutableProofContexts.ContextRoot, ImmutableProofContexts.ContextRootCommon],
|
|
512
580
|
type: ImmutableProofTypes.ImmutableProof,
|
|
513
581
|
id: proofEntity.id,
|
|
582
|
+
nodeIdentity: proofEntity.nodeIdentity,
|
|
514
583
|
userIdentity: proofEntity.userIdentity,
|
|
515
584
|
proofObjectId: proofEntity.proofObjectId,
|
|
516
|
-
proofObjectHash: proofEntity.proofObjectHash
|
|
585
|
+
proofObjectHash: proofEntity.proofObjectHash,
|
|
586
|
+
verifiableStorageId: proofEntity.verifiableStorageId
|
|
517
587
|
};
|
|
518
|
-
return
|
|
588
|
+
return jsonLd;
|
|
519
589
|
}
|
|
520
590
|
/**
|
|
521
591
|
* Process a proof.
|
|
522
592
|
* @param proofEntity The proof entity to process.
|
|
523
593
|
* @internal
|
|
524
594
|
*/
|
|
525
|
-
async
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
595
|
+
async finaliseTask(task) {
|
|
596
|
+
if (task.status === TaskStatus.Success && Is.object(task.payload) && Is.object(task.result)) {
|
|
597
|
+
const proofEntity = await this._proofStorage.get(task.payload.proofId);
|
|
598
|
+
if (Is.object(proofEntity)) {
|
|
599
|
+
const immutableProof = this.proofEntityToJsonLd(proofEntity);
|
|
600
|
+
// As we are adding the proof to the data we update its context
|
|
601
|
+
immutableProof["@context"] = JsonLdProcessor.combineContexts([ImmutableProofContexts.ContextRoot, ImmutableProofContexts.ContextRootCommon], task.result.proof["@context"]);
|
|
602
|
+
immutableProof.proof = task.result.proof;
|
|
603
|
+
ObjectHelper.propertyDelete(immutableProof.proof, "@context");
|
|
604
|
+
if (Is.stringValue(immutableProof.proof.created)) {
|
|
605
|
+
proofEntity.dateCreated = immutableProof.proof.created;
|
|
606
|
+
}
|
|
607
|
+
const compacted = await JsonLdProcessor.compact(immutableProof, immutableProof["@context"]);
|
|
608
|
+
const verifiableCreateResult = await this._verifiableStorage.create(proofEntity.nodeIdentity, ObjectHelper.toBytes(compacted));
|
|
609
|
+
proofEntity.verifiableStorageId = verifiableCreateResult.id;
|
|
610
|
+
await this._proofStorage.set(proofEntity);
|
|
611
|
+
await this._eventBusComponent?.publish(ImmutableProofTopics.ProofCreated, { id: new Urn(ImmutableProofService._NAMESPACE, task.payload.proofId).toString() });
|
|
612
|
+
}
|
|
536
613
|
}
|
|
537
|
-
const compacted = await JsonLdProcessor.compact(immutableProof, immutableProof["@context"]);
|
|
538
|
-
const immutableStoreResult = await this._immutableStorage.store(proofEntity.nodeIdentity, ObjectHelper.toBytes(compacted));
|
|
539
|
-
proofEntity.immutableStorageId = immutableStoreResult.id;
|
|
540
|
-
await this._proofStorage.set(proofEntity);
|
|
541
614
|
}
|
|
542
615
|
/**
|
|
543
|
-
* Verify
|
|
616
|
+
* Verify a proof.
|
|
544
617
|
* @param id The id of the proof to verify.
|
|
545
|
-
* @param
|
|
618
|
+
* @param verify Validate the proof.
|
|
546
619
|
* @returns The result of the verification and any failures.
|
|
547
620
|
* @throws NotFoundError if the proof is not found.
|
|
548
621
|
* @internal
|
|
549
622
|
*/
|
|
550
|
-
async internalGet(id,
|
|
623
|
+
async internalGet(id, verify) {
|
|
551
624
|
const urnParsed = Urn.fromValidString(id);
|
|
552
625
|
const proofId = urnParsed.namespaceSpecific(0);
|
|
553
626
|
const proofEntity = await this._proofStorage.get(proofId);
|
|
554
627
|
if (Is.empty(proofEntity)) {
|
|
555
628
|
throw new NotFoundError(this.CLASS_NAME, "proofNotFound", id);
|
|
556
629
|
}
|
|
557
|
-
let
|
|
630
|
+
let proofJsonLd = this.proofEntityToJsonLd(proofEntity);
|
|
558
631
|
let verified = false;
|
|
559
632
|
let failure = ImmutableProofFailure.NotIssued;
|
|
560
|
-
if (Is.stringValue(proofEntity.
|
|
633
|
+
if (Is.stringValue(proofEntity.verifiableStorageId)) {
|
|
561
634
|
failure = ImmutableProofFailure.ProofMissing;
|
|
562
|
-
const immutableResult = await this.
|
|
635
|
+
const immutableResult = await this._verifiableStorage.get(proofEntity.verifiableStorageId);
|
|
563
636
|
if (Is.uint8Array(immutableResult.data)) {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
637
|
+
proofJsonLd = ObjectHelper.fromBytes(immutableResult.data);
|
|
638
|
+
const unsecureDocument = ObjectHelper.clone(proofJsonLd);
|
|
639
|
+
proofJsonLd.immutableReceipt = immutableResult.receipt;
|
|
640
|
+
proofJsonLd.verifiableStorageId = proofEntity.verifiableStorageId;
|
|
641
|
+
// As we are adding the receipt to the data we update the JSON-LD context
|
|
642
|
+
const receiptContext = immutableResult.receipt["@context"];
|
|
643
|
+
if (!Is.empty(receiptContext)) {
|
|
644
|
+
proofJsonLd["@context"] = JsonLdProcessor.combineContexts(proofJsonLd["@context"], receiptContext);
|
|
569
645
|
}
|
|
570
|
-
if (
|
|
571
|
-
if (
|
|
646
|
+
if (verify && Is.object(proofJsonLd.proof)) {
|
|
647
|
+
if (proofJsonLd.proof.cryptosuite !== DidCryptoSuites.EdDSAJcs2022) {
|
|
572
648
|
failure = ImmutableProofFailure.CryptoSuiteMismatch;
|
|
573
649
|
}
|
|
574
|
-
else if (
|
|
650
|
+
else if (proofJsonLd.proof.type !== ProofTypes.DataIntegrityProof) {
|
|
575
651
|
failure = ImmutableProofFailure.ProofTypeMismatch;
|
|
576
652
|
}
|
|
577
653
|
else {
|
|
578
|
-
const
|
|
579
|
-
const isVerified = await this._identityConnector.verifyProof(hashData, proofModel.proof);
|
|
654
|
+
const isVerified = await this._identityConnector.verifyProof(unsecureDocument, proofJsonLd.proof);
|
|
580
655
|
if (isVerified) {
|
|
581
656
|
verified = true;
|
|
582
657
|
failure = undefined;
|
|
@@ -589,102 +664,13 @@ class ImmutableProofService {
|
|
|
589
664
|
}
|
|
590
665
|
}
|
|
591
666
|
return {
|
|
592
|
-
immutableProof:
|
|
667
|
+
immutableProof: proofJsonLd,
|
|
593
668
|
verified,
|
|
594
669
|
failure
|
|
595
670
|
};
|
|
596
671
|
}
|
|
597
|
-
/**
|
|
598
|
-
* Generate the hash data for the proof.
|
|
599
|
-
* Conforms to https://www.w3.org/TR/vc-di-eddsa/#create-proof-eddsa-jcs-2022
|
|
600
|
-
* @param nodeIdentity The node identity to use for vault operations.
|
|
601
|
-
* @param immutableProof The immutable proof to generate the hash data for.
|
|
602
|
-
* @returns The hash data.
|
|
603
|
-
* @internal
|
|
604
|
-
*/
|
|
605
|
-
async generateHashData(nodeIdentity, immutableProof) {
|
|
606
|
-
// We hash the data for the proof without the the proof or immutable receipt for the proof
|
|
607
|
-
// without these objects we can simplify the context
|
|
608
|
-
const object = ObjectHelper.omit(immutableProof, ["proof", "immutableReceipt"]);
|
|
609
|
-
object["@context"] = ImmutableProofTypes.ContextRoot;
|
|
610
|
-
const canonicalDocument = JsonHelper.canonicalize(object);
|
|
611
|
-
const proofKey = await this._vaultConnector.getKey(`${nodeIdentity}/${this._proofHashKeyId}`);
|
|
612
|
-
const proofHash = Sha256.sum256(proofKey.privateKey);
|
|
613
|
-
const transformedDocumentHash = Sha256.sum256(Converter.utf8ToBytes(canonicalDocument));
|
|
614
|
-
const hashData = new Uint8Array(proofHash.length + transformedDocumentHash.length);
|
|
615
|
-
hashData.set(proofHash);
|
|
616
|
-
hashData.set(transformedDocumentHash, proofHash.length);
|
|
617
|
-
return hashData;
|
|
618
|
-
}
|
|
619
672
|
}
|
|
620
673
|
|
|
621
|
-
// Copyright 2024 IOTA Stiftung.
|
|
622
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
623
|
-
/**
|
|
624
|
-
* Class describing the immutable proof.
|
|
625
|
-
*/
|
|
626
|
-
let ImmutableProof = class ImmutableProof {
|
|
627
|
-
/**
|
|
628
|
-
* The id of the proof.
|
|
629
|
-
*/
|
|
630
|
-
id;
|
|
631
|
-
/**
|
|
632
|
-
* The identity of the node which controls the proof.
|
|
633
|
-
*/
|
|
634
|
-
nodeIdentity;
|
|
635
|
-
/**
|
|
636
|
-
* The identity of the user which created the proof.
|
|
637
|
-
*/
|
|
638
|
-
userIdentity;
|
|
639
|
-
/**
|
|
640
|
-
* The date/time of when the proof was created.
|
|
641
|
-
*/
|
|
642
|
-
dateCreated;
|
|
643
|
-
/**
|
|
644
|
-
* The associated id for the item.
|
|
645
|
-
*/
|
|
646
|
-
proofObjectId;
|
|
647
|
-
/**
|
|
648
|
-
* The associated hash for the item.
|
|
649
|
-
*/
|
|
650
|
-
proofObjectHash;
|
|
651
|
-
/**
|
|
652
|
-
* The immutable storage id.
|
|
653
|
-
*/
|
|
654
|
-
immutableStorageId;
|
|
655
|
-
};
|
|
656
|
-
__decorate([
|
|
657
|
-
property({ type: "string", isPrimary: true }),
|
|
658
|
-
__metadata("design:type", String)
|
|
659
|
-
], ImmutableProof.prototype, "id", void 0);
|
|
660
|
-
__decorate([
|
|
661
|
-
property({ type: "string" }),
|
|
662
|
-
__metadata("design:type", String)
|
|
663
|
-
], ImmutableProof.prototype, "nodeIdentity", void 0);
|
|
664
|
-
__decorate([
|
|
665
|
-
property({ type: "string" }),
|
|
666
|
-
__metadata("design:type", String)
|
|
667
|
-
], ImmutableProof.prototype, "userIdentity", void 0);
|
|
668
|
-
__decorate([
|
|
669
|
-
property({ type: "string", format: "date-time", sortDirection: SortDirection.Descending }),
|
|
670
|
-
__metadata("design:type", String)
|
|
671
|
-
], ImmutableProof.prototype, "dateCreated", void 0);
|
|
672
|
-
__decorate([
|
|
673
|
-
property({ type: "string" }),
|
|
674
|
-
__metadata("design:type", String)
|
|
675
|
-
], ImmutableProof.prototype, "proofObjectId", void 0);
|
|
676
|
-
__decorate([
|
|
677
|
-
property({ type: "string" }),
|
|
678
|
-
__metadata("design:type", String)
|
|
679
|
-
], ImmutableProof.prototype, "proofObjectHash", void 0);
|
|
680
|
-
__decorate([
|
|
681
|
-
property({ type: "string" }),
|
|
682
|
-
__metadata("design:type", String)
|
|
683
|
-
], ImmutableProof.prototype, "immutableStorageId", void 0);
|
|
684
|
-
ImmutableProof = __decorate([
|
|
685
|
-
entity()
|
|
686
|
-
], ImmutableProof);
|
|
687
|
-
|
|
688
674
|
const restEntryPoints = [
|
|
689
675
|
{
|
|
690
676
|
name: "immutable-proof",
|