2021-11-30 11:15:21 +00:00
|
|
|
package configuration
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/mail"
|
2022-03-16 05:16:46 +00:00
|
|
|
"net/url"
|
2021-11-30 11:15:21 +00:00
|
|
|
"reflect"
|
2022-04-01 11:38:49 +00:00
|
|
|
"regexp"
|
2022-03-02 06:40:26 +00:00
|
|
|
"time"
|
2021-11-30 11:15:21 +00:00
|
|
|
|
|
|
|
"github.com/mitchellh/mapstructure"
|
2022-03-02 06:40:26 +00:00
|
|
|
|
|
|
|
"github.com/authelia/authelia/v4/internal/utils"
|
2021-11-30 11:15:21 +00:00
|
|
|
)
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
// StringToMailAddressHookFunc decodes a string into a mail.Address or *mail.Address.
|
2022-03-16 05:16:46 +00:00
|
|
|
func StringToMailAddressHookFunc() mapstructure.DecodeHookFuncType {
|
2022-01-15 02:01:40 +00:00
|
|
|
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
2022-04-03 12:44:52 +00:00
|
|
|
var ptr bool
|
|
|
|
|
|
|
|
if f.Kind() != reflect.String {
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
kindStr := "mail.Address (RFC5322)"
|
|
|
|
|
|
|
|
if t.Kind() == reflect.Ptr {
|
|
|
|
ptr = true
|
|
|
|
kindStr = "*" + kindStr
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedType := reflect.TypeOf(mail.Address{})
|
|
|
|
|
|
|
|
if ptr && t.Elem() != expectedType {
|
|
|
|
return data, nil
|
|
|
|
} else if !ptr && t != expectedType {
|
2021-11-30 11:15:21 +00:00
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
dataStr := data.(string)
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
var result *mail.Address
|
|
|
|
|
|
|
|
if dataStr != "" {
|
|
|
|
if result, err = mail.ParseAddress(dataStr); err != nil {
|
|
|
|
return nil, fmt.Errorf(errFmtDecodeHookCouldNotParse, dataStr, kindStr, err)
|
|
|
|
}
|
2021-11-30 11:15:21 +00:00
|
|
|
}
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
if ptr {
|
|
|
|
return result, nil
|
|
|
|
}
|
2021-11-30 11:15:21 +00:00
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
if result == nil {
|
|
|
|
return mail.Address{}, nil
|
2021-11-30 11:15:21 +00:00
|
|
|
}
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
return *result, nil
|
2021-11-30 11:15:21 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-02 06:40:26 +00:00
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
// StringToURLHookFunc converts string types into a url.URL or *url.URL.
|
2022-03-16 05:16:46 +00:00
|
|
|
func StringToURLHookFunc() mapstructure.DecodeHookFuncType {
|
2022-03-02 06:40:26 +00:00
|
|
|
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
2022-03-16 05:16:46 +00:00
|
|
|
var ptr bool
|
|
|
|
|
|
|
|
if f.Kind() != reflect.String {
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
kindStr := "url.URL"
|
2022-03-16 05:16:46 +00:00
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
if t.Kind() == reflect.Ptr {
|
|
|
|
ptr = true
|
|
|
|
kindStr = "*" + kindStr
|
|
|
|
}
|
2022-03-16 05:16:46 +00:00
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
expectedType := reflect.TypeOf(url.URL{})
|
|
|
|
|
|
|
|
if ptr && t.Elem() != expectedType {
|
2022-03-16 05:16:46 +00:00
|
|
|
return data, nil
|
2022-04-03 12:44:52 +00:00
|
|
|
} else if !ptr && t != expectedType {
|
2022-03-16 05:16:46 +00:00
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
dataStr := data.(string)
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
var result *url.URL
|
2022-03-16 05:16:46 +00:00
|
|
|
|
|
|
|
if dataStr != "" {
|
2022-04-03 12:44:52 +00:00
|
|
|
if result, err = url.Parse(dataStr); err != nil {
|
|
|
|
return nil, fmt.Errorf(errFmtDecodeHookCouldNotParse, dataStr, kindStr, err)
|
2022-03-16 05:16:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ptr {
|
2022-04-03 12:44:52 +00:00
|
|
|
return result, nil
|
2022-03-16 05:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
if result == nil {
|
2022-03-16 05:16:46 +00:00
|
|
|
return url.URL{}, nil
|
|
|
|
}
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
return *result, nil
|
2022-03-16 05:16:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 06:40:26 +00: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
|
|
|
|
}
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
kindStr := "time.Duration"
|
2022-03-02 06:40:26 +00:00
|
|
|
|
|
|
|
if t.Kind() == reflect.Ptr {
|
|
|
|
ptr = true
|
2022-04-03 12:44:52 +00:00
|
|
|
kindStr = "*" + kindStr
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedType := reflect.TypeOf(time.Duration(0))
|
|
|
|
|
|
|
|
if ptr && t.Elem() != expectedType {
|
|
|
|
return data, nil
|
|
|
|
} else if !ptr && t != expectedType {
|
2022-03-02 06:40:26 +00:00
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
var result time.Duration
|
2022-03-02 06:40:26 +00:00
|
|
|
|
|
|
|
switch {
|
|
|
|
case f.Kind() == reflect.String:
|
2022-03-05 05:51:41 +00:00
|
|
|
dataStr := data.(string)
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
if result, err = utils.ParseDurationString(dataStr); err != nil {
|
|
|
|
return nil, fmt.Errorf(errFmtDecodeHookCouldNotParse, dataStr, kindStr, err)
|
2022-03-05 05:51:41 +00:00
|
|
|
}
|
2022-03-02 06:40:26 +00:00
|
|
|
case f.Kind() == reflect.Int:
|
|
|
|
seconds := data.(int)
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
result = time.Second * time.Duration(seconds)
|
2022-03-02 06:40:26 +00:00
|
|
|
case f.Kind() == reflect.Int32:
|
|
|
|
seconds := data.(int32)
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
result = time.Second * time.Duration(seconds)
|
|
|
|
case f == expectedType:
|
|
|
|
result = data.(time.Duration)
|
2022-03-02 06:40:26 +00:00
|
|
|
case f.Kind() == reflect.Int64:
|
|
|
|
seconds := data.(int64)
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
result = time.Second * time.Duration(seconds)
|
2022-03-02 06:40:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ptr {
|
2022-04-03 12:44:52 +00:00
|
|
|
return &result, nil
|
2022-03-02 06:40:26 +00:00
|
|
|
}
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
return result, nil
|
2022-03-02 06:40:26 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-01 11:38:49 +00:00
|
|
|
|
2022-06-01 23:18:45 +00:00
|
|
|
// StringToRegexpHookFunc decodes a string into a *regexp.Regexp or regexp.Regexp.
|
|
|
|
func StringToRegexpHookFunc() mapstructure.DecodeHookFuncType {
|
2022-04-01 11:38:49 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
kindStr := "regexp.Regexp"
|
2022-04-01 11:38:49 +00:00
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
if t.Kind() == reflect.Ptr {
|
|
|
|
ptr = true
|
|
|
|
kindStr = "*" + kindStr
|
|
|
|
}
|
2022-04-01 11:38:49 +00:00
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
expectedType := reflect.TypeOf(regexp.Regexp{})
|
|
|
|
|
|
|
|
if ptr && t.Elem() != expectedType {
|
2022-04-01 11:38:49 +00:00
|
|
|
return data, nil
|
2022-04-03 12:44:52 +00:00
|
|
|
} else if !ptr && t != expectedType {
|
2022-04-01 11:38:49 +00:00
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
dataStr := data.(string)
|
|
|
|
|
|
|
|
var result *regexp.Regexp
|
2022-04-01 11:38:49 +00:00
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
if dataStr != "" {
|
|
|
|
if result, err = regexp.Compile(dataStr); err != nil {
|
|
|
|
return nil, fmt.Errorf(errFmtDecodeHookCouldNotParse, dataStr, kindStr, err)
|
|
|
|
}
|
2022-04-01 11:38:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ptr {
|
2022-04-03 12:44:52 +00:00
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if result == nil {
|
|
|
|
return nil, fmt.Errorf(errFmtDecodeHookCouldNotParseEmptyValue, kindStr, errDecodeNonPtrMustHaveValue)
|
2022-04-01 11:38:49 +00:00
|
|
|
}
|
|
|
|
|
2022-04-03 12:44:52 +00:00
|
|
|
return *result, nil
|
2022-04-01 11:38:49 +00:00
|
|
|
}
|
|
|
|
}
|