From 7868ab3754fad13714640451d664d5bc71b7a02f Mon Sep 17 00:00:00 2001 From: Andre Klapper Date: Sat, 19 Aug 2023 20:18:45 +0200 Subject: [PATCH] Make InterpreterBlockRule regex only match on valid interpreter names Summary: With this patch, the underlying exception described in T15372#8537 still remains. However, with this patch, the bug is more contained as it is not triggered when not calling an interpreter (`cowsay`, `figlet`), so Phorge does not crash rendering `noValidInterpreter {{{foo}}} bar` lines but renders them as is (for whatever reasons such lines may exist). See T15372 Test Plan: Enter strings into a comment: * `invalid {{{saysay}}} foo` now renders as plain text instead of crashing * `invalid (invalid) {{{saysay}}} foo` now renders as plain text instead of crashing * `cowsay (invalid) {{{saysay}}} foo` will still crash as before Reviewers: O1 Blessed Committers, valerio.bozzolan Reviewed By: O1 Blessed Committers, valerio.bozzolan Subscribers: tobiaswiese, valerio.bozzolan, Matthew, Cigaryno Differential Revision: https://we.phorge.it/D25415 --- .../PhutilRemarkupInterpreterBlockRule.php | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/infrastructure/markup/blockrule/PhutilRemarkupInterpreterBlockRule.php b/src/infrastructure/markup/blockrule/PhutilRemarkupInterpreterBlockRule.php index a54e6b8b13..5585ddf541 100644 --- a/src/infrastructure/markup/blockrule/PhutilRemarkupInterpreterBlockRule.php +++ b/src/infrastructure/markup/blockrule/PhutilRemarkupInterpreterBlockRule.php @@ -2,13 +2,35 @@ final class PhutilRemarkupInterpreterBlockRule extends PhutilRemarkupBlockRule { - const START_BLOCK_PATTERN = '/^([\w]+)\s*(?:\(([^)]+)\)\s*)?{{{/'; + /** + * Second part of the regex to find stuff like: + * interpreterName {{{ stuff }}} + * interpreterName (options) {{{ stuff }}} + * You have found the kernel of cowsay and figlet. + */ const END_BLOCK_PATTERN = '/}}}\s*$/'; + /** + * Constructs the first part of the regex to find stuff like: + * interpreterName {{{ stuff }}} + * interpreterName (options) {{{ stuff }}} + * The exact regex is constructed from the available interpreters. + * @return string First part of interpreters regex + */ + private function getStartBlockPattern() { + $interpreters = id(new PhutilClassMapQuery()) + ->setAncestorClass('PhutilRemarkupBlockInterpreter') + ->execute(); + $interpreters_regex = mpull($interpreters, 'getInterpreterName'); + $interpreters_regex = array_map('preg_quote', $interpreters_regex); + $interpreters_regex = implode('|', $interpreters_regex); + return "/^($interpreters_regex)\s*(?:\(([^)]+)\)\s*)?{{{/"; + } + public function getMatchingLineCount(array $lines, $cursor) { $num_lines = 0; - if (preg_match(self::START_BLOCK_PATTERN, $lines[$cursor])) { + if (preg_match(self::getStartBlockPattern(), $lines[$cursor])) { $num_lines++; while (isset($lines[$cursor])) { @@ -33,7 +55,7 @@ final class PhutilRemarkupInterpreterBlockRule extends PhutilRemarkupBlockRule { } $matches = null; - preg_match(self::START_BLOCK_PATTERN, head($lines), $matches); + preg_match(self::getStartBlockPattern(), head($lines), $matches); $argv = array(); if (isset($matches[2])) { @@ -49,7 +71,7 @@ final class PhutilRemarkupInterpreterBlockRule extends PhutilRemarkupBlockRule { } $lines[$first_key] = preg_replace( - self::START_BLOCK_PATTERN, + self::getStartBlockPattern(), '', $lines[$first_key]); $lines[$last_key] = preg_replace(