2021-11-30 18:15:21 +07:00
|
|
|
package configuration
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/mail"
|
2022-03-16 12:16:46 +07:00
|
|
|
"net/url"
|
2021-11-30 18:15:21 +07:00
|
|
|
"reflect"
|
2022-04-01 18:38:49 +07:00
|
|
|
"regexp"
|
2022-03-02 13:40:26 +07:00
|
|
|
"time"
|
2021-11-30 18:15:21 +07:00
|
|
|
|
|
|
|
"github.com/mitchellh/mapstructure"
|
2022-03-02 13:40:26 +07:00
|
|
|
|
|
|
|
"github.com/authelia/authelia/v4/internal/utils"
|
2021-11-30 18:15:21 +07:00
|
|
|
)
|
|
|
|
|
2022-03-16 12:16:46 +07:00
|
|
|
// StringToMailAddressHookFunc decodes a string into a mail.Address.
|
|
|
|
func StringToMailAddressHookFunc() mapstructure.DecodeHookFuncType {
|
2022-01-15 09:01:40 +07:00
|
|
|
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
|
|
|
if f.Kind() != reflect.String || t != reflect.TypeOf(mail.Address{}) {
|
2021-11-30 18:15:21 +07:00
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
dataStr := data.(string)
|
|
|
|
|
|
|
|
if dataStr == "" {
|
|
|
|
return mail.Address{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
2022-03-03 18:20:43 +07:00
|
|
|
parsedAddress *mail.Address
|
2021-11-30 18:15:21 +07:00
|
|
|
)
|
|
|
|
|
2022-03-03 18:20:43 +07:00
|
|
|
if parsedAddress, err = mail.ParseAddress(dataStr); err != nil {
|
2021-11-30 18:15:21 +07:00
|
|
|
return nil, fmt.Errorf("could not parse '%s' as a RFC5322 address: %w", dataStr, err)
|
|
|
|
}
|
|
|
|
|
2022-03-03 18:20:43 +07:00
|
|
|
return *parsedAddress, nil
|
2021-11-30 18:15:21 +07:00
|
|
|
}
|
|
|
|
}
|
2022-03-02 13:40:26 +07:00
|
|
|
|
2022-03-16 12:16:46 +07:00
|
|
|
// StringToURLHookFunc converts string types into a url.URL.
|
|
|
|
func StringToURLHookFunc() mapstructure.DecodeHookFuncType {
|
2022-03-02 13:40:26 +07:00
|
|
|
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
2022-03-16 12:16:46 +07:00
|
|
|
var ptr bool
|
|
|
|
|
|
|
|
if f.Kind() != reflect.String {
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = t.Kind() == reflect.Ptr
|
|
|
|
|
|
|
|
typeURL := reflect.TypeOf(url.URL{})
|
|
|
|
|
|
|
|
if ptr && t.Elem() != typeURL {
|
|
|
|
return data, nil
|
|
|
|
} else if !ptr && t != typeURL {
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
dataStr := data.(string)
|
|
|
|
|
|
|
|
var parsedURL *url.URL
|
|
|
|
|
|
|
|
// Return an empty URL if there is an empty string.
|
|
|
|
if dataStr != "" {
|
|
|
|
if parsedURL, err = url.Parse(dataStr); err != nil {
|
|
|
|
return nil, fmt.Errorf("could not parse '%s' as a URL: %w", dataStr, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ptr {
|
|
|
|
return parsedURL, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return an empty URL if there is an empty string.
|
|
|
|
if parsedURL == nil {
|
|
|
|
return url.URL{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return *parsedURL, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToTimeDurationHookFunc converts string and integer types to a time.Duration.
|
|
|
|
func ToTimeDurationHookFunc() mapstructure.DecodeHookFuncType {
|
|
|
|
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
|
|
|
var ptr bool
|
2022-03-02 13:40:26 +07:00
|
|
|
|
|
|
|
switch f.Kind() {
|
|
|
|
case reflect.String, reflect.Int, reflect.Int32, reflect.Int64:
|
|
|
|
// We only allow string and integer from kinds to match.
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
typeTimeDuration := reflect.TypeOf(time.Hour)
|
|
|
|
|
|
|
|
if t.Kind() == reflect.Ptr {
|
|
|
|
if t.Elem() != typeTimeDuration {
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = true
|
|
|
|
} else if t != typeTimeDuration {
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var duration time.Duration
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case f.Kind() == reflect.String:
|
2022-03-05 12:51:41 +07:00
|
|
|
dataStr := data.(string)
|
|
|
|
|
|
|
|
if duration, err = utils.ParseDurationString(dataStr); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-03-02 13:40:26 +07:00
|
|
|
case f.Kind() == reflect.Int:
|
|
|
|
seconds := data.(int)
|
|
|
|
|
|
|
|
duration = time.Second * time.Duration(seconds)
|
|
|
|
case f.Kind() == reflect.Int32:
|
|
|
|
seconds := data.(int32)
|
|
|
|
|
|
|
|
duration = time.Second * time.Duration(seconds)
|
|
|
|
case f == typeTimeDuration:
|
|
|
|
duration = data.(time.Duration)
|
|
|
|
case f.Kind() == reflect.Int64:
|
|
|
|
seconds := data.(int64)
|
|
|
|
|
|
|
|
duration = time.Second * time.Duration(seconds)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ptr {
|
|
|
|
return &duration, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return duration, nil
|
|
|
|
}
|
|
|
|
}
|
2022-04-01 18:38:49 +07:00
|
|
|
|
|
|
|
// StringToRegexpFunc decodes a string into a *regexp.Regexp or regexp.Regexp.
|
|
|
|
func StringToRegexpFunc() mapstructure.DecodeHookFuncType {
|
|
|
|
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
|
|
|
var ptr bool
|
|
|
|
|
|
|
|
if f.Kind() != reflect.String {
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = t.Kind() == reflect.Ptr
|
|
|
|
|
|
|
|
typeRegexp := reflect.TypeOf(regexp.Regexp{})
|
|
|
|
|
|
|
|
if ptr && t.Elem() != typeRegexp {
|
|
|
|
return data, nil
|
|
|
|
} else if !ptr && t != typeRegexp {
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
regexStr := data.(string)
|
|
|
|
|
|
|
|
pattern, err := regexp.Compile(regexStr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("could not parse '%s' as regexp: %w", regexStr, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ptr {
|
|
|
|
return pattern, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return *pattern, nil
|
|
|
|
}
|
|
|
|
}
|