Files
HomeAgent/cmd/waiter/config.go
JianFeeeee ba5785036a feat: 设备鉴权迁移至客户端 + 插件卸载保护
安全修复(客户端鉴权):
- remotedevice 服务端移除授权状态存储(authorized map/SetAuthorized/handleDeviceAuth)
- DeviceMeta.Authorized 改为设备 hello 自报,服务端仅透传展示
- device_ctl_* 工具移除服务端授权检查,无条件转发,设备端自行决定是否执行
- 共享设备桥库 Bridge 新增本地 authorized 状态,未授权收到 cmd 直接拒绝
- waiter: --device-authorized / device_authorized 配置控制本地授权
- GUI: 授权存 gui-prefs 本地文件;设备页仅本机可切换开关
- webui /device/auth 旧路径返回 410 Gone
- 根因:agent 可经 config_set 篡改服务端授权配置自行授权设备

插件管理强化:
- 内置插件禁止卸载(IsBuiltinPlugin + 409),外部插件卸载即时生效
- 卸载不存在插件返回 404;移除误导性 reload_required 提示
- webui 插件路由:名称白名单校验防路径穿越、保留字路径保护
2026-08-24 19:26:11 +08:00

178 lines
3.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"fmt"
"os"
"path/filepath"
"gopkg.in/yaml.v3"
)
type Connection struct {
Name string `yaml:"name"`
Socket string `yaml:"socket,omitempty"`
Remote string `yaml:"remote,omitempty"`
APIKey string `yaml:"api_key,omitempty"`
}
type Config struct {
Socket string `yaml:"socket"`
Remote string `yaml:"remote"`
APIKey string `yaml:"api_key"`
Default string `yaml:"default"`
Connections []Connection `yaml:"connections,omitempty"`
DeviceGateway string `yaml:"device_gateway,omitempty"` // remotedevice 网关地址(如 127.0.0.1:9890
DeviceToken string `yaml:"device_token,omitempty"` // 设备接入 token
DeviceAuthorized bool `yaml:"device_authorized,omitempty"` // 客户端本地授权(用户手动开启,服务端无法篡改)
}
func (c *Config) Active() *Connection {
for i := range c.Connections {
if c.Connections[i].Name == c.Default {
return &c.Connections[i]
}
}
return nil
}
func (c *Config) ApplyDefault() {
conn := c.Active()
if conn == nil {
return
}
if c.Socket == "" && c.Remote == "" {
c.Socket = conn.Socket
c.Remote = conn.Remote
c.APIKey = conn.APIKey
}
}
func discoverConfig(configPath string) *Config {
if configPath != "" {
if cfg := readFile(configPath); cfg != nil {
return cfg
}
}
candidates := configCandidates()
for _, p := range candidates {
if cfg := readFile(p); cfg != nil {
return cfg
}
}
return &Config{}
}
func configCandidates() []string {
var cands []string
home, _ := os.UserHomeDir()
if home != "" {
cands = append(cands, filepath.Join(home, ".config", "homeagent", "waiter.yaml"))
}
cands = append(cands, "/root/.config/homeagent/waiter.yaml")
cands = append(cands, filepath.Join(".", "waiter.yaml"))
if exe, err := os.Executable(); err == nil {
cands = append(cands, filepath.Join(filepath.Dir(exe), "waiter.yaml"))
}
return cands
}
func configPath() string {
home, _ := os.UserHomeDir()
if home == "" {
return ""
}
return filepath.Join(home, ".config", "homeagent", "waiter.yaml")
}
func readFile(path string) *Config {
data, err := os.ReadFile(path)
if err != nil {
return nil
}
var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
fmt.Fprintf(os.Stderr, "warning: %s: %v\n", path, err)
return nil
}
return &cfg
}
func (c *Config) Save() {
p := configPath()
if p == "" {
return
}
os.MkdirAll(filepath.Dir(p), 0755)
data, err := yaml.Marshal(c)
if err != nil {
return
}
os.WriteFile(p, data, 0644)
}
func (c *Config) MergeCLI(socket, remote, apiKey string) {
if socket != "" {
c.Socket = socket
}
if remote != "" {
c.Remote = remote
}
if apiKey != "" {
c.APIKey = apiKey
}
}
func (c *Config) SaveConnection(name string) {
conn := Connection{
Name: name,
Socket: c.Socket,
Remote: c.Remote,
APIKey: c.APIKey,
}
for i, existing := range c.Connections {
if existing.Name == name {
c.Connections[i] = conn
c.Default = name
c.Save()
return
}
}
c.Connections = append(c.Connections, conn)
c.Default = name
c.Save()
}
func (c *Config) SwitchConnection(name string) bool {
for _, conn := range c.Connections {
if conn.Name == name {
c.Socket = conn.Socket
c.Remote = conn.Remote
c.APIKey = conn.APIKey
c.Default = name
c.Save()
return true
}
}
return false
}
func (c *Config) DeleteConnection(name string) bool {
for i, conn := range c.Connections {
if conn.Name == name {
c.Connections = append(c.Connections[:i], c.Connections[i+1:]...)
if c.Default == name {
c.Default = ""
}
c.Save()
return true
}
}
return false
}