refactor: extract authentication system to auth package

- Create auth/jwt.go with JWT token management
- Create auth/permissions.go with permission checking logic
- Create auth/storage.go with storage key utilities
- Create auth/auth.go with main authentication service
- Create auth/middleware.go with auth and rate limit middleware
- Update main.go to import auth package and use auth.* functions
- Add authService to Server struct

Major auth functionality now separated into dedicated package.
Build tested and verified working.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-18 18:49:27 +03:00
parent 83777fe5a2
commit c273b836be
6 changed files with 535 additions and 34 deletions

56
main.go
View File

@@ -28,6 +28,7 @@ import (
"github.com/robfig/cron/v3"
"github.com/sirupsen/logrus"
"kvs/auth"
"kvs/config"
"kvs/types"
"kvs/utils"
@@ -58,25 +59,12 @@ type Server struct {
cronScheduler *cron.Cron // Cron scheduler for backups
backupStatus types.BackupStatus // Current backup status
backupMu sync.RWMutex // Protects backup status
// Authentication service
authService *auth.AuthService
}
// Phase 2: Storage key generation utilities
func userStorageKey(userUUID string) string {
return "user:" + userUUID
}
func groupStorageKey(groupUUID string) string {
return "group:" + groupUUID
}
func tokenStorageKey(tokenHash string) string {
return "token:" + tokenHash
}
func resourceMetadataKey(resourceKey string) string {
return resourceKey + ":metadata"
}
// Phase 2: Permission checking utilities
func checkPermission(permissions int, operation string, isOwner, isGroupMember bool) bool {
@@ -217,7 +205,7 @@ func (s *Server) storeAPIToken(tokenString string, userUUID string, scopes []str
}
return s.db.Update(func(txn *badger.Txn) error {
entry := badger.NewEntry([]byte(tokenStorageKey(tokenHash)), tokenData)
entry := badger.NewEntry([]byte(auth.TokenStorageKey(tokenHash)), tokenData)
// Set TTL to the token expiration time
ttl := time.Until(time.Unix(expiresAt, 0))
@@ -234,7 +222,7 @@ func (s *Server) getAPIToken(tokenHash string) (*types.APIToken, error) {
var apiToken types.APIToken
err := s.db.View(func(txn *badger.Txn) error {
item, err := txn.Get([]byte(tokenStorageKey(tokenHash)))
item, err := txn.Get([]byte(auth.TokenStorageKey(tokenHash)))
if err != nil {
return err
}
@@ -279,7 +267,7 @@ func extractTokenFromHeader(r *http.Request) (string, error) {
func (s *Server) getUserGroups(userUUID string) ([]string, error) {
var user types.User
err := s.db.View(func(txn *badger.Txn) error {
item, err := txn.Get([]byte(userStorageKey(userUUID)))
item, err := txn.Get([]byte(auth.UserStorageKey(userUUID)))
if err != nil {
return err
}
@@ -339,7 +327,7 @@ func (s *Server) checkResourcePermission(authCtx *AuthContext, resourceKey strin
// Get resource metadata
var metadata types.ResourceMetadata
err := s.db.View(func(txn *badger.Txn) error {
item, err := txn.Get([]byte(resourceMetadataKey(resourceKey)))
item, err := txn.Get([]byte(auth.ResourceMetadataKey(resourceKey)))
if err != nil {
return err
}
@@ -560,7 +548,7 @@ func getRevisionKey(baseKey string, revision int) string {
// storeRevisionHistory stores a value and manages revision history (up to 3 revisions)
func (s *Server) storeRevisionHistory(txn *badger.Txn, key string, storedValue types.StoredValue, ttl time.Duration) error {
// Get existing metadata to check current revisions
metadataKey := resourceMetadataKey(key)
metadataKey := auth.ResourceMetadataKey(key)
var metadata types.ResourceMetadata
var currentRevisions []int
@@ -2416,7 +2404,7 @@ func (s *Server) createUserHandler(w http.ResponseWriter, r *http.Request) {
}
err = s.db.Update(func(txn *badger.Txn) error {
return txn.Set([]byte(userStorageKey(userUUID)), userData)
return txn.Set([]byte(auth.UserStorageKey(userUUID)), userData)
})
if err != nil {
@@ -2444,7 +2432,7 @@ func (s *Server) getUserHandler(w http.ResponseWriter, r *http.Request) {
var user types.User
err := s.db.View(func(txn *badger.Txn) error {
item, err := txn.Get([]byte(userStorageKey(userUUID)))
item, err := txn.Get([]byte(auth.UserStorageKey(userUUID)))
if err != nil {
return err
}
@@ -2495,7 +2483,7 @@ func (s *Server) updateUserHandler(w http.ResponseWriter, r *http.Request) {
err := s.db.Update(func(txn *badger.Txn) error {
// Get existing user
item, err := txn.Get([]byte(userStorageKey(userUUID)))
item, err := txn.Get([]byte(auth.UserStorageKey(userUUID)))
if err != nil {
return err
}
@@ -2526,7 +2514,7 @@ func (s *Server) updateUserHandler(w http.ResponseWriter, r *http.Request) {
return err
}
return txn.Set([]byte(userStorageKey(userUUID)), userData)
return txn.Set([]byte(auth.UserStorageKey(userUUID)), userData)
})
if err == badger.ErrKeyNotFound {
@@ -2556,13 +2544,13 @@ func (s *Server) deleteUserHandler(w http.ResponseWriter, r *http.Request) {
err := s.db.Update(func(txn *badger.Txn) error {
// Check if user exists first
_, err := txn.Get([]byte(userStorageKey(userUUID)))
_, err := txn.Get([]byte(auth.UserStorageKey(userUUID)))
if err != nil {
return err
}
// Delete the user
return txn.Delete([]byte(userStorageKey(userUUID)))
return txn.Delete([]byte(auth.UserStorageKey(userUUID)))
})
if err == badger.ErrKeyNotFound {
@@ -2620,7 +2608,7 @@ func (s *Server) createGroupHandler(w http.ResponseWriter, r *http.Request) {
}
err = s.db.Update(func(txn *badger.Txn) error {
return txn.Set([]byte(groupStorageKey(groupUUID)), groupData)
return txn.Set([]byte(auth.GroupStorageKey(groupUUID)), groupData)
})
if err != nil {
@@ -2648,7 +2636,7 @@ func (s *Server) getGroupHandler(w http.ResponseWriter, r *http.Request) {
var group types.Group
err := s.db.View(func(txn *badger.Txn) error {
item, err := txn.Get([]byte(groupStorageKey(groupUUID)))
item, err := txn.Get([]byte(auth.GroupStorageKey(groupUUID)))
if err != nil {
return err
}
@@ -2699,7 +2687,7 @@ func (s *Server) updateGroupHandler(w http.ResponseWriter, r *http.Request) {
err := s.db.Update(func(txn *badger.Txn) error {
// Get existing group
item, err := txn.Get([]byte(groupStorageKey(groupUUID)))
item, err := txn.Get([]byte(auth.GroupStorageKey(groupUUID)))
if err != nil {
return err
}
@@ -2727,7 +2715,7 @@ func (s *Server) updateGroupHandler(w http.ResponseWriter, r *http.Request) {
return err
}
return txn.Set([]byte(groupStorageKey(groupUUID)), groupData)
return txn.Set([]byte(auth.GroupStorageKey(groupUUID)), groupData)
})
if err == badger.ErrKeyNotFound {
@@ -2757,13 +2745,13 @@ func (s *Server) deleteGroupHandler(w http.ResponseWriter, r *http.Request) {
err := s.db.Update(func(txn *badger.Txn) error {
// Check if group exists first
_, err := txn.Get([]byte(groupStorageKey(groupUUID)))
_, err := txn.Get([]byte(auth.GroupStorageKey(groupUUID)))
if err != nil {
return err
}
// Delete the group
return txn.Delete([]byte(groupStorageKey(groupUUID)))
return txn.Delete([]byte(auth.GroupStorageKey(groupUUID)))
})
if err == badger.ErrKeyNotFound {
@@ -2803,7 +2791,7 @@ func (s *Server) createTokenHandler(w http.ResponseWriter, r *http.Request) {
// Verify user exists
err := s.db.View(func(txn *badger.Txn) error {
_, err := txn.Get([]byte(userStorageKey(req.UserUUID)))
_, err := txn.Get([]byte(auth.UserStorageKey(req.UserUUID)))
return err
})