Refuse open listeners and cross-site writes without auth
Why: The embedded tier starts without auth, and nothing checked Origin or Host, so a public bind or a foreign page could call write APIs. Evidence: go test ./internal/config ./internal/server covering listen policy, origin rejection, and response headers. Impact: Non-loopback without auth exits before opening the database. HTML artifacts get a sandbox CSP. Reverse proxies must list their public host in allowedHosts. Refs: feature/sillytavern-review Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -42,13 +42,15 @@ func main() {
|
||||
artifacts := fs.String("artifacts", "", "工件对象目录(默认 <data>/artifacts;PG 档多实例时指向共享卷)")
|
||||
auth := fs.String("auth", "auto", "API key 认证:auto(PG 档开、嵌入式关)| on | off")
|
||||
instance := fs.String("instance", "", "本进程标识(空 = 主机名:监听地址;启动对账只收口这个实例的 run)")
|
||||
insecure := fs.Bool("insecure-listen", false, "允许在非回环地址上不开启认证(每次启动都会警告)")
|
||||
allowedHosts := fs.String("allowed-hosts", "", "逗号分隔的额外主机名,供反向代理的 Host 与 Origin 校验")
|
||||
fs.Parse(os.Args[1:])
|
||||
cliSet := map[string]bool{}
|
||||
fs.Visit(func(f *flag.Flag) { cliSet[f.Name] = true })
|
||||
cliSet := visited(fs)
|
||||
|
||||
resolved, err := config.Load(*cfgFile, os.LookupEnv, config.Config{
|
||||
Addr: *addr, DataDir: *data, PluginsDir: *pluginsDir, Mock: *mock,
|
||||
StorageDSN: *dsn, ArtifactsDir: *artifacts, AuthMode: *auth, Instance: *instance,
|
||||
InsecureListen: *insecure, AllowedHostsRaw: *allowedHosts,
|
||||
}, cliSet)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "agent-system:", err)
|
||||
@@ -57,13 +59,29 @@ func main() {
|
||||
if err := app.Run(app.Options{
|
||||
Addr: resolved.Addr, DataDir: resolved.DataDir, PluginsDir: resolved.PluginsDir, ForceMock: resolved.Mock,
|
||||
StorageDSN: resolved.StorageDSN, ArtifactsDir: resolved.ArtifactsDir, AuthMode: resolved.AuthMode,
|
||||
InstanceID: resolved.Instance,
|
||||
InstanceID: resolved.Instance, InsecureListen: resolved.InsecureListen, AllowedHosts: resolved.AllowedHosts(),
|
||||
}); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "agent-system:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// visited 把连字符 flag 收成配置字段名,供 Load 的 cliSet 使用。
|
||||
func visited(fs *flag.FlagSet) map[string]bool {
|
||||
set := map[string]bool{}
|
||||
fs.Visit(func(f *flag.Flag) {
|
||||
name := f.Name
|
||||
switch name {
|
||||
case "insecure-listen":
|
||||
name = "insecureListen"
|
||||
case "allowed-hosts":
|
||||
name = "allowedHosts"
|
||||
}
|
||||
set[name] = true
|
||||
})
|
||||
return set
|
||||
}
|
||||
|
||||
// runConfig:config explain——只读解析诊断(不建库、不写业务目录;DSN 脱敏)。
|
||||
func runConfig(args []string) int {
|
||||
if len(args) == 0 || args[0] != "explain" {
|
||||
@@ -80,13 +98,14 @@ func runConfig(args []string) int {
|
||||
artifacts := fs.String("artifacts", "", "")
|
||||
auth := fs.String("auth", "auto", "")
|
||||
instance := fs.String("instance", "", "")
|
||||
insecure := fs.Bool("insecure-listen", false, "")
|
||||
allowedHosts := fs.String("allowed-hosts", "", "")
|
||||
fs.Parse(args[1:])
|
||||
cliSet := map[string]bool{}
|
||||
fs.Visit(func(f *flag.Flag) { cliSet[f.Name] = true })
|
||||
resolved, err := config.Load(*cfgFile, os.LookupEnv, config.Config{
|
||||
Addr: *addr, DataDir: *data, PluginsDir: *pluginsDir, Mock: *mock,
|
||||
StorageDSN: *dsn, ArtifactsDir: *artifacts, AuthMode: *auth, Instance: *instance,
|
||||
}, cliSet)
|
||||
InsecureListen: *insecure, AllowedHostsRaw: *allowedHosts,
|
||||
}, visited(fs))
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "agent-system:", err)
|
||||
return 1
|
||||
|
||||
Reference in New Issue
Block a user