Move the package into src/
Thirty-seven entries in the root, most of them .go files. The assets had to come along: //go:embed cannot reach outside its own directory, so templates/, static/ and migrations/ live beside the code that embeds them, and testdata/ beside the test that reads it. storage/ stays put — runtime data, not source. go build now needs -o. Without it the output would be named after the package directory and collide with src/ itself.
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestLoginRateLimit(t *testing.T) {
|
||||
var l limiter
|
||||
|
||||
for i := range loginMaxFailures - 1 {
|
||||
l.fail("[email protected]")
|
||||
if l.locked("[email protected]") {
|
||||
t.Fatalf("locked after %d failures, limit is %d", i+1, loginMaxFailures)
|
||||
}
|
||||
}
|
||||
l.fail("[email protected]")
|
||||
if !l.locked("[email protected]") {
|
||||
t.Fatalf("not locked after %d failures", loginMaxFailures)
|
||||
}
|
||||
|
||||
// The limit is per email: locking one address must not lock anyone else out.
|
||||
if l.locked("[email protected]") {
|
||||
t.Fatal("a different address was locked too")
|
||||
}
|
||||
|
||||
// A correct password clears it, so a member who mistypes nine times and then gets it right
|
||||
// starts from zero.
|
||||
l.succeed("[email protected]")
|
||||
if l.locked("[email protected]") {
|
||||
t.Fatal("still locked after a successful login")
|
||||
}
|
||||
|
||||
// Failures older than the window don't accumulate.
|
||||
for range loginMaxFailures - 1 {
|
||||
l.fail("[email protected]")
|
||||
}
|
||||
l.by["[email protected]"].first = time.Now().Add(-loginWindow - time.Minute)
|
||||
l.fail("[email protected]")
|
||||
if l.locked("[email protected]") {
|
||||
t.Fatal("failures outside the window were counted")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user