Limits usernames to 1024 bytes, so an account can no longer exist that is unable to log in (#184).
Why 1024. A login stores the username in the session cookie, which securecookie and browsers refuse past about 4096 bytes. The cookie is the session base64-encoded twice, so it holds about 2300 bytes of session, and the signature, timestamp and other session values take about 270 of those. That puts the ceiling near 2030 bytes; the limit is about half, leaving room for values the session may carry later. The comment on MaxUsernameBytes gives the arithmetic.
Where it is enforced.
User.BeforeSave returns ErrUsernameTooLong on every save through GORM, so a future user-creation handler has a validation error to answer with instead of a 500.
A check constraint on users.username, counting bytes rather than characters, covers anything that writes the table without the model. On an existing database GORM adds it at the next start by rebuilding the users table; rows and indexes are kept.
Other session values. Nothing else in the session cookie is unbounded: the user ID is a UUID the service generates, and the rest are a flag and two timestamps.
The stored-username log test now uses usernames just under the limit, and the README passage describing the old 500 is updated.
Judgement call: the limit sits at about half the cookie's ceiling rather than at it.
The number appears twice, in the constant and in the struct tag; the raw-SQL test fails if they disagree.
Model: opus-5-5
Limits usernames to 1024 bytes, so an account can no longer exist that is unable to log in (https://git.eeqj.de/sneak/webhooker/issues/184).
**Why 1024.** A login stores the username in the session cookie, which securecookie and browsers refuse past about 4096 bytes. The cookie is the session base64-encoded twice, so it holds about 2300 bytes of session, and the signature, timestamp and other session values take about 270 of those. That puts the ceiling near 2030 bytes; the limit is about half, leaving room for values the session may carry later. The comment on `MaxUsernameBytes` gives the arithmetic.
**Where it is enforced.**
- `User.BeforeSave` returns `ErrUsernameTooLong` on every save through GORM, so a future user-creation handler has a validation error to answer with instead of a 500.
- A check constraint on `users.username`, counting bytes rather than characters, covers anything that writes the table without the model. On an existing database GORM adds it at the next start by rebuilding the `users` table; rows and indexes are kept.
**Other session values.** Nothing else in the session cookie is unbounded: the user ID is a UUID the service generates, and the rest are a flag and two timestamps.
The stored-username log test now uses usernames just under the limit, and the README passage describing the old 500 is updated.
- Judgement call: the limit sits at about half the cookie's ceiling rather than at it.
- The number appears twice, in the constant and in the struct tag; the raw-SQL test fails if they disagree.
Model: opus-5-5
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
internal/database/model_user.go, the comment on BeforeSave (and the PR body's line repeating it) says every path that saves a user through GORM gets ErrUsernameTooLong rather than the constraint error. Only Create and Save of a whole User do. GORM runs the hook on the model's current value, so db.Model(&user).Update("username", …) or .Updates(User{Username: …}) with an over-long name gets past the hook and returns the raw CHECK constraint failed error. A later rename handler written on the comment's promise would answer 500, which is the failure #184 exists to prevent. Acceptable: the comment says the hook covers creating or saving a whole User, and that a column update is caught only by the check constraint.
Model: opus-5-5
- `internal/database/model_user.go`, the comment on `BeforeSave` (and the PR body's line repeating it) says every path that saves a user through GORM gets `ErrUsernameTooLong` rather than the constraint error. Only `Create` and `Save` of a whole `User` do. GORM runs the hook on the model's current value, so `db.Model(&user).Update("username", …)` or `.Updates(User{Username: …})` with an over-long name gets past the hook and returns the raw `CHECK constraint failed` error. A later rename handler written on the comment's promise would answer 500, which is the failure https://git.eeqj.de/sneak/webhooker/issues/184 exists to prevent. Acceptable: the comment says the hook covers creating or saving a whole `User`, and that a column update is caught only by the check constraint.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Limits usernames to 1024 bytes, so an account can no longer exist that is unable to log in (#184).
Why 1024. A login stores the username in the session cookie, which securecookie and browsers refuse past about 4096 bytes. The cookie is the session base64-encoded twice, so it holds about 2300 bytes of session, and the signature, timestamp and other session values take about 270 of those. That puts the ceiling near 2030 bytes; the limit is about half, leaving room for values the session may carry later. The comment on
MaxUsernameBytesgives the arithmetic.Where it is enforced.
User.BeforeSavereturnsErrUsernameTooLongon every save through GORM, so a future user-creation handler has a validation error to answer with instead of a 500.users.username, counting bytes rather than characters, covers anything that writes the table without the model. On an existing database GORM adds it at the next start by rebuilding theuserstable; rows and indexes are kept.Other session values. Nothing else in the session cookie is unbounded: the user ID is a UUID the service generates, and the rest are a flag and two timestamps.
The stored-username log test now uses usernames just under the limit, and the README passage describing the old 500 is updated.
Model: opus-5-5
internal/database/model_user.go, the comment onBeforeSave(and the PR body's line repeating it) says every path that saves a user through GORM getsErrUsernameTooLongrather than the constraint error. OnlyCreateandSaveof a wholeUserdo. GORM runs the hook on the model's current value, sodb.Model(&user).Update("username", …)or.Updates(User{Username: …})with an over-long name gets past the hook and returns the rawCHECK constraint failederror. A later rename handler written on the comment's promise would answer 500, which is the failure #184 exists to prevent. Acceptable: the comment says the hook covers creating or saving a wholeUser, and that a column update is caught only by the check constraint.Model: opus-5-5
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.