From cbae64fc06723954b977f468e5849c3033daeb2f Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Tue, 8 Apr 2014 15:56:12 +0200 Subject: [PATCH] GUI Basic Authentication (fixes #90) --- cmd/syncthing/config.go | 26 +++++++++++++++++++++----- cmd/syncthing/config_test.go | 2 -- cmd/syncthing/gui.go | 8 ++++++-- cmd/syncthing/main.go | 8 ++++---- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/cmd/syncthing/config.go b/cmd/syncthing/config.go index 3e0878aa0..fc86ab390 100644 --- a/cmd/syncthing/config.go +++ b/cmd/syncthing/config.go @@ -14,6 +14,7 @@ type Configuration struct { Version int `xml:"version,attr" default:"2"` Repositories []RepositoryConfiguration `xml:"repository"` Nodes []NodeConfiguration `xml:"node"` + GUI GUIConfiguration `xml:"gui"` Options OptionsConfiguration `xml:"options"` XMLName xml.Name `xml:"configuration" json:"-"` } @@ -43,9 +44,6 @@ type NodeConfiguration struct { type OptionsConfiguration struct { ListenAddress []string `xml:"listenAddress" default:":22000"` - ReadOnly bool `xml:"readOnly,omitempty"` - GUIEnabled bool `xml:"guiEnabled" default:"true"` - GUIAddress string `xml:"guiAddress" default:"127.0.0.1:8080"` GlobalAnnServer string `xml:"globalAnnounceServer" default:"announce.syncthing.net:22025"` GlobalAnnEnabled bool `xml:"globalAnnounceEnabled" default:"true"` LocalAnnEnabled bool `xml:"localAnnounceEnabled" default:"true"` @@ -55,6 +53,17 @@ type OptionsConfiguration struct { ReconnectIntervalS int `xml:"reconnectionIntervalS" default:"60"` MaxChangeKbps int `xml:"maxChangeKbps" default:"1000"` StartBrowser bool `xml:"startBrowser" default:"true"` + + Deprecated_ReadOnly bool `xml:"readOnly,omitempty"` + Deprecated_GUIEnabled bool `xml:"guiEnabled,omitempty"` + Deprecated_GUIAddress string `xml:"guiAddress,omitempty"` +} + +type GUIConfiguration struct { + Enabled bool `xml:"enabled,attr" default:"true"` + Address string `xml:"address" default:"127.0.0.1:8080"` + User string `xml:"user,omitempty"` + Password string `xml:"password,omitempty"` } func setDefaults(data interface{}) error { @@ -148,6 +157,7 @@ func readConfigXML(rd io.Reader) (Configuration, error) { setDefaults(&cfg) setDefaults(&cfg.Options) + setDefaults(&cfg.GUI) var err error if rd != nil { @@ -184,7 +194,7 @@ func convertV1V2(cfg *Configuration) { // Set all repositories to read only if the global read only flag is set. var nodes = map[string]NodeConfiguration{} for i, repo := range cfg.Repositories { - cfg.Repositories[i].ReadOnly = cfg.Options.ReadOnly + cfg.Repositories[i].ReadOnly = cfg.Options.Deprecated_ReadOnly for j, node := range repo.Nodes { if _, ok := nodes[node.NodeID]; !ok { nodes[node.NodeID] = node @@ -192,6 +202,7 @@ func convertV1V2(cfg *Configuration) { cfg.Repositories[i].Nodes[j] = NodeConfiguration{NodeID: node.NodeID} } } + cfg.Options.Deprecated_ReadOnly = false // Set and sort the list of nodes. for _, node := range nodes { @@ -199,7 +210,12 @@ func convertV1V2(cfg *Configuration) { } sort.Sort(NodeConfigurationList(cfg.Nodes)) - cfg.Options.ReadOnly = false + // GUI + cfg.GUI.Address = cfg.Options.Deprecated_GUIAddress + cfg.GUI.Enabled = cfg.Options.Deprecated_GUIEnabled + cfg.Options.Deprecated_GUIEnabled = false + cfg.Options.Deprecated_GUIAddress = "" + cfg.Version = 2 } diff --git a/cmd/syncthing/config_test.go b/cmd/syncthing/config_test.go index a81f4fc94..1008a7734 100644 --- a/cmd/syncthing/config_test.go +++ b/cmd/syncthing/config_test.go @@ -10,8 +10,6 @@ import ( func TestDefaultValues(t *testing.T) { expected := OptionsConfiguration{ ListenAddress: []string{":22000"}, - GUIEnabled: true, - GUIAddress: "127.0.0.1:8080", GlobalAnnServer: "announce.syncthing.net:22025", GlobalAnnEnabled: true, LocalAnnEnabled: true, diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go index 4ca6285ae..91424e23c 100644 --- a/cmd/syncthing/gui.go +++ b/cmd/syncthing/gui.go @@ -11,6 +11,7 @@ import ( "github.com/calmh/syncthing/scanner" "github.com/codegangsta/martini" + "github.com/codegangsta/martini-contrib/auth" ) type guiError struct { @@ -24,7 +25,7 @@ var ( guiErrorsMut sync.Mutex ) -func startGUI(addr string, m *Model) { +func startGUI(cfg GUIConfiguration, m *Model) { router := martini.NewRouter() router.Get("/", getRoot) router.Get("/rest/version", restGetVersion) @@ -43,12 +44,15 @@ func startGUI(addr string, m *Model) { go func() { mr := martini.New() + if len(cfg.User) > 0 && len(cfg.Password) > 0 { + mr.Use(auth.Basic(cfg.User, cfg.Password)) + } mr.Use(embeddedStatic()) mr.Use(martini.Recovery()) mr.Use(restMiddleware) mr.Action(router.Handle) mr.Map(m) - err := http.ListenAndServe(addr, mr) + err := http.ListenAndServe(cfg.Address, mr) if err != nil { warnln("GUI not possible:", err) } diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index 73bf45d01..32e176092 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -185,10 +185,10 @@ func main() { } // GUI - if cfg.Options.GUIEnabled && cfg.Options.GUIAddress != "" { - addr, err := net.ResolveTCPAddr("tcp", cfg.Options.GUIAddress) + if cfg.GUI.Enabled && cfg.GUI.Address != "" { + addr, err := net.ResolveTCPAddr("tcp", cfg.GUI.Address) if err != nil { - warnf("Cannot start GUI on %q: %v", cfg.Options.GUIAddress, err) + warnf("Cannot start GUI on %q: %v", cfg.GUI.Address, err) } else { var hostOpen, hostShow string switch { @@ -204,7 +204,7 @@ func main() { } infof("Starting web GUI on http://%s:%d/", hostShow, addr.Port) - startGUI(cfg.Options.GUIAddress, m) + startGUI(cfg.GUI, m) if cfg.Options.StartBrowser && len(os.Getenv("STRESTART")) == 0 { openURL(fmt.Sprintf("http://%s:%d", hostOpen, addr.Port)) }