1package command 2 3import ( 4 "errors" 5 "os" 6 "os/user" 7 "strings" 8 9 "github.com/jessevdk/go-flags" 10) 11 12type Options struct { 13 Version bool `short:"v" long:"version" description:"Print version"` 14 Debug bool `short:"d" long:"debug" description:"Enable debugging mode"` 15 URL string `long:"url" description:"Database connection string"` 16 Host string `long:"host" description:"Server hostname or IP" default:"localhost"` 17 Port int `long:"port" description:"Server port" default:"5432"` 18 User string `long:"user" description:"Database user"` 19 Pass string `long:"pass" description:"Password for user"` 20 DbName string `long:"db" description:"Database name"` 21 Ssl string `long:"ssl" description:"SSL mode"` 22 SslRootCert string `long:"ssl-rootcert" description:"SSL certificate authority file"` 23 SslCert string `long:"ssl-cert" description:"SSL client certificate file"` 24 SslKey string `long:"ssl-key" description:"SSL client certificate key file"` 25 HTTPHost string `long:"bind" description:"HTTP server host" default:"localhost"` 26 HTTPPort uint `long:"listen" description:"HTTP server listen port" default:"8081"` 27 AuthUser string `long:"auth-user" description:"HTTP basic auth user"` 28 AuthPass string `long:"auth-pass" description:"HTTP basic auth password"` 29 SkipOpen bool `short:"s" long:"skip-open" description:"Skip browser open on start"` 30 Sessions bool `long:"sessions" description:"Enable multiple database sessions"` 31 Prefix string `long:"prefix" description:"Add a url prefix"` 32 ReadOnly bool `long:"readonly" description:"Run database connection in readonly mode"` 33 LockSession bool `long:"lock-session" description:"Lock session to a single database connection"` 34 Bookmark string `short:"b" long:"bookmark" description:"Bookmark to use for connection. Bookmark files are stored under $HOME/.pgweb/bookmarks/*.toml" default:""` 35 BookmarksDir string `long:"bookmarks-dir" description:"Overrides default directory for bookmark files to search" default:""` 36 DisablePrettyJSON bool `long:"no-pretty-json" description:"Disable JSON formatting feature for result export"` 37 DisableSSH bool `long:"no-ssh" description:"Disable database connections via SSH"` 38 ConnectBackend string `long:"connect-backend" description:"Enable database authentication through a third party backend"` 39 ConnectToken string `long:"connect-token" description:"Authentication token for the third-party connect backend"` 40 ConnectHeaders string `long:"connect-headers" description:"List of headers to pass to the connect backend"` 41 DisableConnectionIdleTimeout bool `long:"no-idle-timeout" description:"Disable connection idle timeout"` 42 ConnectionIdleTimeout int `long:"idle-timeout" description:"Set connection idle timeout in minutes" default:"180"` 43 Cors bool `long:"cors" description:"Enable Cross-Origin Resource Sharing (CORS)"` 44 CorsOrigin string `long:"cors-origin" description:"Allowed CORS origins" default:"*"` 45} 46 47var Opts Options 48 49// ParseOptions returns a new options struct from the input arguments 50func ParseOptions(args []string) (Options, error) { 51 var opts = Options{} 52 53 _, err := flags.ParseArgs(&opts, args) 54 if err != nil { 55 return opts, err 56 } 57 58 if opts.URL == "" { 59 opts.URL = os.Getenv("DATABASE_URL") 60 } 61 62 if opts.Prefix == "" { 63 opts.Prefix = os.Getenv("URL_PREFIX") 64 } 65 66 // Handle edge case where pgweb is started with a default host `localhost` and no user. 67 // When user is not set the `lib/pq` connection will fail and cause pgweb's termination. 68 if (opts.Host == "localhost" || opts.Host == "127.0.0.1") && opts.User == "" { 69 if username := GetCurrentUser(); username != "" { 70 opts.User = username 71 } else { 72 opts.Host = "" 73 } 74 } 75 76 if os.Getenv("SESSIONS") != "" { 77 opts.Sessions = true 78 } 79 80 if os.Getenv("LOCK_SESSION") != "" { 81 opts.LockSession = true 82 opts.Sessions = false 83 } 84 85 if opts.Sessions || opts.ConnectBackend != "" { 86 opts.Bookmark = "" 87 opts.URL = "" 88 opts.Host = "" 89 opts.User = "" 90 opts.Pass = "" 91 opts.DbName = "" 92 opts.Ssl = "" 93 } 94 95 if opts.Prefix != "" && !strings.Contains(opts.Prefix, "/") { 96 opts.Prefix = opts.Prefix + "/" 97 } 98 99 if opts.AuthUser == "" && os.Getenv("AUTH_USER") != "" { 100 opts.AuthUser = os.Getenv("AUTH_USER") 101 } 102 103 if opts.AuthPass == "" && os.Getenv("AUTH_PASS") != "" { 104 opts.AuthPass = os.Getenv("AUTH_PASS") 105 } 106 107 if opts.ConnectBackend != "" { 108 if !opts.Sessions { 109 return opts, errors.New("--sessions flag must be set") 110 } 111 if opts.ConnectToken == "" { 112 return opts, errors.New("--connect-token flag must be set") 113 } 114 } else { 115 if opts.ConnectToken != "" || opts.ConnectHeaders != "" { 116 return opts, errors.New("--connect-backend flag must be set") 117 } 118 } 119 120 return opts, nil 121} 122 123// SetDefaultOptions parses and assigns the options 124func SetDefaultOptions() error { 125 opts, err := ParseOptions([]string{}) 126 if err != nil { 127 return err 128 } 129 Opts = opts 130 return nil 131} 132 133// GetCurrentUser returns a current user name 134func GetCurrentUser() string { 135 u, _ := user.Current() 136 if u != nil { 137 return u.Username 138 } 139 return os.Getenv("USER") 140} 141