问题:移动网络共享出口 IP 会造成游客取号被误限流。 实现:移除公开取号 IP 限制,改用项目总量与手机号 HMAC 限流,并支持 Retry-After 倒计时。
62 lines
1.8 KiB
Go
62 lines
1.8 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestQueryLimiterResetsAfterWindow(t *testing.T) {
|
|
now := time.Unix(100, 0)
|
|
limiter := newQueryLimiter(func() time.Time { return now }, 2, time.Minute)
|
|
|
|
if allowed, _ := limiter.allow("phone:test"); !allowed {
|
|
t.Fatal("first query should be allowed")
|
|
}
|
|
if allowed, _ := limiter.allow("phone:test"); !allowed {
|
|
t.Fatal("second query should be allowed")
|
|
}
|
|
if allowed, retry := limiter.allow("phone:test"); allowed || retry <= 0 {
|
|
t.Fatalf("third query should be limited with a retry duration, got allowed=%v retry=%s", allowed, retry)
|
|
}
|
|
|
|
now = now.Add(time.Minute)
|
|
if allowed, _ := limiter.allow("phone:test"); !allowed {
|
|
t.Fatal("query should be allowed after the window resets")
|
|
}
|
|
}
|
|
|
|
func TestQueryLimiterRemovesExpiredEntries(t *testing.T) {
|
|
now := time.Unix(100, 0)
|
|
limiter := newQueryLimiter(func() time.Time { return now }, 2, time.Minute)
|
|
limiter.allow("project:old-a")
|
|
limiter.allow("project:old-b")
|
|
|
|
now = now.Add(2 * time.Minute)
|
|
limiter.allow("project:current")
|
|
|
|
if len(limiter.entries) != 1 {
|
|
t.Fatalf("entries=%d, want only the current window entry", len(limiter.entries))
|
|
}
|
|
if _, ok := limiter.entries["project:current"]; !ok {
|
|
t.Fatal("current limiter entry was removed")
|
|
}
|
|
}
|
|
|
|
func TestLoginLimiterBlocksAfterTenFailures(t *testing.T) {
|
|
now := time.Unix(100, 0)
|
|
limiter := newLoginLimiter(func() time.Time { return now })
|
|
const key = "staff|127.0.0.1"
|
|
|
|
for attempt := 1; attempt < 10; attempt++ {
|
|
limiter.failure(key)
|
|
if allowed, _ := limiter.allow(key); !allowed {
|
|
t.Fatalf("login should remain allowed after %d failures", attempt)
|
|
}
|
|
}
|
|
|
|
limiter.failure(key)
|
|
if allowed, retry := limiter.allow(key); allowed || retry != 10*time.Minute {
|
|
t.Fatalf("login should be locked for 10 minutes after 10 failures, got allowed=%v retry=%s", allowed, retry)
|
|
}
|
|
}
|