[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 abstract class PhabricatorObjectMailReceiver extends PhabricatorMailReceiver { 4 5 /** 6 * Return a regular expression fragment which matches the name of an 7 * object which can receive mail. For example, Differential uses: 8 * 9 * D[1-9]\d* 10 * 11 * ...to match `D123`, etc., identifying Differential Revisions. 12 * 13 * @return string Regular expression fragment. 14 */ 15 abstract protected function getObjectPattern(); 16 17 18 /** 19 * Load the object receiving mail, based on an identifying pattern. Normally 20 * this pattern is some sort of object ID. 21 * 22 * @param string A string matched by @{method:getObjectPattern} 23 * fragment. 24 * @param PhabricatorUser The viewing user. 25 * @return void 26 */ 27 abstract protected function loadObject($pattern, PhabricatorUser $viewer); 28 29 30 final protected function processReceivedMail( 31 PhabricatorMetaMTAReceivedMail $mail, 32 PhabricatorUser $sender) { 33 34 $object = $this->loadObjectFromMail($mail, $sender); 35 $mail->setRelatedPHID($object->getPHID()); 36 37 $this->processReceivedObjectMail($mail, $object, $sender); 38 39 return $this; 40 } 41 42 abstract protected function processReceivedObjectMail( 43 PhabricatorMetaMTAReceivedMail $mail, 44 PhabricatorLiskDAO $object, 45 PhabricatorUser $sender); 46 47 public function loadMailReceiverObject($pattern, PhabricatorUser $viewer) { 48 return $this->loadObject($pattern, $viewer); 49 } 50 51 public function validateSender( 52 PhabricatorMetaMTAReceivedMail $mail, 53 PhabricatorUser $sender) { 54 55 parent::validateSender($mail, $sender); 56 57 $parts = $this->matchObjectAddressInMail($mail); 58 $pattern = $parts['pattern']; 59 60 try { 61 $object = $this->loadObjectFromMail($mail, $sender); 62 } catch (PhabricatorPolicyException $policy_exception) { 63 throw new PhabricatorMetaMTAReceivedMailProcessingException( 64 MetaMTAReceivedMailStatus::STATUS_POLICY_PROBLEM, 65 pht( 66 'This mail is addressed to an object ("%s") you do not have '. 67 'permission to see: %s', 68 $pattern, 69 $policy_exception->getMessage())); 70 } 71 72 if (!$object) { 73 throw new PhabricatorMetaMTAReceivedMailProcessingException( 74 MetaMTAReceivedMailStatus::STATUS_NO_SUCH_OBJECT, 75 pht( 76 'This mail is addressed to an object ("%s"), but that object '. 77 'does not exist.', 78 $pattern)); 79 } 80 81 $sender_identifier = $parts['sender']; 82 83 if ($sender_identifier === 'public') { 84 if (!PhabricatorEnv::getEnvConfig('metamta.public-replies')) { 85 throw new PhabricatorMetaMTAReceivedMailProcessingException( 86 MetaMTAReceivedMailStatus::STATUS_NO_PUBLIC_MAIL, 87 pht( 88 'This mail is addressed to the public email address of an object '. 89 '("%s"), but public replies are not enabled on this Phabricator '. 90 'install. An administrator may have recently disabled this '. 91 'setting, or you may have replied to an old message. Try '. 92 'replying to a more recent message instead.', 93 $pattern)); 94 } 95 $check_phid = $object->getPHID(); 96 } else { 97 if ($sender_identifier != $sender->getID()) { 98 throw new PhabricatorMetaMTAReceivedMailProcessingException( 99 MetaMTAReceivedMailStatus::STATUS_USER_MISMATCH, 100 pht( 101 'This mail is addressed to the private email address of an object '. 102 '("%s"), but you are not the user who is authorized to use the '. 103 'address you sent mail to. Each private address is unique to the '. 104 'user who received the original mail. Try replying to a message '. 105 'which was sent directly to you instead.', 106 $pattern)); 107 } 108 $check_phid = $sender->getPHID(); 109 } 110 111 $expect_hash = self::computeMailHash($object->getMailKey(), $check_phid); 112 113 if ($expect_hash != $parts['hash']) { 114 throw new PhabricatorMetaMTAReceivedMailProcessingException( 115 MetaMTAReceivedMailStatus::STATUS_HASH_MISMATCH, 116 pht( 117 'This mail is addressed to an object ("%s"), but the address is '. 118 'not correct (the security hash is wrong). Check that the address '. 119 'is correct.', 120 $pattern)); 121 } 122 } 123 124 125 final public function canAcceptMail(PhabricatorMetaMTAReceivedMail $mail) { 126 if ($this->matchObjectAddressInMail($mail)) { 127 return true; 128 } 129 130 return false; 131 } 132 133 private function matchObjectAddressInMail( 134 PhabricatorMetaMTAReceivedMail $mail) { 135 136 foreach ($mail->getToAddresses() as $address) { 137 $parts = $this->matchObjectAddress($address); 138 if ($parts) { 139 return $parts; 140 } 141 } 142 143 return null; 144 } 145 146 private function matchObjectAddress($address) { 147 $regexp = $this->getAddressRegexp(); 148 149 $address = self::stripMailboxPrefix($address); 150 $local = id(new PhutilEmailAddress($address))->getLocalPart(); 151 152 $matches = null; 153 if (!preg_match($regexp, $local, $matches)) { 154 return false; 155 } 156 157 return $matches; 158 } 159 160 private function getAddressRegexp() { 161 $pattern = $this->getObjectPattern(); 162 163 $regexp = 164 '(^'. 165 '(?P<pattern>'.$pattern.')'. 166 '\\+'. 167 '(?P<sender>\w+)'. 168 '\\+'. 169 '(?P<hash>[a-f0-9]{16})'. 170 '$)Ui'; 171 172 return $regexp; 173 } 174 175 private function loadObjectFromMail( 176 PhabricatorMetaMTAReceivedMail $mail, 177 PhabricatorUser $sender) { 178 $parts = $this->matchObjectAddressInMail($mail); 179 180 return $this->loadObject( 181 phutil_utf8_strtoupper($parts['pattern']), 182 $sender); 183 } 184 185 public static function computeMailHash($mail_key, $phid) { 186 $global_mail_key = PhabricatorEnv::getEnvConfig('phabricator.mail-key'); 187 188 $hash = PhabricatorHash::digest($mail_key.$global_mail_key.$phid); 189 return substr($hash, 0, 16); 190 } 191 192 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |