Skip to content

fix(esx_identity): keep the accepted name length within the database column - #1825

Open
seltonmt012 wants to merge 2 commits into
esx-framework:v1.14.1from
seltonmt012:fix/identity-name-length
Open

fix(esx_identity): keep the accepted name length within the database column#1825
seltonmt012 wants to merge 2 commits into
esx-framework:v1.14.1from
seltonmt012:fix/identity-name-length

Conversation

@seltonmt012

Copy link
Copy Markdown
Contributor

A first or last name of 17 to 19 characters passes validation and then fails at the INSERT.

firstname and lastname are varchar(16), but Config.MaxNameLength is 20. On top of that the check uses < instead of <=, so the configured limit itself is never reachable. Names in that window get through checkNameFormat, the insert is rejected by the database, and in the multicharacter path that insert is what triggers loadESXPlayer through its callback. The player is told registration succeeded and then hangs, with nothing else happening.

Fixed by lowering the default to 16, matching the column, and by accepting a name of exactly the configured length.

Tested locally on artifact 25770 with MariaDB in strict mode:

  • 17 characters before the change: server log Data too long for column 'firstname', no row written, player stuck

  • 17 characters after: clean validation error, no hang

  • 14 characters after: character created normally

  • boundary checked separately: varchar(16) takes exactly 16 and rejects 17

  • My commit messages and PR title follow the Conventional Commits standard.

  • My changes have been tested locally and function as expected.

  • My PR does not introduce any breaking changes.

  • I have provided a clear explanation of what my PR does.

…column

Config.MaxNameLength was 20 while firstname and lastname are varchar(16), and
the check used < rather than <=, so names of 17 to 19 characters passed
validation and then failed the insert. MariaDB runs with STRICT_TRANS_TABLES
by default, so the query aborts with "Data too long for column" instead of
truncating.

In multichar the insert is what triggers loadESXPlayer through its callback,
so the callback never fires: the client is told registration succeeded and
then hangs with no character, permanently, on every attempt. The web form only
enforces a minimum of three characters, so this is reachable through the
shipped UI.

Lowering the limit to 16 and comparing with <= makes the accepted length match
the column exactly - a 16 character name still fits, 17 is rejected up front
with the existing invalid format message.

Verified on artifact 25770 with MariaDB. A 17 character first name used to log
"Data too long for column 'firstname'" and leave the player stuck; it is now
rejected before the query. A 14 character name registers normally and the row
is written. Checked separately that varchar(16) accepts exactly 16 characters
and rejects 17.

Widening the columns to varchar(20) would also work but needs a migration for
existing installations, so the validation was aligned to the current schema
instead.

@Zykem Zykem left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thank you for your PR.

Instead of still relying on the SQL Max varchar length, can you please modify the table values during runtime? You can achieve it with code like this:

MySQL.ready(function()
    local MAX_NAME_LENGTH <const> = Config.MaxNameLength

    local column = MySQL.scalar.await([[
        SELECT CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'firstname'
    ]])

    if column == MAX_NAME_LENGTH then return end

    local query = ("ALTER TABLE users MODIFY COLUMN firstname VARCHAR(%d), MODIFY COLUMN lastname VARCHAR(%d)"):format(MAX_NAME_LENGTH, MAX_NAME_LENGTH)
    local result = MySQL.update.await(query)
    if not result then
        return ESX.Trace("Failed to update firstname/lastname columns!")
    end

    ESX.Trace("Successfully updated firstname, lastname columns!")
end)

That way, the server owner will not have to modify the SQL varchar length if he wants his names to exceed strings over 16.

…start

Follow-up to the review. Instead of the config having to match whatever the database
was created with, firstname and lastname are widened to Config.MaxNameLength when the
server starts, so raising the limit no longer needs a manual SQL change. Both columns
are checked, not only firstname.

Only widening is done, never shrinking. Measured on a 50k row users table (156 MB,
MariaDB 12.3.2): widening runs in 0.15s because InnoDB applies it instantly, while
shrinking cannot use ALGORITHM=INSTANT at all (error 1846) and rebuilds the whole
table in 3.5s. On a server without STRICT_TRANS_TABLES the shrink also truncates
existing data without complaining - a stored 17 character name came back cut to 16.
Leaving the column wider than the config costs nothing, checkNameFormat already
enforces the lower value.

With the default config of 16 the columns already match, so this runs no query beyond
one lookup and changes nothing for existing servers.
@seltonmt012

Copy link
Copy Markdown
Contributor Author

Added, thanks. Both columns are checked now, not just firstname.

One deviation: it only widens, never shrinks. Measured on a 50k row users table (156 MB, MariaDB 12.3.2):

  • widening 16 -> 20 takes 0.15s, InnoDB applies it instantly
  • shrinking 20 -> 16 cannot use ALGORITHM=INSTANT at all (error 1846, "Cannot change column type") and rebuilds the whole table in 3.5s
  • worse, on a server without STRICT_TRANS_TABLES the shrink truncates existing data without complaining, a stored 17 character name came back cut to 16

checkNameFormat already enforces the lower value, so leaving the column wider than the config costs nothing and nobody loses a name.

Also worth mentioning about the snippet: MySQL.update.await returns 0 on a successful ALTER and raises on a failed one, so if not result never fires in either case. Wrapped it in pcall so the failure path actually reports.

With the default of 16 the columns already match what the SQL ships, so this runs one lookup and nothing else on existing servers unless someone raises the limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants