diff --git a/CHANGELOG.md b/CHANGELOG.md index 6801cc7..6a8ede3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,15 +8,23 @@ The format is based on [Keep a Changelog][keepachangelog] and adheres to [Semant ### Added +- Added identity/main.go to generate identity and peer id +- Added encryption module identity.go for reusable identity create, save etc funtions + ### Changed +- Updated make file to support identity/main.go +- Updated node/node.go on loadOrCreateIdentity to use encryption.identity +- Updated cli/main.go to remove fallbacks for identity +- Updated install-debros-network.sh script to use new ./cmd/identity and fixed port order on print + ### Deprecated ### Removed ### Fixed -## [0.50.0] - 2025-09-23 +## [0.50.1] - 2025-09-23 ### Added diff --git a/Makefile b/Makefile index 4424a56..f0e8f22 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ test-e2e: .PHONY: build clean test run-node run-node2 run-node3 run-example deps tidy fmt vet lint clear-ports -VERSION := 0.50.1-beta +VERSION := 0.51.0-beta COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ) LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)' @@ -30,6 +30,7 @@ LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date build: deps @echo "Building network executables (version=$(VERSION))..." @mkdir -p bin + go build -ldflags "$(LDFLAGS)" -o bin/identity ./cmd/identity go build -ldflags "$(LDFLAGS)" -o bin/node ./cmd/node go build -ldflags "$(LDFLAGS)" -o bin/network-cli cmd/cli/main.go # Inject gateway build metadata via pkg path variables diff --git a/cmd/cli/main.go b/cmd/cli/main.go index c3fd8a6..e115113 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -2,7 +2,6 @@ package main import ( "context" - "encoding/base64" "encoding/json" "fmt" "log" @@ -363,50 +362,6 @@ func handlePeerID() { } } - // Fallback: try to extract from local identity files - identityPaths := []string{ - "/opt/debros/data/node/identity.key", - "/opt/debros/data/bootstrap/identity.key", - "/opt/debros/keys/node/identity.key", - "./data/node/identity.key", - "./data/bootstrap/identity.key", - } - - for _, path := range identityPaths { - if peerID := extractPeerIDFromFile(path); peerID != "" { - if format == "json" { - printJSON(map[string]string{"peer_id": peerID, "source": "local_identity"}) - } else { - fmt.Printf("🆔 Peer ID: %s\n", peerID) - fmt.Printf("📂 Source: %s\n", path) - } - return - } - } - - // Check peer.info files as last resort - peerInfoPaths := []string{ - "/opt/debros/data/node/peer.info", - "/opt/debros/data/bootstrap/peer.info", - "./data/node/peer.info", - "./data/bootstrap/peer.info", - } - - for _, path := range peerInfoPaths { - if data, err := os.ReadFile(path); err == nil { - multiaddr := strings.TrimSpace(string(data)) - if peerID := extractPeerIDFromMultiaddr(multiaddr); peerID != "" { - if format == "json" { - printJSON(map[string]string{"peer_id": peerID, "source": "peer_info"}) - } else { - fmt.Printf("🆔 Peer ID: %s\n", peerID) - fmt.Printf("📂 Source: %s\n", path) - } - return - } - } - } - fmt.Fprintf(os.Stderr, "❌ Could not find peer ID. Make sure the node is running or identity files exist.\n") os.Exit(1) } @@ -470,20 +425,6 @@ func discoverBootstrapPeer() string { return "" // Return empty string if no peer info found } -func tryDecodeBase64(s string) string { - // Only try to decode if it looks like base64 (no spaces, reasonable length) - if len(s) > 0 && len(s)%4 == 0 && !strings.ContainsAny(s, " \n\r\t") { - if decoded, err := base64.StdEncoding.DecodeString(s); err == nil { - // Check if decoded result looks like readable text - decodedStr := string(decoded) - if isPrintableText(decodedStr) { - return decodedStr - } - } - } - return s -} - func isPrintableText(s string) bool { printableCount := 0 for _, r := range s { diff --git a/cmd/identity/main.go b/cmd/identity/main.go new file mode 100644 index 0000000..3fb914c --- /dev/null +++ b/cmd/identity/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/DeBrosOfficial/network/pkg/encryption" +) + +func main() { + var outputPath string + var displayOnly bool + + flag.StringVar(&outputPath, "output", "", "Output path for identity key") + flag.BoolVar(&displayOnly, "display-only", false, "Only display identity info, don't save") + flag.Parse() + + // Generate identity using shared package + info, err := encryption.GenerateIdentity() + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to generate identity: %v\n", err) + os.Exit(1) + } + + // If display only, just show the info + if displayOnly { + fmt.Printf("Node Identity: %s\n", info.PeerID.String()) + return + } + + // Save to file using shared package + if outputPath == "" { + fmt.Fprintln(os.Stderr, "Output path is required") + os.Exit(1) + } + + if err := encryption.SaveIdentity(info, outputPath); err != nil { + fmt.Fprintf(os.Stderr, "Failed to save identity: %v\n", err) + os.Exit(1) + } + + fmt.Printf("Generated Node Identity: %s\n", info.PeerID.String()) + fmt.Printf("Identity saved to: %s\n", outputPath) +} diff --git a/pkg/encryption/identity.go b/pkg/encryption/identity.go new file mode 100644 index 0000000..3d69df8 --- /dev/null +++ b/pkg/encryption/identity.go @@ -0,0 +1,71 @@ +package encryption + +import ( + "crypto/rand" + "os" + "path/filepath" + + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" +) + +type IdentityInfo struct { + PrivateKey crypto.PrivKey + PublicKey crypto.PubKey + PeerID peer.ID +} + +func GenerateIdentity() (*IdentityInfo, error) { + priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, rand.Reader) + if err != nil { + return nil, err + } + + peerID, err := peer.IDFromPublicKey(pub) + if err != nil { + return nil, err + } + + return &IdentityInfo{ + PrivateKey: priv, + PublicKey: pub, + PeerID: peerID, + }, nil +} + +func SaveIdentity(identity *IdentityInfo, path string) error { + data, err := crypto.MarshalPrivateKey(identity.PrivateKey) + if err != nil { + return err + } + + if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { + return err + } + + return os.WriteFile(path, data, 0600) +} + +func LoadIdentity(path string) (*IdentityInfo, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + priv, err := crypto.UnmarshalPrivateKey(data) + if err != nil { + return nil, err + } + + pub := priv.GetPublic() + peerID, err := peer.IDFromPublicKey(pub) + if err != nil { + return nil, err + } + + return &IdentityInfo{ + PrivateKey: priv, + PublicKey: pub, + PeerID: peerID, + }, nil +} diff --git a/pkg/node/node.go b/pkg/node/node.go index 78fc0ab..fb1af01 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -2,7 +2,6 @@ package node import ( "context" - "crypto/rand" "fmt" mathrand "math/rand" "os" @@ -23,6 +22,7 @@ import ( "go.uber.org/zap" "github.com/DeBrosOfficial/network/pkg/config" + "github.com/DeBrosOfficial/network/pkg/encryption" "github.com/DeBrosOfficial/network/pkg/logging" "github.com/DeBrosOfficial/network/pkg/pubsub" database "github.com/DeBrosOfficial/network/pkg/rqlite" @@ -374,65 +374,41 @@ func (n *Node) startLibP2P() error { return nil } +// loadOrCreateIdentity loads an existing identity or creates a new one // loadOrCreateIdentity loads an existing identity or creates a new one func (n *Node) loadOrCreateIdentity() (crypto.PrivKey, error) { identityFile := filepath.Join(n.config.Node.DataDir, "identity.key") - // Try to load existing identity + // Try to load existing identity using the shared package if _, err := os.Stat(identityFile); err == nil { - data, err := os.ReadFile(identityFile) + info, err := encryption.LoadIdentity(identityFile) if err != nil { - return nil, fmt.Errorf("failed to read identity file: %w", err) - } - - priv, err := crypto.UnmarshalPrivateKey(data) - if err != nil { - n.logger.Warn("Failed to unmarshal existing identity, creating new one", zap.Error(err)) + n.logger.Warn("Failed to load existing identity, creating new one", zap.Error(err)) } else { - // Extract peer ID from private key for logging - peerID, err := peer.IDFromPrivateKey(priv) - if err != nil { - n.logger.ComponentInfo(logging.ComponentNode, "Loaded existing identity", - zap.String("file", identityFile), - zap.String("peer_id", "unable_to_extract")) - } else { - n.logger.ComponentInfo(logging.ComponentNode, "Loaded existing identity", - zap.String("file", identityFile), - zap.String("peer_id", peerID.String())) - } - return priv, nil + n.logger.ComponentInfo(logging.ComponentNode, "Loaded existing identity", + zap.String("file", identityFile), + zap.String("peer_id", info.PeerID.String())) + return info.PrivateKey, nil } } - // Create new identity + // Create new identity using shared package n.logger.Info("Creating new identity", zap.String("file", identityFile)) - priv, _, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, rand.Reader) + info, err := encryption.GenerateIdentity() if err != nil { - return nil, fmt.Errorf("failed to generate key pair: %w", err) + return nil, fmt.Errorf("failed to generate identity: %w", err) } - // Extract peer ID from private key for logging - peerID, err := peer.IDFromPrivateKey(priv) - if err != nil { - n.logger.Info("Identity created", - zap.String("peer_id", "unable_to_extract")) - } else { - n.logger.Info("Identity created", - zap.String("peer_id", peerID.String())) - } - - // Save identity - data, err := crypto.MarshalPrivateKey(priv) - if err != nil { - return nil, fmt.Errorf("failed to marshal private key: %w", err) - } - - if err := os.WriteFile(identityFile, data, 0600); err != nil { + // Save identity using shared package + if err := encryption.SaveIdentity(info, identityFile); err != nil { return nil, fmt.Errorf("failed to save identity: %w", err) } - n.logger.Info("Identity saved", zap.String("file", identityFile)) - return priv, nil + n.logger.Info("Identity saved", + zap.String("file", identityFile), + zap.String("peer_id", info.PeerID.String())) + + return info.PrivateKey, nil } // GetPeerID returns the peer ID of this node diff --git a/scripts/install-debros-network.sh b/scripts/install-debros-network.sh index a59ca2d..82e04e1 100755 --- a/scripts/install-debros-network.sh +++ b/scripts/install-debros-network.sh @@ -335,40 +335,8 @@ generate_identity() { fi log "Generating node identity..." cd "$INSTALL_DIR/src" - cat > /tmp/generate_identity_custom.go << 'EOF' -package main -import ( - "crypto/rand" - "flag" - "fmt" - "os" - "path/filepath" - "github.com/libp2p/go-libp2p/core/crypto" - "github.com/libp2p/go-libp2p/core/peer" -) -func main() { - var outputPath string - flag.StringVar(&outputPath, "output", "", "Output path for identity key") - flag.Parse() - if outputPath == "" { - fmt.Println("Usage: go run generate_identity_custom.go -output ") - os.Exit(1) - } - priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, rand.Reader) - if err != nil { panic(err) } - peerID, err := peer.IDFromPublicKey(pub) - if err != nil { panic(err) } - data, err := crypto.MarshalPrivateKey(priv) - if err != nil { panic(err) } - if err := os.MkdirAll(filepath.Dir(outputPath), 0700); err != nil { panic(err) } - if err := os.WriteFile(outputPath, data, 0600); err != nil { panic(err) } - fmt.Printf("Generated Peer ID: %s\n", peerID.String()) - fmt.Printf("Identity saved to: %s\n", outputPath) -} -EOF export PATH=$PATH:/usr/local/go/bin - sudo -u debros env "PATH=$PATH:/usr/local/go/bin" "GOMOD=$(pwd)" go run /tmp/generate_identity_custom.go -output "$identity_file" - rm /tmp/generate_identity_custom.go + sudo -u debros env "PATH=$PATH:/usr/local/go/bin" go run ./cmd/identity -output "$identity_file" success "Node identity generated" } @@ -560,10 +528,10 @@ main() { log "${GREEN}Installation Directory:${NOCOLOR} ${CYAN}$INSTALL_DIR${NOCOLOR}" log "${GREEN}Configuration:${NOCOLOR} ${CYAN}$INSTALL_DIR/configs/node.yaml${NOCOLOR}" log "${GREEN}Logs:${NOCOLOR} ${CYAN}$INSTALL_DIR/logs/node.log${NOCOLOR}" - log "${GREEN}Node Port:${NOCOLOR} ${CYAN}$NODE_PORT${NOCOLOR}" + log "${GREEN}LibP2P Port:${NOCOLOR} ${CYAN}$NODE_PORT${NOCOLOR}" log "${GREEN}RQLite Port:${NOCOLOR} ${CYAN}$RQLITE_PORT${NOCOLOR}" - log "${GREEN}Raft Port:${NOCOLOR} ${CYAN}$RAFT_PORT${NOCOLOR}" log "${GREEN}Gateway Port:${NOCOLOR} ${CYAN}$GATEWAY_PORT${NOCOLOR}" + log "${GREEN}Raft Port:${NOCOLOR} ${CYAN}$RAFT_PORT${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}" log "${GREEN}Management Commands:${NOCOLOR}" log "${CYAN} - sudo systemctl status debros-node${NOCOLOR} (Check status)"