GUI Basic Authentication (fixes #90)

This commit is contained in:
Jakob Borg 2014-04-08 15:56:12 +02:00
parent 1443a1388e
commit cbae64fc06
4 changed files with 31 additions and 13 deletions

View File

@ -14,6 +14,7 @@ type Configuration struct {
Version int `xml:"version,attr" default:"2"` Version int `xml:"version,attr" default:"2"`
Repositories []RepositoryConfiguration `xml:"repository"` Repositories []RepositoryConfiguration `xml:"repository"`
Nodes []NodeConfiguration `xml:"node"` Nodes []NodeConfiguration `xml:"node"`
GUI GUIConfiguration `xml:"gui"`
Options OptionsConfiguration `xml:"options"` Options OptionsConfiguration `xml:"options"`
XMLName xml.Name `xml:"configuration" json:"-"` XMLName xml.Name `xml:"configuration" json:"-"`
} }
@ -43,9 +44,6 @@ type NodeConfiguration struct {
type OptionsConfiguration struct { type OptionsConfiguration struct {
ListenAddress []string `xml:"listenAddress" default:":22000"` 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"` GlobalAnnServer string `xml:"globalAnnounceServer" default:"announce.syncthing.net:22025"`
GlobalAnnEnabled bool `xml:"globalAnnounceEnabled" default:"true"` GlobalAnnEnabled bool `xml:"globalAnnounceEnabled" default:"true"`
LocalAnnEnabled bool `xml:"localAnnounceEnabled" default:"true"` LocalAnnEnabled bool `xml:"localAnnounceEnabled" default:"true"`
@ -55,6 +53,17 @@ type OptionsConfiguration struct {
ReconnectIntervalS int `xml:"reconnectionIntervalS" default:"60"` ReconnectIntervalS int `xml:"reconnectionIntervalS" default:"60"`
MaxChangeKbps int `xml:"maxChangeKbps" default:"1000"` MaxChangeKbps int `xml:"maxChangeKbps" default:"1000"`
StartBrowser bool `xml:"startBrowser" default:"true"` 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 { func setDefaults(data interface{}) error {
@ -148,6 +157,7 @@ func readConfigXML(rd io.Reader) (Configuration, error) {
setDefaults(&cfg) setDefaults(&cfg)
setDefaults(&cfg.Options) setDefaults(&cfg.Options)
setDefaults(&cfg.GUI)
var err error var err error
if rd != nil { 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. // Set all repositories to read only if the global read only flag is set.
var nodes = map[string]NodeConfiguration{} var nodes = map[string]NodeConfiguration{}
for i, repo := range cfg.Repositories { 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 { for j, node := range repo.Nodes {
if _, ok := nodes[node.NodeID]; !ok { if _, ok := nodes[node.NodeID]; !ok {
nodes[node.NodeID] = node nodes[node.NodeID] = node
@ -192,6 +202,7 @@ func convertV1V2(cfg *Configuration) {
cfg.Repositories[i].Nodes[j] = NodeConfiguration{NodeID: node.NodeID} cfg.Repositories[i].Nodes[j] = NodeConfiguration{NodeID: node.NodeID}
} }
} }
cfg.Options.Deprecated_ReadOnly = false
// Set and sort the list of nodes. // Set and sort the list of nodes.
for _, node := range nodes { for _, node := range nodes {
@ -199,7 +210,12 @@ func convertV1V2(cfg *Configuration) {
} }
sort.Sort(NodeConfigurationList(cfg.Nodes)) 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 cfg.Version = 2
} }

View File

@ -10,8 +10,6 @@ import (
func TestDefaultValues(t *testing.T) { func TestDefaultValues(t *testing.T) {
expected := OptionsConfiguration{ expected := OptionsConfiguration{
ListenAddress: []string{":22000"}, ListenAddress: []string{":22000"},
GUIEnabled: true,
GUIAddress: "127.0.0.1:8080",
GlobalAnnServer: "announce.syncthing.net:22025", GlobalAnnServer: "announce.syncthing.net:22025",
GlobalAnnEnabled: true, GlobalAnnEnabled: true,
LocalAnnEnabled: true, LocalAnnEnabled: true,

View File

@ -11,6 +11,7 @@ import (
"github.com/calmh/syncthing/scanner" "github.com/calmh/syncthing/scanner"
"github.com/codegangsta/martini" "github.com/codegangsta/martini"
"github.com/codegangsta/martini-contrib/auth"
) )
type guiError struct { type guiError struct {
@ -24,7 +25,7 @@ var (
guiErrorsMut sync.Mutex guiErrorsMut sync.Mutex
) )
func startGUI(addr string, m *Model) { func startGUI(cfg GUIConfiguration, m *Model) {
router := martini.NewRouter() router := martini.NewRouter()
router.Get("/", getRoot) router.Get("/", getRoot)
router.Get("/rest/version", restGetVersion) router.Get("/rest/version", restGetVersion)
@ -43,12 +44,15 @@ func startGUI(addr string, m *Model) {
go func() { go func() {
mr := martini.New() 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(embeddedStatic())
mr.Use(martini.Recovery()) mr.Use(martini.Recovery())
mr.Use(restMiddleware) mr.Use(restMiddleware)
mr.Action(router.Handle) mr.Action(router.Handle)
mr.Map(m) mr.Map(m)
err := http.ListenAndServe(addr, mr) err := http.ListenAndServe(cfg.Address, mr)
if err != nil { if err != nil {
warnln("GUI not possible:", err) warnln("GUI not possible:", err)
} }

View File

@ -185,10 +185,10 @@ func main() {
} }
// GUI // GUI
if cfg.Options.GUIEnabled && cfg.Options.GUIAddress != "" { if cfg.GUI.Enabled && cfg.GUI.Address != "" {
addr, err := net.ResolveTCPAddr("tcp", cfg.Options.GUIAddress) addr, err := net.ResolveTCPAddr("tcp", cfg.GUI.Address)
if err != nil { 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 { } else {
var hostOpen, hostShow string var hostOpen, hostShow string
switch { switch {
@ -204,7 +204,7 @@ func main() {
} }
infof("Starting web GUI on http://%s:%d/", hostShow, addr.Port) 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 { if cfg.Options.StartBrowser && len(os.Getenv("STRESTART")) == 0 {
openURL(fmt.Sprintf("http://%s:%d", hostOpen, addr.Port)) openURL(fmt.Sprintf("http://%s:%d", hostOpen, addr.Port))
} }