Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/differential/DifferentialReplyHandler.php b/src/applications/differential/DifferentialReplyHandler.php
index b16dbde854..3104c04b26 100644
--- a/src/applications/differential/DifferentialReplyHandler.php
+++ b/src/applications/differential/DifferentialReplyHandler.php
@@ -1,186 +1,186 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class DifferentialReplyHandler extends PhabricatorMailReplyHandler {
private $receivedMail;
public function validateMailReceiver($mail_receiver) {
if (!($mail_receiver instanceof DifferentialRevision)) {
throw new Exception("Receiver is not a DifferentialRevision!");
}
}
public function getPrivateReplyHandlerEmailAddress(
PhabricatorObjectHandle $handle) {
return $this->getDefaultPrivateReplyHandlerEmailAddress($handle, 'D');
}
public function getPublicReplyHandlerEmailAddress() {
return $this->getDefaultPublicReplyHandlerEmailAddress('D');
}
public function getReplyHandlerDomain() {
return PhabricatorEnv::getEnvConfig(
'metamta.differential.reply-handler-domain');
}
/*
* Generate text like the following from the supported commands.
* "
*
* ACTIONS
* Reply to comment, or !accept, !reject, !abandon, !resign, !reclaim.
*
* "
*/
public function getReplyHandlerInstructions() {
if (!$this->supportsReplies()) {
return null;
}
$supported_commands = $this->getSupportedCommands();
$text = '';
if (empty($supported_commands)) {
return $text;
}
$comment_command_printed = false;
if (in_array(DifferentialAction::ACTION_COMMENT, $supported_commands)) {
$text .= 'Reply to comment';
$comment_command_printed = true;
$supported_commands = array_diff(
$supported_commands, array(DifferentialAction::ACTION_COMMENT));
}
if (!empty($supported_commands)) {
if ($comment_command_printed) {
$text .= ', or ';
}
$modified_commands = array();
foreach ($supported_commands as $command) {
$modified_commands[] = '!'.$command;
}
$text .= implode(', ', $modified_commands);
}
$text .= ".";
return $text;
}
public function getSupportedCommands() {
$actions = array(
DifferentialAction::ACTION_COMMENT,
DifferentialAction::ACTION_REJECT,
DifferentialAction::ACTION_ABANDON,
DifferentialAction::ACTION_RECLAIM,
DifferentialAction::ACTION_RESIGN,
DifferentialAction::ACTION_RETHINK,
'unsubscribe',
);
if (PhabricatorEnv::getEnvConfig('differential.enable-email-accept')) {
$actions[] = DifferentialAction::ACTION_ACCEPT;
}
return $actions;
}
public function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
$this->receivedMail = $mail;
$this->handleAction($mail->getCleanTextBody());
}
public function handleAction($body) {
// all commands start with a bang and separated from the body by a newline
// to make sure that actual feedback text couldn't trigger an action.
// unrecognized commands will be parsed as part of the comment.
$command = DifferentialAction::ACTION_COMMENT;
$supported_commands = $this->getSupportedCommands();
$regex = "/\A\n*!(" . implode('|', $supported_commands) . ")\n*/";
$matches = array();
if (preg_match($regex, $body, $matches)) {
$command = $matches[1];
$body = trim(str_replace('!' . $command, '', $body));
}
$actor = $this->getActor();
if (!$actor) {
throw new Exception('No actor is set for the reply action.');
}
switch ($command) {
case 'unsubscribe':
$this->unsubscribeUser($this->getMailReceiver(), $actor);
// TODO: Send the user a confirmation email?
return null;
}
try {
$editor = new DifferentialCommentEditor(
$this->getMailReceiver(),
$actor->getPHID(),
$command);
// NOTE: We have to be careful about this because Facebook's
// implementation jumps straight into handleAction() and will not have
// a PhabricatorMetaMTAReceivedMail object.
if ($this->receivedMail) {
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_EMAIL,
array(
'id' => $this->receivedMail->getID(),
));
$editor->setContentSource($content_source);
$editor->setParentMessageID($this->receivedMail->getMessageID());
}
$editor->setMessage($body);
$comment = $editor->save();
return $comment->getID();
} catch (Exception $ex) {
$exception_mail = new DifferentialExceptionMail(
$this->getMailReceiver(),
$ex,
- $body);
+ $this->receivedMail->getRawTextBody());
$exception_mail->setToPHIDs(array($this->getActor()->getPHID()));
$exception_mail->send();
throw $ex;
}
}
private function unsubscribeUser(
DifferentialRevision $revision,
PhabricatorUser $user) {
$revision->loadRelationships();
DifferentialRevisionEditor::removeCCAndUpdateRevision(
$revision,
$user->getPHID(),
$user->getPHID());
}
}
diff --git a/src/applications/differential/mail/DifferentialExceptionMail.php b/src/applications/differential/mail/DifferentialExceptionMail.php
index d168302054..90ceed2e8e 100644
--- a/src/applications/differential/mail/DifferentialExceptionMail.php
+++ b/src/applications/differential/mail/DifferentialExceptionMail.php
@@ -1,66 +1,63 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class DifferentialExceptionMail extends DifferentialMail {
public function __construct(
DifferentialRevision $revision,
Exception $exception,
$original_body) {
$this->revision = $revision;
$this->exception = $exception;
$this->originalBody = $original_body;
}
protected function renderBody() {
// Never called since buildBody() is overridden.
}
protected function renderSubject() {
return "Exception: unable to process your mail request";
}
protected function renderVaryPrefix() {
return '';
}
protected function buildBody() {
$exception = $this->exception;
$original_body = $this->originalBody;
$message = $exception->getMessage();
- $trace = $exception->getTraceAsString();
return <<<EOBODY
Your request failed because an exception was encoutered while processing it:
EXCEPTION: {$message}
-{$trace}
-
--- Original Body --------------------------
+-- Original Body -------------------------------------------------------------
{$original_body}
EOBODY;
}
}
diff --git a/src/applications/differential/mail/DifferentialMail.php b/src/applications/differential/mail/DifferentialMail.php
index b54b799737..1820ec1a89 100644
--- a/src/applications/differential/mail/DifferentialMail.php
+++ b/src/applications/differential/mail/DifferentialMail.php
@@ -1,475 +1,474 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
abstract class DifferentialMail {
protected $to = array();
protected $cc = array();
protected $actorHandle;
protected $revision;
protected $comment;
protected $changesets;
protected $inlineComments;
protected $isFirstMailAboutRevision;
protected $isFirstMailToRecipients;
protected $heraldTranscriptURI;
protected $heraldRulesHeader;
protected $replyHandler;
protected $parentMessageID;
protected function renderSubject() {
$revision = $this->getRevision();
$title = $revision->getTitle();
$id = $revision->getID();
return "D{$id}: {$title}";
}
abstract protected function renderVaryPrefix();
abstract protected function renderBody();
public function setActorHandle($actor_handle) {
$this->actorHandle = $actor_handle;
return $this;
}
public function getActorHandle() {
return $this->actorHandle;
}
protected function getActorName() {
$handle = $this->getActorHandle();
if ($handle) {
return $handle->getName();
}
return '???';
}
public function setParentMessageID($parent_message_id) {
$this->parentMessageID = $parent_message_id;
return $this;
}
public function setXHeraldRulesHeader($header) {
$this->heraldRulesHeader = $header;
return $this;
}
public function send() {
$to_phids = $this->getToPHIDs();
if (!$to_phids) {
throw new Exception('No "To:" users provided!');
}
$cc_phids = $this->getCCPHIDs();
$attachments = $this->buildAttachments();
$template = new PhabricatorMetaMTAMail();
$actor_handle = $this->getActorHandle();
$reply_handler = $this->getReplyHandler();
if ($actor_handle) {
$template->setFrom($actor_handle->getPHID());
}
$template
->setIsHTML($this->shouldMarkMailAsHTML())
->setParentMessageID($this->parentMessageID)
->addHeader('Thread-Topic', $this->getThreadTopic());
$template->setAttachments($attachments);
$template->setThreadID(
$this->getThreadID(),
$this->isFirstMailAboutRevision());
if ($this->heraldRulesHeader) {
$template->addHeader('X-Herald-Rules', $this->heraldRulesHeader);
}
$revision = $this->revision;
if ($revision) {
if ($revision->getAuthorPHID()) {
$template->addHeader(
'X-Differential-Author',
'<'.$revision->getAuthorPHID().'>');
}
$reviewer_phids = $revision->getReviewers();
if ($reviewer_phids) {
// Add several headers to support e-mail clients which are not able to
// create rules using regular expressions or wildcards (namely Outlook).
$template->addPHIDHeaders('X-Differential-Reviewer', $reviewer_phids);
// Add it also as a list to allow matching of the first reviewer and
// also for backwards compatibility.
$template->addHeader(
'X-Differential-Reviewers',
'<'.implode('>, <', $reviewer_phids).'>');
}
- $cc_phids = $revision->getCCPHIDs();
if ($cc_phids) {
$template->addPHIDHeaders('X-Differential-CC', $cc_phids);
$template->addHeader(
'X-Differential-CCs',
'<'.implode('>, <', $cc_phids).'>');
// Determine explicit CCs (those added by humans) and put them in a
// header so users can differentiate between Herald CCs and human CCs.
$relation_subscribed = DifferentialRevision::RELATION_SUBSCRIBED;
$raw = $revision->getRawRelations($relation_subscribed);
$reason_phids = ipull($raw, 'reasonPHID');
$reason_handles = id(new PhabricatorObjectHandleData($reason_phids))
->loadHandles();
$explicit_cc = array();
foreach ($raw as $relation) {
if (!$relation['reasonPHID']) {
continue;
}
$type = $reason_handles[$relation['reasonPHID']]->getType();
if ($type == PhabricatorPHIDConstants::PHID_TYPE_USER) {
$explicit_cc[] = $relation['objectPHID'];
}
}
if ($explicit_cc) {
$template->addPHIDHeaders('X-Differential-Explicit-CC', $explicit_cc);
$template->addHeader(
'X-Differential-Explicit-CCs',
'<'.implode('>, <', $explicit_cc).'>');
}
}
}
$template->setIsBulk(true);
$template->setRelatedPHID($this->getRevision()->getPHID());
$mailtags = $this->getMailTags();
if ($mailtags) {
$template->setMailTags($mailtags);
}
$phids = array();
foreach ($to_phids as $phid) {
$phids[$phid] = true;
}
foreach ($cc_phids as $phid) {
$phids[$phid] = true;
}
$phids = array_keys($phids);
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
$objects = id(new PhabricatorObjectHandleData($phids))->loadObjects();
$to_handles = array_select_keys($handles, $to_phids);
$cc_handles = array_select_keys($handles, $cc_phids);
$this->prepareBody();
$mails = $reply_handler->multiplexMail($template, $to_handles, $cc_handles);
$original_translator = PhutilTranslator::getInstance();
if (!PhabricatorMetaMTAMail::shouldMultiplexAllMail()) {
$translation = PhabricatorEnv::newObjectFromConfig(
'translation.provider');
$translator = id(new PhutilTranslator())
->setLanguage($translation->getLanguage())
->addTranslations($translation->getTranslations());
}
try {
foreach ($mails as $mail) {
if (PhabricatorMetaMTAMail::shouldMultiplexAllMail()) {
$translation = newv($mail->getTranslation($objects), array());
$translator = id(new PhutilTranslator())
->setLanguage($translation->getLanguage())
->addTranslations($translation->getTranslations());
PhutilTranslator::setInstance($translator);
}
$body =
$this->buildBody()."\n".
$reply_handler->getRecipientsSummary($to_handles, $cc_handles);
$mail
->setSubject($this->renderSubject())
->setSubjectPrefix($this->getSubjectPrefix())
->setVarySubjectPrefix($this->renderVaryPrefix())
->setBody($body);
$event = new PhabricatorEvent(
PhabricatorEventType::TYPE_DIFFERENTIAL_WILLSENDMAIL,
array(
'mail' => $mail,
)
);
PhutilEventEngine::dispatchEvent($event);
$mail = $event->getValue('mail');
$mail->saveAndSend();
}
} catch (Exception $ex) {
PhutilTranslator::setInstance($original_translator);
throw $ex;
}
PhutilTranslator::setInstance($original_translator);
}
protected function getMailTags() {
return array();
}
protected function getSubjectPrefix() {
return PhabricatorEnv::getEnvConfig('metamta.differential.subject-prefix');
}
protected function shouldMarkMailAsHTML() {
return false;
}
/**
* @{method:buildBody} is called once for each e-mail recipient to allow
* translating text to his language. This method can be used to load data that
* don't need translation and use them later in @{method:buildBody}.
*
* @param
* @return
*/
protected function prepareBody() {
}
protected function buildBody() {
$body = $this->renderBody();
$reply_handler = $this->getReplyHandler();
$reply_instructions = $reply_handler->getReplyHandlerInstructions();
if ($reply_instructions) {
$body .=
"\nREPLY HANDLER ACTIONS\n".
" {$reply_instructions}\n";
}
if ($this->getHeraldTranscriptURI() && $this->isFirstMailToRecipients()) {
$manage_uri = PhabricatorEnv::getProductionURI(
'/herald/view/differential/');
$xscript_uri = $this->getHeraldTranscriptURI();
$body .= <<<EOTEXT
MANAGE HERALD DIFFERENTIAL RULES
{$manage_uri}
WHY DID I GET THIS EMAIL?
{$xscript_uri}
EOTEXT;
}
return $body;
}
/**
* You can override this method in a subclass and return array of attachments
* to be sent with the email. Each attachment is an instance of
* PhabricatorMetaMTAAttachment.
*/
protected function buildAttachments() {
return array();
}
public function getReplyHandler() {
if (!$this->replyHandler) {
$this->replyHandler =
self::newReplyHandlerForRevision($this->getRevision());
}
return $this->replyHandler;
}
public static function newReplyHandlerForRevision(
DifferentialRevision $revision) {
$reply_handler = PhabricatorEnv::newObjectFromConfig(
'metamta.differential.reply-handler');
$reply_handler->setMailReceiver($revision);
return $reply_handler;
}
protected function formatText($text) {
$text = explode("\n", rtrim($text));
foreach ($text as &$line) {
$line = rtrim(' '.$line);
}
unset($line);
return implode("\n", $text);
}
public function setToPHIDs(array $to) {
$this->to = $this->filterContactPHIDs($to);
return $this;
}
public function setCCPHIDs(array $cc) {
$this->cc = $this->filterContactPHIDs($cc);
return $this;
}
protected function filterContactPHIDs(array $phids) {
return $phids;
// TODO: actually do this?
// Differential revisions use Subscriptions for CCs, so any arbitrary
// PHID can end up CC'd to them. Only try to actually send email PHIDs
// which have ToolsHandle types that are marked emailable. If we don't
// filter here, sending the email will fail.
/*
$handles = array();
prep(new ToolsHandleData($phids, $handles));
foreach ($handles as $phid => $handle) {
if (!$handle->isEmailable()) {
unset($handles[$phid]);
}
}
return array_keys($handles);
*/
}
protected function getToPHIDs() {
return $this->to;
}
protected function getCCPHIDs() {
return $this->cc;
}
public function setRevision($revision) {
$this->revision = $revision;
return $this;
}
public function getRevision() {
return $this->revision;
}
protected function getThreadID() {
$phid = $this->getRevision()->getPHID();
return "differential-rev-{$phid}-req";
}
protected function getThreadTopic() {
$id = $this->getRevision()->getID();
$title = $this->getRevision()->getOriginalTitle();
return "D{$id}: {$title}";
}
public function setComment($comment) {
$this->comment = $comment;
return $this;
}
public function getComment() {
return $this->comment;
}
public function setChangesets($changesets) {
$this->changesets = $changesets;
return $this;
}
public function getChangesets() {
return $this->changesets;
}
public function setInlineComments(array $inline_comments) {
assert_instances_of($inline_comments, 'PhabricatorInlineCommentInterface');
$this->inlineComments = $inline_comments;
return $this;
}
public function getInlineComments() {
return $this->inlineComments;
}
protected function renderAuxFields($phase) {
$selector = DifferentialFieldSelector::newSelector();
$aux_fields = $selector->sortFieldsForMail(
$selector->getFieldSpecifications());
$body = array();
foreach ($aux_fields as $field) {
$field->setRevision($this->getRevision());
// TODO: Introduce and use getRequiredHandlePHIDsForMail() and load all
// handles in prepareBody().
$text = $field->renderValueForMail($phase);
if ($text !== null) {
$body[] = $text;
$body[] = null;
}
}
return implode("\n", $body);
}
public function setIsFirstMailToRecipients($first) {
$this->isFirstMailToRecipients = $first;
return $this;
}
public function isFirstMailToRecipients() {
return $this->isFirstMailToRecipients;
}
public function setIsFirstMailAboutRevision($first) {
$this->isFirstMailAboutRevision = $first;
return $this;
}
public function isFirstMailAboutRevision() {
return $this->isFirstMailAboutRevision;
}
public function setHeraldTranscriptURI($herald_transcript_uri) {
$this->heraldTranscriptURI = $herald_transcript_uri;
return $this;
}
public function getHeraldTranscriptURI() {
return $this->heraldTranscriptURI;
}
protected function renderHandleList(array $handles, array $phids) {
assert_instances_of($handles, 'PhabricatorObjectHandle');
$names = array();
foreach ($phids as $phid) {
$names[] = $handles[$phid]->getName();
}
return implode(', ', $names);
}
}
diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php
index f7d2122f20..4a05119952 100644
--- a/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php
+++ b/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php
@@ -1,308 +1,312 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
protected $headers = array();
protected $bodies = array();
protected $attachments = array();
protected $relatedPHID;
protected $authorPHID;
protected $message;
public function getConfiguration() {
return array(
self::CONFIG_SERIALIZATION => array(
'headers' => self::SERIALIZATION_JSON,
'bodies' => self::SERIALIZATION_JSON,
'attachments' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
public function setHeaders(array $headers) {
// Normalize headers to lowercase.
$normalized = array();
foreach ($headers as $name => $value) {
$normalized[strtolower($name)] = $value;
}
$this->headers = $normalized;
return $this;
}
public function getMessageID() {
return idx($this->headers, 'message-id');
}
public function getSubject() {
return idx($this->headers, 'subject');
}
public function processReceivedMail() {
// If Phabricator sent the mail, always drop it immediately. This prevents
// loops where, e.g., the public bug address is also a user email address
// and creating a bug sends them an email, which loops.
$is_phabricator_mail = idx(
$this->headers,
'x-phabricator-sent-this-message');
if ($is_phabricator_mail) {
$message = "Ignoring email with 'X-Phabricator-Sent-This-Message' ".
"header to avoid loops.";
return $this->setMessage($message)->save();
}
$to = idx($this->headers, 'to');
$to = $this->getRawEmailAddress($to);
$from = idx($this->headers, 'from');
$create_task = PhabricatorEnv::getEnvConfig(
'metamta.maniphest.public-create-email');
if ($create_task && $to == $create_task) {
$receiver = new ManiphestTask();
$user = $this->lookupPublicUser();
if ($user) {
$this->setAuthorPHID($user->getPHID());
} else {
$default_author = PhabricatorEnv::getEnvConfig(
'metamta.maniphest.default-public-author');
if ($default_author) {
$user = id(new PhabricatorUser())->loadOneWhere(
'username = %s',
$default_author);
if ($user) {
$receiver->setOriginalEmailSource($from);
} else {
throw new Exception(
"Phabricator is misconfigured, the configuration key ".
"'metamta.maniphest.default-public-author' is set to user ".
"'{$default_author}' but that user does not exist.");
}
} else {
// TODO: We should probably bounce these since from the user's
// perspective their email vanishes into a black hole.
return $this->setMessage("Invalid public user '{$from}'.")->save();
}
}
$receiver->setAuthorPHID($user->getPHID());
$receiver->setPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
$editor = new ManiphestTransactionEditor();
$handler = $editor->buildReplyHandler($receiver);
$handler->setActor($user);
$handler->receiveEmail($this);
$this->setRelatedPHID($receiver->getPHID());
$this->setMessage('OK');
return $this->save();
}
// We've already stripped this, so look for an object address which has
// a format like: D291+291+b0a41ca848d66dcc@example.com
$matches = null;
$single_handle_prefix = PhabricatorEnv::getEnvConfig(
'metamta.single-reply-handler-prefix');
$prefixPattern = ($single_handle_prefix)
? preg_quote($single_handle_prefix, '/') . '\+'
: '';
$pattern = "/^{$prefixPattern}((?:D|T|C)\d+)\+([\w]+)\+([a-f0-9]{16})@/U";
$ok = preg_match(
$pattern,
$to,
$matches);
if (!$ok) {
return $this->setMessage("Unrecognized 'to' format: {$to}")->save();
}
$receiver_name = $matches[1];
$user_id = $matches[2];
$hash = $matches[3];
if ($user_id == 'public') {
if (!PhabricatorEnv::getEnvConfig('metamta.public-replies')) {
return $this->setMessage("Public replies not enabled.")->save();
}
$user = $this->lookupPublicUser();
if (!$user) {
return $this->setMessage("Invalid public user '{$from}'.")->save();
}
$use_user_hash = false;
} else {
$user = id(new PhabricatorUser())->load($user_id);
if (!$user) {
return $this->setMessage("Invalid private user '{$user_id}'.")->save();
}
$use_user_hash = true;
}
if ($user->getIsDisabled()) {
return $this->setMessage("User '{$user_id}' is disabled")->save();
}
$this->setAuthorPHID($user->getPHID());
$receiver = self::loadReceiverObject($receiver_name);
if (!$receiver) {
return $this->setMessage("Invalid object '{$receiver_name}'")->save();
}
$this->setRelatedPHID($receiver->getPHID());
if ($use_user_hash) {
// This is a private reply-to address, check that the user hash is
// correct.
$check_phid = $user->getPHID();
} else {
// This is a public reply-to address, check that the object hash is
// correct.
$check_phid = $receiver->getPHID();
}
$expect_hash = self::computeMailHash($receiver->getMailKey(), $check_phid);
// See note at computeOldMailHash().
$old_hash = self::computeOldMailHash($receiver->getMailKey(), $check_phid);
if ($expect_hash != $hash && $old_hash != $hash) {
return $this->setMessage("Invalid mail hash!")->save();
}
if ($receiver instanceof ManiphestTask) {
$editor = new ManiphestTransactionEditor();
$handler = $editor->buildReplyHandler($receiver);
} else if ($receiver instanceof DifferentialRevision) {
$handler = DifferentialMail::newReplyHandlerForRevision($receiver);
} else if ($receiver instanceof PhabricatorRepositoryCommit) {
$handler = PhabricatorAuditCommentEditor::newReplyHandlerForCommit(
$receiver);
}
$handler->setActor($user);
$handler->receiveEmail($this);
$this->setMessage('OK');
return $this->save();
}
public function getCleanTextBody() {
$body = idx($this->bodies, 'text');
$parser = new PhabricatorMetaMTAEmailBodyParser();
return $parser->stripTextBody($body);
}
+ public function getRawTextBody() {
+ return idx($this->bodies, 'text');
+ }
+
public static function loadReceiverObject($receiver_name) {
if (!$receiver_name) {
return null;
}
$receiver_type = $receiver_name[0];
$receiver_id = substr($receiver_name, 1);
$class_obj = null;
switch ($receiver_type) {
case 'T':
$class_obj = new ManiphestTask();
break;
case 'D':
$class_obj = new DifferentialRevision();
break;
case 'C':
$class_obj = new PhabricatorRepositoryCommit();
break;
default:
return null;
}
return $class_obj->load($receiver_id);
}
public static function computeMailHash($mail_key, $phid) {
$global_mail_key = PhabricatorEnv::getEnvConfig('phabricator.mail-key');
$hash = PhabricatorHash::digest($mail_key.$global_mail_key.$phid);
return substr($hash, 0, 16);
}
public static function computeOldMailHash($mail_key, $phid) {
// TODO: Remove this method entirely in a couple of months. We've moved from
// plain sha1 to sha1+hmac to make the codebase more auditable for good uses
// of hash functions, but still accept the old hashes on email replies to
// avoid breaking things. Once we've been sending only hmac hashes for a
// while, remove this and start rejecting old hashes. See T547.
$global_mail_key = PhabricatorEnv::getEnvConfig('phabricator.mail-key');
$hash = sha1($mail_key.$global_mail_key.$phid);
return substr($hash, 0, 16);
}
/**
* Strip an email address down to the actual user@domain.tld part if
* necessary, since sometimes it will have formatting like
* '"Abraham Lincoln" <alincoln@logcab.in>'.
*/
private function getRawEmailAddress($address) {
$matches = null;
$ok = preg_match('/<(.*)>/', $address, $matches);
if ($ok) {
$address = $matches[1];
}
return $address;
}
private function lookupPublicUser() {
$from = idx($this->headers, 'from');
$from = $this->getRawEmailAddress($from);
$user = PhabricatorUser::loadOneWithEmailAddress($from);
// If Phabricator is configured to allow "Reply-To" authentication, try
// the "Reply-To" address if we failed to match the "From" address.
$config_key = 'metamta.insecure-auth-with-reply-to';
$allow_reply_to = PhabricatorEnv::getEnvConfig($config_key);
if (!$user && $allow_reply_to) {
$reply_to = idx($this->headers, 'reply-to');
$reply_to = $this->getRawEmailAddress($reply_to);
if ($reply_to) {
$user = PhabricatorUser::loadOneWithEmailAddress($reply_to);
}
}
return $user;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Dec 3, 7:16 AM (8 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
433205
Default Alt Text
(31 KB)

Event Timeline