eventmanager: allow to filter based on role name
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
2ea43647ed
commit
221a4878aa
8 changed files with 270 additions and 78 deletions
|
@ -262,6 +262,9 @@ func (r *eventRulesContainer) checkProviderEventMatch(conditions dataprovider.Ev
|
||||||
if !checkEventConditionPatterns(params.Name, conditions.Options.Names) {
|
if !checkEventConditionPatterns(params.Name, conditions.Options.Names) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if !checkEventConditionPatterns(params.Role, conditions.Options.RoleNames) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if len(conditions.Options.ProviderObjects) > 0 && !util.Contains(conditions.Options.ProviderObjects, params.ObjectType) {
|
if len(conditions.Options.ProviderObjects) > 0 && !util.Contains(conditions.Options.ProviderObjects, params.ObjectType) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -275,6 +278,9 @@ func (r *eventRulesContainer) checkFsEventMatch(conditions dataprovider.EventCon
|
||||||
if !checkEventConditionPatterns(params.Name, conditions.Options.Names) {
|
if !checkEventConditionPatterns(params.Name, conditions.Options.Names) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if !checkEventConditionPatterns(params.Role, conditions.Options.RoleNames) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if !checkEventGroupConditionPatters(params.Groups, conditions.Options.GroupNames) {
|
if !checkEventGroupConditionPatters(params.Groups, conditions.Options.GroupNames) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -919,6 +925,19 @@ func checkEventConditionPattern(p dataprovider.ConditionPattern, name string) bo
|
||||||
return matched
|
return matched
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkUserConditionOptions(user *dataprovider.User, conditions *dataprovider.ConditionOptions) bool {
|
||||||
|
if !checkEventConditionPatterns(user.Username, conditions.Names) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !checkEventConditionPatterns(user.Role, conditions.RoleNames) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !checkEventGroupConditionPatters(user.Groups, conditions.GroupNames) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// checkConditionPatterns returns false if patterns are defined and no match is found
|
// checkConditionPatterns returns false if patterns are defined and no match is found
|
||||||
func checkEventConditionPatterns(name string, patterns []dataprovider.ConditionPattern) bool {
|
func checkEventConditionPatterns(name string, patterns []dataprovider.ConditionPattern) bool {
|
||||||
if len(patterns) == 0 {
|
if len(patterns) == 0 {
|
||||||
|
@ -1302,13 +1321,8 @@ func executeDeleteFsRuleAction(deletes []string, replacer *strings.Replacer,
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
// if sender is set, the conditions have already been evaluated
|
// if sender is set, the conditions have already been evaluated
|
||||||
if params.sender == "" {
|
if params.sender == "" {
|
||||||
if !checkEventConditionPatterns(user.Username, conditions.Names) {
|
if !checkUserConditionOptions(&user, &conditions) {
|
||||||
eventManagerLog(logger.LevelDebug, "skipping fs delete for user %s, name conditions don't match",
|
eventManagerLog(logger.LevelDebug, "skipping fs delete for user %s, condition options don't match",
|
||||||
user.Username)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !checkEventGroupConditionPatters(user.Groups, conditions.GroupNames) {
|
|
||||||
eventManagerLog(logger.LevelDebug, "skipping fs delete for user %s, group name conditions don't match",
|
|
||||||
user.Username)
|
user.Username)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1366,13 +1380,8 @@ func executeMkdirFsRuleAction(dirs []string, replacer *strings.Replacer,
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
// if sender is set, the conditions have already been evaluated
|
// if sender is set, the conditions have already been evaluated
|
||||||
if params.sender == "" {
|
if params.sender == "" {
|
||||||
if !checkEventConditionPatterns(user.Username, conditions.Names) {
|
if !checkUserConditionOptions(&user, &conditions) {
|
||||||
eventManagerLog(logger.LevelDebug, "skipping fs mkdir for user %s, name conditions don't match",
|
eventManagerLog(logger.LevelDebug, "skipping fs mkdir for user %s, condition options don't match",
|
||||||
user.Username)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !checkEventGroupConditionPatters(user.Groups, conditions.GroupNames) {
|
|
||||||
eventManagerLog(logger.LevelDebug, "skipping fs mkdir for user %s, group name conditions don't match",
|
|
||||||
user.Username)
|
user.Username)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1453,13 +1462,8 @@ func executeRenameFsRuleAction(renames []dataprovider.KeyValue, replacer *string
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
// if sender is set, the conditions have already been evaluated
|
// if sender is set, the conditions have already been evaluated
|
||||||
if params.sender == "" {
|
if params.sender == "" {
|
||||||
if !checkEventConditionPatterns(user.Username, conditions.Names) {
|
if !checkUserConditionOptions(&user, &conditions) {
|
||||||
eventManagerLog(logger.LevelDebug, "skipping fs rename for user %s, name conditions don't match",
|
eventManagerLog(logger.LevelDebug, "skipping fs rename for user %s, condition options don't match",
|
||||||
user.Username)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !checkEventGroupConditionPatters(user.Groups, conditions.GroupNames) {
|
|
||||||
eventManagerLog(logger.LevelDebug, "skipping fs rename for user %s, group name conditions don't match",
|
|
||||||
user.Username)
|
user.Username)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1559,13 +1563,8 @@ func executeExistFsRuleAction(exist []string, replacer *strings.Replacer, condit
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
// if sender is set, the conditions have already been evaluated
|
// if sender is set, the conditions have already been evaluated
|
||||||
if params.sender == "" {
|
if params.sender == "" {
|
||||||
if !checkEventConditionPatterns(user.Username, conditions.Names) {
|
if !checkUserConditionOptions(&user, &conditions) {
|
||||||
eventManagerLog(logger.LevelDebug, "skipping fs exist for user %s, name conditions don't match",
|
eventManagerLog(logger.LevelDebug, "skipping fs exist for user %s, condition options don't match",
|
||||||
user.Username)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !checkEventGroupConditionPatters(user.Groups, conditions.GroupNames) {
|
|
||||||
eventManagerLog(logger.LevelDebug, "skipping fs exist for user %s, group name conditions don't match",
|
|
||||||
user.Username)
|
user.Username)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1599,13 +1598,8 @@ func executeCompressFsRuleAction(c dataprovider.EventActionFsCompress, replacer
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
// if sender is set, the conditions have already been evaluated
|
// if sender is set, the conditions have already been evaluated
|
||||||
if params.sender == "" {
|
if params.sender == "" {
|
||||||
if !checkEventConditionPatterns(user.Username, conditions.Names) {
|
if !checkUserConditionOptions(&user, &conditions) {
|
||||||
eventManagerLog(logger.LevelDebug, "skipping fs compress for user %s, name conditions don't match",
|
eventManagerLog(logger.LevelDebug, "skipping fs compress for user %s, condition options don't match",
|
||||||
user.Username)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !checkEventGroupConditionPatters(user.Groups, conditions.GroupNames) {
|
|
||||||
eventManagerLog(logger.LevelDebug, "skipping fs compress for user %s, group name conditions don't match",
|
|
||||||
user.Username)
|
user.Username)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1684,13 +1678,8 @@ func executeUsersQuotaResetRuleAction(conditions dataprovider.ConditionOptions,
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
// if sender is set, the conditions have already been evaluated
|
// if sender is set, the conditions have already been evaluated
|
||||||
if params.sender == "" {
|
if params.sender == "" {
|
||||||
if !checkEventConditionPatterns(user.Username, conditions.Names) {
|
if !checkUserConditionOptions(&user, &conditions) {
|
||||||
eventManagerLog(logger.LevelDebug, "skipping quota reset for user %q, name conditions don't match",
|
eventManagerLog(logger.LevelDebug, "skipping quota reset for user %q, condition options don't match",
|
||||||
user.Username)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !checkEventGroupConditionPatters(user.Groups, conditions.GroupNames) {
|
|
||||||
eventManagerLog(logger.LevelDebug, "skipping quota reset for user %q, group name conditions don't match",
|
|
||||||
user.Username)
|
user.Username)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1772,13 +1761,8 @@ func executeTransferQuotaResetRuleAction(conditions dataprovider.ConditionOption
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
// if sender is set, the conditions have already been evaluated
|
// if sender is set, the conditions have already been evaluated
|
||||||
if params.sender == "" {
|
if params.sender == "" {
|
||||||
if !checkEventConditionPatterns(user.Username, conditions.Names) {
|
if !checkUserConditionOptions(&user, &conditions) {
|
||||||
eventManagerLog(logger.LevelDebug, "skipping scheduled transfer quota reset for user %s, name conditions don't match",
|
eventManagerLog(logger.LevelDebug, "skipping scheduled transfer quota reset for user %s, condition options don't match",
|
||||||
user.Username)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !checkEventGroupConditionPatters(user.Groups, conditions.GroupNames) {
|
|
||||||
eventManagerLog(logger.LevelDebug, "skipping scheduled transfer quota reset for user %s, group name conditions don't match",
|
|
||||||
user.Username)
|
user.Username)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1843,13 +1827,8 @@ func executeDataRetentionCheckRuleAction(config dataprovider.EventActionDataRete
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
// if sender is set, the conditions have already been evaluated
|
// if sender is set, the conditions have already been evaluated
|
||||||
if params.sender == "" {
|
if params.sender == "" {
|
||||||
if !checkEventConditionPatterns(user.Username, conditions.Names) {
|
if !checkUserConditionOptions(&user, &conditions) {
|
||||||
eventManagerLog(logger.LevelDebug, "skipping scheduled retention check for user %s, name conditions don't match",
|
eventManagerLog(logger.LevelDebug, "skipping scheduled retention check for user %s, condition options don't match",
|
||||||
user.Username)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !checkEventGroupConditionPatters(user.Groups, conditions.GroupNames) {
|
|
||||||
eventManagerLog(logger.LevelDebug, "skipping scheduled retention check for user %s, group name conditions don't match",
|
|
||||||
user.Username)
|
user.Username)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1900,13 +1879,8 @@ func executeMetadataCheckRuleAction(conditions dataprovider.ConditionOptions, pa
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
// if sender is set, the conditions have already been evaluated
|
// if sender is set, the conditions have already been evaluated
|
||||||
if params.sender == "" {
|
if params.sender == "" {
|
||||||
if !checkEventConditionPatterns(user.Username, conditions.Names) {
|
if !checkUserConditionOptions(&user, &conditions) {
|
||||||
eventManagerLog(logger.LevelDebug, "skipping metadata check for user %q, name conditions don't match",
|
eventManagerLog(logger.LevelDebug, "skipping metadata check for user %q, condition options don't match",
|
||||||
user.Username)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !checkEventGroupConditionPatters(user.Groups, conditions.GroupNames) {
|
|
||||||
eventManagerLog(logger.LevelDebug, "skipping metadata check for user %q, group name conditions don't match",
|
|
||||||
user.Username)
|
user.Username)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEventRuleMatch(t *testing.T) {
|
func TestEventRuleMatch(t *testing.T) {
|
||||||
|
role := "role1"
|
||||||
conditions := dataprovider.EventConditions{
|
conditions := dataprovider.EventConditions{
|
||||||
ProviderEvents: []string{"add", "update"},
|
ProviderEvents: []string{"add", "update"},
|
||||||
Options: dataprovider.ConditionOptions{
|
Options: dataprovider.ConditionOptions{
|
||||||
|
@ -51,20 +52,28 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
InverseMatch: true,
|
InverseMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RoleNames: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: role,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
res := eventManager.checkProviderEventMatch(conditions, EventParams{
|
res := eventManager.checkProviderEventMatch(conditions, EventParams{
|
||||||
Name: "user1",
|
Name: "user1",
|
||||||
|
Role: role,
|
||||||
Event: "add",
|
Event: "add",
|
||||||
})
|
})
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
||||||
Name: "user2",
|
Name: "user2",
|
||||||
|
Role: role,
|
||||||
Event: "update",
|
Event: "update",
|
||||||
})
|
})
|
||||||
assert.True(t, res)
|
assert.True(t, res)
|
||||||
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
||||||
Name: "user2",
|
Name: "user2",
|
||||||
|
Role: role,
|
||||||
Event: "delete",
|
Event: "delete",
|
||||||
})
|
})
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
|
@ -72,15 +81,24 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
||||||
Name: "user2",
|
Name: "user2",
|
||||||
Event: "update",
|
Event: "update",
|
||||||
|
Role: role,
|
||||||
ObjectType: "share",
|
ObjectType: "share",
|
||||||
})
|
})
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
||||||
Name: "user2",
|
Name: "user2",
|
||||||
Event: "update",
|
Event: "update",
|
||||||
|
Role: role,
|
||||||
ObjectType: "api_key",
|
ObjectType: "api_key",
|
||||||
})
|
})
|
||||||
assert.True(t, res)
|
assert.True(t, res)
|
||||||
|
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
||||||
|
Name: "user2",
|
||||||
|
Event: "update",
|
||||||
|
Role: role + "1",
|
||||||
|
ObjectType: "api_key",
|
||||||
|
})
|
||||||
|
assert.False(t, res)
|
||||||
// now test fs events
|
// now test fs events
|
||||||
conditions = dataprovider.EventConditions{
|
conditions = dataprovider.EventConditions{
|
||||||
FsEvents: []string{operationUpload, operationDownload},
|
FsEvents: []string{operationUpload, operationDownload},
|
||||||
|
@ -93,6 +111,12 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
Pattern: "tester*",
|
Pattern: "tester*",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RoleNames: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: role,
|
||||||
|
InverseMatch: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
FsPaths: []dataprovider.ConditionPattern{
|
FsPaths: []dataprovider.ConditionPattern{
|
||||||
{
|
{
|
||||||
Pattern: "*.txt",
|
Pattern: "*.txt",
|
||||||
|
@ -116,6 +140,10 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
params.Event = operationDownload
|
params.Event = operationDownload
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, params)
|
||||||
assert.True(t, res)
|
assert.True(t, res)
|
||||||
|
params.Role = role
|
||||||
|
res = eventManager.checkFsEventMatch(conditions, params)
|
||||||
|
assert.False(t, res)
|
||||||
|
params.Role = ""
|
||||||
params.Name = "name"
|
params.Name = "name"
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, params)
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
|
@ -195,6 +223,49 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
}
|
}
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, params)
|
||||||
assert.True(t, res)
|
assert.True(t, res)
|
||||||
|
// check user conditions
|
||||||
|
user := dataprovider.User{}
|
||||||
|
user.Username = "u1"
|
||||||
|
res = checkUserConditionOptions(&user, &dataprovider.ConditionOptions{})
|
||||||
|
assert.True(t, res)
|
||||||
|
res = checkUserConditionOptions(&user, &dataprovider.ConditionOptions{
|
||||||
|
Names: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: "user",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.False(t, res)
|
||||||
|
res = checkUserConditionOptions(&user, &dataprovider.ConditionOptions{
|
||||||
|
RoleNames: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: role,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.False(t, res)
|
||||||
|
user.Role = role
|
||||||
|
res = checkUserConditionOptions(&user, &dataprovider.ConditionOptions{
|
||||||
|
RoleNames: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: role,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.True(t, res)
|
||||||
|
res = checkUserConditionOptions(&user, &dataprovider.ConditionOptions{
|
||||||
|
GroupNames: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: "group",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RoleNames: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: role,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.False(t, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEventManager(t *testing.T) {
|
func TestEventManager(t *testing.T) {
|
||||||
|
|
|
@ -1021,6 +1021,8 @@ type ConditionOptions struct {
|
||||||
Names []ConditionPattern `json:"names,omitempty"`
|
Names []ConditionPattern `json:"names,omitempty"`
|
||||||
// Group names
|
// Group names
|
||||||
GroupNames []ConditionPattern `json:"group_names,omitempty"`
|
GroupNames []ConditionPattern `json:"group_names,omitempty"`
|
||||||
|
// Role names
|
||||||
|
RoleNames []ConditionPattern `json:"role_names,omitempty"`
|
||||||
// Virtual paths
|
// Virtual paths
|
||||||
FsPaths []ConditionPattern `json:"fs_paths,omitempty"`
|
FsPaths []ConditionPattern `json:"fs_paths,omitempty"`
|
||||||
Protocols []string `json:"protocols,omitempty"`
|
Protocols []string `json:"protocols,omitempty"`
|
||||||
|
@ -1040,6 +1042,7 @@ func (f *ConditionOptions) getACopy() ConditionOptions {
|
||||||
return ConditionOptions{
|
return ConditionOptions{
|
||||||
Names: cloneConditionPatterns(f.Names),
|
Names: cloneConditionPatterns(f.Names),
|
||||||
GroupNames: cloneConditionPatterns(f.GroupNames),
|
GroupNames: cloneConditionPatterns(f.GroupNames),
|
||||||
|
RoleNames: cloneConditionPatterns(f.RoleNames),
|
||||||
FsPaths: cloneConditionPatterns(f.FsPaths),
|
FsPaths: cloneConditionPatterns(f.FsPaths),
|
||||||
Protocols: protocols,
|
Protocols: protocols,
|
||||||
ProviderObjects: providerObjects,
|
ProviderObjects: providerObjects,
|
||||||
|
@ -1050,21 +1053,19 @@ func (f *ConditionOptions) getACopy() ConditionOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ConditionOptions) validate() error {
|
func (f *ConditionOptions) validate() error {
|
||||||
for _, name := range f.Names {
|
if err := validateConditionPatterns(f.Names); err != nil {
|
||||||
if err := name.validate(); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for _, name := range f.GroupNames {
|
if err := validateConditionPatterns(f.GroupNames); err != nil {
|
||||||
if err := name.validate(); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for _, fsPath := range f.FsPaths {
|
if err := validateConditionPatterns(f.RoleNames); err != nil {
|
||||||
if err := fsPath.validate(); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if err := validateConditionPatterns(f.FsPaths); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for _, p := range f.Protocols {
|
for _, p := range f.Protocols {
|
||||||
if !util.Contains(SupportedRuleConditionProtocols, p) {
|
if !util.Contains(SupportedRuleConditionProtocols, p) {
|
||||||
return util.NewValidationError(fmt.Sprintf("unsupported rule condition protocol: %q", p))
|
return util.NewValidationError(fmt.Sprintf("unsupported rule condition protocol: %q", p))
|
||||||
|
@ -1192,6 +1193,7 @@ func (c *EventConditions) validate(trigger int) error {
|
||||||
c.ProviderEvents = nil
|
c.ProviderEvents = nil
|
||||||
c.Options.Names = nil
|
c.Options.Names = nil
|
||||||
c.Options.GroupNames = nil
|
c.Options.GroupNames = nil
|
||||||
|
c.Options.RoleNames = nil
|
||||||
c.Options.FsPaths = nil
|
c.Options.FsPaths = nil
|
||||||
c.Options.Protocols = nil
|
c.Options.Protocols = nil
|
||||||
c.Options.MinFileSize = 0
|
c.Options.MinFileSize = 0
|
||||||
|
@ -1201,6 +1203,7 @@ func (c *EventConditions) validate(trigger int) error {
|
||||||
c.FsEvents = nil
|
c.FsEvents = nil
|
||||||
c.ProviderEvents = nil
|
c.ProviderEvents = nil
|
||||||
c.Options.GroupNames = nil
|
c.Options.GroupNames = nil
|
||||||
|
c.Options.RoleNames = nil
|
||||||
c.Options.FsPaths = nil
|
c.Options.FsPaths = nil
|
||||||
c.Options.Protocols = nil
|
c.Options.Protocols = nil
|
||||||
c.Options.MinFileSize = 0
|
c.Options.MinFileSize = 0
|
||||||
|
@ -1445,6 +1448,15 @@ func cloneConditionPatterns(patterns []ConditionPattern) []ConditionPattern {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateConditionPatterns(patterns []ConditionPattern) error {
|
||||||
|
for _, name := range patterns {
|
||||||
|
if err := name.validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Task stores the state for a scheduled task
|
// Task stores the state for a scheduled task
|
||||||
type Task struct {
|
type Task struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
|
|
@ -1541,6 +1541,14 @@ func TestActionRuleRelations(t *testing.T) {
|
||||||
Month: "*",
|
Month: "*",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Options: dataprovider.ConditionOptions{
|
||||||
|
RoleNames: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: "g*",
|
||||||
|
InverseMatch: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Actions: []dataprovider.EventAction{
|
Actions: []dataprovider.EventAction{
|
||||||
{
|
{
|
||||||
|
@ -2008,6 +2016,16 @@ func TestEventRuleValidation(t *testing.T) {
|
||||||
_, resp, err = httpdtest.AddEventRule(rule, http.StatusBadRequest)
|
_, resp, err = httpdtest.AddEventRule(rule, http.StatusBadRequest)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, string(resp), "unsupported provider event")
|
assert.Contains(t, string(resp), "unsupported provider event")
|
||||||
|
rule.Conditions.ProviderEvents = []string{"add"}
|
||||||
|
rule.Conditions.Options.RoleNames = []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, resp, err = httpdtest.AddEventRule(rule, http.StatusBadRequest)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Contains(t, string(resp), "empty condition pattern not allowed")
|
||||||
|
rule.Conditions.Options.RoleNames = nil
|
||||||
rule.Trigger = dataprovider.EventTriggerSchedule
|
rule.Trigger = dataprovider.EventTriggerSchedule
|
||||||
_, resp, err = httpdtest.AddEventRule(rule, http.StatusBadRequest)
|
_, resp, err = httpdtest.AddEventRule(rule, http.StatusBadRequest)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -2026,8 +2044,8 @@ func TestEventRuleValidation(t *testing.T) {
|
||||||
Month: "*",
|
Month: "*",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, _, err = httpdtest.AddEventRule(rule, http.StatusInternalServerError)
|
_, resp, err = httpdtest.AddEventRule(rule, http.StatusInternalServerError)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err, string(resp))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUserTransferLimits(t *testing.T) {
|
func TestUserTransferLimits(t *testing.T) {
|
||||||
|
@ -20180,6 +20198,12 @@ func TestWebEventRule(t *testing.T) {
|
||||||
InverseMatch: true,
|
InverseMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RoleNames: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: "g*",
|
||||||
|
InverseMatch: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Actions: []dataprovider.EventAction{
|
Actions: []dataprovider.EventAction{
|
||||||
|
@ -20211,6 +20235,8 @@ func TestWebEventRule(t *testing.T) {
|
||||||
form.Set("type_name_pattern0", "inverse")
|
form.Set("type_name_pattern0", "inverse")
|
||||||
form.Set("group_name_pattern0", rule.Conditions.Options.GroupNames[0].Pattern)
|
form.Set("group_name_pattern0", rule.Conditions.Options.GroupNames[0].Pattern)
|
||||||
form.Set("type_group_name_pattern0", "inverse")
|
form.Set("type_group_name_pattern0", "inverse")
|
||||||
|
form.Set("role_name_pattern0", rule.Conditions.Options.RoleNames[0].Pattern)
|
||||||
|
form.Set("type_role_name_pattern0", "inverse")
|
||||||
req, err = http.NewRequest(http.MethodPost, webAdminEventRulePath, bytes.NewBuffer([]byte(form.Encode())))
|
req, err = http.NewRequest(http.MethodPost, webAdminEventRulePath, bytes.NewBuffer([]byte(form.Encode())))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
@ -20309,6 +20335,12 @@ func TestWebEventRule(t *testing.T) {
|
||||||
InverseMatch: true,
|
InverseMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RoleNames: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: "g*",
|
||||||
|
InverseMatch: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
FsPaths: []dataprovider.ConditionPattern{
|
FsPaths: []dataprovider.ConditionPattern{
|
||||||
{
|
{
|
||||||
Pattern: "/subdir/*.txt",
|
Pattern: "/subdir/*.txt",
|
||||||
|
|
|
@ -2169,7 +2169,7 @@ func getEventActionFromPostFields(r *http.Request) (dataprovider.BaseEventAction
|
||||||
|
|
||||||
func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventConditions, error) {
|
func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventConditions, error) {
|
||||||
var schedules []dataprovider.Schedule
|
var schedules []dataprovider.Schedule
|
||||||
var names, groupNames, fsPaths []dataprovider.ConditionPattern
|
var names, groupNames, roleNames, fsPaths []dataprovider.ConditionPattern
|
||||||
for k := range r.Form {
|
for k := range r.Form {
|
||||||
if strings.HasPrefix(k, "schedule_hour") {
|
if strings.HasPrefix(k, "schedule_hour") {
|
||||||
hour := r.Form.Get(k)
|
hour := r.Form.Get(k)
|
||||||
|
@ -2208,6 +2208,17 @@ func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventCo
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(k, "role_name_pattern") {
|
||||||
|
pattern := r.Form.Get(k)
|
||||||
|
if pattern != "" {
|
||||||
|
idx := strings.TrimPrefix(k, "role_name_pattern")
|
||||||
|
patternType := r.Form.Get(fmt.Sprintf("type_role_name_pattern%s", idx))
|
||||||
|
roleNames = append(roleNames, dataprovider.ConditionPattern{
|
||||||
|
Pattern: pattern,
|
||||||
|
InverseMatch: patternType == inversePatternType,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
if strings.HasPrefix(k, "fs_path_pattern") {
|
if strings.HasPrefix(k, "fs_path_pattern") {
|
||||||
pattern := r.Form.Get(k)
|
pattern := r.Form.Get(k)
|
||||||
if pattern != "" {
|
if pattern != "" {
|
||||||
|
@ -2235,6 +2246,7 @@ func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventCo
|
||||||
Options: dataprovider.ConditionOptions{
|
Options: dataprovider.ConditionOptions{
|
||||||
Names: names,
|
Names: names,
|
||||||
GroupNames: groupNames,
|
GroupNames: groupNames,
|
||||||
|
RoleNames: roleNames,
|
||||||
FsPaths: fsPaths,
|
FsPaths: fsPaths,
|
||||||
Protocols: r.Form["fs_protocols"],
|
Protocols: r.Form["fs_protocols"],
|
||||||
ProviderObjects: r.Form["provider_objects"],
|
ProviderObjects: r.Form["provider_objects"],
|
||||||
|
|
|
@ -1510,6 +1510,9 @@ func checkEventConditionOptions(expected, actual dataprovider.ConditionOptions)
|
||||||
if err := compareConditionPatternOptions(expected.GroupNames, actual.GroupNames); err != nil {
|
if err := compareConditionPatternOptions(expected.GroupNames, actual.GroupNames); err != nil {
|
||||||
return errors.New("condition group names mismatch")
|
return errors.New("condition group names mismatch")
|
||||||
}
|
}
|
||||||
|
if err := compareConditionPatternOptions(expected.RoleNames, actual.RoleNames); err != nil {
|
||||||
|
return errors.New("condition role names mismatch")
|
||||||
|
}
|
||||||
if err := compareConditionPatternOptions(expected.FsPaths, actual.FsPaths); err != nil {
|
if err := compareConditionPatternOptions(expected.FsPaths, actual.FsPaths); err != nil {
|
||||||
return errors.New("condition fs_paths mismatch")
|
return errors.New("condition fs_paths mismatch")
|
||||||
}
|
}
|
||||||
|
|
|
@ -6500,6 +6500,10 @@ components:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/ConditionPattern'
|
$ref: '#/components/schemas/ConditionPattern'
|
||||||
|
role_names:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ConditionPattern'
|
||||||
fs_paths:
|
fs_paths:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
|
|
@ -291,6 +291,60 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="card bg-light mb-3 trigger trigger-fs trigger-schedule trigger-provider">
|
||||||
|
<div class="card-header">
|
||||||
|
<b>Role name filters</b>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h6 class="card-title mb-4">Shell-like pattern filters for role names. For example "role*"" will match role names starting with "role".</h6>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-12 form_field_role_names_outer">
|
||||||
|
{{range $idx, $val := .Rule.Conditions.Options.RoleNames}}
|
||||||
|
<div class="row form_field_role_names_outer_row">
|
||||||
|
<div class="form-group col-md-8">
|
||||||
|
<input type="text" class="form-control" id="idRoleNamePattern{{$idx}}" name="role_name_pattern{{$idx}}" placeholder="" value="{{$val.Pattern}}" maxlength="255">
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-3">
|
||||||
|
<select class="form-control selectpicker" id="idRoleNamePatternType{{$idx}}" name="type_role_name_pattern{{$idx}}">
|
||||||
|
<option value=""></option>
|
||||||
|
<option value="inverse" {{if $val.InverseMatch}}selected{{end}}>Inverse match</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-1">
|
||||||
|
<button class="btn btn-circle btn-danger remove_role_name_pattern_btn_frm_field">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="row form_field_role_names_outer_row">
|
||||||
|
<div class="form-group col-md-8">
|
||||||
|
<input type="text" class="form-control" id="idRoleNamePattern0" name="role_name_pattern0" placeholder="" value="" maxlength="255">
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-3">
|
||||||
|
<select class="form-control selectpicker" id="idRoleNamePatternType0" name="type_role_name_pattern0">
|
||||||
|
<option value=""></option>
|
||||||
|
<option value="inverse">Inverse match</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-1">
|
||||||
|
<button class="btn btn-circle btn-danger remove_role_name_pattern_btn_frm_field">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mx-1">
|
||||||
|
<button type="button" class="btn btn-secondary add_new_role_name_pattern_field_btn">
|
||||||
|
<i class="fas fa-plus"></i> Add new filter
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card bg-light mb-3 trigger trigger-fs">
|
<div class="card bg-light mb-3 trigger trigger-fs">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<b>Path filters</b>
|
<b>Path filters</b>
|
||||||
|
@ -542,6 +596,36 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
$(this).closest(".form_field_group_names_outer_row").remove();
|
$(this).closest(".form_field_group_names_outer_row").remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("body").on("click", ".add_new_role_name_pattern_field_btn", function () {
|
||||||
|
var index = $(".form_field_role_names_outer").find(".form_field_role_names_outer_row").length;
|
||||||
|
while (document.getElementById("idRoleNamePattern"+index) != null){
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
$(".form_field_role_names_outer").append(`
|
||||||
|
<div class="row form_field_role_names_outer_row">
|
||||||
|
<div class="form-group col-md-8">
|
||||||
|
<input type="text" class="form-control" id="idRoleNamePattern${index}" name="role_name_pattern${index}" placeholder="" value="" maxlength="255">
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-3">
|
||||||
|
<select class="form-control" id="idRoleNamePatternType${index}" name="type_role_name_pattern${index}">
|
||||||
|
<option value=""></option>
|
||||||
|
<option value="inverse">Inverse match</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-1">
|
||||||
|
<button class="btn btn-circle btn-danger remove_role_name_pattern_btn_frm_field">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
$("#idRoleNamePatternType"+index).selectpicker();
|
||||||
|
});
|
||||||
|
|
||||||
|
$("body").on("click", ".remove_role_name_pattern_btn_frm_field", function () {
|
||||||
|
$(this).closest(".form_field_role_names_outer_row").remove();
|
||||||
|
});
|
||||||
|
|
||||||
$("body").on("click", ".add_new_fs_path_pattern_field_btn", function () {
|
$("body").on("click", ".add_new_fs_path_pattern_field_btn", function () {
|
||||||
var index = $(".form_field_fs_paths_outer").find("form_field_fs_paths_outer_row").length;
|
var index = $(".form_field_fs_paths_outer").find("form_field_fs_paths_outer_row").length;
|
||||||
while (document.getElementById("idFsPathPattern"+index) != null){
|
while (document.getElementById("idFsPathPattern"+index) != null){
|
||||||
|
|
Loading…
Reference in a new issue