refactor: mode label decoder to separate package

This commit is contained in:
Stavros
2025-09-03 12:23:21 +03:00
parent b024d5ffda
commit f5ac7eff99
7 changed files with 120 additions and 42 deletions

View File

@@ -126,51 +126,51 @@ type RedirectQuery struct {
// Labels // Labels
type Labels struct { type Apps struct {
Apps map[string]AppLabels Apps map[string]App
} }
type AppLabels struct { type App struct {
Config ConfigLabels Config AppConfig
Users UsersLabels Users AppUsers
OAuth OAuthLabels OAuth AppOAuth
IP IPLabels IP AppIP
Response ResponseLabels Response AppResponse
Path PathLabels Path AppPath
} }
type ConfigLabels struct { type AppConfig struct {
Domain string Domain string
} }
type UsersLabels struct { type AppUsers struct {
Allow string Allow string
Block string Block string
} }
type OAuthLabels struct { type AppOAuth struct {
Whitelist string Whitelist string
Groups string Groups string
} }
type IPLabels struct { type AppIP struct {
Allow []string Allow []string
Block []string Block []string
Bypass []string Bypass []string
} }
type ResponseLabels struct { type AppResponse struct {
Headers []string Headers []string
BasicAuth BasicAuthLabels BasicAuth AppBasicAuth
} }
type BasicAuthLabels struct { type AppBasicAuth struct {
Username string Username string
Password string Password string
PasswordFile string PasswordFile string
} }
type PathLabels struct { type AppPath struct {
Allow string Allow string
Block string Block string
} }

View File

@@ -251,7 +251,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/login?%s", controller.config.AppURL, queries.Encode())) c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/login?%s", controller.config.AppURL, queries.Encode()))
} }
func (controller *ProxyController) setHeaders(c *gin.Context, labels config.AppLabels) { func (controller *ProxyController) setHeaders(c *gin.Context, labels config.App) {
c.Header("Authorization", c.Request.Header.Get("Authorization")) c.Header("Authorization", c.Request.Header.Get("Authorization"))
headers := utils.ParseHeaders(labels.Response.Headers) headers := utils.ParseHeaders(labels.Response.Headers)

View File

@@ -285,7 +285,7 @@ func (auth *AuthService) UserAuthConfigured() bool {
return len(auth.config.Users) > 0 || auth.ldap != nil return len(auth.config.Users) > 0 || auth.ldap != nil
} }
func (auth *AuthService) IsResourceAllowed(c *gin.Context, context config.UserContext, labels config.AppLabels) bool { func (auth *AuthService) IsResourceAllowed(c *gin.Context, context config.UserContext, labels config.App) bool {
if context.OAuth { if context.OAuth {
log.Debug().Msg("Checking OAuth whitelist") log.Debug().Msg("Checking OAuth whitelist")
return utils.CheckFilter(labels.OAuth.Whitelist, context.Email) return utils.CheckFilter(labels.OAuth.Whitelist, context.Email)
@@ -322,7 +322,7 @@ func (auth *AuthService) IsInOAuthGroup(c *gin.Context, context config.UserConte
return false return false
} }
func (auth *AuthService) IsAuthEnabled(uri string, path config.PathLabels) (bool, error) { func (auth *AuthService) IsAuthEnabled(uri string, path config.AppPath) (bool, error) {
// Check for block list // Check for block list
if path.Block != "" { if path.Block != "" {
regex, err := regexp.Compile(path.Block) regex, err := regexp.Compile(path.Block)
@@ -364,7 +364,7 @@ func (auth *AuthService) GetBasicAuth(c *gin.Context) *config.User {
} }
} }
func (auth *AuthService) CheckIP(labels config.IPLabels, ip string) bool { func (auth *AuthService) CheckIP(labels config.AppIP, ip string) bool {
for _, blocked := range labels.Block { for _, blocked := range labels.Block {
res, err := utils.FilterIP(blocked, ip) res, err := utils.FilterIP(blocked, ip)
if err != nil { if err != nil {
@@ -398,7 +398,7 @@ func (auth *AuthService) CheckIP(labels config.IPLabels, ip string) bool {
return true return true
} }
func (auth *AuthService) IsBypassedIP(labels config.IPLabels, ip string) bool { func (auth *AuthService) IsBypassedIP(labels config.AppIP, ip string) bool {
for _, bypassed := range labels.Bypass { for _, bypassed := range labels.Bypass {
res, err := utils.FilterIP(bypassed, ip) res, err := utils.FilterIP(bypassed, ip)
if err != nil { if err != nil {

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"strings" "strings"
"tinyauth/internal/config" "tinyauth/internal/config"
"tinyauth/internal/utils" "tinyauth/internal/utils/decoders"
container "github.com/docker/docker/api/types/container" container "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client" "github.com/docker/docker/client"
@@ -55,17 +55,17 @@ func (docker *DockerService) DockerConnected() bool {
return err == nil return err == nil
} }
func (docker *DockerService) GetLabels(appDomain string) (config.AppLabels, error) { func (docker *DockerService) GetLabels(appDomain string) (config.App, error) {
isConnected := docker.DockerConnected() isConnected := docker.DockerConnected()
if !isConnected { if !isConnected {
log.Debug().Msg("Docker not connected, returning empty labels") log.Debug().Msg("Docker not connected, returning empty labels")
return config.AppLabels{}, nil return config.App{}, nil
} }
containers, err := docker.GetContainers() containers, err := docker.GetContainers()
if err != nil { if err != nil {
return config.AppLabels{}, err return config.App{}, err
} }
for _, ctr := range containers { for _, ctr := range containers {
@@ -75,7 +75,7 @@ func (docker *DockerService) GetLabels(appDomain string) (config.AppLabels, erro
continue continue
} }
labels, err := utils.GetLabels(inspect.Config.Labels) labels, err := decoders.DecodeLabels(inspect.Config.Labels)
if err != nil { if err != nil {
log.Warn().Str("id", ctr.ID).Err(err).Msg("Error getting container labels, skipping") log.Warn().Str("id", ctr.ID).Err(err).Msg("Error getting container labels, skipping")
continue continue
@@ -95,5 +95,5 @@ func (docker *DockerService) GetLabels(appDomain string) (config.AppLabels, erro
} }
log.Debug().Msg("No matching container found, returning empty labels") log.Debug().Msg("No matching container found, returning empty labels")
return config.AppLabels{}, nil return config.App{}, nil
} }

View File

@@ -0,0 +1,19 @@
package decoders
import (
"tinyauth/internal/config"
"github.com/traefik/paerser/parser"
)
func DecodeLabels(labels map[string]string) (config.Apps, error) {
var appLabels config.Apps
err := parser.Decode(labels, &appLabels, "tinyauth", "tinyauth.apps")
if err != nil {
return config.Apps{}, err
}
return appLabels, nil
}

View File

@@ -0,0 +1,73 @@
package decoders_test
import (
"reflect"
"testing"
"tinyauth/internal/config"
"tinyauth/internal/utils/decoders"
)
func TestDecodeLabels(t *testing.T) {
// Variables
expected := config.Apps{
Apps: map[string]config.App{
"foo": {
Config: config.AppConfig{
Domain: "example.com",
},
Users: config.AppUsers{
Allow: "user1,user2",
Block: "user3",
},
OAuth: config.AppOAuth{
Whitelist: "somebody@example.com",
Groups: "group3",
},
IP: config.AppIP{
Allow: []string{"10.71.0.1/24", "10.71.0.2"},
Block: []string{"10.10.10.10", "10.0.0.0/24"},
Bypass: []string{"192.168.1.1"},
},
Response: config.AppResponse{
Headers: []string{"X-Foo=Bar", "X-Baz=Qux"},
BasicAuth: config.AppBasicAuth{
Username: "admin",
Password: "password",
PasswordFile: "/path/to/passwordfile",
},
},
Path: config.AppPath{
Allow: "/public",
Block: "/private",
},
},
},
}
test := map[string]string{
"tinyauth.apps.foo.config.domain": "example.com",
"tinyauth.apps.foo.users.allow": "user1,user2",
"tinyauth.apps.foo.users.block": "user3",
"tinyauth.apps.foo.oauth.whitelist": "somebody@example.com",
"tinyauth.apps.foo.oauth.groups": "group3",
"tinyauth.apps.foo.ip.allow": "10.71.0.1/24,10.71.0.2",
"tinyauth.apps.foo.ip.block": "10.10.10.10,10.0.0.0/24",
"tinyauth.apps.foo.ip.bypass": "192.168.1.1",
"tinyauth.apps.foo.response.headers": "X-Foo=Bar,X-Baz=Qux",
"tinyauth.apps.foo.response.basicauth.username": "admin",
"tinyauth.apps.foo.response.basicauth.password": "password",
"tinyauth.apps.foo.response.basicauth.passwordfile": "/path/to/passwordfile",
"tinyauth.apps.foo.path.allow": "/public",
"tinyauth.apps.foo.path.block": "/private",
}
// Test
result, err := decoders.DecodeLabels(test)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if reflect.DeepEqual(expected, result) == false {
t.Fatalf("Expected %v but got %v", expected, result)
}
}

View File

@@ -3,22 +3,8 @@ package utils
import ( import (
"net/http" "net/http"
"strings" "strings"
"tinyauth/internal/config"
"github.com/traefik/paerser/parser"
) )
func GetLabels(labels map[string]string) (config.Labels, error) {
var labelsParsed config.Labels
err := parser.Decode(labels, &labelsParsed, "tinyauth", "tinyauth.apps")
if err != nil {
return config.Labels{}, err
}
return labelsParsed, nil
}
func ParseHeaders(headers []string) map[string]string { func ParseHeaders(headers []string) map[string]string {
headerMap := make(map[string]string) headerMap := make(map[string]string)
for _, header := range headers { for _, header := range headers {