From 1667acfa5d7148b7e465649ddbd17680d0911a66 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 25 Nov 2019 15:01:45 -0800 Subject: [PATCH 1/4] Implement "PolicyInterface" on "UserEmail" so "EmailQuery" can load them properly Summary: See PHI1558. Ref T11860. Ref T13444. I partly implemented PHIDs for "UserEmail" objects, but they can't load on their own so you can't directly `bin/remove destroy` them yet. Allow them to actually load by implementing "PolicyInterface". Addresses are viewable and editable by the associated user, unless they are a bot/list address, in which case they are viewable and editable by administrators (in preparation for T11860). This has no real impact on anything today. Test Plan: - Used `bin/remove destroy ` to destroy an individual email address. - Before: error while loading the object by PHID in the query policy layer. - After: clean load and destroy. Maniphest Tasks: T13444, T11860 Differential Revision: https://secure.phabricator.com/D20927 --- src/__phutil_library_map__.php | 1 + .../PhabricatorPeopleUserEmailPHIDType.php | 6 +++ .../query/PhabricatorPeopleUserEmailQuery.php | 26 +++++++++++++ .../people/storage/PhabricatorUserEmail.php | 39 ++++++++++++++++++- 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index f26f36d52e..174c0e4876 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -11690,6 +11690,7 @@ phutil_register_library_map(array( 'PhabricatorUserEmail' => array( 'PhabricatorUserDAO', 'PhabricatorDestructibleInterface', + 'PhabricatorPolicyInterface', ), 'PhabricatorUserEmailTestCase' => 'PhabricatorTestCase', 'PhabricatorUserEmpowerTransaction' => 'PhabricatorUserTransactionType', diff --git a/src/applications/people/phid/PhabricatorPeopleUserEmailPHIDType.php b/src/applications/people/phid/PhabricatorPeopleUserEmailPHIDType.php index 0aadc149f6..e0f0478033 100644 --- a/src/applications/people/phid/PhabricatorPeopleUserEmailPHIDType.php +++ b/src/applications/people/phid/PhabricatorPeopleUserEmailPHIDType.php @@ -29,6 +29,12 @@ final class PhabricatorPeopleUserEmailPHIDType PhabricatorHandleQuery $query, array $handles, array $objects) { + + foreach ($handles as $phid => $handle) { + $email = $objects[$phid]; + $handle->setName($email->getAddress()); + } + return null; } diff --git a/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php b/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php index f0330f34f9..6e2627a96d 100644 --- a/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php +++ b/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php @@ -48,6 +48,32 @@ final class PhabricatorPeopleUserEmailQuery return $where; } + protected function willLoadPage(array $page) { + + $user_phids = mpull($page, 'getUserPHID'); + + $users = id(new PhabricatorPeopleQuery()) + ->setViewer($this->getViewer()) + ->setParentQuery($this) + ->withPHIDs($user_phids) + ->execute(); + $users = mpull($users, null, 'getPHID'); + + foreach ($page as $key => $address) { + $user = idx($users, $address->getUserPHID()); + + if (!$user) { + unset($page[$key]); + $this->didRejectResult($address); + continue; + } + + $address->attachUser($user); + } + + return $page; + } + public function getQueryApplicationClass() { return 'PhabricatorPeopleApplication'; } diff --git a/src/applications/people/storage/PhabricatorUserEmail.php b/src/applications/people/storage/PhabricatorUserEmail.php index cf2c61dc03..4e43b2fb41 100644 --- a/src/applications/people/storage/PhabricatorUserEmail.php +++ b/src/applications/people/storage/PhabricatorUserEmail.php @@ -6,7 +6,9 @@ */ final class PhabricatorUserEmail extends PhabricatorUserDAO - implements PhabricatorDestructibleInterface { + implements + PhabricatorDestructibleInterface, + PhabricatorPolicyInterface { protected $userPHID; protected $address; @@ -14,6 +16,8 @@ final class PhabricatorUserEmail protected $isPrimary; protected $verificationCode; + private $user = self::ATTACHABLE; + const MAX_ADDRESS_LENGTH = 128; protected function getConfiguration() { @@ -52,6 +56,15 @@ final class PhabricatorUserEmail return parent::save(); } + public function attachUser(PhabricatorUser $user) { + $this->user = $user; + return $this; + } + + public function getUser() { + return $this->assertAttached($this->user); + } + /* -( Domain Restrictions )------------------------------------------------ */ @@ -287,4 +300,28 @@ final class PhabricatorUserEmail $this->delete(); } + +/* -( PhabricatorPolicyInterface )----------------------------------------- */ + + public function getCapabilities() { + return array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + ); + } + + public function getPolicy($capability) { + $user = $this->getUser(); + + if ($this->getIsSystemAgent() || $this->getIsMailingList()) { + return PhabricatorPolicies::POLICY_ADMIN; + } + + return $user->getPHID(); + } + + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + return false; + } + } From 33c534f9b74f5aa8c9491c875292ca31a4bdc84f Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 25 Nov 2019 14:34:32 -0800 Subject: [PATCH 2/4] Extend Config to full-width Summary: Ref T13362. Some applications moved to fixed-width a while ago but I was generally unsatisfied with where they ended up and have been pushing them back to full-width. Push Config back to full-width. Some of the subpages end up a little weird, but this provides more space to work with to make some improvements, like makign `maniphest.statuses` more legible in the UI> Test Plan: Grepped for `setFixed(`, updated each page in `/config/`. Browsed each controller, saw workable full-width UIs. Maniphest Tasks: T13362 Differential Revision: https://secure.phabricator.com/D20925 --- .../controller/PhabricatorConfigAllController.php | 5 ++--- .../PhabricatorConfigApplicationController.php | 5 ++--- .../controller/PhabricatorConfigCacheController.php | 5 ++--- .../PhabricatorConfigClusterDatabasesController.php | 5 ++--- ...abricatorConfigClusterNotificationsController.php | 5 ++--- ...habricatorConfigClusterRepositoriesController.php | 12 ++++++------ .../PhabricatorConfigClusterSearchController.php | 5 ++--- .../controller/PhabricatorConfigController.php | 2 -- .../PhabricatorConfigDatabaseIssueController.php | 5 ++--- .../PhabricatorConfigDatabaseStatusController.php | 5 ++--- .../controller/PhabricatorConfigEditController.php | 6 +++--- .../controller/PhabricatorConfigGroupController.php | 5 ++--- .../PhabricatorConfigHistoryController.php | 5 ++--- .../PhabricatorConfigIssueListController.php | 5 ++--- .../PhabricatorConfigIssueViewController.php | 5 ++--- .../controller/PhabricatorConfigListController.php | 5 ++--- .../controller/PhabricatorConfigModuleController.php | 5 ++--- .../PhabricatorConfigVersionController.php | 6 ++---- 18 files changed, 39 insertions(+), 57 deletions(-) diff --git a/src/applications/config/controller/PhabricatorConfigAllController.php b/src/applications/config/controller/PhabricatorConfigAllController.php index 3a19eff006..7452b29e21 100644 --- a/src/applications/config/controller/PhabricatorConfigAllController.php +++ b/src/applications/config/controller/PhabricatorConfigAllController.php @@ -64,13 +64,12 @@ final class PhabricatorConfigAllController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($view); + ->setFooter($view); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigApplicationController.php b/src/applications/config/controller/PhabricatorConfigApplicationController.php index b4f60982e7..a6b8cd38c6 100644 --- a/src/applications/config/controller/PhabricatorConfigApplicationController.php +++ b/src/applications/config/controller/PhabricatorConfigApplicationController.php @@ -18,9 +18,7 @@ final class PhabricatorConfigApplicationController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($apps_list); + ->setFooter($apps_list); $crumbs = $this->buildApplicationCrumbs() ->addTextCrumb($title) @@ -29,6 +27,7 @@ final class PhabricatorConfigApplicationController return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigCacheController.php b/src/applications/config/controller/PhabricatorConfigCacheController.php index a23ab1f9c1..36642657c9 100644 --- a/src/applications/config/controller/PhabricatorConfigCacheController.php +++ b/src/applications/config/controller/PhabricatorConfigCacheController.php @@ -33,13 +33,12 @@ final class PhabricatorConfigCacheController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($page); + ->setFooter($page); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php b/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php index 43e5a15b9d..417fa9d3a1 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php @@ -26,13 +26,12 @@ final class PhabricatorConfigClusterDatabasesController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($status); + ->setFooter($status); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php b/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php index 443b51a903..e9f64d411a 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php @@ -28,13 +28,12 @@ final class PhabricatorConfigClusterNotificationsController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($status); + ->setFooter($status); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php b/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php index 471c4cedf0..eb83a28a2a 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php @@ -32,16 +32,16 @@ final class PhabricatorConfigClusterRepositoriesController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn(array( - $repo_status, - $repo_errors, - )); + ->setFooter( + array( + $repo_status, + $repo_errors, + )); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigClusterSearchController.php b/src/applications/config/controller/PhabricatorConfigClusterSearchController.php index cd00ef73a0..55caeb1cad 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterSearchController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterSearchController.php @@ -26,13 +26,12 @@ final class PhabricatorConfigClusterSearchController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($search_status); + ->setFooter($search_status); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigController.php b/src/applications/config/controller/PhabricatorConfigController.php index ad5ea6cd27..1b6a5af8b5 100644 --- a/src/applications/config/controller/PhabricatorConfigController.php +++ b/src/applications/config/controller/PhabricatorConfigController.php @@ -7,8 +7,6 @@ abstract class PhabricatorConfigController extends PhabricatorController { } public function buildSideNavView($filter = null, $for_app = false) { - - $guide_href = new PhutilURI('/guides/'); $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php b/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php index 708a708043..fa6bcab5e6 100644 --- a/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php +++ b/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php @@ -167,13 +167,12 @@ final class PhabricatorConfigDatabaseIssueController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($view); + ->setFooter($view); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php b/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php index 760317ae80..6831a048d5 100644 --- a/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php +++ b/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php @@ -142,13 +142,12 @@ final class PhabricatorConfigDatabaseStatusController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($body); + ->setFooter($body); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigEditController.php b/src/applications/config/controller/PhabricatorConfigEditController.php index 224705e181..381b54e046 100644 --- a/src/applications/config/controller/PhabricatorConfigEditController.php +++ b/src/applications/config/controller/PhabricatorConfigEditController.php @@ -237,9 +237,8 @@ final class PhabricatorConfigEditController $view = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn(array( + ->setFooter( + array( $error_view, $form_box, $status_items, @@ -250,6 +249,7 @@ final class PhabricatorConfigEditController return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($view); } diff --git a/src/applications/config/controller/PhabricatorConfigGroupController.php b/src/applications/config/controller/PhabricatorConfigGroupController.php index 7a3f77dfea..f981c1c1a1 100644 --- a/src/applications/config/controller/PhabricatorConfigGroupController.php +++ b/src/applications/config/controller/PhabricatorConfigGroupController.php @@ -36,13 +36,12 @@ final class PhabricatorConfigGroupController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($view); + ->setFooter($view); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigHistoryController.php b/src/applications/config/controller/PhabricatorConfigHistoryController.php index 9157ecb8bb..495102b6a2 100644 --- a/src/applications/config/controller/PhabricatorConfigHistoryController.php +++ b/src/applications/config/controller/PhabricatorConfigHistoryController.php @@ -36,13 +36,12 @@ final class PhabricatorConfigHistoryController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($timeline); + ->setFooter($timeline); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigIssueListController.php b/src/applications/config/controller/PhabricatorConfigIssueListController.php index 0ca94abe04..6518ccec97 100644 --- a/src/applications/config/controller/PhabricatorConfigIssueListController.php +++ b/src/applications/config/controller/PhabricatorConfigIssueListController.php @@ -59,13 +59,12 @@ final class PhabricatorConfigIssueListController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($issue_list); + ->setFooter($issue_list); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigIssueViewController.php b/src/applications/config/controller/PhabricatorConfigIssueViewController.php index 29c9078413..2967169e38 100644 --- a/src/applications/config/controller/PhabricatorConfigIssueViewController.php +++ b/src/applications/config/controller/PhabricatorConfigIssueViewController.php @@ -47,13 +47,12 @@ final class PhabricatorConfigIssueViewController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($content); + ->setFooter($content); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigListController.php b/src/applications/config/controller/PhabricatorConfigListController.php index 1a136ea416..38a0afc328 100644 --- a/src/applications/config/controller/PhabricatorConfigListController.php +++ b/src/applications/config/controller/PhabricatorConfigListController.php @@ -22,13 +22,12 @@ final class PhabricatorConfigListController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($core_list); + ->setFooter($core_list); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigModuleController.php b/src/applications/config/controller/PhabricatorConfigModuleController.php index 63cc5b3843..fe919c57e4 100644 --- a/src/applications/config/controller/PhabricatorConfigModuleController.php +++ b/src/applications/config/controller/PhabricatorConfigModuleController.php @@ -28,13 +28,12 @@ final class PhabricatorConfigModuleController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($view); + ->setFooter($view); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); } diff --git a/src/applications/config/controller/PhabricatorConfigVersionController.php b/src/applications/config/controller/PhabricatorConfigVersionController.php index a9571a1f85..153d363062 100644 --- a/src/applications/config/controller/PhabricatorConfigVersionController.php +++ b/src/applications/config/controller/PhabricatorConfigVersionController.php @@ -23,15 +23,13 @@ final class PhabricatorConfigVersionController $content = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) - ->setFixed(true) - ->setMainColumn($view); + ->setFooter($view); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($content); - } public function renderModuleStatus($viewer) { From 4cd333b33fb1495c2b5a0b2ea4123110d1533249 Mon Sep 17 00:00:00 2001 From: Arturas Moskvinas Date: Mon, 9 Dec 2019 13:02:14 +0200 Subject: [PATCH 3/4] Use same method to get object URI as used in DifferentialTransactionEditor and PhabricatorApplicationTransactionEditor Summary: Maniphest object has `getURI` method, let's use it Test Plan: Create event in task - URI generated as expected in email notification Reviewers: epriestley, Pawka, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D20935 --- .../maniphest/editor/ManiphestTransactionEditor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/maniphest/editor/ManiphestTransactionEditor.php b/src/applications/maniphest/editor/ManiphestTransactionEditor.php index ed98ad8ad8..01fc0af83d 100644 --- a/src/applications/maniphest/editor/ManiphestTransactionEditor.php +++ b/src/applications/maniphest/editor/ManiphestTransactionEditor.php @@ -226,7 +226,7 @@ final class ManiphestTransactionEditor $body->addLinkSection( pht('TASK DETAIL'), - PhabricatorEnv::getProductionURI('/T'.$object->getID())); + $this->getObjectLinkButtonURIForMail($object)); $board_phids = array(); From 54bcbdaba94a3573e128c6498816dbfa41d3a9cb Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 13 Dec 2019 10:31:44 -0800 Subject: [PATCH 4/4] Fix an XSS issue with certain high-priority remarkup rules embedded inside lower-priority link rules Summary: See . The link rules don't test that their parameters are flat text before using them in unsafe contexts. Since almost all rules are lower-priority than these link rules, this behavior isn't obvious. However, two rules have broadly higher priority (monospaced text, and one variation of link rules has higher priority than the other), and the latter can be used to perform an XSS attack with input in the general form `()[ [[ ... | ... ]] ]` so that the inner link rule is evaluated first, then the outer link rule uses non-flat text in an unsafe way. Test Plan: Tested examples in HackerOne report. A simple example of broken (but not unsafe) behavior is: ``` [[ `x` | `y` ]] ``` Differential Revision: https://secure.phabricator.com/D20937 --- .../markup/PhrictionRemarkupRule.php | 22 ++++++++++++++----- .../PhutilRemarkupDocumentLinkRule.php | 8 +++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/applications/phriction/markup/PhrictionRemarkupRule.php b/src/applications/phriction/markup/PhrictionRemarkupRule.php index d17de331e5..11994e0aa5 100644 --- a/src/applications/phriction/markup/PhrictionRemarkupRule.php +++ b/src/applications/phriction/markup/PhrictionRemarkupRule.php @@ -16,8 +16,23 @@ final class PhrictionRemarkupRule extends PhutilRemarkupRule { } public function markupDocumentLink(array $matches) { + $name = trim(idx($matches, 2, '')); + if (empty($matches[2])) { + $name = null; + } + + $path = trim($matches[1]); + + if (!$this->isFlatText($name)) { + return $matches[0]; + } + + if (!$this->isFlatText($path)) { + return $matches[0]; + } + // If the link contains an anchor, separate that off first. - $parts = explode('#', trim($matches[1]), 2); + $parts = explode('#', $path, 2); if (count($parts) == 2) { $link = $parts[0]; $anchor = $parts[1]; @@ -48,11 +63,6 @@ final class PhrictionRemarkupRule extends PhutilRemarkupRule { } } - $name = trim(idx($matches, 2, '')); - if (empty($matches[2])) { - $name = null; - } - // Link is now used for slug detection, so append a slash if one // is needed. $link = rtrim($link, '/').'/'; diff --git a/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php b/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php index a6effa00ac..2170d9ae5e 100644 --- a/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php +++ b/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php @@ -136,6 +136,14 @@ final class PhutilRemarkupDocumentLinkRule extends PhutilRemarkupRule { $uri = trim($matches[1]); $name = trim(idx($matches, 2)); + if (!$this->isFlatText($uri)) { + return $matches[0]; + } + + if (!$this->isFlatText($name)) { + return $matches[0]; + } + // If whatever is being linked to begins with "/" or "#", or has "://", // or is "mailto:" or "tel:", treat it as a URI instead of a wiki page. $is_uri = preg_match('@(^/)|(://)|(^#)|(^(?:mailto|tel):)@', $uri);