authelia/internal/configuration/decode_hooks.go
James Elliott 6276883f04
refactor(configuration): utilize time duration decode hook (#2938)
This enhances the existing time.Duration parser to allow multiple units, and implements a decode hook which can be used by koanf to decode string/integers into time.Durations as applicable.
2022-03-02 17:40:26 +11:00

103 lines
2.1 KiB
Go

package configuration
import (
"fmt"
"net/mail"
"reflect"
"time"
"github.com/mitchellh/mapstructure"
"github.com/authelia/authelia/v4/internal/utils"
)
// StringToMailAddressFunc decodes a string into a mail.Address.
func StringToMailAddressFunc() mapstructure.DecodeHookFunc {
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
if f.Kind() != reflect.String || t != reflect.TypeOf(mail.Address{}) {
return data, nil
}
dataStr := data.(string)
if dataStr == "" {
return mail.Address{}, nil
}
var (
mailAddress *mail.Address
)
mailAddress, err = mail.ParseAddress(dataStr)
if err != nil {
return nil, fmt.Errorf("could not parse '%s' as a RFC5322 address: %w", dataStr, err)
}
return *mailAddress, nil
}
}
// ToTimeDurationFunc converts string and integer types to a time.Duration.
func ToTimeDurationFunc() mapstructure.DecodeHookFuncType {
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
var (
ptr bool
)
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:
break
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 duration == 0 {
dataStr := data.(string)
if duration, err = utils.ParseDurationString(dataStr); err != nil {
return nil, err
}
}
if ptr {
return &duration, nil
}
return duration, nil
}
}