From d43ad28b095b89bc831731650daf637953577051 Mon Sep 17 00:00:00 2001 From: u9822914324-web Date: Mon, 21 Sep 2026 01:51:48 +0100 Subject: [PATCH 1/2] feat(pg-connection-string): support the sslpassword parameter Parses sslpassword from the connection string and assigns it to config.ssl.passphrase, which is the Node TLS option used to decrypt an encrypted ssl.key. Issue #3716 asked for this under the name `sslpassphrase`; charmander noted there that the libpq-compatible spelling is `sslpassword`, so that is the name implemented here. Unlike sslcert, sslkey and sslrootcert, sslpassword is a literal value rather than a path, so it is not read from disk. It is added to the condition that initialises config.ssl so that it works on its own, matching how the other ssl parameters behave. toClientConfig passes the whole ssl object through toConnectionOptions, so passphrase reaches ClientConfig without further plumbing. Closes #3716 Co-Authored-By: Claude Opus 5 --- packages/pg-connection-string/README.md | 1 + packages/pg-connection-string/index.d.ts | 1 + packages/pg-connection-string/index.js | 7 +++++- packages/pg-connection-string/test/parse.ts | 25 +++++++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/pg-connection-string/README.md b/packages/pg-connection-string/README.md index 5475f63bf..5ef6ddbf0 100644 --- a/packages/pg-connection-string/README.md +++ b/packages/pg-connection-string/README.md @@ -98,6 +98,7 @@ Query parameters follow a `?` character, including the following special query p * `sslcert=` - reads data from the given file and includes the result as `ssl.cert` * `sslkey=` - reads data from the given file and includes the result as `ssl.key` * `sslrootcert=` - reads data from the given file and includes the result as `ssl.ca` + * `sslpassword=` - sets `ssl.passphrase`, used to decrypt an encrypted `ssl.key` A bare relative URL, such as `salesdata`, will indicate a database name while leaving other properties empty. diff --git a/packages/pg-connection-string/index.d.ts b/packages/pg-connection-string/index.d.ts index 4b305299e..c7525695e 100644 --- a/packages/pg-connection-string/index.d.ts +++ b/packages/pg-connection-string/index.d.ts @@ -11,6 +11,7 @@ interface SSLConfig { ca?: string cert?: string | null key?: string + passphrase?: string rejectUnauthorized?: boolean } diff --git a/packages/pg-connection-string/index.js b/packages/pg-connection-string/index.js index 139cc17b1..fc4664bfb 100644 --- a/packages/pg-connection-string/index.js +++ b/packages/pg-connection-string/index.js @@ -74,7 +74,7 @@ function parse(str, options = {}) { config.ssl = false } - if (config.sslcert || config.sslkey || config.sslrootcert || config.sslmode) { + if (config.sslcert || config.sslkey || config.sslrootcert || config.sslmode || config.sslpassword) { config.ssl = {} } @@ -99,6 +99,11 @@ function parse(str, options = {}) { config.ssl.ca = fs.readFileSync(config.sslrootcert).toString() } + // sslpassword is a literal value rather than a path, so it is not read from disk. + if (config.sslpassword) { + config.ssl.passphrase = config.sslpassword + } + if (options.useLibpqCompat && config.uselibpqcompat) { throw new Error('Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.') } diff --git a/packages/pg-connection-string/test/parse.ts b/packages/pg-connection-string/test/parse.ts index 562c3ece0..8f274c0e4 100644 --- a/packages/pg-connection-string/test/parse.ts +++ b/packages/pg-connection-string/test/parse.ts @@ -268,6 +268,31 @@ describe('parse', function () { }) }) + it('configuration parameter sslpassword=password', function () { + const connectionString = 'pg:///?sslpassword=MySecretPass' + const subject = parse(connectionString) + subject.ssl?.should.eql({ + passphrase: 'MySecretPass', + }) + }) + + it('configuration parameter sslpassword alongside sslkey', function () { + const connectionString = 'pg:///?sslkey=' + __dirname + '/example.key&sslpassword=MySecretPass' + const subject = parse(connectionString) + subject.ssl?.should.eql({ + key: 'example key\n', + passphrase: 'MySecretPass', + }) + }) + + it('configuration parameter sslpassword is url-decoded', function () { + const connectionString = 'pg:///?sslpassword=' + encodeURIComponent('pa ss/word?&=') + const subject = parse(connectionString) + subject.ssl?.should.eql({ + passphrase: 'pa ss/word?&=', + }) + }) + it('configuration parameter sslmode=no-verify', function () { const connectionString = 'pg:///?sslmode=no-verify' const subject = parse(connectionString) From 387265df07b2c5ae2cf4ff246414811fb932f719 Mon Sep 17 00:00:00 2001 From: u9822914324-web Date: Mon, 21 Sep 2026 02:01:47 +0100 Subject: [PATCH 2/2] docs(ssl): list sslpassword among the params that replace the ssl object sslpassword now participates in the condition that initialises config.ssl, so like sslcert, sslkey, sslrootcert and sslmode it causes an ssl object supplied alongside a connection string to be replaced. Co-Authored-By: Claude Opus 5 --- docs/pages/features/ssl.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/features/ssl.mdx b/docs/pages/features/ssl.mdx index 6a29ed739..5aee2659f 100644 --- a/docs/pages/features/ssl.mdx +++ b/docs/pages/features/ssl.mdx @@ -37,7 +37,7 @@ await pool.end() ## Usage with `connectionString` -If you plan to use a combination of a database connection string from the environment and SSL settings in the config object directly, then you must avoid including any of `sslcert`, `sslkey`, `sslrootcert`, or `sslmode` in the connection string. If any of these options are used then the `ssl` object is replaced and any additional options provided there will be lost. +If you plan to use a combination of a database connection string from the environment and SSL settings in the config object directly, then you must avoid including any of `sslcert`, `sslkey`, `sslrootcert`, `sslpassword`, or `sslmode` in the connection string. If any of these options are used then the `ssl` object is replaced and any additional options provided there will be lost. ```js const config = {