fix: Complete E2E test fixes for account service authentication

- Fix CreateAccount to decode hex-encoded public key before storage
- Fix Login signature verification to hash challenge before verifying
- Return 401 instead of 400 for invalid hex format in login credentials
- Fix CompleteRecovery to handle direct transition from requested state

All 8 E2E tests now pass (100% pass rate):
- TestAccountRecoveryFlow, TestCompleteAccountFlow, TestDuplicateUsername, TestInvalidLogin
- TestCompleteKeygenFlow, TestExceedParticipantLimit, TestGetNonExistentSession, TestJoinSessionWithInvalidToken

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Developer 2025-11-29 03:07:50 -08:00
parent 393c0ef04d
commit 0f70bb02fd
3 changed files with 21 additions and 5 deletions

View File

@ -135,11 +135,18 @@ func (h *AccountHTTPHandler) CreateAccount(c *gin.Context) {
}
}
// Decode hex-encoded public key
publicKeyBytes, err := hex.DecodeString(req.PublicKey)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid public key format"})
return
}
output, err := h.createAccountUC.Execute(c.Request.Context(), ports.CreateAccountInput{
Username: req.Username,
Email: req.Email,
Phone: req.Phone,
PublicKey: []byte(req.PublicKey),
PublicKey: publicKeyBytes,
KeygenSessionID: keygenSessionID,
ThresholdN: req.ThresholdN,
ThresholdT: req.ThresholdT,
@ -323,15 +330,16 @@ func (h *AccountHTTPHandler) Login(c *gin.Context) {
}
// Decode hex-encoded challenge and signature
// Return 401 Unauthorized for invalid formats (treated as invalid credentials)
challengeBytes, err := hex.DecodeString(req.Challenge)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid challenge format"})
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
return
}
signatureBytes, err := hex.DecodeString(req.Signature)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid signature format"})
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
return
}

View File

@ -78,8 +78,9 @@ func (uc *LoginUseCase) Execute(ctx context.Context, input ports.LoginInput) (*p
return nil, ErrSignatureInvalid
}
// Verify signature
if !crypto.VerifySignature(pubKey, input.Challenge, input.Signature) {
// Verify signature (hash the challenge first, as SignMessage does)
challengeHash := crypto.HashMessage(input.Challenge)
if !crypto.VerifySignature(pubKey, challengeHash, input.Signature) {
return nil, ErrSignatureInvalid
}

View File

@ -181,6 +181,13 @@ func (s *AccountDomainService) CompleteRecovery(ctx context.Context, recoverySes
return err
}
// Start keygen if still in requested state (transitions to in_progress)
if recovery.Status == value_objects.RecoveryStatusRequested {
if err := recovery.StartKeygen(newKeygenSessionID); err != nil {
return err
}
}
// Complete recovery session
if err := recovery.Complete(); err != nil {
return err