Skip to content

Commit 336c048

Browse files
committed
feat(backend/mongo): add support for TLS/SSL connection
1 parent 5c3e2b4 commit 336c048

File tree

1 file changed

+89
-19
lines changed

1 file changed

+89
-19
lines changed

packages/backend/db/mongo.js

+89-19
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,32 @@ import fs from 'fs'
22
import { MongoClient } from 'mongodb'
33
import ShareDbMongo from 'sharedb-mongo'
44

5-
export const { db, mongo, mongoClient, createMongoIndex } = getMongoDb({
6-
url: process.env.MONGO_URL,
7-
optsString: process.env.MONGO_OPTS,
8-
sslKeyPath: process.env.MONGO_SSL_KEY_PATH,
9-
sslCertPath: process.env.MONGO_SSL_CERT_PATH,
10-
sslCaPath: process.env.MONGO_SSL_CA_PATH
5+
export const { db, mongo, mongoClient, createMongoIndex } = getMongoDb(process.env.MONGO_URL, {
6+
// ssl key, cert and ca can be provided as paths or base64 or directly as strings
7+
8+
// ssl as string
9+
key: process.env.MONGO_SSL_KEY,
10+
cert: process.env.MONGO_SSL_CERT,
11+
ca: process.env.MONGO_SSL_CA,
12+
13+
// ssl as path to the file
14+
keyPath: process.env.MONGO_SSL_KEY_PATH,
15+
certPath: process.env.MONGO_SSL_CERT_PATH,
16+
caPath: process.env.MONGO_SSL_CA_PATH,
17+
18+
// ssl as base64
19+
keyBase64: process.env.MONGO_SSL_KEY_BASE64,
20+
certBase64: process.env.MONGO_SSL_CERT_BASE64,
21+
caBase64: process.env.MONGO_SSL_CA_BASE64,
22+
23+
...(process.env.MONGO_OPTIONS ? JSON.parse(process.env.MONGO_OPTIONS) : undefined)
1124
})
1225

13-
function getMongoDb ({ url, optsString, sslKeyPath, sslCertPath, sslCaPath }) {
14-
const options = { useUnifiedTopology: true }
15-
16-
if (typeof optsString === 'string') {
17-
const { key, cert, ca } = JSON.parse(optsString)
18-
options.sslKey = fs.readFileSync(key)
19-
options.sslCert = fs.readFileSync(cert)
20-
options.sslCA = fs.readFileSync(ca)
21-
} else if (sslKeyPath) {
22-
options.sslKey = fs.readFileSync(sslKeyPath)
23-
options.sslCert = fs.readFileSync(sslCertPath)
24-
options.sslCA = fs.readFileSync(sslCaPath)
25-
}
26+
function getMongoDb (url, options = {}) {
27+
options = { ...options }
28+
options = processSslOptions(options)
29+
30+
options.useUnifiedTopology ??= true
2631

2732
const mongoClient = new MongoClient(url, options)
2833
const mongo = mongoClient.db()
@@ -38,3 +43,68 @@ function getMongoDb ({ url, optsString, sslKeyPath, sslCertPath, sslCaPath }) {
3843
}
3944
}
4045
}
46+
47+
function processSslOptions (options = {}) {
48+
options = { ...options }
49+
let initialized = false
50+
if (options.key || options.cert || options.ca) {
51+
if (!(options.key && options.cert && options.ca)) {
52+
throw Error('[teamplay/mongo] SSL: All 3 strings must be provided: key, cert, ca')
53+
}
54+
if (!(typeof options.key === 'string' && typeof options.cert === 'string' && typeof options.ca === 'string')) {
55+
throw Error('[teamplay/mongo] SSL: All 3 strings must be provided as strings')
56+
}
57+
options = {
58+
...options,
59+
key: Buffer.from(options.key),
60+
cert: Buffer.from(options.cert),
61+
ca: Buffer.from(options.ca)
62+
}
63+
initialized = true
64+
}
65+
if (options.keyPath || options.certPath || options.caPath) {
66+
if (initialized) {
67+
throw Error('[teamplay/mongo] SSL: Cannot mix paths and strings or base64')
68+
}
69+
if (!(options.keyPath && options.certPath && options.caPath)) {
70+
throw Error('[teamplay/mongo] SSL: All 3 paths to files must be provided: keyPath, certPath, caPath')
71+
}
72+
options = {
73+
...options,
74+
key: fs.readFileSync(options.keyPath),
75+
cert: fs.readFileSync(options.certPath),
76+
ca: fs.readFileSync(options.caPath)
77+
}
78+
initialized = true
79+
}
80+
if (options.keyBase64 || options.certBase64 || options.caBase64) {
81+
if (initialized) {
82+
throw Error('[teamplay/mongo] SSL: Cannot mix base64 and strings or paths')
83+
}
84+
if (!(options.keyBase64 && options.certBase64 && options.caBase64)) {
85+
throw Error('[teamplay/mongo] SSL: All 3 base64 strings must be provided: keyBase64, certBase64, caBase64')
86+
}
87+
options = {
88+
...options,
89+
key: Buffer.from(options.keyBase64, 'base64'),
90+
cert: Buffer.from(options.certBase64, 'base64'),
91+
ca: Buffer.from(options.caBase64, 'base64')
92+
}
93+
}
94+
// enable tls mode if certificates are provided (unless explicitly disabled)
95+
if (options.key && options.cert && options.ca) {
96+
options.tls ??= true
97+
}
98+
// cleanup options object from the processed keys
99+
delete options.keyPath
100+
delete options.certPath
101+
delete options.caPath
102+
delete options.keyBase64
103+
delete options.certBase64
104+
delete options.caBase64
105+
// delete the undefined values if they were not provided
106+
if (!options.key) delete options.key
107+
if (!options.cert) delete options.cert
108+
if (!options.ca) delete options.ca
109+
return options
110+
}

0 commit comments

Comments
 (0)