100 lines
2.6 KiB
Go
100 lines
2.6 KiB
Go
package db
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func openTestDB(t *testing.T) *DB {
|
|
t.Helper()
|
|
database, err := Open(filepath.Join(t.TempDir(), "test.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { database.Close() })
|
|
return database
|
|
}
|
|
|
|
// TestBlacklistIPEscalation confirms repeat offenses double the block duration up to the cap.
|
|
func TestBlacklistIPEscalation(t *testing.T) {
|
|
d := openTestDB(t)
|
|
const ip = "203.0.113.7"
|
|
|
|
wantHours := []int{12, 24, 48, 96, 168, 168} // caps at 168 (7 days)
|
|
for i, want := range wantHours {
|
|
if err := d.BlacklistIP(ip, "test", 12, 168); err != nil {
|
|
t.Fatalf("offense %d: %v", i+1, err)
|
|
}
|
|
list, err := d.ListBlacklist()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(list) != 1 {
|
|
t.Fatalf("offense %d: expected 1 entry, got %d", i+1, len(list))
|
|
}
|
|
e := list[0]
|
|
if e.OffenseCount != i+1 {
|
|
t.Errorf("offense %d: OffenseCount = %d, want %d", i+1, e.OffenseCount, i+1)
|
|
}
|
|
gotHours := e.ExpiresAt.Sub(e.BlacklistedAt).Hours()
|
|
if diff := gotHours - float64(want); diff < -1 || diff > 1 {
|
|
t.Errorf("offense %d: duration = %.1fh, want ~%dh", i+1, gotHours, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestCountFailedAuthAttemptsByIPMatchesCurrentTimestamp guards against the exact
|
|
// SQLite time.Time/CURRENT_TIMESTAMP format mismatch already found once in
|
|
// CountRecentFailedAttempts: a row inserted via CURRENT_TIMESTAMP must be found by a
|
|
// since-cutoff comparison using a Go-side time.Time a moment earlier.
|
|
func TestCountFailedAuthAttemptsByIPMatchesCurrentTimestamp(t *testing.T) {
|
|
d := openTestDB(t)
|
|
const ip = "198.51.100.9"
|
|
since := time.Now().Add(-1 * time.Minute)
|
|
|
|
if err := d.LogAuthAttempt("sender", "someone@example.com", ip, false, "bad password"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
n, err := d.CountFailedAuthAttemptsByIP(ip, since)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != 1 {
|
|
t.Fatalf("CountFailedAuthAttemptsByIP = %d, want 1 (CURRENT_TIMESTAMP/time.Time format mismatch?)", n)
|
|
}
|
|
|
|
blacklisted, err := d.IsIPBlacklisted(ip)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if blacklisted {
|
|
t.Fatal("IP should not be blacklisted yet")
|
|
}
|
|
}
|
|
|
|
func TestIPAbuseWhitelist(t *testing.T) {
|
|
d := openTestDB(t)
|
|
const ip = "192.0.2.55"
|
|
|
|
whitelisted, err := d.IsIPAbuseWhitelisted(ip)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if whitelisted {
|
|
t.Fatal("should not be whitelisted before AddAbuseWhitelist")
|
|
}
|
|
|
|
if err := d.AddAbuseWhitelist(ip, "trusted scanner"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
whitelisted, err = d.IsIPAbuseWhitelisted(ip)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !whitelisted {
|
|
t.Fatal("should be whitelisted after AddAbuseWhitelist")
|
|
}
|
|
}
|