From e67a6060e098572b6bc18cae07ee04913a30bfa3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20Mudr=C3=A1k?= Date: Tue, 19 May 2020 23:01:16 +0200 Subject: [PATCH] MDL-68738 wiki: Prevent URLs inside links from turning into another link There was a problem with wiki pages in the HTML markup syntax. If they contain a link and the link text has a URL in it, that URL was converted into another link. But it was not correctly nested and it caused additional troubles with filters (particularly the multimedia filter if the URL was a video such as on youtube). The solution here is similar to what we do in filters. We protect the whole explicit link so that its content is not further parsed. That prevents the inner URL to be converted into another link and the explicit link has the full control. --- mod/wiki/parser/markups/html.php | 9 ++++ mod/wiki/tests/wikiparser_test.php | 86 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/mod/wiki/parser/markups/html.php b/mod/wiki/parser/markups/html.php index fc1545d931e..ad12c34b454 100644 --- a/mod/wiki/parser/markups/html.php +++ b/mod/wiki/parser/markups/html.php @@ -46,6 +46,15 @@ class html_parser extends nwiki_parser { parent::before_parsing(); $this->minheaderlevel = $this->find_min_header_level($this->string); + + // Protect all explicit links from further wiki parsing. The link text may contain another URL which would get + // converted into another link via {@see nwiki_parser::$tagrules} 'url' element. + if (preg_match_all('/]+?>(.*?)<\/a>/is', $this->string, $matches)) { + foreach (array_unique($matches[0]) as $match) { + $this->string = str_replace($match, $this->protect($match), $this->string); + } + } + $this->rules($this->string); } diff --git a/mod/wiki/tests/wikiparser_test.php b/mod/wiki/tests/wikiparser_test.php index 909c2c17e39..003eff0f52f 100644 --- a/mod/wiki/tests/wikiparser_test.php +++ b/mod/wiki/tests/wikiparser_test.php @@ -39,6 +39,92 @@ require_once($CFG->dirroot . '/mod/wiki/parser/parser.php'); class mod_wiki_wikiparser_test extends basic_testcase { + /** + * URL inside the clickable text of some link should not be turned into a new link via the url_tag_rule. + * + * @dataProvider urls_inside_link_text_provider + * @param string $markup Markup of the Wiki page the text is part of. + * @param string $input The input text. + * @param string $output The expected output HTML as a result of the parsed input text. + */ + public function test_urls_inside_link_text(string $markup, string $input, string $output) { + + $parsingresult = wiki_parser_proxy::parse($input, $markup, [ + 'link_callback' => '/mod/wiki/locallib.php:wiki_parser_link', + 'link_callback_args' => ['swid' => 1], + ]); + + $this->assertContains($output, $parsingresult['parsed_text']); + } + + /** + * Provides data sets for {@see self::test_urls_inside_link_text()}. + * + * @return array + */ + public function urls_inside_link_text_provider() { + return [ + 'creole implicit link' => [ + 'markup' => 'creole', + 'input' => 'Visit https://site.url for more information.', + 'output' => 'Visit https://site.url for more information.', + ], + 'creole explicit link' => [ + 'markup' => 'creole', + 'input' => 'Visit [[https://site.url]] for more information.', + 'output' => 'Visit https://site.url for more information.', + ], + 'creole explicit link with text' => [ + 'markup' => 'creole', + 'input' => 'Visit [[https://site.url|http://www.site.url]] for more information.', + 'output' => 'Visit http://www.site.url for more information.', + ], + 'nwiki implicit link' => [ + 'markup' => 'nwiki', + 'input' => 'Visit https://site.url for more information.', + 'output' => 'Visit https://site.url for more information.', + ], + 'nwiki explicit link' => [ + 'markup' => 'nwiki', + 'input' => 'Visit [https://site.url] for more information.', + 'output' => 'Visit https://site.url for more information.', + ], + 'nwiki explicit link with space separated text' => [ + 'markup' => 'nwiki', + 'input' => 'Visit [https://site.url http://www.site.url] for more information.', + 'output' => 'Visit http://www.site.url for more information.', + ], + 'nwiki explicit link with pipe separated text' => [ + 'markup' => 'nwiki', + 'input' => 'Visit [https://site.url|http://www.site.url] for more information.', + 'output' => 'Visit http://www.site.url for more information.', + ], + 'html implicit link' => [ + 'markup' => 'html', + 'input' => 'Visit https://site.url for more information.', + 'output' => 'Visit https://site.url for more information.', + ], + 'html explicit link with text' => [ + 'markup' => 'html', + 'input' => 'Visit http://www.site.url for more information.', + 'output' => 'Visit http://www.site.url for more information.', + ], + 'html wiki link to non-existing page' => [ + 'markup' => 'html', + 'input' => 'Visit [[Another page]] for more information.', + 'output' => 'Visit ' . + 'Another page for more information.', + ], + 'html wiki link inside an explicit link' => [ + // The explicit href URL takes precedence here, the [[...]] is not turned into a wiki link. + 'markup' => 'html', + 'input' => 'Visit [[Another page]] for more information.', + 'output' => 'Visit [[Another page]] for more information.', + ], + ]; + } + function testCreoleMarkup() { $this->assertTestFiles('creole'); } -- 2.11.4.GIT