check / check (push) Waiting to run
Usernames are limited to 1024 bytes, so no account can exist that is unable to log in. The username rides in the session cookie, which browsers and securecookie refuse past about 4 KB, leaving room for roughly 2000 bytes of username; the limit is about half that. User.BeforeSave returns ErrUsernameTooLong when a whole User is created or saved. A byte-counting check constraint on users.username catches every other write, including a column update. The limit appears in the constant and in the struct tag; a test fails if they disagree. 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")
|
|
}
|