From b353aedea710d58aded68fc37ca953a649edc28d Mon Sep 17 00:00:00 2001 From: BeaconCat Date: Mon, 4 May 2026 12:17:01 +0800 Subject: [PATCH] fix: read pico gateway token from security.yml dynamically GetPicoclawInternalToken() now reads the pico channel token directly from ~/.picoclaw/.security.yml on every call instead of caching. This ensures NanoKVM-Server always uses the same token that picoclaw gateway has, even after picoclaw restarts and regenerates its token. Fallback chain: security.yml -> cached -> legacy token file -> generate new --- server/config/picoclaw_internal.go | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/server/config/picoclaw_internal.go b/server/config/picoclaw_internal.go index b9fb6638..84dbe570 100644 --- a/server/config/picoclaw_internal.go +++ b/server/config/picoclaw_internal.go @@ -2,9 +2,12 @@ package config import ( "os" + "os/user" "path/filepath" "strings" "sync" + + "gopkg.in/yaml.v3" ) const ( @@ -21,10 +24,18 @@ func GetPicoclawInternalToken() (string, error) { picoclawInternalToken.mu.Lock() defer picoclawInternalToken.mu.Unlock() + // Always try to read the live pico token from security.yml first + if token := readPicoclawSecurityToken(); token != "" { + picoclawInternalToken.value = token + return token, nil + } + + // Fall back to cached value if picoclawInternalToken.value != "" { return picoclawInternalToken.value, nil } + // Fall back to the legacy token file if token, err := readPicoclawInternalToken(); err == nil { if token != "" { picoclawInternalToken.value = token @@ -59,3 +70,44 @@ func readPicoclawInternalToken() (string, error) { return strings.TrimSpace(string(data)), nil } + +type picoclawSecurityYAML struct { + ChannelList map[string]struct { + Token string `yaml:"token,omitempty"` + Settings *struct { + Token string `yaml:"token,omitempty"` + } `yaml:"settings,omitempty"` + } `yaml:"channel_list,omitempty"` +} + +func readPicoclawSecurityToken() string { + home := os.Getenv("PICOCLAW_HOME") + if home == "" { + u, err := user.Current() + if err != nil { + return "" + } + home = filepath.Join(u.HomeDir, ".picoclaw") + } + + data, err := os.ReadFile(filepath.Join(home, ".security.yml")) + if err != nil { + return "" + } + + var sec picoclawSecurityYAML + if err := yaml.Unmarshal(data, &sec); err != nil { + return "" + } + + entry, ok := sec.ChannelList["pico"] + if !ok { + return "" + } + if entry.Settings != nil { + if t := strings.TrimSpace(entry.Settings.Token); t != "" { + return t + } + } + return strings.TrimSpace(entry.Token) +}