From 130d6a768a4a4e1d7b1e6c3f58125874957de46d Mon Sep 17 00:00:00 2001 From: Simen Strange Date: Mon, 26 Jun 2023 21:55:23 +0200 Subject: [PATCH 1/7] added deny->file->write, so we can prevent OS created garbage, like .DS_Store --- app/config.go | 32 ++++++++++++++++++++++++++++++-- app/fs.go | 20 ++++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/app/config.go b/app/config.go index 69313ae..604bb3e 100644 --- a/app/config.go +++ b/app/config.go @@ -3,11 +3,13 @@ package app import ( "errors" "fmt" + "os" + "path/filepath" + "strings" + "github.com/fsnotify/fsnotify" log "github.com/sirupsen/logrus" "github.com/spf13/viper" - "os" - "path/filepath" ) // Config represents the configuration of the server application. @@ -16,6 +18,7 @@ type Config struct { Port string Prefix string Dir string + Deny Deny TLS *TLS Log Logging Realm string @@ -23,6 +26,14 @@ type Config struct { Cors Cors } +type Deny struct { + File File +} + +type File struct { + Write []string +} + // Logging allows definition for logging each CRUD method. type Logging struct { Error bool @@ -98,6 +109,7 @@ func setDefaults() { viper.SetDefault("Port", "8000") viper.SetDefault("Prefix", "") viper.SetDefault("Dir", "/tmp") + viper.SetDefault("Deny.File.Write", nil) viper.SetDefault("Users", nil) viper.SetDefault("TLS", nil) viper.SetDefault("Realm", "dave") @@ -179,6 +191,10 @@ func updateConfig(cfg *Config, updatedCfg *Config) { cfg.Log.Delete = updatedCfg.Log.Delete log.WithField("enabled", cfg.Log.Delete).Info("Set logging for delete operations") } + if !stringSlicesEqual(cfg.Deny.File.Write, updatedCfg.Deny.File.Write) { + cfg.Deny.File.Write = updatedCfg.Deny.File.Write + log.WithField("updated", strings.Join(cfg.Deny.File.Write, "; ")).Info("Updated denied file write entries") + } } func (cfg *Config) ensureUserDirs() { @@ -201,3 +217,15 @@ func (cfg *Config) ensureUserDirs() { } } } + +func stringSlicesEqual(f, j []string) bool { + if len(f) != len(j) { + return false + } + for i, v := range f { + if v != j[i] { + return false + } + } + return true +} diff --git a/app/fs.go b/app/fs.go index de39e67..f2f6d49 100644 --- a/app/fs.go +++ b/app/fs.go @@ -2,12 +2,15 @@ package app import ( "context" - log "github.com/sirupsen/logrus" - "golang.org/x/net/webdav" + "errors" + "fmt" "os" "path" "path/filepath" "strings" + + log "github.com/sirupsen/logrus" + "golang.org/x/net/webdav" ) // This file is an extension of golang.org/x/net/webdav/file.go. @@ -78,6 +81,19 @@ func (d Dir) OpenFile(ctx context.Context, name string, flag int, perm os.FileMo if name = d.resolve(ctx, name); name == "" { return nil, os.ErrNotExist } + // flag 0, os.O_RDONLY + // flag 1538, os.O_RDWR|os.O_CREATE|os.O_TRUNC + if flag != os.O_RDONLY { + for _, v := range d.Config.Deny.File.Write { + matched, err := filepath.Match(v, filepath.Base(name)) + if err != nil { + return nil, err + } + if matched { + return nil, errors.New(fmt.Sprintf("write %s, access denied", name)) + } + } + } f, err := os.OpenFile(name, flag, perm) if err != nil { return nil, err From 5f9d3a543e5b0c812dce0079c8eae6a38fbc3347 Mon Sep 17 00:00:00 2001 From: Simen Strange Date: Tue, 27 Jun 2023 21:31:23 +0200 Subject: [PATCH 2/7] added deny->directory->write, so we can prevent OS created garbage, like .fsevents --- app/config.go | 12 +++++++++++- app/fs.go | 12 ++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/app/config.go b/app/config.go index 604bb3e..064df2e 100644 --- a/app/config.go +++ b/app/config.go @@ -27,13 +27,18 @@ type Config struct { } type Deny struct { - File File + File File + Directory Directory } type File struct { Write []string } +type Directory struct { + Write []string +} + // Logging allows definition for logging each CRUD method. type Logging struct { Error bool @@ -110,6 +115,7 @@ func setDefaults() { viper.SetDefault("Prefix", "") viper.SetDefault("Dir", "/tmp") viper.SetDefault("Deny.File.Write", nil) + viper.SetDefault("Deny.Directory.Write", nil) viper.SetDefault("Users", nil) viper.SetDefault("TLS", nil) viper.SetDefault("Realm", "dave") @@ -195,6 +201,10 @@ func updateConfig(cfg *Config, updatedCfg *Config) { cfg.Deny.File.Write = updatedCfg.Deny.File.Write log.WithField("updated", strings.Join(cfg.Deny.File.Write, "; ")).Info("Updated denied file write entries") } + if !stringSlicesEqual(cfg.Deny.Directory.Write, updatedCfg.Deny.Directory.Write) { + cfg.Deny.Directory.Write = updatedCfg.Deny.Directory.Write + log.WithField("updated", strings.Join(cfg.Deny.Directory.Write, "; ")).Info("Updated denied directory write entries") + } } func (cfg *Config) ensureUserDirs() { diff --git a/app/fs.go b/app/fs.go index f2f6d49..cb420af 100644 --- a/app/fs.go +++ b/app/fs.go @@ -61,6 +61,17 @@ func (d Dir) Mkdir(ctx context.Context, name string, perm os.FileMode) error { if name = d.resolve(ctx, name); name == "" { return os.ErrNotExist } + + for _, v := range d.Config.Deny.Directory.Write { + matched, err := filepath.Match(v, filepath.Base(name)) + if err != nil { + return err + } + if matched { + return errors.New(fmt.Sprintf("mkdir %s, access denied", name)) + } + } + err := os.Mkdir(name, perm) if err != nil { return err @@ -94,6 +105,7 @@ func (d Dir) OpenFile(ctx context.Context, name string, flag int, perm os.FileMo } } } + f, err := os.OpenFile(name, flag, perm) if err != nil { return nil, err From 6d76c3f37b2015485b9e0b454da9baf7e9e5c3fa Mon Sep 17 00:00:00 2001 From: Simen Strange Date: Tue, 27 Jun 2023 21:45:47 +0200 Subject: [PATCH 3/7] added deny to configuration example --- Readme.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Readme.md b/Readme.md index 764a7df..b427090 100644 --- a/Readme.md +++ b/Readme.md @@ -64,6 +64,14 @@ address: "127.0.0.1" # the bind address port: "8000" # the listening port dir: "/home/webdav" # the provided base dir prefix: "/webdav" # the url-prefix of the original url +deny: # deny your OS to create garbage + file: + write: # deny creation of specified files + - .DS_Store + - ._* # globbing supported, https://pkg.go.dev/path/filepath#Match + directory: + write: # deny creation of specified directories + - .Trashes users: user: # with password 'foo' and jailed access to '/home/webdav/user' password: "$2a$10$yITzSSNJZAdDZs8iVBQzkuZCzZ49PyjTiPIrmBUKUpB0pwX7eySvW" From 728c8e72b584b4778108f0bda681bd1def3b6948 Mon Sep 17 00:00:00 2001 From: Simen Strange Date: Thu, 29 Jun 2023 18:41:03 +0200 Subject: [PATCH 4/7] use create as verb versus write, for files only deny actual creation, while allowing other, truncation, write etc. --- Readme.md | 4 ++-- app/config.go | 20 ++++++++++---------- app/fs.go | 25 +++++++++++++------------ 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/Readme.md b/Readme.md index b427090..92d09de 100644 --- a/Readme.md +++ b/Readme.md @@ -66,11 +66,11 @@ dir: "/home/webdav" # the provided base dir prefix: "/webdav" # the url-prefix of the original url deny: # deny your OS to create garbage file: - write: # deny creation of specified files + create: # deny creation of specified files - .DS_Store - ._* # globbing supported, https://pkg.go.dev/path/filepath#Match directory: - write: # deny creation of specified directories + create: # deny creation of specified directories - .Trashes users: user: # with password 'foo' and jailed access to '/home/webdav/user' diff --git a/app/config.go b/app/config.go index 064df2e..c26a36e 100644 --- a/app/config.go +++ b/app/config.go @@ -32,11 +32,11 @@ type Deny struct { } type File struct { - Write []string + Create []string } type Directory struct { - Write []string + Create []string } // Logging allows definition for logging each CRUD method. @@ -114,8 +114,8 @@ func setDefaults() { viper.SetDefault("Port", "8000") viper.SetDefault("Prefix", "") viper.SetDefault("Dir", "/tmp") - viper.SetDefault("Deny.File.Write", nil) - viper.SetDefault("Deny.Directory.Write", nil) + viper.SetDefault("Deny.File.Create", nil) + viper.SetDefault("Deny.Directory.Create", nil) viper.SetDefault("Users", nil) viper.SetDefault("TLS", nil) viper.SetDefault("Realm", "dave") @@ -197,13 +197,13 @@ func updateConfig(cfg *Config, updatedCfg *Config) { cfg.Log.Delete = updatedCfg.Log.Delete log.WithField("enabled", cfg.Log.Delete).Info("Set logging for delete operations") } - if !stringSlicesEqual(cfg.Deny.File.Write, updatedCfg.Deny.File.Write) { - cfg.Deny.File.Write = updatedCfg.Deny.File.Write - log.WithField("updated", strings.Join(cfg.Deny.File.Write, "; ")).Info("Updated denied file write entries") + if !stringSlicesEqual(cfg.Deny.File.Create, updatedCfg.Deny.File.Create) { + cfg.Deny.File.Create = updatedCfg.Deny.File.Create + log.WithField("updated", strings.Join(cfg.Deny.File.Create, "; ")).Info("Updated denied file create entries") } - if !stringSlicesEqual(cfg.Deny.Directory.Write, updatedCfg.Deny.Directory.Write) { - cfg.Deny.Directory.Write = updatedCfg.Deny.Directory.Write - log.WithField("updated", strings.Join(cfg.Deny.Directory.Write, "; ")).Info("Updated denied directory write entries") + if !stringSlicesEqual(cfg.Deny.Directory.Create, updatedCfg.Deny.Directory.Create) { + cfg.Deny.Directory.Create = updatedCfg.Deny.Directory.Create + log.WithField("updated", strings.Join(cfg.Deny.Directory.Create, "; ")).Info("Updated denied directory create entries") } } diff --git a/app/fs.go b/app/fs.go index cb420af..f8d1c05 100644 --- a/app/fs.go +++ b/app/fs.go @@ -62,13 +62,13 @@ func (d Dir) Mkdir(ctx context.Context, name string, perm os.FileMode) error { return os.ErrNotExist } - for _, v := range d.Config.Deny.Directory.Write { + for _, v := range d.Config.Deny.Directory.Create { matched, err := filepath.Match(v, filepath.Base(name)) if err != nil { return err } if matched { - return errors.New(fmt.Sprintf("mkdir %s, access denied", name)) + return errors.New(fmt.Sprintf("mkdir %s, action denied", name)) } } @@ -92,16 +92,17 @@ func (d Dir) OpenFile(ctx context.Context, name string, flag int, perm os.FileMo if name = d.resolve(ctx, name); name == "" { return nil, os.ErrNotExist } - // flag 0, os.O_RDONLY - // flag 1538, os.O_RDWR|os.O_CREATE|os.O_TRUNC - if flag != os.O_RDONLY { - for _, v := range d.Config.Deny.File.Write { - matched, err := filepath.Match(v, filepath.Base(name)) - if err != nil { - return nil, err - } - if matched { - return nil, errors.New(fmt.Sprintf("write %s, access denied", name)) + if len(d.Config.Deny.File.Create) > 0 { + // os.O_RDONLY: 0, os.O_RDWR: 2, os.O_CREATE: 512, O_TRUNC: 1024 + if flag == os.O_RDWR|os.O_CREATE|os.O_TRUNC || flag == os.O_RDWR|os.O_CREATE || flag == os.O_CREATE|os.O_TRUNC || flag == os.O_CREATE { + for _, v := range d.Config.Deny.File.Create { + matched, err := filepath.Match(v, filepath.Base(name)) + if err != nil { + return nil, err + } + if matched { + return nil, errors.New(fmt.Sprintf("create %s, action denied", name)) + } } } } From 20cc71cee920a3e631cea177354df656ac9e2236 Mon Sep 17 00:00:00 2001 From: Simen Strange Date: Fri, 30 Jun 2023 20:40:58 +0200 Subject: [PATCH 5/7] reorganised structs, Deny.{File,Directory}.Create is now Deny.Create.{File,Directory} --- app/config.go | 28 ++++++++++++---------------- app/fs.go | 6 +++--- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/app/config.go b/app/config.go index c26a36e..bbf407a 100644 --- a/app/config.go +++ b/app/config.go @@ -27,16 +27,12 @@ type Config struct { } type Deny struct { - File File - Directory Directory + Create Create } -type File struct { - Create []string -} - -type Directory struct { - Create []string +type Create struct { + File []string + Directory []string } // Logging allows definition for logging each CRUD method. @@ -114,8 +110,8 @@ func setDefaults() { viper.SetDefault("Port", "8000") viper.SetDefault("Prefix", "") viper.SetDefault("Dir", "/tmp") - viper.SetDefault("Deny.File.Create", nil) - viper.SetDefault("Deny.Directory.Create", nil) + viper.SetDefault("Deny.Create.File", nil) + viper.SetDefault("Deny.Create.Directory", nil) viper.SetDefault("Users", nil) viper.SetDefault("TLS", nil) viper.SetDefault("Realm", "dave") @@ -197,13 +193,13 @@ func updateConfig(cfg *Config, updatedCfg *Config) { cfg.Log.Delete = updatedCfg.Log.Delete log.WithField("enabled", cfg.Log.Delete).Info("Set logging for delete operations") } - if !stringSlicesEqual(cfg.Deny.File.Create, updatedCfg.Deny.File.Create) { - cfg.Deny.File.Create = updatedCfg.Deny.File.Create - log.WithField("updated", strings.Join(cfg.Deny.File.Create, "; ")).Info("Updated denied file create entries") + if !stringSlicesEqual(cfg.Deny.Create.File, updatedCfg.Deny.Create.File) { + cfg.Deny.Create.File = updatedCfg.Deny.Create.File + log.WithField("updated", strings.Join(cfg.Deny.Create.File, "; ")).Info("Updated denied file create entries") } - if !stringSlicesEqual(cfg.Deny.Directory.Create, updatedCfg.Deny.Directory.Create) { - cfg.Deny.Directory.Create = updatedCfg.Deny.Directory.Create - log.WithField("updated", strings.Join(cfg.Deny.Directory.Create, "; ")).Info("Updated denied directory create entries") + if !stringSlicesEqual(cfg.Deny.Create.Directory, updatedCfg.Deny.Create.Directory) { + cfg.Deny.Create.Directory = updatedCfg.Deny.Create.Directory + log.WithField("updated", strings.Join(cfg.Deny.Create.Directory, "; ")).Info("Updated denied directory create entries") } } diff --git a/app/fs.go b/app/fs.go index f8d1c05..e91802a 100644 --- a/app/fs.go +++ b/app/fs.go @@ -62,7 +62,7 @@ func (d Dir) Mkdir(ctx context.Context, name string, perm os.FileMode) error { return os.ErrNotExist } - for _, v := range d.Config.Deny.Directory.Create { + for _, v := range d.Config.Deny.Create.Directory { matched, err := filepath.Match(v, filepath.Base(name)) if err != nil { return err @@ -92,10 +92,10 @@ func (d Dir) OpenFile(ctx context.Context, name string, flag int, perm os.FileMo if name = d.resolve(ctx, name); name == "" { return nil, os.ErrNotExist } - if len(d.Config.Deny.File.Create) > 0 { + if len(d.Config.Deny.Create.File) > 0 { // os.O_RDONLY: 0, os.O_RDWR: 2, os.O_CREATE: 512, O_TRUNC: 1024 if flag == os.O_RDWR|os.O_CREATE|os.O_TRUNC || flag == os.O_RDWR|os.O_CREATE || flag == os.O_CREATE|os.O_TRUNC || flag == os.O_CREATE { - for _, v := range d.Config.Deny.File.Create { + for _, v := range d.Config.Deny.Create.File { matched, err := filepath.Match(v, filepath.Base(name)) if err != nil { return nil, err From 09b2d7ca31ef687d13719c30fa30f02b84b5039f Mon Sep 17 00:00:00 2001 From: Simen Strange Date: Fri, 30 Jun 2023 20:43:35 +0200 Subject: [PATCH 6/7] reorganised structs, Deny.{File,Directory}.Create is now Deny.Create.{File,Directory} --- Readme.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index 92d09de..4b98d8a 100644 --- a/Readme.md +++ b/Readme.md @@ -65,12 +65,11 @@ port: "8000" # the listening port dir: "/home/webdav" # the provided base dir prefix: "/webdav" # the url-prefix of the original url deny: # deny your OS to create garbage - file: - create: # deny creation of specified files + create: + file: # deny creation of specified files - .DS_Store - ._* # globbing supported, https://pkg.go.dev/path/filepath#Match - directory: - create: # deny creation of specified directories + directory: # deny creation of specified directories - .Trashes users: user: # with password 'foo' and jailed access to '/home/webdav/user' From 0a321f0d190f51f37b0b7001b59f1d8d44178bae Mon Sep 17 00:00:00 2001 From: Simen Strange Date: Fri, 22 Sep 2023 16:38:45 +0200 Subject: [PATCH 7/7] fixed missing leading whitespaces on directory --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 4b98d8a..57600cf 100644 --- a/Readme.md +++ b/Readme.md @@ -69,7 +69,7 @@ deny: # deny your OS to create garbage file: # deny creation of specified files - .DS_Store - ._* # globbing supported, https://pkg.go.dev/path/filepath#Match - directory: # deny creation of specified directories + directory: # deny creation of specified directories - .Trashes users: user: # with password 'foo' and jailed access to '/home/webdav/user'