...
1
2 package pgpassfile
3
4 import (
5 "bufio"
6 "io"
7 "os"
8 "regexp"
9 "strings"
10 )
11
12
13 type Entry struct {
14 Hostname string
15 Port string
16 Database string
17 Username string
18 Password string
19 }
20
21
22 type Passfile struct {
23 Entries []*Entry
24 }
25
26
27 func ReadPassfile(path string) (*Passfile, error) {
28 f, err := os.Open(path)
29 if err != nil {
30 return nil, err
31 }
32 defer f.Close()
33
34 return ParsePassfile(f)
35 }
36
37
38 func ParsePassfile(r io.Reader) (*Passfile, error) {
39 passfile := &Passfile{}
40
41 scanner := bufio.NewScanner(r)
42 for scanner.Scan() {
43 entry := parseLine(scanner.Text())
44 if entry != nil {
45 passfile.Entries = append(passfile.Entries, entry)
46 }
47 }
48
49 return passfile, scanner.Err()
50 }
51
52
53
54 var colonSplitterRegexp = regexp.MustCompile("(([^:]|(\\:)))+")
55
56
57
58
59
60 func parseLine(line string) *Entry {
61 const (
62 tmpBackslash = "\r"
63 tmpColon = "\n"
64 )
65
66 line = strings.TrimSpace(line)
67
68 if strings.HasPrefix(line, "#") {
69 return nil
70 }
71
72 line = strings.Replace(line, `\\`, tmpBackslash, -1)
73 line = strings.Replace(line, `\:`, tmpColon, -1)
74
75 parts := strings.Split(line, ":")
76 if len(parts) != 5 {
77 return nil
78 }
79
80
81 for i := range parts {
82 parts[i] = strings.Replace(parts[i], tmpBackslash, `\`, -1)
83 parts[i] = strings.Replace(parts[i], tmpColon, `:`, -1)
84 }
85
86 return &Entry{
87 Hostname: parts[0],
88 Port: parts[1],
89 Database: parts[2],
90 Username: parts[3],
91 Password: parts[4],
92 }
93 }
94
95
96
97
98
99
100 func (pf *Passfile) FindPassword(hostname, port, database, username string) (password string) {
101 for _, e := range pf.Entries {
102 if (e.Hostname == "*" || e.Hostname == hostname) &&
103 (e.Port == "*" || e.Port == port) &&
104 (e.Database == "*" || e.Database == database) &&
105 (e.Username == "*" || e.Username == username) {
106 return e.Password
107 }
108 }
109 return ""
110 }
111
View as plain text