From 9627c84a399a5b3e4a9165557b633d0ab74d0c85 Mon Sep 17 00:00:00 2001
From: Brian Wolff <bawolff+wn@gmail.com>
Date: Thu, 10 Mar 2016 20:08:06 -0500
Subject: [PATCH 6/8] SECURITY: Always normalize link url before adding to
 ParserOutput

Move link normalization directly into addExternalLink() method,
since you always need to do it - having it separate is just
inviting people to forget to normalize a link.

Additionally, links weren't properly registered for <gallery>.
This was somewhat unnoticed, as the call to recursiveTagParse()
would register free links, but it wouldn't work for example with
protocol relative links.

Issue originally reported by MZMcBride.

Bug: T48143
Change-Id: I557fb3b433ef9d618097b6ba4eacc6bada250ca2
---
 RELEASE-NOTES-1.23               |  2 ++
 includes/parser/Parser.php       | 13 +++++--------
 includes/parser/ParserOutput.php |  4 ++++
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/RELEASE-NOTES-1.23 b/RELEASE-NOTES-1.23
index db03d7e..b0bf4c2 100644
--- a/RELEASE-NOTES-1.23
+++ b/RELEASE-NOTES-1.23
@@ -17,6 +17,8 @@ This is not a release yet!
 * (T156184) SECURITY: Escape content model/format url parameter in message.
 * (T151735) SECURITY: SVG filter evasion using default attribute values in DTD
   declaration.
+* (T48143) SECURITY: Spam blacklist ineffective on encoded URLs inside file inclusion
+  syntax's link parameter.
 
 == MediaWiki 1.23.15 ==
 
diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php
index f6cd888..2cdb6de 100644
--- a/includes/parser/Parser.php
+++ b/includes/parser/Parser.php
@@ -1374,9 +1374,7 @@ class Parser {
 				true, 'free',
 				$this->getExternalLinkAttribs( $url ) );
 			# Register it in the output object...
-			# Replace unnecessary URL escape codes with their equivalent characters
-			$pasteurized = self::replaceUnusualEscapes( $url );
-			$this->mOutput->addExternalLink( $pasteurized );
+			$this->mOutput->addExternalLink( $url );
 		}
 		wfProfileOut( __METHOD__ );
 		return $text . $trail;
@@ -1680,10 +1678,7 @@ class Parser {
 				$this->getExternalLinkAttribs( $url ) ) . $dtrail . $trail;
 
 			# Register link in the output object.
-			# Replace unnecessary URL escape codes with the referenced character
-			# This prevents spammers from hiding links from the filters
-			$pasteurized = self::replaceUnusualEscapes( $url );
-			$this->mOutput->addExternalLink( $pasteurized );
+			$this->mOutput->addExternalLink( $url );
 		}
 
 		wfProfileOut( __METHOD__ );
@@ -5214,10 +5209,12 @@ class Parser {
 							//check to see if link matches an absolute url, if not then it must be a wiki link.
 							if ( preg_match( "/^($prots)$chars+$/u", $linkValue ) ) {
 								$link = $linkValue;
+								$this->mOutput->addExternalLink( $link );
 							} else {
 								$localLinkTitle = Title::newFromText( $linkValue );
 								if ( $localLinkTitle !== null ) {
-									$link = $localLinkTitle->getLocalURL();
+									$this->mOutput->addLink( $localLinkTitle );
+									$link = $localLinkTitle->getLinkURL();
 								}
 							}
 							break;
diff --git a/includes/parser/ParserOutput.php b/includes/parser/ParserOutput.php
index 054ee0d..90891da 100644
--- a/includes/parser/ParserOutput.php
+++ b/includes/parser/ParserOutput.php
@@ -201,6 +201,10 @@ class ParserOutput extends CacheTime {
 		# We don't register links pointing to our own server, unless... :-)
 		global $wgServer, $wgRegisterInternalExternals;
 
+		# Replace unnecessary URL escape codes with the referenced character
+		# This prevents spammers from hiding links from the filters
+		$url = parser::normalizeLinkUrl( $url );
+
 		$registerExternalLink = true;
 		if ( !$wgRegisterInternalExternals ) {
 			$registerExternalLink = !self::isLinkInternal( $wgServer, $url );
-- 
2.9.3

