mirror of
https://github.com/warmbly/warmbly.git
synced 2026-09-06 16:01:28 +00:00
99 lines
2.6 KiB
Go
99 lines
2.6 KiB
Go
package webhook
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestSign_DeterministicForSameInputs(t *testing.T) {
|
|
secret := "whsec_test"
|
|
ts := time.Unix(1700000000, 0)
|
|
payload := []byte(`{"hello":"world"}`)
|
|
|
|
a := Sign(secret, ts, payload)
|
|
b := Sign(secret, ts, payload)
|
|
if a != b {
|
|
t.Fatalf("signature should be deterministic; got %s vs %s", a, b)
|
|
}
|
|
if len(a) != 64 { // SHA-256 hex = 64 chars
|
|
t.Errorf("expected 64-char hex signature, got %d chars", len(a))
|
|
}
|
|
}
|
|
|
|
func TestSign_DiffersBySecret(t *testing.T) {
|
|
ts := time.Unix(1700000000, 0)
|
|
payload := []byte(`{"x":1}`)
|
|
a := Sign("whsec_a", ts, payload)
|
|
b := Sign("whsec_b", ts, payload)
|
|
if a == b {
|
|
t.Error("different secrets must produce different signatures")
|
|
}
|
|
}
|
|
|
|
func TestSign_DiffersByTimestamp(t *testing.T) {
|
|
secret := "whsec_test"
|
|
payload := []byte(`{}`)
|
|
a := Sign(secret, time.Unix(100, 0), payload)
|
|
b := Sign(secret, time.Unix(200, 0), payload)
|
|
if a == b {
|
|
t.Error("different timestamps must produce different signatures")
|
|
}
|
|
}
|
|
|
|
func TestFormatSignatureHeader_Shape(t *testing.T) {
|
|
ts := time.Unix(1700000000, 0)
|
|
got := FormatSignatureHeader(ts, "abc123")
|
|
if !strings.HasPrefix(got, "t=1700000000,v1=") {
|
|
t.Errorf("unexpected header format: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestBackoffFor_GrowsAndCaps(t *testing.T) {
|
|
got1 := backoffFor(1)
|
|
if got1 != 30*time.Second {
|
|
t.Errorf("attempt 1 should be 30s, got %v", got1)
|
|
}
|
|
got2 := backoffFor(2)
|
|
if got2 != time.Minute {
|
|
t.Errorf("attempt 2 should be 1m, got %v", got2)
|
|
}
|
|
// Attempts past cap should clamp at 1h.
|
|
got20 := backoffFor(20)
|
|
if got20 != time.Hour {
|
|
t.Errorf("very large attempt count should clamp to 1h, got %v", got20)
|
|
}
|
|
}
|
|
|
|
func TestValidateURL_RejectsBadInput(t *testing.T) {
|
|
cases := map[string]bool{
|
|
"": true,
|
|
"not-a-url": true,
|
|
"ftp://x.com": true,
|
|
"javascript:alert(1)": true,
|
|
"http://": true,
|
|
"https://example.com/hook": false,
|
|
"http://localhost:3000/hook": true,
|
|
"https://localhost/hook": true,
|
|
"https://127.0.0.1/hook": true,
|
|
"https://10.0.0.10/hook": true,
|
|
}
|
|
for input, wantErr := range cases {
|
|
err := validateURL(input)
|
|
if wantErr && err == nil {
|
|
t.Errorf("validateURL(%q) should have errored", input)
|
|
}
|
|
if !wantErr && err != nil {
|
|
t.Errorf("validateURL(%q) unexpected error: %v", input, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateURL_AllowsUnsafeLocalDevelopmentWhenEnabled(t *testing.T) {
|
|
t.Setenv("WARMBLY_ALLOW_UNSAFE_WEBHOOK_URLS", "true")
|
|
|
|
if err := validateURL("http://localhost:3000/hook"); err != nil {
|
|
t.Fatalf("expected unsafe local URL to be accepted in development mode: %v", err)
|
|
}
|
|
}
|