pg-connection-string
Advanced tools
Comparing version
@@ -1,3 +0,10 @@ | ||
export function parse(connectionString: string): ConnectionOptions | ||
import { ClientConfig } from 'pg' | ||
export function parse(connectionString: string, options: Options): ConnectionOptions | ||
export interface Options { | ||
// Use libpq semantics when interpreting the connection string | ||
useLibpqCompat?: boolean | ||
} | ||
export interface ConnectionOptions { | ||
@@ -16,1 +23,4 @@ host: string | null | ||
} | ||
export function toClientConfig(config: ConnectionOptions): ClientConfig | ||
export function parseIntoClientConfig(connectionString: string): ClientConfig |
130
index.js
@@ -8,3 +8,3 @@ 'use strict' | ||
//parses a connection string | ||
function parse(str) { | ||
function parse(str, options = {}) { | ||
//unix socket | ||
@@ -23,3 +23,3 @@ if (str.charAt(0) === '/') { | ||
// Ensure spaces are encoded as %20 | ||
str = encodeURI(str).replace(/\%25(\d\d)/g, '%$1') | ||
str = encodeURI(str).replace(/%25(\d\d)/g, '%$1') | ||
} | ||
@@ -92,17 +92,55 @@ | ||
switch (config.sslmode) { | ||
case 'disable': { | ||
config.ssl = false | ||
break | ||
if (options.useLibpqCompat && config.uselibpqcompat) { | ||
throw new Error('Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.') | ||
} | ||
if (config.uselibpqcompat === 'true' || options.useLibpqCompat) { | ||
switch (config.sslmode) { | ||
case 'disable': { | ||
config.ssl = false | ||
break | ||
} | ||
case 'prefer': { | ||
config.ssl.rejectUnauthorized = false | ||
break | ||
} | ||
case 'require': { | ||
if (config.sslrootcert) { | ||
// If a root CA is specified, behavior of `sslmode=require` will be the same as that of `verify-ca` | ||
config.ssl.checkServerIdentity = function () {} | ||
} else { | ||
config.ssl.rejectUnauthorized = false | ||
} | ||
break | ||
} | ||
case 'verify-ca': { | ||
if (!config.ssl.ca) { | ||
throw new Error( | ||
'SECURITY WARNING: Using sslmode=verify-ca requires specifying a CA with sslrootcert. If a public CA is used, verify-ca allows connections to a server that somebody else may have registered with the CA, making you vulnerable to Man-in-the-Middle attacks. Either specify a custom CA certificate with sslrootcert parameter or use sslmode=verify-full for proper security.' | ||
) | ||
} | ||
config.ssl.checkServerIdentity = function () {} | ||
break | ||
} | ||
case 'verify-full': { | ||
break | ||
} | ||
} | ||
case 'prefer': | ||
case 'require': | ||
case 'verify-ca': | ||
case 'verify-full': { | ||
break | ||
} else { | ||
switch (config.sslmode) { | ||
case 'disable': { | ||
config.ssl = false | ||
break | ||
} | ||
case 'prefer': | ||
case 'require': | ||
case 'verify-ca': | ||
case 'verify-full': { | ||
break | ||
} | ||
case 'no-verify': { | ||
config.ssl.rejectUnauthorized = false | ||
break | ||
} | ||
} | ||
case 'no-verify': { | ||
config.ssl.rejectUnauthorized = false | ||
break | ||
} | ||
} | ||
@@ -113,4 +151,66 @@ | ||
// convert pg-connection-string ssl config to a ClientConfig.ConnectionOptions | ||
function toConnectionOptions(sslConfig) { | ||
const connectionOptions = Object.entries(sslConfig).reduce((c, [key, value]) => { | ||
// we explicitly check for undefined and null instead of `if (value)` because some | ||
// options accept falsy values. Example: `ssl.rejectUnauthorized = false` | ||
if (value !== undefined && value !== null) { | ||
c[key] = value | ||
} | ||
return c | ||
}, {}) | ||
return connectionOptions | ||
} | ||
// convert pg-connection-string config to a ClientConfig | ||
function toClientConfig(config) { | ||
const poolConfig = Object.entries(config).reduce((c, [key, value]) => { | ||
if (key === 'ssl') { | ||
const sslConfig = value | ||
if (typeof sslConfig === 'boolean') { | ||
c[key] = sslConfig | ||
} | ||
// else path is taken. multiple tests produce a sslConfig that is an object | ||
// and we can console.log to see that we take this path | ||
// | ||
// see https://github.com/istanbuljs/babel-plugin-istanbul/issues/186#issuecomment-1137765139 | ||
// istanbul ignore else | ||
else if (typeof sslConfig === 'object') { | ||
c[key] = toConnectionOptions(sslConfig) | ||
} | ||
} else if (value !== undefined && value !== null) { | ||
if (key === 'port') { | ||
// when port is not specified, it is converted into an empty string | ||
// we want to avoid NaN or empty string as a values in ClientConfig | ||
if (value !== '') { | ||
const v = parseInt(value, 10) | ||
if (isNaN(v)) { | ||
throw new Error(`Invalid ${key}: ${value}`) | ||
} | ||
c[key] = v | ||
} | ||
} else { | ||
c[key] = value | ||
} | ||
} | ||
return c | ||
}, {}) | ||
return poolConfig | ||
} | ||
// parses a connection string into ClientConfig | ||
function parseIntoClientConfig(str) { | ||
return toClientConfig(parse(str)) | ||
} | ||
module.exports = parse | ||
parse.parse = parse | ||
parse.toClientConfig = toClientConfig | ||
parse.parseIntoClientConfig = parseIntoClientConfig |
{ | ||
"name": "pg-connection-string", | ||
"version": "2.7.0", | ||
"version": "2.7.1-alpha.0", | ||
"description": "Functions for dealing with a PostgresSQL connection string", | ||
"main": "./index.js", | ||
"types": "./index.d.ts", | ||
"exports": { | ||
".": { | ||
"types": "./index.d.ts", | ||
"import": "./esm/index.mjs", | ||
"require": "./index.js", | ||
"default": "./index.js" | ||
} | ||
}, | ||
"scripts": { | ||
@@ -37,5 +45,6 @@ "test": "istanbul cover _mocha && npm run check-coverage", | ||
"index.js", | ||
"index.d.ts" | ||
"index.d.ts", | ||
"esm" | ||
], | ||
"gitHead": "92cb640fd316972e323ced6256b2acd89b1b58e0" | ||
"gitHead": "56762beebf750fe7798354301237a5bc62ef7740" | ||
} |
@@ -38,2 +38,23 @@ pg-connection-string | ||
### ClientConfig Compatibility for TypeScript | ||
The pg-connection-string `ConnectionOptions` interface is not compatible with the `ClientConfig` interface that [pg.Client](https://node-postgres.com/apis/client) expects. To remedy this, use the `parseIntoClientConfig` function instead of `parse`: | ||
```ts | ||
import { ClientConfig } from 'pg'; | ||
import { parseIntoClientConfig } from 'pg-connection-string'; | ||
const config: ClientConfig = parseIntoClientConfig('postgres://someuser:somepassword@somehost:381/somedatabase') | ||
``` | ||
You can also use `toClientConfig` to convert an existing `ConnectionOptions` interface into a `ClientConfig` interface: | ||
```ts | ||
import { ClientConfig } from 'pg'; | ||
import { parse, toClientConfig } from 'pg-connection-string'; | ||
const config = parse('postgres://someuser:somepassword@somehost:381/somedatabase') | ||
const clientConfig: ClientConfig = toClientConfig(config) | ||
``` | ||
## Connection Strings | ||
@@ -70,6 +91,13 @@ | ||
* `ssl=1`, `ssl=true`, `ssl=0`, `ssl=false` - sets `ssl` to true or false, accordingly | ||
* `sslmode=<sslmode>` | ||
* `uselibpqcompat=true` - use libpq semantics | ||
* `sslmode=<sslmode>` when `sslcompat` is not set | ||
* `sslmode=disable` - sets `ssl` to false | ||
* `sslmode=no-verify` - sets `ssl` to `{ rejectUnauthorized: false }` | ||
* `sslmode=prefer`, `sslmode=require`, `sslmode=verify-ca`, `sslmode=verify-full` - sets `ssl` to true | ||
* `sslmode=<sslmode>` when `sslcompat=libpq` | ||
* `sslmode=disable` - sets `ssl` to false | ||
* `sslmode=prefer` - sets `ssl` to `{ rejectUnauthorized: false }` | ||
* `sslmode=require` - sets `ssl` to `{ rejectUnauthorized: false }` unless `sslrootcert` is specified, in which case it behaves like `verify-ca` | ||
* `sslmode=verify-ca` - sets `ssl` to `{ checkServerIdentity: no-op }` (verify CA, but not server identity). This verifies the presented certificate against the effective CA specified in sslrootcert. | ||
* `sslmode=verify-full` - sets `ssl` to `{}` (verify CA and server identity) | ||
* `sslcert=<filename>` - reads data from the given file and includes the result as `ssl.cert` | ||
@@ -80,1 +108,4 @@ * `sslkey=<filename>` - reads data from the given file and includes the result as `ssl.key` | ||
A bare relative URL, such as `salesdata`, will indicate a database name while leaving other properties empty. | ||
> [!CAUTION] | ||
> Choosing an sslmode other than verify-full has serious security implications. Please read https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS to understand the trade-offs. |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
15041
65.32%6
20%209
99.05%109
39.74%1
Infinity%