Files
OpenFlare/openflare-server/internal/utils/cap/cap_test.go
T
2026-06-06 16:50:24 +08:00

94 lines
2.3 KiB
Go

package cap
import (
"context"
"crypto/sha256"
"encoding/hex"
"strconv"
"strings"
"testing"
"time"
)
func TestCapFullFlow(t *testing.T) {
secret := []byte("a-very-long-secret-key-at-least-16-bytes")
store := NewMemoryStore(1 * time.Minute)
manager := NewManager(Config{
Secret: secret,
ChallengeCount: 3, // small count for fast test
ChallengeSize: 32,
ChallengeDifficulty: 3, // small difficulty for fast test
ChallengeTTL: 5 * time.Second,
TokenTTL: 10 * time.Second,
}, store)
scope := "test-scope"
resp, err := manager.Generate(scope)
if err != nil {
t.Fatalf("Generate failed: %v", err)
}
if resp.Challenge.C != 3 {
t.Errorf("Expected count 3, got %d", resp.Challenge.C)
}
// Solve the challenge (acting as client)
solutions := make([]int, resp.Challenge.C)
tokenFnv := fnv1a(resp.Token)
for i := 0; i < resp.Challenge.C; i++ {
idxStr := strconv.Itoa(i + 1)
saltSeed := fnv1aResume(tokenFnv, idxStr)
targetSeed := fnv1aResume(saltSeed, "d")
salt := prngFromHash(saltSeed, resp.Challenge.S)
target := prngFromHash(targetSeed, resp.Challenge.D)
// Brute force the PoW solution
var found bool
for nonce := 0; nonce < 1000000; nonce++ {
hashInput := salt + strconv.Itoa(nonce)
hashBytes := sha256.Sum256([]byte(hashInput))
hashHex := hex.EncodeToString(hashBytes[:])
if strings.HasPrefix(hashHex, target) {
solutions[i] = nonce
found = true
break
}
}
if !found {
t.Fatalf("Failed to solve puzzle %d", i)
}
}
// Redeem
ctx := context.Background()
redeemResp, err := manager.Redeem(ctx, resp.Token, solutions, scope)
if err != nil {
t.Fatalf("Redeem failed: %v", err)
}
if !redeemResp.Success {
t.Fatalf("Redeem returned success=false: %s", redeemResp.Error)
}
if redeemResp.Token == "" {
t.Fatalf("Expected token, got empty")
}
// Verify the token
valid, err := manager.VerifyToken(ctx, redeemResp.Token, scope)
if err != nil {
t.Fatalf("VerifyToken failed: %v", err)
}
if !valid {
t.Fatalf("Expected redeem token to be valid")
}
// Verify token is one-time use
validAgain, err := manager.VerifyToken(ctx, redeemResp.Token, scope)
if err != nil {
t.Fatalf("VerifyToken second call failed: %v", err)
}
if validAgain {
t.Fatalf("Expected redeem token to be single-use (invalidated after verification)")
}
}