Merge pull request 'chore: Go 1.26 modernization' (#2) from chore/go-1.26-modernization into main
This commit is contained in:
commit
8f049dd29c
11 changed files with 58 additions and 45 deletions
|
|
@ -6,6 +6,7 @@ import (
|
|||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
|
@ -134,7 +135,7 @@ func CreateMinerBundle(minerPath string, profileJSON []byte, name string, passwo
|
|||
func ExtractProfileBundle(bundle *Bundle, password string) ([]byte, error) {
|
||||
// Verify checksum first
|
||||
if calculateChecksum(bundle.Data) != bundle.Checksum {
|
||||
return nil, fmt.Errorf("checksum mismatch - bundle may be corrupted")
|
||||
return nil, errors.New("checksum mismatch - bundle may be corrupted")
|
||||
}
|
||||
|
||||
// If it's unencrypted JSON, just return it
|
||||
|
|
@ -155,7 +156,7 @@ func ExtractProfileBundle(bundle *Bundle, password string) ([]byte, error) {
|
|||
func ExtractMinerBundle(bundle *Bundle, password string, destDir string) (string, []byte, error) {
|
||||
// Verify checksum
|
||||
if calculateChecksum(bundle.Data) != bundle.Checksum {
|
||||
return "", nil, fmt.Errorf("checksum mismatch - bundle may be corrupted")
|
||||
return "", nil, errors.New("checksum mismatch - bundle may be corrupted")
|
||||
}
|
||||
|
||||
// Decrypt STIM format
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package node
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -106,7 +107,7 @@ func (c *Controller) sendRequest(peerID string, msg *Message, timeout time.Durat
|
|||
case resp := <-respCh:
|
||||
return resp, nil
|
||||
case <-ctx.Done():
|
||||
return nil, fmt.Errorf("request timeout")
|
||||
return nil, errors.New("request timeout")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +115,7 @@ func (c *Controller) sendRequest(peerID string, msg *Message, timeout time.Durat
|
|||
func (c *Controller) GetRemoteStats(peerID string) (*StatsPayload, error) {
|
||||
identity := c.node.GetIdentity()
|
||||
if identity == nil {
|
||||
return nil, fmt.Errorf("node identity not initialized")
|
||||
return nil, ErrIdentityNotInitialized
|
||||
}
|
||||
|
||||
msg, err := NewMessage(MsgGetStats, identity.ID, peerID, nil)
|
||||
|
|
@ -139,11 +140,11 @@ func (c *Controller) GetRemoteStats(peerID string) (*StatsPayload, error) {
|
|||
func (c *Controller) StartRemoteMiner(peerID, minerType, profileID string, configOverride json.RawMessage) error {
|
||||
identity := c.node.GetIdentity()
|
||||
if identity == nil {
|
||||
return fmt.Errorf("node identity not initialized")
|
||||
return ErrIdentityNotInitialized
|
||||
}
|
||||
|
||||
if minerType == "" {
|
||||
return fmt.Errorf("miner type is required")
|
||||
return errors.New("miner type is required")
|
||||
}
|
||||
|
||||
payload := StartMinerPayload{
|
||||
|
|
@ -178,7 +179,7 @@ func (c *Controller) StartRemoteMiner(peerID, minerType, profileID string, confi
|
|||
func (c *Controller) StopRemoteMiner(peerID, minerName string) error {
|
||||
identity := c.node.GetIdentity()
|
||||
if identity == nil {
|
||||
return fmt.Errorf("node identity not initialized")
|
||||
return ErrIdentityNotInitialized
|
||||
}
|
||||
|
||||
payload := StopMinerPayload{
|
||||
|
|
@ -211,7 +212,7 @@ func (c *Controller) StopRemoteMiner(peerID, minerName string) error {
|
|||
func (c *Controller) GetRemoteLogs(peerID, minerName string, lines int) ([]string, error) {
|
||||
identity := c.node.GetIdentity()
|
||||
if identity == nil {
|
||||
return nil, fmt.Errorf("node identity not initialized")
|
||||
return nil, ErrIdentityNotInitialized
|
||||
}
|
||||
|
||||
payload := GetLogsPayload{
|
||||
|
|
@ -270,7 +271,7 @@ func (c *Controller) GetAllStats() map[string]*StatsPayload {
|
|||
func (c *Controller) PingPeer(peerID string) (float64, error) {
|
||||
identity := c.node.GetIdentity()
|
||||
if identity == nil {
|
||||
return 0, fmt.Errorf("node identity not initialized")
|
||||
return 0, ErrIdentityNotInitialized
|
||||
}
|
||||
sentAt := time.Now()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"iter"
|
||||
"sync"
|
||||
|
|
@ -136,8 +137,8 @@ var (
|
|||
|
||||
// ErrUnknownIntent is returned when no handler is registered for the
|
||||
// packet's IntentID.
|
||||
ErrUnknownIntent = fmt.Errorf("packet dropped: unknown intent")
|
||||
ErrUnknownIntent = errors.New("packet dropped: unknown intent")
|
||||
|
||||
// ErrNilPacket is returned when a nil packet is passed to Dispatch.
|
||||
ErrNilPacket = fmt.Errorf("dispatch: nil packet")
|
||||
ErrNilPacket = errors.New("dispatch: nil packet")
|
||||
)
|
||||
|
|
|
|||
14
node/errors.go
Normal file
14
node/errors.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package node
|
||||
|
||||
import "errors"
|
||||
|
||||
// Sentinel errors shared across the node package.
|
||||
var (
|
||||
// ErrIdentityNotInitialized is returned when a node operation requires
|
||||
// a node identity but none has been generated or loaded.
|
||||
ErrIdentityNotInitialized = errors.New("node identity not initialized")
|
||||
|
||||
// ErrMinerManagerNotConfigured is returned when a miner operation is
|
||||
// attempted but no MinerManager has been set on the Worker.
|
||||
ErrMinerManagerNotConfigured = errors.New("miner manager not configured")
|
||||
)
|
||||
|
|
@ -173,7 +173,7 @@ func (n *NodeManager) DeriveSharedSecret(peerPubKeyBase64 string) ([]byte, error
|
|||
defer n.mu.RUnlock()
|
||||
|
||||
if n.privateKey == nil {
|
||||
return nil, fmt.Errorf("node identity not initialized")
|
||||
return nil, ErrIdentityNotInitialized
|
||||
}
|
||||
|
||||
// Load peer's public key
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ import (
|
|||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"math"
|
||||
"sort"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// Portable storage signatures and version (9-byte header).
|
||||
|
|
@ -299,11 +300,7 @@ func EncodeStorage(s Section) ([]byte, error) {
|
|||
// encodeSection appends a section (entry count + entries) to buf.
|
||||
func encodeSection(buf []byte, s Section) ([]byte, error) {
|
||||
// Sort keys for deterministic output.
|
||||
keys := make([]string, 0, len(s))
|
||||
for k := range s {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
keys := slices.Sorted(maps.Keys(s))
|
||||
|
||||
// Entry count as varint.
|
||||
buf = append(buf, PackVarint(uint64(len(keys)))...)
|
||||
|
|
|
|||
13
node/peer.go
13
node/peer.go
|
|
@ -2,6 +2,7 @@ package node
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"iter"
|
||||
"maps"
|
||||
|
|
@ -12,8 +13,8 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
poindexter "forge.lthn.ai/Snider/Poindexter"
|
||||
"forge.lthn.ai/core/go-p2p/logging"
|
||||
"forge.lthn.ai/Snider/Poindexter"
|
||||
"github.com/adrg/xdg"
|
||||
)
|
||||
|
||||
|
|
@ -84,7 +85,7 @@ func validatePeerName(name string) error {
|
|||
return fmt.Errorf("peer name too long (max %d characters)", PeerNameMaxLength)
|
||||
}
|
||||
if !peerNameRegex.MatchString(name) {
|
||||
return fmt.Errorf("peer name contains invalid characters (use alphanumeric, hyphens, underscores, spaces)")
|
||||
return errors.New("peer name contains invalid characters (use alphanumeric, hyphens, underscores, spaces)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -243,7 +244,7 @@ func (r *PeerRegistry) AddPeer(peer *Peer) error {
|
|||
|
||||
if peer.ID == "" {
|
||||
r.mu.Unlock()
|
||||
return fmt.Errorf("peer ID is required")
|
||||
return errors.New("peer ID is required")
|
||||
}
|
||||
|
||||
// Validate peer name (P2P-LOW-3)
|
||||
|
|
@ -376,11 +377,7 @@ func (r *PeerRegistry) UpdateScore(id string, score float64) error {
|
|||
}
|
||||
|
||||
// Clamp score to 0-100
|
||||
if score < 0 {
|
||||
score = 0
|
||||
} else if score > 100 {
|
||||
score = 100
|
||||
}
|
||||
score = max(0, min(score, 100))
|
||||
|
||||
peer.Score = score
|
||||
r.rebuildKDTree()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
|
|
@ -24,7 +25,7 @@ type ResponseHandler struct{}
|
|||
// 3. If response type matches expected (returns error if not)
|
||||
func (h *ResponseHandler) ValidateResponse(resp *Message, expectedType MessageType) error {
|
||||
if resp == nil {
|
||||
return fmt.Errorf("nil response")
|
||||
return errors.New("nil response")
|
||||
}
|
||||
|
||||
// Check for error response
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"iter"
|
||||
"maps"
|
||||
|
|
@ -621,7 +622,7 @@ func (t *Transport) performHandshake(pc *PeerConnection) error {
|
|||
|
||||
identity := t.node.GetIdentity()
|
||||
if identity == nil {
|
||||
return fmt.Errorf("node identity not initialized")
|
||||
return ErrIdentityNotInitialized
|
||||
}
|
||||
|
||||
// Generate challenge for the server to prove it has the matching private key
|
||||
|
|
@ -689,10 +690,10 @@ func (t *Transport) performHandshake(pc *PeerConnection) error {
|
|||
|
||||
// Verify the server's response to our challenge
|
||||
if len(ackPayload.ChallengeResponse) == 0 {
|
||||
return fmt.Errorf("server did not provide challenge response")
|
||||
return errors.New("server did not provide challenge response")
|
||||
}
|
||||
if !VerifyChallenge(challenge, ackPayload.ChallengeResponse, sharedSecret) {
|
||||
return fmt.Errorf("challenge response verification failed: server may not have matching private key")
|
||||
return errors.New("challenge response verification failed: server may not have matching private key")
|
||||
}
|
||||
|
||||
// Store the shared secret for later use
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package node
|
|||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
|
@ -130,7 +131,7 @@ func (w *Worker) handlePing(msg *Message) (*Message, error) {
|
|||
func (w *Worker) handleGetStats(msg *Message) (*Message, error) {
|
||||
identity := w.node.GetIdentity()
|
||||
if identity == nil {
|
||||
return nil, fmt.Errorf("node identity not initialized")
|
||||
return nil, ErrIdentityNotInitialized
|
||||
}
|
||||
|
||||
stats := StatsPayload{
|
||||
|
|
@ -193,7 +194,7 @@ func convertMinerStats(miner MinerInstance, rawStats any) MinerStatsItem {
|
|||
// handleStartMiner starts a miner with the given profile.
|
||||
func (w *Worker) handleStartMiner(msg *Message) (*Message, error) {
|
||||
if w.minerManager == nil {
|
||||
return nil, fmt.Errorf("miner manager not configured")
|
||||
return nil, ErrMinerManagerNotConfigured
|
||||
}
|
||||
|
||||
var payload StartMinerPayload
|
||||
|
|
@ -203,7 +204,7 @@ func (w *Worker) handleStartMiner(msg *Message) (*Message, error) {
|
|||
|
||||
// Validate miner type is provided
|
||||
if payload.MinerType == "" {
|
||||
return nil, fmt.Errorf("miner type is required")
|
||||
return nil, errors.New("miner type is required")
|
||||
}
|
||||
|
||||
// Get the config from the profile or use the override
|
||||
|
|
@ -217,7 +218,7 @@ func (w *Worker) handleStartMiner(msg *Message) (*Message, error) {
|
|||
}
|
||||
config = profile
|
||||
} else {
|
||||
return nil, fmt.Errorf("no config provided and no profile manager configured")
|
||||
return nil, errors.New("no config provided and no profile manager configured")
|
||||
}
|
||||
|
||||
// Start the miner
|
||||
|
|
@ -240,7 +241,7 @@ func (w *Worker) handleStartMiner(msg *Message) (*Message, error) {
|
|||
// handleStopMiner stops a running miner.
|
||||
func (w *Worker) handleStopMiner(msg *Message) (*Message, error) {
|
||||
if w.minerManager == nil {
|
||||
return nil, fmt.Errorf("miner manager not configured")
|
||||
return nil, ErrMinerManagerNotConfigured
|
||||
}
|
||||
|
||||
var payload StopMinerPayload
|
||||
|
|
@ -263,7 +264,7 @@ func (w *Worker) handleStopMiner(msg *Message) (*Message, error) {
|
|||
// handleGetLogs returns console logs from a miner.
|
||||
func (w *Worker) handleGetLogs(msg *Message) (*Message, error) {
|
||||
if w.minerManager == nil {
|
||||
return nil, fmt.Errorf("miner manager not configured")
|
||||
return nil, ErrMinerManagerNotConfigured
|
||||
}
|
||||
|
||||
var payload GetLogsPayload
|
||||
|
|
@ -317,7 +318,7 @@ func (w *Worker) handleDeploy(conn *PeerConnection, msg *Message) (*Message, err
|
|||
switch bundle.Type {
|
||||
case BundleProfile:
|
||||
if w.profileManager == nil {
|
||||
return nil, fmt.Errorf("profile manager not configured")
|
||||
return nil, errors.New("profile manager not configured")
|
||||
}
|
||||
|
||||
// Decrypt and extract profile data
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
|
|
@ -40,25 +39,25 @@ func ReadAndVerify(r *bufio.Reader, sharedSecret []byte) (*ParsedPacket, error)
|
|||
// Stop recording signedData here (HMAC covers headers + payload, but logic splits)
|
||||
// Actually, wait. The HMAC covers (Headers + Payload).
|
||||
// We need to read the payload to verify.
|
||||
|
||||
|
||||
// For this implementation, we read until EOF or a specific delimiter?
|
||||
// In a TCP stream, we need a length.
|
||||
// If you are using standard TCP, you typically prefix the WHOLE frame with
|
||||
// In a TCP stream, we need a length.
|
||||
// If you are using standard TCP, you typically prefix the WHOLE frame with
|
||||
// a 4-byte length. Assuming you handle that framing *before* calling this.
|
||||
|
||||
|
||||
// Reading the rest as payload:
|
||||
remaining, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payload = remaining
|
||||
|
||||
|
||||
// Add 0xFF and payload to the buffer for signature check?
|
||||
// NO. In MarshalAndSign:
|
||||
// mac.Write(buf.Bytes()) // Headers
|
||||
// mac.Write(p.Payload) // Data
|
||||
// It did NOT write the 0xFF tag into the HMAC.
|
||||
|
||||
|
||||
break // Exit loop
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +127,7 @@ func ReadAndVerify(r *bufio.Reader, sharedSecret []byte) (*ParsedPacket, error)
|
|||
if !hmac.Equal(signature, expectedMAC) {
|
||||
// Log this. This is a Threat Event.
|
||||
// "Axiom Violation: Integrity Check Failed"
|
||||
return nil, fmt.Errorf("integrity violation: HMAC mismatch (ThreatScore +100)")
|
||||
return nil, errors.New("integrity violation: HMAC mismatch (ThreatScore +100)")
|
||||
}
|
||||
|
||||
return &ParsedPacket{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue