Skip to content

[3.0] Say a username is taken instead of erroring about it - #9483

Open
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/username-taken-not-fatal
Open

[3.0] Say a username is taken instead of erroring about it#9483
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/username-taken-not-fatal

Conversation

@albertlast

Copy link
Copy Markdown
Collaborator

Description

The registration form asks whether a username is free as it is typed. For almost
every name anybody actually tries, the answer is an error page.

On release-3.0, ?action=signup;sa=usernamecheck;xml:

Typed Answer
zzznewuser <username valid="1">
Guest <username valid="0">
testmember (an existing member) the fatal error page
Administrator (a membergroup) the fatal error page
Webmaster (on the reserved list) the fatal error page

Each one also writes a row to smf_log_errors, so a busy registration page fills
the error log with ordinary typing. And checkUsernameCallback() reads
XMLDoc.getElementsByTagName("username")[0], which is undefined when the body
is HTML, so the check throws and the icon never updates either.

Why. Security::isReservedName() passes $fatal down to the two checks that
look for an existing member or membergroup with a similar name:

if (Unicode\SpoofDetector::checkSimilarMemberName($name, $current_id_member, $fatal)) {

2.1 asked the members table in that same spot and only ever returned true
its $fatal branches covered the reserved-word list, the censor and *, which
are things an admin forbade. "Somebody already has this name" is not one of
those, and every caller is asking about exactly that.

The same fault has a second symptom in the profile. Profile.php has

if ($this->name != $value && Security::isReservedName($value, $this->id)) {
    return 'name_taken';
}

return 'name_taken' is dead. Changing a display name to one already in use ends
the request with "contains the reserved name" — the wrong words as well as the
wrong shape — before the return is reached.

What changes

Those two checks report rather than die, so isReservedName() answers the
question it was asked and the callers phrase it. The reserved-word list, the
censor and * still die when $fatal says so.

validateUsername() has the same shape one level up: $return_error is a
promise to hand the problems back, and the caller that asks for it wants XML, so
pass it on. Without that a name on the admin's reserved list still ends the
availability check with an error page.

Testing

Every row of the table above now returns <username valid="0"> or
valid="1"> correctly, including star*name and the empty string, with zero
new rows in smf_log_errors across the whole run.

Setting a display name to one in use now shows the inline field error "That
username/display name has already been taken" instead of a fatal page.

Submitting a registration with a reserved username still refuses it — now in the
form's error box rather than as an error page. A clean registration still
succeeds.

Issues References (Fixes|Related|Closes)

Related to #7933

The registration form asks whether a username is free as it is typed, and the
answer for almost every name anybody tries is an error page.

isReservedName() hands $fatal down to the two checks that look for an existing
member or membergroup of a similar name, so those die instead of returning
true. 2.1 asked the members table in the same place and only ever returned. Two
things follow from that:

The availability check answers `?action=signup;sa=usernamecheck;xml` with the
fatal error page rather than <username valid="0">, writes a row to the error
log for each one, and the callback that reads the response finds no <username>
element in it and throws.

And Profile.php returns 'name_taken' when a display name is in use, which is
dead code: isReservedName() has already ended the request, with the wrong words,
before the return is reached.

validateUsername() has the same shape one level up. $return_error is a promise
to hand the problems back rather than die of them, so pass that on: without it a
name on the admin's reserved list still ends the availability check with an
error page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants