Merge pull request #491 from mialinx/master

More precise .pgpass handling
pull/500/head
Jack Christensen 2018-12-15 17:11:13 -06:00 committed by GitHub
commit 4618730e71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 11 deletions

View File

@ -9,7 +9,7 @@ import (
"strings" "strings"
) )
func parsepgpass(cfg *ConnConfig, line string) *string { func parsepgpass(line, cfgHost, cfgPort, cfgDatabase, cfgUsername string) *string {
const ( const (
backslash = "\r" backslash = "\r"
colon = "\n" colon = "\n"
@ -21,6 +21,9 @@ func parsepgpass(cfg *ConnConfig, line string) *string {
username username
pw pw
) )
if strings.HasPrefix(line, "#") {
return nil
}
line = strings.Replace(line, `\:`, colon, -1) line = strings.Replace(line, `\:`, colon, -1)
line = strings.Replace(line, `\\`, backslash, -1) line = strings.Replace(line, `\\`, backslash, -1)
parts := strings.Split(line, `:`) parts := strings.Split(line, `:`)
@ -34,23 +37,19 @@ func parsepgpass(cfg *ConnConfig, line string) *string {
parts[i] = strings.Replace(strings.Replace(parts[i], backslash, `\`, -1), colon, `:`, -1) parts[i] = strings.Replace(strings.Replace(parts[i], backslash, `\`, -1), colon, `:`, -1)
switch i { switch i {
case host: case host:
if parts[i] != cfg.Host { if parts[i] != cfgHost {
return nil return nil
} }
case port: case port:
portstr := fmt.Sprintf(`%v`, cfg.Port) if parts[i] != cfgPort {
if portstr == "0" {
portstr = "5432"
}
if parts[i] != portstr {
return nil return nil
} }
case database: case database:
if parts[i] != cfg.Database { if parts[i] != cfgDatabase {
return nil return nil
} }
case username: case username:
if parts[i] != cfg.User { if parts[i] != cfgUsername {
return nil return nil
} }
} }
@ -72,10 +71,32 @@ func pgpass(cfg *ConnConfig) (found bool) {
return return
} }
defer f.Close() defer f.Close()
host := cfg.Host
if _, err := os.Stat(host); err == nil {
host = "localhost"
}
port := fmt.Sprintf(`%v`, cfg.Port)
if port == "0" {
port = "5432"
}
username := cfg.User
if username == "" {
user, err := user.Current()
if err != nil {
return
}
username = user.Username
}
database := cfg.Database
if database == "" {
database = username
}
scanner := bufio.NewScanner(f) scanner := bufio.NewScanner(f)
var pw *string var pw *string
for scanner.Scan() { for scanner.Scan() {
pw = parsepgpass(cfg, scanner.Text()) pw = parsepgpass(scanner.Text(), host, port, database, username)
if pw != nil { if pw != nil {
cfg.Password = *pw cfg.Password = *pw
return true return true

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"os/user"
"strings" "strings"
"testing" "testing"
) )
@ -20,6 +21,8 @@ var passfile = [][]string{
{"test1", "5432", "curlydb", "curly", "nyuknyuknyuk"}, {"test1", "5432", "curlydb", "curly", "nyuknyuknyuk"},
{"test2", "5432", "*", "shemp", "heymoe"}, {"test2", "5432", "*", "shemp", "heymoe"},
{"test2", "5432", "*", "*", `test\\ing\:`}, {"test2", "5432", "*", "*", `test\\ing\:`},
{"localhost", "*", "*", "*", "sesam"},
{"test3", "*", "", "", "swordfish"}, // user will be filled later
} }
func TestPGPass(t *testing.T) { func TestPGPass(t *testing.T) {
@ -27,9 +30,20 @@ func TestPGPass(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
user, err := user.Current()
if err != nil {
t.Fatal(err)
}
passfile[len(passfile)-1][2] = user.Username
passfile[len(passfile)-1][3] = user.Username
defer tf.Close() defer tf.Close()
defer os.Remove(tf.Name()) defer os.Remove(tf.Name())
os.Setenv("PGPASSFILE", tf.Name()) os.Setenv("PGPASSFILE", tf.Name())
_, err = fmt.Fprintln(tf, "#some comment\n\n#more comment")
if err != nil {
t.Fatal(err)
}
for _, l := range passfile { for _, l := range passfile {
_, err := fmt.Fprintln(tf, strings.Join(l, `:`)) _, err := fmt.Fprintln(tf, strings.Join(l, `:`))
if err != nil { if err != nil {
@ -48,9 +62,28 @@ func TestPGPass(t *testing.T) {
if cfg.Password != unescape(l[4]) { if cfg.Password != unescape(l[4]) {
t.Fatalf(`Password mismatch entry %v want %s got %s`, i, unescape(l[4]), cfg.Password) t.Fatalf(`Password mismatch entry %v want %s got %s`, i, unescape(l[4]), cfg.Password)
} }
if l[0] == "localhost" {
// using some existing path as socket
cfg := ConnConfig{Host: tf.Name(), Database: l[2], User: l[3]}
found := pgpass(&cfg)
if !found {
t.Fatalf("Entry %v not found", i)
}
if cfg.Password != unescape(l[4]) {
t.Fatalf(`Password mismatch entry %v want %s got %s`, i, unescape(l[4]), cfg.Password)
}
}
} }
cfg := ConnConfig{Host: "derp", Database: "herp", User: "joe"} cfg := ConnConfig{Host: "test3"}
found := pgpass(&cfg) found := pgpass(&cfg)
if !found {
t.Fatalf("Entry for default user name")
}
if cfg.Password != "swordfish" {
t.Fatalf(`Password mismatch for default user entry, want %s got %s`, "swordfish", cfg.Password)
}
cfg = ConnConfig{Host: "derp", Database: "herp", User: "joe"}
found = pgpass(&cfg)
if found { if found {
t.Fatal("bad found") t.Fatal("bad found")
} }