rework to keep regex under specific conditions

This commit is contained in:
Scott McKendry
2026-07-28 19:53:16 +12:00
parent 3d5ab54ab8
commit cce0eaa974
3 changed files with 51 additions and 35 deletions
+8 -4
View File
@@ -9,14 +9,14 @@ import (
"regexp"
"strings"
"github.com/gin-gonic/gin"
"github.com/google/go-querystring/query"
"go.uber.org/dig"
"github.com/tinyauthapp/tinyauth/internal/model"
"github.com/tinyauthapp/tinyauth/internal/service"
"github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/tinyauthapp/tinyauth/internal/utils/logger"
"go.uber.org/dig"
"github.com/gin-gonic/gin"
"github.com/google/go-querystring/query"
)
type AuthModuleType int
@@ -396,6 +396,10 @@ func (controller *ProxyController) getForwardAuthContext(c *gin.Context) (ProxyC
return ProxyContext{}, fmt.Errorf("invalid x-forwarded-uri: %w", err)
}
if parsedURI.Path == "" {
parsedURI.Path = "/"
}
proto, ok := controller.getHeader(c, "x-forwarded-proto")
if !ok {
+31 -9
View File
@@ -2,6 +2,8 @@ package service
import (
"errors"
"fmt"
"regexp"
"strings"
"github.com/tinyauthapp/tinyauth/internal/model"
@@ -179,26 +181,38 @@ type AuthEnabledRule struct {
Log *logger.Logger
}
func matchPathRule(paths, path string) bool {
func matchPathRule(paths, path string) (bool, error) {
for _, configuredPath := range strings.Split(paths, ",") {
configuredPath = strings.TrimSpace(configuredPath)
if configuredPath == "/" {
return true
return true, nil
}
configuredPath = strings.TrimRight(configuredPath, "/")
if configuredPath == "" {
continue
}
if path == configuredPath || strings.HasPrefix(path, configuredPath+"/") {
return true
// only apply regex if the path starts and ends with a slash, e.g. /regex/
if strings.HasPrefix(configuredPath, "/") && strings.HasSuffix(configuredPath, "/") {
regex, err := regexp.Compile(configuredPath[1 : len(configuredPath)-1])
if err != nil {
return false, fmt.Errorf("invalid path regex %q: %w", configuredPath, err)
}
if regex.MatchString(path) {
return true, nil
}
continue
}
if strings.HasPrefix(path, configuredPath) {
return true, nil
}
}
return false
return false, nil
}
func (rule *AuthEnabledRule) Evaluate(ctx *ACLContext) Effect {
@@ -207,7 +221,11 @@ func (rule *AuthEnabledRule) Evaluate(ctx *ACLContext) Effect {
}
if ctx.ACLs.Path.Block != "" {
match := matchPathRule(ctx.ACLs.Path.Block, ctx.Path)
match, err := matchPathRule(ctx.ACLs.Path.Block, ctx.Path)
if err != nil {
rule.Log.App.Warn().Err(err).Msg("Invalid path block rule")
return EffectDeny
}
if !match {
return EffectAllow
@@ -215,7 +233,11 @@ func (rule *AuthEnabledRule) Evaluate(ctx *ACLContext) Effect {
}
if ctx.ACLs.Path.Allow != "" {
match := matchPathRule(ctx.ACLs.Path.Allow, ctx.Path)
match, err := matchPathRule(ctx.ACLs.Path.Allow, ctx.Path)
if err != nil {
rule.Log.App.Warn().Err(err).Msg("Invalid path allow rule")
return EffectDeny
}
if match {
return EffectAllow
+12 -22
View File
@@ -527,32 +527,22 @@ func TestAuthEnabledRule(t *testing.T) {
expected: EffectDeny,
},
{
name: "allows when path does not match block path",
ctx: &ACLContext{
ACLs: &model.App{
Path: model.AppPath{Block: "/admin"},
},
Path: "/public",
},
expected: EffectAllow,
},
{
name: "denies when path matches block path",
ctx: &ACLContext{
ACLs: &model.App{
Path: model.AppPath{Block: "/admin"},
},
Path: "/admin/users",
},
expected: EffectDeny,
},
{
name: "allows when path matches allow path",
name: "allows when path starts with allow path",
ctx: &ACLContext{
ACLs: &model.App{
Path: model.AppPath{Allow: "/public"},
},
Path: "/public/index",
Path: "/publicity",
},
expected: EffectAllow,
},
{
name: "allows when path matches allow regex",
ctx: &ACLContext{
ACLs: &model.App{
Path: model.AppPath{Allow: "/^/public-[0-9]+$/"},
},
Path: "/public-42",
},
expected: EffectAllow,
},