fix: Address high severity security and reliability issues
Security: - Configure CORS to only allow local origins (localhost, 127.0.0.1, wails://) - Add CLI args validation for TTMiner to block shell metacharacters - Add HTTPPort validation (must be 1024-65535) Reliability: - Manager.Stop() now stops all running miners before shutdown - Close stdin pipe on Start() error to prevent resource leak (xmrig, ttminer) - Fix node_service query parameter parsing (was dead code) Feature: - Add TTMiner support in service layer (install, update check, info cache) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
006dd3712e
commit
68c0033c55
5 changed files with 75 additions and 5 deletions
|
|
@ -212,6 +212,13 @@ func (m *Manager) StartMiner(minerType string, config *Config) (Miner, error) {
|
|||
return nil, fmt.Errorf("a miner with a similar configuration is already running: %s", instanceName)
|
||||
}
|
||||
|
||||
// Validate user-provided HTTPPort if specified
|
||||
if config.HTTPPort != 0 {
|
||||
if config.HTTPPort < 1024 || config.HTTPPort > 65535 {
|
||||
return nil, fmt.Errorf("HTTPPort must be between 1024 and 65535, got %d", config.HTTPPort)
|
||||
}
|
||||
}
|
||||
|
||||
apiPort, err := findAvailablePort()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find an available port for the miner API: %w", err)
|
||||
|
|
@ -471,8 +478,17 @@ func (m *Manager) GetMinerHashrateHistory(name string) ([]HashratePoint, error)
|
|||
return miner.GetHashrateHistory(), nil
|
||||
}
|
||||
|
||||
// Stop stops the manager and its background goroutines.
|
||||
// Stop stops all running miners, background goroutines, and closes resources.
|
||||
func (m *Manager) Stop() {
|
||||
// Stop all running miners first
|
||||
m.mu.Lock()
|
||||
for name, miner := range m.miners {
|
||||
if err := miner.Stop(); err != nil {
|
||||
log.Printf("Warning: failed to stop miner %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
m.mu.Unlock()
|
||||
|
||||
close(m.stopChan)
|
||||
m.waitGroup.Wait()
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package mining
|
|||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/Snider/Mining/pkg/node"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
|
@ -407,8 +408,8 @@ func (ns *NodeService) handleRemoteLogs(c *gin.Context) {
|
|||
minerName := c.Param("miner")
|
||||
lines := 100
|
||||
if l := c.Query("lines"); l != "" {
|
||||
if _, err := c.GetQuery("lines"); err {
|
||||
// Use default
|
||||
if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 {
|
||||
lines = parsed
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,25 @@ func NewService(manager ManagerInterface, listenAddr string, displayAddr string,
|
|||
// After calling InitRouter, you can use the Router field directly as an http.Handler.
|
||||
func (s *Service) InitRouter() {
|
||||
s.Router = gin.Default()
|
||||
s.Router.Use(cors.Default())
|
||||
|
||||
// Configure CORS to only allow local origins
|
||||
corsConfig := cors.Config{
|
||||
AllowOrigins: []string{
|
||||
"http://localhost:4200", // Angular dev server
|
||||
"http://127.0.0.1:4200",
|
||||
"http://localhost:9090", // Default API port
|
||||
"http://127.0.0.1:9090",
|
||||
"http://localhost:" + strings.Split(s.Server.Addr, ":")[len(strings.Split(s.Server.Addr, ":"))-1],
|
||||
"http://127.0.0.1:" + strings.Split(s.Server.Addr, ":")[len(strings.Split(s.Server.Addr, ":"))-1],
|
||||
"wails://wails", // Wails desktop app
|
||||
},
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||
AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization"},
|
||||
ExposeHeaders: []string{"Content-Length"},
|
||||
AllowCredentials: true,
|
||||
MaxAge: 12 * time.Hour,
|
||||
}
|
||||
s.Router.Use(cors.New(corsConfig))
|
||||
s.SetupRoutes()
|
||||
}
|
||||
|
||||
|
|
@ -207,6 +225,8 @@ func (s *Service) updateInstallationCache() (*SystemInfo, error) {
|
|||
switch availableMiner.Name {
|
||||
case "xmrig":
|
||||
miner = NewXMRigMiner()
|
||||
case "tt-miner":
|
||||
miner = NewTTMiner()
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
|
@ -265,6 +285,8 @@ func (s *Service) handleUpdateCheck(c *gin.Context) {
|
|||
switch availableMiner.Name {
|
||||
case "xmrig":
|
||||
miner = NewXMRigMiner()
|
||||
case "tt-miner":
|
||||
miner = NewTTMiner()
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
|
@ -360,6 +382,8 @@ func (s *Service) handleInstallMiner(c *gin.Context) {
|
|||
switch minerType {
|
||||
case "xmrig":
|
||||
miner = NewXMRigMiner()
|
||||
case "tt-miner":
|
||||
miner = NewTTMiner()
|
||||
default:
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "unknown miner type"})
|
||||
return
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ func (m *TTMiner) Start(config *Config) error {
|
|||
}
|
||||
|
||||
if err := m.cmd.Start(); err != nil {
|
||||
stdinPipe.Close()
|
||||
return fmt.Errorf("failed to start TT-Miner: %w", err)
|
||||
}
|
||||
|
||||
|
|
@ -131,6 +132,33 @@ func addTTMinerCliArgs(config *Config, args *[]string) {
|
|||
// Add any extra arguments passed via CLIArgs
|
||||
if config.CLIArgs != "" {
|
||||
extraArgs := strings.Fields(config.CLIArgs)
|
||||
*args = append(*args, extraArgs...)
|
||||
for _, arg := range extraArgs {
|
||||
// Skip potentially dangerous arguments
|
||||
if isValidCLIArg(arg) {
|
||||
*args = append(*args, arg)
|
||||
} else {
|
||||
log.Printf("Warning: skipping invalid CLI argument: %s", arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isValidCLIArg validates CLI arguments to prevent injection or dangerous patterns
|
||||
func isValidCLIArg(arg string) bool {
|
||||
// Block shell metacharacters and dangerous patterns
|
||||
dangerousPatterns := []string{";", "|", "&", "`", "$", "(", ")", "{", "}", "<", ">", "\n", "\r"}
|
||||
for _, p := range dangerousPatterns {
|
||||
if strings.Contains(arg, p) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// Block arguments that could override security-related settings
|
||||
blockedArgs := []string{"--api-access-token", "--api-worker-id"}
|
||||
lowerArg := strings.ToLower(arg)
|
||||
for _, blocked := range blockedArgs {
|
||||
if strings.HasPrefix(lowerArg, blocked) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ func (m *XMRigMiner) Start(config *Config) error {
|
|||
}
|
||||
|
||||
if err := m.cmd.Start(); err != nil {
|
||||
stdinPipe.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue