mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 17:38:10 +00:00
安全修复(客户端鉴权): - 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 插件路由:名称白名单校验防路径穿越、保留字路径保护
178 lines
3.6 KiB
Go
178 lines
3.6 KiB
Go
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
|
||
}
|