This commit is contained in:
Stavros
2025-11-04 17:37:40 +02:00
parent 5f7e89c330
commit 1ad862d86c
13 changed files with 155 additions and 230 deletions

View File

@@ -1,76 +0,0 @@
package decoders
import (
"reflect"
"strings"
"github.com/stoewer/go-strcase"
)
func normalizeKeys[T any](input map[string]string, root string, sep string) map[string]string {
knownKeys := getKnownKeys[T]()
normalized := make(map[string]string)
for k, v := range input {
parts := []string{"tinyauth"}
key := strings.ToLower(k)
key = strings.ReplaceAll(key, sep, "-")
suffix := ""
for _, known := range knownKeys {
if strings.HasSuffix(key, known) {
suffix = known
break
}
}
if suffix == "" {
continue
}
parts = append(parts, root)
id := strings.TrimPrefix(key, root+"-")
id = strings.TrimSuffix(id, "-"+suffix)
if id == "" {
continue
}
parts = append(parts, id)
parts = append(parts, suffix)
final := ""
for i, part := range parts {
if i > 0 {
final += "."
}
final += strcase.LowerCamelCase(part)
}
normalized[final] = v
}
return normalized
}
func getKnownKeys[T any]() []string {
var keys []string
var t T
v := reflect.ValueOf(t)
typeOfT := v.Type()
for field := range typeOfT.NumField() {
if typeOfT.Field(field).Tag.Get("field") != "" {
keys = append(keys, typeOfT.Field(field).Tag.Get("field"))
continue
}
keys = append(keys, strcase.KebabCase(typeOfT.Field(field).Name))
}
return keys
}

View File

@@ -1,19 +1,17 @@
package decoders
import (
"github.com/traefik/paerser/parser"
"github.com/traefik/paerser/env"
)
func DecodeEnv[T any, C any](env map[string]string, subName string) (T, error) {
var result T
func DecodeEnv[T any](environ []string) (T, error) {
var target T
normalized := normalizeKeys[C](env, subName, "_")
err := parser.Decode(normalized, &result, "tinyauth", "tinyauth."+subName)
err := env.Decode(environ, "TINYAUTH_", &target)
if err != nil {
return result, err
return target, err
}
return result, nil
return target, nil
}

View File

@@ -10,11 +10,11 @@ import (
func TestDecodeEnv(t *testing.T) {
// Setup
env := map[string]string{
"PROVIDERS_GOOGLE_CLIENT_ID": "google-client-id",
"PROVIDERS_GOOGLE_CLIENT_SECRET": "google-client-secret",
"PROVIDERS_MY_GITHUB_CLIENT_ID": "github-client-id",
"PROVIDERS_MY_GITHUB_CLIENT_SECRET": "github-client-secret",
env := []string{
"TINYAUTH_PROVIDERS_GOOGLE_CLIENTID=google-client-id",
"TINYAUTH_PROVIDERS_GOOGLE_CLIENTSECRET=google-client-secret",
"TINYAUTH_PROVIDERS_GITHUB_CLIENTID=github-client-id",
"TINYAUTH_PROVIDERS_GITHUB_CLIENTSECRET=github-client-secret",
}
expected := config.Providers{
@@ -23,7 +23,7 @@ func TestDecodeEnv(t *testing.T) {
ClientID: "google-client-id",
ClientSecret: "google-client-secret",
},
"myGithub": {
"github": {
ClientID: "github-client-id",
ClientSecret: "github-client-secret",
},
@@ -31,7 +31,7 @@ func TestDecodeEnv(t *testing.T) {
}
// Execute
result, err := decoders.DecodeEnv[config.Providers, config.OAuthServiceConfig](env, "providers")
result, err := decoders.DecodeEnv[config.Providers](env)
assert.NilError(t, err)
assert.DeepEqual(t, result, expected)
}

View File

@@ -3,28 +3,32 @@ package decoders
import (
"strings"
"github.com/traefik/paerser/parser"
"github.com/traefik/paerser/flag"
)
func DecodeFlags[T any, C any](flags map[string]string, subName string) (T, error) {
var result T
func DecodeFlags[T any](args []string) (T, error) {
var target T
var formatted = []string{}
filtered := filterFlags(flags)
normalized := normalizeKeys[C](filtered, subName, "_")
for _, arg := range args {
argFmt := strings.TrimPrefix(arg, "--")
argParts := strings.SplitN(argFmt, "=", 2)
err := parser.Decode(normalized, &result, "tinyauth", "tinyauth."+subName)
if len(argParts) != 2 {
continue
}
key := argParts[0]
value := argParts[1]
formatted = append(formatted, "--"+strings.ReplaceAll(key, "-", ".")+"="+value)
}
err := flag.Decode(formatted, &target)
if err != nil {
return result, err
return target, err
}
return result, nil
}
func filterFlags(flags map[string]string) map[string]string {
filtered := make(map[string]string)
for k, v := range flags {
filtered[strings.TrimPrefix(k, "--")] = v
}
return filtered
return target, nil
}

View File

@@ -10,11 +10,11 @@ import (
func TestDecodeFlags(t *testing.T) {
// Setup
flags := map[string]string{
"--providers-google-client-id": "google-client-id",
"--providers-google-client-secret": "google-client-secret",
"--providers-my-github-client-id": "github-client-id",
"--providers-my-github-client-secret": "github-client-secret",
args := []string{
"--providers-google-clientid=google-client-id",
"--providers-google-clientsecret=google-client-secret",
"--providers-github-clientid=github-client-id",
"--providers-github-clientsecret=github-client-secret",
}
expected := config.Providers{
@@ -23,7 +23,7 @@ func TestDecodeFlags(t *testing.T) {
ClientID: "google-client-id",
ClientSecret: "google-client-secret",
},
"myGithub": {
"github": {
ClientID: "github-client-id",
ClientSecret: "github-client-secret",
},
@@ -31,7 +31,7 @@ func TestDecodeFlags(t *testing.T) {
}
// Execute
result, err := decoders.DecodeFlags[config.Providers, config.OAuthServiceConfig](flags, "providers")
result, err := decoders.DecodeFlags[config.Providers](args)
assert.NilError(t, err)
assert.DeepEqual(t, result, expected)
}

View File

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

View File

@@ -9,7 +9,24 @@ import (
)
func TestDecodeLabels(t *testing.T) {
// Variables
// Setup
labels := 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",
}
expected := config.Apps{
Apps: map[string]config.App{
"foo": {
@@ -44,25 +61,9 @@ func TestDecodeLabels(t *testing.T) {
},
},
}
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)
result, err := decoders.DecodeLabels[config.Apps](labels)
assert.NilError(t, err)
assert.DeepEqual(t, expected, result)
}