chore: ⬆️ updated deps
This commit is contained in:
+100
-10
@@ -8,6 +8,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"math"
|
||||
"net"
|
||||
"net/url"
|
||||
@@ -55,6 +56,13 @@ type Config struct {
|
||||
|
||||
SSLNegotiation string // sslnegotiation=postgres or sslnegotiation=direct
|
||||
|
||||
// AfterNetConnect is called after the network connection, including TLS if applicable, is established but before any
|
||||
// PostgreSQL protocol communication. It takes the established net.Conn and returns a net.Conn that will be used in
|
||||
// its place. It can be used to wrap the net.Conn (e.g. for logging, diagnostics, or testing). Its functionality has
|
||||
// some overlap with DialFunc. However, DialFunc takes place before TLS is established and cannot be used to control
|
||||
// the final net.Conn used for PostgreSQL protocol communication while AfterNetConnect can.
|
||||
AfterNetConnect func(ctx context.Context, config *Config, conn net.Conn) (net.Conn, error)
|
||||
|
||||
// ValidateConnect is called during a connection attempt after a successful authentication with the PostgreSQL server.
|
||||
// It can be used to validate that the server is acceptable. If this returns an error the connection is closed and the next
|
||||
// fallback config is tried. This allows implementing high availability behavior such as libpq does with target_session_attrs.
|
||||
@@ -75,6 +83,23 @@ type Config struct {
|
||||
// that you close on FATAL errors by returning false.
|
||||
OnPgError PgErrorHandler
|
||||
|
||||
// OAuthTokenProvider is a function that returns an OAuth token for authentication. If set, it will be used for
|
||||
// OAUTHBEARER SASL authentication when the server requests it.
|
||||
OAuthTokenProvider func(context.Context) (string, error)
|
||||
|
||||
// MinProtocolVersion is the minimum acceptable PostgreSQL protocol version.
|
||||
// If the server does not support at least this version, the connection will fail.
|
||||
// Valid values: "3.0", "3.2", "latest". Defaults to "3.0".
|
||||
MinProtocolVersion string
|
||||
|
||||
// MaxProtocolVersion is the maximum PostgreSQL protocol version to request from the server.
|
||||
// Valid values: "3.0", "3.2", "latest". Defaults to "3.0" for compatibility.
|
||||
MaxProtocolVersion string
|
||||
|
||||
// ChannelBinding is the channel_binding parameter for SCRAM-SHA-256-PLUS authentication.
|
||||
// Valid values: "disable", "prefer", "require". Defaults to "prefer".
|
||||
ChannelBinding string
|
||||
|
||||
createdByParseConfig bool // Used to enforce created by ParseConfig rule.
|
||||
}
|
||||
|
||||
@@ -96,9 +121,7 @@ func (c *Config) Copy() *Config {
|
||||
}
|
||||
if newConf.RuntimeParams != nil {
|
||||
newConf.RuntimeParams = make(map[string]string, len(c.RuntimeParams))
|
||||
for k, v := range c.RuntimeParams {
|
||||
newConf.RuntimeParams[k] = v
|
||||
}
|
||||
maps.Copy(newConf.RuntimeParams, c.RuntimeParams)
|
||||
}
|
||||
if newConf.Fallbacks != nil {
|
||||
newConf.Fallbacks = make([]*FallbackConfig, len(c.Fallbacks))
|
||||
@@ -207,6 +230,8 @@ func NetworkAddress(host string, port uint16) (network, address string) {
|
||||
// PGCONNECT_TIMEOUT
|
||||
// PGTARGETSESSIONATTRS
|
||||
// PGTZ
|
||||
// PGMINPROTOCOLVERSION
|
||||
// PGMAXPROTOCOLVERSION
|
||||
//
|
||||
// See http://www.postgresql.org/docs/current/static/libpq-envars.html for details on the meaning of environment variables.
|
||||
//
|
||||
@@ -332,6 +357,9 @@ func ParseConfigWithOptions(connString string, options ParseConfigOptions) (*Con
|
||||
"target_session_attrs": {},
|
||||
"service": {},
|
||||
"servicefile": {},
|
||||
"min_protocol_version": {},
|
||||
"max_protocol_version": {},
|
||||
"channel_binding": {},
|
||||
}
|
||||
|
||||
// Adding kerberos configuration
|
||||
@@ -424,6 +452,52 @@ func ParseConfigWithOptions(connString string, options ParseConfigOptions) (*Con
|
||||
return nil, &ParseConfigError{ConnString: connString, msg: fmt.Sprintf("unknown target_session_attrs value: %v", tsa)}
|
||||
}
|
||||
|
||||
minProto, err := parseProtocolVersion(settings["min_protocol_version"])
|
||||
if err != nil {
|
||||
return nil, &ParseConfigError{ConnString: connString, msg: fmt.Sprintf("invalid min_protocol_version: %q", settings["min_protocol_version"]), err: err}
|
||||
}
|
||||
maxProto, err := parseProtocolVersion(settings["max_protocol_version"])
|
||||
if err != nil {
|
||||
return nil, &ParseConfigError{ConnString: connString, msg: fmt.Sprintf("invalid max_protocol_version: %q", settings["max_protocol_version"]), err: err}
|
||||
}
|
||||
|
||||
config.MinProtocolVersion = settings["min_protocol_version"]
|
||||
config.MaxProtocolVersion = settings["max_protocol_version"]
|
||||
|
||||
if config.MinProtocolVersion == "" {
|
||||
config.MinProtocolVersion = "3.0"
|
||||
}
|
||||
|
||||
// When max_protocol_version is not explicitly set, default based on
|
||||
// min_protocol_version. This matches libpq behavior: if min > 3.0,
|
||||
// default max to latest; otherwise default to 3.0 for compatibility
|
||||
// with older servers/poolers that don't support NegotiateProtocolVersion.
|
||||
if config.MaxProtocolVersion == "" {
|
||||
if minProto > pgproto3.ProtocolVersion30 {
|
||||
config.MaxProtocolVersion = "latest"
|
||||
} else {
|
||||
config.MaxProtocolVersion = "3.0"
|
||||
}
|
||||
}
|
||||
|
||||
// Only error when max_protocol_version was explicitly set and conflicts
|
||||
// with min_protocol_version. When max_protocol_version is not explicitly
|
||||
// set, the auto-raise logic above already ensures a valid default.
|
||||
if minProto > maxProto && settings["max_protocol_version"] != "" {
|
||||
return nil, &ParseConfigError{ConnString: connString, msg: "min_protocol_version cannot be greater than max_protocol_version"}
|
||||
}
|
||||
|
||||
switch channelBinding := settings["channel_binding"]; channelBinding {
|
||||
case "", "prefer":
|
||||
config.ChannelBinding = "prefer"
|
||||
case "disable":
|
||||
config.ChannelBinding = "disable"
|
||||
case "require":
|
||||
config.ChannelBinding = "require"
|
||||
default:
|
||||
return nil, &ParseConfigError{ConnString: connString, msg: fmt.Sprintf("unknown channel_binding value: %v", channelBinding)}
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
@@ -431,9 +505,7 @@ func mergeSettings(settingSets ...map[string]string) map[string]string {
|
||||
settings := make(map[string]string)
|
||||
|
||||
for _, s2 := range settingSets {
|
||||
for k, v := range s2 {
|
||||
settings[k] = v
|
||||
}
|
||||
maps.Copy(settings, s2)
|
||||
}
|
||||
|
||||
return settings
|
||||
@@ -463,6 +535,8 @@ func parseEnvSettings() map[string]string {
|
||||
"PGSERVICEFILE": "servicefile",
|
||||
"PGTZ": "timezone",
|
||||
"PGOPTIONS": "options",
|
||||
"PGMINPROTOCOLVERSION": "min_protocol_version",
|
||||
"PGMAXPROTOCOLVERSION": "max_protocol_version",
|
||||
}
|
||||
|
||||
for envname, realname := range nameMap {
|
||||
@@ -487,7 +561,9 @@ func parseURLSettings(connString string) (map[string]string, error) {
|
||||
}
|
||||
|
||||
if parsedURL.User != nil {
|
||||
settings["user"] = parsedURL.User.Username()
|
||||
if u := parsedURL.User.Username(); u != "" {
|
||||
settings["user"] = u
|
||||
}
|
||||
if password, present := parsedURL.User.Password(); present {
|
||||
settings["password"] = password
|
||||
}
|
||||
@@ -496,7 +572,7 @@ func parseURLSettings(connString string) (map[string]string, error) {
|
||||
// Handle multiple host:port's in url.Host by splitting them into host,host,host and port,port,port.
|
||||
var hosts []string
|
||||
var ports []string
|
||||
for _, host := range strings.Split(parsedURL.Host, ",") {
|
||||
for host := range strings.SplitSeq(parsedURL.Host, ",") {
|
||||
if host == "" {
|
||||
continue
|
||||
}
|
||||
@@ -614,6 +690,9 @@ func parseKeywordValueSettings(s string) (map[string]string, error) {
|
||||
return nil, errors.New("invalid keyword/value")
|
||||
}
|
||||
|
||||
if key == "user" && val == "" {
|
||||
continue
|
||||
}
|
||||
settings[key] = val
|
||||
}
|
||||
|
||||
@@ -784,7 +863,7 @@ func configTLS(settings map[string]string, thisHost string, parseConfigOptions P
|
||||
// Attempt decryption with pass phrase
|
||||
// NOTE: only supports RSA (PKCS#1)
|
||||
if sslpassword != "" {
|
||||
decryptedKey, decryptedError = x509.DecryptPEMBlock(block, []byte(sslpassword))
|
||||
decryptedKey, decryptedError = x509.DecryptPEMBlock(block, []byte(sslpassword)) //nolint:ineffassign
|
||||
}
|
||||
// if sslpassword not provided or has decryption error when use it
|
||||
// try to find sslpassword with callback function
|
||||
@@ -799,7 +878,7 @@ func configTLS(settings map[string]string, thisHost string, parseConfigOptions P
|
||||
decryptedKey, decryptedError = x509.DecryptPEMBlock(block, []byte(sslpassword))
|
||||
// Should we also provide warning for PKCS#1 needed?
|
||||
if decryptedError != nil {
|
||||
return nil, fmt.Errorf("unable to decrypt key: %w", err)
|
||||
return nil, fmt.Errorf("unable to decrypt key: %w", decryptedError)
|
||||
}
|
||||
|
||||
pemBytes := pem.Block{
|
||||
@@ -951,3 +1030,14 @@ func ValidateConnectTargetSessionAttrsPreferStandby(ctx context.Context, pgConn
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseProtocolVersion(s string) (uint32, error) {
|
||||
switch s {
|
||||
case "", "3.0":
|
||||
return pgproto3.ProtocolVersion30, nil
|
||||
case "3.2", "latest":
|
||||
return pgproto3.ProtocolVersion32, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("invalid protocol version: %q", s)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user