From c40ccb5aa90537ccfd0afac24b2685fbc19da31c 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 08/10] 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.27               |  2 ++
 includes/parser/Parser.php       | 11 ++++-------
 includes/parser/ParserOutput.php |  4 ++++
 3 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/RELEASE-NOTES-1.27 b/RELEASE-NOTES-1.27
index ff34d4d..b2ce3a5 100644
--- a/RELEASE-NOTES-1.27
+++ b/RELEASE-NOTES-1.27
@@ -36,6 +36,8 @@ was released.
   declaration.
 * (T161453) SECURITY: LocalisationCache will no longer use the temporary directory
   in it's fallback chain when trying to work out where to write the cache.
+* (T48143) SECURITY: Spam blacklist ineffective on encoded URLs inside file inclusion
+  syntax's link parameter.
 
 == MediaWiki 1.27.1 ==
 
diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php
index 178d7fd..3adeb6c 100644
--- a/includes/parser/Parser.php
+++ b/includes/parser/Parser.php
@@ -1538,9 +1538,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::normalizeLinkUrl( $url );
-			$this->mOutput->addExternalLink( $pasteurized );
+			$this->mOutput->addExternalLink( $url );
 		}
 		return $text . $trail;
 	}
@@ -1836,10 +1834,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::normalizeLinkUrl( $url );
-			$this->mOutput->addExternalLink( $pasteurized );
+			$this->mOutput->addExternalLink( $url );
 		}
 
 		return $s;
@@ -5445,9 +5440,11 @@ class Parser {
 							// check to see if link matches an absolute url, if not then it must be a wiki link.
 							if ( preg_match( "/^($prots)$addr$chars*$/u", $linkValue ) ) {
 								$link = $linkValue;
+								$this->mOutput->addExternalLink( $link );
 							} else {
 								$localLinkTitle = Title::newFromText( $linkValue );
 								if ( $localLinkTitle !== null ) {
+									$this->mOutput->addLink( $localLinkTitle );
 									$link = $localLinkTitle->getLinkURL();
 								}
 							}
diff --git a/includes/parser/ParserOutput.php b/includes/parser/ParserOutput.php
index 6c7ad4e..68305c5 100644
--- a/includes/parser/ParserOutput.php
+++ b/includes/parser/ParserOutput.php
@@ -509,6 +509,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

