2015-04-30 11:47:07 -05:00
package command
import (
2017-09-15 18:54:14 -05:00
"errors"
2022-11-22 15:20:49 -06:00
"fmt"
2015-04-30 11:47:07 -05:00
"os"
2019-01-28 14:03:45 -06:00
"os/user"
2016-02-19 21:14:56 -06:00
"strings"
2015-04-30 11:47:07 -05:00
"github.com/jessevdk/go-flags"
2022-12-06 12:09:21 -06:00
"github.com/sirupsen/logrus"
2015-04-30 11:47:07 -05:00
)
2022-11-22 14:50:58 -06:00
const (
// Prefix to use for all pgweb env vars, ie PGWEB_HOST, PGWEB_PORT, etc
envVarPrefix = "PGWEB_"
)
2015-04-30 11:47:07 -05:00
type Options struct {
2018-02-22 14:20:18 -06:00
Version bool ` short:"v" long:"version" description:"Print version" `
2018-08-31 21:49:24 -05:00
Debug bool ` short:"d" long:"debug" description:"Enable debugging mode" `
2022-12-06 12:09:21 -06:00
LogLevel string ` long:"log-level" description:"Logging level" default:"info" `
LogFormat string ` long:"log-format" description:"Logging output format" default:"text" `
2019-11-02 13:00:23 -05:00
URL string ` long:"url" description:"Database connection string" `
2018-09-14 00:04:02 -05:00
Host string ` long:"host" description:"Server hostname or IP" default:"localhost" `
2018-02-22 14:20:18 -06:00
Port int ` long:"port" description:"Server port" default:"5432" `
User string ` long:"user" description:"Database user" `
Pass string ` long:"pass" description:"Password for user" `
DbName string ` long:"db" description:"Database name" `
2022-11-23 16:21:30 -06:00
SSLMode string ` long:"ssl" description:"SSL mode" `
SSLRootCert string ` long:"ssl-rootcert" description:"SSL certificate authority file" `
SSLCert string ` long:"ssl-cert" description:"SSL client certificate file" `
SSLKey string ` long:"ssl-key" description:"SSL client certificate key file" `
2019-11-02 13:00:23 -05:00
HTTPHost string ` long:"bind" description:"HTTP server host" default:"localhost" `
HTTPPort uint ` long:"listen" description:"HTTP server listen port" default:"8081" `
2018-02-22 14:20:18 -06:00
AuthUser string ` long:"auth-user" description:"HTTP basic auth user" `
AuthPass string ` long:"auth-pass" description:"HTTP basic auth password" `
SkipOpen bool ` short:"s" long:"skip-open" description:"Skip browser open on start" `
2018-08-31 21:49:24 -05:00
Sessions bool ` long:"sessions" description:"Enable multiple database sessions" `
2018-02-22 14:20:18 -06:00
Prefix string ` long:"prefix" description:"Add a url prefix" `
ReadOnly bool ` long:"readonly" description:"Run database connection in readonly mode" `
2018-08-31 21:49:24 -05:00
LockSession bool ` long:"lock-session" description:"Lock session to a single database connection" `
2018-02-22 14:20:18 -06:00
Bookmark string ` short:"b" long:"bookmark" description:"Bookmark to use for connection. Bookmark files are stored under $HOME/.pgweb/bookmarks/*.toml" default:"" `
BookmarksDir string ` long:"bookmarks-dir" description:"Overrides default directory for bookmark files to search" default:"" `
2019-11-02 13:00:23 -05:00
DisablePrettyJSON bool ` long:"no-pretty-json" description:"Disable JSON formatting feature for result export" `
2018-08-31 21:49:24 -05:00
DisableSSH bool ` long:"no-ssh" description:"Disable database connections via SSH" `
2018-02-22 14:20:18 -06:00
ConnectBackend string ` long:"connect-backend" description:"Enable database authentication through a third party backend" `
ConnectToken string ` long:"connect-token" description:"Authentication token for the third-party connect backend" `
ConnectHeaders string ` long:"connect-headers" description:"List of headers to pass to the connect backend" `
2018-08-31 21:49:24 -05:00
DisableConnectionIdleTimeout bool ` long:"no-idle-timeout" description:"Disable connection idle timeout" `
2018-02-22 14:20:18 -06:00
ConnectionIdleTimeout int ` long:"idle-timeout" description:"Set connection idle timeout in minutes" default:"180" `
2022-12-07 18:56:58 -06:00
QueryTimeout int ` long:"query-timeout" description:"Set global query execution timeout in seconds" default:"0" `
2018-08-31 21:49:24 -05:00
Cors bool ` long:"cors" description:"Enable Cross-Origin Resource Sharing (CORS)" `
2018-02-22 14:20:18 -06:00
CorsOrigin string ` long:"cors-origin" description:"Allowed CORS origins" default:"*" `
2022-03-26 18:11:33 -05:00
BinaryCodec string ` long:"binary-codec" description:"Codec for binary data serialization, one of 'none', 'hex', 'base58', 'base64'" default:"none" `
2015-04-30 11:47:07 -05:00
}
var Opts Options
2020-02-05 22:01:25 -06:00
// ParseOptions returns a new options struct from the input arguments
2018-02-22 14:20:18 -06:00
func ParseOptions ( args [ ] string ) ( Options , error ) {
var opts = Options { }
_ , err := flags . ParseArgs ( & opts , args )
2015-04-30 11:47:07 -05:00
if err != nil {
2018-02-22 14:20:18 -06:00
return opts , err
2015-04-30 11:47:07 -05:00
}
2022-12-06 12:09:21 -06:00
_ , err = logrus . ParseLevel ( opts . LogLevel )
if err != nil {
return opts , err
}
2019-11-02 13:00:23 -05:00
if opts . URL == "" {
2022-11-22 14:50:58 -06:00
opts . URL = getPrefixedEnvVar ( "DATABASE_URL" )
2015-04-30 11:47:07 -05:00
}
2018-11-27 14:58:50 -06:00
if opts . Prefix == "" {
2022-11-22 14:50:58 -06:00
opts . Prefix = getPrefixedEnvVar ( "URL_PREFIX" )
2018-11-27 14:58:50 -06:00
}
2019-01-28 14:22:05 -06:00
// 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.
2019-01-28 14:03:45 -06:00
if ( opts . Host == "localhost" || opts . Host == "127.0.0.1" ) && opts . User == "" {
2022-11-22 14:39:06 -06:00
if username := getCurrentUser ( ) ; username != "" {
2019-01-28 14:03:45 -06:00
opts . User = username
} else {
opts . Host = ""
}
}
2022-11-22 14:50:58 -06:00
if getPrefixedEnvVar ( "SESSIONS" ) != "" {
2018-02-22 14:20:18 -06:00
opts . Sessions = true
2016-01-10 15:22:30 -06:00
}
2022-11-22 14:50:58 -06:00
if getPrefixedEnvVar ( "LOCK_SESSION" ) != "" {
2018-02-22 14:20:18 -06:00
opts . LockSession = true
opts . Sessions = false
2016-11-05 21:23:37 -05:00
}
2018-09-14 00:54:42 -05:00
if opts . Sessions || opts . ConnectBackend != "" {
2018-09-14 00:56:16 -05:00
opts . Bookmark = ""
2019-11-02 13:00:23 -05:00
opts . URL = ""
2018-09-14 00:54:42 -05:00
opts . Host = ""
opts . User = ""
opts . Pass = ""
opts . DbName = ""
2022-11-23 16:21:30 -06:00
opts . SSLMode = ""
2018-09-14 00:54:42 -05:00
}
2018-02-22 14:20:18 -06:00
if opts . Prefix != "" && ! strings . Contains ( opts . Prefix , "/" ) {
opts . Prefix = opts . Prefix + "/"
2016-02-19 21:14:56 -06:00
}
2022-11-22 14:50:58 -06:00
if opts . AuthUser == "" {
opts . AuthUser = getPrefixedEnvVar ( "AUTH_USER" )
2016-09-28 20:37:07 -05:00
}
2022-11-22 14:50:58 -06:00
if opts . AuthPass == "" {
opts . AuthPass = getPrefixedEnvVar ( "AUTH_PASS" )
2016-09-28 20:37:07 -05:00
}
2018-02-22 14:20:18 -06:00
if opts . ConnectBackend != "" {
if ! opts . Sessions {
return opts , errors . New ( "--sessions flag must be set" )
2017-09-15 18:54:14 -05:00
}
2018-02-22 14:20:18 -06:00
if opts . ConnectToken == "" {
return opts , errors . New ( "--connect-token flag must be set" )
2017-09-15 18:54:14 -05:00
}
2017-09-21 02:06:14 -05:00
} else {
2018-02-22 14:20:18 -06:00
if opts . ConnectToken != "" || opts . ConnectHeaders != "" {
return opts , errors . New ( "--connect-backend flag must be set" )
2017-09-21 02:06:14 -05:00
}
2017-09-15 18:54:14 -05:00
}
2018-02-22 14:20:18 -06:00
return opts , nil
}
2019-01-28 14:03:45 -06:00
// SetDefaultOptions parses and assigns the options
2018-02-22 14:20:18 -06:00
func SetDefaultOptions ( ) error {
opts , err := ParseOptions ( [ ] string { } )
if err != nil {
return err
}
Opts = opts
2015-04-30 11:47:07 -05:00
return nil
}
2019-01-28 14:03:45 -06:00
2022-11-22 14:39:06 -06:00
// getCurrentUser returns a current user name
func getCurrentUser ( ) string {
2019-01-28 14:03:45 -06:00
u , _ := user . Current ( )
if u != nil {
return u . Username
}
return os . Getenv ( "USER" )
}
2022-11-22 14:50:58 -06:00
// getPrefixedEnvVar returns env var with prefix, or falls back to unprefixed one
func getPrefixedEnvVar ( name string ) string {
val := os . Getenv ( envVarPrefix + name )
if val == "" {
val = os . Getenv ( name )
2022-11-22 15:20:49 -06:00
if val != "" {
fmt . Printf ( "[DEPRECATION] Usage of %s env var is deprecated, please use PGWEB_%s variable instead\n" , name , name )
}
2022-11-22 14:50:58 -06:00
}
return val
}
2022-11-22 16:09:01 -06:00
2022-11-22 16:17:28 -06:00
// AvailableEnvVars returns list of supported env vars.
//
// TODO: These should probably be embedded into flag parsing logic so we dont have
2022-11-22 16:09:01 -06:00
// to maintain the list manually.
func AvailableEnvVars ( ) string {
return strings . Join ( [ ] string {
" " + envVarPrefix + "DATABASE_URL Database connection string" ,
" " + envVarPrefix + "URL_PREFIX HTTP server path prefix" ,
" " + envVarPrefix + "SESSIONS: Enable multiple database sessions" ,
" " + envVarPrefix + "LOCK_SESSION Lock session to a single database connection" ,
" " + envVarPrefix + "AUTH_USER HTTP basic auth username" ,
" " + envVarPrefix + "AUTH_PASS HTTP basic auth password" ,
} , "\n" )
}