diff --git a/core/modules/user/config/install/user.settings.yml b/core/modules/user/config/install/user.settings.yml index ca46109..677add0 100644 --- a/core/modules/user/config/install/user.settings.yml +++ b/core/modules/user/config/install/user.settings.yml @@ -14,6 +14,5 @@ notify: register: visitors cancel_method: user_cancel_block password_reset_timeout: 86400 -mail_change_timeout: 86400 password_strength: true langcode: en diff --git a/core/modules/user/config/schema/user.schema.yml b/core/modules/user/config/schema/user.schema.yml index 206a853..40a8475 100644 --- a/core/modules/user/config/schema/user.schema.yml +++ b/core/modules/user/config/schema/user.schema.yml @@ -53,9 +53,6 @@ user.settings: password_reset_timeout: type: integer label: 'Password reset timeout' - mail_change_timeout: - type: integer - label: 'Mail change timeout' password_strength: type: boolean label: 'Enable password strength indicator' diff --git a/core/modules/user/src/AccountForm.php b/core/modules/user/src/AccountForm.php index 9bbf9fb..9fdd4ce 100644 --- a/core/modules/user/src/AccountForm.php +++ b/core/modules/user/src/AccountForm.php @@ -396,7 +396,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { _user_mail_notify('mail_change_notification', $account); // The user's mail address will be updated only after verification. $form_state->setValue('mail', $old_mail); - drupal_set_message($this->t('Your new email address needs to be validated. Further instructions have been sent to your new email address.'), 'warning'); + drupal_set_message($this->t('Your updated email address needs to be validated. Further instructions have been sent to your new email address.'), 'warning'); } } diff --git a/core/modules/user/src/Controller/MailChangeController.php b/core/modules/user/src/Controller/MailChangeController.php index 487c70d..14649e3 100644 --- a/core/modules/user/src/Controller/MailChangeController.php +++ b/core/modules/user/src/Controller/MailChangeController.php @@ -5,6 +5,7 @@ use Drupal\Component\Utility\Crypt; use Drupal\Core\Access\AccessResult; use Drupal\Core\Controller\ControllerBase; +use Drupal\Core\Site\Settings; use Drupal\Core\Url; use Drupal\user\UserInterface; @@ -29,27 +30,28 @@ class MailChangeController extends ControllerBase { * An HTTP response doing a redirect. */ public function page(UserInterface $user, $new_mail, $timestamp, $hash) { - $timeout = $this->config('user.settings')->get('mail_change_timeout'); + $timeout = Settings::get('mail_change_timeout', 86400); /** @var \Drupal\Core\Session\AccountProxyInterface $current_user */ $current_user = $this->currentUser(); + $request_time = \Drupal::time()->getRequestTime(); // Other user is authenticated. if ($current_user->isAuthenticated() && $current_user->id() != $user->id()) { drupal_set_message($this->t('You are currently logged in as %user, and are attempting to confirm an email address change for another account. Please log out and try using the link again.', ['%user' => $current_user->getAccountName(), ':logout' => Url::fromRoute('user.logout')->toString()]), 'error'); } // The link has expired. - elseif (REQUEST_TIME - $timestamp > $timeout) { + elseif ($request_time - $timestamp > $timeout) { drupal_set_message($this->t('You have tried to use an email address change link that has expired. Please visit your account and change your email again.'), 'error'); } // The link is valid. - elseif ($timestamp <= REQUEST_TIME && $timestamp >= $user->getLastLoginTime() && Crypt::hashEquals($hash, user_pass_rehash($user, $timestamp, $new_mail))) { + elseif ($timestamp <= $request_time && $timestamp >= $user->getLastLoginTime() && Crypt::hashEquals($hash, user_pass_rehash($user, $timestamp, $new_mail))) { // Save the new email but refresh also the last login time so that this - // mail change link get expired. - $user->setEmail($new_mail)->setLastLoginTime(REQUEST_TIME)->save(); + // mail change link gets expired. + $user->setEmail($new_mail)->setLastLoginTime($request_time)->save(); /** @var \Drupal\user\UserStorageInterface $user_storage */ $user_storage = $this->entityTypeManager()->getStorage('user'); $user_storage->updateLastLoginTimestamp($user); - // Reflect the changes in the session if the user is user is logged in. + // Reflect the changes in the session if the user is logged in. if ($current_user->isAuthenticated() && $current_user->id() == $user->id()) { $current_user->setAccount($user); } @@ -96,7 +98,8 @@ public function access(UserInterface $user) { * @return \Drupal\Core\Url * A unique url that provides a one-time email change confirmation. */ - public static function getUrl(UserInterface $account, array $options = [], $timestamp = REQUEST_TIME, $hash = NULL) { + public static function getUrl(UserInterface $account, array $options = [], $timestamp = NULL, $hash = NULL) { + $timestamp = $timestamp ?: \Drupal::time()->getRequestTime(); $langcode = isset($options['langcode']) ? $options['langcode'] : $account->getPreferredLangcode(); $hash = empty($hash) ? user_pass_rehash($account, $timestamp) : $hash; $url_options = ['absolute' => TRUE, 'language' => \Drupal::service('language_manager')->getLanguage($langcode)]; diff --git a/core/modules/user/src/Tests/Update/UpdateMailChangeTest.php b/core/modules/user/src/Tests/Update/UpdateMailChangeTest.php index 78d31dd..f5098e9 100644 --- a/core/modules/user/src/Tests/Update/UpdateMailChangeTest.php +++ b/core/modules/user/src/Tests/Update/UpdateMailChangeTest.php @@ -33,7 +33,6 @@ public function testMailChangeUpdate() { // Check that mail change notifications settings are not set. $this->assertNull($user_settings->get('notify.mail_change_notification')); $this->assertNull($user_settings->get('notify.mail_change_verification')); - $this->assertNull($user_settings->get('mail_change_timeout')); // Check that mail change configurations are not set. $this->assertNull($user_mail->get('mail_change_notification')); @@ -47,8 +46,6 @@ public function testMailChangeUpdate() { // Check that mail change notifications were set to FALSE. $this->assertFalse($user_settings->get('notify.mail_change_notification')); $this->assertFalse($user_settings->get('notify.mail_change_verification')); - // Check that mail change timeout was set. - $this->assertIdentical($user_settings->get('mail_change_timeout'), 86400); $config = Yaml::parse(file_get_contents(__DIR__ . '/../../../config/install/user.mail.yml')); diff --git a/core/modules/user/tests/src/Functional/UserMailChangeTest.php b/core/modules/user/tests/src/Functional/UserMailChangeTest.php index cdc1b4e..1d376f5 100644 --- a/core/modules/user/tests/src/Functional/UserMailChangeTest.php +++ b/core/modules/user/tests/src/Functional/UserMailChangeTest.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\user\Functional; +use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Test\AssertMailTrait; use Drupal\Core\Url; use Drupal\Component\Utility\Unicode; @@ -26,12 +27,20 @@ class UserMailChangeTest extends BrowserTestBase { protected $account; /** + * The date/time service. + * + * @var \Drupal\Component\Datetime\TimeInterface + */ + protected $time; + + /** * {@inheritdoc} */ protected function setUp() { parent::setUp(); // Create a user. $this->account = $this->drupalCreateUser(); + $this->time = $this->container->get('datetime.time'); } /** @@ -46,10 +55,10 @@ public function testMailChange() { 'mail' => $new_mail, 'current_pass' => $this->account->pass_raw, ]; - $this->drupalPostForm($this->account->toUrl('edit-form'), $edit, t('Save')); + $this->drupalPostForm($this->account->toUrl('edit-form'), $edit, 'Save'); // Check that the validation status message has been displayed. - $this->assertSession()->pageTextContains(t('Your new email address needs to be validated. Further instructions have been sent to your new email address.')); + $this->assertSession()->pageTextContains('Your updated email address needs to be validated. Further instructions have been sent to your new email address.'); $user_mail = $this->config('user.mail'); @@ -70,12 +79,12 @@ public function testMailChange() { // Check that the email has been successfully updated. $this->drupalGet($sent_mail_change_url); - $this->assertSession()->responseContains(t('Your email address has been changed to %mail.', ['%mail' => $new_mail])); + $this->assertSession()->responseContains(new FormattableMarkup('Your email address has been changed to %mail.', ['%mail' => $new_mail])); // Check that the change mail URL is not cached and expires after first use. $this->drupalGet($sent_mail_change_url); $this->assertNull($this->drupalGetHeader('X-Drupal-Cache')); - $this->assertSession()->responseContains(t('You have tried to use an email address change link that has either been used or is no longer valid. Please visit your account and change your email again.')); + $this->assertSession()->responseContains('You have tried to use an email address change link that has either been used or is no longer valid. Please visit your account and change your email again.'); // Check that the user mail has been changed. self::assertSame(User::load($this->account->id())->getEmail(), $new_mail); @@ -97,10 +106,10 @@ public function testMailChangeNoVerification() { 'mail' => $new_mail, 'current_pass' => $this->account->pass_raw, ]; - $this->drupalPostForm($this->account->toUrl('edit-form'), $edit, t('Save')); + $this->drupalPostForm($this->account->toUrl('edit-form'), $edit, 'Save'); // Check that the validation status message has not been displayed. - $this->assertSession()->pageTextNotContains(t('Your new email address needs to be validated. Further instructions have been sent to your new email address.')); + $this->assertSession()->pageTextNotContains('Your updated email address needs to be validated. Further instructions have been sent to your new email address.'); // Check that no E-mail was sent to the old or to the new address. $this->assertEmpty($this->getMails()); @@ -113,7 +122,7 @@ public function testMailChangeNoVerification() { * Tests change of email for blocked users. */ public function testBlockedUser() { - $timestamp = REQUEST_TIME - 1; + $timestamp = $this->time->getRequestTime() - 1; $account_cloned = clone $this->account; $account_cloned->block()->save(); $this->drupalGet(MailChangeController::getUrl($account_cloned, [], $timestamp)->getInternalPath()); @@ -124,16 +133,16 @@ public function testBlockedUser() { * Tests change of email for expired timestamp. */ public function testExpiredTimestamp() { - $timestamp = REQUEST_TIME - (24 * 60 * 60 + 1); + $timestamp = $this->time->getRequestTime() - (24 * 60 * 60 + 1); $this->drupalGet(MailChangeController::getUrl($this->account, [], $timestamp)->getInternalPath()); - $this->assertSession()->responseContains(t('You have tried to use an email address change link that has expired. Please visit your account and change your email again.')); + $this->assertSession()->responseContains('You have tried to use an email address change link that has expired. Please visit your account and change your email again.'); } /** * Tests change of email when other user is logged in. */ public function testOtherUserLoggedIn() { - $timestamp = REQUEST_TIME - 1; + $timestamp = $this->time->getRequestTime() - 1; // Create other account and login with it. $current_account = $this->drupalCreateUser(); $this->drupalLogin($current_account); @@ -143,33 +152,33 @@ public function testOtherUserLoggedIn() { $this->account->setEmail($new_mail); $path = MailChangeController::getUrl($this->account, [], $timestamp)->getInternalPath(); $this->drupalGet($path); - $this->assertSession()->responseContains(t('You are currently logged in as %user, and are attempting to confirm an email address change for another account. Please log out and try using the link again.', ['%user' => $current_account->getAccountName(), ':logout' => Url::fromRoute('user.logout')->toString()])); + $this->assertSession()->responseContains(new FormattableMarkup('You are currently logged in as %user, and are attempting to confirm an email address change for another account. Please log out and try using the link again.', ['%user' => $current_account->getAccountName(), ':logout' => Url::fromRoute('user.logout')->toString()])); // Retry as anonymous. $this->drupalLogout(); $this->drupalGet($path); - $this->assertSession()->responseContains(t('Your email address has been changed to %mail.', ['%mail' => $new_mail])); + $this->assertSession()->responseContains(new FormattableMarkup('Your email address has been changed to %mail.', ['%mail' => $new_mail])); } /** * Tests change of email for timestamp in the future. */ public function testFutureTimestamp() { - $timestamp = REQUEST_TIME + 60 * 60; + $timestamp = $this->time->getRequestTime() + 60 * 60; $this->drupalGet(MailChangeController::getUrl($this->account, [], $timestamp)->getInternalPath()); - $this->assertSession()->responseContains(t('You have tried to use an email address change link that has either been used or is no longer valid. Please visit your account and change your email again.')); + $this->assertSession()->responseContains('You have tried to use an email address change link that has either been used or is no longer valid. Please visit your account and change your email again.'); } /** * Tests change of email with the wrong hash. */ public function testWrongHash() { - $timestamp = REQUEST_TIME - 1; + $timestamp = $this->time->getRequestTime() - 1; // Generate the hash for other user. $other_account = $this->drupalCreateUser(); $hash = user_pass_rehash($other_account, $timestamp); $this->drupalGet(MailChangeController::getUrl($this->account, [], $timestamp, $hash)->getInternalPath()); - $this->assertSession()->responseContains(t('You have tried to use an email address change link that has either been used or is no longer valid. Please visit your account and change your email again.')); + $this->assertSession()->responseContains('You have tried to use an email address change link that has either been used or is no longer valid. Please visit your account and change your email again.'); } /** diff --git a/core/modules/user/user.post_update.php b/core/modules/user/user.post_update.php index c463cc7..7d41a35 100644 --- a/core/modules/user/user.post_update.php +++ b/core/modules/user/user.post_update.php @@ -21,13 +21,20 @@ function user_post_update_mail_change() { $config_factory->getEditable('user.settings') ->set('notify.mail_change_notification', FALSE) ->set('notify.mail_change_verification', FALSE) - ->set('mail_change_timeout', 86400) ->save(); - $config = Yaml::parse(file_get_contents(__DIR__ . '/config/install/user.mail.yml')); + $mail_change_notification = [ + 'body' => "[user:display-name],\n\nA request to change your email address has been made at [site:name]. In order to complete the change you will need to follow the instructions sent to your new email address within one day.", + 'subject' => 'Email change information for [user:display-name] at [site:name]', + ]; + $mail_change_verification = [ + 'body' => "[user:display-name],\n\nA request to change your email address has been made at [site:name]. You need to verify the change by clicking on the link below or copying and pasting it in your browser:\n\n[user:mail-change-url]\n\nThis is a one-time URL, so it can be used only once. It expires after one day. If not used, your email address at [site:name] will not change.", + 'subject' => 'Email change information for [user:display-name] at [site:name]', + ]; + $config_factory->getEditable('user.mail') - ->set('mail_change_notification', $config['mail_change_notification']) - ->set('mail_change_verification', $config['mail_change_verification']) + ->set('mail_change_notification', $mail_change_notification) + ->set('mail_change_verification', $mail_change_verification) ->save(); }