feat: customize login and lobby spaces from the panel
This commit is contained in:
54 files changed
+1146
-158
No files matched your search
@@ -456,7 +456,7 @@ const (
|
||||
redactedValue = "<redacted by felis>"
|
||||
)
|
||||
|
||||
// redactSecretProps blanks the RCON password when server.properties is read.
|
||||
// redactSecretProps hides RCON and Limbo forwarding secrets when server.properties is read.
|
||||
//
|
||||
// Unlike secretConfigPath this is a value redaction rather than a whole-file
|
||||
// denial, because the file is not platform material that merely happens to sit in
|
||||
@@ -468,6 +468,9 @@ const (
|
||||
// regardless of blast radius, and because the console already gives an owner every
|
||||
// capability the password would.
|
||||
//
|
||||
// Limbo stores its cluster forwarding key in this file too; that value is
|
||||
// withheld by the same redaction and refreshed by the Limbo entrypoint.
|
||||
//
|
||||
// The write path is left alone on purpose, mirroring the reasoning at
|
||||
// secretConfigPath: felis-lobby's entrypoint rewrites all three rcon keys from the
|
||||
// injected Secret on every boot, so saving the placeholder back cannot lock the
|
||||
@@ -481,8 +484,10 @@ func redactSecretProps(name string, content []byte) []byte {
|
||||
for i, line := range lines {
|
||||
// TrimSpace before matching: a properties key may be indented, and the
|
||||
// trailing \r of a CRLF file would otherwise ride along into the value.
|
||||
if bytes.HasPrefix(bytes.TrimSpace(line), []byte(rconPasswordKey+"=")) {
|
||||
lines[i] = []byte(rconPasswordKey + "=" + redactedValue)
|
||||
for _, key := range []string{rconPasswordKey, "forwarding-secrets"} {
|
||||
if bytes.HasPrefix(bytes.TrimSpace(line), []byte(key+"=")) {
|
||||
lines[i] = []byte(key + "=" + redactedValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
return bytes.Join(lines, []byte("\n"))
|
||||
|
||||
@@ -678,3 +678,23 @@ func assertNoTemporaries(t *testing.T, dir string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadRedactsLimboForwardingSecret(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
props := "spawn-x=8\nforwarding-secrets=shared-key\nvelocity-modern=true\n"
|
||||
if err := os.WriteFile(filepath.Join(root, "server.properties"), []byte(props), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Link(filepath.Join(root, "server.properties"), filepath.Join(root, "copy.properties")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, path := range []string{"server.properties", "copy.properties"} {
|
||||
res, err := run(root, OpRead, path, nil, "")
|
||||
if err != nil || res.Code != "" {
|
||||
t.Fatalf("read: %+v %v", res, err)
|
||||
}
|
||||
if strings.Contains(string(res.Content), "shared-key") || !strings.Contains(string(res.Content), "spawn-x=8") {
|
||||
t.Fatalf("unsafe redaction: %s", res.Content)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
// What leaves a world mount — a read, a download, a world export, a backup
|
||||
// export — passes the same two guards: the forwarding-secret file
|
||||
// (secretConfigPath) is withheld, and server.properties has its RCON password
|
||||
// redacted (propsPath).
|
||||
// redacted (propsPath), along with Limbo's forwarding-secrets.
|
||||
//
|
||||
// On a live mount both are matched by the file itself (os.SameFile), not by the
|
||||
// name it was reached under. A plugin runs arbitrary code as the game uid and can
|
||||
@@ -51,7 +51,7 @@ func ArchiveRule(name string) (withhold, redact bool) {
|
||||
return name == secretConfigPath, name == propsPath
|
||||
}
|
||||
|
||||
// RedactProps replaces the RCON password in server.properties content with
|
||||
// RedactProps replaces RCON and Limbo forwarding secrets in server.properties with
|
||||
// redactedValue (see redactSecretProps for why a placeholder and not a blank).
|
||||
func RedactProps(content []byte) []byte {
|
||||
return redactSecretProps(propsPath, content)
|
||||
|
||||
Reference in new issue
Block a user