Skip to content

Confirm an email change from the new address, notify the current one, require the current password (#571) - #580

Merged
silverbackdan merged 4 commits into
mainfrom
feat/571-email-change-confirm-new
Oct 31, 2026
Merged

silverbackdan merged 4 commits into
mainfrom
feat/571-email-change-confirm-new

Conversation

@silverbackdan

Copy link
Copy Markdown
Collaborator

Closes #571.

Breaking (2.0 alpha, no BC):

  • The email change confirmation link now goes to the new address, which proves it. Confirming swaps emailAddress and marks it verified, as before.
  • Setting newEmailAddress to a non-empty value that differs from the stored one needs oldPassword, the signed-in user's current password (a 422 on oldPassword otherwise). This applies to API writes and NewEmailAddressType, which gains an oldPassword field. A super admin editing another user enters their own password. A cancel (null/''), or a write that leaves a pending change alone, needs no password.

Added

  • A notice to the current address when a change is requested: "being changed to n***@example.com; if this wasn't you, reset your password". It carries no link and is sent whenever a confirmation token is created, even if the confirmation's link is refused. It is not sent on a resend. It is configured at user.emails.change_email_notice (canBeDisabled, subject).

Not included (agreed): a cancel link and a confirm_to config.

Module and template: the module's admin user modal sends the admin's oldPassword in the same PATCH. The template's change-email form adds the field.

Tests: tests/Functional/User/NewEmailAddressTest.php (password required, wrong, admin uses own, unchanged pending needs none, both emails), the updated EmailLinkHostTest, EmailRequestThrottleTest and UserPutTest, a new recipient helper in EmailTrait (assertTemplatedEmailSentTo(), tested in EmailTraitTest), and unit tests for the validator, the notice factory, MaskedEmailAddress, the notifier, the mailer and the config wiring.

Expect conflicts with #577 (UserDataProcessor, CHANGELOG, CLAUDE.md); this branch does not depend on it.

🤖 Generated with Claude Code

@codecov

codecov Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.43750% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 97.09%. Comparing base (3e0b84c) to head (54f8940).

Files with missing lines Patch % Lines
src/Form/Type/User/NewEmailAddressType.php 85.71% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #580      +/-   ##
============================================
+ Coverage     97.06%   97.09%   +0.02%     
- Complexity     5318     5341      +23     
============================================
  Files           434      438       +4     
  Lines         13755    13817      +62     
============================================
+ Hits          13351    13415      +64     
+ Misses          404      402       -2     
Flag Coverage Δ
phpunit 97.09% <98.43%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@silverbackdan
silverbackdan merged commit 79d78eb into main Oct 31, 2026
14 of 15 checks passed
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.

Feature: on email change, confirm the new address and notify the old one

1 participant