@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Move "Password Reset" email to "PeopleMailEngine"

Summary:
Ref T13343. This makes "Password Reset" email a little more consistent with other modern types of email. My expectation is that this patch has no functional changes, just organizes code a little more consistently.

The new `setRecipientAddress()` mechanism deals with the case where the user types a secondary (but still verified) address.

Test Plan:
- Sent a normal "login with email" email.
- Sent a "login with email to set password" email by trying to set a password on an account with no password yet.
- Tried to email reset a bot account (no dice: they can't do web logins so this operation isn't valid).
- Tested existing "PeopleMailEngine" subclasses:
- Created a new user and sent a "welcome" email.
- Renamed a user and sent a "username changed" email.
- Reviewed all generated mail with `bin/mail list-outbound`.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13343

Differential Revision: https://secure.phabricator.com/D20662

+151 -65
+2
src/__phutil_library_map__.php
··· 4001 4001 'PhabricatorPeopleDeleteController' => 'applications/people/controller/PhabricatorPeopleDeleteController.php', 4002 4002 'PhabricatorPeopleDetailsProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleDetailsProfileMenuItem.php', 4003 4003 'PhabricatorPeopleDisableController' => 'applications/people/controller/PhabricatorPeopleDisableController.php', 4004 + 'PhabricatorPeopleEmailLoginMailEngine' => 'applications/people/mail/PhabricatorPeopleEmailLoginMailEngine.php', 4004 4005 'PhabricatorPeopleEmpowerController' => 'applications/people/controller/PhabricatorPeopleEmpowerController.php', 4005 4006 'PhabricatorPeopleExternalPHIDType' => 'applications/people/phid/PhabricatorPeopleExternalPHIDType.php', 4006 4007 'PhabricatorPeopleIconSet' => 'applications/people/icon/PhabricatorPeopleIconSet.php', ··· 10231 10232 'PhabricatorPeopleDeleteController' => 'PhabricatorPeopleController', 10232 10233 'PhabricatorPeopleDetailsProfileMenuItem' => 'PhabricatorProfileMenuItem', 10233 10234 'PhabricatorPeopleDisableController' => 'PhabricatorPeopleController', 10235 + 'PhabricatorPeopleEmailLoginMailEngine' => 'PhabricatorPeopleMailEngine', 10234 10236 'PhabricatorPeopleEmpowerController' => 'PhabricatorPeopleController', 10235 10237 'PhabricatorPeopleExternalPHIDType' => 'PhabricatorPHIDType', 10236 10238 'PhabricatorPeopleIconSet' => 'PhabricatorIconSet',
+17 -61
src/applications/auth/controller/PhabricatorEmailLoginController.php
··· 94 94 } 95 95 96 96 if (!$errors) { 97 - $body = $this->newAccountLoginMailBody( 98 - $target_user, 99 - $is_logged_in); 97 + $target_address = new PhutilEmailAddress($target_email->getAddress()); 98 + 99 + $mail_engine = id(new PhabricatorPeopleEmailLoginMailEngine()) 100 + ->setSender($viewer) 101 + ->setRecipient($target_user) 102 + ->setRecipientAddress($target_address); 103 + 104 + try { 105 + $mail_engine->validateMail(); 106 + } catch (PhabricatorPeopleMailEngineException $ex) { 107 + return $this->newDialog() 108 + ->setTitle($ex->getTitle()) 109 + ->appendParagraph($ex->getBody()) 110 + ->addCancelButton('/auth/start/', pht('Done')); 111 + } 112 + 113 + $mail_engine->sendMail(); 100 114 101 115 if ($is_logged_in) { 102 - $subject = pht('[Phabricator] Account Password Link'); 103 116 $instructions = pht( 104 117 'An email has been sent containing a link you can use to set '. 105 118 'a password for your account.'); 106 119 } else { 107 - $subject = pht('[Phabricator] Account Login Link'); 108 120 $instructions = pht( 109 121 'An email has been sent containing a link you can use to log '. 110 122 'in to your account.'); 111 123 } 112 - 113 - $mail = id(new PhabricatorMetaMTAMail()) 114 - ->setSubject($subject) 115 - ->setForceDelivery(true) 116 - ->addRawTos(array($target_email->getAddress())) 117 - ->setBody($body) 118 - ->saveAndSend(); 119 124 120 125 return $this->newDialog() 121 126 ->setTitle(pht('Check Your Email')) ··· 180 185 ->appendForm($form) 181 186 ->addCancelButton('/auth/start/') 182 187 ->addSubmitButton(pht('Send Email')); 183 - } 184 - 185 - private function newAccountLoginMailBody( 186 - PhabricatorUser $user, 187 - $is_logged_in) { 188 - 189 - $engine = new PhabricatorAuthSessionEngine(); 190 - $uri = $engine->getOneTimeLoginURI( 191 - $user, 192 - null, 193 - PhabricatorAuthSessionEngine::ONETIME_RESET); 194 - 195 - $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); 196 - $have_passwords = $this->isPasswordAuthEnabled(); 197 - 198 - if ($have_passwords) { 199 - if ($is_logged_in) { 200 - $body = pht( 201 - 'You can use this link to set a password on your account:'. 202 - "\n\n %s\n", 203 - $uri); 204 - } else if ($is_serious) { 205 - $body = pht( 206 - "You can use this link to reset your Phabricator password:". 207 - "\n\n %s\n", 208 - $uri); 209 - } else { 210 - $body = pht( 211 - "Condolences on forgetting your password. You can use this ". 212 - "link to reset it:\n\n". 213 - " %s\n\n". 214 - "After you set a new password, consider writing it down on a ". 215 - "sticky note and attaching it to your monitor so you don't ". 216 - "forget again! Choosing a very short, easy-to-remember password ". 217 - "like \"cat\" or \"1234\" might also help.\n\n". 218 - "Best Wishes,\nPhabricator\n", 219 - $uri); 220 - 221 - } 222 - } else { 223 - $body = pht( 224 - "You can use this login link to regain access to your Phabricator ". 225 - "account:". 226 - "\n\n". 227 - " %s\n", 228 - $uri); 229 - } 230 - 231 - return $body; 232 188 } 233 189 234 190 private function isPasswordAuthEnabled() {
+107
src/applications/people/mail/PhabricatorPeopleEmailLoginMailEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorPeopleEmailLoginMailEngine 4 + extends PhabricatorPeopleMailEngine { 5 + 6 + public function validateMail() { 7 + $recipient = $this->getRecipient(); 8 + 9 + if ($recipient->getIsDisabled()) { 10 + $this->throwValidationException( 11 + pht('User is Disabled'), 12 + pht( 13 + 'You can not send an email login link to this email address '. 14 + 'because the associated user account is disabled.')); 15 + } 16 + 17 + if (!$recipient->canEstablishWebSessions()) { 18 + $this->throwValidationException( 19 + pht('Not a Normal User'), 20 + pht( 21 + 'You can not send an email login link to this email address '. 22 + 'because the associated user account is not a normal user account '. 23 + 'and can not log in to the web interface.')); 24 + } 25 + } 26 + 27 + protected function newMail() { 28 + $is_set_password = $this->isSetPasswordWorkflow(); 29 + 30 + if ($is_set_password) { 31 + $subject = pht('[Phabricator] Account Password Link'); 32 + } else { 33 + $subject = pht('[Phabricator] Account Login Link'); 34 + } 35 + 36 + $recipient = $this->getRecipient(); 37 + $engine = new PhabricatorAuthSessionEngine(); 38 + $login_uri = $engine->getOneTimeLoginURI( 39 + $recipient, 40 + null, 41 + PhabricatorAuthSessionEngine::ONETIME_RESET); 42 + 43 + $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); 44 + $have_passwords = $this->isPasswordAuthEnabled(); 45 + 46 + if ($have_passwords) { 47 + if ($is_set_password) { 48 + $body = pht( 49 + 'You can use this link to set a password on your account:'. 50 + "\n\n %s\n", 51 + $login_uri); 52 + } else if ($is_serious) { 53 + $body = pht( 54 + "You can use this link to reset your Phabricator password:". 55 + "\n\n %s\n", 56 + $login_uri); 57 + } else { 58 + $body = pht( 59 + "Condolences on forgetting your password. You can use this ". 60 + "link to reset it:\n\n". 61 + " %s\n\n". 62 + "After you set a new password, consider writing it down on a ". 63 + "sticky note and attaching it to your monitor so you don't ". 64 + "forget again! Choosing a very short, easy-to-remember password ". 65 + "like \"cat\" or \"1234\" might also help.\n\n". 66 + "Best Wishes,\nPhabricator\n", 67 + $login_uri); 68 + 69 + } 70 + } else { 71 + $body = pht( 72 + "You can use this login link to regain access to your Phabricator ". 73 + "account:". 74 + "\n\n". 75 + " %s\n", 76 + $login_uri); 77 + } 78 + 79 + return id(new PhabricatorMetaMTAMail()) 80 + ->setSubject($subject) 81 + ->setBody($body); 82 + } 83 + 84 + private function isPasswordAuthEnabled() { 85 + return (bool)PhabricatorPasswordAuthProvider::getPasswordProvider(); 86 + } 87 + 88 + private function isSetPasswordWorkflow() { 89 + $sender = $this->getSender(); 90 + $recipient = $this->getRecipient(); 91 + 92 + // Users can hit the "login with an email link" workflow while trying to 93 + // set a password on an account which does not yet have a password. We 94 + // require they verify that they own the email address and send them 95 + // through the email login flow. In this case, the messaging is slightly 96 + // different. 97 + 98 + if ($sender->getPHID()) { 99 + if ($sender->getPHID() === $recipient->getPHID()) { 100 + return true; 101 + } 102 + } 103 + 104 + return false; 105 + } 106 + 107 + }
+25 -1
src/applications/people/mail/PhabricatorPeopleMailEngine.php
··· 5 5 6 6 private $sender; 7 7 private $recipient; 8 + private $recipientAddress; 8 9 9 10 final public function setSender(PhabricatorUser $sender) { 10 11 $this->sender = $sender; ··· 30 31 return $this->recipient; 31 32 } 32 33 34 + final public function setRecipientAddress(PhutilEmailAddress $address) { 35 + $this->recipientAddress = $address; 36 + return $this; 37 + } 38 + 39 + final public function getRecipientAddress() { 40 + if (!$this->recipientAddress) { 41 + throw new PhutilInvalidStateException('recipientAddress'); 42 + } 43 + return $this->recipientAddress; 44 + } 45 + 46 + final public function hasRecipientAddress() { 47 + return ($this->recipientAddress !== null); 48 + } 49 + 33 50 final public function canSendMail() { 34 51 try { 35 52 $this->validateMail(); ··· 43 60 $this->validateMail(); 44 61 $mail = $this->newMail(); 45 62 63 + if ($this->hasRecipientAddress()) { 64 + $recipient_address = $this->getRecipientAddress(); 65 + $mail->addRawTos(array($recipient_address->getAddress())); 66 + } else { 67 + $recipient = $this->getRecipient(); 68 + $mail->addTos(array($recipient->getPHID())); 69 + } 70 + 46 71 $mail 47 72 ->setForceDelivery(true) 48 73 ->save(); ··· 52 77 53 78 abstract public function validateMail(); 54 79 abstract protected function newMail(); 55 - 56 80 57 81 final protected function throwValidationException($title, $body) { 58 82 throw new PhabricatorPeopleMailEngineException($title, $body);
-2
src/applications/people/mail/PhabricatorPeopleUsernameMailEngine.php
··· 30 30 31 31 protected function newMail() { 32 32 $sender = $this->getSender(); 33 - $recipient = $this->getRecipient(); 34 33 35 34 $sender_username = $sender->getUsername(); 36 35 $sender_realname = $sender->getRealName(); ··· 52 51 $new_username)); 53 52 54 53 return id(new PhabricatorMetaMTAMail()) 55 - ->addTos(array($recipient->getPHID())) 56 54 ->setSubject(pht('[Phabricator] Username Changed')) 57 55 ->setBody($body); 58 56 }
-1
src/applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php
··· 104 104 $message = implode("\n\n", $message); 105 105 106 106 return id(new PhabricatorMetaMTAMail()) 107 - ->addTos(array($recipient->getPHID())) 108 107 ->setSubject(pht('[Phabricator] Welcome to Phabricator')) 109 108 ->setBody($message); 110 109 }