Skip to content

Commit

Permalink
feat: rules behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Dec 7, 2024
1 parent ca7f337 commit 51b101d
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 5 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,21 @@ directory: .
# permissions. For example, to allow to read and create, set "RC". Default is "R".
permissions: R

# The default permissions rules for users. Default is none.
# The default permissions rules for users. Default is none. Rules are applied
# from last to first, that is, the first rule that matches the request, starting
# from the end, will be applied to the request.
rules: []

# The behavior of redefining the rules for users. It can be:
# - overwrite: when a user has rules defined, these will overwrite any global
# rules already defined. That is, the global rules are not applicable to the
# user.
# - append: when a user has rules defined, these will be appended to the global
# rules already defined. That is, for this user, their own specific rules will
# be checked first, and then the global rules.
# Default is 'overwrite'.
rulesBehavior: overwrite

# Logging configuration
log:
# Logging format ('console', 'json'). Default is 'console'.
Expand Down
17 changes: 16 additions & 1 deletion lib/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func ParseConfig(filename string, flags *pflag.FlagSet) (*Config, error) {
v.SetDefault("Prefix", DefaultPrefix)

// Other defaults
v.SetDefault("RulesBehavior", RulesOverwrite)
v.SetDefault("Directory", ".")
v.SetDefault("Permissions", "R")
v.SetDefault("Debug", false)
Expand Down Expand Up @@ -115,7 +116,21 @@ func ParseConfig(filename string, flags *pflag.FlagSet) (*Config, error) {
cfg.Users[i].Permissions = cfg.Permissions
}

if !v.IsSet(fmt.Sprintf("Users.%d.Rules", i)) {
if !v.IsSet(fmt.Sprintf("Users.%d.RulesBehavior", i)) {
cfg.Users[i].RulesBehavior = cfg.RulesBehavior
}

if v.IsSet(fmt.Sprintf("Users.%d.Rules", i)) {
switch cfg.Users[i].RulesBehavior {
case RulesOverwrite:
// Do nothing
case RulesAppend:
rules := append([]*Rule{}, cfg.Rules...)
rules = append(rules, cfg.Users[i].Rules...)

cfg.Users[i].Rules = rules
}
} else {
cfg.Users[i].Rules = cfg.Rules
}
}
Expand Down
65 changes: 65 additions & 0 deletions lib/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,71 @@ rules:
require.Nil(t, cfg.Rules[1].Regex)
})

t.Run("Rules Behavior (Default: Overwrite)", func(t *testing.T) {
content := `
directory: /
rules:
- regex: '^.+\.js$'
- path: /public/access/
users:
- username: foo
password: bar
rules:
- path: /private/access/`

cfg := writeAndParseConfig(t, content, ".yaml")
require.NoError(t, cfg.Validate())

require.Len(t, cfg.Rules, 2)

require.Empty(t, cfg.Rules[0].Path)
require.NotNil(t, cfg.Rules[0].Regex)
require.True(t, cfg.Rules[0].Regex.MatchString("/my/path/to/file.js"))
require.False(t, cfg.Rules[0].Regex.MatchString("/my/path/to/file.ts"))

require.EqualValues(t, "/public/access/", cfg.Rules[1].Path)
require.Nil(t, cfg.Rules[1].Regex)

require.Len(t, cfg.Users, 1)
require.Len(t, cfg.Users[0].Rules, 1)
require.EqualValues(t, "/private/access/", cfg.Users[0].Rules[0].Path)
})

t.Run("Rules Behavior (Append)", func(t *testing.T) {
content := `
directory: /
rules:
- regex: '^.+\.js$'
- path: /public/access/
rulesBehavior: append
users:
- username: foo
password: bar
rules:
- path: /private/access/`

cfg := writeAndParseConfig(t, content, ".yaml")
require.NoError(t, cfg.Validate())

require.Len(t, cfg.Rules, 2)

require.Empty(t, cfg.Rules[0].Path)
require.NotNil(t, cfg.Rules[0].Regex)
require.True(t, cfg.Rules[0].Regex.MatchString("/my/path/to/file.js"))
require.False(t, cfg.Rules[0].Regex.MatchString("/my/path/to/file.ts"))

require.EqualValues(t, "/public/access/", cfg.Rules[1].Path)
require.Nil(t, cfg.Rules[1].Regex)

require.Len(t, cfg.Users, 1)
require.Len(t, cfg.Users[0].Rules, 3)

require.EqualValues(t, cfg.Rules[0], cfg.Users[0].Rules[0])
require.EqualValues(t, cfg.Rules[1], cfg.Users[0].Rules[1])
require.EqualValues(t, "/private/access/", cfg.Users[0].Rules[2].Path)
})
}

func TestConfigEnv(t *testing.T) {
Expand Down
21 changes: 18 additions & 3 deletions lib/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,18 @@ func (r *Rule) Matches(path string) bool {
return strings.HasPrefix(path, r.Path)
}

type RulesBehavior string

const (
RulesOverwrite RulesBehavior = "overwrite"
RulesAppend RulesBehavior = "append"
)

type UserPermissions struct {
Directory string
Permissions Permissions
Rules []*Rule
Directory string
Permissions Permissions
Rules []*Rule
RulesBehavior RulesBehavior
}

// Allowed checks if the user has permission to access a directory/file
Expand Down Expand Up @@ -91,6 +99,13 @@ func (p *UserPermissions) Validate() error {
}
}

switch p.RulesBehavior {
case RulesAppend, RulesOverwrite:
// Good to go
default:
return fmt.Errorf("invalid rule behavior: %s", p.RulesBehavior)
}

return nil
}

Expand Down

0 comments on commit 51b101d

Please sign in to comment.