From 7944380adaa9beacc5d7ac7e9b63955e6a8b6cf4 Mon Sep 17 00:00:00 2001 From: Patrick Britton Date: Mon, 16 Feb 2026 23:32:02 -0600 Subject: [PATCH] fix: implement proper ALTCHA challenge with HMAC signatures - Use proper cryptographic challenge generation - Add HMAC-SHA256 signatures for challenge verification - Replace test signatures with real cryptographic signatures - This should fix the verification failures --- go-backend/internal/handlers/admin_handler.go | 26 ++++++++++++++----- go-backend/internal/handlers/auth_handler.go | 24 ++++++++++++----- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/go-backend/internal/handlers/admin_handler.go b/go-backend/internal/handlers/admin_handler.go index 1b8ccba..c8459f7 100644 --- a/go-backend/internal/handlers/admin_handler.go +++ b/go-backend/internal/handlers/admin_handler.go @@ -3,6 +3,9 @@ package handlers import ( "bytes" "context" + "crypto/hmac" + "crypto/sha256" + "encoding/hex" "encoding/json" "fmt" "io" @@ -4130,12 +4133,23 @@ func (h *AdminHandler) SendTestEmail(c *gin.Context) { } func (h *AdminHandler) GetAltchaChallenge(c *gin.Context) { - // Simple ALTCHA challenge implementation - challenge := map[string]interface{}{ + // Generate a proper ALTCHA challenge + salt := fmt.Sprintf("%d", time.Now().UnixNano()) + + // Create a simple number challenge (find a number that when hashed with salt produces a hash starting with certain digits) + challenge := fmt.Sprintf("%x", sha256.Sum256([]byte(salt)))[:10] + + // Create HMAC signature using JWT secret as the key + h := hmac.New(sha256.New, []byte(h.jwtSecret)) + h.Write([]byte(challenge + salt)) + signature := hex.EncodeToString(h.Sum(nil)) + + response := map[string]interface{}{ "algorithm": "SHA-256", - "challenge": fmt.Sprintf("%d", time.Now().UnixNano()), - "salt": fmt.Sprintf("%d", time.Now().Unix()), - "signature": "test-signature", + "challenge": challenge, + "salt": salt, + "signature": signature, } - c.JSON(http.StatusOK, challenge) + + c.JSON(http.StatusOK, response) } diff --git a/go-backend/internal/handlers/auth_handler.go b/go-backend/internal/handlers/auth_handler.go index 9e678eb..fc9878b 100644 --- a/go-backend/internal/handlers/auth_handler.go +++ b/go-backend/internal/handlers/auth_handler.go @@ -1,6 +1,7 @@ package handlers import ( + "crypto/hmac" "crypto/rand" "crypto/sha256" "encoding/base64" @@ -598,12 +599,23 @@ func (h *AuthHandler) ResetPassword(c *gin.Context) { } func (h *AuthHandler) GetAltchaChallenge(c *gin.Context) { - // Simple ALTCHA challenge implementation - challenge := map[string]interface{}{ + // Generate a proper ALTCHA challenge + salt := fmt.Sprintf("%d", time.Now().UnixNano()) + + // Create a simple number challenge (find a number that when hashed with salt produces a hash starting with certain digits) + challenge := fmt.Sprintf("%x", sha256.Sum256([]byte(salt)))[:10] + + // Create HMAC signature using JWT secret as the key + h := hmac.New(sha256.New, []byte(h.config.JWTSecret)) + h.Write([]byte(challenge + salt)) + signature := hex.EncodeToString(h.Sum(nil)) + + response := map[string]interface{}{ "algorithm": "SHA-256", - "challenge": fmt.Sprintf("%d", time.Now().UnixNano()), - "salt": fmt.Sprintf("%d", time.Now().Unix()), - "signature": "test-signature", + "challenge": challenge, + "salt": salt, + "signature": signature, } - c.JSON(http.StatusOK, challenge) + + c.JSON(http.StatusOK, response) }