feat(config): CORS-Erlaubnisliste server.allowed_origins (TALK_ALLOWED_ORIGINS)
Exakte Origins wie https://chat.az-gruppe.com; Wildcard "*" nur explizit. Bewusster Default: leer = keine CORS-Header (Tür zu). Env schlägt Datei (kommagetrennt; "off" leert), leere Einträge sind klare Fehler.
This commit is contained in:
1 parent
24ceff3f48
commit
cef6e6b9f2
2 files changed
+147
No files matched your search
@@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
@@ -85,6 +86,14 @@ type Server struct {
|
||||
// Port des Daemon-HTTP-Servers auf 127.0.0.1 — config
|
||||
// `[server] port = 7800`, Env-Override TALK_PORT, Default 7800.
|
||||
Port int `toml:"port"`
|
||||
|
||||
// AllowedOrigins ist die CORS-Erlaubnisliste für POST /speak (Task 06):
|
||||
// exakte Origins wie "https://chat.az-gruppe.com". Der Eintrag "*"
|
||||
// erlaubt jede Origin ausdrücklich. Bewusster Default: LEER — ohne
|
||||
// Einträge sendet der Daemon gar keine CORS-Header und der Browser
|
||||
// blockt Cross-Origin-Anfragen; die Tür ist zu, bis sie konfiguriert
|
||||
// wird (Env-Override TALK_ALLOWED_ORIGINS, kommagetrennt; "off" leert).
|
||||
AllowedOrigins []string `toml:"allowed_origins"`
|
||||
}
|
||||
|
||||
// Queue sind die Rate-Limit-Gesetze des Daemons (TOML `[queue]`).
|
||||
@@ -178,6 +187,17 @@ func applyEnv(cfg Config, getenv func(string) string) (Config, error) {
|
||||
}
|
||||
cfg.Server.Port = port
|
||||
}
|
||||
if v := getenv("TALK_ALLOWED_ORIGINS"); v != "" {
|
||||
if v == "off" {
|
||||
cfg.Server.AllowedOrigins = nil
|
||||
} else {
|
||||
origins, err := splitOrigins(v)
|
||||
if err != nil {
|
||||
return cfg, fmt.Errorf("TALK_ALLOWED_ORIGINS: %w", err)
|
||||
}
|
||||
cfg.Server.AllowedOrigins = origins
|
||||
}
|
||||
}
|
||||
if v := getenv("TALK_RATE_LIMIT"); v != "" {
|
||||
d, err := time.ParseDuration(v)
|
||||
if err != nil || d < 0 {
|
||||
@@ -215,6 +235,14 @@ func applyEnv(cfg Config, getenv func(string) string) (Config, error) {
|
||||
return cfg, fmt.Errorf("audio.sink: ungültiger Wert %q (erlaubt: %q, %q)",
|
||||
cfg.Audio.Sink, SinkOto, SinkNull)
|
||||
}
|
||||
// allowed_origins aus der Datei prüfen (Env wurde oben geparst): Eine
|
||||
// leere Liste ist gültig (Tür zu), einzelne Einträge müssen aber
|
||||
// substanziell sein — klarer Fehler statt stiller Ignoranz.
|
||||
for _, o := range cfg.Server.AllowedOrigins {
|
||||
if strings.TrimSpace(o) == "" {
|
||||
return cfg, fmt.Errorf("server.allowed_origins: leerer Eintrag in %v", cfg.Server.AllowedOrigins)
|
||||
}
|
||||
}
|
||||
// quiet_hours aus der Datei validieren (Env wurde oben geprüft) und
|
||||
// quiet_mode leer (Datei ohne Wert) auf den Default heben.
|
||||
if cfg.QuietHours != "" {
|
||||
@@ -227,3 +255,19 @@ func applyEnv(cfg Config, getenv func(string) string) (Config, error) {
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// splitOrigins zerlegt eine kommagetrennte Origin-Liste (Env-Form von
|
||||
// server.allowed_origins, z. B. "https://a.example, https://b.example").
|
||||
// Whitespace um Einträge toleriert, leere Einträge sind ein klarer Fehler.
|
||||
func splitOrigins(v string) ([]string, error) {
|
||||
parts := strings.Split(v, ",")
|
||||
origins := make([]string, 0, len(parts))
|
||||
for _, p := range parts {
|
||||
p = strings.TrimSpace(p)
|
||||
if p == "" {
|
||||
return nil, fmt.Errorf("leerer Eintrag in %q (komma-getrennte Origins oder \"off\")", v)
|
||||
}
|
||||
origins = append(origins, p)
|
||||
}
|
||||
return origins, nil
|
||||
}
|
||||
Reference in new issue
Block a user