aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/jackc/pgpassfile/pgpass.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/jackc/pgpassfile/pgpass.go')
-rw-r--r--vendor/github.com/jackc/pgpassfile/pgpass.go110
1 files changed, 110 insertions, 0 deletions
diff --git a/vendor/github.com/jackc/pgpassfile/pgpass.go b/vendor/github.com/jackc/pgpassfile/pgpass.go
new file mode 100644
index 0000000..f7eed3c
--- /dev/null
+++ b/vendor/github.com/jackc/pgpassfile/pgpass.go
@@ -0,0 +1,110 @@
+// Package pgpassfile is a parser PostgreSQL .pgpass files.
+package pgpassfile
+
+import (
+ "bufio"
+ "io"
+ "os"
+ "regexp"
+ "strings"
+)
+
+// Entry represents a line in a PG passfile.
+type Entry struct {
+ Hostname string
+ Port string
+ Database string
+ Username string
+ Password string
+}
+
+// Passfile is the in memory data structure representing a PG passfile.
+type Passfile struct {
+ Entries []*Entry
+}
+
+// ReadPassfile reads the file at path and parses it into a Passfile.
+func ReadPassfile(path string) (*Passfile, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return ParsePassfile(f)
+}
+
+// ParsePassfile reads r and parses it into a Passfile.
+func ParsePassfile(r io.Reader) (*Passfile, error) {
+ passfile := &Passfile{}
+
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ entry := parseLine(scanner.Text())
+ if entry != nil {
+ passfile.Entries = append(passfile.Entries, entry)
+ }
+ }
+
+ return passfile, scanner.Err()
+}
+
+// Match (not colons or escaped colon or escaped backslash)+. Essentially gives a split on unescaped
+// colon.
+var colonSplitterRegexp = regexp.MustCompile("(([^:]|(\\:)))+")
+
+// var colonSplitterRegexp = regexp.MustCompile("((?:[^:]|(?:\\:)|(?:\\\\))+)")
+
+// parseLine parses a line into an *Entry. It returns nil on comment lines or any other unparsable
+// line.
+func parseLine(line string) *Entry {
+ const (
+ tmpBackslash = "\r"
+ tmpColon = "\n"
+ )
+
+ line = strings.TrimSpace(line)
+
+ if strings.HasPrefix(line, "#") {
+ return nil
+ }
+
+ line = strings.Replace(line, `\\`, tmpBackslash, -1)
+ line = strings.Replace(line, `\:`, tmpColon, -1)
+
+ parts := strings.Split(line, ":")
+ if len(parts) != 5 {
+ return nil
+ }
+
+ // Unescape escaped colons and backslashes
+ for i := range parts {
+ parts[i] = strings.Replace(parts[i], tmpBackslash, `\`, -1)
+ parts[i] = strings.Replace(parts[i], tmpColon, `:`, -1)
+ }
+
+ return &Entry{
+ Hostname: parts[0],
+ Port: parts[1],
+ Database: parts[2],
+ Username: parts[3],
+ Password: parts[4],
+ }
+}
+
+// FindPassword finds the password for the provided hostname, port, database, and username. For a
+// Unix domain socket hostname must be set to "localhost". An empty string will be returned if no
+// match is found.
+//
+// See https://www.postgresql.org/docs/current/libpq-pgpass.html for more password file information.
+func (pf *Passfile) FindPassword(hostname, port, database, username string) (password string) {
+ for _, e := range pf.Entries {
+ if (e.Hostname == "*" || e.Hostname == hostname) &&
+ (e.Port == "*" || e.Port == port) &&
+ (e.Database == "*" || e.Database == database) &&
+ (e.Username == "*" || e.Username == username) {
+ return e.Password
+ }
+ }
+ return ""
+}