@twin.org/identity-connector-entity-storage 0.0.1-next.5 → 0.0.1-next.51
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 +252 -201
- package/dist/esm/index.mjs +256 -206
- package/dist/types/entityStorageIdentityConnector.d.ts +24 -40
- package/dist/types/entityStorageIdentityProfileConnector.d.ts +4 -6
- package/dist/types/entityStorageIdentityResolverConnector.d.ts +28 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/models/IEntityStorageIdentityConnectorConstructorOptions.d.ts +6 -0
- package/dist/types/models/IEntityStorageIdentityProfileConnectorConstructorOptions.d.ts +10 -0
- package/dist/types/models/IEntityStorageIdentityResolverConnectorConstructorOptions.d.ts +15 -0
- package/docs/changelog.md +176 -1
- package/docs/reference/classes/EntityStorageIdentityConnector.md +144 -158
- package/docs/reference/classes/EntityStorageIdentityProfileConnector.md +67 -53
- package/docs/reference/classes/EntityStorageIdentityResolverConnector.md +77 -0
- package/docs/reference/classes/IdentityDocument.md +3 -3
- package/docs/reference/classes/IdentityProfile.md +3 -3
- package/docs/reference/functions/initSchema.md +8 -4
- package/docs/reference/index.md +7 -0
- package/docs/reference/interfaces/IEntityStorageIdentityConnectorConstructorOptions.md +43 -0
- package/docs/reference/interfaces/IEntityStorageIdentityProfileConnectorConstructorOptions.md +17 -0
- package/docs/reference/interfaces/IEntityStorageIdentityResolverConnectorConstructorOptions.md +35 -0
- package/locales/en.json +9 -4
- package/package.json +5 -5
package/dist/cjs/index.cjs
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
var entity = require('@twin.org/entity');
|
|
4
4
|
var core = require('@twin.org/core');
|
|
5
|
-
var crypto = require('@twin.org/crypto');
|
|
6
5
|
var dataJsonLd = require('@twin.org/data-json-ld');
|
|
7
6
|
var entityStorageModels = require('@twin.org/entity-storage-models');
|
|
8
7
|
var identityModels = require('@twin.org/identity-models');
|
|
@@ -77,11 +76,11 @@ __decorate([
|
|
|
77
76
|
__metadata("design:type", String)
|
|
78
77
|
], exports.IdentityProfile.prototype, "identity", void 0);
|
|
79
78
|
__decorate([
|
|
80
|
-
entity.property({ type: "object" }),
|
|
79
|
+
entity.property({ type: "object", optional: true }),
|
|
81
80
|
__metadata("design:type", Object)
|
|
82
81
|
], exports.IdentityProfile.prototype, "publicProfile", void 0);
|
|
83
82
|
__decorate([
|
|
84
|
-
entity.property({ type: "object" }),
|
|
83
|
+
entity.property({ type: "object", optional: true }),
|
|
85
84
|
__metadata("design:type", Object)
|
|
86
85
|
], exports.IdentityProfile.prototype, "privateProfile", void 0);
|
|
87
86
|
exports.IdentityProfile = __decorate([
|
|
@@ -119,14 +118,34 @@ class EntityStorageIdentityConnector {
|
|
|
119
118
|
_vaultConnector;
|
|
120
119
|
/**
|
|
121
120
|
* Create a new instance of EntityStorageIdentityConnector.
|
|
122
|
-
* @param options The
|
|
123
|
-
* @param options.didDocumentEntityStorageType The entity storage for the did documents, defaults to "identity-document".
|
|
124
|
-
* @param options.vaultConnectorType The vault for the private keys, defaults to "vault".
|
|
121
|
+
* @param options The options for the identity connector.
|
|
125
122
|
*/
|
|
126
123
|
constructor(options) {
|
|
127
124
|
this._didDocumentEntityStorage = entityStorageModels.EntityStorageConnectorFactory.get(options?.didDocumentEntityStorageType ?? "identity-document");
|
|
128
125
|
this._vaultConnector = vaultModels.VaultConnectorFactory.get(options?.vaultConnectorType ?? "vault");
|
|
129
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Build the key name to access the specified key in the vault.
|
|
129
|
+
* @param identity The identity of the user to access the vault keys.
|
|
130
|
+
* @returns The vault key.
|
|
131
|
+
* @internal
|
|
132
|
+
*/
|
|
133
|
+
static buildVaultKey(identity, key) {
|
|
134
|
+
return `${identity}/${key}`;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Verify the document in storage.
|
|
138
|
+
* @param didDocument The did document that was stored.
|
|
139
|
+
* @internal
|
|
140
|
+
*/
|
|
141
|
+
static async verifyDocument(didDocument, vaultConnector) {
|
|
142
|
+
const stringifiedDocument = core.JsonHelper.canonicalize(didDocument.document);
|
|
143
|
+
const docBytes = core.Converter.utf8ToBytes(stringifiedDocument);
|
|
144
|
+
const verified = await vaultConnector.verify(EntityStorageIdentityConnector.buildVaultKey(didDocument.id, "did"), docBytes, core.Converter.base64ToBytes(didDocument.signature));
|
|
145
|
+
if (!verified) {
|
|
146
|
+
throw new core.GeneralError("EntityStorageIdentityResolverConnector", "signatureVerificationFailed");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
130
149
|
/**
|
|
131
150
|
* Create a new document.
|
|
132
151
|
* @param controller The controller of the identity who can make changes.
|
|
@@ -136,10 +155,11 @@ class EntityStorageIdentityConnector {
|
|
|
136
155
|
core.Guards.stringValue(this.CLASS_NAME, "controller", controller);
|
|
137
156
|
try {
|
|
138
157
|
const did = `did:${EntityStorageIdentityConnector.NAMESPACE}:${core.Converter.bytesToHex(core.RandomHelper.generate(32), true)}`;
|
|
139
|
-
await this._vaultConnector.createKey(
|
|
158
|
+
await this._vaultConnector.createKey(EntityStorageIdentityConnector.buildVaultKey(did, "did"), vaultModels.VaultKeyType.Ed25519);
|
|
140
159
|
const bitString = new core.BitString(EntityStorageIdentityConnector._REVOCATION_BITS_SIZE);
|
|
141
160
|
const compressed = await core.Compression.compress(bitString.getBits(), core.CompressionType.Gzip);
|
|
142
161
|
const didDocument = {
|
|
162
|
+
"@context": standardsW3cDid.DidContexts.Context,
|
|
143
163
|
id: did,
|
|
144
164
|
service: [
|
|
145
165
|
{
|
|
@@ -156,26 +176,6 @@ class EntityStorageIdentityConnector {
|
|
|
156
176
|
throw new core.GeneralError(this.CLASS_NAME, "createDocumentFailed", undefined, error);
|
|
157
177
|
}
|
|
158
178
|
}
|
|
159
|
-
/**
|
|
160
|
-
* Resolve a document from its id.
|
|
161
|
-
* @param documentId The id of the document to resolve.
|
|
162
|
-
* @returns The resolved document.
|
|
163
|
-
* @throws NotFoundError if the id can not be resolved.
|
|
164
|
-
*/
|
|
165
|
-
async resolveDocument(documentId) {
|
|
166
|
-
core.Guards.stringValue(this.CLASS_NAME, "documentId", documentId);
|
|
167
|
-
try {
|
|
168
|
-
const didIdentityDocument = await this._didDocumentEntityStorage.get(documentId);
|
|
169
|
-
if (core.Is.undefined(didIdentityDocument)) {
|
|
170
|
-
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", documentId);
|
|
171
|
-
}
|
|
172
|
-
await this.verifyDocument(didIdentityDocument);
|
|
173
|
-
return didIdentityDocument.document;
|
|
174
|
-
}
|
|
175
|
-
catch (error) {
|
|
176
|
-
throw new core.GeneralError(this.CLASS_NAME, "resolveDocumentFailed", undefined, error);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
179
|
/**
|
|
180
180
|
* Add a verification method to the document in JSON Web key Format.
|
|
181
181
|
* @param controller The controller of the identity who can make changes.
|
|
@@ -195,19 +195,19 @@ class EntityStorageIdentityConnector {
|
|
|
195
195
|
if (core.Is.undefined(didIdentityDocument)) {
|
|
196
196
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", documentId);
|
|
197
197
|
}
|
|
198
|
-
await
|
|
198
|
+
await EntityStorageIdentityConnector.verifyDocument(didIdentityDocument, this._vaultConnector);
|
|
199
199
|
const didDocument = didIdentityDocument.document;
|
|
200
|
-
const tempKeyId = `temp-${core.Converter.bytesToBase64Url(core.RandomHelper.generate(
|
|
201
|
-
const verificationPublicKey = await this._vaultConnector.createKey(
|
|
200
|
+
const tempKeyId = `temp-vm-${core.Converter.bytesToBase64Url(core.RandomHelper.generate(16))}`;
|
|
201
|
+
const verificationPublicKey = await this._vaultConnector.createKey(EntityStorageIdentityConnector.buildVaultKey(didDocument.id, tempKeyId), vaultModels.VaultKeyType.Ed25519);
|
|
202
202
|
const jwkParams = {
|
|
203
203
|
alg: "EdDSA",
|
|
204
204
|
kty: "OKP",
|
|
205
205
|
crv: "Ed25519",
|
|
206
206
|
x: core.Converter.bytesToBase64Url(verificationPublicKey)
|
|
207
207
|
};
|
|
208
|
-
const kid =
|
|
208
|
+
const kid = await web.Jwk.generateKid(jwkParams);
|
|
209
209
|
const methodId = `${documentId}#${verificationMethodId ?? kid}`;
|
|
210
|
-
await this._vaultConnector.renameKey(
|
|
210
|
+
await this._vaultConnector.renameKey(EntityStorageIdentityConnector.buildVaultKey(didDocument.id, tempKeyId), EntityStorageIdentityConnector.buildVaultKey(didDocument.id, verificationMethodId ?? kid));
|
|
211
211
|
const methods = this.getAllMethods(didDocument);
|
|
212
212
|
const existingMethodIndex = methods.findIndex(m => {
|
|
213
213
|
if (core.Is.string(m.method)) {
|
|
@@ -215,7 +215,7 @@ class EntityStorageIdentityConnector {
|
|
|
215
215
|
}
|
|
216
216
|
return m.method.id === methodId;
|
|
217
217
|
});
|
|
218
|
-
if (existingMethodIndex
|
|
218
|
+
if (existingMethodIndex !== -1) {
|
|
219
219
|
const methodArray = didDocument[methods[existingMethodIndex].arrayKey];
|
|
220
220
|
if (core.Is.array(methodArray)) {
|
|
221
221
|
methodArray.splice(existingMethodIndex, 1);
|
|
@@ -251,15 +251,15 @@ class EntityStorageIdentityConnector {
|
|
|
251
251
|
core.Guards.stringValue(this.CLASS_NAME, "controller", controller);
|
|
252
252
|
core.Guards.stringValue(this.CLASS_NAME, "verificationMethodId", verificationMethodId);
|
|
253
253
|
try {
|
|
254
|
-
const idParts = identityModels.DocumentHelper.
|
|
255
|
-
if (core.Is.empty(idParts.
|
|
254
|
+
const idParts = identityModels.DocumentHelper.parseId(verificationMethodId);
|
|
255
|
+
if (core.Is.empty(idParts.fragment)) {
|
|
256
256
|
throw new core.NotFoundError(this.CLASS_NAME, "missingDid", verificationMethodId);
|
|
257
257
|
}
|
|
258
258
|
const didIdentityDocument = await this._didDocumentEntityStorage.get(idParts.id);
|
|
259
259
|
if (core.Is.undefined(didIdentityDocument)) {
|
|
260
260
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", idParts.id);
|
|
261
261
|
}
|
|
262
|
-
await
|
|
262
|
+
await EntityStorageIdentityConnector.verifyDocument(didIdentityDocument, this._vaultConnector);
|
|
263
263
|
const didDocument = didIdentityDocument.document;
|
|
264
264
|
const methods = this.getAllMethods(didDocument);
|
|
265
265
|
const existingMethodIndex = methods.findIndex(m => {
|
|
@@ -268,7 +268,7 @@ class EntityStorageIdentityConnector {
|
|
|
268
268
|
}
|
|
269
269
|
return m.method.id === verificationMethodId;
|
|
270
270
|
});
|
|
271
|
-
if (existingMethodIndex
|
|
271
|
+
if (existingMethodIndex !== -1) {
|
|
272
272
|
const methodArray = didDocument[methods[existingMethodIndex].arrayKey];
|
|
273
273
|
if (core.Is.array(methodArray)) {
|
|
274
274
|
methodArray.splice(existingMethodIndex, 1);
|
|
@@ -300,19 +300,29 @@ class EntityStorageIdentityConnector {
|
|
|
300
300
|
core.Guards.stringValue(this.CLASS_NAME, "controller", controller);
|
|
301
301
|
core.Guards.stringValue(this.CLASS_NAME, "documentId", documentId);
|
|
302
302
|
core.Guards.stringValue(this.CLASS_NAME, "serviceId", serviceId);
|
|
303
|
-
core.
|
|
304
|
-
|
|
303
|
+
if (core.Is.array(serviceType)) {
|
|
304
|
+
core.Guards.arrayValue(this.CLASS_NAME, "serviceType", serviceType);
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
core.Guards.stringValue(this.CLASS_NAME, "serviceType", serviceType);
|
|
308
|
+
}
|
|
309
|
+
if (core.Is.array(serviceEndpoint)) {
|
|
310
|
+
core.Guards.arrayValue(this.CLASS_NAME, "serviceEndpoint", serviceEndpoint);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
core.Guards.stringValue(this.CLASS_NAME, "serviceEndpoint", serviceEndpoint);
|
|
314
|
+
}
|
|
305
315
|
try {
|
|
306
316
|
const didIdentityDocument = await this._didDocumentEntityStorage.get(documentId);
|
|
307
317
|
if (core.Is.undefined(didIdentityDocument)) {
|
|
308
318
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", documentId);
|
|
309
319
|
}
|
|
310
|
-
await
|
|
320
|
+
await EntityStorageIdentityConnector.verifyDocument(didIdentityDocument, this._vaultConnector);
|
|
311
321
|
const didDocument = didIdentityDocument.document;
|
|
312
322
|
const fullServiceId = serviceId.includes("#") ? serviceId : `${documentId}#${serviceId}`;
|
|
313
323
|
if (core.Is.array(didDocument.service)) {
|
|
314
324
|
const existingServiceIndex = didDocument.service.findIndex(s => s.id === fullServiceId);
|
|
315
|
-
if (existingServiceIndex
|
|
325
|
+
if (existingServiceIndex !== -1) {
|
|
316
326
|
didDocument.service?.splice(existingServiceIndex, 1);
|
|
317
327
|
}
|
|
318
328
|
}
|
|
@@ -341,19 +351,19 @@ class EntityStorageIdentityConnector {
|
|
|
341
351
|
core.Guards.stringValue(this.CLASS_NAME, "controller", controller);
|
|
342
352
|
core.Guards.stringValue(this.CLASS_NAME, "serviceId", serviceId);
|
|
343
353
|
try {
|
|
344
|
-
const idParts = identityModels.DocumentHelper.
|
|
345
|
-
if (core.Is.empty(idParts.
|
|
354
|
+
const idParts = identityModels.DocumentHelper.parseId(serviceId);
|
|
355
|
+
if (core.Is.empty(idParts.fragment)) {
|
|
346
356
|
throw new core.NotFoundError(this.CLASS_NAME, "missingDid", serviceId);
|
|
347
357
|
}
|
|
348
358
|
const didIdentityDocument = await this._didDocumentEntityStorage.get(idParts.id);
|
|
349
359
|
if (core.Is.undefined(didIdentityDocument)) {
|
|
350
360
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", idParts.id);
|
|
351
361
|
}
|
|
352
|
-
await
|
|
362
|
+
await EntityStorageIdentityConnector.verifyDocument(didIdentityDocument, this._vaultConnector);
|
|
353
363
|
const didDocument = didIdentityDocument.document;
|
|
354
364
|
if (core.Is.array(didDocument.service)) {
|
|
355
365
|
const existingServiceIndex = didDocument.service.findIndex(s => s.id === serviceId);
|
|
356
|
-
if (existingServiceIndex
|
|
366
|
+
if (existingServiceIndex !== -1) {
|
|
357
367
|
didDocument.service?.splice(existingServiceIndex, 1);
|
|
358
368
|
if (didDocument.service?.length === 0) {
|
|
359
369
|
delete didDocument.service;
|
|
@@ -373,51 +383,29 @@ class EntityStorageIdentityConnector {
|
|
|
373
383
|
* Create a verifiable credential for a verification method.
|
|
374
384
|
* @param controller The controller of the identity who can make changes.
|
|
375
385
|
* @param verificationMethodId The verification method id to use.
|
|
376
|
-
* @param
|
|
377
|
-
* @param
|
|
378
|
-
* @param subject The subject data to store for the credential.
|
|
379
|
-
* @param contexts Additional contexts to include in the credential.
|
|
386
|
+
* @param id The id of the credential.
|
|
387
|
+
* @param subject The credential subject to store in the verifiable credential.
|
|
380
388
|
* @param revocationIndex The bitmap revocation index of the credential, if undefined will not have revocation status.
|
|
381
389
|
* @returns The created verifiable credential and its token.
|
|
382
390
|
* @throws NotFoundError if the id can not be resolved.
|
|
383
391
|
*/
|
|
384
|
-
async createVerifiableCredential(controller, verificationMethodId,
|
|
392
|
+
async createVerifiableCredential(controller, verificationMethodId, id, subject, revocationIndex) {
|
|
385
393
|
core.Guards.stringValue(this.CLASS_NAME, "controller", controller);
|
|
386
394
|
core.Guards.stringValue(this.CLASS_NAME, "verificationMethodId", verificationMethodId);
|
|
387
|
-
|
|
388
|
-
core.Guards.stringValue(this.CLASS_NAME, "credentialId", credentialId);
|
|
389
|
-
}
|
|
390
|
-
if (core.Is.array(types)) {
|
|
391
|
-
core.Guards.array(this.CLASS_NAME, "types", types);
|
|
392
|
-
}
|
|
393
|
-
else if (!core.Is.undefined(types)) {
|
|
394
|
-
core.Guards.stringValue(this.CLASS_NAME, "types", types);
|
|
395
|
-
}
|
|
396
|
-
if (core.Is.array(subject)) {
|
|
397
|
-
core.Guards.arrayValue(this.CLASS_NAME, "subject", subject);
|
|
398
|
-
}
|
|
399
|
-
else {
|
|
400
|
-
core.Guards.object(this.CLASS_NAME, "subject", subject);
|
|
401
|
-
}
|
|
402
|
-
if (core.Is.array(contexts)) {
|
|
403
|
-
core.Guards.array(this.CLASS_NAME, "contexts", contexts);
|
|
404
|
-
}
|
|
405
|
-
else if (!core.Is.undefined(contexts)) {
|
|
406
|
-
core.Guards.stringValue(this.CLASS_NAME, "contexts", contexts);
|
|
407
|
-
}
|
|
395
|
+
core.Guards.object(this.CLASS_NAME, "subject", subject);
|
|
408
396
|
if (!core.Is.undefined(revocationIndex)) {
|
|
409
397
|
core.Guards.number(this.CLASS_NAME, "revocationIndex", revocationIndex);
|
|
410
398
|
}
|
|
411
399
|
try {
|
|
412
|
-
const idParts = identityModels.DocumentHelper.
|
|
413
|
-
if (core.Is.empty(idParts.
|
|
400
|
+
const idParts = identityModels.DocumentHelper.parseId(verificationMethodId);
|
|
401
|
+
if (core.Is.empty(idParts.fragment)) {
|
|
414
402
|
throw new core.NotFoundError(this.CLASS_NAME, "missingDid", verificationMethodId);
|
|
415
403
|
}
|
|
416
404
|
const issuerIdentityDocument = await this._didDocumentEntityStorage.get(idParts.id);
|
|
417
405
|
if (core.Is.undefined(issuerIdentityDocument)) {
|
|
418
406
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", idParts.id);
|
|
419
407
|
}
|
|
420
|
-
await
|
|
408
|
+
await EntityStorageIdentityConnector.verifyDocument(issuerIdentityDocument, this._vaultConnector);
|
|
421
409
|
const issuerDidDocument = issuerIdentityDocument.document;
|
|
422
410
|
const methods = this.getAllMethods(issuerDidDocument);
|
|
423
411
|
const methodAndArray = methods.find(m => {
|
|
@@ -427,26 +415,30 @@ class EntityStorageIdentityConnector {
|
|
|
427
415
|
return m.method.id === verificationMethodId;
|
|
428
416
|
});
|
|
429
417
|
if (!methodAndArray) {
|
|
430
|
-
throw new core.GeneralError(this.CLASS_NAME, "methodMissing");
|
|
418
|
+
throw new core.GeneralError(this.CLASS_NAME, "methodMissing", { method: verificationMethodId });
|
|
431
419
|
}
|
|
432
420
|
const verificationDidMethod = methodAndArray.method;
|
|
433
421
|
if (!core.Is.stringValue(verificationDidMethod.publicKeyJwk?.x)) {
|
|
434
|
-
throw new core.GeneralError(this.CLASS_NAME, "publicKeyJwkMissing"
|
|
422
|
+
throw new core.GeneralError(this.CLASS_NAME, "publicKeyJwkMissing", {
|
|
423
|
+
method: verificationMethodId
|
|
424
|
+
});
|
|
435
425
|
}
|
|
436
426
|
const revocationService = issuerDidDocument.service?.find(s => s.id.endsWith("#revocation"));
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
427
|
+
const subjectClone = core.ObjectHelper.clone(subject);
|
|
428
|
+
const finalTypes = [standardsW3cDid.DidTypes.VerifiableCredential];
|
|
429
|
+
const credContext = core.ObjectHelper.extractProperty(subjectClone, [
|
|
430
|
+
"@context"
|
|
431
|
+
]);
|
|
432
|
+
const credId = core.ObjectHelper.extractProperty(subjectClone, ["@id", "id"], false);
|
|
433
|
+
const credType = core.ObjectHelper.extractProperty(subjectClone, ["@type", "type"]);
|
|
434
|
+
if (core.Is.stringValue(credType)) {
|
|
435
|
+
finalTypes.push(credType);
|
|
443
436
|
}
|
|
444
437
|
const verifiableCredential = {
|
|
445
|
-
"@context": dataJsonLd.JsonLdProcessor.combineContexts(
|
|
446
|
-
|
|
447
|
-
id: credentialId,
|
|
438
|
+
"@context": dataJsonLd.JsonLdProcessor.combineContexts(standardsW3cDid.DidContexts.ContextVCv2, credContext),
|
|
439
|
+
id,
|
|
448
440
|
type: finalTypes,
|
|
449
|
-
credentialSubject:
|
|
441
|
+
credentialSubject: subjectClone,
|
|
450
442
|
issuer: issuerDidDocument.id,
|
|
451
443
|
issuanceDate: new Date().toISOString(),
|
|
452
444
|
credentialStatus: revocationService && !core.Is.undefined(revocationIndex)
|
|
@@ -483,15 +475,10 @@ class EntityStorageIdentityConnector {
|
|
|
483
475
|
iss: idParts.id,
|
|
484
476
|
nbf: Math.floor(Date.now() / 1000),
|
|
485
477
|
jti: verifiableCredential.id,
|
|
486
|
-
sub:
|
|
487
|
-
? core.ObjectHelper.propertyGet(subject[0], "id")
|
|
488
|
-
: core.ObjectHelper.propertyGet(subject, "id"),
|
|
478
|
+
sub: credId,
|
|
489
479
|
vc: jwtVc
|
|
490
480
|
};
|
|
491
|
-
const signature = await web.Jwt.encodeWithSigner(jwtHeader, jwtPayload, async (
|
|
492
|
-
const sig = await this._vaultConnector.sign(this.buildVaultKey(idParts.id, verificationMethodId), payload);
|
|
493
|
-
return sig;
|
|
494
|
-
});
|
|
481
|
+
const signature = await web.Jwt.encodeWithSigner(jwtHeader, jwtPayload, async (header, payload) => vaultModels.VaultConnectorHelper.jwtSigner(this._vaultConnector, EntityStorageIdentityConnector.buildVaultKey(idParts.id, idParts.fragment ?? ""), header, payload));
|
|
495
482
|
return {
|
|
496
483
|
verifiableCredential,
|
|
497
484
|
jwt: signature
|
|
@@ -524,7 +511,7 @@ class EntityStorageIdentityConnector {
|
|
|
524
511
|
if (core.Is.undefined(issuerIdentityDocument)) {
|
|
525
512
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", issuerDocumentId);
|
|
526
513
|
}
|
|
527
|
-
await
|
|
514
|
+
await EntityStorageIdentityConnector.verifyDocument(issuerIdentityDocument, this._vaultConnector);
|
|
528
515
|
const issuerDidDocument = issuerIdentityDocument.document;
|
|
529
516
|
const methods = this.getAllMethods(issuerDidDocument);
|
|
530
517
|
const methodAndArray = methods.find(m => {
|
|
@@ -534,16 +521,13 @@ class EntityStorageIdentityConnector {
|
|
|
534
521
|
return m.method.id === jwtHeader.kid;
|
|
535
522
|
});
|
|
536
523
|
if (!methodAndArray) {
|
|
537
|
-
throw new core.GeneralError(this.CLASS_NAME, "methodMissing");
|
|
524
|
+
throw new core.GeneralError(this.CLASS_NAME, "methodMissing", { method: jwtHeader.kid });
|
|
538
525
|
}
|
|
539
526
|
const didMethod = methodAndArray.method;
|
|
540
527
|
if (!core.Is.stringValue(didMethod.publicKeyJwk?.x)) {
|
|
541
|
-
throw new core.GeneralError(this.CLASS_NAME, "publicKeyJwkMissing");
|
|
542
|
-
}
|
|
543
|
-
const verified = web.Jwt.verifySignature(jwtHeader, jwtPayload, jwtSignature, core.Converter.base64UrlToBytes(didMethod.publicKeyJwk.x));
|
|
544
|
-
if (!verified) {
|
|
545
|
-
throw new core.GeneralError(this.CLASS_NAME, "jwkSignatureFailed");
|
|
528
|
+
throw new core.GeneralError(this.CLASS_NAME, "publicKeyJwkMissing", { method: jwtHeader.kid });
|
|
546
529
|
}
|
|
530
|
+
await web.Jwt.verifySignature(credentialJwt, await web.Jwk.toCryptoKey(didMethod.publicKeyJwk));
|
|
547
531
|
const verifiableCredential = jwtPayload.vc;
|
|
548
532
|
if (core.Is.object(verifiableCredential)) {
|
|
549
533
|
if (core.Is.string(jwtPayload.jti)) {
|
|
@@ -563,7 +547,19 @@ class EntityStorageIdentityConnector {
|
|
|
563
547
|
core.ObjectHelper.propertySet(verifiableCredential.credentialSubject, "id", jwtPayload.sub);
|
|
564
548
|
}
|
|
565
549
|
}
|
|
566
|
-
const
|
|
550
|
+
const credentialStatus = verifiableCredential.credentialStatus;
|
|
551
|
+
let revoked = false;
|
|
552
|
+
if (core.Is.object(credentialStatus)) {
|
|
553
|
+
revoked = await this.checkRevocation(issuerDidDocument, credentialStatus.revocationBitmapIndex);
|
|
554
|
+
}
|
|
555
|
+
else if (core.Is.arrayValue(credentialStatus)) {
|
|
556
|
+
for (let i = 0; i < credentialStatus.length; i++) {
|
|
557
|
+
revoked = await this.checkRevocation(issuerDidDocument, credentialStatus[i].revocationBitmapIndex);
|
|
558
|
+
if (revoked) {
|
|
559
|
+
break;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
567
563
|
return {
|
|
568
564
|
revoked,
|
|
569
565
|
verifiableCredential: revoked ? undefined : verifiableCredential
|
|
@@ -589,7 +585,7 @@ class EntityStorageIdentityConnector {
|
|
|
589
585
|
if (core.Is.undefined(issuerIdentityDocument)) {
|
|
590
586
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", issuerDocumentId);
|
|
591
587
|
}
|
|
592
|
-
await
|
|
588
|
+
await EntityStorageIdentityConnector.verifyDocument(issuerIdentityDocument, this._vaultConnector);
|
|
593
589
|
const issuerDidDocument = issuerIdentityDocument.document;
|
|
594
590
|
const revocationService = issuerDidDocument.service?.find(s => s.id.endsWith("#revocation"));
|
|
595
591
|
if (revocationService &&
|
|
@@ -629,7 +625,7 @@ class EntityStorageIdentityConnector {
|
|
|
629
625
|
if (core.Is.undefined(issuerIdentityDocument)) {
|
|
630
626
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", issuerDocumentId);
|
|
631
627
|
}
|
|
632
|
-
await
|
|
628
|
+
await EntityStorageIdentityConnector.verifyDocument(issuerIdentityDocument, this._vaultConnector);
|
|
633
629
|
const issuerDidDocument = issuerIdentityDocument.document;
|
|
634
630
|
const revocationService = issuerDidDocument.service?.find(s => s.id.endsWith("#revocation"));
|
|
635
631
|
if (revocationService &&
|
|
@@ -656,17 +652,18 @@ class EntityStorageIdentityConnector {
|
|
|
656
652
|
/**
|
|
657
653
|
* Create a verifiable presentation from the supplied verifiable credentials.
|
|
658
654
|
* @param controller The controller of the identity who can make changes.
|
|
659
|
-
* @param
|
|
655
|
+
* @param verificationMethodId The method to associate with the presentation.
|
|
656
|
+
* @param presentationId The id of the presentation.
|
|
657
|
+
* @param contexts The contexts for the data stored in the verifiable credential.
|
|
660
658
|
* @param types The types for the data stored in the verifiable credential.
|
|
661
659
|
* @param verifiableCredentials The credentials to use for creating the presentation in jwt format.
|
|
662
|
-
* @param contexts Additional contexts to include in the presentation.
|
|
663
660
|
* @param expiresInMinutes The time in minutes for the presentation to expire.
|
|
664
661
|
* @returns The created verifiable presentation and its token.
|
|
665
662
|
* @throws NotFoundError if the id can not be resolved.
|
|
666
663
|
*/
|
|
667
|
-
async createVerifiablePresentation(controller,
|
|
664
|
+
async createVerifiablePresentation(controller, verificationMethodId, presentationId, contexts, types, verifiableCredentials, expiresInMinutes) {
|
|
668
665
|
core.Guards.stringValue(this.CLASS_NAME, "controller", controller);
|
|
669
|
-
core.Guards.stringValue(this.CLASS_NAME, "
|
|
666
|
+
core.Guards.stringValue(this.CLASS_NAME, "verificationMethodId", verificationMethodId);
|
|
670
667
|
if (core.Is.array(types)) {
|
|
671
668
|
core.Guards.arrayValue(this.CLASS_NAME, "types", types);
|
|
672
669
|
}
|
|
@@ -674,41 +671,37 @@ class EntityStorageIdentityConnector {
|
|
|
674
671
|
core.Guards.stringValue(this.CLASS_NAME, "types", types);
|
|
675
672
|
}
|
|
676
673
|
core.Guards.arrayValue(this.CLASS_NAME, "verifiableCredentials", verifiableCredentials);
|
|
677
|
-
if (core.Is.array(contexts)) {
|
|
678
|
-
core.Guards.arrayValue(this.CLASS_NAME, "contexts", contexts);
|
|
679
|
-
}
|
|
680
|
-
else if (core.Is.string(contexts)) {
|
|
681
|
-
core.Guards.stringValue(this.CLASS_NAME, "contexts", contexts);
|
|
682
|
-
}
|
|
683
674
|
if (!core.Is.undefined(expiresInMinutes)) {
|
|
684
675
|
core.Guards.integer(this.CLASS_NAME, "expiresInMinutes", expiresInMinutes);
|
|
685
676
|
}
|
|
686
677
|
try {
|
|
687
|
-
const idParts = identityModels.DocumentHelper.
|
|
688
|
-
if (core.Is.empty(idParts.
|
|
689
|
-
throw new core.NotFoundError(this.CLASS_NAME, "missingDid",
|
|
678
|
+
const idParts = identityModels.DocumentHelper.parseId(verificationMethodId);
|
|
679
|
+
if (core.Is.empty(idParts.fragment)) {
|
|
680
|
+
throw new core.NotFoundError(this.CLASS_NAME, "missingDid", verificationMethodId);
|
|
690
681
|
}
|
|
691
682
|
const holderIdentityDocument = await this._didDocumentEntityStorage.get(idParts.id);
|
|
692
683
|
if (core.Is.undefined(holderIdentityDocument)) {
|
|
693
684
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", idParts.id);
|
|
694
685
|
}
|
|
695
|
-
await
|
|
686
|
+
await EntityStorageIdentityConnector.verifyDocument(holderIdentityDocument, this._vaultConnector);
|
|
696
687
|
const holderDidDocument = holderIdentityDocument.document;
|
|
697
688
|
const methods = this.getAllMethods(holderDidDocument);
|
|
698
689
|
const methodAndArray = methods.find(m => {
|
|
699
690
|
if (core.Is.string(m.method)) {
|
|
700
|
-
return m.method ===
|
|
691
|
+
return m.method === verificationMethodId;
|
|
701
692
|
}
|
|
702
|
-
return m.method.id ===
|
|
693
|
+
return m.method.id === verificationMethodId;
|
|
703
694
|
});
|
|
704
695
|
if (!methodAndArray) {
|
|
705
|
-
throw new core.GeneralError(this.CLASS_NAME, "methodMissing");
|
|
696
|
+
throw new core.GeneralError(this.CLASS_NAME, "methodMissing", { method: verificationMethodId });
|
|
706
697
|
}
|
|
707
698
|
const didMethod = methodAndArray.method;
|
|
708
699
|
if (!core.Is.stringValue(didMethod.publicKeyJwk?.x)) {
|
|
709
|
-
throw new core.GeneralError(this.CLASS_NAME, "publicKeyJwkMissing"
|
|
700
|
+
throw new core.GeneralError(this.CLASS_NAME, "publicKeyJwkMissing", {
|
|
701
|
+
method: verificationMethodId
|
|
702
|
+
});
|
|
710
703
|
}
|
|
711
|
-
const finalTypes = [
|
|
704
|
+
const finalTypes = [standardsW3cDid.DidTypes.VerifiablePresentation];
|
|
712
705
|
if (core.Is.array(types)) {
|
|
713
706
|
finalTypes.push(...types);
|
|
714
707
|
}
|
|
@@ -716,8 +709,8 @@ class EntityStorageIdentityConnector {
|
|
|
716
709
|
finalTypes.push(types);
|
|
717
710
|
}
|
|
718
711
|
const verifiablePresentation = {
|
|
719
|
-
"@context": dataJsonLd.JsonLdProcessor.combineContexts(
|
|
720
|
-
|
|
712
|
+
"@context": dataJsonLd.JsonLdProcessor.combineContexts(standardsW3cDid.DidContexts.ContextVCv2, contexts),
|
|
713
|
+
id: presentationId,
|
|
721
714
|
type: finalTypes,
|
|
722
715
|
verifiableCredential: verifiableCredentials,
|
|
723
716
|
holder: idParts.id
|
|
@@ -741,10 +734,7 @@ class EntityStorageIdentityConnector {
|
|
|
741
734
|
const expiresInSeconds = expiresInMinutes * 60;
|
|
742
735
|
jwtPayload.exp = Math.floor(Date.now() / 1000) + expiresInSeconds;
|
|
743
736
|
}
|
|
744
|
-
const signature = await web.Jwt.encodeWithSigner(jwtHeader, jwtPayload, async (
|
|
745
|
-
const sig = await this._vaultConnector.sign(this.buildVaultKey(idParts.id, presentationMethodId), payload);
|
|
746
|
-
return sig;
|
|
747
|
-
});
|
|
737
|
+
const signature = await web.Jwt.encodeWithSigner(jwtHeader, jwtPayload, async (header, payload) => vaultModels.VaultConnectorHelper.jwtSigner(this._vaultConnector, EntityStorageIdentityConnector.buildVaultKey(idParts.id, idParts.fragment ?? ""), header, payload));
|
|
748
738
|
return {
|
|
749
739
|
verifiablePresentation,
|
|
750
740
|
jwt: signature
|
|
@@ -777,29 +767,54 @@ class EntityStorageIdentityConnector {
|
|
|
777
767
|
if (core.Is.undefined(holderIdentityDocument)) {
|
|
778
768
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", holderDocumentId);
|
|
779
769
|
}
|
|
780
|
-
await
|
|
770
|
+
await EntityStorageIdentityConnector.verifyDocument(holderIdentityDocument, this._vaultConnector);
|
|
781
771
|
const issuers = [];
|
|
782
772
|
const tokensRevoked = [];
|
|
783
773
|
const verifiablePresentation = jwtPayload?.vp;
|
|
784
774
|
if (core.Is.object(verifiablePresentation) &&
|
|
785
775
|
core.Is.array(verifiablePresentation.verifiableCredential)) {
|
|
786
776
|
for (const vcJwt of verifiablePresentation.verifiableCredential) {
|
|
787
|
-
const jwt = await web.Jwt.decode(vcJwt);
|
|
788
777
|
let revoked = true;
|
|
789
|
-
if (core.Is.
|
|
790
|
-
const
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
778
|
+
if (core.Is.stringValue(vcJwt)) {
|
|
779
|
+
const jwt = await web.Jwt.decode(vcJwt);
|
|
780
|
+
if (core.Is.string(jwt.payload?.iss)) {
|
|
781
|
+
const issuerDocumentId = jwt.payload.iss;
|
|
782
|
+
verifiablePresentation.holder = issuerDocumentId;
|
|
783
|
+
const issuerDidDocument = await this._didDocumentEntityStorage.get(issuerDocumentId);
|
|
784
|
+
if (core.Is.undefined(issuerDidDocument)) {
|
|
785
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", issuerDocumentId);
|
|
786
|
+
}
|
|
787
|
+
await EntityStorageIdentityConnector.verifyDocument(issuerDidDocument, this._vaultConnector);
|
|
788
|
+
issuers.push({
|
|
789
|
+
"@context": standardsW3cDid.DidContexts.Context,
|
|
790
|
+
...issuerDidDocument
|
|
791
|
+
});
|
|
792
|
+
const vc = jwt.payload.vc;
|
|
793
|
+
if (core.Is.object(vc)) {
|
|
794
|
+
const credentialStatus = vc.credentialStatus;
|
|
795
|
+
if (core.Is.object(credentialStatus)) {
|
|
796
|
+
revoked = await this.checkRevocation({
|
|
797
|
+
"@context": standardsW3cDid.DidContexts.Context,
|
|
798
|
+
...issuerDidDocument
|
|
799
|
+
}, credentialStatus.revocationBitmapIndex);
|
|
800
|
+
}
|
|
801
|
+
else if (core.Is.arrayValue(credentialStatus)) {
|
|
802
|
+
for (let i = 0; i < credentialStatus.length; i++) {
|
|
803
|
+
revoked = await this.checkRevocation({
|
|
804
|
+
"@context": standardsW3cDid.DidContexts.Context,
|
|
805
|
+
...issuerDidDocument
|
|
806
|
+
}, credentialStatus[i].revocationBitmapIndex);
|
|
807
|
+
if (revoked) {
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
801
813
|
}
|
|
802
814
|
}
|
|
815
|
+
else {
|
|
816
|
+
revoked = false;
|
|
817
|
+
}
|
|
803
818
|
tokensRevoked.push(revoked);
|
|
804
819
|
}
|
|
805
820
|
}
|
|
@@ -822,23 +837,25 @@ class EntityStorageIdentityConnector {
|
|
|
822
837
|
* Create a proof for arbitrary data with the specified verification method.
|
|
823
838
|
* @param controller The controller of the identity who can make changes.
|
|
824
839
|
* @param verificationMethodId The verification method id to use.
|
|
825
|
-
* @param
|
|
826
|
-
* @
|
|
840
|
+
* @param proofType The type of proof to create.
|
|
841
|
+
* @param unsecureDocument The unsecure document to create the proof for.
|
|
842
|
+
* @returns The proof.
|
|
827
843
|
*/
|
|
828
|
-
async createProof(controller, verificationMethodId,
|
|
844
|
+
async createProof(controller, verificationMethodId, proofType, unsecureDocument) {
|
|
829
845
|
core.Guards.stringValue(this.CLASS_NAME, "controller", controller);
|
|
830
846
|
core.Guards.stringValue(this.CLASS_NAME, "verificationMethodId", verificationMethodId);
|
|
831
|
-
core.Guards.
|
|
847
|
+
core.Guards.arrayOneOf(this.CLASS_NAME, "proofType", proofType, Object.values(standardsW3cDid.ProofTypes));
|
|
848
|
+
core.Guards.object(this.CLASS_NAME, "unsecureDocument", unsecureDocument);
|
|
832
849
|
try {
|
|
833
|
-
const idParts = identityModels.DocumentHelper.
|
|
834
|
-
if (core.Is.empty(idParts.
|
|
850
|
+
const idParts = identityModels.DocumentHelper.parseId(verificationMethodId);
|
|
851
|
+
if (core.Is.empty(idParts.fragment)) {
|
|
835
852
|
throw new core.NotFoundError(this.CLASS_NAME, "missingDid", verificationMethodId);
|
|
836
853
|
}
|
|
837
854
|
const didIdentityDocument = await this._didDocumentEntityStorage.get(idParts.id);
|
|
838
855
|
if (core.Is.undefined(didIdentityDocument)) {
|
|
839
856
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", idParts.id);
|
|
840
857
|
}
|
|
841
|
-
await
|
|
858
|
+
await EntityStorageIdentityConnector.verifyDocument(didIdentityDocument, this._vaultConnector);
|
|
842
859
|
const didDocument = didIdentityDocument.document;
|
|
843
860
|
const methods = this.getAllMethods(didDocument);
|
|
844
861
|
const methodAndArray = methods.find(m => {
|
|
@@ -848,17 +865,18 @@ class EntityStorageIdentityConnector {
|
|
|
848
865
|
return m.method.id === verificationMethodId;
|
|
849
866
|
});
|
|
850
867
|
if (!methodAndArray) {
|
|
851
|
-
throw new core.GeneralError(this.CLASS_NAME, "methodMissing");
|
|
868
|
+
throw new core.GeneralError(this.CLASS_NAME, "methodMissing", { method: verificationMethodId });
|
|
852
869
|
}
|
|
853
870
|
const didMethod = methodAndArray.method;
|
|
854
871
|
if (!core.Is.stringValue(didMethod.publicKeyJwk?.x)) {
|
|
855
|
-
throw new core.GeneralError(this.CLASS_NAME, "publicKeyJwkMissing"
|
|
872
|
+
throw new core.GeneralError(this.CLASS_NAME, "publicKeyJwkMissing", {
|
|
873
|
+
method: verificationMethodId
|
|
874
|
+
});
|
|
856
875
|
}
|
|
857
|
-
const
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
};
|
|
876
|
+
const vaultKey = EntityStorageIdentityConnector.buildVaultKey(didDocument.id, idParts.fragment ?? "");
|
|
877
|
+
const key = await this._vaultConnector.getKey(vaultKey);
|
|
878
|
+
const signedProof = await standardsW3cDid.ProofHelper.createProof(proofType, unsecureDocument, standardsW3cDid.ProofHelper.createUnsignedProof(proofType, verificationMethodId), await web.Jwk.fromEd25519Private(key.privateKey));
|
|
879
|
+
return signedProof;
|
|
862
880
|
}
|
|
863
881
|
catch (error) {
|
|
864
882
|
throw new core.GeneralError(this.CLASS_NAME, "createProofFailed", undefined, error);
|
|
@@ -866,43 +884,44 @@ class EntityStorageIdentityConnector {
|
|
|
866
884
|
}
|
|
867
885
|
/**
|
|
868
886
|
* Verify proof for arbitrary data with the specified verification method.
|
|
869
|
-
* @param
|
|
870
|
-
* @param
|
|
871
|
-
* @
|
|
872
|
-
* @param signatureValue The value of the signature for the proof.
|
|
873
|
-
* @returns True if the signature is valid.
|
|
887
|
+
* @param document The document to verify.
|
|
888
|
+
* @param proof The proof to verify.
|
|
889
|
+
* @returns True if the proof is verified.
|
|
874
890
|
*/
|
|
875
|
-
async verifyProof(
|
|
876
|
-
core.Guards.
|
|
877
|
-
core.Guards.
|
|
878
|
-
core.Guards.stringValue(this.CLASS_NAME, "
|
|
879
|
-
core.Guards.uint8Array(this.CLASS_NAME, "signatureValue", signatureValue);
|
|
891
|
+
async verifyProof(document, proof) {
|
|
892
|
+
core.Guards.object(this.CLASS_NAME, "document", document);
|
|
893
|
+
core.Guards.object(this.CLASS_NAME, "proof", proof);
|
|
894
|
+
core.Guards.stringValue(this.CLASS_NAME, "proof.verificationMethod", proof.verificationMethod);
|
|
880
895
|
try {
|
|
881
|
-
const idParts = identityModels.DocumentHelper.
|
|
882
|
-
if (core.Is.empty(idParts.
|
|
883
|
-
throw new core.NotFoundError(this.CLASS_NAME, "missingDid",
|
|
896
|
+
const idParts = identityModels.DocumentHelper.parseId(proof.verificationMethod);
|
|
897
|
+
if (core.Is.empty(idParts.fragment)) {
|
|
898
|
+
throw new core.NotFoundError(this.CLASS_NAME, "missingDid", proof.verificationMethod);
|
|
884
899
|
}
|
|
885
900
|
const didIdentityDocument = await this._didDocumentEntityStorage.get(idParts.id);
|
|
886
901
|
if (core.Is.undefined(didIdentityDocument)) {
|
|
887
902
|
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", idParts.id);
|
|
888
903
|
}
|
|
889
|
-
await
|
|
904
|
+
await EntityStorageIdentityConnector.verifyDocument(didIdentityDocument, this._vaultConnector);
|
|
890
905
|
const didDocument = didIdentityDocument.document;
|
|
891
906
|
const methods = this.getAllMethods(didDocument);
|
|
892
907
|
const methodAndArray = methods.find(m => {
|
|
893
908
|
if (core.Is.string(m.method)) {
|
|
894
|
-
return m.method ===
|
|
909
|
+
return m.method === proof.verificationMethod;
|
|
895
910
|
}
|
|
896
|
-
return m.method.id ===
|
|
911
|
+
return m.method.id === proof.verificationMethod;
|
|
897
912
|
});
|
|
898
913
|
if (!methodAndArray) {
|
|
899
|
-
throw new core.GeneralError(this.CLASS_NAME, "methodMissing"
|
|
914
|
+
throw new core.GeneralError(this.CLASS_NAME, "methodMissing", {
|
|
915
|
+
method: proof.verificationMethod
|
|
916
|
+
});
|
|
900
917
|
}
|
|
901
918
|
const didMethod = methodAndArray.method;
|
|
902
919
|
if (!core.Is.stringValue(didMethod.publicKeyJwk?.x)) {
|
|
903
|
-
throw new core.GeneralError(this.CLASS_NAME, "publicKeyJwkMissing"
|
|
920
|
+
throw new core.GeneralError(this.CLASS_NAME, "publicKeyJwkMissing", {
|
|
921
|
+
method: proof.verificationMethod
|
|
922
|
+
});
|
|
904
923
|
}
|
|
905
|
-
return
|
|
924
|
+
return standardsW3cDid.ProofHelper.verifyProof(document, proof, didMethod.publicKeyJwk);
|
|
906
925
|
}
|
|
907
926
|
catch (error) {
|
|
908
927
|
throw new core.GeneralError(this.CLASS_NAME, "verifyProofFailed", undefined, error);
|
|
@@ -955,19 +974,6 @@ class EntityStorageIdentityConnector {
|
|
|
955
974
|
}
|
|
956
975
|
return false;
|
|
957
976
|
}
|
|
958
|
-
/**
|
|
959
|
-
* Verify the document in storage.
|
|
960
|
-
* @param didDocument The did document that was stored.
|
|
961
|
-
* @internal
|
|
962
|
-
*/
|
|
963
|
-
async verifyDocument(didDocument) {
|
|
964
|
-
const stringifiedDocument = core.JsonHelper.canonicalize(didDocument.document);
|
|
965
|
-
const docBytes = core.Converter.utf8ToBytes(stringifiedDocument);
|
|
966
|
-
const verified = await this._vaultConnector.verify(this.buildVaultKey(didDocument.id, didDocument.id), docBytes, core.Converter.base64ToBytes(didDocument.signature));
|
|
967
|
-
if (!verified) {
|
|
968
|
-
throw new core.GeneralError(this.CLASS_NAME, "signatureVerificationFailed");
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
977
|
/**
|
|
972
978
|
* Update the document in storage.
|
|
973
979
|
* @param controller The controller of the document.
|
|
@@ -977,7 +983,7 @@ class EntityStorageIdentityConnector {
|
|
|
977
983
|
async updateDocument(controller, didDocument) {
|
|
978
984
|
const stringifiedDocument = core.JsonHelper.canonicalize(didDocument);
|
|
979
985
|
const docBytes = core.Converter.utf8ToBytes(stringifiedDocument);
|
|
980
|
-
const signature = await this._vaultConnector.sign(
|
|
986
|
+
const signature = await this._vaultConnector.sign(EntityStorageIdentityConnector.buildVaultKey(didDocument.id, "did"), docBytes);
|
|
981
987
|
await this._didDocumentEntityStorage.set({
|
|
982
988
|
id: didDocument.id,
|
|
983
989
|
document: didDocument,
|
|
@@ -985,15 +991,6 @@ class EntityStorageIdentityConnector {
|
|
|
985
991
|
controller
|
|
986
992
|
});
|
|
987
993
|
}
|
|
988
|
-
/**
|
|
989
|
-
* Build the key name to access the specified key in the vault.
|
|
990
|
-
* @param identity The identity of the user to access the vault keys.
|
|
991
|
-
* @returns The vault key.
|
|
992
|
-
* @internal
|
|
993
|
-
*/
|
|
994
|
-
buildVaultKey(identity, key) {
|
|
995
|
-
return `${identity}/${key}`;
|
|
996
|
-
}
|
|
997
994
|
}
|
|
998
995
|
|
|
999
996
|
// Copyright 2024 IOTA Stiftung.
|
|
@@ -1016,9 +1013,8 @@ class EntityStorageIdentityProfileConnector {
|
|
|
1016
1013
|
*/
|
|
1017
1014
|
_profileEntityStorage;
|
|
1018
1015
|
/**
|
|
1019
|
-
* Create a new instance of
|
|
1020
|
-
* @param options The
|
|
1021
|
-
* @param options.profileEntityStorageType The storage connector for the profiles, default to "identity-profile".
|
|
1016
|
+
* Create a new instance of EntityStorageIdentityProfileConnector.
|
|
1017
|
+
* @param options The options for the identity service.
|
|
1022
1018
|
*/
|
|
1023
1019
|
constructor(options) {
|
|
1024
1020
|
this._profileEntityStorage = entityStorageModels.EntityStorageConnectorFactory.get(options?.profileEntityStorageType ?? "identity-profile");
|
|
@@ -1190,6 +1186,60 @@ class EntityStorageIdentityProfileConnector {
|
|
|
1190
1186
|
}
|
|
1191
1187
|
}
|
|
1192
1188
|
|
|
1189
|
+
// Copyright 2024 IOTA Stiftung.
|
|
1190
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
1191
|
+
/**
|
|
1192
|
+
* Class for performing identity operations using entity storage.
|
|
1193
|
+
*/
|
|
1194
|
+
class EntityStorageIdentityResolverConnector {
|
|
1195
|
+
/**
|
|
1196
|
+
* The namespace supported by the identity connector.
|
|
1197
|
+
*/
|
|
1198
|
+
static NAMESPACE = "entity-storage";
|
|
1199
|
+
/**
|
|
1200
|
+
* Runtime name for the class.
|
|
1201
|
+
*/
|
|
1202
|
+
CLASS_NAME = "EntityStorageIdentityResolverConnector";
|
|
1203
|
+
/**
|
|
1204
|
+
* The entity storage for identities.
|
|
1205
|
+
* @internal
|
|
1206
|
+
*/
|
|
1207
|
+
_didDocumentEntityStorage;
|
|
1208
|
+
/**
|
|
1209
|
+
* The vault for the keys.
|
|
1210
|
+
* @internal
|
|
1211
|
+
*/
|
|
1212
|
+
_vaultConnector;
|
|
1213
|
+
/**
|
|
1214
|
+
* Create a new instance of EntityStorageIdentityResolverConnector.
|
|
1215
|
+
* @param options The options for the identity connector.
|
|
1216
|
+
*/
|
|
1217
|
+
constructor(options) {
|
|
1218
|
+
this._didDocumentEntityStorage = entityStorageModels.EntityStorageConnectorFactory.get(options?.didDocumentEntityStorageType ?? "identity-document");
|
|
1219
|
+
this._vaultConnector = vaultModels.VaultConnectorFactory.get(options?.vaultConnectorType ?? "vault");
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Resolve a document from its id.
|
|
1223
|
+
* @param documentId The id of the document to resolve.
|
|
1224
|
+
* @returns The resolved document.
|
|
1225
|
+
* @throws NotFoundError if the id can not be resolved.
|
|
1226
|
+
*/
|
|
1227
|
+
async resolveDocument(documentId) {
|
|
1228
|
+
core.Guards.stringValue(this.CLASS_NAME, "documentId", documentId);
|
|
1229
|
+
try {
|
|
1230
|
+
const didIdentityDocument = await this._didDocumentEntityStorage.get(documentId);
|
|
1231
|
+
if (core.Is.undefined(didIdentityDocument)) {
|
|
1232
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentNotFound", documentId);
|
|
1233
|
+
}
|
|
1234
|
+
await EntityStorageIdentityConnector.verifyDocument(didIdentityDocument, this._vaultConnector);
|
|
1235
|
+
return didIdentityDocument.document;
|
|
1236
|
+
}
|
|
1237
|
+
catch (error) {
|
|
1238
|
+
throw new core.GeneralError(this.CLASS_NAME, "resolveDocumentFailed", undefined, error);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1193
1243
|
// Copyright 2024 IOTA Stiftung.
|
|
1194
1244
|
// SPDX-License-Identifier: Apache-2.0.
|
|
1195
1245
|
/**
|
|
@@ -1209,4 +1259,5 @@ function initSchema(options) {
|
|
|
1209
1259
|
|
|
1210
1260
|
exports.EntityStorageIdentityConnector = EntityStorageIdentityConnector;
|
|
1211
1261
|
exports.EntityStorageIdentityProfileConnector = EntityStorageIdentityProfileConnector;
|
|
1262
|
+
exports.EntityStorageIdentityResolverConnector = EntityStorageIdentityResolverConnector;
|
|
1212
1263
|
exports.initSchema = initSchema;
|