79 lines
1.8 KiB
Go
79 lines
1.8 KiB
Go
package hmac
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestSignVerifyRoundTrip(t *testing.T) {
|
|
secret := "topsecret"
|
|
body := `{"brand_uid":"001DESke","source_url":"https://vogue.com/x"}`
|
|
ts := tsNow()
|
|
nonce := "abc123nonce"
|
|
|
|
sig := Sign(secret, ts, nonce, body)
|
|
if !Verify(secret, body, sig, ts, nonce, DefaultTTL) {
|
|
t.Fatal("valid signature should verify")
|
|
}
|
|
// 篡改 body → 失败
|
|
if Verify(secret, body+"x", sig, ts, nonce, DefaultTTL) {
|
|
t.Fatal("tampered body should fail")
|
|
}
|
|
// 错误密钥 → 失败
|
|
if Verify("wrong", body, sig, ts, nonce, DefaultTTL) {
|
|
t.Fatal("wrong secret should fail")
|
|
}
|
|
// 缺头 → 失败
|
|
if Verify(secret, body, "", ts, nonce, DefaultTTL) {
|
|
t.Fatal("missing header should fail")
|
|
}
|
|
}
|
|
|
|
func TestVerifyRejectsStaleTimestamp(t *testing.T) {
|
|
secret := "s"
|
|
body := "{}"
|
|
// 早于窗口
|
|
old := timeNowMinus(600)
|
|
nonce := "n1"
|
|
sig := Sign(secret, old, nonce, body)
|
|
if Verify(secret, body, sig, old, nonce, DefaultTTL) {
|
|
t.Fatal("stale timestamp should be rejected")
|
|
}
|
|
// 晚于窗口(未来太多)
|
|
future := timeNowPlus(600)
|
|
sig2 := Sign(secret, future, nonce, body)
|
|
if Verify(secret, body, sig2, future, nonce, DefaultTTL) {
|
|
t.Fatal("future timestamp beyond window should be rejected")
|
|
}
|
|
}
|
|
|
|
// 简易时间助手(避免直接依赖 time.Now 的不可控)
|
|
func tsNow() string { return itoa(int64(time.Now().Unix())) }
|
|
func timeNowMinus(sec int) string {
|
|
return itoa(int64(time.Now().Unix()) - int64(sec))
|
|
}
|
|
func timeNowPlus(sec int) string {
|
|
return itoa(int64(time.Now().Unix()) + int64(sec))
|
|
}
|
|
func itoa(v int64) string {
|
|
if v == 0 {
|
|
return "0"
|
|
}
|
|
neg := v < 0
|
|
if neg {
|
|
v = -v
|
|
}
|
|
buf := [20]byte{}
|
|
i := len(buf)
|
|
for v > 0 {
|
|
i--
|
|
buf[i] = byte('0' + v%10)
|
|
v /= 10
|
|
}
|
|
if neg {
|
|
i--
|
|
buf[i] = '-'
|
|
}
|
|
return string(buf[i:])
|
|
}
|