feat: initialize panel access before linking Minecraft accounts
Configure connection and storage before creating or resuming the one-time Owner login. Remove Minecraft prerequisites from setup and preserve established login credentials. Let staff preview and confirm roles from configured authentication sources using the existing account-link storage and game UUID mapping. Retain in-game code proof for players, add client-version and lobby guidance, and support NodePort passkey origins.
This commit is contained in:
59 files changed
+1702
-1564
No files matched your search
@@ -62,6 +62,8 @@ type AuthSourceConfig struct {
|
||||
Tag string `toml:"tag"`
|
||||
Prefix string `toml:"prefix"`
|
||||
URL string `toml:"url"`
|
||||
// APIURL is optional for sources whose hasJoined URL does not use the standard path.
|
||||
APIURL string `toml:"api_url"`
|
||||
}
|
||||
|
||||
// SMTPConfig is the [smtp] table: the outbound mail relay felis-api delivers
|
||||
@@ -149,6 +151,9 @@ type VelocityConfig struct {
|
||||
// FELIS_GAME_PORT). The panel adds it to the server addresses players copy
|
||||
// when it is not Minecraft's default; 0 means that default, 25565.
|
||||
GamePort int `toml:"game_port"`
|
||||
// GameVersion is the login/lobby protocol built by bootstrap. Empty means
|
||||
// unknown for custom images; the panel must not guess a client version.
|
||||
GameVersion string `toml:"game_version"`
|
||||
}
|
||||
|
||||
// AuthConfig is the [auth] table: the two privileged faces and the Cloudflare
|
||||
@@ -721,6 +726,11 @@ func (c *Config) validateAuthSources() error {
|
||||
if problem := hasJoinedURLProblem(s.URL); problem != "" {
|
||||
return fmt.Errorf("config: [[auth_source]] %q url %q %s", s.Tag, s.URL, problem)
|
||||
}
|
||||
if s.APIURL != "" {
|
||||
if problem := hasJoinedURLProblem(s.APIURL); problem != "" {
|
||||
return fmt.Errorf("config: [[auth_source]] %q api_url %q %s", s.Tag, s.APIURL, problem)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -501,6 +501,28 @@ func TestLoadRejectsUnqueryableAuthSourceURL(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthSourceProfileAPIURL(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
url string
|
||||
valid bool
|
||||
}{
|
||||
{"https://ygg.example.net/api/yggdrasil", true},
|
||||
{"http://127.0.0.1:8080/ygg", true},
|
||||
{"ygg.example.net/api", false},
|
||||
{"http://ygg.example.net/api", false},
|
||||
{"https://ygg.example.net/api?token=x", false},
|
||||
} {
|
||||
cfg, err := config.LoadNano(writeTOML(t, "[[auth_source]]\ntag = \"a\"\nprefix = \"AA\"\nurl = \"https://ygg.example.net/custom-check\"\napi_url = \""+tc.url+"\"\n"))
|
||||
if tc.valid {
|
||||
if err != nil || cfg.AuthSources[0].APIURL != tc.url {
|
||||
t.Fatalf("api_url %q = %v, %v", tc.url, cfg, err)
|
||||
}
|
||||
} else if err == nil || !strings.Contains(err.Error(), "api_url") {
|
||||
t.Fatalf("invalid api_url %q: %v", tc.url, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A source reached over plaintext can be answered by anyone on the path, who can then log in
|
||||
// as any player of that source. Only a same-host or private-network root may skip TLS, and
|
||||
// that is decided on the literal host, since nothing is resolved at load time.
|
||||
|
||||
Reference in new issue
Block a user