Procházet zdrojové kódy

lib/api, lib/config: Apply defaults before deserializing json (#7690)

Simon Frei před 4 roky
rodič
revize
52eb7392c4

+ 1 - 1
gui/default/syncthing/core/syncthingController.js

@@ -2129,7 +2129,7 @@ angular.module('syncthing.core')
                 folderCfg.versioning.params.command = '' + folderCfg._guiVersioning.externalCommand;
                 break;
             default:
-                delete folderCfg.versioning;
+                folderCfg.versioning = {type: ''};
             }
             delete folderCfg._guiVersioning;
 

+ 44 - 29
lib/api/confighandler.go

@@ -17,6 +17,7 @@ import (
 
 	"github.com/syncthing/syncthing/lib/config"
 	"github.com/syncthing/syncthing/lib/protocol"
+	"github.com/syncthing/syncthing/lib/util"
 )
 
 type configMuxBuilder struct {
@@ -63,10 +64,15 @@ func (c *configMuxBuilder) registerFolders(path string) {
 	})
 
 	c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
-		var folders []config.FolderConfiguration
-		if err := unmarshalTo(r.Body, &folders); err != nil {
-			http.Error(w, err.Error(), http.StatusBadRequest)
-			return
+		data, err := unmarshalToRawMessages(r.Body)
+		folders := make([]config.FolderConfiguration, len(data))
+		defaultFolder := c.cfg.DefaultFolder()
+		for i, bs := range data {
+			folders[i] = defaultFolder.Copy()
+			if err := json.Unmarshal(bs, &folders[i]); err != nil {
+				http.Error(w, err.Error(), http.StatusBadRequest)
+				return
+			}
 		}
 		waiter, err := c.cfg.Modify(func(cfg *config.Configuration) {
 			cfg.SetFolders(folders)
@@ -79,7 +85,7 @@ func (c *configMuxBuilder) registerFolders(path string) {
 	})
 
 	c.HandlerFunc(http.MethodPost, path, func(w http.ResponseWriter, r *http.Request) {
-		c.adjustFolder(w, r, config.FolderConfiguration{}, false)
+		c.adjustFolder(w, r, c.cfg.DefaultFolder(), false)
 	})
 }
 
@@ -89,10 +95,15 @@ func (c *configMuxBuilder) registerDevices(path string) {
 	})
 
 	c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
-		var devices []config.DeviceConfiguration
-		if err := unmarshalTo(r.Body, &devices); err != nil {
-			http.Error(w, err.Error(), http.StatusBadRequest)
-			return
+		data, err := unmarshalToRawMessages(r.Body)
+		devices := make([]config.DeviceConfiguration, len(data))
+		defaultDevice := c.cfg.DefaultDevice()
+		for i, bs := range data {
+			devices[i] = defaultDevice.Copy()
+			if err := json.Unmarshal(bs, &devices[i]); err != nil {
+				http.Error(w, err.Error(), http.StatusBadRequest)
+				return
+			}
 		}
 		waiter, err := c.cfg.Modify(func(cfg *config.Configuration) {
 			cfg.SetDevices(devices)
@@ -105,19 +116,7 @@ func (c *configMuxBuilder) registerDevices(path string) {
 	})
 
 	c.HandlerFunc(http.MethodPost, path, func(w http.ResponseWriter, r *http.Request) {
-		var device config.DeviceConfiguration
-		if err := unmarshalTo(r.Body, &device); err != nil {
-			http.Error(w, err.Error(), http.StatusBadRequest)
-			return
-		}
-		waiter, err := c.cfg.Modify(func(cfg *config.Configuration) {
-			cfg.SetDevice(device)
-		})
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-		c.finish(w, waiter)
+		c.adjustDevice(w, r, c.cfg.DefaultDevice(), false)
 	})
 }
 
@@ -132,7 +131,7 @@ func (c *configMuxBuilder) registerFolder(path string) {
 	})
 
 	c.Handle(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
-		c.adjustFolder(w, r, config.FolderConfiguration{}, false)
+		c.adjustFolder(w, r, c.cfg.DefaultFolder(), false)
 	})
 
 	c.Handle(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
@@ -176,7 +175,7 @@ func (c *configMuxBuilder) registerDevice(path string) {
 	})
 
 	c.Handle(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
-		c.adjustDevice(w, r, config.DeviceConfiguration{}, false)
+		c.adjustDevice(w, r, c.cfg.DefaultDevice(), false)
 	})
 
 	c.Handle(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
@@ -206,7 +205,9 @@ func (c *configMuxBuilder) registerDefaultFolder(path string) {
 	})
 
 	c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
