fix(auth): improve token metadata parsing and validation

Safeguard integer parsing in the `Whoami` handler by trimming whitespace and handling errors explicitly for `master_id`, `issued_at_epoch`, and `expires_at`. This prevents potential validation bypasses or incorrect behavior due to malformed metadata.

Add unit tests to verify invalid epoch handling and response correctness.
This commit is contained in:
zenfun
2026-01-03 16:19:42 +08:00
parent 8b63aa6ec0
commit 03ec45c84c
2 changed files with 176 additions and 4 deletions

View File

@@ -186,14 +186,19 @@ func (h *AuthHandler) Whoami(c *gin.Context) {
}
// Get master ID and issued_at_epoch
masterIDStr := keyData["master_id"]
masterIDStr := strings.TrimSpace(keyData["master_id"])
masterID, err := strconv.ParseUint(masterIDStr, 10, 64)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token metadata"})
return
}
issuedAtEpoch, _ := strconv.ParseInt(keyData["issued_at_epoch"], 10, 64)
issuedAtStr := strings.TrimSpace(keyData["issued_at_epoch"])
issuedAtEpoch, err := strconv.ParseInt(issuedAtStr, 10, 64)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token metadata"})
return
}
// Get master metadata from Redis
masterData, err := h.rdb.HGetAll(ctx, "auth:master:"+masterIDStr).Result()
@@ -210,14 +215,27 @@ func (h *AuthHandler) Whoami(c *gin.Context) {
}
// Check epoch (key revocation)
masterEpoch, _ := strconv.ParseInt(masterData["epoch"], 10, 64)
masterEpochStr := strings.TrimSpace(masterData["epoch"])
masterEpoch, err := strconv.ParseInt(masterEpochStr, 10, 64)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid master metadata"})
return
}
if issuedAtEpoch < masterEpoch {
c.JSON(http.StatusUnauthorized, gin.H{"error": "token has been revoked"})
return
}
// Check expiration
expiresAt, _ := strconv.ParseInt(keyData["expires_at"], 10, 64)
expiresAt := int64(0)
expiresAtStr := strings.TrimSpace(keyData["expires_at"])
if expiresAtStr != "" {
expiresAt, err = strconv.ParseInt(expiresAtStr, 10, 64)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token metadata"})
return
}
}
if expiresAt > 0 && time.Now().Unix() >= expiresAt {
c.JSON(http.StatusUnauthorized, gin.H{"error": "token has expired"})
return