@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Bedrock VC Verifier API module _(@bedrock/vc-verifier)_
2
2
 
3
- [![Build Status](https://img.shields.io/github/workflow/status/digitalbazaar/bedrock-vc-verifier/Bedrock%20Node.js%20CI)](https://github.com/digitalbazaar/bedrock-vc-verifier/actions?query=workflow%3A%22Bedrock+Node.js+CI%22)
3
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/digitalbazaar/bedrock-vc-verifier/main.yml)](https://github.com/digitalbazaar/bedrock-vc-verifier/actions/workflows/main.yml)
4
4
  [![NPM Version](https://img.shields.io/npm/v/bedrock-vc-verifier.svg)](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 verifiers to fetch `http` documents from the Web
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 verifiers to fetch `https` documents from the Web
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
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
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
- // resolve all DID URLs through did-io
57
+ // handle DID URLs...
57
58
  if(url.startsWith('did:')) {
58
- const document = await didIo.get({url});
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
- if(url.startsWith('http') && e.name === 'NotFoundError' && webLoader) {
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-2022 Digital Bazaar, Inc. All rights reserved.
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": "19.1.0",
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.1.0",
29
- "@digitalbazaar/data-integrity": "^2.0.0",
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.1",
32
- "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.2.0",
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.0.0",
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.1",
37
- "@digitalbazaar/vc": "^6.0.0",
38
- "@digitalbazaar/vc-revocation-list": "^6.0.0",
39
- "@digitalbazaar/vc-status-list": "^7.0.0",
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.0",
42
+ "body-parser": "^1.20.2",
43
43
  "cors": "^2.8.5",
44
- "serialize-error": "^11.0.0"
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.0.1",
49
- "@bedrock/credentials-context": "^4.0.0",
50
- "@bedrock/data-integrity-context": "^3.0.0",
51
- "@bedrock/did-context": "^5.0.0",
52
- "@bedrock/did-io": "^10.2.0",
53
- "@bedrock/express": "^8.0.0",
54
- "@bedrock/https-agent": "^4.0.0",
55
- "@bedrock/jsonld-document-loader": "^4.0.0",
56
- "@bedrock/mongodb": "^10.0.0",
57
- "@bedrock/multikey-context": "^2.0.0",
58
- "@bedrock/security-context": "^8.0.0",
59
- "@bedrock/service-agent": "^8.0.0",
60
- "@bedrock/service-context-store": "^11.0.0",
61
- "@bedrock/service-core": "^9.0.0",
62
- "@bedrock/validation": "^7.0.0",
63
- "@bedrock/vc-revocation-list-context": "^4.0.0",
64
- "@bedrock/vc-status-list-context": "^5.0.0",
65
- "@bedrock/veres-one-context": "^15.0.0"
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.47.0",
69
- "eslint-config-digitalbazaar": "^5.0.1",
70
- "eslint-plugin-jsdoc": "^48.0.3",
71
- "eslint-plugin-unicorn": "^50.0.1",
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',