-		c.adjustFolder(w, r, config.FolderConfiguration{}, true)
+		var cfg config.FolderConfiguration
+		util.SetDefaults(&cfg)
+		c.adjustFolder(w, r, cfg, true)
 	})
 
 	c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
@@ -220,7 +221,9 @@ func (c *configMuxBuilder) registerDefaultDevice(path string) {
 	})
 
 	c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
-		c.adjustDevice(w, r, config.DeviceConfiguration{}, true)
+		var cfg config.DeviceConfiguration
+		util.SetDefaults(&cfg)
+		c.adjustDevice(w, r, cfg, true)
 	})
 
 	c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
@@ -234,7 +237,9 @@ func (c *configMuxBuilder) registerOptions(path string) {
 	})
 
 	c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
-		c.adjustOptions(w, r, config.OptionsConfiguration{})
+		var cfg config.OptionsConfiguration
+		util.SetDefaults(&cfg)
+		c.adjustOptions(w, r, cfg)
 	})
 
 	c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
@@ -248,7 +253,9 @@ func (c *configMuxBuilder) registerLDAP(path string) {
 	})
 
 	c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
-		c.adjustLDAP(w, r, config.LDAPConfiguration{})
+		var cfg config.LDAPConfiguration
+		util.SetDefaults(&cfg)
+		c.adjustLDAP(w, r, cfg)
 	})
 
 	c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
@@ -262,7 +269,9 @@ func (c *configMuxBuilder) registerGUI(path string) {
 	})
 
 	c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
-		c.adjustGUI(w, r, config.GUIConfiguration{})
+		var cfg config.GUIConfiguration
+		util.SetDefaults(&cfg)
+		c.adjustGUI(w, r, cfg)
 	})
 
 	c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
@@ -403,6 +412,12 @@ func unmarshalTo(body io.ReadCloser, to interface{}) error {
 	return json.Unmarshal(bs, to)
 }
 
+func unmarshalToRawMessages(body io.ReadCloser) ([]json.RawMessage, error) {
+	var data []json.RawMessage
+	err := unmarshalTo(body, &data)
+	return data, err
+}
+
 func checkGUIPassword(oldPassword, newPassword string) (string, error) {
 	if newPassword == oldPassword {
 		return newPassword, nil

+ 28 - 3
lib/config/config.go

@@ -163,19 +163,44 @@ func ReadXML(r io.Reader, myID protocol.DeviceID) (Configuration, int, error) {
 }
 
 func ReadJSON(r io.Reader, myID protocol.DeviceID) (Configuration, error) {
+	bs, err := ioutil.ReadAll(r)
+	if err != nil {
+		return Configuration{}, err
+	}
+
 	var cfg Configuration
 
 	util.SetDefaults(&cfg)
 
-	bs, err := ioutil.ReadAll(r)
-	if err != nil {
+	if err := json.Unmarshal(bs, &cfg); err != nil {
 		return Configuration{}, err
 	}
 
-	if err := json.Unmarshal(bs, &cfg); err != nil {
+	// Unmarshal list of devices and folders separately to set defaults
+	var rawFoldersDevices struct {
+		Folders []json.RawMessage
+		Devices []json.RawMessage
+	}
+	if err := json.Unmarshal(bs, &rawFoldersDevices); err != nil {
 		return Configuration{}, err
 	}
 
+	cfg.Folders = make([]FolderConfiguration, len(rawFoldersDevices.Folders))
+	for i, bs := range rawFoldersDevices.Folders {
+		cfg.Folders[i] = cfg.Defaults.Folder.Copy()
+		if err := json.Unmarshal(bs, &cfg.Folders[i]); err != nil {
+			return Configuration{}, err
+		}
+	}
+
+	cfg.Devices = make([]DeviceConfiguration, len(rawFoldersDevices.Devices))
+	for i, bs := range rawFoldersDevices.Devices {
+		cfg.Devices[i] = cfg.Defaults.Device.Copy()
+		if err := json.Unmarshal(bs, &cfg.Devices[i]); err != nil {
+			return Configuration{}, err
+		}
+	}
+
 	if err := cfg.prepare(myID); err != nil {
 		return Configuration{}, err
 	}