From 7d9c3d8f6273b7873f44a66acde1b8d0f562432c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rychli=C5=84ski=20Arkadiusz?= Date: Tue, 22 Nov 2022 15:43:54 +0100 Subject: [PATCH] feat: Dodane parsowanie pliku pgpass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pgpass jest prsowany i przy uruchomieniu psql podawane jest wybrane hasło pasujące do połaczenia --- .gitignore | 1 + mgr/mgr.go | 12 +++++++- pass/pass.go | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++ psql/psql.go | 51 ++++++++++++++------------------- 4 files changed, 114 insertions(+), 31 deletions(-) create mode 100644 pass/pass.go diff --git a/.gitignore b/.gitignore index 004263b..513b10f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/.vscode /output /pgpass diff --git a/mgr/mgr.go b/mgr/mgr.go index 029d493..c086512 100644 --- a/mgr/mgr.go +++ b/mgr/mgr.go @@ -9,6 +9,7 @@ import ( "time" "baal.ar76.eu/x/pub/multisql/cfg" + "baal.ar76.eu/x/pub/multisql/pass" "baal.ar76.eu/x/pub/multisql/psql" ) @@ -69,6 +70,15 @@ func (self Manager) Run() error { return err } + var passdb *pass.PassDb + + if self.config.PassFile != "" { + passdb, err = pass.Load(self.config.PassFile, "TODO") + if err != nil { + return err + } + } + var group sync.WaitGroup for _, con := range self.config.Connections { @@ -84,7 +94,7 @@ func (self Manager) Run() error { go self.Logger(&group, stream, con) sql := psql.Create( - self.config.PassFile, + passdb, dbDir, scripts, con, diff --git a/pass/pass.go b/pass/pass.go new file mode 100644 index 0000000..fa2325c --- /dev/null +++ b/pass/pass.go @@ -0,0 +1,81 @@ +package pass + +import ( + "bytes" + "fmt" + "os" +) + +type pgpassrow struct { + hostname string + port string + database string + username string + password string +} + +type PassDb struct { + db []pgpassrow + cache map[string]*pgpassrow +} + +func Load(file string, master string) (*PassDb, error) { + + data, err := os.ReadFile(file) + if err != nil { + return nil, err + } + + lines := bytes.Split(data, []byte{'\n'}) + + var rows []pgpassrow + + for i, line := range lines { + line = bytes.TrimRight(line, "\n\r \t") + if len(line) == 0 || line[0] == byte('#') { + continue + } + fields := bytes.Split(line, []byte{':'}) + if len(fields) != 5 { + return nil, fmt.Errorf("błąd w pliku hasłeł %s:%d: niewłaściwa liczba pól", file, i) + } + rows = append(rows, pgpassrow{ + hostname: string(fields[0]), + port: string(fields[1]), + database: string(fields[2]), + username: string(fields[3]), + password: string(fields[4]), + }) + } + + return &PassDb{ + db: rows, + cache: make(map[string]*pgpassrow), + }, nil +} + +func match(value string, pattern string) bool { + return pattern == "*" || pattern == value +} + +func (self *PassDb) FindPassword(host string, port uint, database string, user string) string { + myport := fmt.Sprintf("%d", port) + key := fmt.Sprintf("%s:%s:%s:%s", host, myport, database, user) + cached, ok := self.cache[key] + if ok { + return cached.password + } + + // pierwszy pasujący do wzorca + for i := range self.db { + if match(host, self.db[i].hostname) && + match(myport, self.db[i].port) && + match(database, self.db[i].database) && + match(user, self.db[i].username) { + + self.cache[key] = &self.db[i] + return self.db[i].password + } + } + return "" +} diff --git a/psql/psql.go b/psql/psql.go index 809e128..e91e6c8 100644 --- a/psql/psql.go +++ b/psql/psql.go @@ -10,15 +10,16 @@ import ( "runtime" "baal.ar76.eu/x/pub/multisql/cfg" + "baal.ar76.eu/x/pub/multisql/pass" ) type Instance struct { - outdir string - scripts []string - passfile string - psqlExe string - conn cfg.Connection - verbose bool + outdir string + scripts []string + pasdb *pass.PassDb + psqlExe string + conn cfg.Connection + verbose bool } type Result struct { @@ -26,32 +27,22 @@ type Result struct { Err error } -func Create(passfile string, outdir string, scripts []string, conn cfg.Connection, psqlExe string, verbose bool) (instnace Instance) { +func Create(passdb *pass.PassDb, outdir string, scripts []string, conn cfg.Connection, psqlExe string, verbose bool) (instnace Instance) { instnace = Instance{ - outdir: outdir, - scripts: scripts, - passfile: passfile, - conn: conn, - psqlExe: psqlExe, - verbose: verbose, + outdir: outdir, + scripts: scripts, + pasdb: passdb, + conn: conn, + psqlExe: psqlExe, + verbose: verbose, } return instnace } func (self Instance) Exec(result chan<- Result) { - absPassFile := "" - if self.passfile != "" { - var err error - absPassFile, err = filepath.Abs(self.passfile) - if err != nil { - result <- Result{ - Script: "*", - Err: fmt.Errorf("problem ze zbudowaniem ściężki do pliku haseł: %w", err), - } - return - } - } + + connString := fmt.Sprintf("host=%s port=%d dbname=%s user=%s", self.conn.Host, self.conn.Port, self.conn.DbName, self.conn.User) for _, scr := range self.scripts { @@ -65,7 +56,8 @@ func (self Instance) Exec(result chan<- Result) { } continue } - err = self.cmdPsql(outdir, connString, scr, absPassFile) + password := self.pasdb.FindPassword(self.conn.Host, self.conn.Port, self.conn.DbName, self.conn.User) + err = self.cmdPsql(outdir, connString, scr, password) result <- Result{ Script: scr, Err: err, @@ -74,7 +66,7 @@ func (self Instance) Exec(result chan<- Result) { close(result) } -func (self Instance) cmdPsql(outdir string, connString string, script string, passfile string) error { +func (self Instance) cmdPsql(outdir string, connString string, script string, password string) error { absScript, err := filepath.Abs(script) if err != nil { return fmt.Errorf("problem ze zbudowaniem ściezki do skryptu: %w", err) @@ -112,13 +104,12 @@ func (self Instance) cmdPsql(outdir string, connString string, script string, pa cmd.Stdout = fhOut cmd.Dir = outdir - if passfile != "" { + if password != "" { env := os.Environ() - env = append(env, "PGPASSFILE=" + passfile) + env = append(env, "PGPASSWORD="+password) cmd.Env = env } - if self.verbose { log.Printf("Uruchamiam %s", cmd.String()) }