// Package pgpassfile is a parser PostgreSQL .pgpass files.
package pgpassfile import ( ) // 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 ( string) (*Passfile, error) { , := os.Open() if != nil { return nil, } defer .Close() return ParsePassfile() } // ParsePassfile reads r and parses it into a Passfile. func ( io.Reader) (*Passfile, error) { := &Passfile{} := bufio.NewScanner() for .Scan() { := parseLine(.Text()) if != nil { .Entries = append(.Entries, ) } } return , .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( string) *Entry { const ( = "\r" = "\n" ) = strings.TrimSpace() if strings.HasPrefix(, "#") { return nil } = strings.Replace(, `\\`, , -1) = strings.Replace(, `\:`, , -1) := strings.Split(, ":") if len() != 5 { return nil } // Unescape escaped colons and backslashes for := range { [] = strings.Replace([], , `\`, -1) [] = strings.Replace([], , `:`, -1) } return &Entry{ Hostname: [0], Port: [1], Database: [2], Username: [3], Password: [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 ( *Passfile) (, , , string) ( string) { for , := range .Entries { if (.Hostname == "*" || .Hostname == ) && (.Port == "*" || .Port == ) && (.Database == "*" || .Database == ) && (.Username == "*" || .Username == ) { return .Password } } return "" }