mirror of
https://github.com/hacdias/webdav.git
synced 2026-09-22 03:20:41 +08:00
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:
@@ -34,11 +34,11 @@ For usage information regarding the CLI, run `webdav --help`.
|
|||||||
|
|
||||||
### Docker
|
### 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
|
```yaml
|
||||||
port: 6060
|
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.
|
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
|
debug: false
|
||||||
|
|
||||||
# The directory that will be able to be accessed by the users when connecting.
|
# 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).
|
# Default is "." (current directory).
|
||||||
scope: .
|
directory: .
|
||||||
|
|
||||||
# Whether the users can, by default, modify the contents. Default is false.
|
# Whether the users can, by default, modify the contents. Default is false.
|
||||||
modify: true
|
modify: true
|
||||||
@@ -86,10 +86,10 @@ users:
|
|||||||
# Example 'admin' user with plaintext password.
|
# Example 'admin' user with plaintext password.
|
||||||
- username: admin
|
- username: admin
|
||||||
password: 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
|
- username: john
|
||||||
password: "{bcrypt}$2y$10$zEP6oofmXFeHaeMfBNLnP.DO8m.H.Mwhd24/TOX2MWLxAExXi4qgi"
|
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.
|
# Example user whose details will be picked up from the environment.
|
||||||
- username: "{env}ENV_USERNAME"
|
- username: "{env}ENV_USERNAME"
|
||||||
password: "{env}ENV_PASSWORD"
|
password: "{env}ENV_PASSWORD"
|
||||||
|
|||||||
+5
-5
@@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultScope = "."
|
DefaultDirectory = "."
|
||||||
DefaultModify = false
|
DefaultModify = false
|
||||||
DefaultDebug = false
|
DefaultDebug = false
|
||||||
DefaultNoSniff = false
|
DefaultNoSniff = false
|
||||||
@@ -74,7 +74,7 @@ func ParseConfig(filename string, flags *pflag.FlagSet) (*Config, error) {
|
|||||||
// empty or false.
|
// empty or false.
|
||||||
|
|
||||||
// Defaults shared with flags
|
// Defaults shared with flags
|
||||||
v.SetDefault("Scope", DefaultScope)
|
v.SetDefault("Directory", DefaultDirectory)
|
||||||
v.SetDefault("Modify", DefaultModify)
|
v.SetDefault("Modify", DefaultModify)
|
||||||
v.SetDefault("Debug", DefaultDebug)
|
v.SetDefault("Debug", DefaultDebug)
|
||||||
v.SetDefault("NoSniff", DefaultNoSniff)
|
v.SetDefault("NoSniff", DefaultNoSniff)
|
||||||
@@ -111,8 +111,8 @@ func ParseConfig(filename string, flags *pflag.FlagSet) (*Config, error) {
|
|||||||
|
|
||||||
// Cascade user settings
|
// Cascade user settings
|
||||||
for i := range cfg.Users {
|
for i := range cfg.Users {
|
||||||
if !v.IsSet(fmt.Sprintf("Users.%d.Scope", i)) {
|
if !v.IsSet(fmt.Sprintf("Users.%d.Directory", i)) {
|
||||||
cfg.Users[i].Scope = cfg.Scope
|
cfg.Users[i].Directory = cfg.Directory
|
||||||
}
|
}
|
||||||
|
|
||||||
if !v.IsSet(fmt.Sprintf("Users.%d.Modify", i)) {
|
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")
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid config: %w", err)
|
return fmt.Errorf("invalid config: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-14
@@ -36,7 +36,7 @@ func TestConfigDefaults(t *testing.T) {
|
|||||||
|
|
||||||
dir, err := os.Getwd()
|
dir, err := os.Getwd()
|
||||||
require.NoError(t, err)
|
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.AllowedHeaders)
|
||||||
require.EqualValues(t, []string{"*"}, cfg.CORS.AllowedHosts)
|
require.EqualValues(t, []string{"*"}, cfg.CORS.AllowedHosts)
|
||||||
@@ -48,23 +48,23 @@ func TestConfigCascade(t *testing.T) {
|
|||||||
|
|
||||||
check := func(t *testing.T, cfg *Config) {
|
check := func(t *testing.T, cfg *Config) {
|
||||||
require.True(t, cfg.Modify)
|
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.Rules, 1)
|
||||||
|
|
||||||
require.Len(t, cfg.Users, 2)
|
require.Len(t, cfg.Users, 2)
|
||||||
|
|
||||||
require.True(t, cfg.Users[0].Modify)
|
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.Len(t, cfg.Users[0].Rules, 1)
|
||||||
|
|
||||||
require.False(t, cfg.Users[1].Modify)
|
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)
|
require.Len(t, cfg.Users[1].Rules, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("YAML", func(t *testing.T) {
|
t.Run("YAML", func(t *testing.T) {
|
||||||
content := `
|
content := `
|
||||||
scope: /
|
directory: /
|
||||||
modify: true
|
modify: true
|
||||||
rules:
|
rules:
|
||||||
- path: /public/access/
|
- path: /public/access/
|
||||||
@@ -75,7 +75,7 @@ users:
|
|||||||
password: admin
|
password: admin
|
||||||
- username: basic
|
- username: basic
|
||||||
password: basic
|
password: basic
|
||||||
scope: /basic
|
directory: /basic
|
||||||
modify: false
|
modify: false
|
||||||
rules: []`
|
rules: []`
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ users:
|
|||||||
|
|
||||||
t.Run("JSON", func(t *testing.T) {
|
t.Run("JSON", func(t *testing.T) {
|
||||||
content := `{
|
content := `{
|
||||||
"scope": "/",
|
"directory": "/",
|
||||||
"modify": true,
|
"modify": true,
|
||||||
"rules": [
|
"rules": [
|
||||||
{
|
{
|
||||||
@@ -103,7 +103,7 @@ users:
|
|||||||
{
|
{
|
||||||
"username": "basic",
|
"username": "basic",
|
||||||
"password": "basic",
|
"password": "basic",
|
||||||
"scope": "/basic",
|
"directory": "/basic",
|
||||||
"modify": false,
|
"modify": false,
|
||||||
"rules": []
|
"rules": []
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ users:
|
|||||||
|
|
||||||
t.Run("`TOML", func(t *testing.T) {
|
t.Run("`TOML", func(t *testing.T) {
|
||||||
content := `
|
content := `
|
||||||
scope = "/"
|
directory = "/"
|
||||||
modify = true
|
modify = true
|
||||||
|
|
||||||
[[rules]]
|
[[rules]]
|
||||||
@@ -132,7 +132,7 @@ password = "admin"
|
|||||||
[[users]]
|
[[users]]
|
||||||
username = "basic"
|
username = "basic"
|
||||||
password = "basic"
|
password = "basic"
|
||||||
scope = "/basic"
|
directory = "/basic"
|
||||||
modify = false
|
modify = false
|
||||||
rules = []
|
rules = []
|
||||||
`
|
`
|
||||||
@@ -172,7 +172,7 @@ cors:
|
|||||||
|
|
||||||
func TestConfigRules(t *testing.T) {
|
func TestConfigRules(t *testing.T) {
|
||||||
content := `
|
content := `
|
||||||
scope: /
|
directory: /
|
||||||
modify: true
|
modify: true
|
||||||
rules:
|
rules:
|
||||||
- regex: '^.+\.js$'
|
- 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_PORT", "1234"))
|
||||||
require.NoError(t, os.Setenv("WD_DEBUG", "true"))
|
require.NoError(t, os.Setenv("WD_DEBUG", "true"))
|
||||||
require.NoError(t, os.Setenv("WD_MODIFY", "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)
|
cfg, err := ParseConfig("", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1234, cfg.Port)
|
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.Debug)
|
||||||
assert.Equal(t, true, cfg.Modify)
|
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_PORT", ""))
|
||||||
require.NoError(t, os.Setenv("WD_DEBUG", ""))
|
require.NoError(t, os.Setenv("WD_DEBUG", ""))
|
||||||
require.NoError(t, os.Setenv("WD_MODIFY", ""))
|
require.NoError(t, os.Setenv("WD_MODIFY", ""))
|
||||||
require.NoError(t, os.Setenv("WD_SCOPE", ""))
|
require.NoError(t, os.Setenv("WD_DIRECTORY", ""))
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -28,7 +28,7 @@ func NewHandler(c *Config) (http.Handler, error) {
|
|||||||
Handler: webdav.Handler{
|
Handler: webdav.Handler{
|
||||||
Prefix: c.Prefix,
|
Prefix: c.Prefix,
|
||||||
FileSystem: Dir{
|
FileSystem: Dir{
|
||||||
Dir: webdav.Dir(c.Scope),
|
Dir: webdav.Dir(c.Directory),
|
||||||
noSniff: c.NoSniff,
|
noSniff: c.NoSniff,
|
||||||
},
|
},
|
||||||
LockSystem: webdav.NewMemLS(),
|
LockSystem: webdav.NewMemLS(),
|
||||||
@@ -43,7 +43,7 @@ func NewHandler(c *Config) (http.Handler, error) {
|
|||||||
Handler: webdav.Handler{
|
Handler: webdav.Handler{
|
||||||
Prefix: c.Prefix,
|
Prefix: c.Prefix,
|
||||||
FileSystem: Dir{
|
FileSystem: Dir{
|
||||||
Dir: webdav.Dir(u.Scope),
|
Dir: webdav.Dir(u.Directory),
|
||||||
noSniff: c.NoSniff,
|
noSniff: c.NoSniff,
|
||||||
},
|
},
|
||||||
LockSystem: webdav.NewMemLS(),
|
LockSystem: webdav.NewMemLS(),
|
||||||
|
|||||||
+6
-6
@@ -50,7 +50,7 @@ func TestServerDefaults(t *testing.T) {
|
|||||||
"sub/bar.txt": []byte("bar"),
|
"sub/bar.txt": []byte("bar"),
|
||||||
})
|
})
|
||||||
|
|
||||||
srv := makeTestServer(t, "scope: "+dir)
|
srv := makeTestServer(t, "directory: "+dir)
|
||||||
client := gowebdav.NewClient(srv.URL, "", "")
|
client := gowebdav.NewClient(srv.URL, "", "")
|
||||||
|
|
||||||
// By default, reading permissions.
|
// By default, reading permissions.
|
||||||
@@ -90,7 +90,7 @@ func TestServerAuthentication(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
srv := makeTestServer(t, fmt.Sprintf(`
|
srv := makeTestServer(t, fmt.Sprintf(`
|
||||||
scope: %s
|
directory: %s
|
||||||
modify: true
|
modify: true
|
||||||
|
|
||||||
users:
|
users:
|
||||||
@@ -152,7 +152,7 @@ func TestServerRules(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
srv := makeTestServer(t, fmt.Sprintf(`
|
srv := makeTestServer(t, fmt.Sprintf(`
|
||||||
scope: %s
|
directory: %s
|
||||||
modify: true
|
modify: true
|
||||||
|
|
||||||
users:
|
users:
|
||||||
@@ -194,16 +194,16 @@ func TestServerPermissions(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
srv := makeTestServer(t, fmt.Sprintf(`
|
srv := makeTestServer(t, fmt.Sprintf(`
|
||||||
scope: %s
|
directory: %s
|
||||||
modify: true
|
modify: true
|
||||||
|
|
||||||
users:
|
users:
|
||||||
- username: a
|
- username: a
|
||||||
password: a
|
password: a
|
||||||
scope: %s/a
|
directory: %s/a
|
||||||
- username: b
|
- username: b
|
||||||
password: b
|
password: b
|
||||||
scope: %s/b
|
directory: %s/b
|
||||||
modify: false
|
modify: false
|
||||||
`, dir, dir, dir))
|
`, dir, dir, dir))
|
||||||
|
|
||||||
|
|||||||
+11
-3
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -40,9 +41,9 @@ func (r *Rule) Matches(path string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Permissions struct {
|
type Permissions struct {
|
||||||
Scope string
|
Directory string
|
||||||
Modify bool
|
Modify bool
|
||||||
Rules []*Rule
|
Rules []*Rule
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allowed checks if the user has permission to access a directory/file
|
// 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 {
|
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 {
|
for _, r := range p.Rules {
|
||||||
if err := r.Validate(); err != nil {
|
if err := r.Validate(); err != nil {
|
||||||
return fmt.Errorf("invalid permissions: %w", err)
|
return fmt.Errorf("invalid permissions: %w", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user