mirror of
https://github.com/brianc/node-postgres.git
synced 2026-01-18 15:55:05 +00:00
* Set default PostgreSQL user to 'postgres' to avoid Deno env access errors Currently, the pg package defaults the database user to process.env.USER (or USERNAME on Windows). This causes errors when running in Deno without --allow-env, as environment access is restricted. This PR changes the default user to 'postgres', so: - Node.js behavior is unchanged when a user is explicitly provided in config. - Deno users no longer hit NotCapable errors for environment access. - Avoids relying on process.env for default values. Example: Before: user: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, After: user: 'postgres', // default user, avoids using process.env * Prioritize config values over environment variables in ConnectionParameters Previously, ConnectionParameters would first check process.env for connection settings before using the provided config object. This could cause errors in environments like Deno where environment access is restricted. This change updates the val function to: 1. Use the value from config if it is defined. 2. Fall back to environment variables only if config does not provide a value. 3. Use default values if neither config nor environment variables are set. This ensures that explicitly provided configuration values are always respected, avoiding unnecessary errors in restricted environments. * Wrap NODE_PG_FORCE_NATIVE check in try/catch for Deno compatibility Replace the `typeof process.env.NODE_PG_FORCE_NATIVE !== 'undefined'` check with a try/catch to safely handle environments like Deno without `--allow-env`. - Keeps Node.js behavior unchanged. - Prevents errors when accessing process.env in Deno. - Preserves lazy loading of the native module. * Make default database user Deno-safe Wrap the default database user assignment in a try/catch to prevent errors when environment access is restricted (e.g., in Deno). - Uses process.env.USER / USERNAME on Node if available - Falls back to 'postgres' when env access fails or is unavailable - Maintains code structure and comments - Ensures Node tests continue to pass while preventing Deno runtime errors * Fixing checks pass * Update packages/pg/lib/connection-parameters.js Co-authored-by: Charmander <~@charmander.me> * fix(pg): only guard process.env access when forcing native client --------- Co-authored-by: Charmander <~@charmander.me>
172 lines
5.2 KiB
JavaScript
172 lines
5.2 KiB
JavaScript
'use strict'
|
|
|
|
const dns = require('dns')
|
|
|
|
const defaults = require('./defaults')
|
|
|
|
const parse = require('pg-connection-string').parse // parses a connection string
|
|
|
|
const val = function (key, config, envVar) {
|
|
if (config[key]) {
|
|
return config[key]
|
|
}
|
|
|
|
if (envVar === undefined) {
|
|
envVar = process.env['PG' + key.toUpperCase()]
|
|
} else if (envVar === false) {
|
|
// do nothing ... use false
|
|
} else {
|
|
envVar = process.env[envVar]
|
|
}
|
|
|
|
return envVar || defaults[key]
|
|
}
|
|
|
|
const readSSLConfigFromEnvironment = function () {
|
|
switch (process.env.PGSSLMODE) {
|
|
case 'disable':
|
|
return false
|
|
case 'prefer':
|
|
case 'require':
|
|
case 'verify-ca':
|
|
case 'verify-full':
|
|
return true
|
|
case 'no-verify':
|
|
return { rejectUnauthorized: false }
|
|
}
|
|
return defaults.ssl
|
|
}
|
|
|
|
// Convert arg to a string, surround in single quotes, and escape single quotes and backslashes
|
|
const quoteParamValue = function (value) {
|
|
return "'" + ('' + value).replace(/\\/g, '\\\\').replace(/'/g, "\\'") + "'"
|
|
}
|
|
|
|
const add = function (params, config, paramName) {
|
|
const value = config[paramName]
|
|
if (value !== undefined && value !== null) {
|
|
params.push(paramName + '=' + quoteParamValue(value))
|
|
}
|
|
}
|
|
|
|
class ConnectionParameters {
|
|
constructor(config) {
|
|
// if a string is passed, it is a raw connection string so we parse it into a config
|
|
config = typeof config === 'string' ? parse(config) : config || {}
|
|
|
|
// if the config has a connectionString defined, parse IT into the config we use
|
|
// this will override other default values with what is stored in connectionString
|
|
if (config.connectionString) {
|
|
config = Object.assign({}, config, parse(config.connectionString))
|
|
}
|
|
|
|
this.user = val('user', config)
|
|
this.database = val('database', config)
|
|
|
|
if (this.database === undefined) {
|
|
this.database = this.user
|
|
}
|
|
|
|
this.port = parseInt(val('port', config), 10)
|
|
this.host = val('host', config)
|
|
|
|
// "hiding" the password so it doesn't show up in stack traces
|
|
// or if the client is console.logged
|
|
Object.defineProperty(this, 'password', {
|
|
configurable: true,
|
|
enumerable: false,
|
|
writable: true,
|
|
value: val('password', config),
|
|
})
|
|
|
|
this.binary = val('binary', config)
|
|
this.options = val('options', config)
|
|
|
|
this.ssl = typeof config.ssl === 'undefined' ? readSSLConfigFromEnvironment() : config.ssl
|
|
|
|
if (typeof this.ssl === 'string') {
|
|
if (this.ssl === 'true') {
|
|
this.ssl = true
|
|
}
|
|
}
|
|
// support passing in ssl=no-verify via connection string
|
|
if (this.ssl === 'no-verify') {
|
|
this.ssl = { rejectUnauthorized: false }
|
|
}
|
|
if (this.ssl && this.ssl.key) {
|
|
Object.defineProperty(this.ssl, 'key', {
|
|
enumerable: false,
|
|
})
|
|
}
|
|
|
|
this.client_encoding = val('client_encoding', config)
|
|
this.replication = val('replication', config)
|
|
// a domain socket begins with '/'
|
|
this.isDomainSocket = !(this.host || '').indexOf('/')
|
|
|
|
this.application_name = val('application_name', config, 'PGAPPNAME')
|
|
this.fallback_application_name = val('fallback_application_name', config, false)
|
|
this.statement_timeout = val('statement_timeout', config, false)
|
|
this.lock_timeout = val('lock_timeout', config, false)
|
|
this.idle_in_transaction_session_timeout = val('idle_in_transaction_session_timeout', config, false)
|
|
this.query_timeout = val('query_timeout', config, false)
|
|
|
|
if (config.connectionTimeoutMillis === undefined) {
|
|
this.connect_timeout = process.env.PGCONNECT_TIMEOUT || 0
|
|
} else {
|
|
this.connect_timeout = Math.floor(config.connectionTimeoutMillis / 1000)
|
|
}
|
|
|
|
if (config.keepAlive === false) {
|
|
this.keepalives = 0
|
|
} else if (config.keepAlive === true) {
|
|
this.keepalives = 1
|
|
}
|
|
|
|
if (typeof config.keepAliveInitialDelayMillis === 'number') {
|
|
this.keepalives_idle = Math.floor(config.keepAliveInitialDelayMillis / 1000)
|
|
}
|
|
}
|
|
|
|
getLibpqConnectionString(cb) {
|
|
const params = []
|
|
add(params, this, 'user')
|
|
add(params, this, 'password')
|
|
add(params, this, 'port')
|
|
add(params, this, 'application_name')
|
|
add(params, this, 'fallback_application_name')
|
|
add(params, this, 'connect_timeout')
|
|
add(params, this, 'options')
|
|
|
|
const ssl = typeof this.ssl === 'object' ? this.ssl : this.ssl ? { sslmode: this.ssl } : {}
|
|
add(params, ssl, 'sslmode')
|
|
add(params, ssl, 'sslca')
|
|
add(params, ssl, 'sslkey')
|
|
add(params, ssl, 'sslcert')
|
|
add(params, ssl, 'sslrootcert')
|
|
|
|
if (this.database) {
|
|
params.push('dbname=' + quoteParamValue(this.database))
|
|
}
|
|
if (this.replication) {
|
|
params.push('replication=' + quoteParamValue(this.replication))
|
|
}
|
|
if (this.host) {
|
|
params.push('host=' + quoteParamValue(this.host))
|
|
}
|
|
if (this.isDomainSocket) {
|
|
return cb(null, params.join(' '))
|
|
}
|
|
if (this.client_encoding) {
|
|
params.push('client_encoding=' + quoteParamValue(this.client_encoding))
|
|
}
|
|
dns.lookup(this.host, function (err, address) {
|
|
if (err) return cb(err, null)
|
|
params.push('hostaddr=' + quoteParamValue(address))
|
|
return cb(null, params.join(' '))
|
|
})
|
|
}
|
|
}
|
|
|
|
module.exports = ConnectionParameters
|