add hide policy to pattern filters

Disallowed files/dirs can be completly hidden. This may cause performance
issues for large directories

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino
2022-01-15 17:16:49 +01:00
parent 9b6b9cca3d
commit c3831de94e
20 changed files with 358 additions and 139 deletions

View File

@@ -92,7 +92,7 @@ func createUserDir(w http.ResponseWriter, r *http.Request) {
return
}
}
err = connection.CreateDir(name)
err = connection.CreateDir(name, true)
if err != nil {
sendAPIResponse(w, r, err, fmt.Sprintf("Unable to create directory %#v", name), getMappedStatusCode(err))
return

View File

@@ -66,7 +66,7 @@ func (c *Connection) Stat(name string, mode int) (os.FileInfo, error) {
return nil, c.GetPermissionDeniedError()
}
fi, err := c.DoStat(name, mode)
fi, err := c.DoStat(name, mode, true)
if err != nil {
return nil, err
}
@@ -89,9 +89,9 @@ func (c *Connection) getFileReader(name string, offset int64, method string) (io
return nil, c.GetPermissionDeniedError()
}
if !c.User.IsFileAllowed(name) {
if ok, policy := c.User.IsFileAllowed(name); !ok {
c.Log(logger.LevelWarn, "reading file %#v is not allowed", name)
return nil, c.GetPermissionDeniedError()
return nil, c.GetErrorForDeniedFile(policy)
}
fs, p, err := c.GetFsAndResolvedPath(name)
@@ -120,7 +120,7 @@ func (c *Connection) getFileReader(name string, offset int64, method string) (io
func (c *Connection) getFileWriter(name string) (io.WriteCloser, error) {
c.UpdateLastActivity()
if !c.User.IsFileAllowed(name) {
if ok, _ := c.User.IsFileAllowed(name); !ok {
c.Log(logger.LevelWarn, "writing file %#v is not allowed", name)
return nil, c.GetPermissionDeniedError()
}

View File

@@ -1482,6 +1482,15 @@ func TestAddUserInvalidFilters(t *testing.T) {
}
_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
assert.NoError(t, err)
u.Filters.FilePatterns = []sdk.PatternsFilter{
{
Path: "/subdir",
AllowedPatterns: []string{"*.*"},
DenyPolicy: 100,
},
}
_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
assert.NoError(t, err)
u.Filters.DeniedProtocols = []string{"invalid"}
_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
assert.NoError(t, err)
@@ -2087,6 +2096,7 @@ func TestUpdateUser(t *testing.T) {
Path: "/subdir",
AllowedPatterns: []string{"*.zip", "*.rar"},
DeniedPatterns: []string{"*.jpg", "*.png"},
DenyPolicy: sdk.DenyPolicyHide,
})
user.Filters.MaxUploadFileSize = 4096
user.UploadBandwidth = 1024
@@ -13061,6 +13071,7 @@ func TestWebUserAddMock(t *testing.T) {
form.Set("pattern_path0", "/dir2")
form.Set("patterns0", "*.jpg,*.png")
form.Set("pattern_type0", "allowed")
form.Set("pattern_policy0", "1")
form.Set("pattern_path1", "/dir1")
form.Set("patterns1", "*.png")
form.Set("pattern_type1", "allowed")
@@ -13294,23 +13305,25 @@ func TestWebUserAddMock(t *testing.T) {
}
assert.Len(t, newUser.Filters.FilePatterns, 3)
for _, filter := range newUser.Filters.FilePatterns {
if filter.Path == "/dir1" {
switch filter.Path {
case "/dir1":
assert.Len(t, filter.DeniedPatterns, 1)
assert.Len(t, filter.AllowedPatterns, 1)
assert.True(t, util.IsStringInSlice("*.png", filter.AllowedPatterns))
assert.True(t, util.IsStringInSlice("*.zip", filter.DeniedPatterns))
}
if filter.Path == "/dir2" {
assert.Equal(t, sdk.DenyPolicyDefault, filter.DenyPolicy)
case "/dir2":
assert.Len(t, filter.DeniedPatterns, 1)
assert.Len(t, filter.AllowedPatterns, 2)
assert.True(t, util.IsStringInSlice("*.jpg", filter.AllowedPatterns))
assert.True(t, util.IsStringInSlice("*.png", filter.AllowedPatterns))
assert.True(t, util.IsStringInSlice("*.mkv", filter.DeniedPatterns))
}
if filter.Path == "/dir3" {
assert.Equal(t, sdk.DenyPolicyHide, filter.DenyPolicy)
case "/dir3":
assert.Len(t, filter.DeniedPatterns, 1)
assert.Len(t, filter.AllowedPatterns, 0)
assert.True(t, util.IsStringInSlice("*.rar", filter.DeniedPatterns))
assert.Equal(t, sdk.DenyPolicyDefault, filter.DenyPolicy)
}
}
if assert.Len(t, newUser.Filters.BandwidthLimits, 2) {
@@ -14140,9 +14153,11 @@ func TestWebUserS3Mock(t *testing.T) {
form.Set("pattern_path0", "/dir1")
form.Set("patterns0", "*.jpg,*.png")
form.Set("pattern_type0", "allowed")
form.Set("pattern_policy0", "0")
form.Set("pattern_path1", "/dir2")
form.Set("patterns1", "*.zip")
form.Set("pattern_type1", "denied")
form.Set("pattern_policy1", "1")
form.Set("max_upload_file_size", "0")
form.Set("s3_force_path_style", "checked")
form.Set("description", user.Description)
@@ -14221,7 +14236,16 @@ func TestWebUserS3Mock(t *testing.T) {
assert.Equal(t, updateUser.FsConfig.S3Config.DownloadPartSize, user.FsConfig.S3Config.DownloadPartSize)
assert.Equal(t, updateUser.FsConfig.S3Config.DownloadConcurrency, user.FsConfig.S3Config.DownloadConcurrency)
assert.True(t, updateUser.FsConfig.S3Config.ForcePathStyle)
assert.Equal(t, 2, len(updateUser.Filters.FilePatterns))
if assert.Equal(t, 2, len(updateUser.Filters.FilePatterns)) {
for _, filter := range updateUser.Filters.FilePatterns {
switch filter.Path {
case "/dir1":
assert.Equal(t, sdk.DenyPolicyDefault, filter.DenyPolicy)
case "/dir2":
assert.Equal(t, sdk.DenyPolicyHide, filter.DenyPolicy)
}
}
}
assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.S3Config.AccessSecret.GetStatus())
assert.NotEmpty(t, updateUser.FsConfig.S3Config.AccessSecret.GetPayload())
assert.Empty(t, updateUser.FsConfig.S3Config.AccessSecret.GetKey())

View File

@@ -797,11 +797,20 @@ func getBandwidthLimitsFromPostFields(r *http.Request) ([]sdk.BandwidthLimit, er
return result, nil
}
func getPatterDenyPolicyFromString(policy string) int {
denyPolicy := sdk.DenyPolicyDefault
if policy == "1" {
denyPolicy = sdk.DenyPolicyHide
}
return denyPolicy
}
func getFilePatternsFromPostField(r *http.Request) []sdk.PatternsFilter {
var result []sdk.PatternsFilter
allowedPatterns := make(map[string][]string)
deniedPatterns := make(map[string][]string)
patternPolicies := make(map[string]string)
for k := range r.Form {
if strings.HasPrefix(k, "pattern_path") {
@@ -810,12 +819,16 @@ func getFilePatternsFromPostField(r *http.Request) []sdk.PatternsFilter {
filters := strings.TrimSpace(r.Form.Get(fmt.Sprintf("patterns%v", idx)))
filters = strings.ReplaceAll(filters, " ", "")
patternType := r.Form.Get(fmt.Sprintf("pattern_type%v", idx))
patternPolicy := r.Form.Get(fmt.Sprintf("pattern_policy%v", idx))
if p != "" && filters != "" {
if patternType == "allowed" {
allowedPatterns[p] = append(allowedPatterns[p], strings.Split(filters, ",")...)
} else {
deniedPatterns[p] = append(deniedPatterns[p], strings.Split(filters, ",")...)
}
if patternPolicy != "" && patternPolicy != "0" {
patternPolicies[p] = patternPolicy
}
}
}
}
@@ -823,11 +836,12 @@ func getFilePatternsFromPostField(r *http.Request) []sdk.PatternsFilter {
for dirAllowed, allowPatterns := range allowedPatterns {
filter := sdk.PatternsFilter{
Path: dirAllowed,
AllowedPatterns: util.RemoveDuplicates(allowPatterns),
AllowedPatterns: allowPatterns,
DenyPolicy: getPatterDenyPolicyFromString(patternPolicies[dirAllowed]),
}
for dirDenied, denPatterns := range deniedPatterns {
if dirAllowed == dirDenied {
filter.DeniedPatterns = util.RemoveDuplicates(denPatterns)
filter.DeniedPatterns = denPatterns
break
}
}
@@ -845,6 +859,7 @@ func getFilePatternsFromPostField(r *http.Request) []sdk.PatternsFilter {
result = append(result, sdk.PatternsFilter{
Path: dirDenied,
DeniedPatterns: denPatterns,
DenyPolicy: getPatterDenyPolicyFromString(patternPolicies[dirDenied]),
})
}
}