Skip to content

Commit a0955bd

Browse files
W-A-Jamesdurran
andauthoredAug 22, 2023
fix(NODE-5548): ensure that tlsCertificateKeyFile maps to cert and key (#3819)
Co-authored-by: Durran Jordan <durran@gmail.com>
1 parent bf00e32 commit a0955bd

File tree

3 files changed

+57
-6
lines changed

3 files changed

+57
-6
lines changed
 

‎src/mongo_client.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -435,10 +435,14 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> {
435435

436436
if (options.tls) {
437437
if (typeof options.tlsCAFile === 'string') {
438-
options.ca ??= await fs.readFile(options.tlsCAFile, { encoding: 'utf8' });
438+
options.ca ??= await fs.readFile(options.tlsCAFile);
439439
}
440440
if (typeof options.tlsCertificateKeyFile === 'string') {
441-
options.key ??= await fs.readFile(options.tlsCertificateKeyFile, { encoding: 'utf8' });
441+
if (!options.key || !options.cert) {
442+
const contents = await fs.readFile(options.tlsCertificateKeyFile);
443+
options.key ??= contents;
444+
options.cert ??= contents;
445+
}
442446
}
443447
}
444448
if (typeof options.srvHost === 'string') {
@@ -787,6 +791,7 @@ export interface MongoOptions
787791
* |:----------------------|:----------------------------------------------|:-------------------|
788792
* | `ca` | `tlsCAFile` | `string` |
789793
* | `crl` | N/A | `string` |
794+
* | `cert` | `tlsCertificateKeyFile` | `string` |
790795
* | `key` | `tlsCertificateKeyFile` | `string` |
791796
* | `passphrase` | `tlsCertificateKeyFilePassword` | `string` |
792797
* | `rejectUnauthorized` | `tlsAllowInvalidCertificates` | `boolean` |
@@ -804,9 +809,9 @@ export interface MongoOptions
804809
*
805810
* The files specified by the paths passed in to the `tlsCAFile` and `tlsCertificateKeyFile` fields
806811
* are read lazily on the first call to `MongoClient.connect`. Once these files have been read and
807-
* the `ca` and `key` fields are populated, they will not be read again on subsequent calls to
808-
* `MongoClient.connect`. As a result, until the first call to `MongoClient.connect`, the `ca`
809-
* and `key` fields will be undefined.
812+
* the `ca`, `cert` and `key` fields are populated, they will not be read again on subsequent calls to
813+
* `MongoClient.connect`. As a result, until the first call to `MongoClient.connect`, the `ca`,
814+
* `cert` and `key` fields will be undefined.
810815
*/
811816
tls: boolean;
812817

‎test/manual/tls_support.test.ts

+46-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { expect } from 'chai';
22
import { promises as fs } from 'fs';
33

4-
import { LEGACY_HELLO_COMMAND, MongoClient, type MongoClientOptions } from '../mongodb';
4+
import {
5+
LEGACY_HELLO_COMMAND,
6+
MongoClient,
7+
type MongoClientOptions,
8+
MongoServerSelectionError
9+
} from '../mongodb';
510

611
const REQUIRED_ENV = ['MONGODB_URI', 'SSL_KEY_FILE', 'SSL_CA_FILE'];
712

@@ -51,11 +56,13 @@ describe('TLS Support', function () {
5156
expect(client.options).property('tlsCertificateKeyFile', TLS_CERT_KEY_FILE);
5257
expect(client.options).not.have.property('ca');
5358
expect(client.options).not.have.property('key');
59+
expect(client.options).not.have.property('cert');
5460

5561
await client.connect();
5662

5763
expect(client.options).property('ca').to.exist;
5864
expect(client.options).property('key').to.exist;
65+
expect(client.options).property('cert').to.exist;
5966
});
6067

6168
context('when client has been opened and closed more than once', function () {
@@ -106,6 +113,44 @@ describe('TLS Support', function () {
106113
});
107114
});
108115
});
116+
117+
context('when tlsCertificateKeyFile is provided, but tlsCAFile is missing', () => {
118+
let client: MongoClient;
119+
beforeEach(() => {
120+
client = new MongoClient(CONNECTION_STRING, {
121+
tls: true,
122+
tlsCertificateKeyFile: TLS_CERT_KEY_FILE,
123+
serverSelectionTimeoutMS: 5000,
124+
connectTimeoutMS: 5000
125+
});
126+
});
127+
afterEach(async () => {
128+
if (client) await client.close();
129+
});
130+
131+
it('throws a MongoServerSelectionError', async () => {
132+
const err = await client.connect().catch(e => e);
133+
expect(err).to.be.instanceOf(MongoServerSelectionError);
134+
});
135+
});
136+
137+
context('when tlsCAFile is provided, but tlsCertificateKeyFile is missing', () => {
138+
let client: MongoClient;
139+
beforeEach(() => {
140+
client = new MongoClient(CONNECTION_STRING, {
141+
tls: true,
142+
tlsCAFile: TLS_CA_FILE
143+
});
144+
});
145+
afterEach(async () => {
146+
if (client) await client.close();
147+
});
148+
149+
it('connects without error', async () => {
150+
const clientOrError = await client.connect().catch(e => e);
151+
expect(clientOrError).to.be.instanceOf(MongoClient);
152+
});
153+
});
109154
});
110155

111156
function makeConnectionTest(connectionString: string, clientOptions?: MongoClientOptions) {

‎test/unit/mongo_client.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ describe('MongoOptions', function () {
5858
expect(options).to.not.have.property('tlsCertificateKeyFilePassword');
5959
expect(options).to.not.have.property('key');
6060
expect(options).to.not.have.property('ca');
61+
expect(options).to.not.have.property('cert');
6162
expect(options).to.have.property('tlsCertificateKeyFile', filename);
6263
expect(options).to.have.property('tlsCAFile', filename);
6364
expect(options).has.property('passphrase', 'tlsCertificateKeyFilePassword');

0 commit comments

Comments
 (0)