mirror of
https://github.com/prometheus-community/postgres_exporter
synced 2025-04-27 05:28:03 +00:00
Updated lib/pg driver to 1.2.0 in order to support stronger SCRAM-SHA-256 authentication. This drops support for Go < 1.11 and PostgreSQL < 9.4. (#304)
This commit is contained in:
parent
b33c2f9349
commit
69a90e8a33
15
vendor/github.com/lib/pq/README.md
generated
vendored
15
vendor/github.com/lib/pq/README.md
generated
vendored
@ -10,22 +10,11 @@
|
|||||||
## Docs
|
## Docs
|
||||||
|
|
||||||
For detailed documentation and basic usage examples, please see the package
|
For detailed documentation and basic usage examples, please see the package
|
||||||
documentation at <http://godoc.org/github.com/lib/pq>.
|
documentation at <https://godoc.org/github.com/lib/pq>.
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
`go test` is used for testing. A running PostgreSQL server is
|
`go test` is used for testing. See [TESTS.md](TESTS.md) for more details.
|
||||||
required, with the ability to log in. The default database to connect
|
|
||||||
to test with is "pqgotest," but it can be overridden using environment
|
|
||||||
variables.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
PGHOST=/run/postgresql go test github.com/lib/pq
|
|
||||||
|
|
||||||
Optionally, a benchmark suite can be run as part of the tests:
|
|
||||||
|
|
||||||
PGHOST=/run/postgresql go test -bench .
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
33
vendor/github.com/lib/pq/TESTS.md
generated
vendored
Normal file
33
vendor/github.com/lib/pq/TESTS.md
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Tests
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
`go test` is used for testing. A running PostgreSQL
|
||||||
|
server is required, with the ability to log in. The
|
||||||
|
database to connect to test with is "pqgotest," on
|
||||||
|
"localhost" but these can be overridden using [environment
|
||||||
|
variables](https://www.postgresql.org/docs/9.3/static/libpq-envars.html).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
PGHOST=/run/postgresql go test
|
||||||
|
|
||||||
|
## Benchmarks
|
||||||
|
|
||||||
|
A benchmark suite can be run as part of the tests:
|
||||||
|
|
||||||
|
go test -bench .
|
||||||
|
|
||||||
|
## Example setup (Docker)
|
||||||
|
|
||||||
|
Run a postgres container:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run --expose 5432:5432 postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
Run tests:
|
||||||
|
|
||||||
|
```
|
||||||
|
PGHOST=localhost PGPORT=5432 PGUSER=postgres PGSSLMODE=disable PGDATABASE=postgres go test
|
||||||
|
```
|
2
vendor/github.com/lib/pq/buf.go
generated
vendored
2
vendor/github.com/lib/pq/buf.go
generated
vendored
@ -66,7 +66,7 @@ func (b *writeBuf) int16(n int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *writeBuf) string(s string) {
|
func (b *writeBuf) string(s string) {
|
||||||
b.buf = append(b.buf, (s + "\000")...)
|
b.buf = append(append(b.buf, s...), '\000')
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *writeBuf) byte(c byte) {
|
func (b *writeBuf) byte(c byte) {
|
||||||
|
324
vendor/github.com/lib/pq/conn.go
generated
vendored
324
vendor/github.com/lib/pq/conn.go
generated
vendored
@ -2,7 +2,9 @@ package pq
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
"crypto/sha256"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
@ -20,6 +22,7 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/lib/pq/oid"
|
"github.com/lib/pq/oid"
|
||||||
|
"github.com/lib/pq/scram"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common error types
|
// Common error types
|
||||||
@ -89,13 +92,25 @@ type Dialer interface {
|
|||||||
DialTimeout(network, address string, timeout time.Duration) (net.Conn, error)
|
DialTimeout(network, address string, timeout time.Duration) (net.Conn, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type defaultDialer struct{}
|
// DialerContext is the context-aware dialer interface.
|
||||||
|
type DialerContext interface {
|
||||||
func (d defaultDialer) Dial(ntw, addr string) (net.Conn, error) {
|
DialContext(ctx context.Context, network, address string) (net.Conn, error)
|
||||||
return net.Dial(ntw, addr)
|
|
||||||
}
|
}
|
||||||
func (d defaultDialer) DialTimeout(ntw, addr string, timeout time.Duration) (net.Conn, error) {
|
|
||||||
return net.DialTimeout(ntw, addr, timeout)
|
type defaultDialer struct {
|
||||||
|
d net.Dialer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d defaultDialer) Dial(network, address string) (net.Conn, error) {
|
||||||
|
return d.d.Dial(network, address)
|
||||||
|
}
|
||||||
|
func (d defaultDialer) DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
return d.DialContext(ctx, network, address)
|
||||||
|
}
|
||||||
|
func (d defaultDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
|
return d.d.DialContext(ctx, network, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
type conn struct {
|
type conn struct {
|
||||||
@ -244,90 +259,35 @@ func (cn *conn) writeBuf(b byte) *writeBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open opens a new connection to the database. name is a connection string.
|
// Open opens a new connection to the database. dsn is a connection string.
|
||||||
// Most users should only use it through database/sql package from the standard
|
// Most users should only use it through database/sql package from the standard
|
||||||
// library.
|
// library.
|
||||||
func Open(name string) (_ driver.Conn, err error) {
|
func Open(dsn string) (_ driver.Conn, err error) {
|
||||||
return DialOpen(defaultDialer{}, name)
|
return DialOpen(defaultDialer{}, dsn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialOpen opens a new connection to the database using a dialer.
|
// DialOpen opens a new connection to the database using a dialer.
|
||||||
func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
|
func DialOpen(d Dialer, dsn string) (_ driver.Conn, err error) {
|
||||||
|
c, err := NewConnector(dsn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.dialer = d
|
||||||
|
return c.open(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connector) open(ctx context.Context) (cn *conn, err error) {
|
||||||
// Handle any panics during connection initialization. Note that we
|
// Handle any panics during connection initialization. Note that we
|
||||||
// specifically do *not* want to use errRecover(), as that would turn any
|
// specifically do *not* want to use errRecover(), as that would turn any
|
||||||
// connection errors into ErrBadConns, hiding the real error message from
|
// connection errors into ErrBadConns, hiding the real error message from
|
||||||
// the user.
|
// the user.
|
||||||
defer errRecoverNoErrBadConn(&err)
|
defer errRecoverNoErrBadConn(&err)
|
||||||
|
|
||||||
o := make(values)
|
o := c.opts
|
||||||
|
|
||||||
// A number of defaults are applied here, in this order:
|
cn = &conn{
|
||||||
//
|
|
||||||
// * Very low precedence defaults applied in every situation
|
|
||||||
// * Environment variables
|
|
||||||
// * Explicitly passed connection information
|
|
||||||
o["host"] = "localhost"
|
|
||||||
o["port"] = "5432"
|
|
||||||
// N.B.: Extra float digits should be set to 3, but that breaks
|
|
||||||
// Postgres 8.4 and older, where the max is 2.
|
|
||||||
o["extra_float_digits"] = "2"
|
|
||||||
for k, v := range parseEnviron(os.Environ()) {
|
|
||||||
o[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(name, "postgres://") || strings.HasPrefix(name, "postgresql://") {
|
|
||||||
name, err = ParseURL(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := parseOpts(name, o); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the "fallback" application name if necessary
|
|
||||||
if fallback, ok := o["fallback_application_name"]; ok {
|
|
||||||
if _, ok := o["application_name"]; !ok {
|
|
||||||
o["application_name"] = fallback
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can't work with any client_encoding other than UTF-8 currently.
|
|
||||||
// However, we have historically allowed the user to set it to UTF-8
|
|
||||||
// explicitly, and there's no reason to break such programs, so allow that.
|
|
||||||
// Note that the "options" setting could also set client_encoding, but
|
|
||||||
// parsing its value is not worth it. Instead, we always explicitly send
|
|
||||||
// client_encoding as a separate run-time parameter, which should override
|
|
||||||
// anything set in options.
|
|
||||||
if enc, ok := o["client_encoding"]; ok && !isUTF8(enc) {
|
|
||||||
return nil, errors.New("client_encoding must be absent or 'UTF8'")
|
|
||||||
}
|
|
||||||
o["client_encoding"] = "UTF8"
|
|
||||||
// DateStyle needs a similar treatment.
|
|
||||||
if datestyle, ok := o["datestyle"]; ok {
|
|
||||||
if datestyle != "ISO, MDY" {
|
|
||||||
panic(fmt.Sprintf("setting datestyle must be absent or %v; got %v",
|
|
||||||
"ISO, MDY", datestyle))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
o["datestyle"] = "ISO, MDY"
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a user is not provided by any other means, the last
|
|
||||||
// resort is to use the current operating system provided user
|
|
||||||
// name.
|
|
||||||
if _, ok := o["user"]; !ok {
|
|
||||||
u, err := userCurrent()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
o["user"] = u
|
|
||||||
}
|
|
||||||
|
|
||||||
cn := &conn{
|
|
||||||
opts: o,
|
opts: o,
|
||||||
dialer: d,
|
dialer: c.dialer,
|
||||||
}
|
}
|
||||||
err = cn.handleDriverSettings(o)
|
err = cn.handleDriverSettings(o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -335,11 +295,27 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
|
|||||||
}
|
}
|
||||||
cn.handlePgpass(o)
|
cn.handlePgpass(o)
|
||||||
|
|
||||||
cn.c, err = dial(d, o)
|
cn.c, err = dial(ctx, c.dialer, o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cn.ssl(o)
|
|
||||||
|
err = cn.ssl(o)
|
||||||
|
if err != nil {
|
||||||
|
if cn.c != nil {
|
||||||
|
cn.c.Close()
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// cn.startup panics on error. Make sure we don't leak cn.c.
|
||||||
|
panicking := true
|
||||||
|
defer func() {
|
||||||
|
if panicking {
|
||||||
|
cn.c.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
cn.buf = bufio.NewReader(cn.c)
|
cn.buf = bufio.NewReader(cn.c)
|
||||||
cn.startup(o)
|
cn.startup(o)
|
||||||
|
|
||||||
@ -347,13 +323,14 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
|
|||||||
if timeout, ok := o["connect_timeout"]; ok && timeout != "0" {
|
if timeout, ok := o["connect_timeout"]; ok && timeout != "0" {
|
||||||
err = cn.c.SetDeadline(time.Time{})
|
err = cn.c.SetDeadline(time.Time{})
|
||||||
}
|
}
|
||||||
|
panicking = false
|
||||||
return cn, err
|
return cn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func dial(d Dialer, o values) (net.Conn, error) {
|
func dial(ctx context.Context, d Dialer, o values) (net.Conn, error) {
|
||||||
ntw, addr := network(o)
|
network, address := network(o)
|
||||||
// SSL is not necessary or supported over UNIX domain sockets
|
// SSL is not necessary or supported over UNIX domain sockets
|
||||||
if ntw == "unix" {
|
if network == "unix" {
|
||||||
o["sslmode"] = "disable"
|
o["sslmode"] = "disable"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,19 +341,30 @@ func dial(d Dialer, o values) (net.Conn, error) {
|
|||||||
return nil, fmt.Errorf("invalid value for parameter connect_timeout: %s", err)
|
return nil, fmt.Errorf("invalid value for parameter connect_timeout: %s", err)
|
||||||
}
|
}
|
||||||
duration := time.Duration(seconds) * time.Second
|
duration := time.Duration(seconds) * time.Second
|
||||||
|
|
||||||
// connect_timeout should apply to the entire connection establishment
|
// connect_timeout should apply to the entire connection establishment
|
||||||
// procedure, so we both use a timeout for the TCP connection
|
// procedure, so we both use a timeout for the TCP connection
|
||||||
// establishment and set a deadline for doing the initial handshake.
|
// establishment and set a deadline for doing the initial handshake.
|
||||||
// The deadline is then reset after startup() is done.
|
// The deadline is then reset after startup() is done.
|
||||||
deadline := time.Now().Add(duration)
|
deadline := time.Now().Add(duration)
|
||||||
conn, err := d.DialTimeout(ntw, addr, duration)
|
var conn net.Conn
|
||||||
|
if dctx, ok := d.(DialerContext); ok {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, duration)
|
||||||
|
defer cancel()
|
||||||
|
conn, err = dctx.DialContext(ctx, network, address)
|
||||||
|
} else {
|
||||||
|
conn, err = d.DialTimeout(network, address, duration)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = conn.SetDeadline(deadline)
|
err = conn.SetDeadline(deadline)
|
||||||
return conn, err
|
return conn, err
|
||||||
}
|
}
|
||||||
return d.Dial(ntw, addr)
|
if dctx, ok := d.(DialerContext); ok {
|
||||||
|
return dctx.DialContext(ctx, network, address)
|
||||||
|
}
|
||||||
|
return d.Dial(network, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
func network(o values) (string, string) {
|
func network(o values) (string, string) {
|
||||||
@ -562,7 +550,7 @@ func (cn *conn) Commit() (err error) {
|
|||||||
// would get the same behaviour if you issued a COMMIT in a failed
|
// would get the same behaviour if you issued a COMMIT in a failed
|
||||||
// transaction, so it's also the least surprising thing to do here.
|
// transaction, so it's also the least surprising thing to do here.
|
||||||
if cn.txnStatus == txnStatusInFailedTransaction {
|
if cn.txnStatus == txnStatusInFailedTransaction {
|
||||||
if err := cn.Rollback(); err != nil {
|
if err := cn.rollback(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return ErrInFailedTransaction
|
return ErrInFailedTransaction
|
||||||
@ -589,7 +577,10 @@ func (cn *conn) Rollback() (err error) {
|
|||||||
return driver.ErrBadConn
|
return driver.ErrBadConn
|
||||||
}
|
}
|
||||||
defer cn.errRecover(&err)
|
defer cn.errRecover(&err)
|
||||||
|
return cn.rollback()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cn *conn) rollback() (err error) {
|
||||||
cn.checkIsInTransaction(true)
|
cn.checkIsInTransaction(true)
|
||||||
_, commandTag, err := cn.simpleExec("ROLLBACK")
|
_, commandTag, err := cn.simpleExec("ROLLBACK")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -690,7 +681,7 @@ func (cn *conn) simpleQuery(q string) (res *rows, err error) {
|
|||||||
// res might be non-nil here if we received a previous
|
// res might be non-nil here if we received a previous
|
||||||
// CommandComplete, but that's fine; just overwrite it
|
// CommandComplete, but that's fine; just overwrite it
|
||||||
res = &rows{cn: cn}
|
res = &rows{cn: cn}
|
||||||
res.colNames, res.colFmts, res.colTyps = parsePortalRowDescribe(r)
|
res.rowsHeader = parsePortalRowDescribe(r)
|
||||||
|
|
||||||
// To work around a bug in QueryRow in Go 1.2 and earlier, wait
|
// To work around a bug in QueryRow in Go 1.2 and earlier, wait
|
||||||
// until the first DataRow has been received.
|
// until the first DataRow has been received.
|
||||||
@ -847,7 +838,7 @@ func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {
|
|||||||
cn.readParseResponse()
|
cn.readParseResponse()
|
||||||
cn.readBindResponse()
|
cn.readBindResponse()
|
||||||
rows := &rows{cn: cn}
|
rows := &rows{cn: cn}
|
||||||
rows.colNames, rows.colFmts, rows.colTyps = cn.readPortalDescribeResponse()
|
rows.rowsHeader = cn.readPortalDescribeResponse()
|
||||||
cn.postExecuteWorkaround()
|
cn.postExecuteWorkaround()
|
||||||
return rows, nil
|
return rows, nil
|
||||||
}
|
}
|
||||||
@ -855,9 +846,7 @@ func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {
|
|||||||
st.exec(args)
|
st.exec(args)
|
||||||
return &rows{
|
return &rows{
|
||||||
cn: cn,
|
cn: cn,
|
||||||
colNames: st.colNames,
|
rowsHeader: st.rowsHeader,
|
||||||
colTyps: st.colTyps,
|
|
||||||
colFmts: st.colFmts,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -978,7 +967,6 @@ func (cn *conn) recv() (t byte, r *readBuf) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
case 'E':
|
case 'E':
|
||||||
panic(parseError(r))
|
panic(parseError(r))
|
||||||
@ -1019,30 +1007,35 @@ func (cn *conn) recv1() (t byte, r *readBuf) {
|
|||||||
return t, r
|
return t, r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cn *conn) ssl(o values) {
|
func (cn *conn) ssl(o values) error {
|
||||||
upgrade := ssl(o)
|
upgrade, err := ssl(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if upgrade == nil {
|
if upgrade == nil {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
w := cn.writeBuf(0)
|
w := cn.writeBuf(0)
|
||||||
w.int32(80877103)
|
w.int32(80877103)
|
||||||
if err := cn.sendStartupPacket(w); err != nil {
|
if err = cn.sendStartupPacket(w); err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
b := cn.scratch[:1]
|
b := cn.scratch[:1]
|
||||||
_, err := io.ReadFull(cn.c, b)
|
_, err = io.ReadFull(cn.c, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if b[0] != 'S' {
|
if b[0] != 'S' {
|
||||||
panic(ErrSSLNotSupported)
|
return ErrSSLNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
cn.c = upgrade(cn.c)
|
cn.c, err = upgrade(cn.c)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// isDriverSetting returns true iff a setting is purely for configuring the
|
// isDriverSetting returns true iff a setting is purely for configuring the
|
||||||
@ -1144,6 +1137,55 @@ func (cn *conn) auth(r *readBuf, o values) {
|
|||||||
if r.int32() != 0 {
|
if r.int32() != 0 {
|
||||||
errorf("unexpected authentication response: %q", t)
|
errorf("unexpected authentication response: %q", t)
|
||||||
}
|
}
|
||||||
|
case 10:
|
||||||
|
sc := scram.NewClient(sha256.New, o["user"], o["password"])
|
||||||
|
sc.Step(nil)
|
||||||
|
if sc.Err() != nil {
|
||||||
|
errorf("SCRAM-SHA-256 error: %s", sc.Err().Error())
|
||||||
|
}
|
||||||
|
scOut := sc.Out()
|
||||||
|
|
||||||
|
w := cn.writeBuf('p')
|
||||||
|
w.string("SCRAM-SHA-256")
|
||||||
|
w.int32(len(scOut))
|
||||||
|
w.bytes(scOut)
|
||||||
|
cn.send(w)
|
||||||
|
|
||||||
|
t, r := cn.recv()
|
||||||
|
if t != 'R' {
|
||||||
|
errorf("unexpected password response: %q", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.int32() != 11 {
|
||||||
|
errorf("unexpected authentication response: %q", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
nextStep := r.next(len(*r))
|
||||||
|
sc.Step(nextStep)
|
||||||
|
if sc.Err() != nil {
|
||||||
|
errorf("SCRAM-SHA-256 error: %s", sc.Err().Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
scOut = sc.Out()
|
||||||
|
w = cn.writeBuf('p')
|
||||||
|
w.bytes(scOut)
|
||||||
|
cn.send(w)
|
||||||
|
|
||||||
|
t, r = cn.recv()
|
||||||
|
if t != 'R' {
|
||||||
|
errorf("unexpected password response: %q", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.int32() != 12 {
|
||||||
|
errorf("unexpected authentication response: %q", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
nextStep = r.next(len(*r))
|
||||||
|
sc.Step(nextStep)
|
||||||
|
if sc.Err() != nil {
|
||||||
|
errorf("SCRAM-SHA-256 error: %s", sc.Err().Error())
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errorf("unknown authentication response: %d", code)
|
errorf("unknown authentication response: %d", code)
|
||||||
}
|
}
|
||||||
@ -1163,10 +1205,8 @@ var colFmtDataAllText = []byte{0, 0}
|
|||||||
type stmt struct {
|
type stmt struct {
|
||||||
cn *conn
|
cn *conn
|
||||||
name string
|
name string
|
||||||
colNames []string
|
rowsHeader
|
||||||
colFmts []format
|
|
||||||
colFmtData []byte
|
colFmtData []byte
|
||||||
colTyps []fieldDesc
|
|
||||||
paramTyps []oid.Oid
|
paramTyps []oid.Oid
|
||||||
closed bool
|
closed bool
|
||||||
}
|
}
|
||||||
@ -1213,9 +1253,7 @@ func (st *stmt) Query(v []driver.Value) (r driver.Rows, err error) {
|
|||||||
st.exec(v)
|
st.exec(v)
|
||||||
return &rows{
|
return &rows{
|
||||||
cn: st.cn,
|
cn: st.cn,
|
||||||
colNames: st.colNames,
|
rowsHeader: st.rowsHeader,
|
||||||
colTyps: st.colTyps,
|
|
||||||
colFmts: st.colFmts,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1325,16 +1363,22 @@ func (cn *conn) parseComplete(commandTag string) (driver.Result, string) {
|
|||||||
return driver.RowsAffected(n), commandTag
|
return driver.RowsAffected(n), commandTag
|
||||||
}
|
}
|
||||||
|
|
||||||
type rows struct {
|
type rowsHeader struct {
|
||||||
cn *conn
|
|
||||||
finish func()
|
|
||||||
colNames []string
|
colNames []string
|
||||||
colTyps []fieldDesc
|
colTyps []fieldDesc
|
||||||
colFmts []format
|
colFmts []format
|
||||||
|
}
|
||||||
|
|
||||||
|
type rows struct {
|
||||||
|
cn *conn
|
||||||
|
finish func()
|
||||||
|
rowsHeader
|
||||||
done bool
|
done bool
|
||||||
rb readBuf
|
rb readBuf
|
||||||
result driver.Result
|
result driver.Result
|
||||||
tag string
|
tag string
|
||||||
|
|
||||||
|
next *rowsHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *rows) Close() error {
|
func (rs *rows) Close() error {
|
||||||
@ -1421,7 +1465,8 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
case 'T':
|
case 'T':
|
||||||
rs.colNames, rs.colFmts, rs.colTyps = parsePortalRowDescribe(&rs.rb)
|
next := parsePortalRowDescribe(&rs.rb)
|
||||||
|
rs.next = &next
|
||||||
return io.EOF
|
return io.EOF
|
||||||
default:
|
default:
|
||||||
errorf("unexpected message after execute: %q", t)
|
errorf("unexpected message after execute: %q", t)
|
||||||
@ -1430,10 +1475,16 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rs *rows) HasNextResultSet() bool {
|
func (rs *rows) HasNextResultSet() bool {
|
||||||
return !rs.done
|
hasNext := rs.next != nil && !rs.done
|
||||||
|
return hasNext
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *rows) NextResultSet() error {
|
func (rs *rows) NextResultSet() error {
|
||||||
|
if rs.next == nil {
|
||||||
|
return io.EOF
|
||||||
|
}
|
||||||
|
rs.rowsHeader = *rs.next
|
||||||
|
rs.next = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1456,6 +1507,39 @@ func QuoteIdentifier(name string) string {
|
|||||||
return `"` + strings.Replace(name, `"`, `""`, -1) + `"`
|
return `"` + strings.Replace(name, `"`, `""`, -1) + `"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QuoteLiteral quotes a 'literal' (e.g. a parameter, often used to pass literal
|
||||||
|
// to DDL and other statements that do not accept parameters) to be used as part
|
||||||
|
// of an SQL statement. For example:
|
||||||
|
//
|
||||||
|
// exp_date := pq.QuoteLiteral("2023-01-05 15:00:00Z")
|
||||||
|
// err := db.Exec(fmt.Sprintf("CREATE ROLE my_user VALID UNTIL %s", exp_date))
|
||||||
|
//
|
||||||
|
// Any single quotes in name will be escaped. Any backslashes (i.e. "\") will be
|
||||||
|
// replaced by two backslashes (i.e. "\\") and the C-style escape identifier
|
||||||
|
// that PostgreSQL provides ('E') will be prepended to the string.
|
||||||
|
func QuoteLiteral(literal string) string {
|
||||||
|
// This follows the PostgreSQL internal algorithm for handling quoted literals
|
||||||
|
// from libpq, which can be found in the "PQEscapeStringInternal" function,
|
||||||
|
// which is found in the libpq/fe-exec.c source file:
|
||||||
|
// https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/interfaces/libpq/fe-exec.c
|
||||||
|
//
|
||||||
|
// substitute any single-quotes (') with two single-quotes ('')
|
||||||
|
literal = strings.Replace(literal, `'`, `''`, -1)
|
||||||
|
// determine if the string has any backslashes (\) in it.
|
||||||
|
// if it does, replace any backslashes (\) with two backslashes (\\)
|
||||||
|
// then, we need to wrap the entire string with a PostgreSQL
|
||||||
|
// C-style escape. Per how "PQEscapeStringInternal" handles this case, we
|
||||||
|
// also add a space before the "E"
|
||||||
|
if strings.Contains(literal, `\`) {
|
||||||
|
literal = strings.Replace(literal, `\`, `\\`, -1)
|
||||||
|
literal = ` E'` + literal + `'`
|
||||||
|
} else {
|
||||||
|
// otherwise, we can just wrap the literal with a pair of single quotes
|
||||||
|
literal = `'` + literal + `'`
|
||||||
|
}
|
||||||
|
return literal
|
||||||
|
}
|
||||||
|
|
||||||
func md5s(s string) string {
|
func md5s(s string) string {
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
h.Write([]byte(s))
|
h.Write([]byte(s))
|
||||||
@ -1611,13 +1695,13 @@ func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cn *conn) readPortalDescribeResponse() (colNames []string, colFmts []format, colTyps []fieldDesc) {
|
func (cn *conn) readPortalDescribeResponse() rowsHeader {
|
||||||
t, r := cn.recv1()
|
t, r := cn.recv1()
|
||||||
switch t {
|
switch t {
|
||||||
case 'T':
|
case 'T':
|
||||||
return parsePortalRowDescribe(r)
|
return parsePortalRowDescribe(r)
|
||||||
case 'n':
|
case 'n':
|
||||||
return nil, nil, nil
|
return rowsHeader{}
|
||||||
case 'E':
|
case 'E':
|
||||||
err := parseError(r)
|
err := parseError(r)
|
||||||
cn.readReadyForQuery()
|
cn.readReadyForQuery()
|
||||||
@ -1723,11 +1807,11 @@ func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []fieldDe
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePortalRowDescribe(r *readBuf) (colNames []string, colFmts []format, colTyps []fieldDesc) {
|
func parsePortalRowDescribe(r *readBuf) rowsHeader {
|
||||||
n := r.int16()
|
n := r.int16()
|
||||||
colNames = make([]string, n)
|
colNames := make([]string, n)
|
||||||
colFmts = make([]format, n)
|
colFmts := make([]format, n)
|
||||||
colTyps = make([]fieldDesc, n)
|
colTyps := make([]fieldDesc, n)
|
||||||
for i := range colNames {
|
for i := range colNames {
|
||||||
colNames[i] = r.string()
|
colNames[i] = r.string()
|
||||||
r.next(6)
|
r.next(6)
|
||||||
@ -1736,7 +1820,11 @@ func parsePortalRowDescribe(r *readBuf) (colNames []string, colFmts []format, co
|
|||||||
colTyps[i].Mod = r.int32()
|
colTyps[i].Mod = r.int32()
|
||||||
colFmts[i] = format(r.int16())
|
colFmts[i] = format(r.int16())
|
||||||
}
|
}
|
||||||
return
|
return rowsHeader{
|
||||||
|
colNames: colNames,
|
||||||
|
colFmts: colFmts,
|
||||||
|
colTyps: colTyps,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseEnviron tries to mimic some of libpq's environment handling
|
// parseEnviron tries to mimic some of libpq's environment handling
|
||||||
|
33
vendor/github.com/lib/pq/conn_go18.go
generated
vendored
33
vendor/github.com/lib/pq/conn_go18.go
generated
vendored
@ -1,5 +1,3 @@
|
|||||||
// +build go1.8
|
|
||||||
|
|
||||||
package pq
|
package pq
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -9,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Implement the "QueryerContext" interface
|
// Implement the "QueryerContext" interface
|
||||||
@ -76,13 +75,32 @@ func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx,
|
|||||||
return tx, nil
|
return tx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cn *conn) Ping(ctx context.Context) error {
|
||||||
|
if finish := cn.watchCancel(ctx); finish != nil {
|
||||||
|
defer finish()
|
||||||
|
}
|
||||||
|
rows, err := cn.simpleQuery("SELECT 'lib/pq ping test';")
|
||||||
|
if err != nil {
|
||||||
|
return driver.ErrBadConn // https://golang.org/pkg/database/sql/driver/#Pinger
|
||||||
|
}
|
||||||
|
rows.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (cn *conn) watchCancel(ctx context.Context) func() {
|
func (cn *conn) watchCancel(ctx context.Context) func() {
|
||||||
if done := ctx.Done(); done != nil {
|
if done := ctx.Done(); done != nil {
|
||||||
finished := make(chan struct{})
|
finished := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
_ = cn.cancel()
|
// At this point the function level context is canceled,
|
||||||
|
// so it must not be used for the additional network
|
||||||
|
// request to cancel the query.
|
||||||
|
// Create a new context to pass into the dial.
|
||||||
|
ctxCancel, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
_ = cn.cancel(ctxCancel)
|
||||||
finished <- struct{}{}
|
finished <- struct{}{}
|
||||||
case <-finished:
|
case <-finished:
|
||||||
}
|
}
|
||||||
@ -97,8 +115,8 @@ func (cn *conn) watchCancel(ctx context.Context) func() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cn *conn) cancel() error {
|
func (cn *conn) cancel(ctx context.Context) error {
|
||||||
c, err := dial(cn.dialer, cn.opts)
|
c, err := dial(ctx, cn.dialer, cn.opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -108,7 +126,10 @@ func (cn *conn) cancel() error {
|
|||||||
can := conn{
|
can := conn{
|
||||||
c: c,
|
c: c,
|
||||||
}
|
}
|
||||||
can.ssl(cn.opts)
|
err = can.ssl(cn.opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
w := can.writeBuf(0)
|
w := can.writeBuf(0)
|
||||||
w.int32(80877102) // cancel request code
|
w.int32(80877102) // cancel request code
|
||||||
|
110
vendor/github.com/lib/pq/connector.go
generated
vendored
Normal file
110
vendor/github.com/lib/pq/connector.go
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package pq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql/driver"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Connector represents a fixed configuration for the pq driver with a given
|
||||||
|
// name. Connector satisfies the database/sql/driver Connector interface and
|
||||||
|
// can be used to create any number of DB Conn's via the database/sql OpenDB
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
// See https://golang.org/pkg/database/sql/driver/#Connector.
|
||||||
|
// See https://golang.org/pkg/database/sql/#OpenDB.
|
||||||
|
type Connector struct {
|
||||||
|
opts values
|
||||||
|
dialer Dialer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect returns a connection to the database using the fixed configuration
|
||||||
|
// of this Connector. Context is not used.
|
||||||
|
func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) {
|
||||||
|
return c.open(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Driver returnst the underlying driver of this Connector.
|
||||||
|
func (c *Connector) Driver() driver.Driver {
|
||||||
|
return &Driver{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConnector returns a connector for the pq driver in a fixed configuration
|
||||||
|
// with the given dsn. The returned connector can be used to create any number
|
||||||
|
// of equivalent Conn's. The returned connector is intended to be used with
|
||||||
|
// database/sql.OpenDB.
|
||||||
|
//
|
||||||
|
// See https://golang.org/pkg/database/sql/driver/#Connector.
|
||||||
|
// See https://golang.org/pkg/database/sql/#OpenDB.
|
||||||
|
func NewConnector(dsn string) (*Connector, error) {
|
||||||
|
var err error
|
||||||
|
o := make(values)
|
||||||
|
|
||||||
|
// A number of defaults are applied here, in this order:
|
||||||
|
//
|
||||||
|
// * Very low precedence defaults applied in every situation
|
||||||
|
// * Environment variables
|
||||||
|
// * Explicitly passed connection information
|
||||||
|
o["host"] = "localhost"
|
||||||
|
o["port"] = "5432"
|
||||||
|
// N.B.: Extra float digits should be set to 3, but that breaks
|
||||||
|
// Postgres 8.4 and older, where the max is 2.
|
||||||
|
o["extra_float_digits"] = "2"
|
||||||
|
for k, v := range parseEnviron(os.Environ()) {
|
||||||
|
o[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(dsn, "postgres://") || strings.HasPrefix(dsn, "postgresql://") {
|
||||||
|
dsn, err = ParseURL(dsn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := parseOpts(dsn, o); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the "fallback" application name if necessary
|
||||||
|
if fallback, ok := o["fallback_application_name"]; ok {
|
||||||
|
if _, ok := o["application_name"]; !ok {
|
||||||
|
o["application_name"] = fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't work with any client_encoding other than UTF-8 currently.
|
||||||
|
// However, we have historically allowed the user to set it to UTF-8
|
||||||
|
// explicitly, and there's no reason to break such programs, so allow that.
|
||||||
|
// Note that the "options" setting could also set client_encoding, but
|
||||||
|
// parsing its value is not worth it. Instead, we always explicitly send
|
||||||
|
// client_encoding as a separate run-time parameter, which should override
|
||||||
|
// anything set in options.
|
||||||
|
if enc, ok := o["client_encoding"]; ok && !isUTF8(enc) {
|
||||||
|
return nil, errors.New("client_encoding must be absent or 'UTF8'")
|
||||||
|
}
|
||||||
|
o["client_encoding"] = "UTF8"
|
||||||
|
// DateStyle needs a similar treatment.
|
||||||
|
if datestyle, ok := o["datestyle"]; ok {
|
||||||
|
if datestyle != "ISO, MDY" {
|
||||||
|
return nil, fmt.Errorf("setting datestyle must be absent or %v; got %v", "ISO, MDY", datestyle)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
o["datestyle"] = "ISO, MDY"
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a user is not provided by any other means, the last
|
||||||
|
// resort is to use the current operating system provided user
|
||||||
|
// name.
|
||||||
|
if _, ok := o["user"]; !ok {
|
||||||
|
u, err := userCurrent()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
o["user"] = u
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Connector{opts: o, dialer: defaultDialer{}}, nil
|
||||||
|
}
|
2
vendor/github.com/lib/pq/copy.go
generated
vendored
2
vendor/github.com/lib/pq/copy.go
generated
vendored
@ -229,7 +229,7 @@ func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(v) == 0 {
|
if len(v) == 0 {
|
||||||
return nil, ci.Close()
|
return driver.RowsAffected(0), ci.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
numValues := len(v)
|
numValues := len(v)
|
||||||
|
2
vendor/github.com/lib/pq/doc.go
generated
vendored
2
vendor/github.com/lib/pq/doc.go
generated
vendored
@ -239,7 +239,7 @@ for more information). Note that the channel name will be truncated to 63
|
|||||||
bytes by the PostgreSQL server.
|
bytes by the PostgreSQL server.
|
||||||
|
|
||||||
You can find a complete, working example of Listener usage at
|
You can find a complete, working example of Listener usage at
|
||||||
http://godoc.org/github.com/lib/pq/examples/listen.
|
https://godoc.org/github.com/lib/pq/example/listen.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package pq
|
package pq
|
||||||
|
11
vendor/github.com/lib/pq/encode.go
generated
vendored
11
vendor/github.com/lib/pq/encode.go
generated
vendored
@ -117,11 +117,10 @@ func textDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interfa
|
|||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
case oid.T_float4, oid.T_float8:
|
case oid.T_float4, oid.T_float8:
|
||||||
bits := 64
|
// We always use 64 bit parsing, regardless of whether the input text is for
|
||||||
if typ == oid.T_float4 {
|
// a float4 or float8, because clients expect float64s for all float datatypes
|
||||||
bits = 32
|
// and returning a 32-bit parsed float64 produces lossy results.
|
||||||
}
|
f, err := strconv.ParseFloat(string(s), 64)
|
||||||
f, err := strconv.ParseFloat(string(s), bits)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorf("%s", err)
|
errorf("%s", err)
|
||||||
}
|
}
|
||||||
@ -488,7 +487,7 @@ func FormatTimestamp(t time.Time) []byte {
|
|||||||
b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00"))
|
b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00"))
|
||||||
|
|
||||||
_, offset := t.Zone()
|
_, offset := t.Zone()
|
||||||
offset = offset % 60
|
offset %= 60
|
||||||
if offset != 0 {
|
if offset != 0 {
|
||||||
// RFC3339Nano already printed the minus sign
|
// RFC3339Nano already printed the minus sign
|
||||||
if offset < 0 {
|
if offset < 0 {
|
||||||
|
17
vendor/github.com/lib/pq/error.go
generated
vendored
17
vendor/github.com/lib/pq/error.go
generated
vendored
@ -153,6 +153,7 @@ var errorCodeNames = map[ErrorCode]string{
|
|||||||
"22004": "null_value_not_allowed",
|
"22004": "null_value_not_allowed",
|
||||||
"22002": "null_value_no_indicator_parameter",
|
"22002": "null_value_no_indicator_parameter",
|
||||||
"22003": "numeric_value_out_of_range",
|
"22003": "numeric_value_out_of_range",
|
||||||
|
"2200H": "sequence_generator_limit_exceeded",
|
||||||
"22026": "string_data_length_mismatch",
|
"22026": "string_data_length_mismatch",
|
||||||
"22001": "string_data_right_truncation",
|
"22001": "string_data_right_truncation",
|
||||||
"22011": "substring_error",
|
"22011": "substring_error",
|
||||||
@ -459,6 +460,11 @@ func errorf(s string, args ...interface{}) {
|
|||||||
panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
|
panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(ainar-g) Rename to errorf after removing panics.
|
||||||
|
func fmterrorf(s string, args ...interface{}) error {
|
||||||
|
return fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))
|
||||||
|
}
|
||||||
|
|
||||||
func errRecoverNoErrBadConn(err *error) {
|
func errRecoverNoErrBadConn(err *error) {
|
||||||
e := recover()
|
e := recover()
|
||||||
if e == nil {
|
if e == nil {
|
||||||
@ -472,13 +478,13 @@ func errRecoverNoErrBadConn(err *error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) errRecover(err *error) {
|
func (cn *conn) errRecover(err *error) {
|
||||||
e := recover()
|
e := recover()
|
||||||
switch v := e.(type) {
|
switch v := e.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
// Do nothing
|
// Do nothing
|
||||||
case runtime.Error:
|
case runtime.Error:
|
||||||
c.bad = true
|
cn.bad = true
|
||||||
panic(v)
|
panic(v)
|
||||||
case *Error:
|
case *Error:
|
||||||
if v.Fatal() {
|
if v.Fatal() {
|
||||||
@ -487,7 +493,8 @@ func (c *conn) errRecover(err *error) {
|
|||||||
*err = v
|
*err = v
|
||||||
}
|
}
|
||||||
case *net.OpError:
|
case *net.OpError:
|
||||||
*err = driver.ErrBadConn
|
cn.bad = true
|
||||||
|
*err = v
|
||||||
case error:
|
case error:
|
||||||
if v == io.EOF || v.(error).Error() == "remote error: handshake failure" {
|
if v == io.EOF || v.(error).Error() == "remote error: handshake failure" {
|
||||||
*err = driver.ErrBadConn
|
*err = driver.ErrBadConn
|
||||||
@ -496,13 +503,13 @@ func (c *conn) errRecover(err *error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
c.bad = true
|
cn.bad = true
|
||||||
panic(fmt.Sprintf("unknown error: %#v", e))
|
panic(fmt.Sprintf("unknown error: %#v", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any time we return ErrBadConn, we need to remember it since *Tx doesn't
|
// Any time we return ErrBadConn, we need to remember it since *Tx doesn't
|
||||||
// mark the connection bad in database/sql.
|
// mark the connection bad in database/sql.
|
||||||
if *err == driver.ErrBadConn {
|
if *err == driver.ErrBadConn {
|
||||||
c.bad = true
|
cn.bad = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
vendor/github.com/lib/pq/go.mod
generated
vendored
Normal file
1
vendor/github.com/lib/pq/go.mod
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module github.com/lib/pq
|
9
vendor/github.com/lib/pq/notify.go
generated
vendored
9
vendor/github.com/lib/pq/notify.go
generated
vendored
@ -637,7 +637,7 @@ func (l *Listener) disconnectCleanup() error {
|
|||||||
// after the connection has been established.
|
// after the connection has been established.
|
||||||
func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notification) error {
|
func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notification) error {
|
||||||
doneChan := make(chan error)
|
doneChan := make(chan error)
|
||||||
go func() {
|
go func(notificationChan <-chan *Notification) {
|
||||||
for channel := range l.channels {
|
for channel := range l.channels {
|
||||||
// If we got a response, return that error to our caller as it's
|
// If we got a response, return that error to our caller as it's
|
||||||
// going to be more descriptive than cn.Err().
|
// going to be more descriptive than cn.Err().
|
||||||
@ -658,7 +658,7 @@ func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notificatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
doneChan <- nil
|
doneChan <- nil
|
||||||
}()
|
}(notificationChan)
|
||||||
|
|
||||||
// Ignore notifications while synchronization is going on to avoid
|
// Ignore notifications while synchronization is going on to avoid
|
||||||
// deadlocks. We have to send a nil notification over Notify anyway as
|
// deadlocks. We have to send a nil notification over Notify anyway as
|
||||||
@ -725,6 +725,9 @@ func (l *Listener) Close() error {
|
|||||||
}
|
}
|
||||||
l.isClosed = true
|
l.isClosed = true
|
||||||
|
|
||||||
|
// Unblock calls to Listen()
|
||||||
|
l.reconnectCond.Broadcast()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -784,7 +787,7 @@ func (l *Listener) listenerConnLoop() {
|
|||||||
}
|
}
|
||||||
l.emitEvent(ListenerEventDisconnected, err)
|
l.emitEvent(ListenerEventDisconnected, err)
|
||||||
|
|
||||||
time.Sleep(nextReconnect.Sub(time.Now()))
|
time.Sleep(time.Until(nextReconnect))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
264
vendor/github.com/lib/pq/scram/scram.go
generated
vendored
Normal file
264
vendor/github.com/lib/pq/scram/scram.go
generated
vendored
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
// Copyright (c) 2014 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
// list of conditions and the following disclaimer.
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// Package scram implements a SCRAM-{SHA-1,etc} client per RFC5802.
|
||||||
|
//
|
||||||
|
// http://tools.ietf.org/html/rfc5802
|
||||||
|
//
|
||||||
|
package scram
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"hash"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client implements a SCRAM-* client (SCRAM-SHA-1, SCRAM-SHA-256, etc).
|
||||||
|
//
|
||||||
|
// A Client may be used within a SASL conversation with logic resembling:
|
||||||
|
//
|
||||||
|
// var in []byte
|
||||||
|
// var client = scram.NewClient(sha1.New, user, pass)
|
||||||
|
// for client.Step(in) {
|
||||||
|
// out := client.Out()
|
||||||
|
// // send out to server
|
||||||
|
// in := serverOut
|
||||||
|
// }
|
||||||
|
// if client.Err() != nil {
|
||||||
|
// // auth failed
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
type Client struct {
|
||||||
|
newHash func() hash.Hash
|
||||||
|
|
||||||
|
user string
|
||||||
|
pass string
|
||||||
|
step int
|
||||||
|
out bytes.Buffer
|
||||||
|
err error
|
||||||
|
|
||||||
|
clientNonce []byte
|
||||||
|
serverNonce []byte
|
||||||
|
saltedPass []byte
|
||||||
|
authMsg bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a new SCRAM-* client with the provided hash algorithm.
|
||||||
|
//
|
||||||
|
// For SCRAM-SHA-256, for example, use:
|
||||||
|
//
|
||||||
|
// client := scram.NewClient(sha256.New, user, pass)
|
||||||
|
//
|
||||||
|
func NewClient(newHash func() hash.Hash, user, pass string) *Client {
|
||||||
|
c := &Client{
|
||||||
|
newHash: newHash,
|
||||||
|
user: user,
|
||||||
|
pass: pass,
|
||||||
|
}
|
||||||
|
c.out.Grow(256)
|
||||||
|
c.authMsg.Grow(256)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Out returns the data to be sent to the server in the current step.
|
||||||
|
func (c *Client) Out() []byte {
|
||||||
|
if c.out.Len() == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return c.out.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err returns the error that occurred, or nil if there were no errors.
|
||||||
|
func (c *Client) Err() error {
|
||||||
|
return c.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNonce sets the client nonce to the provided value.
|
||||||
|
// If not set, the nonce is generated automatically out of crypto/rand on the first step.
|
||||||
|
func (c *Client) SetNonce(nonce []byte) {
|
||||||
|
c.clientNonce = nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
var escaper = strings.NewReplacer("=", "=3D", ",", "=2C")
|
||||||
|
|
||||||
|
// Step processes the incoming data from the server and makes the
|
||||||
|
// next round of data for the server available via Client.Out.
|
||||||
|
// Step returns false if there are no errors and more data is
|
||||||
|
// still expected.
|
||||||
|
func (c *Client) Step(in []byte) bool {
|
||||||
|
c.out.Reset()
|
||||||
|
if c.step > 2 || c.err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
c.step++
|
||||||
|
switch c.step {
|
||||||
|
case 1:
|
||||||
|
c.err = c.step1(in)
|
||||||
|
case 2:
|
||||||
|
c.err = c.step2(in)
|
||||||
|
case 3:
|
||||||
|
c.err = c.step3(in)
|
||||||
|
}
|
||||||
|
return c.step > 2 || c.err != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) step1(in []byte) error {
|
||||||
|
if len(c.clientNonce) == 0 {
|
||||||
|
const nonceLen = 16
|
||||||
|
buf := make([]byte, nonceLen+b64.EncodedLen(nonceLen))
|
||||||
|
if _, err := rand.Read(buf[:nonceLen]); err != nil {
|
||||||
|
return fmt.Errorf("cannot read random SCRAM-SHA-256 nonce from operating system: %v", err)
|
||||||
|
}
|
||||||
|
c.clientNonce = buf[nonceLen:]
|
||||||
|
b64.Encode(c.clientNonce, buf[:nonceLen])
|
||||||
|
}
|
||||||
|
c.authMsg.WriteString("n=")
|
||||||
|
escaper.WriteString(&c.authMsg, c.user)
|
||||||
|
c.authMsg.WriteString(",r=")
|
||||||
|
c.authMsg.Write(c.clientNonce)
|
||||||
|
|
||||||
|
c.out.WriteString("n,,")
|
||||||
|
c.out.Write(c.authMsg.Bytes())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var b64 = base64.StdEncoding
|
||||||
|
|
||||||
|
func (c *Client) step2(in []byte) error {
|
||||||
|
c.authMsg.WriteByte(',')
|
||||||
|
c.authMsg.Write(in)
|
||||||
|
|
||||||
|
fields := bytes.Split(in, []byte(","))
|
||||||
|
if len(fields) != 3 {
|
||||||
|
return fmt.Errorf("expected 3 fields in first SCRAM-SHA-256 server message, got %d: %q", len(fields), in)
|
||||||
|
}
|
||||||
|
if !bytes.HasPrefix(fields[0], []byte("r=")) || len(fields[0]) < 2 {
|
||||||
|
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 nonce: %q", fields[0])
|
||||||
|
}
|
||||||
|
if !bytes.HasPrefix(fields[1], []byte("s=")) || len(fields[1]) < 6 {
|
||||||
|
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 salt: %q", fields[1])
|
||||||
|
}
|
||||||
|
if !bytes.HasPrefix(fields[2], []byte("i=")) || len(fields[2]) < 6 {
|
||||||
|
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
c.serverNonce = fields[0][2:]
|
||||||
|
if !bytes.HasPrefix(c.serverNonce, c.clientNonce) {
|
||||||
|
return fmt.Errorf("server SCRAM-SHA-256 nonce is not prefixed by client nonce: got %q, want %q+\"...\"", c.serverNonce, c.clientNonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
salt := make([]byte, b64.DecodedLen(len(fields[1][2:])))
|
||||||
|
n, err := b64.Decode(salt, fields[1][2:])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot decode SCRAM-SHA-256 salt sent by server: %q", fields[1])
|
||||||
|
}
|
||||||
|
salt = salt[:n]
|
||||||
|
iterCount, err := strconv.Atoi(string(fields[2][2:]))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2])
|
||||||
|
}
|
||||||
|
c.saltPassword(salt, iterCount)
|
||||||
|
|
||||||
|
c.authMsg.WriteString(",c=biws,r=")
|
||||||
|
c.authMsg.Write(c.serverNonce)
|
||||||
|
|
||||||
|
c.out.WriteString("c=biws,r=")
|
||||||
|
c.out.Write(c.serverNonce)
|
||||||
|
c.out.WriteString(",p=")
|
||||||
|
c.out.Write(c.clientProof())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) step3(in []byte) error {
|
||||||
|
var isv, ise bool
|
||||||
|
var fields = bytes.Split(in, []byte(","))
|
||||||
|
if len(fields) == 1 {
|
||||||
|
isv = bytes.HasPrefix(fields[0], []byte("v="))
|
||||||
|
ise = bytes.HasPrefix(fields[0], []byte("e="))
|
||||||
|
}
|
||||||
|
if ise {
|
||||||
|
return fmt.Errorf("SCRAM-SHA-256 authentication error: %s", fields[0][2:])
|
||||||
|
} else if !isv {
|
||||||
|
return fmt.Errorf("unsupported SCRAM-SHA-256 final message from server: %q", in)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(c.serverSignature(), fields[0][2:]) {
|
||||||
|
return fmt.Errorf("cannot authenticate SCRAM-SHA-256 server signature: %q", fields[0][2:])
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) saltPassword(salt []byte, iterCount int) {
|
||||||
|
mac := hmac.New(c.newHash, []byte(c.pass))
|
||||||
|
mac.Write(salt)
|
||||||
|
mac.Write([]byte{0, 0, 0, 1})
|
||||||
|
ui := mac.Sum(nil)
|
||||||
|
hi := make([]byte, len(ui))
|
||||||
|
copy(hi, ui)
|
||||||
|
for i := 1; i < iterCount; i++ {
|
||||||
|
mac.Reset()
|
||||||
|
mac.Write(ui)
|
||||||
|
mac.Sum(ui[:0])
|
||||||
|
for j, b := range ui {
|
||||||
|
hi[j] ^= b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.saltedPass = hi
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) clientProof() []byte {
|
||||||
|
mac := hmac.New(c.newHash, c.saltedPass)
|
||||||
|
mac.Write([]byte("Client Key"))
|
||||||
|
clientKey := mac.Sum(nil)
|
||||||
|
hash := c.newHash()
|
||||||
|
hash.Write(clientKey)
|
||||||
|
storedKey := hash.Sum(nil)
|
||||||
|
mac = hmac.New(c.newHash, storedKey)
|
||||||
|
mac.Write(c.authMsg.Bytes())
|
||||||
|
clientProof := mac.Sum(nil)
|
||||||
|
for i, b := range clientKey {
|
||||||
|
clientProof[i] ^= b
|
||||||
|
}
|
||||||
|
clientProof64 := make([]byte, b64.EncodedLen(len(clientProof)))
|
||||||
|
b64.Encode(clientProof64, clientProof)
|
||||||
|
return clientProof64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) serverSignature() []byte {
|
||||||
|
mac := hmac.New(c.newHash, c.saltedPass)
|
||||||
|
mac.Write([]byte("Server Key"))
|
||||||
|
serverKey := mac.Sum(nil)
|
||||||
|
|
||||||
|
mac = hmac.New(c.newHash, serverKey)
|
||||||
|
mac.Write(c.authMsg.Bytes())
|
||||||
|
serverSignature := mac.Sum(nil)
|
||||||
|
|
||||||
|
encoded := make([]byte, b64.EncodedLen(len(serverSignature)))
|
||||||
|
b64.Encode(encoded, serverSignature)
|
||||||
|
return encoded
|
||||||
|
}
|
63
vendor/github.com/lib/pq/ssl.go
generated
vendored
63
vendor/github.com/lib/pq/ssl.go
generated
vendored
@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
// ssl generates a function to upgrade a net.Conn based on the "sslmode" and
|
// ssl generates a function to upgrade a net.Conn based on the "sslmode" and
|
||||||
// related settings. The function is nil when no upgrade should take place.
|
// related settings. The function is nil when no upgrade should take place.
|
||||||
func ssl(o values) func(net.Conn) net.Conn {
|
func ssl(o values) (func(net.Conn) (net.Conn, error), error) {
|
||||||
verifyCaOnly := false
|
verifyCaOnly := false
|
||||||
tlsConf := tls.Config{}
|
tlsConf := tls.Config{}
|
||||||
switch mode := o["sslmode"]; mode {
|
switch mode := o["sslmode"]; mode {
|
||||||
@ -45,29 +45,44 @@ func ssl(o values) func(net.Conn) net.Conn {
|
|||||||
case "verify-full":
|
case "verify-full":
|
||||||
tlsConf.ServerName = o["host"]
|
tlsConf.ServerName = o["host"]
|
||||||
case "disable":
|
case "disable":
|
||||||
return nil
|
return nil, nil
|
||||||
default:
|
default:
|
||||||
errorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
|
return nil, fmterrorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
sslClientCertificates(&tlsConf, o)
|
err := sslClientCertificates(&tlsConf, o)
|
||||||
sslCertificateAuthority(&tlsConf, o)
|
if err != nil {
|
||||||
sslRenegotiation(&tlsConf)
|
return nil, err
|
||||||
|
}
|
||||||
|
err = sslCertificateAuthority(&tlsConf, o)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return func(conn net.Conn) net.Conn {
|
// Accept renegotiation requests initiated by the backend.
|
||||||
|
//
|
||||||
|
// Renegotiation was deprecated then removed from PostgreSQL 9.5, but
|
||||||
|
// the default configuration of older versions has it enabled. Redshift
|
||||||
|
// also initiates renegotiations and cannot be reconfigured.
|
||||||
|
tlsConf.Renegotiation = tls.RenegotiateFreelyAsClient
|
||||||
|
|
||||||
|
return func(conn net.Conn) (net.Conn, error) {
|
||||||
client := tls.Client(conn, &tlsConf)
|
client := tls.Client(conn, &tlsConf)
|
||||||
if verifyCaOnly {
|
if verifyCaOnly {
|
||||||
sslVerifyCertificateAuthority(client, &tlsConf)
|
err := sslVerifyCertificateAuthority(client, &tlsConf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return client
|
|
||||||
}
|
}
|
||||||
|
return client, nil
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// sslClientCertificates adds the certificate specified in the "sslcert" and
|
// sslClientCertificates adds the certificate specified in the "sslcert" and
|
||||||
// "sslkey" settings, or if they aren't set, from the .postgresql directory
|
// "sslkey" settings, or if they aren't set, from the .postgresql directory
|
||||||
// in the user's home directory. The configured files must exist and have
|
// in the user's home directory. The configured files must exist and have
|
||||||
// the correct permissions.
|
// the correct permissions.
|
||||||
func sslClientCertificates(tlsConf *tls.Config, o values) {
|
func sslClientCertificates(tlsConf *tls.Config, o values) error {
|
||||||
// user.Current() might fail when cross-compiling. We have to ignore the
|
// user.Current() might fail when cross-compiling. We have to ignore the
|
||||||
// error and continue without home directory defaults, since we wouldn't
|
// error and continue without home directory defaults, since we wouldn't
|
||||||
// know from where to load them.
|
// know from where to load them.
|
||||||
@ -82,13 +97,13 @@ func sslClientCertificates(tlsConf *tls.Config, o values) {
|
|||||||
}
|
}
|
||||||
// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045
|
// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045
|
||||||
if len(sslcert) == 0 {
|
if len(sslcert) == 0 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054
|
// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054
|
||||||
if _, err := os.Stat(sslcert); os.IsNotExist(err) {
|
if _, err := os.Stat(sslcert); os.IsNotExist(err) {
|
||||||
return
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// In libpq, the ssl key is only loaded if the setting is not blank.
|
// In libpq, the ssl key is only loaded if the setting is not blank.
|
||||||
@ -101,19 +116,21 @@ func sslClientCertificates(tlsConf *tls.Config, o values) {
|
|||||||
|
|
||||||
if len(sslkey) > 0 {
|
if len(sslkey) > 0 {
|
||||||
if err := sslKeyPermissions(sslkey); err != nil {
|
if err := sslKeyPermissions(sslkey); err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
|
cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConf.Certificates = []tls.Certificate{cert}
|
tlsConf.Certificates = []tls.Certificate{cert}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting.
|
// sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting.
|
||||||
func sslCertificateAuthority(tlsConf *tls.Config, o values) {
|
func sslCertificateAuthority(tlsConf *tls.Config, o values) error {
|
||||||
// In libpq, the root certificate is only loaded if the setting is not blank.
|
// In libpq, the root certificate is only loaded if the setting is not blank.
|
||||||
//
|
//
|
||||||
// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951
|
// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951
|
||||||
@ -122,22 +139,24 @@ func sslCertificateAuthority(tlsConf *tls.Config, o values) {
|
|||||||
|
|
||||||
cert, err := ioutil.ReadFile(sslrootcert)
|
cert, err := ioutil.ReadFile(sslrootcert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !tlsConf.RootCAs.AppendCertsFromPEM(cert) {
|
if !tlsConf.RootCAs.AppendCertsFromPEM(cert) {
|
||||||
errorf("couldn't parse pem in sslrootcert")
|
return fmterrorf("couldn't parse pem in sslrootcert")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// sslVerifyCertificateAuthority carries out a TLS handshake to the server and
|
// sslVerifyCertificateAuthority carries out a TLS handshake to the server and
|
||||||
// verifies the presented certificate against the CA, i.e. the one specified in
|
// verifies the presented certificate against the CA, i.e. the one specified in
|
||||||
// sslrootcert or the system CA if sslrootcert was not specified.
|
// sslrootcert or the system CA if sslrootcert was not specified.
|
||||||
func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) {
|
func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) error {
|
||||||
err := client.Handshake()
|
err := client.Handshake()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
certs := client.ConnectionState().PeerCertificates
|
certs := client.ConnectionState().PeerCertificates
|
||||||
opts := x509.VerifyOptions{
|
opts := x509.VerifyOptions{
|
||||||
@ -152,7 +171,5 @@ func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) {
|
|||||||
opts.Intermediates.AddCert(cert)
|
opts.Intermediates.AddCert(cert)
|
||||||
}
|
}
|
||||||
_, err = certs[0].Verify(opts)
|
_, err = certs[0].Verify(opts)
|
||||||
if err != nil {
|
return err
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
14
vendor/github.com/lib/pq/ssl_go1.7.go
generated
vendored
14
vendor/github.com/lib/pq/ssl_go1.7.go
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
// +build go1.7
|
|
||||||
|
|
||||||
package pq
|
|
||||||
|
|
||||||
import "crypto/tls"
|
|
||||||
|
|
||||||
// Accept renegotiation requests initiated by the backend.
|
|
||||||
//
|
|
||||||
// Renegotiation was deprecated then removed from PostgreSQL 9.5, but
|
|
||||||
// the default configuration of older versions has it enabled. Redshift
|
|
||||||
// also initiates renegotiations and cannot be reconfigured.
|
|
||||||
func sslRenegotiation(conf *tls.Config) {
|
|
||||||
conf.Renegotiation = tls.RenegotiateFreelyAsClient
|
|
||||||
}
|
|
8
vendor/github.com/lib/pq/ssl_renegotiation.go
generated
vendored
8
vendor/github.com/lib/pq/ssl_renegotiation.go
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
// +build !go1.7
|
|
||||||
|
|
||||||
package pq
|
|
||||||
|
|
||||||
import "crypto/tls"
|
|
||||||
|
|
||||||
// Renegotiation is not supported by crypto/tls until Go 1.7.
|
|
||||||
func sslRenegotiation(*tls.Config) {}
|
|
12
vendor/vendor.json
vendored
12
vendor/vendor.json
vendored
@ -87,10 +87,10 @@
|
|||||||
"revisionTime": "2017-02-15T23:32:05Z"
|
"revisionTime": "2017-02-15T23:32:05Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "3HVfwgLpCDH8JX211UWdrSi/GU4=",
|
"checksumSHA1": "GKTFbGomCP1fhH7mFecvwKvh7bc=",
|
||||||
"path": "github.com/lib/pq",
|
"path": "github.com/lib/pq",
|
||||||
"revision": "b609790bd85edf8e9ab7e0f8912750a786177bcf",
|
"revision": "78223426e7c66d631117c0a9da1b7f3fde4d23a5",
|
||||||
"revisionTime": "2017-10-22T19:20:43Z"
|
"revisionTime": "2019-08-13T06:55:22Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "AU3fA8Sm33Vj9PBoRPSeYfxLRuE=",
|
"checksumSHA1": "AU3fA8Sm33Vj9PBoRPSeYfxLRuE=",
|
||||||
@ -98,6 +98,12 @@
|
|||||||
"revision": "b609790bd85edf8e9ab7e0f8912750a786177bcf",
|
"revision": "b609790bd85edf8e9ab7e0f8912750a786177bcf",
|
||||||
"revisionTime": "2017-10-22T19:20:43Z"
|
"revisionTime": "2017-10-22T19:20:43Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"checksumSHA1": "n0MMCrKKsQuuhv7vLsrtRUGJVA8=",
|
||||||
|
"path": "github.com/lib/pq/scram",
|
||||||
|
"revision": "78223426e7c66d631117c0a9da1b7f3fde4d23a5",
|
||||||
|
"revisionTime": "2019-08-13T06:55:22Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "k3e1TD8wrhxfUUG3pQBb10ppNGA=",
|
"checksumSHA1": "k3e1TD8wrhxfUUG3pQBb10ppNGA=",
|
||||||
"path": "github.com/magefile/mage",
|
"path": "github.com/magefile/mage",
|
||||||
|
Loading…
Reference in New Issue
Block a user