@bedrock/kms-http 13.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.
@@ -0,0 +1,143 @@
1
+ /*!
2
+ * Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
3
+ */
4
+ import * as helpers from './helpers.js';
5
+ import {httpsAgent} from '@bedrock/https-agent';
6
+ import {createRequire} from 'module';
7
+ const require = createRequire(import.meta.url);
8
+ const {CapabilityAgent, KmsClient, KeystoreAgent} =
9
+ require('@digitalbazaar/webkms-client');
10
+
11
+ const ZCAP_ROOT_PREFIX = 'urn:zcap:root:';
12
+
13
+ describe('revocations API with ipAllowList', () => {
14
+ let aliceCapabilityAgent;
15
+ let aliceKeystoreConfig;
16
+ let aliceKeystoreAgent;
17
+ let bobCapabilityAgent;
18
+ let carolCapabilityAgent;
19
+
20
+ before(async () => {
21
+ const secret = '40762a17-1696-428f-a2b2-ddf9fe9b4987';
22
+ const handle = 'alice';
23
+ aliceCapabilityAgent = await CapabilityAgent.fromSecret({secret, handle});
24
+
25
+ aliceKeystoreConfig = await helpers.createKeystore(
26
+ {capabilityAgent: aliceCapabilityAgent});
27
+ const kmsClient = new KmsClient({httpsAgent});
28
+ aliceKeystoreAgent = new KeystoreAgent({
29
+ capabilityAgent: aliceCapabilityAgent,
30
+ keystoreId: aliceKeystoreConfig.id,
31
+ kmsClient,
32
+ });
33
+ });
34
+
35
+ // generate a capability agent for Bob
36
+ before(async () => {
37
+ const secret = '34f2afd1-34ef-4d46-a998-cdc5462dc0d2';
38
+ const handle = 'bob';
39
+ bobCapabilityAgent = await CapabilityAgent.fromSecret({secret, handle});
40
+ });
41
+
42
+ // generate a capability agent for Carol
43
+ before(async () => {
44
+ const secret = 'ae806cd9-2765-4232-b955-01e1024ac032';
45
+ const handle = 'carol';
46
+ carolCapabilityAgent = await CapabilityAgent.fromSecret({secret, handle});
47
+ });
48
+
49
+ it('returns NotAllowedError for invalid source IP', async () => {
50
+ // first generate a new key for alice; use a did:key ID for its public ID
51
+ const aliceKey = await aliceKeystoreAgent.generateKey({
52
+ type: 'asymmetric',
53
+ publicAliasTemplate: 'did:key:{publicKeyMultibase}#${publicKeyMultibase}'
54
+ });
55
+
56
+ // next, delegate authority to bob to use alice's key
57
+ const rootCapability = ZCAP_ROOT_PREFIX +
58
+ encodeURIComponent(aliceKeystoreAgent.keystoreId);
59
+ const bobZcap = await helpers.delegate({
60
+ parentCapability: rootCapability,
61
+ controller: bobCapabilityAgent.id,
62
+ invocationTarget: aliceKey.kmsId,
63
+ allowedAction: 'sign',
64
+ delegator: aliceCapabilityAgent
65
+ });
66
+
67
+ // Bob now uses his delegated authority to sign a document with Alice's key
68
+ const bobSignedDocument = await helpers.signWithDelegatedKey({
69
+ capability: bobZcap,
70
+ // bob signs the invocation to use alice's key (and alice's key will
71
+ // sign the document)
72
+ invocationSigner: bobCapabilityAgent.getSigner()
73
+ });
74
+
75
+ bobSignedDocument.should.have.property('@context');
76
+ bobSignedDocument.should.have.property('example:foo');
77
+ bobSignedDocument.should.have.property('proof');
78
+ bobSignedDocument.proof.should.have.property('verificationMethod');
79
+ // the document was ultimately signed with alice's key
80
+ bobSignedDocument.proof.verificationMethod.should.equal(aliceKey.id);
81
+
82
+ // Bob has successfully used alice's key to sign a document!
83
+
84
+ // Bob now delegates the use of Alice's key to Carol
85
+ const carolZcap = await helpers.delegate({
86
+ parentCapability: bobZcap,
87
+ controller: carolCapabilityAgent.id,
88
+ delegator: bobCapabilityAgent
89
+ });
90
+
91
+ // Bob would then store record of the delegation to Carol in an EDV
92
+
93
+ // demonstrate that Carol can also sign with Alice's key
94
+ const carolSignedDocument = await helpers.signWithDelegatedKey({
95
+ capability: carolZcap,
96
+ // carol signs the invocation to use alice's key (and alice's key
97
+ // will sign the document)
98
+ invocationSigner: carolCapabilityAgent.getSigner()
99
+ });
100
+ carolSignedDocument.should.have.property('@context');
101
+ carolSignedDocument.should.have.property('example:foo');
102
+ carolSignedDocument.should.have.property('proof');
103
+ carolSignedDocument.proof.should.have.property('verificationMethod');
104
+ // the document was ultimately signed with alice's key
105
+ carolSignedDocument.proof.verificationMethod.should.equal(aliceKey.id);
106
+
107
+ // update Alice's keystore config to include ipAllowList
108
+ aliceKeystoreConfig.sequence++;
109
+ aliceKeystoreConfig.ipAllowList = ['8.8.8.8/32'];
110
+
111
+ const {config} = await aliceKeystoreAgent.updateConfig(
112
+ {config: aliceKeystoreConfig});
113
+ config.should.eql(aliceKeystoreConfig);
114
+
115
+ // Bob now submits a revocation to revoke the capability he gave to Carol.
116
+
117
+ // in practice bob is going to locate the capability he gave to carol
118
+ // by way of bedrock-web-zcap-storage
119
+
120
+ // this adds a revocation for Carol's `sign` capability on Alice's
121
+ // kms system
122
+
123
+ // this request should fails because the request does not originate from
124
+ // an IP in the `ipAllowList` on Alice's keystore.
125
+ let err;
126
+ let result;
127
+ try {
128
+ result = await helpers.revokeDelegatedCapability({
129
+ // the `sign` capability that Bob gave to Carol
130
+ capabilityToRevoke: carolZcap,
131
+ // bob is revoking the capability he gave to carol
132
+ invocationSigner: bobCapabilityAgent.getSigner()
133
+ });
134
+ } catch(e) {
135
+ err = e;
136
+ }
137
+ should.not.exist(result);
138
+ should.exist(err);
139
+ err.status.should.equal(403);
140
+ err.data.type.should.equal('NotAllowedError');
141
+ err.data.message.should.contain('Source IP');
142
+ });
143
+ });
@@ -0,0 +1,180 @@
1
+ /*!
2
+ * Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
3
+ */
4
+ import * as helpers from './helpers.js';
5
+ import {httpsAgent} from '@bedrock/https-agent';
6
+ import {createRequire} from 'module';
7
+ const require = createRequire(import.meta.url);
8
+ const {CapabilityAgent, KmsClient, KeystoreAgent} =
9
+ require('@digitalbazaar/webkms-client');
10
+ const {httpClient, DEFAULT_HEADERS} = require('@digitalbazaar/http-client');
11
+ const {signCapabilityInvocation} = require(
12
+ '@digitalbazaar/http-signature-zcap-invoke');
13
+
14
+ describe('generateKey', () => {
15
+ it('generates a key', async () => {
16
+ const secret = '0628a44e-7599-11ec-989d-10bf48838a41';
17
+ const handle = 'testKey';
18
+ const keystoreAgent = await helpers.createKeystoreAgent(
19
+ {handle, secret});
20
+ let err;
21
+ let result;
22
+ try {
23
+ result = await keystoreAgent.generateKey({type: 'hmac'});
24
+ } catch(e) {
25
+ err = e;
26
+ }
27
+ assertNoError(err);
28
+ should.exist(result);
29
+ result.should.include.keys([
30
+ 'algorithm', 'capability', 'id', 'type', 'invocationSigner', 'kmsClient'
31
+ ]);
32
+ });
33
+ it('generates a key with ipAllowList', async () => {
34
+ // source of requests in the test suite are from 127.0.0.1
35
+ const secret = '22612679-05ce-4ffd-bf58-22b3c4bc1314';
36
+ const handle = 'testKeyAllowList';
37
+ const ipAllowList = ['127.0.0.1/32'];
38
+ const keystoreAgent = await helpers.createKeystoreAgent(
39
+ {handle, ipAllowList, secret});
40
+ let err;
41
+ let result;
42
+ try {
43
+ result = await keystoreAgent.generateKey({type: 'hmac'});
44
+ } catch(e) {
45
+ err = e;
46
+ }
47
+ assertNoError(err);
48
+ should.exist(result);
49
+ result.should.include.keys([
50
+ 'algorithm', 'capability', 'id', 'type', 'invocationSigner', 'kmsClient'
51
+ ]);
52
+ });
53
+ it('generates a key with x-forwarded-for header', async () => {
54
+ // source of requests in the test suite are from 127.0.0.1
55
+ const secret = '22612679-05ce-4ffd-bf58-22b3c4bc1314';
56
+ const handle = 'testKeyAllowList';
57
+ const ipAllowList = ['8.8.8.8/32'];
58
+ const keystoreAgent = await helpers.createKeystoreAgent({
59
+ handle, ipAllowList, secret, kmsClientHeaders: {
60
+ 'x-forwarded-for': '8.8.8.8',
61
+ }
62
+ });
63
+ let err;
64
+ let result;
65
+ try {
66
+ result = await keystoreAgent.generateKey({type: 'hmac'});
67
+ } catch(e) {
68
+ err = e;
69
+ }
70
+ assertNoError(err);
71
+ should.exist(result);
72
+ result.should.include.keys([
73
+ 'algorithm', 'capability', 'id', 'type', 'invocationSigner', 'kmsClient'
74
+ ]);
75
+ });
76
+ it('generates a key with multiple ipAllowList entries', async () => {
77
+ // source of requests in the test suite are from 127.0.0.1
78
+ const secret = 'efef2772-f7aa-4d25-9eac-6228f2a64b3b';
79
+ const handle = 'testKeyAllowList';
80
+ const ipAllowList = ['8.8.8.8/32', '127.0.0.1/32'];
81
+ const keystoreAgent = await helpers.createKeystoreAgent(
82
+ {handle, ipAllowList, secret});
83
+ let err;
84
+ let result;
85
+ try {
86
+ result = await keystoreAgent.generateKey({type: 'hmac'});
87
+ } catch(e) {
88
+ err = e;
89
+ }
90
+ assertNoError(err);
91
+ should.exist(result);
92
+ result.should.include.keys([
93
+ 'algorithm', 'capability', 'id', 'type', 'invocationSigner', 'kmsClient'
94
+ ]);
95
+ });
96
+ it('returns NotAllowedError for invalid source IP', async () => {
97
+ // source of requests in the test suite are from 127.0.0.1
98
+ const secret = '860a6bc8-74e1-4dfd-b701-7efc2a596e91';
99
+ const handle = 'testKeyAllowList';
100
+ const ipAllowList = ['8.8.8.8/32'];
101
+ const keystoreAgent = await helpers.createKeystoreAgent(
102
+ {handle, ipAllowList, secret});
103
+
104
+ let err;
105
+ let result;
106
+ try {
107
+ result = await keystoreAgent.generateKey({type: 'hmac'});
108
+ } catch(e) {
109
+ err = e;
110
+ }
111
+ should.exist(err);
112
+ should.not.exist(result);
113
+ err.status.should.equal(403);
114
+ err.data.type.should.equal('NotAllowedError');
115
+ });
116
+ it('generates a key with "maxCapabilityChainLength=1"', async () => {
117
+ const secret = '0ad59134-7583-11ec-b16e-10bf48838a41';
118
+ const handle = 'testKeyMaxCapabilityChainLength';
119
+ const keystoreAgent = await helpers.createKeystoreAgent(
120
+ {handle, secret});
121
+ let err;
122
+ let result;
123
+ try {
124
+ result = await keystoreAgent.generateKey({
125
+ type: 'asymmetric', maxCapabilityChainLength: 1
126
+ });
127
+ } catch(e) {
128
+ err = e;
129
+ }
130
+ assertNoError(err);
131
+ should.exist(result);
132
+ result.should.include.keys([
133
+ 'capability', 'id', 'type', 'invocationSigner', 'kmsClient', 'kmsId'
134
+ ]);
135
+ });
136
+ }); // generateKey with ipAllowList
137
+
138
+ describe('get public key description', () => {
139
+ it('gets public key description', async () => {
140
+ const secret = '34f2afd1-34ef-4d46-a998-cdc5462dc0d2';
141
+ const handle = 'bobKey';
142
+ const capabilityAgent = await CapabilityAgent.fromSecret(
143
+ {secret, handle});
144
+ const {id: keystoreId} = await helpers.createKeystore(
145
+ {capabilityAgent});
146
+ const kmsClient = new KmsClient({keystoreId, httpsAgent});
147
+ let keystoreAgent;
148
+ try {
149
+ keystoreAgent = new KeystoreAgent(
150
+ {capabilityAgent, keystoreId, kmsClient});
151
+ } catch(e) {
152
+ assertNoError(e);
153
+ }
154
+ const key = await keystoreAgent.generateKey({type: 'asymmetric'});
155
+
156
+ const url = key.id;
157
+ const headers = await signCapabilityInvocation({
158
+ url, method: 'get',
159
+ headers: DEFAULT_HEADERS,
160
+ capability: 'urn:zcap:root:' + encodeURIComponent(url),
161
+ invocationSigner: capabilityAgent.getSigner(),
162
+ capabilityAction: 'read'
163
+ });
164
+
165
+ let err;
166
+ let result;
167
+ try {
168
+ result = await httpClient.get(url, {agent: httpsAgent, headers});
169
+ } catch(e) {
170
+ err = e;
171
+ }
172
+ assertNoError(err);
173
+ should.exist(result);
174
+ result.data.should.include.keys([
175
+ '@context', 'id', 'type', 'publicKeyMultibase', 'controller'
176
+ ]);
177
+ result.data.id.should.equal(key.id);
178
+ result.data.type.should.equal(key.type);
179
+ });
180
+ });
@@ -0,0 +1,178 @@
1
+ /*!
2
+ * Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
3
+ */
4
+ import * as bedrock from '@bedrock/core';
5
+ import * as helpers from './helpers.js';
6
+ import {httpsAgent} from '@bedrock/https-agent';
7
+ import {createRequire} from 'module';
8
+ import pMap from 'p-map';
9
+ const require = createRequire(import.meta.url);
10
+ const {CapabilityAgent, Hmac, KmsClient} = require(
11
+ '@digitalbazaar/webkms-client');
12
+
13
+ const {util: {uuid}} = bedrock;
14
+
15
+ const ZCAP_ROOT_PREFIX = 'urn:zcap:root:';
16
+
17
+ describe('bedrock-kms-http HMAC operations', () => {
18
+ describe('Sha256HmacKey2019', () => {
19
+ let hmac;
20
+ before(async () => {
21
+ const secret = 'b07e6b31-d910-438e-9a5f-08d945a5f676';
22
+ const handle = 'testKey1';
23
+ const keystoreAgent = await helpers.createKeystoreAgent({handle, secret});
24
+ hmac = await keystoreAgent.generateKey({type: 'hmac'});
25
+ });
26
+ it('successfully signs', async () => {
27
+ const data = new TextEncoder('utf-8').encode('hello');
28
+ let err;
29
+ let result;
30
+ try {
31
+ result = await hmac.sign({data});
32
+ } catch(e) {
33
+ err = e;
34
+ }
35
+ assertNoError(err);
36
+ should.exist(result);
37
+ result.should.be.a('Uint8Array');
38
+ });
39
+ }); // end Sha256HmacKey2019
40
+
41
+ describe('Sha256HmacKey2019 with ipAllowList', () => {
42
+ it('successfully signs', async () => {
43
+ const secret = '22612679-05ce-4ffd-bf58-22b3c4bc1314';
44
+ const handle = 'testKeyAllowList';
45
+ const ipAllowList = ['127.0.0.1/32'];
46
+ const keystoreAgent = await helpers.createKeystoreAgent(
47
+ {handle, ipAllowList, secret});
48
+ const hmac = await keystoreAgent.generateKey({type: 'hmac'});
49
+ const data = new TextEncoder('utf-8').encode('hello');
50
+ let err;
51
+ let result;
52
+ try {
53
+ result = await hmac.sign({data});
54
+ } catch(e) {
55
+ err = e;
56
+ }
57
+ assertNoError(err);
58
+ should.exist(result);
59
+ result.should.be.a('Uint8Array');
60
+ });
61
+ it('fails when "maxCapabilityChainLength" is exceeded', async () => {
62
+ const secret = '22612679-05ce-4ffd-bf58-22b3c4bc1314';
63
+ const handle = 'testKeyMaxCapabilityChainLength';
64
+ const keystoreAgent = await helpers.createKeystoreAgent(
65
+ {handle, secret});
66
+ const hmac = await keystoreAgent.generateKey({
67
+ type: 'hmac', maxCapabilityChainLength: 1
68
+ });
69
+ const data = new TextEncoder('utf-8').encode('hello');
70
+
71
+ let err;
72
+ let result;
73
+ try {
74
+ result = await hmac.sign({data});
75
+ } catch(e) {
76
+ err = e;
77
+ }
78
+ assertNoError(err);
79
+ should.exist(result);
80
+ result.should.be.a('Uint8Array');
81
+
82
+ // now delegate and try to invoke
83
+ const delegatee = await CapabilityAgent.fromSecret({
84
+ secret: uuid(),
85
+ handle: uuid()
86
+ });
87
+ const rootCapability = ZCAP_ROOT_PREFIX +
88
+ encodeURIComponent(keystoreAgent.keystoreId);
89
+ const delegatedZcap = await helpers.delegate({
90
+ parentCapability: rootCapability,
91
+ controller: delegatee.id,
92
+ invocationTarget: hmac.id,
93
+ allowedAction: 'sign',
94
+ delegator: keystoreAgent.capabilityAgent
95
+ });
96
+ const hmac2 = await Hmac.fromCapability({
97
+ capability: delegatedZcap,
98
+ invocationSigner: delegatee.getSigner(),
99
+ kmsClient: new KmsClient({httpsAgent})
100
+ });
101
+
102
+ let err2;
103
+ let result2;
104
+ try {
105
+ result2 = await hmac2.sign({data});
106
+ } catch(e) {
107
+ err2 = e;
108
+ }
109
+ should.exist(err2);
110
+ should.not.exist(result2);
111
+ should.exist(err2.data);
112
+ err2.data.type.should.equal('NotAllowedError');
113
+ should.exist(err2.data.cause);
114
+ err2.data.cause.message.should.equal(
115
+ 'Maximum zcap invocation capability chain length (1) exceeded.');
116
+ });
117
+ it('successfully signs with x-forwarded-for header', async () => {
118
+ const secret = '2726f62d-31bb-4688-b54a-1a0b4e50329f';
119
+ const handle = 'testKeyAllowList';
120
+ const ipAllowList = ['8.8.8.8/32'];
121
+ const keystoreAgent = await helpers.createKeystoreAgent({
122
+ handle, ipAllowList, secret, kmsClientHeaders: {
123
+ 'x-forwarded-for': '8.8.8.8',
124
+ }
125
+ });
126
+ const hmac = await keystoreAgent.generateKey({type: 'hmac'});
127
+ const data = new TextEncoder('utf-8').encode('hello');
128
+ let err;
129
+ let result;
130
+ try {
131
+ result = await hmac.sign({data});
132
+ } catch(e) {
133
+ err = e;
134
+ }
135
+ assertNoError(err);
136
+ should.exist(result);
137
+ result.should.be.a('Uint8Array');
138
+ });
139
+ }); // end Sha256HmacKey2019 with ipAllowList
140
+
141
+ describe('bulk operations', () => {
142
+ const operationCount = 1000;
143
+ const vData = [];
144
+ let hmac;
145
+
146
+ before(async () => {
147
+ const secret = '9b5a0a63-aac2-447c-a60a-8cc79b46418d';
148
+ const handle = 'testKeyBulk';
149
+ const keystoreAgent = await helpers.createKeystoreAgent({handle, secret});
150
+ hmac = await keystoreAgent.generateKey({type: 'hmac'});
151
+ });
152
+ before(async () => {
153
+ for(let i = 0; i < operationCount; ++i) {
154
+ // uuids are 37 chars long, * 30 is ~1KiB
155
+ let v = '';
156
+ for(let n = 0; n < 30; ++n) {
157
+ v += uuid();
158
+ }
159
+ vData.push(new TextEncoder('utf-8').encode(v));
160
+ }
161
+ });
162
+ it(`performs ${operationCount} signatures`, async function() {
163
+ this.timeout(0);
164
+ let result;
165
+ let err;
166
+ try {
167
+ result = await pMap(
168
+ vData, data => hmac.sign({data}), {concurrency: 30});
169
+ } catch(e) {
170
+ err = e;
171
+ }
172
+ assertNoError(err);
173
+ should.exist(result);
174
+ result.should.be.an('array');
175
+ result.should.have.length(operationCount);
176
+ });
177
+ }); // end bulk operations
178
+ });
@@ -0,0 +1,163 @@
1
+ /*
2
+ * Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
3
+ */
4
+ import * as bedrock from '@bedrock/core';
5
+ import {createRequire} from 'module';
6
+ import {documentLoader} from '@bedrock/jsonld-document-loader';
7
+ import {getAppIdentity} from '@bedrock/app-identity';
8
+ import {httpsAgent} from '@bedrock/https-agent';
9
+ import jsigs from 'jsonld-signatures';
10
+ const require = createRequire(import.meta.url);
11
+ const {AsymmetricKey, CapabilityAgent, KeystoreAgent, KmsClient} =
12
+ require('@digitalbazaar/webkms-client');
13
+ const {
14
+ CapabilityDelegation,
15
+ constants: zcapConstants
16
+ } = require('@digitalbazaar/zcap');
17
+ const {Ed25519Signature2020} = require('@digitalbazaar/ed25519-signature-2020');
18
+ const {ZcapClient} = require('@digitalbazaar/ezcap');
19
+
20
+ const {purposes: {AssertionProofPurpose}} = jsigs;
21
+ const {util: {uuid}} = bedrock;
22
+ const {ZCAP_CONTEXT_URL} = zcapConstants;
23
+
24
+ export async function createMeter({capabilityAgent} = {}) {
25
+ // create signer using the application's capability invocation key
26
+ const {keys: {capabilityInvocationKey}} = getAppIdentity();
27
+
28
+ const zcapClient = new ZcapClient({
29
+ agent: httpsAgent,
30
+ invocationSigner: capabilityInvocationKey.signer(),
31
+ SuiteClass: Ed25519Signature2020
32
+ });
33
+ // create a meter
34
+ const meterService = `${bedrock.config.server.baseUri}/meters`;
35
+ let meter = {
36
+ controller: capabilityAgent.id,
37
+ product: {
38
+ // mock ID for webkms service product
39
+ id: 'urn:uuid:80a82316-e8c2-11eb-9570-10bf48838a41'
40
+ }
41
+ };
42
+ ({data: {meter}} = await zcapClient.write({url: meterService, json: meter}));
43
+
44
+ // return full meter ID
45
+ const {id} = meter;
46
+ return {id: `${meterService}/${id}`};
47
+ }
48
+
49
+ export async function createKeystore({
50
+ capabilityAgent, ipAllowList, referenceId, meterId,
51
+ kmsBaseUrl = `${bedrock.config.server.baseUri}/kms`,
52
+ kmsModule = 'ssm-v1',
53
+ }) {
54
+ if(!meterId) {
55
+ // create a meter for the keystore
56
+ ({id: meterId} = await createMeter({capabilityAgent}));
57
+ }
58
+
59
+ // create keystore
60
+ const config = {
61
+ sequence: 0,
62
+ controller: capabilityAgent.id,
63
+ meterId,
64
+ kmsModule
65
+ };
66
+ if(referenceId) {
67
+ config.referenceId = referenceId;
68
+ }
69
+ if(ipAllowList) {
70
+ config.ipAllowList = ipAllowList;
71
+ }
72
+
73
+ return KmsClient.createKeystore({
74
+ url: `${kmsBaseUrl}/keystores`,
75
+ config,
76
+ invocationSigner: capabilityAgent.getSigner(),
77
+ httpsAgent
78
+ });
79
+ }
80
+
81
+ export async function createKeystoreAgent({
82
+ handle, ipAllowList, secret, kmsClientHeaders = {}
83
+ }) {
84
+ const capabilityAgent = await CapabilityAgent.fromSecret({secret, handle});
85
+
86
+ let err;
87
+ let keystore;
88
+ try {
89
+ keystore = await createKeystore({capabilityAgent, ipAllowList});
90
+ } catch(e) {
91
+ err = e;
92
+ }
93
+ assertNoError(err);
94
+
95
+ // create kmsClient only required because we need to use httpsAgent
96
+ // that accepts self-signed certs used in test suite
97
+ const kmsClient = new KmsClient(
98
+ {httpsAgent, defaultHeaders: kmsClientHeaders});
99
+ const keystoreAgent = new KeystoreAgent({
100
+ capabilityAgent,
101
+ keystoreId: keystore.id,
102
+ kmsClient
103
+ });
104
+
105
+ return keystoreAgent;
106
+ }
107
+
108
+ export async function getKeystore({id, capabilityAgent}) {
109
+ const kmsClient = new KmsClient({keystoreId: id, httpsAgent});
110
+ const invocationSigner = capabilityAgent.getSigner();
111
+ return kmsClient.getKeystore({invocationSigner});
112
+ }
113
+
114
+ export async function delegate({
115
+ parentCapability, controller, invocationTarget, expires, allowedAction,
116
+ delegator, purposeOptions = {}
117
+ }) {
118
+ const newCapability = {
119
+ '@context': ZCAP_CONTEXT_URL,
120
+ id: `urn:zcap:${uuid()}`,
121
+ controller,
122
+ parentCapability: parentCapability.id || parentCapability,
123
+ invocationTarget: invocationTarget || parentCapability.invocationTarget,
124
+ expires: expires || parentCapability.expires ||
125
+ new Date(Date.now() + 5000).toISOString().slice(0, -5) + 'Z',
126
+ allowedAction: allowedAction || parentCapability.allowedAction
127
+ };
128
+ // attach capability delegation proof
129
+ return jsigs.sign(newCapability, {
130
+ documentLoader,
131
+ purpose: new CapabilityDelegation({parentCapability, ...purposeOptions}),
132
+ suite: new Ed25519Signature2020({signer: delegator.getSigner()}),
133
+ });
134
+ }
135
+
136
+ export async function revokeDelegatedCapability({
137
+ capabilityToRevoke, invocationSigner
138
+ }) {
139
+ const kmsClient = new KmsClient({httpsAgent});
140
+ await kmsClient.revokeCapability({
141
+ capabilityToRevoke,
142
+ invocationSigner
143
+ });
144
+ }
145
+
146
+ export async function signWithDelegatedKey({
147
+ capability, doc, invocationSigner
148
+ }) {
149
+ const delegatedSigningKey = await AsymmetricKey.fromCapability({
150
+ capability,
151
+ invocationSigner,
152
+ kmsClient: new KmsClient({httpsAgent})
153
+ });
154
+ const suite = new Ed25519Signature2020({signer: delegatedSigningKey});
155
+
156
+ doc = doc || {'example:foo': 'test'};
157
+
158
+ return jsigs.sign(doc, {
159
+ documentLoader,
160
+ purpose: new AssertionProofPurpose(),
161
+ suite
162
+ });
163
+ }
@@ -0,0 +1,40 @@
1
+ /*!
2
+ * Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
3
+ */
4
+ import {createRequire} from 'module';
5
+ const require = createRequire(import.meta.url);
6
+ const {constants: zcapConstants} = require('@digitalbazaar/zcap');
7
+
8
+ const {ZCAP_CONTEXT_URL} = zcapConstants;
9
+
10
+ export const mockData = {};
11
+
12
+ const zcaps = mockData.zcaps = {};
13
+
14
+ // Note: This zcap is only used to check JSON schema validators, it does not
15
+ // have valid proofs.
16
+ const zcap0 = {
17
+ '@context': ZCAP_CONTEXT_URL,
18
+ id: 'urn:zcap:z19vWhR8EsNbWqvazp5bg6BTu',
19
+ controller: 'did:key:z6Mkkt1BWYLPAAXwYBwyVHAZkL94tgT8QbQv2SUxeW1U3DaG',
20
+ expires: '2022-01-08T17:27:15Z',
21
+ invocationTarget: 'https://bedrock.localhost:18443/kms' +
22
+ '/keystores/z1AAWWM7Zd4YyyV3NfaCqFuzQ/keys/z19wxodgv1UhrToQMvSxGhQG6',
23
+ parentCapability: 'urn:zcap:root:' + encodeURIComponent(
24
+ 'https://bedrock.localhost:18443/kms/keystores/z1AAWWM7Zd4YyyV3NfaCqFuzQ'),
25
+ allowedAction: 'sign',
26
+ proof: {
27
+ type: 'Ed25519Signature2020',
28
+ created: '2020-02-27T21:22:48Z',
29
+ verificationMethod: 'did:key:z6MkkrtV7wnBpXKBtiZjxaSghCo8ttb5kZUJTk8bEwT' +
30
+ 'TTYvg#z6MkkrtV7wnBpXKBtiZjxaSghCo8ttb5kZUJTk8bEwTTTYvg',
31
+ proofPurpose: 'capabilityDelegation',
32
+ capabilityChain: [
33
+ 'urn:zcap:root:' + encodeURIComponent(
34
+ 'https://bedrock.localhost:18443/kms/keystores/z1AAWWM7Zd4YyyV3NfaCqFu')
35
+ ],
36
+ proofValue: 'eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19'
37
+ }
38
+ };
39
+
40
+ zcaps.zero = zcap0;