fix: tolerate retried internal api nonce

This commit is contained in:
richjohnrambo
2026-08-28 10:43:01 +08:00
parent ba06ee3472
commit 4ea828fb09
2 changed files with 48 additions and 8 deletions
+22 -8
View File
@@ -185,7 +185,8 @@ func authorizeInternalAPI(wrt http.ResponseWriter, req *http.Request, capability
writeIMError(wrt, req, http.StatusUnauthorized, 30043, imReasonAuthRequired, "invalid internal signature", nil)
return false
}
if !claimInternalNonce(serviceName, nonce, time.Now().Add(window)) {
requestClaim := internalRequestClaimValue(signingText)
if !claimInternalNonce(serviceName, nonce, requestClaim, time.Now().Add(window)) {
writeIMError(wrt, req, http.StatusUnauthorized, 30043, imReasonAuthRequired, "internal nonce replayed", nil)
return false
}
@@ -572,23 +573,36 @@ func verifyInternalSignature(secret, signingText, signature string) bool {
return false
}
func claimInternalNonce(serviceName, nonce string, expiresAt time.Time) bool {
func claimInternalNonce(serviceName, nonce, requestClaim string, expiresAt time.Time) bool {
ttl := time.Until(expiresAt)
if ok, enabled, err := store.ClaimShortState("internal_api_nonce", fmt.Sprintf("%s:%s", serviceName, nonce), ttl); enabled {
nonceKey := fmt.Sprintf("%s:%s", serviceName, nonce)
if claimed, sameValue, enabled, err := store.ClaimShortStateValue("internal_api_nonce", nonceKey, requestClaim, ttl); enabled {
if err != nil {
logs.Warn.Println("internal api: failed to claim nonce in redis", err)
return false
}
return ok
return claimed || sameValue
}
now := time.Now()
internalAPI.nonces.Range(func(key, value any) bool {
if expires, ok := value.(time.Time); ok && expires.Before(now) {
if claim, ok := value.(internalNonceClaim); ok && claim.expiresAt.Before(now) {
internalAPI.nonces.Delete(key)
}
return true
})
nonceKey := fmt.Sprintf("%s:%s", serviceName, nonce)
_, loaded := internalAPI.nonces.LoadOrStore(nonceKey, expiresAt)
return !loaded
if existing, loaded := internalAPI.nonces.LoadOrStore(nonceKey, internalNonceClaim{value: requestClaim, expiresAt: expiresAt}); loaded {
claim, ok := existing.(internalNonceClaim)
return ok && claim.value == requestClaim
}
return true
}
type internalNonceClaim struct {
value string
expiresAt time.Time
}
func internalRequestClaimValue(signingText string) string {
sum := sha256.Sum256([]byte(signingText))
return hex.EncodeToString(sum[:])
}