Skip to content

Send a password reset link instead of the password itself - #32

Merged
bonelifer merged 1 commit into
phpbbmodders:masterfrom
pkoevesdi:reset-link
Sep 28, 2026
Merged

bonelifer merged 1 commit into
phpbbmodders:masterfrom
pkoevesdi:reset-link

Conversation

@pkoevesdi

@pkoevesdi pkoevesdi commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

As invited in #25, and the feature originally requested in #22.

The welcome email carries the new account's password in clear text. And when pass_complex is PASS_TYPE_ANY or PASS_TYPE_CASE — the default — the generated password is a truncated base64(md5(time() . $username)), so it follows from the second the account was created and the username rather than being drawn at random. The remaining two branches use mt_rand() and str_shuffle(), both the Mersenne Twister.

Password generation. All three branches are replaced by one that draws from random_int(). It takes one character from every class validate_password() requires for the configured pass_complex, fills up to 20 characters (or min_pass_chars, whichever is larger), and shuffles by hand. generate_password() is then unused and removed.

The email. Instead of {PASSWORD}, the welcome emails carry a reset link, built the way core's "forgot password" builds it: a 32 character reset_token with an expiry, and the URL to the reset controller. The templates gain {U_RESET_PASSWORD} and {RESET_EXPIRES}; the ACP messages and the README follow.

The generated password is still stored, so nothing else in the flow changes. It is simply never disclosed, and the user replaces it through the link.

Two details worth a look:

  • The reset URL goes through controller.helper::route(), so boards with enable_mod_rewrite get the rewritten form. route() ends in append_sid(), which picks up $_SID; in the ACP that is set, so the link would otherwise carry the session id of the admin creating the account. $_SID is blanked around the call. Core's own use in the UCP does not hit this, because the requester there usually has no $_SID.
  • {RESET_EXPIRES} uses DATETIME_FORMAT with the relative-date markers stripped, so the email states an absolute date and time rather than "Tomorrow".

\phpbb\user::get_token_expiration() exists from 3.3.12, and ext.php already requires 3.3.19, so it is called directly.

Only language/en is in the repository. Translations distributed elsewhere still have a Password: {PASSWORD} line, which will now render empty.

Tested on phpBB 3.3.19 with PHP 8.3: accounts created through the ACP mask receive the link, the reset form accepts it, and the new password takes effect.

@bonelifer

Copy link
Copy Markdown
Contributor

Thanks for this. It works as described, and I'm going to merge it.

Claude tested it on a clean phpBB 3.3.19 board (PHP 8.4, SQLite). It added users through the ACP page and followed the links in the emails that were actually sent:

  • No activation: the email has the link and no password. The link has no session id, the reset works, and the new password logs in. Using the link a second time is refused.
  • Admin activation, "activate" box ticked: same result.
  • Admin activation, admin activates later: the link works after activation, within the 24 hour limit.
  • Password generator: 2,000 passwords for each pass_complex setting, and for an invalid value, all pass validate_password().

Two edge cases showed up. They don't block the merge. I'll fix them in a separate PR myself, so nothing more is needed from you:

  1. Self activation (require_activation set to user): the link can never be used. Before activation, the reset form refuses inactive users. Activating through ucp.php?mode=activate clears reset_token, so the link fails afterwards too. The user has to use "Forgot password", but the email says the link is valid.
  2. Admin activation, link clicked before the admin activates: the user sees "The password reset token you supplied is invalid or has expired", even though the same link works once the account is activated.

Investigated and written by Claude on behalf of William Jacoby (bonelifer).

@bonelifer
bonelifer merged commit c1fa3b5 into phpbbmodders:master Sep 28, 2026
7 checks passed
@pkoevesdi
pkoevesdi deleted the reset-link branch September 28, 2026 18:48
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