2022-10-22 11:19:32 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2023-01-25 09:36:40 +00:00
|
|
|
"crypto/ecdsa"
|
|
|
|
"crypto/rsa"
|
2022-10-22 11:19:32 +00:00
|
|
|
"fmt"
|
2023-01-25 09:36:40 +00:00
|
|
|
"net/mail"
|
|
|
|
"net/url"
|
2022-10-22 11:19:32 +00:00
|
|
|
"path/filepath"
|
2023-01-25 09:36:40 +00:00
|
|
|
"reflect"
|
|
|
|
"regexp"
|
2022-10-22 11:19:32 +00:00
|
|
|
"strings"
|
2023-01-25 09:36:40 +00:00
|
|
|
"time"
|
2022-10-22 11:19:32 +00:00
|
|
|
|
|
|
|
"github.com/spf13/pflag"
|
2023-01-25 09:36:40 +00:00
|
|
|
|
|
|
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
2022-10-22 11:19:32 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func getPFlagPath(flags *pflag.FlagSet, flagNames ...string) (fullPath string, err error) {
|
|
|
|
if len(flagNames) == 0 {
|
|
|
|
return "", fmt.Errorf("no flag names")
|
|
|
|
}
|
|
|
|
|
|
|
|
var p string
|
|
|
|
|
|
|
|
for i, flagName := range flagNames {
|
|
|
|
if p, err = flags.GetString(flagName); err != nil {
|
|
|
|
return "", fmt.Errorf("failed to lookup flag '%s': %w", flagName, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if i == 0 {
|
|
|
|
fullPath = p
|
|
|
|
} else {
|
|
|
|
fullPath = filepath.Join(fullPath, p)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return fullPath, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func buildCSP(defaultSrc string, ruleSets ...[]CSPValue) string {
|
|
|
|
var rules []string
|
|
|
|
|
|
|
|
for _, ruleSet := range ruleSets {
|
|
|
|
for _, rule := range ruleSet {
|
|
|
|
switch rule.Name {
|
|
|
|
case "default-src":
|
|
|
|
rules = append(rules, fmt.Sprintf("%s %s", rule.Name, defaultSrc))
|
|
|
|
default:
|
|
|
|
rules = append(rules, fmt.Sprintf("%s %s", rule.Name, rule.Value))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.Join(rules, "; ")
|
|
|
|
}
|
2023-01-25 09:36:40 +00:00
|
|
|
|
|
|
|
var decodedTypes = []reflect.Type{
|
|
|
|
reflect.TypeOf(mail.Address{}),
|
|
|
|
reflect.TypeOf(regexp.Regexp{}),
|
|
|
|
reflect.TypeOf(url.URL{}),
|
|
|
|
reflect.TypeOf(time.Duration(0)),
|
|
|
|
reflect.TypeOf(schema.Address{}),
|
|
|
|
reflect.TypeOf(schema.X509CertificateChain{}),
|
|
|
|
reflect.TypeOf(schema.PasswordDigest{}),
|
|
|
|
reflect.TypeOf(rsa.PrivateKey{}),
|
|
|
|
reflect.TypeOf(ecdsa.PrivateKey{}),
|
|
|
|
}
|
|
|
|
|
|
|
|
func containsType(needle reflect.Type, haystack []reflect.Type) (contains bool) {
|
|
|
|
for _, t := range haystack {
|
|
|
|
if needle.Kind() == reflect.Ptr {
|
|
|
|
if needle.Elem() == t {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
} else if needle == t {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
//nolint:gocyclo
|
|
|
|
func readTags(prefix string, t reflect.Type) (tags []string) {
|
|
|
|
tags = make([]string, 0)
|
|
|
|
|
|
|
|
if t.Kind() != reflect.Struct {
|
|
|
|
if t.Kind() == reflect.Slice {
|
|
|
|
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, "", true, false), t.Elem())...)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < t.NumField(); i++ {
|
|
|
|
field := t.Field(i)
|
|
|
|
|
|
|
|
tag := field.Tag.Get("koanf")
|
|
|
|
|
|
|
|
if tag == "" {
|
|
|
|
tags = append(tags, prefix)
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
switch kind := field.Type.Kind(); kind {
|
|
|
|
case reflect.Struct:
|
|
|
|
if !containsType(field.Type, decodedTypes) {
|
|
|
|
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, false, false), field.Type)...)
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
case reflect.Slice, reflect.Map:
|
|
|
|
switch field.Type.Elem().Kind() {
|
|
|
|
case reflect.Struct:
|
|
|
|
if !containsType(field.Type.Elem(), decodedTypes) {
|
|
|
|
tags = append(tags, getKeyNameFromTagAndPrefix(prefix, tag, false, false))
|
|
|
|
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, kind == reflect.Slice, kind == reflect.Map), field.Type.Elem())...)
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
case reflect.Slice:
|
|
|
|
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, kind == reflect.Slice, kind == reflect.Map), field.Type.Elem())...)
|
|
|
|
}
|
|
|
|
case reflect.Ptr:
|
|
|
|
switch field.Type.Elem().Kind() {
|
|
|
|
case reflect.Struct:
|
|
|
|
if !containsType(field.Type.Elem(), decodedTypes) {
|
|
|
|
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, false, false), field.Type.Elem())...)
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
case reflect.Slice:
|
|
|
|
if field.Type.Elem().Elem().Kind() == reflect.Struct {
|
|
|
|
if !containsType(field.Type.Elem(), decodedTypes) {
|
|
|
|
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, true, false), field.Type.Elem())...)
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tags = append(tags, getKeyNameFromTagAndPrefix(prefix, tag, false, false))
|
|
|
|
}
|
|
|
|
|
|
|
|
return tags
|
|
|
|
}
|
|
|
|
|
|
|
|
func getKeyNameFromTagAndPrefix(prefix, name string, isSlice, isMap bool) string {
|
|
|
|
nameParts := strings.SplitN(name, ",", 2)
|
|
|
|
|
|
|
|
if prefix == "" {
|
|
|
|
return nameParts[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(nameParts) == 2 && nameParts[1] == "squash" {
|
|
|
|
return prefix
|
|
|
|
}
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case isMap:
|
|
|
|
if name == "" {
|
|
|
|
return fmt.Sprintf("%s.*", prefix)
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("%s.%s.*", prefix, nameParts[0])
|
|
|
|
case isSlice:
|
|
|
|
if name == "" {
|
|
|
|
return fmt.Sprintf("%s[]", prefix)
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("%s.%s[]", prefix, nameParts[0])
|
|
|
|
default:
|
|
|
|
return fmt.Sprintf("%s.%s", prefix, nameParts[0])
|
|
|
|
}
|
|
|
|
}
|