Files
wangjia b5ab92a57e
ci / server (push) Failing after 13s
ci / design-tokens (push) Failing after 11s
fix: 应用 xhigh 代码评审的跨端修复
来自 xhigh code review 的正确性/健壮性修复,覆盖全部五端:
- server:鉴权 fail-closed、计量交叉校验与配额扣穿处理、WS 网关并发与关闭顺序、
  billing 行锁、redis Lua 过期与设备槽刷新、config 解析
- desktop:会话 epoch 防串话、WS 重连与 401 处理、api 客户端复用、统一 usePoll 轮询
- android:握手时序、请求头封装、账户状态派生、按需重组
- ios:finalize 宽限、串行采集、错误文案服务端优先、删除死代码 CommitController

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 11:50:08 +08:00

65 lines
1.7 KiB
Go

package auth
import (
"context"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/redis/go-redis/v9"
)
func TestSignParseRevoke(t *testing.T) {
mr := miniredis.RunT(t)
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
j := NewJWT("test-secret", time.Hour, rdb)
ctx := context.Background()
token, err := j.Sign("u1")
if err != nil {
t.Fatal(err)
}
uid, jti, exp, err := j.Parse(ctx, token)
if err != nil || uid != "u1" || jti == "" {
t.Fatalf("parse failed: uid=%s jti=%s err=%v", uid, jti, err)
}
if exp.IsZero() || time.Until(exp) <= 0 {
t.Fatalf("expiresAt should be in the future, got %v", exp)
}
// 拉黑后解析失败
if err := j.Revoke(ctx, jti, time.Now().Add(time.Hour)); err != nil {
t.Fatal(err)
}
if _, _, _, err := j.Parse(ctx, token); err == nil {
t.Fatal("expect parse failure after revoke")
}
// 篡改签名失败
if _, _, _, err := j.Parse(ctx, token+"x"); err == nil {
t.Fatal("expect parse failure on tampered token")
}
}
// TestParseFailClosed Redis 不可用时黑名单检查应 fail-closed:拒绝放行(17A)。
func TestParseFailClosed(t *testing.T) {
mr := miniredis.RunT(t)
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
j := NewJWT("test-secret", time.Hour, rdb)
ctx := context.Background()
token, err := j.Sign("u1")
if err != nil {
t.Fatal(err)
}
// 正常情况下放行
if _, _, _, err := j.Parse(ctx, token); err != nil {
t.Fatalf("parse should pass while redis up: %v", err)
}
// Redis 故障:Exists 返回 error → 必须拒绝(不得 fail-open)。
mr.Close()
if _, _, _, err := j.Parse(ctx, token); err == nil {
t.Fatal("expect parse failure when redis is unavailable (fail-closed)")
}
}