feat: Dodane parsowanie pliku pgpass
pgpass jest prsowany i przy uruchomieniu psql podawane jest wybrane hasło pasujące do połaczenia
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					/.vscode
 | 
				
			||||||
/output
 | 
					/output
 | 
				
			||||||
/pgpass
 | 
					/pgpass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								mgr/mgr.go
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								mgr/mgr.go
									
									
									
									
									
								
							@@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"baal.ar76.eu/x/pub/multisql/cfg"
 | 
						"baal.ar76.eu/x/pub/multisql/cfg"
 | 
				
			||||||
 | 
						"baal.ar76.eu/x/pub/multisql/pass"
 | 
				
			||||||
	"baal.ar76.eu/x/pub/multisql/psql"
 | 
						"baal.ar76.eu/x/pub/multisql/psql"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,6 +70,15 @@ func (self Manager) Run() error {
 | 
				
			|||||||
		return err
 | 
							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
 | 
						var group sync.WaitGroup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, con := range self.config.Connections {
 | 
						for _, con := range self.config.Connections {
 | 
				
			||||||
@@ -84,7 +94,7 @@ func (self Manager) Run() error {
 | 
				
			|||||||
		go self.Logger(&group, stream, con)
 | 
							go self.Logger(&group, stream, con)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sql := psql.Create(
 | 
							sql := psql.Create(
 | 
				
			||||||
			self.config.PassFile,
 | 
								passdb,
 | 
				
			||||||
			dbDir,
 | 
								dbDir,
 | 
				
			||||||
			scripts,
 | 
								scripts,
 | 
				
			||||||
			con,
 | 
								con,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										81
									
								
								pass/pass.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								pass/pass.go
									
									
									
									
									
										Normal file
									
								
							@@ -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 ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										31
									
								
								psql/psql.go
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								psql/psql.go
									
									
									
									
									
								
							@@ -10,12 +10,13 @@ import (
 | 
				
			|||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"baal.ar76.eu/x/pub/multisql/cfg"
 | 
						"baal.ar76.eu/x/pub/multisql/cfg"
 | 
				
			||||||
 | 
						"baal.ar76.eu/x/pub/multisql/pass"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Instance struct {
 | 
					type Instance struct {
 | 
				
			||||||
	outdir  string
 | 
						outdir  string
 | 
				
			||||||
	scripts []string
 | 
						scripts []string
 | 
				
			||||||
	passfile string
 | 
						pasdb   *pass.PassDb
 | 
				
			||||||
	psqlExe string
 | 
						psqlExe string
 | 
				
			||||||
	conn    cfg.Connection
 | 
						conn    cfg.Connection
 | 
				
			||||||
	verbose bool
 | 
						verbose bool
 | 
				
			||||||
@@ -26,12 +27,12 @@ type Result struct {
 | 
				
			|||||||
	Err    error
 | 
						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{
 | 
						instnace = Instance{
 | 
				
			||||||
		outdir:  outdir,
 | 
							outdir:  outdir,
 | 
				
			||||||
		scripts: scripts,
 | 
							scripts: scripts,
 | 
				
			||||||
		passfile: passfile,
 | 
							pasdb:   passdb,
 | 
				
			||||||
		conn:    conn,
 | 
							conn:    conn,
 | 
				
			||||||
		psqlExe: psqlExe,
 | 
							psqlExe: psqlExe,
 | 
				
			||||||
		verbose: verbose,
 | 
							verbose: verbose,
 | 
				
			||||||
@@ -40,18 +41,8 @@ func Create(passfile string, outdir string, scripts []string, conn cfg.Connectio
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self Instance) Exec(result chan<- Result) {
 | 
					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)
 | 
						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 {
 | 
						for _, scr := range self.scripts {
 | 
				
			||||||
@@ -65,7 +56,8 @@ func (self Instance) Exec(result chan<- Result) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			continue
 | 
								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{
 | 
							result <- Result{
 | 
				
			||||||
			Script: scr,
 | 
								Script: scr,
 | 
				
			||||||
			Err:    err,
 | 
								Err:    err,
 | 
				
			||||||
@@ -74,7 +66,7 @@ func (self Instance) Exec(result chan<- Result) {
 | 
				
			|||||||
	close(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)
 | 
						absScript, err := filepath.Abs(script)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("problem ze zbudowaniem ściezki do skryptu: %w", err)
 | 
							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.Stdout = fhOut
 | 
				
			||||||
	cmd.Dir = outdir
 | 
						cmd.Dir = outdir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if passfile != "" {
 | 
						if password != "" {
 | 
				
			||||||
		env := os.Environ()
 | 
							env := os.Environ()
 | 
				
			||||||
		env = append(env, "PGPASSFILE=" + passfile)
 | 
							env = append(env, "PGPASSWORD="+password)
 | 
				
			||||||
		cmd.Env = env
 | 
							cmd.Env = env
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if self.verbose {
 | 
						if self.verbose {
 | 
				
			||||||
		log.Printf("Uruchamiam %s", cmd.String())
 | 
							log.Printf("Uruchamiam %s", cmd.String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user