Skip to content

Commit fd99925

Browse files
committed
Make enableChannelBinding emit a deprecation warning; allow booleans for enableChannelBinding but not channel_binding
1 parent 3124258 commit fd99925

2 files changed

Lines changed: 32 additions & 25 deletions

File tree

packages/pg/lib/channel-binding.js

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,41 @@
44
// has to be bound to the server's certificate:
55
// https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-CHANNEL-BINDING
66

7+
const nodeUtils = require('util')
78
const defaults = require('./defaults')
89

910
const channelBindingLevels = ['disable', 'prefer', 'require']
1011

11-
// Accepts the levels libpq's channel_binding parameter defines, plus the booleans that
12-
// pg's original enableChannelBinding option took. Any other non-string keeps its
13-
// historical truthiness, so previously working configs keep working. A string that is not
14-
// a level is refused rather than read as the weakest one that resembles it.
15-
const normalizeChannelBinding = function (value) {
16-
if (typeof value !== 'string') {
17-
return value ? 'prefer' : 'disable'
18-
}
12+
const emitEnableChannelBindingDeprecationNotice = nodeUtils.deprecate(
13+
() => {},
14+
'enableChannelBinding is deprecated: instead, please set channel_binding to "disable", "prefer" or "require"'
15+
)
16+
17+
function channelBindingFromDeprecatedBoolean(value) {
18+
if (value === undefined) return // undefined passes straight through, no warning
19+
emitEnableChannelBindingDeprecationNotice();
20+
// note: we pass through valid string values to avoid confusion, otherwise
21+
// "disable" and "require" would both resolve as truthy and mean "prefer"
22+
return channelBindingLevels.includes(value) ? value : (value ? 'prefer' : 'disable')
23+
}
24+
25+
function validatedChannelBinding(value) {
1926
if (!channelBindingLevels.includes(value)) {
2027
throw new Error(
21-
`Invalid channel_binding value: "${value}". Valid values are "disable", "prefer" and "require" (or a boolean).`
28+
`Invalid channel_binding value: "${value}". Valid values are "disable", "prefer" and "require".`
2229
)
2330
}
2431
return value
2532
}
2633

27-
// channel_binding, being libpq's own spelling, wins over the older
28-
// enableChannelBinding option, then the environment, then the default.
29-
const resolveChannelBinding = function (channelBinding, enableChannelBinding) {
30-
const value = [channelBinding, enableChannelBinding, process.env.PGCHANNELBINDING, defaults.channel_binding].find(
31-
(candidate) => candidate !== undefined && candidate !== null
32-
)
33-
return normalizeChannelBinding(value)
34+
function resolveChannelBinding(channelBinding, enableChannelBinding) {
35+
const value =
36+
channelBinding ??
37+
channelBindingFromDeprecatedBoolean(enableChannelBinding) ??
38+
process.env.PGCHANNELBINDING ??
39+
defaults.channel_binding
40+
41+
return validatedChannelBinding(value)
3442
}
3543

36-
module.exports = { channelBindingLevels, normalizeChannelBinding, resolveChannelBinding }
44+
module.exports = { channelBindingLevels, channelBindingFromDeprecatedBoolean, validatedChannelBinding, resolveChannelBinding }

packages/pg/lib/client.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const utils = require('./utils')
33
const nodeUtils = require('util')
44
const sasl = require('./crypto/sasl')
55
const { checkAuthRequest, resolveAuthRequirement } = require('./require-auth')
6-
const { normalizeChannelBinding } = require('./channel-binding')
6+
const { validatedChannelBinding, channelBindingFromDeprecatedBoolean } = require('./channel-binding')
77
const TypeOverrides = require('./type-overrides')
88

99
const ConnectionParameters = require('./connection-parameters')
@@ -91,10 +91,10 @@ class Client extends EventEmitter {
9191
// enableChannelBinding options and the PGCHANNELBINDING environment variable.
9292
this._channelBinding = this.connectionParameters.channel_binding
9393
// What the server has to do to authenticate itself, from require_auth and
94-
// channel_binding, or null if any supported method will do
94+
// channel_binding, or null if any supported method will do.
9595
this._authRequirement = this.connectionParameters.authRequirement
9696
// Whether the client has done all the authenticating it is going to do, and whether
97-
// that included binding the exchange to the server's certificate
97+
// that included binding the exchange to the server's certificate.
9898
this._authFinished = false
9999
this._channelBound = false
100100
// Whether a requirement has been broken, which nothing later can put right. Anything
@@ -103,6 +103,7 @@ class Client extends EventEmitter {
103103
// loop, and Connection#end() sends its Terminate before ending the stream, so a write
104104
// that arrived in the meantime would still reach the server.
105105
this._authAborted = false
106+
106107
this.scramMaxIterations = coerceNumberOrDefault(c.scramMaxIterations, sasl.DEFAULT_MAX_SCRAM_ITERATIONS)
107108
this.connection =
108109
c.connection ||
@@ -139,11 +140,9 @@ class Client extends EventEmitter {
139140
}
140141

141142
// Changing the level after construction re-derives what the server has to do, so that
142-
// the two cannot come to disagree over whether channel binding is mandatory. The value
143-
// is checked as it would have been in the constructor, so that a level this client does
144-
// not know cannot pass for the weakest one.
143+
// the two cannot come to disagree over whether channel binding is mandatory.
145144
set channelBinding(value) {
146-
this._channelBinding = normalizeChannelBinding(value)
145+
this._channelBinding = validatedChannelBinding(value)
147146
this._authRequirement = resolveAuthRequirement(this.connectionParameters.require_auth, this._channelBinding)
148147
}
149148

@@ -155,7 +154,7 @@ class Client extends EventEmitter {
155154
}
156155

157156
set enableChannelBinding(value) {
158-
this.channelBinding = value
157+
this.channelBinding = channelBindingFromDeprecatedBoolean(value)
159158
}
160159

161160
get activeQuery() {

0 commit comments

Comments
 (0)