verify / verify (push) Successful in 2m55s
Export the reviewed application-neutral package set through the exact public allowlist. Development history and private application evidence remain outside this canonical source root. Developed with material AI assistance under maintainer review. Signed-off-by: Cole Speelman <crspeelman@gmail.com>
74 lines
2.1 KiB
Go
74 lines
2.1 KiB
Go
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package websec
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestSameOriginRejectsCrossSiteAndContradiction(t *testing.T) {
|
|
request := httptest.NewRequest(http.MethodPost, "https://example.test/change", nil)
|
|
request.Header.Set("Origin", "https://example.test")
|
|
request.Header.Set("Sec-Fetch-Site", "same-origin")
|
|
if !SameOrigin(request, "https://example.test") {
|
|
t.Fatal("same origin rejected")
|
|
}
|
|
request.Header.Set("Sec-Fetch-Site", "cross-site")
|
|
if SameOrigin(request, "https://example.test") {
|
|
t.Fatal("cross-site accepted")
|
|
}
|
|
request.Header.Set("Sec-Fetch-Site", "same-origin")
|
|
request.Header.Set("Origin", "https://attacker.test")
|
|
if SameOrigin(request, "https://example.test") {
|
|
t.Fatal("foreign origin accepted")
|
|
}
|
|
}
|
|
|
|
func TestCSRFIsPurposeBound(t *testing.T) {
|
|
secret := []byte("0123456789abcdef0123456789abcdef")
|
|
token, err := CSRFToken(secret, "account:update")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !VerifyCSRF(secret, "account:update", token) {
|
|
t.Fatal("valid token rejected")
|
|
}
|
|
if VerifyCSRF(secret, "account:delete", token) {
|
|
t.Fatal("cross-purpose token accepted")
|
|
}
|
|
}
|
|
|
|
func TestSafeLocalRedirect(t *testing.T) {
|
|
for _, unsafe := range []string{"https://attacker.test/", "//attacker.test/", "/\\attacker", "javascript:alert(1)"} {
|
|
if got := SafeLocalRedirect(unsafe, "/home"); got != "/home" {
|
|
t.Fatalf("%q => %q", unsafe, got)
|
|
}
|
|
}
|
|
if got := SafeLocalRedirect("/items?page=2", "/"); got != "/items?page=2" {
|
|
t.Fatalf("got=%q", got)
|
|
}
|
|
}
|
|
|
|
func TestLimiterRefillsAndStaysBounded(t *testing.T) {
|
|
now := time.Unix(100, 0)
|
|
limiter, err := NewLimiter(LimitConfig{RatePerSecond: 1, Burst: 2, MaxEntries: 2, Now: func() time.Time { return now }})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !limiter.Allow("a") || !limiter.Allow("a") || limiter.Allow("a") {
|
|
t.Fatal("unexpected initial budget")
|
|
}
|
|
now = now.Add(time.Second)
|
|
if !limiter.Allow("a") {
|
|
t.Fatal("token did not refill")
|
|
}
|
|
_ = limiter.Allow("b")
|
|
_ = limiter.Allow("c")
|
|
if len(limiter.entries) != 2 {
|
|
t.Fatalf("entries=%d", len(limiter.entries))
|
|
}
|
|
}
|