Make user subdirs optional to allow admin access to the whole directory

This commit is contained in:
Christian Claus 2018-04-11 16:19:00 +02:00
parent 6bd8f49b70
commit 07a719c03c
3 changed files with 30 additions and 24 deletions

View file

@ -28,6 +28,7 @@ type TLS struct {
// UserInfo allows storing of a password and user directory. // UserInfo allows storing of a password and user directory.
type UserInfo struct { type UserInfo struct {
Password string Password string
Subdir *string
} }
// ParseConfig parses the application configuration an sets defaults. // ParseConfig parses the application configuration an sets defaults.
@ -116,11 +117,13 @@ func (cfg *Config) ensureUserDirs() {
fmt.Printf("Created base dir: %s\n", cfg.Dir) fmt.Printf("Created base dir: %s\n", cfg.Dir)
} }
for username := range cfg.Users { for _, user := range cfg.Users {
path := filepath.Join(cfg.Dir, username) if user.Subdir != nil {
if _, err := os.Stat(path); os.IsNotExist(err) { path := filepath.Join(cfg.Dir, *user.Subdir)
os.Mkdir(path, os.ModePerm) if _, err := os.Stat(path); os.IsNotExist(err) {
fmt.Printf("Created user dir: %s\n", path) os.Mkdir(path, os.ModePerm)
fmt.Printf("Created user dir: %s\n", path)
}
} }
} }
} }

View file

@ -12,36 +12,39 @@ import (
// This file is an extension of golang.org/x/net/webdav/file.go. // This file is an extension of golang.org/x/net/webdav/file.go.
// UserDir is specialization of webdav.Dir with respect of an authenticated // Dir is specialization of webdav.Dir with respect of an authenticated
// user to allow synthetic user directories // user to allow configuration access.
type UserDir struct { type Dir struct {
BaseDir string Config *Config
} }
// resolve tries to gain authentication information and suffixes the BaseDir with the // resolve tries to gain authentication information and suffixes the BaseDir with the
// username of the authentication information. If none authentication information can // username of the authentication information. If none authentication information can
// achieved during the process, the BaseDir is used // achieved during the process, the BaseDir is used
func (d UserDir) resolve(ctx context.Context, name string) string { func (d Dir) resolve(ctx context.Context, name string) string {
// This implementation is based on Dir.Open's code in the standard net/http package. // This implementation is based on Dir.Open's code in the standard net/http package.
if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 || if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
strings.Contains(name, "\x00") { strings.Contains(name, "\x00") {
return "" return ""
} }
dir := string(d.BaseDir) dir := string(d.Config.Dir)
if dir == "" { if dir == "" {
dir = "." dir = "."
} }
authInfo := auth.FromContext(ctx) authInfo := auth.FromContext(ctx)
if authInfo == nil || !authInfo.Authenticated { if authInfo != nil && authInfo.Authenticated {
return filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))) userInfo := d.Config.Users[authInfo.Username]
if userInfo != nil && userInfo.Subdir != nil {
return filepath.Join(dir, authInfo.Username, filepath.FromSlash(path.Clean("/"+name)))
}
} }
return filepath.Join(dir, authInfo.Username, filepath.FromSlash(path.Clean("/"+name))) return filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
} }
// Mkdir resolves the physical file and delegates this to an os.Mkdir execution // Mkdir resolves the physical file and delegates this to an os.Mkdir execution
func (d UserDir) Mkdir(ctx context.Context, name string, perm os.FileMode) error { func (d Dir) Mkdir(ctx context.Context, name string, perm os.FileMode) error {
if name = d.resolve(ctx, name); name == "" { if name = d.resolve(ctx, name); name == "" {
return os.ErrNotExist return os.ErrNotExist
} }
@ -49,7 +52,7 @@ func (d UserDir) Mkdir(ctx context.Context, name string, perm os.FileMode) error
} }
// OpenFile resolves the physical file and delegates this to an os.OpenFile execution // OpenFile resolves the physical file and delegates this to an os.OpenFile execution
func (d UserDir) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) { func (d Dir) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) {
if name = d.resolve(ctx, name); name == "" { if name = d.resolve(ctx, name); name == "" {
return nil, os.ErrNotExist return nil, os.ErrNotExist
} }
@ -61,11 +64,11 @@ func (d UserDir) OpenFile(ctx context.Context, name string, flag int, perm os.Fi
} }
// RemoveAll resolves the physical file and delegates this to an os.RemoveAll execution // RemoveAll resolves the physical file and delegates this to an os.RemoveAll execution
func (d UserDir) RemoveAll(ctx context.Context, name string) error { func (d Dir) RemoveAll(ctx context.Context, name string) error {
if name = d.resolve(ctx, name); name == "" { if name = d.resolve(ctx, name); name == "" {
return os.ErrNotExist return os.ErrNotExist
} }
if name == filepath.Clean(string(d.BaseDir)) { if name == filepath.Clean(string(d.Config.Dir)) {
// Prohibit removing the virtual root directory. // Prohibit removing the virtual root directory.
return os.ErrInvalid return os.ErrInvalid
} }
@ -73,14 +76,14 @@ func (d UserDir) RemoveAll(ctx context.Context, name string) error {
} }
// Rename resolves the physical file and delegates this to an os.Rename execution // Rename resolves the physical file and delegates this to an os.Rename execution
func (d UserDir) Rename(ctx context.Context, oldName, newName string) error { func (d Dir) Rename(ctx context.Context, oldName, newName string) error {
if oldName = d.resolve(ctx, oldName); oldName == "" { if oldName = d.resolve(ctx, oldName); oldName == "" {
return os.ErrNotExist return os.ErrNotExist
} }
if newName = d.resolve(ctx, newName); newName == "" { if newName = d.resolve(ctx, newName); newName == "" {
return os.ErrNotExist return os.ErrNotExist
} }
if root := filepath.Clean(string(d.BaseDir)); root == oldName || root == newName { if root := filepath.Clean(string(d.Config.Dir)); root == oldName || root == newName {
// Prohibit renaming from or to the virtual root directory. // Prohibit renaming from or to the virtual root directory.
return os.ErrInvalid return os.ErrInvalid
} }
@ -88,7 +91,7 @@ func (d UserDir) Rename(ctx context.Context, oldName, newName string) error {
} }
// Stat resolves the physical file and delegates this to an os.Stat execution // Stat resolves the physical file and delegates this to an os.Stat execution
func (d UserDir) Stat(ctx context.Context, name string) (os.FileInfo, error) { func (d Dir) Stat(ctx context.Context, name string) (os.FileInfo, error) {
if name = d.resolve(ctx, name); name == "" { if name = d.resolve(ctx, name); name == "" {
return nil, os.ErrNotExist return nil, os.ErrNotExist
} }

View file

@ -13,13 +13,13 @@ func main() {
wdHandler := &webdav.Handler{ wdHandler := &webdav.Handler{
Prefix: config.Prefix, Prefix: config.Prefix,
FileSystem: &app.UserDir{ FileSystem: &app.Dir{
BaseDir: config.Dir, Config: config,
}, },
LockSystem: webdav.NewMemLS(), LockSystem: webdav.NewMemLS(),
} }
wdHandler.Logger = app.ModificationLogHandler //wdHandler.Logger = app.ModificationLogHandler
a := &app.App{ a := &app.App{
Config: config, Config: config,