Allow configuring GUI options from command line and environment (fixes #505, closes #507)

This commit is contained in:
Audrius Butkevicius 2014-08-15 23:24:24 +01:00
parent 3a01eaa4a6
commit 8803bac708

View File

@ -26,6 +26,7 @@ import (
"strings" "strings"
"time" "time"
"code.google.com/p/go.crypto/bcrypt"
"github.com/juju/ratelimit" "github.com/juju/ratelimit"
"github.com/syncthing/syncthing/config" "github.com/syncthing/syncthing/config"
"github.com/syncthing/syncthing/discover" "github.com/syncthing/syncthing/discover"
@ -102,6 +103,15 @@ show time only (2).
The following enviroment variables are interpreted by syncthing: The following enviroment variables are interpreted by syncthing:
STGUIADDRESS Override GUI listen address set in config. Expects protocol type
followed by hostname or an IP address, followed by a port, such
as "https://127.0.0.1:8888".
STGUIAUTH Override GUI authentication credentials set in config. Expects
a colon separated username and password, such as "admin:secret".
STGUIAPIKEY Override GUI API key set in config.
STNORESTART Do not attempt to restart when requested to, instead just exit. STNORESTART Do not attempt to restart when requested to, instead just exit.
Set this variable when running under a service manager such as Set this variable when running under a service manager such as
runit, launchd, etc. runit, launchd, etc.
@ -144,16 +154,22 @@ func main() {
var showVersion bool var showVersion bool
var doUpgrade bool var doUpgrade bool
var doUpgradeCheck bool var doUpgradeCheck bool
var generateDir string
var noBrowser bool var noBrowser bool
var generateDir string
var guiAddress string
var guiAuthentication string
var guiAPIKey string
flag.StringVar(&confDir, "home", getDefaultConfDir(), "Set configuration directory") flag.StringVar(&confDir, "home", getDefaultConfDir(), "Set configuration directory")
flag.BoolVar(&reset, "reset", false, "Prepare to resync from cluster") flag.BoolVar(&reset, "reset", false, "Prepare to resync from cluster")
flag.BoolVar(&showVersion, "version", false, "Show version") flag.BoolVar(&showVersion, "version", false, "Show version")
flag.BoolVar(&doUpgrade, "upgrade", false, "Perform upgrade") flag.BoolVar(&doUpgrade, "upgrade", false, "Perform upgrade")
flag.BoolVar(&doUpgradeCheck, "upgrade-check", false, "Check for available upgrade") flag.BoolVar(&doUpgradeCheck, "upgrade-check", false, "Check for available upgrade")
flag.BoolVar(&noBrowser, "no-browser", false, "Do not start browser") flag.BoolVar(&noBrowser, "no-browser", false, "Do not start browser")
flag.IntVar(&logFlags, "logflags", logFlags, "Set log flags")
flag.StringVar(&generateDir, "generate", "", "Generate key in specified dir") flag.StringVar(&generateDir, "generate", "", "Generate key in specified dir")
flag.StringVar(&guiAddress, "gui-address", "", "Override GUI address")
flag.StringVar(&guiAuthentication, "gui-authentication", "", "Override GUI authentication. Expects 'username:password'")
flag.StringVar(&guiAPIKey, "gui-apikey", "", "Override GUI API key")
flag.IntVar(&logFlags, "logflags", logFlags, "Set log flags")
flag.Usage = usageFor(flag.CommandLine, usage, extraUsage) flag.Usage = usageFor(flag.CommandLine, usage, extraUsage)
flag.Parse() flag.Parse()
@ -410,10 +426,13 @@ nextRepo:
} }
// GUI // GUI
if cfg.GUI.Enabled && cfg.GUI.Address != "" {
addr, err := net.ResolveTCPAddr("tcp", cfg.GUI.Address) guiCfg := overrideGUIConfig(cfg.GUI, guiAddress, guiAuthentication, guiAPIKey)
if guiCfg.Enabled && guiCfg.Address != "" {
addr, err := net.ResolveTCPAddr("tcp", guiCfg.Address)
if err != nil { if err != nil {
l.Fatalf("Cannot start GUI on %q: %v", cfg.GUI.Address, err) l.Fatalf("Cannot start GUI on %q: %v", guiCfg.Address, err)
} else { } else {
var hostOpen, hostShow string var hostOpen, hostShow string
switch { switch {
@ -429,12 +448,12 @@ nextRepo:
} }
var proto = "http" var proto = "http"
if cfg.GUI.UseTLS { if guiCfg.UseTLS {
proto = "https" proto = "https"
} }
l.Infof("Starting web GUI on %s://%s:%d/", proto, hostShow, addr.Port) l.Infof("Starting web GUI on %s://%s:%d/", proto, hostShow, addr.Port)
err := startGUI(cfg.GUI, os.Getenv("STGUIASSETS"), m) err := startGUI(guiCfg, os.Getenv("STGUIASSETS"), m)
if err != nil { if err != nil {
l.Fatalln("Cannot start GUI:", err) l.Fatalln("Cannot start GUI:", err)
} }
@ -1095,3 +1114,52 @@ func getLockPort() (int, error) {
addr := lockConn.Addr().(*net.TCPAddr) addr := lockConn.Addr().(*net.TCPAddr)
return addr.Port, nil return addr.Port, nil
} }
func overrideGUIConfig(originalCfg config.GUIConfiguration, address, authentication, apikey string) config.GUIConfiguration {
// Make a copy of the config
cfg := originalCfg
if address == "" {
address = os.Getenv("STGUIADDRESS")
}
if address != "" {
cfg.Enabled = true
addressParts := strings.SplitN(address, "://", 2)
switch addressParts[0] {
case "http":
cfg.UseTLS = false
case "https":
cfg.UseTLS = true
default:
l.Fatalln("Unidentified protocol", addressParts[0])
}
cfg.Address = addressParts[1]
}
if authentication == "" {
authentication = os.Getenv("STGUIAUTH")
}
if authentication != "" {
authenticationParts := strings.SplitN(authentication, ":", 2)
hash, err := bcrypt.GenerateFromPassword([]byte(authenticationParts[1]), 0)
if err != nil {
l.Fatalln("Invalid GUI password:", err)
}
cfg.User = authenticationParts[0]
cfg.Password = string(hash)
}
if apikey == "" {
apikey = os.Getenv("STGUIAPIKEY")
}
if apikey != "" {
cfg.APIKey = apikey
}
return cfg
}