From f9965c8f9cb04918b1dc72b8f47f1320fdd1d4aa Mon Sep 17 00:00:00 2001 From: ryyst Date: Thu, 18 Sep 2025 18:36:47 +0300 Subject: [PATCH] refactor: extract SHA3 hashing utilities to utils/hash.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move all SHA3-512 hashing functions to utils package - Update import statements and function calls - Maintain zero functional changes - First step in systematic main.go refactoring 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- --help | 33 +++++++++++++++++++++++++ main.go | 33 ++++++------------------- refactor.md | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++ utils/hash.go | 25 +++++++++++++++++++ 4 files changed, 134 insertions(+), 25 deletions(-) create mode 100644 --help create mode 100644 refactor.md create mode 100644 utils/hash.go diff --git a/--help b/--help new file mode 100644 index 0000000..7ed33ae --- /dev/null +++ b/--help @@ -0,0 +1,33 @@ +node_id: GALACTICA +bind_address: 127.0.0.1 +port: 8080 +data_dir: ./data +seed_nodes: [] +read_only: false +log_level: info +gossip_interval_min: 60 +gossip_interval_max: 120 +sync_interval: 300 +catchup_interval: 120 +bootstrap_max_age_hours: 720 +throttle_delay_ms: 100 +fetch_delay_ms: 50 +compression_enabled: true +compression_level: 3 +default_ttl: "0" +max_json_size: 1048576 +rate_limit_requests: 100 +rate_limit_window: 1m +tamper_log_actions: + - data_write + - user_create + - auth_failure +backup_enabled: true +backup_schedule: 0 0 * * * +backup_path: ./backups +backup_retention: 7 +auth_enabled: true +tamper_logging_enabled: true +clustering_enabled: true +rate_limiting_enabled: true +revision_history_enabled: true diff --git a/main.go b/main.go index b2fcaf8..2838f23 100644 --- a/main.go +++ b/main.go @@ -27,8 +27,9 @@ import ( "github.com/klauspost/compress/zstd" "github.com/robfig/cron/v3" "github.com/sirupsen/logrus" - "golang.org/x/crypto/sha3" "gopkg.in/yaml.v3" + + "kvs/utils" ) // Core data structures @@ -329,24 +330,6 @@ type Server struct { backupMu sync.RWMutex // Protects backup status } -// SHA3-512 hashing utilities for Phase 2 authentication -func hashSHA3512(input string) string { - hasher := sha3.New512() - hasher.Write([]byte(input)) - return hex.EncodeToString(hasher.Sum(nil)) -} - -func hashUserNickname(nickname string) string { - return hashSHA3512(nickname) -} - -func hashGroupName(groupname string) string { - return hashSHA3512(groupname) -} - -func hashToken(token string) string { - return hashSHA3512(token) -} // Phase 2: Storage key generation utilities func userStorageKey(userUUID string) string { @@ -488,7 +471,7 @@ func validateJWT(tokenString string) (*JWTClaims, error) { // storeAPIToken stores an API token in BadgerDB with TTL func (s *Server) storeAPIToken(tokenString string, userUUID string, scopes []string, expiresAt int64) error { - tokenHash := hashToken(tokenString) + tokenHash := utils.HashToken(tokenString) apiToken := APIToken{ TokenHash: tokenHash, @@ -598,7 +581,7 @@ func (s *Server) authenticateRequest(r *http.Request) (*AuthContext, error) { } // Verify token exists in our database (not revoked) - tokenHash := hashToken(tokenString) + tokenHash := utils.HashToken(tokenString) _, err = s.getAPIToken(tokenHash) if err == badger.ErrKeyNotFound { return nil, fmt.Errorf("token not found or revoked") @@ -1152,7 +1135,7 @@ func getMerkleLogKey(timestamp string) string { func generateLogSignature(timestamp, action, userUUID, resource string) string { // Concatenate all fields in a deterministic order data := fmt.Sprintf("%s|%s|%s|%s", timestamp, action, userUUID, resource) - return hashSHA3512(data) + return utils.HashSHA3512(data) } // isActionLogged checks if a specific action should be logged @@ -2771,7 +2754,7 @@ func (s *Server) createUserHandler(w http.ResponseWriter, r *http.Request) { user := User{ UUID: userUUID, - NicknameHash: hashUserNickname(req.Nickname), + NicknameHash: utils.HashUserNickname(req.Nickname), Groups: []string{}, CreatedAt: now, UpdatedAt: now, @@ -2883,7 +2866,7 @@ func (s *Server) updateUserHandler(w http.ResponseWriter, r *http.Request) { user.UpdatedAt = now if req.Nickname != "" { - user.NicknameHash = hashUserNickname(req.Nickname) + user.NicknameHash = utils.HashUserNickname(req.Nickname) } if req.Groups != nil { @@ -2971,7 +2954,7 @@ func (s *Server) createGroupHandler(w http.ResponseWriter, r *http.Request) { group := Group{ UUID: groupUUID, - NameHash: hashGroupName(req.Groupname), + NameHash: utils.HashGroupName(req.Groupname), Members: req.Members, CreatedAt: now, UpdatedAt: now, diff --git a/refactor.md b/refactor.md new file mode 100644 index 0000000..9f3e770 --- /dev/null +++ b/refactor.md @@ -0,0 +1,68 @@ +# Refactoring Proposal for KVS Main.go + +After analyzing your 3,990-line main.go file, I've identified clear functional areas that can be separated into manageable modules. +Here's my comprehensive refactoring proposal: + +Proposed File Structure + +kvs/ +├── main.go # Entry point + minimal server setup +├── config/ +│ └── config.go # Configuration structures and loading +├── types/ +│ └── types.go # All data structures and type definitions +├── auth/ +│ ├── auth.go # Authentication & authorization logic +│ ├── jwt.go # JWT token management +│ ├── middleware.go # Auth middleware +│ └── permissions.go # Permission checking utilities +├── storage/ +│ ├── storage.go # BadgerDB operations and utilities +│ ├── compression.go # ZSTD compression/decompression +│ ├── ttl.go # TTL and metadata management +│ └── revision.go # Revision history system +├── cluster/ +│ ├── gossip.go # Gossip protocol implementation +│ ├── members.go # Member management +│ ├── sync.go # Data synchronization +│ └── merkle.go # Merkle tree operations +├── server/ +│ ├── server.go # Server struct and core methods +│ ├── handlers.go # HTTP request handlers +│ ├── routes.go # Route setup +│ └── lifecycle.go # Server startup/shutdown logic +├── features/ +│ ├── ratelimit.go # Rate limiting middleware and utilities +│ ├── tamperlog.go # Tamper-evident logging +│ └── backup.go # Backup system +└── utils/ + └── hash.go # Hashing utilities (SHA3, etc.) + +Key Benefits + +1. Clear Separation of Concerns: Each package handles a specific responsibility +2. Better Testability: Smaller, focused functions are easier to unit test +3. Improved Maintainability: Changes to one feature don't affect others +4. Go Best Practices: Follows standard Go project layout conventions +5. Reduced Coupling: Clear interfaces between components + +Functional Areas Identified + +1. Configuration (~100 lines): Config structs, defaults, loading +2. Types (~400 lines): All data structures and constants +3. Authentication (~800 lines): User/Group/Token management, JWT, middleware +4. Storage (~600 lines): BadgerDB operations, compression, TTL, revisions +5. Clustering (~1,200 lines): Gossip, members, sync, Merkle trees +6. Server (~600 lines): Server struct, handlers, routes, lifecycle +7. Features (~200 lines): Rate limiting, tamper logging, backup +8. Utilities (~90 lines): Hashing and other utilities + +Migration Strategy + +1. Start with the most independent modules (types, config, utils) +2. Move storage and authentication components +3. Extract clustering logic +4. Refactor server components last +5. Create commits for each major module migration + +The refactoring will maintain zero functional changes - purely cosmetic restructuring for better code organization. diff --git a/utils/hash.go b/utils/hash.go new file mode 100644 index 0000000..c354c50 --- /dev/null +++ b/utils/hash.go @@ -0,0 +1,25 @@ +package utils + +import ( + "encoding/hex" + "golang.org/x/crypto/sha3" +) + +// SHA3-512 hashing utilities for Phase 2 authentication +func HashSHA3512(input string) string { + hasher := sha3.New512() + hasher.Write([]byte(input)) + return hex.EncodeToString(hasher.Sum(nil)) +} + +func HashUserNickname(nickname string) string { + return HashSHA3512(nickname) +} + +func HashGroupName(groupname string) string { + return HashSHA3512(groupname) +} + +func HashToken(token string) string { + return HashSHA3512(token) +} \ No newline at end of file