2022-04-16 09:00:39 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/mail"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"reflect"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
"text/template"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
|
|
|
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
|
|
)
|
|
|
|
|
|
|
|
// NewRunGenCmd implements the code generation cobra command.
|
|
|
|
func NewRunGenCmd() (cmd *cobra.Command) {
|
|
|
|
cmd = &cobra.Command{
|
|
|
|
Use: "gen",
|
|
|
|
RunE: runGenE,
|
|
|
|
}
|
|
|
|
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func runGenE(cmd *cobra.Command, args []string) (err error) {
|
|
|
|
if err = genConfigurationKeys(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func genConfigurationKeys() (err error) {
|
|
|
|
data := loadKeysTemplate()
|
|
|
|
|
|
|
|
f, err := os.Create("./internal/configuration/schema/keys.go")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return keysTemplate.Execute(f, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
var keysTemplate = template.Must(template.New("keys").Parse(`// Code generated by go generate. DO NOT EDIT.
|
|
|
|
//
|
|
|
|
// Run the following command to generate this file:
|
|
|
|
// go run ./cmd/authelia-scripts gen
|
|
|
|
//
|
|
|
|
|
|
|
|
package schema
|
|
|
|
|
|
|
|
// Keys represents the detected schema keys.
|
|
|
|
var Keys = []string{
|
|
|
|
{{- range .Keys }}
|
|
|
|
{{ printf "%q" . }},
|
|
|
|
{{- end }}
|
|
|
|
}
|
|
|
|
`))
|
|
|
|
|
|
|
|
type keysTemplateStruct struct {
|
|
|
|
Timestamp time.Time
|
|
|
|
Keys []string
|
|
|
|
}
|
|
|
|
|
|
|
|
func loadKeysTemplate() keysTemplateStruct {
|
|
|
|
config := schema.Configuration{
|
|
|
|
Storage: schema.StorageConfiguration{
|
|
|
|
Local: &schema.LocalStorageConfiguration{},
|
|
|
|
MySQL: &schema.MySQLStorageConfiguration{},
|
|
|
|
PostgreSQL: &schema.PostgreSQLStorageConfiguration{},
|
|
|
|
},
|
|
|
|
Notifier: schema.NotifierConfiguration{
|
|
|
|
FileSystem: &schema.FileSystemNotifierConfiguration{},
|
|
|
|
SMTP: &schema.SMTPNotifierConfiguration{
|
|
|
|
TLS: &schema.TLSConfig{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
AuthenticationBackend: schema.AuthenticationBackendConfiguration{
|
|
|
|
File: &schema.FileAuthenticationBackendConfiguration{
|
|
|
|
Password: &schema.PasswordConfiguration{},
|
|
|
|
},
|
|
|
|
LDAP: &schema.LDAPAuthenticationBackendConfiguration{
|
|
|
|
TLS: &schema.TLSConfig{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Session: schema.SessionConfiguration{
|
|
|
|
Redis: &schema.RedisSessionConfiguration{
|
|
|
|
TLS: &schema.TLSConfig{},
|
|
|
|
HighAvailability: &schema.RedisHighAvailabilityConfiguration{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
IdentityProviders: schema.IdentityProvidersConfiguration{
|
|
|
|
OIDC: &schema.OpenIDConnectConfiguration{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
return keysTemplateStruct{
|
|
|
|
Timestamp: time.Now(),
|
|
|
|
Keys: readTags("", reflect.TypeOf(config)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var decodedTypes = []reflect.Type{
|
|
|
|
reflect.TypeOf(mail.Address{}),
|
|
|
|
reflect.TypeOf(regexp.Regexp{}),
|
|
|
|
reflect.TypeOf(url.URL{}),
|
|
|
|
reflect.TypeOf(time.Duration(0)),
|
2022-06-14 07:20:13 +00:00
|
|
|
reflect.TypeOf(schema.Address{}),
|
2022-04-16 09:00:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
func readTags(prefix string, t reflect.Type) (tags []string) {
|
|
|
|
tags = make([]string, 0)
|
|
|
|
|
|
|
|
for i := 0; i < t.NumField(); i++ {
|
|
|
|
field := t.Field(i)
|
|
|
|
|
|
|
|
tag := field.Tag.Get("koanf")
|
|
|
|
|
|
|
|
if tag == "" {
|
|
|
|
tags = append(tags, prefix)
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
switch field.Type.Kind() {
|
|
|
|
case reflect.Struct:
|
|
|
|
if !containsType(field.Type, decodedTypes) {
|
|
|
|
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, false), field.Type)...)
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
case reflect.Slice:
|
|
|
|
if field.Type.Elem().Kind() == reflect.Struct {
|
|
|
|
if !containsType(field.Type.Elem(), decodedTypes) {
|
|
|
|
tags = append(tags, getKeyNameFromTagAndPrefix(prefix, tag, false))
|
|
|
|
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, true), field.Type.Elem())...)
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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), 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), field.Type.Elem())...)
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tags = append(tags, getKeyNameFromTagAndPrefix(prefix, tag, false))
|
|
|
|
}
|
|
|
|
|
|
|
|
return tags
|
|
|
|
}
|
|
|
|
|
|
|
|
func getKeyNameFromTagAndPrefix(prefix, name string, slice bool) string {
|
|
|
|
nameParts := strings.SplitN(name, ",", 2)
|
|
|
|
|
|
|
|
if prefix == "" {
|
|
|
|
return nameParts[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(nameParts) == 2 && nameParts[1] == "squash" {
|
|
|
|
return prefix
|
|
|
|
}
|
|
|
|
|
|
|
|
if slice {
|
|
|
|
return fmt.Sprintf("%s.%s[]", prefix, nameParts[0])
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("%s.%s", prefix, nameParts[0])
|
|
|
|
}
|