Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ac14310642 | ||
|
b82a136fef | ||
|
18c29e4621 | ||
|
473b76d1c9 | ||
|
4dc83c3915 | ||
|
8af918bdce | ||
|
c8c1ba52b9 | ||
|
9ab0bcdb35 | ||
|
7d9c3d8f62 | ||
|
c34954ef14 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
/.vscode
|
||||
/output
|
||||
/pgpass
|
||||
/pgpass*
|
||||
|
||||
#exec
|
||||
/multisql
|
||||
|
7
LICENSE.txt
Normal file
7
LICENSE.txt
Normal file
@ -0,0 +1,7 @@
|
||||
Copyright 2022 ark76
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
50
README.md
50
README.md
@ -108,3 +108,53 @@ Powyższy select (dzieki \gset) zapamięta pozyskaną wartość (w tym wypadku p
|
||||
Sekcja if / endif wykona się tylko wtedy, jeśli warunek był true i operacja `\o`, która tworzy nowy plik i resztę wyników kieruje do niego, też wykonuje się warunkowo.
|
||||
|
||||
W efekcie, jeśli warunek jest spełniony, w katalogu wynikowym działania skryptu pojawi się dodatkowy plik (ekstra.txt) co pozwoli łatwo wychwycić, dla których baz ów warunek występuje.
|
||||
|
||||
## Obsługa plików szyfrowanych
|
||||
|
||||
Od wersji 0.2.1 plik z hasłami (pgpass) musi być zaszyforwany. Szyfrowanie można wykonać następującym poleceniem:
|
||||
|
||||
```sh
|
||||
multisql encrypt pgpass.sec pgpass
|
||||
```
|
||||
|
||||
Program zapyta o nowe hasło a następnie zaszyfruje treść pliku pgpass i zapisze go do pliku pgpass.sec.
|
||||
|
||||
W konfiguracji należy ustawić plik wartość `"Passfile"` na `pgpass.sec`.
|
||||
|
||||
Zaszyfrowany plik można odszyfrować i zapisać do pliku jawnego lub podejrzeć:
|
||||
|
||||
```bash
|
||||
multisql -P decrypt pgpass.sec # po udanym odszyfrowaniu wyświetli treść pliku
|
||||
# lub
|
||||
multisql -P decryp pgpass.sec newpgpass # w tym wariancie odszyfrowana treść zostanie zapisana do newpgpass
|
||||
```
|
||||
|
||||
Opcja `-P` powoduje, że program pyta o hasło. Jeśli nie podano tej opcji, program
|
||||
próbuje użyć hasła ustawionego w zmiennej środowiskowej `MULTISQLPASS`.
|
||||
|
||||
Zmienną można ustawić w następujący sposób:
|
||||
|
||||
Linux:
|
||||
|
||||
```bash
|
||||
export MULTISQLPASS=abc
|
||||
```
|
||||
|
||||
Windows cmd:
|
||||
|
||||
```cmd
|
||||
set MULTISQLPASS=abc
|
||||
```
|
||||
|
||||
Windows, powershell:
|
||||
|
||||
```powershell
|
||||
$env:MULTISQLPASS = "abc"
|
||||
```
|
||||
|
||||
Użycie opcji `-P` powoduje, że zmienna środowiskowa jest ignorowana i hasło pobierane jest z klawiatury.
|
||||
|
||||
> Uwaga: Od wersji 0.2.3 wykorzystywany jest format szyfrowania
|
||||
> [age-encryption](https://age-encryption.org/).
|
||||
> Plik haseł można więc szyfrować i deszyftować również narzędziem
|
||||
> `age` (https://github.com/FiloSottile/age/releases/tag/v1.0.0)
|
||||
|
@ -1,10 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
"baal.ar76.eu/x/pub/multisql/cfg"
|
||||
"baal.ar76.eu/x/pub/multisql/mgr"
|
||||
"baal.ar76.eu/x/pub/multisql/internal/cfg"
|
||||
"baal.ar76.eu/x/pub/multisql/internal/mgr"
|
||||
"baal.ar76.eu/x/pub/multisql/internal/pass"
|
||||
|
||||
"log"
|
||||
)
|
||||
@ -12,6 +17,15 @@ import (
|
||||
func main() {
|
||||
log.SetFlags(log.LstdFlags)
|
||||
params := cfg.GetParams()
|
||||
if params.Version {
|
||||
printVersion()
|
||||
return
|
||||
}
|
||||
args := flag.Args()
|
||||
if len (args) > 0 {
|
||||
encryption(args, params)
|
||||
return
|
||||
}
|
||||
|
||||
if params.LogFile != "" {
|
||||
fh, err := os.OpenFile(params.LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o664)
|
||||
@ -44,7 +58,7 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
manager, err := mgr.Create(params.Verbose, params.OutDir, config)
|
||||
manager, err := mgr.Create(params.Verbose, params.AskPass, params.OutDir, config)
|
||||
if err != nil {
|
||||
log.Fatalf("Nie można wystartować operacji: %v\n", err)
|
||||
}
|
||||
@ -56,3 +70,60 @@ func main() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func encryption(args []string, params cfg.Parameters) {
|
||||
switch strings.ToLower(args[0]) {
|
||||
case "encrypt":
|
||||
if len(args) < 3 {
|
||||
log.Fatal("encrypt wymaga dwu plików: cel-plik.zaszyfrowany źródło-plik.jawny")
|
||||
return
|
||||
}
|
||||
plain, err := os.ReadFile(args[2])
|
||||
if err != nil {
|
||||
log.Fatalf("Błąd odczytu pliku: %v", err)
|
||||
}
|
||||
|
||||
password := pass.EnterMasterPass()
|
||||
|
||||
err = pass.EncryptFile(password, args[1], plain)
|
||||
if err != nil {
|
||||
_ = os.Remove(args[1]) // jeśli błąd to usuń plik
|
||||
log.Fatalf("Błąd szyfrowania pliku: %v", err)
|
||||
}
|
||||
case "decrypt":
|
||||
if len(args) < 2 {
|
||||
log.Fatal("decryp wymaga podania pliku zaszyfrowanego")
|
||||
return
|
||||
}
|
||||
password := pass.GetMasterPass(params.AskPass)
|
||||
|
||||
data, err := pass.DecryptFile(password, args[1])
|
||||
if err !=nil {
|
||||
log.Fatalf("Błąd deszyfrowania pliku: %v", err)
|
||||
}
|
||||
if len(args) > 2 {
|
||||
err = os.WriteFile(args[2], data, 0o600)
|
||||
if err != nil {
|
||||
log.Fatalf("Błąd zapisu pliku: %v", err)
|
||||
}
|
||||
log.Printf("Zapisano odszyfrowane dane do pliku %s", args[2])
|
||||
} else {
|
||||
os.Stdout.Write(data)
|
||||
}
|
||||
|
||||
default:
|
||||
log.Println("W trybie komend wymagane jest podanie polecenie encrypt lub decrypt i nazw plików: zaszyfrowanego i jawnego");
|
||||
log.Println("Np:")
|
||||
log.Println("multisql encrypt hasła.zaszyfrowany hasła")
|
||||
log.Println("multisql decrypt hasła.zaszyfrowany hasła")
|
||||
}
|
||||
}
|
||||
|
||||
func printVersion() {
|
||||
bi, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
log.Fatalf("Błąd odczytu informacji o wersji")
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Wersja głównego modułu: %v\n", bi.Main.Version)
|
||||
fmt.Fprintln(os.Stderr, bi)
|
||||
}
|
||||
|
10
go.mod
10
go.mod
@ -1,3 +1,13 @@
|
||||
module baal.ar76.eu/x/pub/multisql
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
filippo.io/age v1.0.0
|
||||
golang.org/x/term v0.2.0
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.3.0 // indirect
|
||||
golang.org/x/sys v0.2.0 // indirect
|
||||
)
|
||||
|
8
go.sum
Normal file
8
go.sum
Normal file
@ -0,0 +1,8 @@
|
||||
filippo.io/age v1.0.0 h1:V6q14n0mqYU3qKFkZ6oOaF9oXneOviS3ubXsSVBRSzc=
|
||||
filippo.io/age v1.0.0/go.mod h1:PaX+Si/Sd5G8LgfCwldsSba3H1DDQZhIhFGkhbHaBq8=
|
||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
@ -8,13 +8,17 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
const MULTISQLPASS = "MULTISQLPASS" // nazwa ziennej środowiskowej z hasłem
|
||||
|
||||
type Parameters struct {
|
||||
Verbose bool
|
||||
ConfigFile string
|
||||
Passfile string
|
||||
OutDir string
|
||||
SqlDir string
|
||||
LogFile string
|
||||
LogFile string
|
||||
Verbose bool
|
||||
AskPass bool
|
||||
Version bool
|
||||
}
|
||||
|
||||
var params Parameters
|
||||
@ -26,6 +30,9 @@ func init() {
|
||||
flag.StringVar(¶ms.OutDir, "outdir", "", "Katalog (istniejący i z prawem do zapisu), do którego generowane są wyniki")
|
||||
flag.StringVar(¶ms.SqlDir, "sqldir", "scripts", "Katalog, w którym znajdują się skrypty do uruchomienia")
|
||||
flag.StringVar(¶ms.LogFile, "log", "", "Plik, do którego zostanie dopisany log programu")
|
||||
flag.BoolVar(¶ms.AskPass, "P", false, "Pytaj o hasło. Jeśli nie podane wymaga się hasła w ")
|
||||
flag.BoolVar(¶ms.Version, "version", false, "Wypisuje wersję i kończy działanie")
|
||||
|
||||
flag.Usage = printUsage
|
||||
flag.Parse()
|
||||
}
|
||||
@ -58,6 +65,11 @@ output:
|
||||
Użycie:
|
||||
multisql -outdir /tmp -sqldir /data/skrypty -passfile ./hasla
|
||||
|
||||
Użycie w trybie szyfrowania:
|
||||
multisql encrypt plik.wynikowy.zaszyfrowany plik.zródłowy
|
||||
lub
|
||||
multisql [-P] decrypt plik.źródłowy.zaszyfrowany [plik.wynikowy.jawny]
|
||||
|
||||
Opis flag:
|
||||
`,
|
||||
)
|
||||
@ -96,7 +108,7 @@ Plik multisql.conf ma format JSON, np:
|
||||
_ = json.Indent(&out, b, "> ", "\t")
|
||||
_, _ = out.WriteTo(os.Stderr)
|
||||
|
||||
fmt.Fprintln(os.Stderr, `
|
||||
fmt.Fprintf(os.Stderr, `
|
||||
|
||||
PsqlExec jest opcjonalny - jesli nie zostanie podany wyszukuje się programu psql.exe w PATH.
|
||||
|
||||
@ -110,5 +122,16 @@ Format pliku passfile jest następujący:
|
||||
|
||||
hostname:port:database:username:password
|
||||
|
||||
W szczególach opisano go na https://www.postgresql.org/docs/current/libpq-pgpass.html.`)
|
||||
W szczegółach opisano go na https://www.postgresql.org/docs/current/libpq-pgpass.html.
|
||||
|
||||
Aktualnie obsługiwana jest jedynie zaszyforowana postać pliku. Przed użyciem należy
|
||||
plik zaszyfrować:
|
||||
|
||||
multsql encrypt pgpass.encrypted pgpass
|
||||
|
||||
Przy użyciu (odszyfrowaniu) pliku, hasło jest pobierane ze zmiennej
|
||||
środowiskowej %s lub z klawiatury, jeśli użyto opcji -P.
|
||||
|
||||
`, MULTISQLPASS)
|
||||
|
||||
}
|
@ -8,23 +8,26 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"baal.ar76.eu/x/pub/multisql/cfg"
|
||||
"baal.ar76.eu/x/pub/multisql/psql"
|
||||
"baal.ar76.eu/x/pub/multisql/internal/cfg"
|
||||
"baal.ar76.eu/x/pub/multisql/internal/pass"
|
||||
"baal.ar76.eu/x/pub/multisql/internal/psql"
|
||||
)
|
||||
|
||||
type Manager struct {
|
||||
config cfg.Config
|
||||
runDir string
|
||||
config cfg.Config
|
||||
runDir string
|
||||
verbose bool
|
||||
askPass bool
|
||||
}
|
||||
|
||||
func Create(verbose bool, outdir string, config cfg.Config) (Manager, error) {
|
||||
func Create(verbose bool, askPass bool, outdir string, config cfg.Config) (Manager, error) {
|
||||
runDir := createRunDir(outdir)
|
||||
|
||||
manager := Manager{
|
||||
config: config,
|
||||
runDir: runDir,
|
||||
config: config,
|
||||
runDir: runDir,
|
||||
verbose: verbose,
|
||||
askPass: askPass,
|
||||
}
|
||||
|
||||
return manager, nil
|
||||
@ -69,6 +72,16 @@ func (self Manager) Run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
var passdb *pass.PassDb
|
||||
|
||||
if self.config.PassFile != "" {
|
||||
password := pass.GetMasterPass(self.askPass)
|
||||
passdb, err = pass.Load(self.config.PassFile, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var group sync.WaitGroup
|
||||
|
||||
for _, con := range self.config.Connections {
|
||||
@ -84,7 +97,7 @@ func (self Manager) Run() error {
|
||||
go self.Logger(&group, stream, con)
|
||||
|
||||
sql := psql.Create(
|
||||
self.config.PassFile,
|
||||
passdb,
|
||||
dbDir,
|
||||
scripts,
|
||||
con,
|
||||
@ -105,7 +118,6 @@ func (self Manager) createDirPerCon(con cfg.Connection) (string, error) {
|
||||
return dir, err
|
||||
}
|
||||
|
||||
|
||||
func (self Manager) Logger(group *sync.WaitGroup, stream <-chan psql.Result, con cfg.Connection) {
|
||||
for event := range stream {
|
||||
if event.Err != nil {
|
65
internal/pass/crypt.go
Normal file
65
internal/pass/crypt.go
Normal file
@ -0,0 +1,65 @@
|
||||
package pass
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"filippo.io/age"
|
||||
"filippo.io/age/armor"
|
||||
)
|
||||
|
||||
func DecryptFile(password []byte, file string) ([]byte, error) {
|
||||
identity, err := age.NewScryptIdentity(string(password))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("błąd przetwarzania hasła: %w", err)
|
||||
}
|
||||
fd, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("błąd otwarcia pliku: %w", err)
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
in := armor.NewReader(fd)
|
||||
|
||||
r, err := age.Decrypt(in, identity)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("błąd deszyfrowania #01: %w", err)
|
||||
}
|
||||
|
||||
out := &bytes.Buffer{}
|
||||
if _, err := io.Copy(out, r); err != nil {
|
||||
return nil, fmt.Errorf("błąd deszyfrowania #02: %v", err)
|
||||
}
|
||||
return out.Bytes(), nil
|
||||
}
|
||||
|
||||
func EncryptFile(password []byte, file string, data []byte) error {
|
||||
recipient, err := age.NewScryptRecipient(string(password))
|
||||
if err != nil {
|
||||
return fmt.Errorf("błąd przetwarzania hasła: %w", err)
|
||||
}
|
||||
fd, err := os.OpenFile(file, os.O_WRONLY | os.O_CREATE | os.O_EXCL, 0o600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("błąd tworzenia pliku: %w", err)
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
out := armor.NewWriter(fd) // armor
|
||||
defer out.Close()
|
||||
|
||||
w, err := age.Encrypt(out, recipient)
|
||||
if err != nil {
|
||||
return fmt.Errorf("błąd szyfrowania #01: %w", err)
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("błąd szyfrowania #02: %w", err)
|
||||
}
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("błąd szyfrowania #03: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
80
internal/pass/pass.go
Normal file
80
internal/pass/pass.go
Normal file
@ -0,0 +1,80 @@
|
||||
package pass
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
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 []byte) (*PassDb, error) {
|
||||
|
||||
data, err := DecryptFile(master, 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 ""
|
||||
}
|
55
internal/pass/term.go
Normal file
55
internal/pass/term.go
Normal file
@ -0,0 +1,55 @@
|
||||
package pass
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"baal.ar76.eu/x/pub/multisql/internal/cfg"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
func GetMasterPass(askPass bool) []byte {
|
||||
if askPass {
|
||||
res, err := termGetPassword("Podaj hasło")
|
||||
if err != nil {
|
||||
log.Fatalln("Nie udało się wczytać hasła z konsoli")
|
||||
}
|
||||
return res
|
||||
}
|
||||
password := os.Getenv(cfg.MULTISQLPASS)
|
||||
|
||||
if password != "" {
|
||||
return []byte(password)
|
||||
}
|
||||
|
||||
log.Fatalf("Nieustalone hasło. Użyj flagi -P lub ustaw hasło w zmiennej %s", cfg.MULTISQLPASS)
|
||||
return nil
|
||||
}
|
||||
|
||||
func EnterMasterPass() []byte {
|
||||
p1, err := termGetPassword("Podaj nowe hasło (min 8 znaków)")
|
||||
if err != nil {
|
||||
log.Fatalf("Błąd wczytywania hasła: %v", err)
|
||||
}
|
||||
if len(p1) < 8 {
|
||||
log.Fatalf("podano zbyt krótkie hasło")
|
||||
}
|
||||
p2, err := termGetPassword("Powtórz nowe hasło")
|
||||
if err != nil {
|
||||
log.Fatalf("Błąd wczytywania hasła: %v", err)
|
||||
}
|
||||
if !bytes.Equal(p1, p2) {
|
||||
log.Fatalf("podane hasła są różne")
|
||||
}
|
||||
|
||||
return p1
|
||||
}
|
||||
|
||||
func termGetPassword(prompt string) ([]byte, error) {
|
||||
fmt.Fprintf(os.Stderr, "%s: ", prompt)
|
||||
passwd, err := term.ReadPassword(int(os.Stdin.Fd()))
|
||||
fmt.Fprintln(os.Stderr)
|
||||
return passwd, err
|
||||
}
|
@ -9,16 +9,17 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"baal.ar76.eu/x/pub/multisql/cfg"
|
||||
"baal.ar76.eu/x/pub/multisql/internal/cfg"
|
||||
"baal.ar76.eu/x/pub/multisql/internal/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())
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user