Add support for .pgpass file (#617)
* Add support for .pgpass file * Support password lookup in /api/connect endpoint * Restrore removed code for BuildStringFromOptions * Restructure connection string test and add extra case for pgpass * Add test for FormatURL method
This commit is contained in:
@@ -5,8 +5,10 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/jackc/pgpassfile"
|
||||
"github.com/jessevdk/go-flags"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -26,6 +28,7 @@ type Options struct {
|
||||
Port int `long:"port" description:"Server port" default:"5432"`
|
||||
User string `long:"user" description:"Database user"`
|
||||
Pass string `long:"pass" description:"Password for user"`
|
||||
Passfile string `long:"passfile" description:"Local passwords file location"`
|
||||
DbName string `long:"db" description:"Database name"`
|
||||
SSLMode string `long:"ssl" description:"SSL mode"`
|
||||
SSLRootCert string `long:"ssl-rootcert" description:"SSL certificate authority file"`
|
||||
@@ -79,6 +82,23 @@ func ParseOptions(args []string) (Options, error) {
|
||||
opts.Prefix = getPrefixedEnvVar("URL_PREFIX")
|
||||
}
|
||||
|
||||
if opts.Passfile == "" {
|
||||
passfile := os.Getenv("PGPASSFILE")
|
||||
if passfile == "" {
|
||||
passfile = filepath.Join(os.Getenv("HOME"), ".pgpass")
|
||||
}
|
||||
|
||||
_, err := os.Stat(passfile)
|
||||
if err == nil {
|
||||
_, err = pgpassfile.ReadPassfile(passfile)
|
||||
if err == nil {
|
||||
opts.Passfile = passfile
|
||||
} else {
|
||||
fmt.Printf("[WARN] Pgpass file unreadable: %s\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle edge case where pgweb is started with a default host `localhost` and no user.
|
||||
// When user is not set the `lib/pq` connection will fail and cause pgweb's termination.
|
||||
if (opts.Host == "localhost" || opts.Host == "127.0.0.1") && opts.User == "" {
|
||||
|
||||
@@ -1,47 +1,75 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseOptions(t *testing.T) {
|
||||
// Test default behavior
|
||||
opts, err := ParseOptions([]string{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, opts.Sessions)
|
||||
assert.Equal(t, "", opts.Prefix)
|
||||
assert.Equal(t, "", opts.ConnectToken)
|
||||
assert.Equal(t, "", opts.ConnectHeaders)
|
||||
assert.Equal(t, false, opts.DisableSSH)
|
||||
assert.Equal(t, false, opts.DisablePrettyJSON)
|
||||
assert.Equal(t, false, opts.DisableConnectionIdleTimeout)
|
||||
assert.Equal(t, 180, opts.ConnectionIdleTimeout)
|
||||
assert.Equal(t, false, opts.Cors)
|
||||
assert.Equal(t, "*", opts.CorsOrigin)
|
||||
t.Run("defaults", func(t *testing.T) {
|
||||
opts, err := ParseOptions([]string{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, opts.Sessions)
|
||||
assert.Equal(t, "", opts.Prefix)
|
||||
assert.Equal(t, "", opts.ConnectToken)
|
||||
assert.Equal(t, "", opts.ConnectHeaders)
|
||||
assert.Equal(t, false, opts.DisableSSH)
|
||||
assert.Equal(t, false, opts.DisablePrettyJSON)
|
||||
assert.Equal(t, false, opts.DisableConnectionIdleTimeout)
|
||||
assert.Equal(t, 180, opts.ConnectionIdleTimeout)
|
||||
assert.Equal(t, false, opts.Cors)
|
||||
assert.Equal(t, "*", opts.CorsOrigin)
|
||||
assert.Equal(t, "", opts.Passfile)
|
||||
})
|
||||
|
||||
// Test sessions
|
||||
opts, err = ParseOptions([]string{"--sessions", "1"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, opts.Sessions)
|
||||
t.Run("sessions", func(t *testing.T) {
|
||||
opts, err := ParseOptions([]string{"--sessions", "1"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, opts.Sessions)
|
||||
})
|
||||
|
||||
// Test url prefix
|
||||
opts, err = ParseOptions([]string{"--prefix", "pgweb"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "pgweb/", opts.Prefix)
|
||||
t.Run("url prefix", func(t *testing.T) {
|
||||
opts, err := ParseOptions([]string{"--prefix", "pgweb"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "pgweb/", opts.Prefix)
|
||||
|
||||
opts, err = ParseOptions([]string{"--prefix", "pgweb/"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "pgweb/", opts.Prefix)
|
||||
opts, err = ParseOptions([]string{"--prefix", "pgweb/"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "pgweb/", opts.Prefix)
|
||||
})
|
||||
|
||||
// Test connect backend options
|
||||
opts, err = ParseOptions([]string{"--connect-backend", "test"})
|
||||
assert.EqualError(t, err, "--sessions flag must be set")
|
||||
t.Run("connect backend", func(t *testing.T) {
|
||||
_, err := ParseOptions([]string{"--connect-backend", "test"})
|
||||
assert.EqualError(t, err, "--sessions flag must be set")
|
||||
|
||||
opts, err = ParseOptions([]string{"--connect-backend", "test", "--sessions"})
|
||||
assert.EqualError(t, err, "--connect-token flag must be set")
|
||||
_, err = ParseOptions([]string{"--connect-backend", "test", "--sessions"})
|
||||
assert.EqualError(t, err, "--connect-token flag must be set")
|
||||
|
||||
opts, err = ParseOptions([]string{"--connect-backend", "test", "--sessions", "--connect-token", "token"})
|
||||
assert.NoError(t, err)
|
||||
_, err = ParseOptions([]string{"--connect-backend", "test", "--sessions", "--connect-token", "token"})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("passfile", func(t *testing.T) {
|
||||
defer os.Unsetenv("PGPASSFILE")
|
||||
|
||||
// File does not exist
|
||||
os.Setenv("PGPASSFILE", "/tmp/foo")
|
||||
opts, err := ParseOptions([]string{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "", opts.Passfile)
|
||||
|
||||
// File exists and valid
|
||||
os.Setenv("PGPASSFILE", "../../data/passfile")
|
||||
opts, err = ParseOptions([]string{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "../../data/passfile", opts.Passfile)
|
||||
|
||||
// Set via flag
|
||||
os.Unsetenv("PGPASSFILE")
|
||||
opts, err = ParseOptions([]string{"--passfile", "../../data/passfile"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "../../data/passfile", opts.Passfile)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user