check / check (push) Successful in 5m15s
A login stores the username in the session cookie, which cannot carry a value past about 4096 bytes, so a username of about 2 KB or more could never log in and the login answered 500. Usernames are now limited to 1024 bytes, about half of what the cookie can carry. The User model rejects a longer one with ErrUsernameTooLong, and a check constraint on the users table rejects it for any path that bypasses the model. The comment on MaxUsernameBytes gives the arithmetic. Model: opus-5-5
66 lines
1.7 KiB
Go
66 lines
1.7 KiB
Go
package database_test
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/webhooker/internal/database"
|
|
)
|
|
|
|
// usernameAtLimit is exactly MaxUsernameBytes long, built from a
|
|
// two-byte character. A check that counted characters rather than bytes
|
|
// would see half the length and let the one-byte-longer name through.
|
|
func usernameAtLimit() string {
|
|
return strings.Repeat("é", database.MaxUsernameBytes/2)
|
|
}
|
|
|
|
func TestUserCreate_RejectsOverlongUsername(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := startedTestDB(t)
|
|
|
|
err := db.Create(&database.User{
|
|
Username: usernameAtLimit() + "x",
|
|
Password: "hash",
|
|
}).Error
|
|
|
|
require.ErrorIs(t, err, database.ErrUsernameTooLong)
|
|
}
|
|
|
|
func TestUserCreate_AcceptsUsernameAtLimit(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := startedTestDB(t)
|
|
|
|
require.NoError(t, db.Create(&database.User{
|
|
Username: usernameAtLimit(),
|
|
Password: "hash",
|
|
}).Error)
|
|
}
|
|
|
|
// TestUsersTable_EnforcesUsernameLimitWithoutTheModel inserts with raw
|
|
// SQL, as a path that bypassed User.BeforeSave would, so only the
|
|
// table's check constraint stands between it and an over-long
|
|
// username. Accepting the name at the limit and refusing the next byte
|
|
// also pins the constraint's number to MaxUsernameBytes.
|
|
func TestUsersTable_EnforcesUsernameLimitWithoutTheModel(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := startedTestDB(t)
|
|
|
|
insert := "INSERT INTO users (id, username, password) VALUES (?, ?, ?)"
|
|
|
|
require.NoError(t, db.Exec(
|
|
insert, uuid.New().String(), usernameAtLimit(), "hash",
|
|
).Error)
|
|
|
|
err := db.Exec(
|
|
insert, uuid.New().String(), usernameAtLimit()+"x", "hash",
|
|
).Error
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "CHECK constraint failed")
|
|
}
|