From 1e71b0093626a00867725813bebc733e967f5353 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Sat, 5 Jan 2019 18:10:02 +0100 Subject: [PATCH] lib/model: Sanitize paths used for auto accepted folders (fixes #5411) (#5435) --- lib/model/model.go | 26 +++++++++++++++++++++++++- lib/model/model_test.go | 19 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/model/model.go b/lib/model/model.go index 5a3122ed9..a96775fb0 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -16,6 +16,7 @@ import ( "net" "path/filepath" "reflect" + "regexp" "runtime" "strings" stdsync "sync" @@ -1244,7 +1245,11 @@ func (m *Model) handleAutoAccepts(deviceCfg config.DeviceConfiguration, folder p if cfg, ok := m.cfg.Folder(folder.ID); !ok { defaultPath := m.cfg.Options().DefaultFolderPath defaultPathFs := fs.NewFilesystem(fs.FilesystemTypeBasic, defaultPath) - for _, path := range []string{folder.Label, folder.ID} { + pathAlternatives := []string{ + sanitizePath(folder.Label), + sanitizePath(folder.ID), + } + for _, path := range pathAlternatives { if _, err := defaultPathFs.Lstat(path); !fs.IsNotExist(err) { continue } @@ -2845,3 +2850,22 @@ func (m *syncMutexMap) Get(key string) sync.Mutex { v, _ := m.inner.LoadOrStore(key, sync.NewMutex()) return v.(sync.Mutex) } + +// sanitizePath takes a string that might contain all kinds of special +// characters and makes a valid, similar, path name out of it. +// +// Spans of invalid characters are replaced by a single space. Invalid +// characters are control characters, the things not allowed in file names +// in Windows, and common shell metacharacters. Even if asterisks and pipes +// and stuff are allowed on Unixes in general they might not be allowed by +// the filesystem and may surprise the user and cause shell oddness. This +// function is intended for file names we generate on behalf of the user, +// and surprising them with odd shell characters in file names is unkind. +// +// We include whitespace in the invalid characters so that multiple +// whitespace is collapsed to a single space. Additionally, whitespace at +// either end is removed. +func sanitizePath(path string) string { + invalid := regexp.MustCompile(`([[:cntrl:]]|[<>:"'/\\|?*\n\r\t \[\]\{\};:!@$%&^#])+`) + return strings.TrimSpace(invalid.ReplaceAllString(path, " ")) +} diff --git a/lib/model/model_test.go b/lib/model/model_test.go index c094612f6..e8f286c8c 100644 --- a/lib/model/model_test.go +++ b/lib/model/model_test.go @@ -3799,3 +3799,22 @@ func TestRequestLimit(t *testing.T) { t.Fatalf("Second request did not return after first was done") } } + +func TestSanitizePath(t *testing.T) { + cases := [][2]string{ + {"", ""}, + {"foo", "foo"}, + {`\*/foo\?/bar[{!@$%^&*#()}]`, "foo bar ()"}, + {"Räksmörgås", "Räksmörgås"}, + {`Räk \/ smörgås`, "Räk smörgås"}, + {"هذا هو *\x07?اسم الملف", "هذا هو اسم الملف"}, + {`../foo.txt`, `.. foo.txt`}, + } + + for _, tc := range cases { + res := sanitizePath(tc[0]) + if res != tc[1] { + t.Errorf("sanitizePath(%q) => %q, expected %q", tc[0], res, tc[1]) + } + } +}