vendor
This commit is contained in:
71
vendor/github.com/lib/pq/internal/pgpass/pgpass.go
generated
vendored
Normal file
71
vendor/github.com/lib/pq/internal/pgpass/pgpass.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
package pgpass
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/lib/pq/internal/pqutil"
|
||||
)
|
||||
|
||||
func PasswordFromPgpass(passfile, user, password, host, port, dbname string, passwordSet bool) string {
|
||||
// Do not process .pgpass if a password was supplied.
|
||||
if passwordSet {
|
||||
return password
|
||||
}
|
||||
|
||||
filename := pqutil.Pgpass(passfile)
|
||||
if filename == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
fp, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
scan := bufio.NewScanner(fp)
|
||||
for scan.Scan() {
|
||||
line := scan.Text()
|
||||
if len(line) == 0 || line[0] == '#' {
|
||||
continue
|
||||
}
|
||||
split := splitFields(line)
|
||||
if len(split) != 5 {
|
||||
continue
|
||||
}
|
||||
|
||||
socket := host == "" || filepath.IsAbs(host) || strings.HasPrefix(host, "@")
|
||||
if (split[0] == "*" || split[0] == host || (split[0] == "localhost" && socket)) &&
|
||||
(split[1] == "*" || split[1] == port) &&
|
||||
(split[2] == "*" || split[2] == dbname) &&
|
||||
(split[3] == "*" || split[3] == user) {
|
||||
return split[4]
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func splitFields(s string) []string {
|
||||
var (
|
||||
fs = make([]string, 0, 5)
|
||||
f = make([]rune, 0, len(s))
|
||||
esc bool
|
||||
)
|
||||
for _, c := range s {
|
||||
switch {
|
||||
case esc:
|
||||
f, esc = append(f, c), false
|
||||
case c == '\\':
|
||||
esc = true
|
||||
case c == ':':
|
||||
fs, f = append(fs, string(f)), f[:0]
|
||||
default:
|
||||
f = append(f, c)
|
||||
}
|
||||
}
|
||||
return append(fs, string(f))
|
||||
}
|
||||
37
vendor/github.com/lib/pq/internal/pqsql/copy.go
generated
vendored
Normal file
37
vendor/github.com/lib/pq/internal/pqsql/copy.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package pqsql
|
||||
|
||||
// StartsWithCopy reports if the SQL strings start with "copy", ignoring
|
||||
// whitespace, comments, and casing.
|
||||
func StartsWithCopy(query string) bool {
|
||||
if len(query) < 4 {
|
||||
return false
|
||||
}
|
||||
var linecmt, blockcmt bool
|
||||
for i := 0; i < len(query); i++ {
|
||||
c := query[i]
|
||||
if linecmt {
|
||||
linecmt = c != '\n'
|
||||
continue
|
||||
}
|
||||
if blockcmt {
|
||||
blockcmt = !(c == '/' && query[i-1] == '*')
|
||||
continue
|
||||
}
|
||||
if c == '-' && len(query) > i+1 && query[i+1] == '-' {
|
||||
linecmt = true
|
||||
continue
|
||||
}
|
||||
if c == '/' && len(query) > i+1 && query[i+1] == '*' {
|
||||
blockcmt = true
|
||||
continue
|
||||
}
|
||||
if c == ' ' || c == '\t' || c == '\r' || c == '\n' {
|
||||
continue
|
||||
}
|
||||
|
||||
// First non-comment and non-whitespace.
|
||||
return len(query) > i+3 && c|0x20 == 'c' && query[i+1]|0x20 == 'o' &&
|
||||
query[i+2]|0x20 == 'p' && query[i+3]|0x20 == 'y'
|
||||
}
|
||||
return false
|
||||
}
|
||||
65
vendor/github.com/lib/pq/internal/pqutil/path.go
generated
vendored
Normal file
65
vendor/github.com/lib/pq/internal/pqutil/path.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
package pqutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Home gets the user's home directory. Matches pqGetHomeDirectory() from
|
||||
// PostgreSQL
|
||||
//
|
||||
// https://github.com/postgres/postgres/blob/2b117bb/src/interfaces/libpq/fe-connect.c#L8214
|
||||
func Home() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
// pq uses SHGetFolderPath(), which is deprecated but x/sys/windows has
|
||||
// KnownFolderPath(). We don't really want to pull that in though, so
|
||||
// use APPDATA env. This is also what PostgreSQL uses in some other
|
||||
// codepaths (get_home_path() for example).
|
||||
ad := os.Getenv("APPDATA")
|
||||
if ad == "" {
|
||||
return ""
|
||||
}
|
||||
return filepath.Join(ad, "postgresql")
|
||||
}
|
||||
|
||||
home, _ := os.UserHomeDir()
|
||||
if home == "" {
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
home = u.HomeDir
|
||||
}
|
||||
return home
|
||||
}
|
||||
|
||||
// Pgpass gets the filepath to the pgpass file to use, returning "" if a pgpass
|
||||
// file shouldn't be used.
|
||||
func Pgpass(passfile string) string {
|
||||
// Get passfile from the options.
|
||||
if passfile == "" {
|
||||
home := Home()
|
||||
if home == "" {
|
||||
return ""
|
||||
}
|
||||
passfile = filepath.Join(home, ".pgpass")
|
||||
}
|
||||
|
||||
// On Win32, the directory is protected, so we don't have to check the file.
|
||||
if runtime.GOOS != "windows" {
|
||||
fi, err := os.Stat(passfile)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if fi.Mode().Perm()&(0x77) != 0 {
|
||||
fmt.Fprintf(os.Stderr,
|
||||
"WARNING: password file %q has group or world access; permissions should be u=rw (0600) or less\n",
|
||||
passfile)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return passfile
|
||||
}
|
||||
64
vendor/github.com/lib/pq/internal/pqutil/perm.go
generated
vendored
Normal file
64
vendor/github.com/lib/pq/internal/pqutil/perm.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
//go:build !windows && !plan9
|
||||
|
||||
package pqutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrSSLKeyUnknownOwnership = errors.New("pq: could not get owner information for private key, may not be properly protected")
|
||||
ErrSSLKeyHasWorldPermissions = errors.New("pq: private key has world access; permissions should be u=rw,g=r (0640) if owned by root, or u=rw (0600), or less")
|
||||
)
|
||||
|
||||
// SSLKeyPermissions checks the permissions on user-supplied SSL key files,
|
||||
// which should have very little access. libpq does not check key file
|
||||
// permissions on Windows.
|
||||
//
|
||||
// If the file is owned by the same user the process is running as, the file
|
||||
// should only have 0600. If the file is owned by root, and the group matches
|
||||
// the group that the process is running in, the permissions cannot be more than
|
||||
// 0640. The file should never have world permissions.
|
||||
//
|
||||
// Returns an error when the permission check fails.
|
||||
func SSLKeyPermissions(sslkey string) error {
|
||||
fi, err := os.Stat(sslkey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return checkPermissions(fi)
|
||||
}
|
||||
|
||||
func checkPermissions(fi os.FileInfo) error {
|
||||
// The maximum permissions that a private key file owned by a regular user
|
||||
// is allowed to have. This translates to u=rw. Regardless of if we're
|
||||
// running as root or not, 0600 is acceptable, so we return if we match the
|
||||
// regular user permission mask.
|
||||
if fi.Mode().Perm()&os.FileMode(0777)^0600 == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We need to pull the Unix file information to get the file's owner.
|
||||
// If we can't access it, there's some sort of operating system level error
|
||||
// and we should fail rather than attempting to use faulty information.
|
||||
sys, ok := fi.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return ErrSSLKeyUnknownOwnership
|
||||
}
|
||||
|
||||
// if the file is owned by root, we allow 0640 (u=rw,g=r) to match what
|
||||
// Postgres does.
|
||||
if sys.Uid == 0 {
|
||||
// The maximum permissions that a private key file owned by root is
|
||||
// allowed to have. This translates to u=rw,g=r.
|
||||
if fi.Mode().Perm()&os.FileMode(0777)^0640 != 0 {
|
||||
return ErrSSLKeyHasWorldPermissions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrSSLKeyHasWorldPermissions
|
||||
}
|
||||
12
vendor/github.com/lib/pq/internal/pqutil/perm_unsupported.go
generated
vendored
Normal file
12
vendor/github.com/lib/pq/internal/pqutil/perm_unsupported.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build windows || plan9
|
||||
|
||||
package pqutil
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrSSLKeyUnknownOwnership = errors.New("unused")
|
||||
ErrSSLKeyHasWorldPermissions = errors.New("unused")
|
||||
)
|
||||
|
||||
func SSLKeyPermissions(sslkey string) error { return nil }
|
||||
32
vendor/github.com/lib/pq/internal/pqutil/pqutil.go
generated
vendored
Normal file
32
vendor/github.com/lib/pq/internal/pqutil/pqutil.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package pqutil
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseBool is like strconv.ParseBool, but also accepts "yes"/"no" and
|
||||
// "on"/"off".
|
||||
func ParseBool(str string) (bool, error) {
|
||||
switch str {
|
||||
case "1", "t", "T", "true", "TRUE", "True", "yes", "on":
|
||||
return true, nil
|
||||
case "0", "f", "F", "false", "FALSE", "False", "no", "off":
|
||||
return false, nil
|
||||
}
|
||||
return false, &strconv.NumError{Func: "ParseBool", Num: str, Err: strconv.ErrSyntax}
|
||||
}
|
||||
|
||||
func Join[S ~[]E, E ~string](s S) string {
|
||||
var b strings.Builder
|
||||
for i := range s {
|
||||
if i > 0 {
|
||||
b.WriteString(", ")
|
||||
}
|
||||
if i == len(s)-1 {
|
||||
b.WriteString("or ")
|
||||
}
|
||||
b.WriteString(string(s[i]))
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
9
vendor/github.com/lib/pq/internal/pqutil/user_other.go
generated
vendored
Normal file
9
vendor/github.com/lib/pq/internal/pqutil/user_other.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build js || android || hurd || zos || wasip1 || appengine
|
||||
|
||||
package pqutil
|
||||
|
||||
import "errors"
|
||||
|
||||
func User() (string, error) {
|
||||
return "", errors.New("pqutil.User: not supported on current platform")
|
||||
}
|
||||
25
vendor/github.com/lib/pq/internal/pqutil/user_posix.go
generated
vendored
Normal file
25
vendor/github.com/lib/pq/internal/pqutil/user_posix.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
//go:build !windows && !js && !android && !hurd && !zos && !wasip1 && !appengine
|
||||
|
||||
package pqutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/user"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func User() (string, error) {
|
||||
env := "USER"
|
||||
if runtime.GOOS == "plan9" {
|
||||
env = "user"
|
||||
}
|
||||
if n := os.Getenv(env); n != "" {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return u.Username, nil
|
||||
}
|
||||
28
vendor/github.com/lib/pq/internal/pqutil/user_windows.go
generated
vendored
Normal file
28
vendor/github.com/lib/pq/internal/pqutil/user_windows.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
//go:build windows && !appengine
|
||||
|
||||
package pqutil
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func User() (string, error) {
|
||||
// Perform Windows user name lookup identically to libpq.
|
||||
//
|
||||
// The PostgreSQL code makes use of the legacy Win32 function GetUserName,
|
||||
// and that function has not been imported into stock Go. GetUserNameEx is
|
||||
// available though, the difference being that a wider range of names are
|
||||
// available. To get the output to be the same as GetUserName, only the
|
||||
// base (or last) component of the result is returned.
|
||||
var (
|
||||
name = make([]uint16, 128)
|
||||
pwnameSz = uint32(len(name)) - 1
|
||||
)
|
||||
err := syscall.GetUserNameEx(syscall.NameSamCompatible, &name[0], &pwnameSz)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s := syscall.UTF16ToString(name)
|
||||
return filepath.Base(s), nil
|
||||
}
|
||||
186
vendor/github.com/lib/pq/internal/proto/proto.go
generated
vendored
Normal file
186
vendor/github.com/lib/pq/internal/proto/proto.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
// From src/include/libpq/protocol.h and src/include/libpq/pqcomm.h – PostgreSQL 18.1
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Constants from pqcomm.h
|
||||
const (
|
||||
ProtocolVersion30 = (3 << 16) | 0 //lint:ignore SA4016 x
|
||||
ProtocolVersion32 = (3 << 16) | 2 // PostgreSQL ≥18; not yet supported.
|
||||
CancelRequestCode = (1234 << 16) | 5678
|
||||
NegotiateSSLCode = (1234 << 16) | 5679
|
||||
NegotiateGSSCode = (1234 << 16) | 5680
|
||||
)
|
||||
|
||||
// Constants from fe-connect.c
|
||||
const (
|
||||
MaxErrlen = 30_000 // https://github.com/postgres/postgres/blob/c6a10a89f/src/interfaces/libpq/fe-connect.c#L4067
|
||||
)
|
||||
|
||||
// RequestCode is a request codes sent by the frontend.
|
||||
type RequestCode byte
|
||||
|
||||
// These are the request codes sent by the frontend.
|
||||
const (
|
||||
Bind = RequestCode('B')
|
||||
Close = RequestCode('C')
|
||||
Describe = RequestCode('D')
|
||||
Execute = RequestCode('E')
|
||||
FunctionCall = RequestCode('F')
|
||||
Flush = RequestCode('H')
|
||||
Parse = RequestCode('P')
|
||||
Query = RequestCode('Q')
|
||||
Sync = RequestCode('S')
|
||||
Terminate = RequestCode('X')
|
||||
CopyFail = RequestCode('f')
|
||||
GSSResponse = RequestCode('p')
|
||||
PasswordMessage = RequestCode('p')
|
||||
SASLInitialResponse = RequestCode('p')
|
||||
SASLResponse = RequestCode('p')
|
||||
CopyDoneRequest = RequestCode('c')
|
||||
CopyDataRequest = RequestCode('d')
|
||||
)
|
||||
|
||||
func (r RequestCode) String() string {
|
||||
s, ok := map[RequestCode]string{
|
||||
Bind: "Bind",
|
||||
Close: "Close",
|
||||
Describe: "Describe",
|
||||
Execute: "Execute",
|
||||
FunctionCall: "FunctionCall",
|
||||
Flush: "Flush",
|
||||
Parse: "Parse",
|
||||
Query: "Query",
|
||||
Sync: "Sync",
|
||||
Terminate: "Terminate",
|
||||
CopyFail: "CopyFail",
|
||||
// These are all the same :-/
|
||||
//GSSResponse: "GSSResponse",
|
||||
PasswordMessage: "PasswordMessage",
|
||||
//SASLInitialResponse: "SASLInitialResponse",
|
||||
//SASLResponse: "SASLResponse",
|
||||
CopyDoneRequest: "CopyDone",
|
||||
CopyDataRequest: "CopyData",
|
||||
}[r]
|
||||
if !ok {
|
||||
s = "<unknown>"
|
||||
}
|
||||
c := string(r)
|
||||
if r <= 0x1f || r == 0x7f {
|
||||
c = fmt.Sprintf("0x%x", string(r))
|
||||
}
|
||||
return "(" + c + ") " + s
|
||||
}
|
||||
|
||||
// ResponseCode is a response codes sent by the backend.
|
||||
type ResponseCode byte
|
||||
|
||||
// These are the response codes sent by the backend.
|
||||
const (
|
||||
ParseComplete = ResponseCode('1')
|
||||
BindComplete = ResponseCode('2')
|
||||
CloseComplete = ResponseCode('3')
|
||||
NotificationResponse = ResponseCode('A')
|
||||
CommandComplete = ResponseCode('C')
|
||||
DataRow = ResponseCode('D')
|
||||
ErrorResponse = ResponseCode('E')
|
||||
CopyInResponse = ResponseCode('G')
|
||||
CopyOutResponse = ResponseCode('H')
|
||||
EmptyQueryResponse = ResponseCode('I')
|
||||
BackendKeyData = ResponseCode('K')
|
||||
NoticeResponse = ResponseCode('N')
|
||||
AuthenticationRequest = ResponseCode('R')
|
||||
ParameterStatus = ResponseCode('S')
|
||||
RowDescription = ResponseCode('T')
|
||||
FunctionCallResponse = ResponseCode('V')
|
||||
CopyBothResponse = ResponseCode('W')
|
||||
ReadyForQuery = ResponseCode('Z')
|
||||
NoData = ResponseCode('n')
|
||||
PortalSuspended = ResponseCode('s')
|
||||
ParameterDescription = ResponseCode('t')
|
||||
NegotiateProtocolVersion = ResponseCode('v')
|
||||
CopyDoneResponse = ResponseCode('c')
|
||||
CopyDataResponse = ResponseCode('d')
|
||||
)
|
||||
|
||||
func (r ResponseCode) String() string {
|
||||
s, ok := map[ResponseCode]string{
|
||||
ParseComplete: "ParseComplete",
|
||||
BindComplete: "BindComplete",
|
||||
CloseComplete: "CloseComplete",
|
||||
NotificationResponse: "NotificationResponse",
|
||||
CommandComplete: "CommandComplete",
|
||||
DataRow: "DataRow",
|
||||
ErrorResponse: "ErrorResponse",
|
||||
CopyInResponse: "CopyInResponse",
|
||||
CopyOutResponse: "CopyOutResponse",
|
||||
EmptyQueryResponse: "EmptyQueryResponse",
|
||||
BackendKeyData: "BackendKeyData",
|
||||
NoticeResponse: "NoticeResponse",
|
||||
AuthenticationRequest: "AuthRequest",
|
||||
ParameterStatus: "ParamStatus",
|
||||
RowDescription: "RowDescription",
|
||||
FunctionCallResponse: "FunctionCallResponse",
|
||||
CopyBothResponse: "CopyBothResponse",
|
||||
ReadyForQuery: "ReadyForQuery",
|
||||
NoData: "NoData",
|
||||
PortalSuspended: "PortalSuspended",
|
||||
ParameterDescription: "ParamDescription",
|
||||
NegotiateProtocolVersion: "NegotiateProtocolVersion",
|
||||
CopyDoneResponse: "CopyDone",
|
||||
CopyDataResponse: "CopyData",
|
||||
}[r]
|
||||
if !ok {
|
||||
s = "<unknown>"
|
||||
}
|
||||
c := string(r)
|
||||
if r <= 0x1f || r == 0x7f {
|
||||
c = fmt.Sprintf("0x%x", string(r))
|
||||
}
|
||||
return "(" + c + ") " + s
|
||||
}
|
||||
|
||||
// AuthCode are authentication request codes sent by the backend.
|
||||
type AuthCode int32
|
||||
|
||||
// These are the authentication request codes sent by the backend.
|
||||
const (
|
||||
AuthReqOk = AuthCode(0) // User is authenticated
|
||||
AuthReqKrb4 = AuthCode(1) // Kerberos V4. Not supported any more.
|
||||
AuthReqKrb5 = AuthCode(2) // Kerberos V5. Not supported any more.
|
||||
AuthReqPassword = AuthCode(3) // Password
|
||||
AuthReqCrypt = AuthCode(4) // crypt password. Not supported any more.
|
||||
AuthReqMD5 = AuthCode(5) // md5 password
|
||||
_ = AuthCode(6) // 6 is available. It was used for SCM creds, not supported any more.
|
||||
AuthReqGSS = AuthCode(7) // GSSAPI without wrap()
|
||||
AuthReqGSSCont = AuthCode(8) // Continue GSS exchanges
|
||||
AuthReqSSPI = AuthCode(9) // SSPI negotiate without wrap()
|
||||
AuthReqSASL = AuthCode(10) // Begin SASL authentication
|
||||
AuthReqSASLCont = AuthCode(11) // Continue SASL authentication
|
||||
AuthReqSASLFin = AuthCode(12) // Final SASL message
|
||||
)
|
||||
|
||||
func (a AuthCode) String() string {
|
||||
s, ok := map[AuthCode]string{
|
||||
AuthReqOk: "ok",
|
||||
AuthReqKrb4: "krb4",
|
||||
AuthReqKrb5: "krb5",
|
||||
AuthReqPassword: "password",
|
||||
AuthReqCrypt: "crypt",
|
||||
AuthReqMD5: "md5",
|
||||
AuthReqGSS: "GDD",
|
||||
AuthReqGSSCont: "GSSCont",
|
||||
AuthReqSSPI: "SSPI",
|
||||
AuthReqSASL: "SASL",
|
||||
AuthReqSASLCont: "SASLCont",
|
||||
AuthReqSASLFin: "SASLFin",
|
||||
}[a]
|
||||
if !ok {
|
||||
s = "<unknown>"
|
||||
}
|
||||
return s + " (" + strconv.Itoa(int(a)) + ")"
|
||||
}
|
||||
7
vendor/github.com/lib/pq/internal/proto/sz_32.go
generated
vendored
Normal file
7
vendor/github.com/lib/pq/internal/proto/sz_32.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build 386 || arm || mips || mipsle
|
||||
|
||||
package proto
|
||||
|
||||
import "math"
|
||||
|
||||
const MaxUint32 = math.MaxInt
|
||||
7
vendor/github.com/lib/pq/internal/proto/sz_64.go
generated
vendored
Normal file
7
vendor/github.com/lib/pq/internal/proto/sz_64.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build !386 && !arm && !mips && !mipsle
|
||||
|
||||
package proto
|
||||
|
||||
import "math"
|
||||
|
||||
const MaxUint32 = math.MaxUint32
|
||||
Reference in New Issue
Block a user