feat!: rename 'scope' to 'directory'

Directory makes it more clear of what it is. In addition, this will make it easier when
allowing for multiple directories in the future, since we can just name it 'directories', which is more clear than 'scopes'.
This commit is contained in:
Henrique Dias
2024-07-29 10:11:02 +02:00
parent a255fb51e2
commit d5e5052f63
6 changed files with 44 additions and 36 deletions
+6 -6
View File
@@ -34,11 +34,11 @@ For usage information regarding the CLI, run `webdav --help`.
### Docker
To use with Docker, you need to provide a configuration file and mount the data directories. For example, let's take the following configuration file that simply sets the port to `6060` and the scope to `/data`.
To use with Docker, you need to provide a configuration file and mount the data directories. For example, let's take the following configuration file that simply sets the port to `6060` and the directory to `/data`.
```yaml
port: 6060
scope: /data
directory: /data
```
You can now run with the following Docker command, where you mount the configuration file inside the container, and the data directory too, as well as forwarding the port 6060. You will need to change this to match your own configuration.
@@ -71,9 +71,9 @@ prefix: /
debug: false
# The directory that will be able to be accessed by the users when connecting.
# This directory will be used by users unless they have their own 'scope' defined.
# This directory will be used by users unless they have their own 'directory' defined.
# Default is "." (current directory).
scope: .
directory: .
# Whether the users can, by default, modify the contents. Default is false.
modify: true
@@ -86,10 +86,10 @@ users:
# Example 'admin' user with plaintext password.
- username: admin
password: admin
# Example 'john' user with bcrypt encrypted password, with custom scope.
# Example 'john' user with bcrypt encrypted password, with custom directory.
- username: john
password: "{bcrypt}$2y$10$zEP6oofmXFeHaeMfBNLnP.DO8m.H.Mwhd24/TOX2MWLxAExXi4qgi"
scope: /another/path
directory: /another/path
# Example user whose details will be picked up from the environment.
- username: "{env}ENV_USERNAME"
password: "{env}ENV_PASSWORD"
+5 -5
View File
@@ -13,7 +13,7 @@ import (
)
const (
DefaultScope = "."
DefaultDirectory = "."
DefaultModify = false
DefaultDebug = false
DefaultNoSniff = false
@@ -74,7 +74,7 @@ func ParseConfig(filename string, flags *pflag.FlagSet) (*Config, error) {
// empty or false.
// Defaults shared with flags
v.SetDefault("Scope", DefaultScope)
v.SetDefault("Directory", DefaultDirectory)
v.SetDefault("Modify", DefaultModify)
v.SetDefault("Debug", DefaultDebug)
v.SetDefault("NoSniff", DefaultNoSniff)
@@ -111,8 +111,8 @@ func ParseConfig(filename string, flags *pflag.FlagSet) (*Config, error) {
// Cascade user settings
for i := range cfg.Users {
if !v.IsSet(fmt.Sprintf("Users.%d.Scope", i)) {
cfg.Users[i].Scope = cfg.Scope
if !v.IsSet(fmt.Sprintf("Users.%d.Directory", i)) {
cfg.Users[i].Directory = cfg.Directory
}
if !v.IsSet(fmt.Sprintf("Users.%d.Modify", i)) {
@@ -139,7 +139,7 @@ func (c *Config) Validate() error {
zap.L().Warn("unprotected config: no users have been set, so no authentication will be used")
}
c.Scope, err = filepath.Abs(c.Scope)
c.Directory, err = filepath.Abs(c.Directory)
if err != nil {
return fmt.Errorf("invalid config: %w", err)
}
+14 -14
View File
@@ -36,7 +36,7 @@ func TestConfigDefaults(t *testing.T) {
dir, err := os.Getwd()
require.NoError(t, err)
require.Equal(t, dir, cfg.Scope)
require.Equal(t, dir, cfg.Directory)
require.EqualValues(t, []string{"*"}, cfg.CORS.AllowedHeaders)
require.EqualValues(t, []string{"*"}, cfg.CORS.AllowedHosts)
@@ -48,23 +48,23 @@ func TestConfigCascade(t *testing.T) {
check := func(t *testing.T, cfg *Config) {
require.True(t, cfg.Modify)
require.Equal(t, "/", cfg.Scope)
require.Equal(t, "/", cfg.Directory)
require.Len(t, cfg.Rules, 1)
require.Len(t, cfg.Users, 2)
require.True(t, cfg.Users[0].Modify)
require.Equal(t, "/", cfg.Users[0].Scope)
require.Equal(t, "/", cfg.Users[0].Directory)
require.Len(t, cfg.Users[0].Rules, 1)
require.False(t, cfg.Users[1].Modify)
require.Equal(t, "/basic", cfg.Users[1].Scope)
require.Equal(t, "/basic", cfg.Users[1].Directory)
require.Len(t, cfg.Users[1].Rules, 0)
}
t.Run("YAML", func(t *testing.T) {
content := `
scope: /
directory: /
modify: true
rules:
- path: /public/access/
@@ -75,7 +75,7 @@ users:
password: admin
- username: basic
password: basic
scope: /basic
directory: /basic
modify: false
rules: []`
@@ -87,7 +87,7 @@ users:
t.Run("JSON", func(t *testing.T) {
content := `{
"scope": "/",
"directory": "/",
"modify": true,
"rules": [
{
@@ -103,7 +103,7 @@ users:
{
"username": "basic",
"password": "basic",
"scope": "/basic",
"directory": "/basic",
"modify": false,
"rules": []
}
@@ -118,7 +118,7 @@ users:
t.Run("`TOML", func(t *testing.T) {
content := `
scope = "/"
directory = "/"
modify = true
[[rules]]
@@ -132,7 +132,7 @@ password = "admin"
[[users]]
username = "basic"
password = "basic"
scope = "/basic"
directory = "/basic"
modify = false
rules = []
`
@@ -172,7 +172,7 @@ cors:
func TestConfigRules(t *testing.T) {
content := `
scope: /
directory: /
modify: true
rules:
- regex: '^.+\.js$'
@@ -198,13 +198,13 @@ func TestConfigEnv(t *testing.T) {
require.NoError(t, os.Setenv("WD_PORT", "1234"))
require.NoError(t, os.Setenv("WD_DEBUG", "true"))
require.NoError(t, os.Setenv("WD_MODIFY", "true"))
require.NoError(t, os.Setenv("WD_SCOPE", "/test"))
require.NoError(t, os.Setenv("WD_DIRECTORY", "/test"))
cfg, err := ParseConfig("", nil)
require.NoError(t, err)
assert.Equal(t, 1234, cfg.Port)
assert.Equal(t, "/test", cfg.Scope)
assert.Equal(t, "/test", cfg.Directory)
assert.Equal(t, true, cfg.Debug)
assert.Equal(t, true, cfg.Modify)
@@ -212,5 +212,5 @@ func TestConfigEnv(t *testing.T) {
require.NoError(t, os.Setenv("WD_PORT", ""))
require.NoError(t, os.Setenv("WD_DEBUG", ""))
require.NoError(t, os.Setenv("WD_MODIFY", ""))
require.NoError(t, os.Setenv("WD_SCOPE", ""))
require.NoError(t, os.Setenv("WD_DIRECTORY", ""))
}
+2 -2
View File
@@ -28,7 +28,7 @@ func NewHandler(c *Config) (http.Handler, error) {
Handler: webdav.Handler{
Prefix: c.Prefix,
FileSystem: Dir{
Dir: webdav.Dir(c.Scope),
Dir: webdav.Dir(c.Directory),
noSniff: c.NoSniff,
},
LockSystem: webdav.NewMemLS(),
@@ -43,7 +43,7 @@ func NewHandler(c *Config) (http.Handler, error) {
Handler: webdav.Handler{
Prefix: c.Prefix,
FileSystem: Dir{
Dir: webdav.Dir(u.Scope),
Dir: webdav.Dir(u.Directory),
noSniff: c.NoSniff,
},
LockSystem: webdav.NewMemLS(),
+6 -6
View File
@@ -50,7 +50,7 @@ func TestServerDefaults(t *testing.T) {
"sub/bar.txt": []byte("bar"),
})
srv := makeTestServer(t, "scope: "+dir)
srv := makeTestServer(t, "directory: "+dir)
client := gowebdav.NewClient(srv.URL, "", "")
// By default, reading permissions.
@@ -90,7 +90,7 @@ func TestServerAuthentication(t *testing.T) {
})
srv := makeTestServer(t, fmt.Sprintf(`
scope: %s
directory: %s
modify: true
users:
@@ -152,7 +152,7 @@ func TestServerRules(t *testing.T) {
})
srv := makeTestServer(t, fmt.Sprintf(`
scope: %s
directory: %s
modify: true
users:
@@ -194,16 +194,16 @@ func TestServerPermissions(t *testing.T) {
})
srv := makeTestServer(t, fmt.Sprintf(`
scope: %s
directory: %s
modify: true
users:
- username: a
password: a
scope: %s/a
directory: %s/a
- username: b
password: b
scope: %s/b
directory: %s/b
modify: false
`, dir, dir, dir))
+11 -3
View File
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"net/http"
"path/filepath"
"regexp"
"strings"
)
@@ -40,9 +41,9 @@ func (r *Rule) Matches(path string) bool {
}
type Permissions struct {
Scope string
Modify bool
Rules []*Rule
Directory string
Modify bool
Rules []*Rule
}
// Allowed checks if the user has permission to access a directory/file
@@ -69,6 +70,13 @@ func (p Permissions) Allowed(r *http.Request) bool {
}
func (p *Permissions) Validate() error {
var err error
p.Directory, err = filepath.Abs(p.Directory)
if err != nil {
return fmt.Errorf("invalid permissions: %w", err)
}
for _, r := range p.Rules {
if err := r.Validate(); err != nil {
return fmt.Errorf("invalid permissions: %w", err)