@bedrock/vc-verifier 19.1.0 → 20.0.0
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/README.md +1 -1
- package/lib/config.js +4 -2
- package/lib/documentLoader.js +77 -5
- package/lib/index.js +15 -2
- package/package.json +36 -37
- package/schemas/bedrock-vc-verifier.js +37 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bedrock VC Verifier API module _(@bedrock/vc-verifier)_
|
|
2
2
|
|
|
3
|
-
[](https://github.com/digitalbazaar/bedrock-vc-verifier/actions/workflows/main.yml)
|
|
4
4
|
[](https://npm.im/bedrock-vc-verifier)
|
|
5
5
|
|
|
6
6
|
> A VC Verifier API library for use with Bedrock applications.
|
package/lib/config.js
CHANGED
|
@@ -17,9 +17,11 @@ cfg.challenges = {
|
|
|
17
17
|
// also allow any verifier instance to optionally load `http` and `https`
|
|
18
18
|
// documents directly from the Web
|
|
19
19
|
cfg.documentLoader = {
|
|
20
|
-
// `true` enables all
|
|
20
|
+
// `true` enables all verifier instances that do not have document loader
|
|
21
|
+
// instance-specific constraints to fetch `http` documents from the Web
|
|
21
22
|
http: false,
|
|
22
|
-
// `true` enables all
|
|
23
|
+
// `true` enables all verifier instances that do not have document loader
|
|
24
|
+
// instance-specific constraints to fetch `https` documents from the Web
|
|
23
25
|
https: true
|
|
24
26
|
};
|
|
25
27
|
|
package/lib/documentLoader.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Copyright (c) 2019-
|
|
2
|
+
* Copyright (c) 2019-2024 Digital Bazaar, Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
import * as bedrock from '@bedrock/core';
|
|
5
5
|
import {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from '@bedrock/jsonld-document-loader';
|
|
10
10
|
import {createContextDocumentLoader} from '@bedrock/service-context-store';
|
|
11
11
|
import {didIo} from '@bedrock/did-io';
|
|
12
|
+
import {klona} from 'klona';
|
|
12
13
|
import '@bedrock/credentials-context';
|
|
13
14
|
import '@bedrock/data-integrity-context';
|
|
14
15
|
import '@bedrock/did-context';
|
|
@@ -53,9 +54,17 @@ export async function createDocumentLoader({config} = {}) {
|
|
|
53
54
|
{config, serviceType});
|
|
54
55
|
|
|
55
56
|
return async function documentLoader(url) {
|
|
56
|
-
//
|
|
57
|
+
// handle DID URLs...
|
|
57
58
|
if(url.startsWith('did:')) {
|
|
58
|
-
|
|
59
|
+
let document;
|
|
60
|
+
if(config.verifyOptions?.didResolver) {
|
|
61
|
+
// resolve via configured DID resolver
|
|
62
|
+
const {verifyOptions: {didResolver}} = config;
|
|
63
|
+
document = await _resolve({didResolver, didUrl: url});
|
|
64
|
+
} else {
|
|
65
|
+
// resolve via did-io
|
|
66
|
+
document = await didIo.get({url});
|
|
67
|
+
}
|
|
59
68
|
return {
|
|
60
69
|
contextUrl: null,
|
|
61
70
|
documentUrl: url,
|
|
@@ -75,11 +84,74 @@ export async function createDocumentLoader({config} = {}) {
|
|
|
75
84
|
// try to resolve URL through context doc loader
|
|
76
85
|
return await contextDocumentLoader(url);
|
|
77
86
|
} catch(e) {
|
|
78
|
-
// use web loader if configured
|
|
79
|
-
|
|
87
|
+
// use web loader if configured and instance config allows it and
|
|
88
|
+
// the url starts with `http`, and the core config allows it
|
|
89
|
+
const allowRemoteContexts = !config.verifyOptions?.documentLoader ||
|
|
90
|
+
config.verifyOptions.documentLoader.allowRemoteContexts;
|
|
91
|
+
if(allowRemoteContexts &&
|
|
92
|
+
url.startsWith('http') && e.name === 'NotFoundError' && webLoader) {
|
|
80
93
|
return webLoader(url);
|
|
81
94
|
}
|
|
82
95
|
throw e;
|
|
83
96
|
}
|
|
84
97
|
};
|
|
85
98
|
}
|
|
99
|
+
|
|
100
|
+
async function _resolve({didResolver, didUrl}) {
|
|
101
|
+
// split on `?` query or `#` fragment
|
|
102
|
+
const [did] = didUrl.split(/(?=[\?#])/);
|
|
103
|
+
|
|
104
|
+
// fetch DID document using DID resolver, assume DID param is prepended
|
|
105
|
+
const url = didResolver.url.endsWith('/') ?
|
|
106
|
+
`${didResolver.url}${encodeURIComponent(did)}` :
|
|
107
|
+
`${didResolver.url}/${encodeURIComponent(did)}`;
|
|
108
|
+
const data = await httpClientHandler.get({url});
|
|
109
|
+
|
|
110
|
+
if(data?.didDocument?.id !== did) {
|
|
111
|
+
throw new Error(`DID document for DID "${did}" not found.`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// FIXME: perform DID document validation
|
|
115
|
+
// FIXME: handle URL query param / services
|
|
116
|
+
const {didDocument} = data;
|
|
117
|
+
|
|
118
|
+
// if a fragment was found use the fragment to dereference a subnode
|
|
119
|
+
// in the did doc
|
|
120
|
+
const [, fragment] = didUrl.split('#');
|
|
121
|
+
if(fragment) {
|
|
122
|
+
const id = `${didDocument.id}#${fragment}`;
|
|
123
|
+
return _getNode({didDocument, id});
|
|
124
|
+
}
|
|
125
|
+
// resolve the full DID Document
|
|
126
|
+
return didDocument;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function _getNode({didDocument, id}) {
|
|
130
|
+
// do verification method search first
|
|
131
|
+
let match = didDocument?.verificationMethod?.find(vm => vm?.id === id);
|
|
132
|
+
if(!match) {
|
|
133
|
+
// check other top-level nodes
|
|
134
|
+
for(const [key, value] of Object.entries(didDocument)) {
|
|
135
|
+
if(key === '@context' || key === 'verificationMethod') {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if(Array.isArray(value)) {
|
|
139
|
+
match = value.find(e => e?.id === id);
|
|
140
|
+
} else if(value?.id === id) {
|
|
141
|
+
match = value;
|
|
142
|
+
}
|
|
143
|
+
if(match) {
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if(!match) {
|
|
150
|
+
throw new Error(`DID document entity with id "${id}" not found.`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
'@context': klona(didDocument['@context']),
|
|
155
|
+
...klona(match)
|
|
156
|
+
};
|
|
157
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Copyright (c) 2021-
|
|
2
|
+
* Copyright (c) 2021-2024 Digital Bazaar, Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
import * as bedrock from '@bedrock/core';
|
|
5
|
+
import {createService, schemas} from '@bedrock/service-core';
|
|
5
6
|
import {
|
|
6
7
|
addRoutes as addContextStoreRoutes
|
|
7
8
|
} from '@bedrock/service-context-store';
|
|
8
9
|
import {addRoutes} from './http.js';
|
|
9
|
-
import {createService} from '@bedrock/service-core';
|
|
10
10
|
import {initializeServiceAgent} from '@bedrock/service-agent';
|
|
11
|
+
import {klona} from 'klona';
|
|
12
|
+
import {verifyOptions} from '../schemas/bedrock-vc-verifier.js';
|
|
11
13
|
|
|
12
14
|
// load config defaults
|
|
13
15
|
import './config.js';
|
|
@@ -15,6 +17,15 @@ import './config.js';
|
|
|
15
17
|
const serviceType = 'vc-verifier';
|
|
16
18
|
|
|
17
19
|
bedrock.events.on('bedrock.init', async () => {
|
|
20
|
+
// add customizations to config validators...
|
|
21
|
+
const createConfigBody = klona(schemas.createConfigBody);
|
|
22
|
+
const updateConfigBody = klona(schemas.updateConfigBody);
|
|
23
|
+
const schemasToUpdate = [createConfigBody, updateConfigBody];
|
|
24
|
+
for(const schema of schemasToUpdate) {
|
|
25
|
+
// verify options
|
|
26
|
+
schema.properties.verifyOptions = verifyOptions;
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
// create `vc-verifier` service
|
|
19
30
|
const service = await createService({
|
|
20
31
|
serviceType,
|
|
@@ -24,6 +35,8 @@ bedrock.events.on('bedrock.init', async () => {
|
|
|
24
35
|
revocation: 1
|
|
25
36
|
},
|
|
26
37
|
validation: {
|
|
38
|
+
createConfigBody,
|
|
39
|
+
updateConfigBody,
|
|
27
40
|
// require these zcaps (by reference ID)
|
|
28
41
|
zcapReferenceIds: [{
|
|
29
42
|
referenceId: 'edv',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bedrock/vc-verifier",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "20.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Bedrock VC Verifier",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"schemas/**/*.js"
|
|
10
10
|
],
|
|
11
11
|
"scripts": {
|
|
12
|
-
"lint": "eslint ."
|
|
12
|
+
"lint": "eslint --ext .cjs,.js ."
|
|
13
13
|
},
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
@@ -25,52 +25,51 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://github.com/digitalbazaar/bedrock-vc-verifier",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@digitalbazaar/bbs-2023-cryptosuite": "^1.
|
|
29
|
-
"@digitalbazaar/data-integrity": "^2.
|
|
28
|
+
"@digitalbazaar/bbs-2023-cryptosuite": "^1.2.0",
|
|
29
|
+
"@digitalbazaar/data-integrity": "^2.2.0",
|
|
30
30
|
"@digitalbazaar/ecdsa-2019-cryptosuite": "^2.0.0",
|
|
31
|
-
"@digitalbazaar/ecdsa-rdfc-2019-cryptosuite": "^1.0
|
|
32
|
-
"@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.2.
|
|
31
|
+
"@digitalbazaar/ecdsa-rdfc-2019-cryptosuite": "^1.1.0",
|
|
32
|
+
"@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.2.1",
|
|
33
33
|
"@digitalbazaar/ed25519-signature-2018": "^4.0.0",
|
|
34
|
-
"@digitalbazaar/ed25519-signature-2020": "^5.
|
|
34
|
+
"@digitalbazaar/ed25519-signature-2020": "^5.4.0",
|
|
35
35
|
"@digitalbazaar/eddsa-2022-cryptosuite": "^1.0.0",
|
|
36
|
-
"@digitalbazaar/eddsa-rdfc-2022-cryptosuite": "^1.0
|
|
37
|
-
"@digitalbazaar/vc": "^
|
|
38
|
-
"@digitalbazaar/vc-revocation-list": "^
|
|
39
|
-
"@digitalbazaar/vc-status-list": "^
|
|
36
|
+
"@digitalbazaar/eddsa-rdfc-2022-cryptosuite": "^1.1.0",
|
|
37
|
+
"@digitalbazaar/vc": "^7.0.0",
|
|
38
|
+
"@digitalbazaar/vc-revocation-list": "^7.0.0",
|
|
39
|
+
"@digitalbazaar/vc-status-list": "^8.0.0",
|
|
40
40
|
"assert-plus": "^1.0.0",
|
|
41
41
|
"bnid": "^3.0.0",
|
|
42
|
-
"body-parser": "^1.20.
|
|
42
|
+
"body-parser": "^1.20.2",
|
|
43
43
|
"cors": "^2.8.5",
|
|
44
|
-
"
|
|
44
|
+
"klona": "^2.0.6",
|
|
45
|
+
"serialize-error": "^11.0.3"
|
|
45
46
|
},
|
|
46
47
|
"peerDependencies": {
|
|
47
48
|
"@bedrock/app-identity": "^4.0.0",
|
|
48
|
-
"@bedrock/core": "^6.
|
|
49
|
-
"@bedrock/credentials-context": "^
|
|
50
|
-
"@bedrock/data-integrity-context": "^
|
|
51
|
-
"@bedrock/did-context": "^
|
|
52
|
-
"@bedrock/did-io": "^10.
|
|
53
|
-
"@bedrock/express": "^8.
|
|
54
|
-
"@bedrock/https-agent": "^4.
|
|
55
|
-
"@bedrock/jsonld-document-loader": "^
|
|
56
|
-
"@bedrock/mongodb": "^10.
|
|
57
|
-
"@bedrock/multikey-context": "^
|
|
58
|
-
"@bedrock/security-context": "^
|
|
59
|
-
"@bedrock/service-agent": "^
|
|
60
|
-
"@bedrock/service-context-store": "^
|
|
61
|
-
"@bedrock/service-core": "^
|
|
62
|
-
"@bedrock/validation": "^7.
|
|
63
|
-
"@bedrock/vc-revocation-list-context": "^
|
|
64
|
-
"@bedrock/vc-status-list-context": "^
|
|
65
|
-
"@bedrock/veres-one-context": "^
|
|
49
|
+
"@bedrock/core": "^6.1.3",
|
|
50
|
+
"@bedrock/credentials-context": "^5.0.2",
|
|
51
|
+
"@bedrock/data-integrity-context": "^4.0.3",
|
|
52
|
+
"@bedrock/did-context": "^6.0.0",
|
|
53
|
+
"@bedrock/did-io": "^10.3.1",
|
|
54
|
+
"@bedrock/express": "^8.3.1",
|
|
55
|
+
"@bedrock/https-agent": "^4.1.0",
|
|
56
|
+
"@bedrock/jsonld-document-loader": "^5.1.0",
|
|
57
|
+
"@bedrock/mongodb": "^10.2.0",
|
|
58
|
+
"@bedrock/multikey-context": "^3.0.0",
|
|
59
|
+
"@bedrock/security-context": "^9.0.0",
|
|
60
|
+
"@bedrock/service-agent": "^9.0.2",
|
|
61
|
+
"@bedrock/service-context-store": "^12.0.0",
|
|
62
|
+
"@bedrock/service-core": "^10.0.0",
|
|
63
|
+
"@bedrock/validation": "^7.1.0",
|
|
64
|
+
"@bedrock/vc-revocation-list-context": "^5.0.0",
|
|
65
|
+
"@bedrock/vc-status-list-context": "^6.0.2",
|
|
66
|
+
"@bedrock/veres-one-context": "^16.0.0"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
68
|
-
"eslint": "^8.
|
|
69
|
-
"eslint-config-digitalbazaar": "^5.0
|
|
70
|
-
"eslint-plugin-jsdoc": "^48.0
|
|
71
|
-
"eslint-plugin-unicorn": "^
|
|
72
|
-
"jsdoc": "^4.0.2",
|
|
73
|
-
"jsdoc-to-markdown": "^8.0.0"
|
|
69
|
+
"eslint": "^8.57.0",
|
|
70
|
+
"eslint-config-digitalbazaar": "^5.2.0",
|
|
71
|
+
"eslint-plugin-jsdoc": "^48.11.0",
|
|
72
|
+
"eslint-plugin-unicorn": "^55.0.0"
|
|
74
73
|
},
|
|
75
74
|
"engines": {
|
|
76
75
|
"node": ">=18"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Copyright (c) 2022 Digital Bazaar, Inc. All rights reserved.
|
|
2
|
+
* Copyright (c) 2022-2024 Digital Bazaar, Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
const context = {
|
|
5
5
|
title: '@context',
|
|
@@ -10,6 +10,42 @@ const context = {
|
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
export const verifyOptions = {
|
|
14
|
+
title: 'Verify Options',
|
|
15
|
+
type: 'object',
|
|
16
|
+
oneOf: [{
|
|
17
|
+
required: ['didResolver']
|
|
18
|
+
}, {
|
|
19
|
+
required: ['documentLoader']
|
|
20
|
+
}],
|
|
21
|
+
additionalProperties: false,
|
|
22
|
+
properties: {
|
|
23
|
+
didResolver: {
|
|
24
|
+
title: 'DID Resolver',
|
|
25
|
+
type: 'object',
|
|
26
|
+
required: ['url'],
|
|
27
|
+
additionalProperties: false,
|
|
28
|
+
properties: {
|
|
29
|
+
url: {
|
|
30
|
+
type: 'string',
|
|
31
|
+
pattern: '^https://[^.]+.[^.]+'
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
documentLoader: {
|
|
36
|
+
title: 'Document Loader',
|
|
37
|
+
type: 'object',
|
|
38
|
+
required: ['allowRemoteContexts'],
|
|
39
|
+
additionalProperties: false,
|
|
40
|
+
properties: {
|
|
41
|
+
allowRemoteContexts: {
|
|
42
|
+
type: 'boolean'
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
13
49
|
export const createChallengeBody = {
|
|
14
50
|
title: 'Create Challenge Body',
|
|
15
51
|
type: 'object',
|