Skip to content

[3.0] Reserve the names on the reserved names list - #9484

Merged
Sesquipedalian merged 2 commits into
SimpleMachines:release-3.0from
albertlast:3.0/reserved-names-separator
Aug 29, 2026
Merged

[3.0] Reserve the names on the reserved names list#9484
Sesquipedalian merged 2 commits into
SimpleMachines:release-3.0from
albertlast:3.0/reserved-names-separator

Conversation

@albertlast

Copy link
Copy Markdown
Collaborator

Description

A fresh 3.0 forum reserves nothing. Admin, Webmaster, Guest and root are
all free to register, and so is anything an admin adds afterwards — until they
open Registration → Reserved Names and press Save, which is the only thing that
ever writes the setting properly.

The stored value on a fresh install:

$ mysql -e "SELECT HEX(value) FROM smf_settings WHERE variable='reserveNames'"
41646D696E5C6E5765626D61737465725C6E47756573745C6E726F6F74
                ^^^^                ^^^^         ^^^^

5C6E is backslash-n, two characters, not a newline. checkReservedName() does
explode("\n", …) and gets one element back: the whole list as a single name
that nobody would ever type.

Where it comes from. The default is a language string that spells its
separators that way:

$txt['default_reserved_names'] = 'Admin\nWebmaster\nGuest\nroot';

2.1 fed that straight into an SQL literal — plain '…' for MySQL, E'…' for
PostgreSQL — and both engines turned the escapes into newlines on the way in.
3.0 defines its schema in PHP and inserts the value as a query parameter, so
nothing unescapes it. The strtr() in Table.php that survives from 2.1 only
turns \n back into \n; it was compensating for the escaping that the SQL
literal then undid, and there is no SQL literal any more.

Why nobody noticed. Admin/Registration.php has carried
str_replace('\n', "\n", …) since 2.1, so the textarea splits the list onto
separate lines and it looks exactly right. It has just never been in force.

What changes

Seeds real newlines, so a new install is correct.

Reads either form in checkReservedName(), so a forum that is already installed
starts enforcing its list without the admin having to go and re-save a page they
have no reason to think is broken. That is also why this needs no migration.

Testing

On a forum installed before the change, ?action=signup;sa=usernamecheck;xml:
root, Webmaster and Guest come back valid="0"; r00t and zzznewuser
come back valid="1". Submitting a registration as Webmaster is refused with
the name in the error box. A name not on the list registers as before.

(Read together with #9483, which is what makes the refusal a valid="0" rather
than an error page. Each stands alone.)

Issues References (Fixes|Related|Closes)

Related to #7933

A fresh forum reserves nothing. Admin, Webmaster, Guest and root are all free to
register, and so is every name an admin adds afterwards until they open the
settings page and press Save.

The default list comes from a language string that spells its separators as the
two characters backslash and n. 2.1 fed that into an SQL literal, where both
MySQL and PostgreSQL's E'' turned them into newlines. 3.0 defines its schema in
PHP and inserts the value as a query parameter, so nothing unescapes it and the
whole list is stored as one name that nobody would ever type. checkReservedName()
explodes it on "\n" and gets a single element back.

The admin page has carried its own str_replace for this since 2.1, so the list
has always looked right in the textarea while none of it was in force.

Seeds real newlines, and reads either form, so a forum already installed is
fixed without having to touch its settings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
@jdarwood007 jdarwood007 added this to the 3.0 Alpha 6 milestone Aug 10, 2026
Comment thread Sources/Unicode/SpoofDetector.php Outdated
Comment thread Sources/Db/Schema/Table.php Outdated
Co-authored-by: Jon Stovell <jonstovell@gmail.com>
@github-actions github-actions Bot added Database Charset/Encoding UTF8 & mb4 encoding related issues labels Aug 29, 2026
@Sesquipedalian
Sesquipedalian merged commit 6ec4a58 into SimpleMachines:release-3.0 Aug 29, 2026
7 checks passed
@jdarwood007 jdarwood007 modified the milestones: 3.0 Alpha 6, 3.0 Alpha 5 Aug 30, 2026
live627 pushed a commit that referenced this pull request Aug 31, 2026
A second sweep of the bug fixes now on release-3.0, in the same spirit as
#9511: ask of each one whether the suite can reach it, and write a test where
it can. Everything merged since that sweep was looked at, along with the
backlog that landed in one batch on the 29th and 30th. Most of it is templates,
JavaScript, or PHP that wants Db::$db or User::$me. Four fixes do not.

#9484 made SMF\Unicode\SpoofDetector::checkReservedName() split the admin's
list on the two characters backslash and n as well as on a real newline. The
installer writes the default list with the separators spelled out that way, so
splitting on newlines alone gave one long name nobody would type and every
reserved name was free to register.

#9409 made SMF\Localization\MessageFormatter::formatMessage() flatten a
\Stringable argument to its string value. The class skips any argument that is
not already a string and hands the intl formatter only the scalar ones, so an
object argument reached neither and the member was shown the placeholder.

#9453 made SMF\PageIndex remember, across __toString(), that the start value it
was handed was out of bounds. fixStart() records that as a side effect of
clamping, and __toString() called it again on a value already clamped, so the
verdict was always thrown away: page 1 came out as plain text rather than a
link, with a "next page" link beside it.

#9440 and #9442 both concern a gallery avatar, which is stored as a path under
the avatars directory rather than as a URL. Read as a URL, it was worked back
to a file from the URL's path, which lands outside the avatar directories; and
on a forum at the root of its domain that path is null, so stripping the board
URL off it threw a TypeError on every page the member appeared on.

Each set was run against the code as it was before its fix, by checking out the
single source file at the commit before the merge:

- SpoofDetector.php before #9484: one failure, the installer's list.
- MessageFormatter.php before #9409: three failures, all the \Stringable cases.
  The plain string, the number and the no-placeholder message pass either side.
- PageIndex.php before #9453: two failures. The four tests covering an ordinary
  start pass either side, which is what makes them the control.
- Avatar.php before #9440: five of six fail, the root-of-domain cases with the
  TypeError and the subdirectory ones by falling through to default.png. With
  #9440 but not #9442, four still fail: every gallery avatar becomes the
  default image.

202 tests, 295 assertions, still under a second.

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

Labels

Charset/Encoding UTF8 & mb4 encoding related issues Database Installer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants