Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,50 @@ const SocksProxyAgent = require('socks-proxy-agent');
const agent = new SocksProxyAgent(`socks://127.0.0.1:${socks4Port}`, true);
const options = {
apiVersion: 'v1',
rpOptions: {
requestOptions: {
agent,
},
};

const vault = require('node-vault')(options);
```

## Custom SSL/TLS Configuration

If you encounter SSL errors after upgrading to Node 18+ (e.g., `EPROTO` errors related to
`unsafe legacy renegotiation disabled`), you can pass SSL/TLS options via `requestOptions`
or `rpDefaults` when initializing the client:

```javascript
const vault = require('node-vault')({
apiVersion: 'v1',
endpoint: 'https://vault.example.com:8200',
token: 'MY_TOKEN',
requestOptions: {
agentOptions: {
securityOptions: 'SSL_OP_LEGACY_SERVER_CONNECT',
},
},
});
```

The `requestOptions` object is passed through to the underlying HTTP library
([postman-request](https://www.npmjs.com/package/postman-request)) for every request. You can
use it to configure any supported request option, including `agentOptions`, custom `headers`,
or a custom `agent`.

You can also pass request options per-call to any method:

```javascript
vault.read('secret/hello', {
agentOptions: {
securityOptions: 'SSL_OP_LEGACY_SERVER_CONNECT',
},
});
```

See [example/pass_request_options.js](example/pass_request_options.js) for more examples.

[![Backers](https://opencollective.com/node-vault/tiers/backers.svg?avatarHeight=80&width=600)](https://opencollective.com/node-vault/contribute)

[examples]: https://github.com/nodevault/node-vault/tree/master/example
Expand Down
24 changes: 18 additions & 6 deletions example/pass_request_options.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,32 @@

process.env.DEBUG = 'node-vault'; // switch on debug mode

const vault = require('./../src/index')();
// Pass request options at initialization time.
// These options are forwarded to postman-request for every request.
const vault = require('./../src/index')({
requestOptions: {
agentOptions: {
cert: '<path-to-cert>',
key: '<path-to-key>',
passphrase: '<your-passphrase>',
securityOptions: 'SSL_OP_NO_SSLv3',
},
},
});

const options = {
// You can also pass (or override) request options per-call.
const perCallOptions = {
headers: {
'X-HELLO': 'world',
},
agentOptions: {
cert: 'mycert',
key: 'mykey',
passphrase: 'password',
cert: '<path-to-cert>',
key: '<path-to-key>',
passphrase: '<your-passphrase>',
securityOptions: 'SSL_OP_NO_SSLv3',
},
};

vault.help('sys/policy', options)
vault.help('sys/policy', perCallOptions)
.then(() => vault.help('sys/mounts'))
.catch((err) => console.error(err.message));
136 changes: 136 additions & 0 deletions test/unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,142 @@ describe('node-vault', () => {
});
});

describe('config.requestOptions forwarding', () => {
let requestWithOpts = null;
let vaultWithOpts = null;

const agentOpts = {
securityOptions: 'SSL_OP_LEGACY_SERVER_CONNECT',
};

function getURIWithOpts(path) {
return [vaultWithOpts.endpoint, vaultWithOpts.apiVersion, path].join('/');
}

function assertRequestWithOpts(thisRequest, params, done) {
return () => {
thisRequest.should.have.calledOnce();
thisRequest.calledWithMatch(params).should.be.ok();
return done();
};
}

beforeEach(() => {
requestWithOpts = sinon.stub();
const resp = sinon.stub();
resp.statusCode = 200;

requestWithOpts.returns({
then(fn) {
return fn(resp);
},
catch(fn) {
return fn();
},
});

vaultWithOpts = index({
endpoint: 'http://localhost:8200',
token: '123',
'request-promise': {
defaults: () => requestWithOpts,
},
requestOptions: {
agentOptions: agentOpts,
},
});
});

it('should forward agentOptions from config.requestOptions in help()', (done) => {
const path = 'sys/policy';
const params = {
method: 'GET',
uri: `${getURIWithOpts(path)}?help=1`,
agentOptions: agentOpts,
};
vaultWithOpts.help(path)
.then(assertRequestWithOpts(requestWithOpts, params, done))
.catch(done);
});

it('should forward agentOptions from config.requestOptions in read()', (done) => {
const path = 'secret/hello';
const params = {
method: 'GET',
uri: getURIWithOpts(path),
agentOptions: agentOpts,
};
vaultWithOpts.read(path)
.then(assertRequestWithOpts(requestWithOpts, params, done))
.catch(done);
});

it('should forward agentOptions from config.requestOptions in write()', (done) => {
const path = 'secret/hello';
const params = {
method: 'POST',
uri: getURIWithOpts(path),
agentOptions: agentOpts,
};
vaultWithOpts.write(path, { value: 'world' })
.then(assertRequestWithOpts(requestWithOpts, params, done))
.catch(done);
});

it('should forward agentOptions from config.requestOptions in delete()', (done) => {
const path = 'secret/hello';
const params = {
method: 'DELETE',
uri: getURIWithOpts(path),
agentOptions: agentOpts,
};
vaultWithOpts.delete(path)
.then(assertRequestWithOpts(requestWithOpts, params, done))
.catch(done);
});

it('should forward agentOptions from config.requestOptions in list()', (done) => {
const path = 'secret/hello';
const params = {
method: 'LIST',
uri: getURIWithOpts(path),
agentOptions: agentOpts,
};
vaultWithOpts.list(path)
.then(assertRequestWithOpts(requestWithOpts, params, done))
.catch(done);
});

it('should forward agentOptions from config.requestOptions in generated functions', (done) => {
const name = 'myTestFunction';
vaultWithOpts.generateFunction(name, {
method: 'GET',
path: '/myroute',
});
const params = {
agentOptions: agentOpts,
};
vaultWithOpts[name]()
.then(assertRequestWithOpts(requestWithOpts, params, done))
.catch(done);
});

it('should allow per-call requestOptions to override config.requestOptions', (done) => {
const path = 'secret/hello';
const overrideOpts = {
securityOptions: 'SSL_OP_NO_SSLv3',
};
const params = {
method: 'GET',
uri: getURIWithOpts(path),
agentOptions: overrideOpts,
};
vaultWithOpts.read(path, { agentOptions: overrideOpts })
.then(assertRequestWithOpts(requestWithOpts, params, done))
.catch(done);
});
});

describe('unwrap(options)', () => {
it('should return original response', (done) => {
const path = 'sys/wrapping/unwrap';
Expand Down
Loading