package agentkey import ( "crypto/rand" "encoding/hex" "fmt" "os" "path/filepath" "strings" ) const ( fileName = "agent.key" keyBytes = 32 keyLen = keyBytes * 2 ) func LoadOrCreate(stateDir string) (string, error) { if err := os.MkdirAll(stateDir, 0o700); err != nil { return "", err } if err := os.Chmod(stateDir, 0o700); err != nil { return "", err } path := filepath.Join(stateDir, fileName) if info, err := os.Stat(path); err == nil { if !info.Mode().IsRegular() { return "", fmt.Errorf("agent key is not a regular file: %s", path) } if info.Mode().Perm() != 0o600 { if err := os.Chmod(path, 0o600); err != nil { return "", err } } b, err := os.ReadFile(path) if err != nil { return "", err } return validate(strings.TrimSpace(string(b)), path) } else if !os.IsNotExist(err) { return "", err } key, err := generate() if err != nil { return "", err } tmp := fmt.Sprintf("%s.%d.tmp", path, os.Getpid()) defer os.Remove(tmp) if err := os.WriteFile(tmp, []byte(key+"\n"), 0o600); err != nil { return "", err } if err := os.Rename(tmp, path); err != nil { return "", err } return key, nil } func validate(key string, path string) (string, error) { if len(key) != keyLen { return "", fmt.Errorf("invalid agent key in %s", path) } if _, err := hex.DecodeString(key); err != nil { return "", fmt.Errorf("invalid agent key in %s", path) } return strings.ToLower(key), nil } func generate() (string, error) { var b [keyBytes]byte if _, err := rand.Read(b[:]); err != nil { return "", err } return hex.EncodeToString(b[:]), nil }