2021-08-03 09:55:21 +00:00
|
|
|
package configuration
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/knadh/koanf"
|
|
|
|
"github.com/mitchellh/mapstructure"
|
|
|
|
|
2021-08-11 01:04:35 +00:00
|
|
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
2021-08-03 09:55:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Load the configuration given the provided options and sources.
|
|
|
|
func Load(val *schema.StructValidator, sources ...Source) (keys []string, configuration *schema.Configuration, err error) {
|
2021-11-23 09:45:38 +00:00
|
|
|
configuration = &schema.Configuration{}
|
|
|
|
|
|
|
|
keys, err = LoadAdvanced(val, "", configuration, sources...)
|
|
|
|
|
|
|
|
return keys, configuration, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// LoadAdvanced is intended to give more flexibility over loading a particular path to a specific interface.
|
|
|
|
func LoadAdvanced(val *schema.StructValidator, path string, result interface{}, sources ...Source) (keys []string, err error) {
|
2021-08-03 09:55:21 +00:00
|
|
|
if val == nil {
|
2021-11-23 09:45:38 +00:00
|
|
|
return keys, errNoValidator
|
2021-08-03 09:55:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ko := koanf.NewWithConf(koanf.Conf{
|
|
|
|
Delim: constDelimiter,
|
|
|
|
StrictMerge: false,
|
|
|
|
})
|
|
|
|
|
2022-06-28 03:15:50 +00:00
|
|
|
if err = loadSources(ko, val, sources...); err != nil {
|
2021-11-23 09:45:38 +00:00
|
|
|
return ko.Keys(), err
|
2021-08-03 09:55:21 +00:00
|
|
|
}
|
|
|
|
|
2022-06-28 03:15:50 +00:00
|
|
|
var final *koanf.Koanf
|
2021-08-03 09:55:21 +00:00
|
|
|
|
2022-06-28 03:15:50 +00:00
|
|
|
if final, err = koanfRemapKeys(val, ko, deprecations); err != nil {
|
|
|
|
return koanfGetKeys(ko), err
|
|
|
|
}
|
|
|
|
|
|
|
|
unmarshal(final, val, path, result)
|
|
|
|
|
|
|
|
return koanfGetKeys(final), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func mapHasKey(k string, m map[string]interface{}) bool {
|
|
|
|
if _, ok := m[k]; ok {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
2021-08-03 09:55:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func unmarshal(ko *koanf.Koanf, val *schema.StructValidator, path string, o interface{}) {
|
|
|
|
c := koanf.UnmarshalConf{
|
|
|
|
DecoderConfig: &mapstructure.DecoderConfig{
|
|
|
|
DecodeHook: mapstructure.ComposeDecodeHookFunc(
|
|
|
|
mapstructure.StringToSliceHookFunc(","),
|
2022-03-16 05:16:46 +00:00
|
|
|
StringToMailAddressHookFunc(),
|
|
|
|
StringToURLHookFunc(),
|
2022-06-01 23:18:45 +00:00
|
|
|
StringToRegexpHookFunc(),
|
2022-06-14 07:20:13 +00:00
|
|
|
StringToAddressHookFunc(),
|
2022-10-02 02:07:40 +00:00
|
|
|
StringToX509CertificateHookFunc(),
|
|
|
|
StringToX509CertificateChainHookFunc(),
|
2022-10-03 00:52:29 +00:00
|
|
|
StringToPrivateKeyHookFunc(),
|
2022-06-01 23:18:45 +00:00
|
|
|
ToTimeDurationHookFunc(),
|
2021-08-03 09:55:21 +00:00
|
|
|
),
|
|
|
|
Metadata: nil,
|
|
|
|
Result: o,
|
|
|
|
WeaklyTypedInput: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ko.UnmarshalWithConf(path, o, c); err != nil {
|
|
|
|
val.Push(fmt.Errorf("error occurred during unmarshalling configuration: %w", err))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func loadSources(ko *koanf.Koanf, val *schema.StructValidator, sources ...Source) (err error) {
|
|
|
|
if len(sources) == 0 {
|
|
|
|
return errNoSources
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, source := range sources {
|
|
|
|
err := source.Load(val)
|
|
|
|
if err != nil {
|
|
|
|
val.Push(fmt.Errorf("failed to load configuration from %s source: %+v", source.Name(), err))
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
err = source.Merge(ko, val)
|
|
|
|
if err != nil {
|
|
|
|
val.Push(fmt.Errorf("failed to merge configuration from %s source: %+v", source.Name(), err))
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|