mirror of
https://github.com/unmojang/drasl.git
synced 2025-08-03 19:06:04 -04:00
Defaults for array-of-tables config settings
Due to https://github.com/BurntSushi/toml/issues/169, we can't simply use IsDefined to check whether a user supplied a config value in an array of tables, as in: [[FallbackAPIServers]] CacheTTLSeconds = 123 We can work around this by using *T instead of T in the config file schema. If the TOML key is not set, it will be parsed as nil.
This commit is contained in:
parent
30ba03adf4
commit
3ed22110b3
338
config.go
338
config.go
@ -15,6 +15,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -28,14 +29,36 @@ type bodyLimitConfig struct {
|
||||
SizeLimitKiB int
|
||||
}
|
||||
|
||||
type rawFallbackAPIServerConfig struct {
|
||||
Nickname *string
|
||||
SessionURL *string
|
||||
AccountURL *string
|
||||
ServicesURL *string
|
||||
SkinDomains *[]string
|
||||
CacheTTLSeconds *int
|
||||
DenyUnknownUsers *bool
|
||||
EnableAuthentication *bool
|
||||
}
|
||||
|
||||
type FallbackAPIServerConfig struct {
|
||||
Nickname string
|
||||
SessionURL string
|
||||
AccountURL string
|
||||
ServicesURL string
|
||||
SkinDomains []string
|
||||
CacheTTLSeconds int
|
||||
DenyUnknownUsers bool
|
||||
Nickname string
|
||||
SessionURL string
|
||||
AccountURL string
|
||||
ServicesURL string
|
||||
SkinDomains []string
|
||||
CacheTTLSeconds int
|
||||
DenyUnknownUsers bool
|
||||
EnableAuthentication bool
|
||||
}
|
||||
|
||||
type rawRegistrationOIDCConfig struct {
|
||||
Name *string
|
||||
Issuer *string
|
||||
ClientID *string
|
||||
ClientSecret *string
|
||||
PKCE *bool
|
||||
RequireInvite *bool
|
||||
AllowChoosingPlayerName *bool
|
||||
}
|
||||
|
||||
type RegistrationOIDCConfig struct {
|
||||
@ -92,7 +115,7 @@ type importExistingPlayerConfig struct {
|
||||
RequireSkinVerification bool
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
type BaseConfig struct {
|
||||
AllowCapes bool
|
||||
AllowChangingPlayerName bool
|
||||
AllowMultipleAccessTokens bool
|
||||
@ -114,14 +137,12 @@ type Config struct {
|
||||
EnableBackgroundEffect bool
|
||||
EnableFooter bool
|
||||
EnableWebFrontEnd bool
|
||||
FallbackAPIServers []FallbackAPIServerConfig
|
||||
ForwardSkins bool
|
||||
InstanceName string
|
||||
ImportExistingPlayer importExistingPlayerConfig
|
||||
ListenAddress string
|
||||
LogRequests bool
|
||||
MinPasswordLength int
|
||||
RegistrationOIDC []RegistrationOIDCConfig
|
||||
PreMigrationBackups bool
|
||||
RateLimit rateLimitConfig
|
||||
RegistrationExistingPlayer registrationExistingPlayerConfig
|
||||
@ -137,6 +158,18 @@ type Config struct {
|
||||
ValidPlayerNameRegex string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
BaseConfig
|
||||
FallbackAPIServers []FallbackAPIServerConfig
|
||||
RegistrationOIDC []RegistrationOIDCConfig
|
||||
}
|
||||
|
||||
type RawConfig struct {
|
||||
BaseConfig
|
||||
FallbackAPIServers []rawFallbackAPIServerConfig
|
||||
RegistrationOIDC []rawRegistrationOIDCConfig
|
||||
}
|
||||
|
||||
var defaultRateLimitConfig = rateLimitConfig{
|
||||
Enable: true,
|
||||
RequestsPerSecond: 5,
|
||||
@ -153,63 +186,118 @@ var DefaultRistrettoConfig = &ristretto.Config{
|
||||
BufferItems: 64,
|
||||
}
|
||||
|
||||
func DefaultRawConfig() RawConfig {
|
||||
return RawConfig{
|
||||
BaseConfig: BaseConfig{
|
||||
AllowCapes: true,
|
||||
AllowChangingPlayerName: true,
|
||||
AllowPasswordLogin: true,
|
||||
AllowSkins: true,
|
||||
AllowTextureFromURL: false,
|
||||
AllowAddingDeletingPlayers: false,
|
||||
ApplicationName: "Drasl",
|
||||
ApplicationOwner: "Anonymous",
|
||||
BaseURL: "",
|
||||
BodyLimit: defaultBodyLimitConfig,
|
||||
CORSAllowOrigins: []string{},
|
||||
CreateNewPlayer: createNewPlayerConfig{
|
||||
Allow: true,
|
||||
AllowChoosingUUID: false,
|
||||
},
|
||||
DataDirectory: GetDefaultDataDirectory(),
|
||||
DefaultAdmins: []string{},
|
||||
DefaultPreferredLanguage: "en",
|
||||
DefaultMaxPlayerCount: 1,
|
||||
Domain: "",
|
||||
EnableBackgroundEffect: true,
|
||||
EnableFooter: true,
|
||||
EnableWebFrontEnd: true,
|
||||
ForwardSkins: true,
|
||||
ImportExistingPlayer: importExistingPlayerConfig{
|
||||
Allow: false,
|
||||
},
|
||||
InstanceName: "Drasl",
|
||||
ListenAddress: "0.0.0.0:25585",
|
||||
LogRequests: true,
|
||||
MinPasswordLength: 8,
|
||||
OfflineSkins: true,
|
||||
PreMigrationBackups: true,
|
||||
RateLimit: defaultRateLimitConfig,
|
||||
RegistrationExistingPlayer: registrationExistingPlayerConfig{
|
||||
Allow: false,
|
||||
},
|
||||
RegistrationNewPlayer: registrationNewPlayerConfig{
|
||||
Allow: true,
|
||||
RequireInvite: false,
|
||||
},
|
||||
RequestCache: *DefaultRistrettoConfig,
|
||||
SignPublicKeys: true,
|
||||
SkinSizeLimit: 64,
|
||||
StateDirectory: GetDefaultStateDirectory(),
|
||||
TokenExpireSec: 0,
|
||||
TokenStaleSec: 0,
|
||||
TransientUsers: transientUsersConfig{
|
||||
Allow: false,
|
||||
},
|
||||
ValidPlayerNameRegex: "^[a-zA-Z0-9_]+$",
|
||||
},
|
||||
FallbackAPIServers: []rawFallbackAPIServerConfig{},
|
||||
RegistrationOIDC: []rawRegistrationOIDCConfig{},
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultConfig() Config {
|
||||
return Config{
|
||||
AllowCapes: true,
|
||||
AllowChangingPlayerName: true,
|
||||
AllowPasswordLogin: true,
|
||||
AllowSkins: true,
|
||||
AllowTextureFromURL: false,
|
||||
AllowAddingDeletingPlayers: false,
|
||||
ApplicationName: "Drasl",
|
||||
ApplicationOwner: "Anonymous",
|
||||
BaseURL: "",
|
||||
BodyLimit: defaultBodyLimitConfig,
|
||||
CORSAllowOrigins: []string{},
|
||||
CreateNewPlayer: createNewPlayerConfig{
|
||||
Allow: true,
|
||||
AllowChoosingUUID: false,
|
||||
},
|
||||
DataDirectory: GetDefaultDataDirectory(),
|
||||
DefaultAdmins: []string{},
|
||||
DefaultPreferredLanguage: "en",
|
||||
DefaultMaxPlayerCount: 1,
|
||||
Domain: "",
|
||||
EnableBackgroundEffect: true,
|
||||
EnableFooter: true,
|
||||
EnableWebFrontEnd: true,
|
||||
ForwardSkins: true,
|
||||
ImportExistingPlayer: importExistingPlayerConfig{
|
||||
Allow: false,
|
||||
},
|
||||
InstanceName: "Drasl",
|
||||
ListenAddress: "0.0.0.0:25585",
|
||||
LogRequests: true,
|
||||
MinPasswordLength: 8,
|
||||
RegistrationOIDC: []RegistrationOIDCConfig{},
|
||||
OfflineSkins: true,
|
||||
PreMigrationBackups: true,
|
||||
RateLimit: defaultRateLimitConfig,
|
||||
RegistrationExistingPlayer: registrationExistingPlayerConfig{
|
||||
Allow: false,
|
||||
},
|
||||
RegistrationNewPlayer: registrationNewPlayerConfig{
|
||||
Allow: true,
|
||||
RequireInvite: false,
|
||||
},
|
||||
RequestCache: *DefaultRistrettoConfig,
|
||||
SignPublicKeys: true,
|
||||
SkinSizeLimit: 64,
|
||||
StateDirectory: GetDefaultStateDirectory(),
|
||||
TokenExpireSec: 0,
|
||||
TokenStaleSec: 0,
|
||||
TransientUsers: transientUsersConfig{
|
||||
Allow: false,
|
||||
},
|
||||
ValidPlayerNameRegex: "^[a-zA-Z0-9_]+$",
|
||||
BaseConfig: DefaultRawConfig().BaseConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultFallbackAPIServer() FallbackAPIServerConfig {
|
||||
return FallbackAPIServerConfig{
|
||||
CacheTTLSeconds: 600,
|
||||
DenyUnknownUsers: false,
|
||||
EnableAuthentication: true,
|
||||
SkinDomains: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultRegistrationOIDC() RegistrationOIDCConfig {
|
||||
return RegistrationOIDCConfig{
|
||||
AllowChoosingPlayerName: true,
|
||||
PKCE: true,
|
||||
RequireInvite: false,
|
||||
}
|
||||
}
|
||||
|
||||
func AssignConfig[Res, Raw any](defaults Res, raw Raw) Res {
|
||||
configType := reflect.TypeOf(defaults)
|
||||
|
||||
rawValue := reflect.ValueOf(raw)
|
||||
defaultsValue := reflect.ValueOf(defaults)
|
||||
|
||||
out := new(Res)
|
||||
outValue := reflect.ValueOf(out).Elem()
|
||||
|
||||
for i := 0; i < configType.NumField(); i += 1 {
|
||||
key := configType.Field(i).Name
|
||||
|
||||
rawField := rawValue.FieldByName(key)
|
||||
if rawField == (reflect.Value{}) {
|
||||
continue
|
||||
}
|
||||
|
||||
outField := outValue.FieldByName(key)
|
||||
if rawField.IsNil() {
|
||||
outField.Set(defaultsValue.FieldByName(key))
|
||||
} else {
|
||||
rawField := rawValue.FieldByName(key).Elem()
|
||||
outField.Set(rawField)
|
||||
}
|
||||
}
|
||||
|
||||
return *out
|
||||
}
|
||||
|
||||
func cleanURL(key string, required mo.Option[string], urlString string, trimTrailingSlash bool) (string, error) {
|
||||
if urlString == "" {
|
||||
if example, ok := required.Get(); ok {
|
||||
@ -250,19 +338,22 @@ func cleanDomain(key string, required mo.Option[string], domain string) (string,
|
||||
return punycoded, nil
|
||||
}
|
||||
|
||||
func CleanConfig(config *Config) error {
|
||||
func CleanConfig(rawConfig *RawConfig) (Config, error) {
|
||||
config := Config{}
|
||||
config.BaseConfig = rawConfig.BaseConfig
|
||||
|
||||
var err error
|
||||
config.BaseURL, err = cleanURL("BaseURL", mo.Some("https://drasl.example.com"), config.BaseURL, true)
|
||||
if err != nil {
|
||||
return err
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
if !IsValidPreferredLanguage(config.DefaultPreferredLanguage) {
|
||||
return fmt.Errorf("Invalid DefaultPreferredLanguage %s", config.DefaultPreferredLanguage)
|
||||
return Config{}, fmt.Errorf("Invalid DefaultPreferredLanguage %s", config.DefaultPreferredLanguage)
|
||||
}
|
||||
|
||||
if config.Domain == "" {
|
||||
return errors.New("Domain must be set to a valid fully qualified domain name")
|
||||
return Config{}, errors.New("Domain must be set to a valid fully qualified domain name")
|
||||
}
|
||||
|
||||
config.Domain, err = cleanDomain(
|
||||
@ -271,40 +362,40 @@ func CleanConfig(config *Config) error {
|
||||
config.Domain,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
if config.InstanceName == "" {
|
||||
return errors.New("InstanceName must be set")
|
||||
return Config{}, errors.New("InstanceName must be set")
|
||||
}
|
||||
if config.ListenAddress == "" {
|
||||
return errors.New("ListenAddress must be set. Example: 0.0.0.0:25585")
|
||||
return Config{}, errors.New("ListenAddress must be set. Example: 0.0.0.0:25585")
|
||||
}
|
||||
if config.DefaultMaxPlayerCount < 0 && config.DefaultMaxPlayerCount != Constants.MaxPlayerCountUnlimited {
|
||||
return fmt.Errorf("DefaultMaxPlayerCount must be >= 0, or %d to indicate unlimited players", Constants.MaxPlayerCountUnlimited)
|
||||
return Config{}, fmt.Errorf("DefaultMaxPlayerCount must be >= 0, or %d to indicate unlimited players", Constants.MaxPlayerCountUnlimited)
|
||||
}
|
||||
if config.RegistrationNewPlayer.Allow {
|
||||
if !config.CreateNewPlayer.Allow {
|
||||
return errors.New("If RegisterNewPlayer is allowed, CreateNewPlayer must be allowed.")
|
||||
return Config{}, errors.New("If RegisterNewPlayer is allowed, CreateNewPlayer must be allowed.")
|
||||
}
|
||||
}
|
||||
if config.RegistrationExistingPlayer.Allow {
|
||||
if !config.ImportExistingPlayer.Allow {
|
||||
return errors.New("If RegistrationExistingPlayer is allowed, ImportExistingPlayer must be allowed.")
|
||||
return Config{}, errors.New("If RegistrationExistingPlayer is allowed, ImportExistingPlayer must be allowed.")
|
||||
}
|
||||
if config.ImportExistingPlayer.Nickname == "" {
|
||||
return errors.New("If RegistrationExistingPlayer is allowed, ImportExistingPlayer.Nickname must be set")
|
||||
return Config{}, errors.New("If RegistrationExistingPlayer is allowed, ImportExistingPlayer.Nickname must be set")
|
||||
}
|
||||
if config.ImportExistingPlayer.SessionURL == "" {
|
||||
return errors.New("If RegistrationExistingPlayer is allowed, ImportExistingPlayer.SessionURL must be set. Example: https://sessionserver.mojang.com")
|
||||
return Config{}, errors.New("If RegistrationExistingPlayer is allowed, ImportExistingPlayer.SessionURL must be set. Example: https://sessionserver.mojang.com")
|
||||
}
|
||||
if config.ImportExistingPlayer.AccountURL == "" {
|
||||
return errors.New("If RegistrationExistingPlayer is allowed, ImportExistingPlayer.AccountURL must be set. Example: https://api.mojang.com")
|
||||
return Config{}, errors.New("If RegistrationExistingPlayer is allowed, ImportExistingPlayer.AccountURL must be set. Example: https://api.mojang.com")
|
||||
}
|
||||
}
|
||||
if config.ImportExistingPlayer.Allow {
|
||||
if config.ImportExistingPlayer.Nickname == "" {
|
||||
return errors.New("ImportExistingPlayer.Nickname must be set")
|
||||
return Config{}, errors.New("ImportExistingPlayer.Nickname must be set")
|
||||
}
|
||||
|
||||
config.ImportExistingPlayer.SessionURL, err = cleanURL(
|
||||
@ -313,7 +404,7 @@ func CleanConfig(config *Config) error {
|
||||
config.ImportExistingPlayer.SessionURL, true,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
config.ImportExistingPlayer.AccountURL, err = cleanURL(
|
||||
@ -322,7 +413,7 @@ func CleanConfig(config *Config) error {
|
||||
config.ImportExistingPlayer.AccountURL, true,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
config.ImportExistingPlayer.SetSkinURL, err = cleanURL(
|
||||
@ -331,66 +422,72 @@ func CleanConfig(config *Config) error {
|
||||
config.ImportExistingPlayer.SetSkinURL, true,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return Config{}, err
|
||||
}
|
||||
}
|
||||
|
||||
fallbackAPIServerNames := mapset.NewSet[string]()
|
||||
for _, fallbackAPIServer := range PtrSlice(config.FallbackAPIServers) {
|
||||
if fallbackAPIServer.Nickname == "" {
|
||||
return errors.New("FallbackAPIServer Nickname must be set")
|
||||
}
|
||||
if fallbackAPIServerNames.Contains(fallbackAPIServer.Nickname) {
|
||||
return fmt.Errorf("Duplicate FallbackAPIServer Nickname: %s", fallbackAPIServer.Nickname)
|
||||
}
|
||||
fallbackAPIServerNames.Add(fallbackAPIServer.Nickname)
|
||||
for _, rawFallbackAPIServer := range PtrSlice(rawConfig.FallbackAPIServers) {
|
||||
fallbackAPIServerConfig := AssignConfig(DefaultFallbackAPIServer(), *rawFallbackAPIServer)
|
||||
|
||||
fallbackAPIServer.SessionURL, err = cleanURL(
|
||||
fmt.Sprintf("FallbackAPIServer %s SessionURL", fallbackAPIServer.Nickname),
|
||||
if fallbackAPIServerConfig.Nickname == "" {
|
||||
return Config{}, errors.New("FallbackAPIServer Nickname must be set")
|
||||
}
|
||||
if fallbackAPIServerNames.Contains(fallbackAPIServerConfig.Nickname) {
|
||||
return Config{}, fmt.Errorf("Duplicate FallbackAPIServer Nickname: %s", fallbackAPIServerConfig.Nickname)
|
||||
}
|
||||
fallbackAPIServerNames.Add(fallbackAPIServerConfig.Nickname)
|
||||
|
||||
fallbackAPIServerConfig.SessionURL, err = cleanURL(
|
||||
fmt.Sprintf("FallbackAPIServer %s SessionURL", fallbackAPIServerConfig.Nickname),
|
||||
mo.Some("https://sessionserver.mojang.com"),
|
||||
fallbackAPIServer.SessionURL, true,
|
||||
fallbackAPIServerConfig.SessionURL, true,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
fallbackAPIServer.AccountURL, err = cleanURL(
|
||||
fmt.Sprintf("FallbackAPIServer %s AccountURL", fallbackAPIServer.Nickname),
|
||||
fallbackAPIServerConfig.AccountURL, err = cleanURL(
|
||||
fmt.Sprintf("FallbackAPIServer %s AccountURL", fallbackAPIServerConfig.Nickname),
|
||||
mo.Some("https://api.mojang.com"),
|
||||
fallbackAPIServer.AccountURL, true,
|
||||
fallbackAPIServerConfig.AccountURL, true,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
fallbackAPIServer.ServicesURL, err = cleanURL(
|
||||
fmt.Sprintf("FallbackAPIServer %s ServicesURL", fallbackAPIServer.Nickname),
|
||||
fallbackAPIServerConfig.ServicesURL, err = cleanURL(
|
||||
fmt.Sprintf("FallbackAPIServer %s ServicesURL", fallbackAPIServerConfig.Nickname),
|
||||
mo.Some("https://api.minecraftservices.com"),
|
||||
fallbackAPIServer.ServicesURL, true,
|
||||
fallbackAPIServerConfig.ServicesURL, true,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
for _, skinDomain := range PtrSlice(fallbackAPIServer.SkinDomains) {
|
||||
for _, skinDomain := range PtrSlice(fallbackAPIServerConfig.SkinDomains) {
|
||||
*skinDomain, err = cleanDomain(
|
||||
fmt.Sprintf("FallbackAPIServer %s SkinDomain", fallbackAPIServer.Nickname),
|
||||
fmt.Sprintf("FallbackAPIServer %s SkinDomain", fallbackAPIServerConfig.Nickname),
|
||||
mo.Some("textures.minecraft.net"),
|
||||
*skinDomain,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return Config{}, err
|
||||
}
|
||||
}
|
||||
|
||||
config.FallbackAPIServers = append(config.FallbackAPIServers, fallbackAPIServerConfig)
|
||||
}
|
||||
|
||||
oidcNames := mapset.NewSet[string]()
|
||||
for _, oidcConfig := range PtrSlice(config.RegistrationOIDC) {
|
||||
for _, rawOIDCConfig := range PtrSlice(rawConfig.RegistrationOIDC) {
|
||||
oidcConfig := AssignConfig(DefaultRegistrationOIDC(), *rawOIDCConfig)
|
||||
|
||||
if oidcConfig.Name == "" {
|
||||
return errors.New("RegistrationOIDC Name must be set")
|
||||
return Config{}, errors.New("RegistrationOIDC Name must be set")
|
||||
}
|
||||
if oidcNames.Contains(oidcConfig.Name) {
|
||||
return fmt.Errorf("Duplicate RegistrationOIDC Name: %s", oidcConfig.Name)
|
||||
return Config{}, fmt.Errorf("Duplicate RegistrationOIDC Name: %s", oidcConfig.Name)
|
||||
}
|
||||
oidcNames.Add(oidcConfig.Name)
|
||||
oidcConfig.Issuer, err = cleanURL(
|
||||
@ -400,10 +497,12 @@ func CleanConfig(config *Config) error {
|
||||
false,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
config.RegistrationOIDC = append(config.RegistrationOIDC, oidcConfig)
|
||||
}
|
||||
return nil
|
||||
return config, nil
|
||||
}
|
||||
|
||||
const TEMPLATE_CONFIG_FILE = `# Drasl default config file
|
||||
@ -422,7 +521,8 @@ Allow = true
|
||||
RequireInvite = true
|
||||
`
|
||||
|
||||
func HandleDeprecations(config Config, metadata *toml.MetaData) [][]string {
|
||||
func HandleDeprecations(oldRawConfig *RawConfig, metadata *toml.MetaData) (RawConfig, [][]string) {
|
||||
rawConfig := *oldRawConfig
|
||||
deprecatedPaths := make([][]string, 0)
|
||||
|
||||
warningTemplate := "Warning: config option %s is deprecated and will be removed in a future version. Use %s instead."
|
||||
@ -432,7 +532,7 @@ func HandleDeprecations(config Config, metadata *toml.MetaData) [][]string {
|
||||
LogInfo(fmt.Sprintf(warningTemplate, strings.Join(path_, "."), "CreateNewPlayer.AllowChoosingUUID"))
|
||||
deprecatedPaths = append(deprecatedPaths, path_)
|
||||
if !metadata.IsDefined("CreateNewPlayer", "AllowChoosingUUID") {
|
||||
config.CreateNewPlayer.AllowChoosingUUID = config.RegistrationNewPlayer.AllowChoosingUUID
|
||||
rawConfig.CreateNewPlayer.AllowChoosingUUID = rawConfig.RegistrationNewPlayer.AllowChoosingUUID
|
||||
}
|
||||
}
|
||||
path_ = []string{"RegistrationExistingPlayer", "Nickname"}
|
||||
@ -440,7 +540,7 @@ func HandleDeprecations(config Config, metadata *toml.MetaData) [][]string {
|
||||
LogInfo(fmt.Sprintf(warningTemplate, strings.Join(path_, "."), "ImportExistingPlayer.Nickname"))
|
||||
deprecatedPaths = append(deprecatedPaths, path_)
|
||||
if !metadata.IsDefined("ImportExistingPlayer", "Nickname") {
|
||||
config.ImportExistingPlayer.Nickname = config.RegistrationExistingPlayer.Nickname
|
||||
rawConfig.ImportExistingPlayer.Nickname = rawConfig.RegistrationExistingPlayer.Nickname
|
||||
}
|
||||
}
|
||||
path_ = []string{"RegistrationExistingPlayer", "SessionURL"}
|
||||
@ -448,7 +548,7 @@ func HandleDeprecations(config Config, metadata *toml.MetaData) [][]string {
|
||||
LogInfo(fmt.Sprintf(warningTemplate, strings.Join(path_, "."), "ImportExistingPlayer.SessionURL"))
|
||||
deprecatedPaths = append(deprecatedPaths, path_)
|
||||
if !metadata.IsDefined("ImportExistingPlayer", "SessionURL") {
|
||||
config.ImportExistingPlayer.SessionURL = config.RegistrationExistingPlayer.SessionURL
|
||||
rawConfig.ImportExistingPlayer.SessionURL = rawConfig.RegistrationExistingPlayer.SessionURL
|
||||
}
|
||||
}
|
||||
path_ = []string{"RegistrationExistingPlayer", "AccountURL"}
|
||||
@ -456,7 +556,7 @@ func HandleDeprecations(config Config, metadata *toml.MetaData) [][]string {
|
||||
LogInfo(fmt.Sprintf(warningTemplate, strings.Join(path_, "."), "ImportExistingPlayer.AccountURL"))
|
||||
deprecatedPaths = append(deprecatedPaths, path_)
|
||||
if !metadata.IsDefined("ImportExistingPlayer", "AccountURL") {
|
||||
config.ImportExistingPlayer.AccountURL = config.RegistrationExistingPlayer.AccountURL
|
||||
rawConfig.ImportExistingPlayer.AccountURL = rawConfig.RegistrationExistingPlayer.AccountURL
|
||||
}
|
||||
}
|
||||
path_ = []string{"RegistrationExistingPlayer", "SetSkinURL"}
|
||||
@ -464,7 +564,7 @@ func HandleDeprecations(config Config, metadata *toml.MetaData) [][]string {
|
||||
LogInfo(fmt.Sprintf(warningTemplate, strings.Join(path_, "."), "ImportExistingPlayer.SetSkinURL"))
|
||||
deprecatedPaths = append(deprecatedPaths, path_)
|
||||
if !metadata.IsDefined("ImportExistingPlayer", "SetSkinURL") {
|
||||
config.ImportExistingPlayer.SetSkinURL = config.RegistrationExistingPlayer.SetSkinURL
|
||||
rawConfig.ImportExistingPlayer.SetSkinURL = rawConfig.RegistrationExistingPlayer.SetSkinURL
|
||||
}
|
||||
}
|
||||
path_ = []string{"RegistrationExistingPlayer", "RequireSkinVerification"}
|
||||
@ -472,15 +572,15 @@ func HandleDeprecations(config Config, metadata *toml.MetaData) [][]string {
|
||||
LogInfo(fmt.Sprintf(warningTemplate, strings.Join(path_, "."), "ImportExistingPlayer.RequireSkinVerification"))
|
||||
deprecatedPaths = append(deprecatedPaths, path_)
|
||||
if !metadata.IsDefined("ImportExistingPlayer", "RequireSkinVerification") {
|
||||
config.ImportExistingPlayer.RequireSkinVerification = config.RegistrationExistingPlayer.RequireSkinVerification
|
||||
rawConfig.ImportExistingPlayer.RequireSkinVerification = rawConfig.RegistrationExistingPlayer.RequireSkinVerification
|
||||
}
|
||||
}
|
||||
|
||||
return deprecatedPaths
|
||||
return rawConfig, deprecatedPaths
|
||||
}
|
||||
|
||||
func ReadConfig(path string, createIfNotExists bool) (Config, [][]string, error) {
|
||||
config := DefaultConfig()
|
||||
rawConfig := DefaultRawConfig()
|
||||
|
||||
_, err := os.Stat(path)
|
||||
if err != nil {
|
||||
@ -501,15 +601,15 @@ func ReadConfig(path string, createIfNotExists bool) (Config, [][]string, error)
|
||||
}
|
||||
|
||||
LogInfo("Loading config from", path)
|
||||
metadata, err := toml.DecodeFile(path, &config)
|
||||
metadata, err := toml.DecodeFile(path, &rawConfig)
|
||||
Check(err)
|
||||
|
||||
for _, key := range metadata.Undecoded() {
|
||||
LogInfo("Warning: unknown config option", strings.Join(key, "."))
|
||||
}
|
||||
|
||||
deprecations := HandleDeprecations(config, &metadata)
|
||||
err = CleanConfig(&config)
|
||||
rawConfig, deprecations := HandleDeprecations(&rawConfig, &metadata)
|
||||
config, err := CleanConfig(&rawConfig)
|
||||
if err != nil {
|
||||
return Config{}, nil, err
|
||||
}
|
||||
|
199
config_test.go
199
config_test.go
@ -7,11 +7,13 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func configTestConfig(stateDirectory string) *Config {
|
||||
config := testConfig()
|
||||
config.StateDirectory = stateDirectory
|
||||
config.DataDirectory = "."
|
||||
return config
|
||||
func configTestRawConfig(stateDirectory string) RawConfig {
|
||||
rawConfig := RawConfig{
|
||||
BaseConfig: testConfig().BaseConfig,
|
||||
}
|
||||
rawConfig.StateDirectory = stateDirectory
|
||||
rawConfig.DataDirectory = "."
|
||||
return rawConfig
|
||||
}
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
@ -19,136 +21,138 @@ func TestConfig(t *testing.T) {
|
||||
sd := Unwrap(os.MkdirTemp("", "tmp"))
|
||||
defer os.RemoveAll(sd)
|
||||
|
||||
config := configTestConfig(sd)
|
||||
assert.Nil(t, CleanConfig(config))
|
||||
rawConfig := configTestRawConfig(sd)
|
||||
assert.Nil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.BaseURL = "https://δρασλ.example.com/"
|
||||
config.Domain = "δρασλ.example.com"
|
||||
assert.Nil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.BaseURL = "https://δρασλ.example.com/"
|
||||
rawConfig.Domain = "δρασλ.example.com"
|
||||
config, err := CleanConfig(&rawConfig)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "https://xn--mxafwwl.example.com", config.BaseURL)
|
||||
assert.Equal(t, "xn--mxafwwl.example.com", config.Domain)
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.BaseURL = ""
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.BaseURL = ""
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.BaseURL = ":an invalid URL"
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.BaseURL = ":an invalid URL"
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.DefaultPreferredLanguage = "xx"
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.DefaultPreferredLanguage = "xx"
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.Domain = ""
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.Domain = ""
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.InstanceName = ""
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.InstanceName = ""
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.ListenAddress = ""
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.ListenAddress = ""
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.DefaultMaxPlayerCount = Constants.MaxPlayerCountUseDefault
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.DefaultMaxPlayerCount = Constants.MaxPlayerCountUseDefault
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.DefaultMaxPlayerCount = Constants.MaxPlayerCountUnlimited
|
||||
assert.Nil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.DefaultMaxPlayerCount = Constants.MaxPlayerCountUnlimited
|
||||
assert.Nil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
// Missing state directory should be ignored
|
||||
config = configTestConfig(sd)
|
||||
config.StateDirectory = "/tmp/DraslInvalidStateDirectoryNothingHere"
|
||||
assert.Nil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.StateDirectory = "/tmp/DraslInvalidStateDirectoryNothingHere"
|
||||
assert.Nil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.RegistrationExistingPlayer.Allow = true
|
||||
config.ImportExistingPlayer.Allow = true
|
||||
config.ImportExistingPlayer.Nickname = "Example"
|
||||
config.ImportExistingPlayer.SessionURL = "https://δρασλ.example.com/"
|
||||
config.ImportExistingPlayer.AccountURL = "https://drasl.example.com/"
|
||||
assert.Nil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.RegistrationExistingPlayer.Allow = true
|
||||
rawConfig.ImportExistingPlayer.Allow = true
|
||||
rawConfig.ImportExistingPlayer.Nickname = "Example"
|
||||
rawConfig.ImportExistingPlayer.SessionURL = "https://δρασλ.example.com/"
|
||||
rawConfig.ImportExistingPlayer.AccountURL = "https://drasl.example.com/"
|
||||
config, err = CleanConfig(&rawConfig)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "https://xn--mxafwwl.example.com", config.ImportExistingPlayer.SessionURL)
|
||||
assert.Equal(t, "https://drasl.example.com", config.ImportExistingPlayer.AccountURL)
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.RegistrationExistingPlayer.Allow = true
|
||||
config.ImportExistingPlayer.Nickname = ""
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.RegistrationExistingPlayer.Allow = true
|
||||
rawConfig.ImportExistingPlayer.Nickname = ""
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.RegistrationExistingPlayer.Allow = true
|
||||
config.ImportExistingPlayer.SessionURL = ""
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.RegistrationExistingPlayer.Allow = true
|
||||
rawConfig.ImportExistingPlayer.SessionURL = ""
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
config.RegistrationExistingPlayer.Allow = true
|
||||
config.ImportExistingPlayer.AccountURL = ""
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
rawConfig.RegistrationExistingPlayer.Allow = true
|
||||
rawConfig.ImportExistingPlayer.AccountURL = ""
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
config = configTestConfig(sd)
|
||||
testFallbackAPIServer := FallbackAPIServerConfig{
|
||||
Nickname: "Nickname",
|
||||
SessionURL: "https://δρασλ.example.com/",
|
||||
AccountURL: "https://δρασλ.example.com/",
|
||||
ServicesURL: "https://δρασλ.example.com/",
|
||||
SkinDomains: []string{"δρασλ.example.com"},
|
||||
rawConfig = configTestRawConfig(sd)
|
||||
testFallbackAPIServer := rawFallbackAPIServerConfig{
|
||||
Nickname: Ptr("Nickname"),
|
||||
SessionURL: Ptr("https://δρασλ.example.com/"),
|
||||
AccountURL: Ptr("https://δρασλ.example.com/"),
|
||||
ServicesURL: Ptr("https://δρασλ.example.com/"),
|
||||
SkinDomains: Ptr([]string{"δρασλ.example.com"}),
|
||||
}
|
||||
fb := testFallbackAPIServer
|
||||
config.FallbackAPIServers = []FallbackAPIServerConfig{fb}
|
||||
assert.Nil(t, CleanConfig(config))
|
||||
rawConfig.FallbackAPIServers = []rawFallbackAPIServerConfig{fb}
|
||||
config, err = CleanConfig(&rawConfig)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, []FallbackAPIServerConfig{{
|
||||
Nickname: fb.Nickname,
|
||||
SessionURL: "https://xn--mxafwwl.example.com",
|
||||
AccountURL: "https://xn--mxafwwl.example.com",
|
||||
ServicesURL: "https://xn--mxafwwl.example.com",
|
||||
SkinDomains: []string{"xn--mxafwwl.example.com"},
|
||||
}}, config.FallbackAPIServers)
|
||||
assert.Equal(t, 1, len(config.FallbackAPIServers))
|
||||
assert.Equal(t, *fb.Nickname, config.FallbackAPIServers[0].Nickname)
|
||||
assert.Equal(t, "https://xn--mxafwwl.example.com", config.FallbackAPIServers[0].SessionURL)
|
||||
assert.Equal(t, "https://xn--mxafwwl.example.com", config.FallbackAPIServers[0].AccountURL)
|
||||
assert.Equal(t, "https://xn--mxafwwl.example.com", config.FallbackAPIServers[0].ServicesURL)
|
||||
assert.Equal(t, []string{"xn--mxafwwl.example.com"}, config.FallbackAPIServers[0].SkinDomains)
|
||||
|
||||
fb = testFallbackAPIServer
|
||||
fb.Nickname = ""
|
||||
config.FallbackAPIServers = []FallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
fb.Nickname = Ptr("")
|
||||
rawConfig.FallbackAPIServers = []rawFallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
fb = testFallbackAPIServer
|
||||
fb.SessionURL = ""
|
||||
config.FallbackAPIServers = []FallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
fb.SessionURL = Ptr("")
|
||||
rawConfig.FallbackAPIServers = []rawFallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
fb = testFallbackAPIServer
|
||||
fb.SessionURL = ":invalid URL"
|
||||
config.FallbackAPIServers = []FallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
fb.SessionURL = Ptr(":invalid URL")
|
||||
rawConfig.FallbackAPIServers = []rawFallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
fb = testFallbackAPIServer
|
||||
fb.AccountURL = ""
|
||||
config.FallbackAPIServers = []FallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
fb.AccountURL = Ptr("")
|
||||
rawConfig.FallbackAPIServers = []rawFallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
fb = testFallbackAPIServer
|
||||
fb.AccountURL = ":invalid URL"
|
||||
config.FallbackAPIServers = []FallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
fb.AccountURL = Ptr(":invalid URL")
|
||||
rawConfig.FallbackAPIServers = []rawFallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
fb = testFallbackAPIServer
|
||||
fb.ServicesURL = ""
|
||||
config.FallbackAPIServers = []FallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
fb.ServicesURL = Ptr("")
|
||||
rawConfig.FallbackAPIServers = []rawFallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
fb = testFallbackAPIServer
|
||||
fb.ServicesURL = ":invalid URL"
|
||||
config.FallbackAPIServers = []FallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, CleanConfig(config))
|
||||
fb.ServicesURL = Ptr(":invalid URL")
|
||||
rawConfig.FallbackAPIServers = []rawFallbackAPIServerConfig{fb}
|
||||
assert.NotNil(t, UnwrapError(CleanConfig(&rawConfig)))
|
||||
|
||||
// Test that TEMPLATE_CONFIG_FILE is valid
|
||||
var templateConfig Config
|
||||
_, err := toml.Decode(TEMPLATE_CONFIG_FILE, &templateConfig)
|
||||
_, err = toml.Decode(TEMPLATE_CONFIG_FILE, &templateConfig)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Test that the example configs are valid
|
||||
@ -167,4 +171,9 @@ func TestConfig(t *testing.T) {
|
||||
configBytes, err = os.ReadFile("example/docker-caddy/config/config.toml")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, correctBytes, configBytes)
|
||||
|
||||
// Test AssignConfig
|
||||
defaults := DefaultFallbackAPIServer()
|
||||
assigned := AssignConfig(defaults, rawFallbackAPIServerConfig{})
|
||||
assert.Equal(t, defaults, assigned)
|
||||
}
|
||||
|
@ -37,11 +37,11 @@ Other available options:
|
||||
- `[[FallbackAPIServers]]`: Allows players to authenticate using other API servers. For example, say you had a Minecraft server configured to authenticate players with your Drasl instance. You could configure Mojang's API as a fallback, and a player signed in with either a Drasl account or a Mojang account could play on your server. Does not work with Minecraft servers that have `enforce-secure-profile=true` in server.properties. See [recipes.md](recipes.md) for example configurations.
|
||||
|
||||
- You can configure any number of fallback API servers, and they will be tried in sequence, in the order they appear in the config file. By default, none are configured.
|
||||
- `Nickname`: A name for the API server
|
||||
- `Nickname`: A name for the API server. String. Example value: `"Mojang"`.
|
||||
- `AccountURL`: The URL of the "account" server. String. Example value: `"https://api.mojang.com"`.
|
||||
- `SessionURL`: The URL of the "session" server. String. Example value: `"https://sessionserver.mojang.com"`.
|
||||
- `ServicesURL`: The URL of the "services" server. String. Example value: `"https://api.minecraftservices.com"`.
|
||||
- `SkinDomains`: Array of domains where skins are hosted. For authlib-injector-compatible API servers, the correct value should be returned by the root of the API, e.g. go to [https://example.com/yggdrasil](https://example.com/yggdrasil) and look for the `skinDomains` field. Array of strings. Example value: `["textures.minecraft.net"]`
|
||||
- `SkinDomains`: Array of domains where skins are hosted. For authlib-injector-compatible API servers, the correct value should be returned by the root of the API, e.g. go to [https://example.com/yggdrasil](https://example.com/yggdrasil) and look for the `skinDomains` field. Array of strings. Example value: `["textures.minecraft.net"]`.
|
||||
- Note: API servers set up for authlib-injector may only give you one URL---if their API URL is e.g. `https://example.com/yggdrasil`, then you would use the following settings:
|
||||
|
||||
```
|
||||
@ -50,11 +50,11 @@ Other available options:
|
||||
ServicesURL = https://example.com/yggdrasil/minecraftservices
|
||||
```
|
||||
|
||||
- `CacheTTLSec`: Time in seconds to cache API server responses. This option is set to `0` by default, which disables caching. For authentication servers like Mojang which may rate-limit, it's recommended to at least set it to something small like `60`. Integer. Default value: `0`.
|
||||
- `CacheTTLSec`: Time in seconds to cache API server responses. This option is set to `0` by default, which disables caching. For authentication servers like Mojang which may rate-limit, it's recommended to at least set it to something small like `60`. Integer. Default value: `600` (10 minutes).
|
||||
|
||||
- `DenyUnknownUsers`: Don't allow clients using this authentication server to log in to a Minecraft server using Drasl unless there is a Drasl user with the client's player name. This option effectively allows you to use Drasl as a whitelist for your Minecraft server. You could allow users to authenticate using, for example, Mojang's authentication server, but only if they are also registered on Drasl. Boolean. Default value: `false`.
|
||||
|
||||
- `OfflineSkins`: Try to resolve skins for "offline" UUIDs. When `online-mode` is set to `false` in `server.properties` (sometimes called "offline mode"), players' UUIDs are computed deterministically from their player names instead of being managed by the authentication server. If this option is enabled and a skin for an unknown UUID is requested, Drasl will search for a matching player by offline UUID. This option is required to see other players' skins on offline servers. Boolean. Default value: `true`.
|
||||
- `OfflineSkins`: Try to resolve skins for "offline" UUIDs. When `online-mode` is set to `false` in `server.properties` (sometimes called "offline mode"), players' UUIDs are computed deterministically from their player names instead of being managed by the authentication server. If this option is enabled and a skin for an unknown UUID is requested, Drasl will search for a matching player by offline UUID. This option is required to see other players' skins on offline servers. Boolean. Default value: `true`.
|
||||
|
||||
<!-- - `[TransientLogin]`: Allow certain usernames to authenticate with a shared password, without registering. Useful for supporting bot accounts. -->
|
||||
<!-- - `Allow`: Boolean. Default value: `false`. -->
|
||||
@ -89,9 +89,9 @@ Other available options:
|
||||
- `Issuer`: OIDC issuer URL. String. Example value: `"https://idm.example.com/oauth2/openid/drasl"`.
|
||||
- `ClientID`: OIDC client ID. String. Example value: `"drasl"`.
|
||||
- `ClientSecret`: OIDC client secret. String. Example value: `"yfUfeFuUI6YiTU23ngJtq8ioYq75FxQid8ls3RdNf0qWSiBO"`.
|
||||
- `PKCE`: Whether to use [PKCE](https://datatracker.ietf.org/doc/html/rfc7636). Recommended, but must be supported by the OIDC provider. Boolean. Default value: `false`.
|
||||
- `RequireInvite`: Whether registration via this OIDC provider requires an invite. If enabled, users will only be able to create a new account via this OIDC provider if they use an invite link generated by an admin (see `DefaultAdmins`). Boolean.
|
||||
- `AllowChoosingPlayerName`: Whether to allow choosing a player name other than the OIDC user's `preferredUsername` during registration. Boolean.
|
||||
- `PKCE`: Whether to use [PKCE](https://datatracker.ietf.org/doc/html/rfc7636). Recommended, but must be supported by the OIDC provider. Boolean. Default value: `true`.
|
||||
- `RequireInvite`: Whether registration via this OIDC provider requires an invite. If enabled, users will only be able to create a new account via this OIDC provider if they use an invite link generated by an admin (see `DefaultAdmins`). Boolean. Default value: `false`.
|
||||
- `AllowChoosingPlayerName`: Whether to allow choosing a player name other than the OIDC user's `preferredUsername` during registration. Boolean. Default value: `true`.
|
||||
|
||||
- `[RequestCache]`: Settings for the cache used for `FallbackAPIServers`. You probably don't need to change these settings. Modify `[[FallbackAPIServers]].CacheTTLSec` instead if you want to disable caching. See [https://pkg.go.dev/github.com/dgraph-io/ristretto#readme-config](https://pkg.go.dev/github.com/dgraph-io/ristretto#readme-config).
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user