vibes
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestAdminSessionTokens(t *testing.T) {
|
||||
a := newAdminAuth("correct horse battery")
|
||||
now := time.Unix(1_800_000_000, 0)
|
||||
tok := a.token(now)
|
||||
|
||||
if !a.valid(tok, now) || !a.valid(tok, now.Add(adminSessionTTL-time.Second)) {
|
||||
t.Fatal("a fresh token should be valid for its whole lifetime")
|
||||
}
|
||||
if a.valid(tok, now.Add(adminSessionTTL)) || a.valid(tok, now.Add(24*time.Hour)) {
|
||||
t.Fatal("an expired token was accepted")
|
||||
}
|
||||
exp, mac, _ := strings.Cut(tok, ".")
|
||||
for name, bad := range map[string]string{
|
||||
"empty": "",
|
||||
"no separator": "12345",
|
||||
"wrong signature": exp + "." + strings.Repeat("0", len(mac)),
|
||||
"extended expiry": "9999999999." + mac, // keep the signature, lengthen the life
|
||||
"not a number": "abc." + a.sign("abc"),
|
||||
"signature missing": exp + ".",
|
||||
} {
|
||||
if a.valid(bad, now) {
|
||||
t.Errorf("%s: forged token accepted", name)
|
||||
}
|
||||
}
|
||||
// Another password derives another key: tokens do not carry over.
|
||||
if newAdminAuth("a different password").valid(tok, now) {
|
||||
t.Fatal("a token signed under one password was accepted under another")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminPasswordCheck(t *testing.T) {
|
||||
a := newAdminAuth("correct horse battery")
|
||||
if !a.passwordOK("correct horse battery") {
|
||||
t.Fatal("the right password was refused")
|
||||
}
|
||||
for _, pw := range []string{"", "correct horse batter", "correct horse battery ", "CORRECT HORSE BATTERY"} {
|
||||
if a.passwordOK(pw) {
|
||||
t.Errorf("%q accepted", pw)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminLockoutWindow(t *testing.T) {
|
||||
a := newAdminAuth("pw")
|
||||
now := time.Unix(1_800_000_000, 0)
|
||||
for i := 0; i < adminMaxFails-1; i++ {
|
||||
a.recordFailure("1.2.3.4", now)
|
||||
if _, locked := a.lockedOut("1.2.3.4", now); locked {
|
||||
t.Fatalf("locked out after only %d failures", i+1)
|
||||
}
|
||||
}
|
||||
a.recordFailure("1.2.3.4", now)
|
||||
wait, locked := a.lockedOut("1.2.3.4", now)
|
||||
if !locked || wait != adminLockout {
|
||||
t.Fatalf("after %d failures: locked=%v wait=%v", adminMaxFails, locked, wait)
|
||||
}
|
||||
if _, locked := a.lockedOut("5.6.7.8", now); locked {
|
||||
t.Fatal("one address's failures locked out another")
|
||||
}
|
||||
if _, locked := a.lockedOut("1.2.3.4", now.Add(adminLockout+time.Second)); locked {
|
||||
t.Fatal("the lockout never ends")
|
||||
}
|
||||
// Failures that are spread out over more than the window do not add up.
|
||||
b := newAdminAuth("pw")
|
||||
for i := 0; i < adminMaxFails+3; i++ {
|
||||
b.recordFailure("9.9.9.9", now.Add(time.Duration(i)*adminLockout))
|
||||
}
|
||||
if _, locked := b.lockedOut("9.9.9.9", now.Add(time.Duration(adminMaxFails+3)*adminLockout)); locked {
|
||||
t.Fatal("slow guessing should not trip the lockout")
|
||||
}
|
||||
a.clear("1.2.3.4")
|
||||
if _, locked := a.lockedOut("1.2.3.4", now); locked {
|
||||
t.Fatal("a successful login should clear the failures")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user