<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/">
  <channel rdf:about="http://blog.gmane.org/gmane.org.wikimedia.mediawiki.cvs">
    <title>gmane.org.wikimedia.mediawiki.cvs</title>
    <link>http://blog.gmane.org/gmane.org.wikimedia.mediawiki.cvs</link>
    <description/>
    <syn:updatePeriod>hourly</syn:updatePeriod>
    <syn:updateFrequency>1</syn:updateFrequency>
    <syn:updateBase>1901-01-01T00:00+00:00</syn:updateBase>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172172"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172171"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172170"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172169"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172168"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172167"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172166"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172165"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172164"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172163"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172162"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172161"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172160"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172159"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172158"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172157"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172156"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172155"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172154"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172153"/>
      </rdf:Seq>
    </items>
    <image rdf:resource="http://gmane.org/img/gmane-25t.png"/>
    <textinput rdf:resource=""/>
  </channel>
  <image rdf:about="http://gmane.org/img/gmane-25t.png">
    <title>Gmane</title>
    <url>http://gmane.org/img/gmane-25t.png</url>
    <link>http://gmane.org</link>
  </image>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172172">
    <title>[MediaWiki-commits] [Gerrit] Updating MobileFrontend to productiontip - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172172</link>
    <description>&lt;pre&gt;awjrichards has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/64856


Change subject: Updating MobileFrontend to production tip
......................................................................

Updating MobileFrontend to production tip

Change-Id: Idd3da6688736fa23d5c4d9cf31d18872712cd65e
---
M extensions/MobileFrontend
1 file changed, 0 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core refs/changes/56/64856/1

diff --git a/extensions/MobileFrontend b/extensions/MobileFrontend
index 05d3a18..8ee5fdf 160000
--- a/extensions/MobileFrontend
+++ b/extensions/MobileFrontend
-Subproject commit 05d3a1821cf77bda90f7bbab9eb6be7c5cdd9b22
+Subproject commit 8ee5fdf6954e2feaad42b35012e5230e92ad9bae

&lt;/pre&gt;</description>
    <dc:creator>awjrichards (Code Review</dc:creator>
    <dc:date>2013-05-21T20:51:05</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172171">
    <title>[MediaWiki-commits] [Gerrit] Updated release notes and versionnumber - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172171</link>
    <description>&lt;pre&gt;jenkins-bot has submitted this change and it was merged.

Change subject: Updated release notes and version number
......................................................................


Updated release notes and version number

Change-Id: I1fb122b2e946df330578474ace5c1da7e163f5b1
---
M RELEASE-NOTES-1.19
M includes/DefaultSettings.php
2 files changed, 9 insertions(+), 1 deletion(-)

Approvals:
  Krinkle: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/RELEASE-NOTES-1.19 b/RELEASE-NOTES-1.19
index a61c237..560ee3b 100644
--- a/RELEASE-NOTES-1.19
+++ b/RELEASE-NOTES-1.19
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -3,6 +3,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 Security reminder: MediaWiki does not require PHP's register_globals
 setting since version 1.2.0. If you have it on, turn it '''off''' if you can.
 
+== MediaWiki 1.19.7 ==
+
+This is a security and maintenance release of the MediaWiki 1.19 branch
+
+=== Changes since 1.19.6 ===
+* (bug 48306) SECURITY: Run file validation checks on  chunked uploads, and chunks
+  of upload, during the upload process.
+
 == MediaWiki 1.19.6 ==
 
 This is a security and maintenance release of the MediaWiki 1.19 branch
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index 6aa5c9e..84cc9c2 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -33,7 +33,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 /** &amp;lt; at &amp;gt;endcond */
 
 /** MediaWiki version number */
-$wgVersion = '1.19.6';
+$wgVersion = '1.19.7';
 
 /** Name of the site. It must be changed in LocalSettings.php */
 $wgSitename = 'MediaWiki';

&lt;/pre&gt;</description>
    <dc:creator>jenkins-bot (Code Review</dc:creator>
    <dc:date>2013-05-21T20:50:27</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172170">
    <title>[MediaWiki-commits] [Gerrit] Updated release notes and versionnumber - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172170</link>
    <description>&lt;pre&gt;jenkins-bot has submitted this change and it was merged.

Change subject: Updated release notes and version number
......................................................................


Updated release notes and version number

Change-Id: I630010e6371ac4ba9ea24e5f2f48e891d3e41c2f
---
M RELEASE-NOTES-1.20
M includes/DefaultSettings.php
2 files changed, 6 insertions(+), 3 deletions(-)

Approvals:
  CSteipp: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/RELEASE-NOTES-1.20 b/RELEASE-NOTES-1.20
index 2da9e35..d4f399a 100644
--- a/RELEASE-NOTES-1.20
+++ b/RELEASE-NOTES-1.20
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6,11 +6,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 == MediaWiki 1.20.6 ==
 
-This is a maintenance release of the MediaWiki 1.20 branch.
+This is a security and maintenance release of the MediaWiki 1.20 branch.
 
 === Changes since 1.20.5 ===
+* (bug 48306) SECURITY: Run file validation checks on chunked uploads, and chunks
+  of upload, during the upload process.
+* (bug 44327) mediawiki.user: Use session ID instead of 1-year cross-session cookies
 * (bug 47202) wikibits: FF2Fixes.css should not be loaded in Firefox 20.
-
+* (bug 31044) Make ResourceLoader behave in read-only mode
 
 == MediaWiki 1.20.5 ==
 
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index 6abc2b1..710605a 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -59,7 +59,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $wgConf = new SiteConfiguration;
 
 /** MediaWiki version number */
-$wgVersion = '1.20.5';
+$wgVersion = '1.20.6';
 
 /** Name of the site. It must be changed in LocalSettings.php */
 $wgSitename = 'MediaWiki';

&lt;/pre&gt;</description>
    <dc:creator>jenkins-bot (Code Review</dc:creator>
    <dc:date>2013-05-21T20:43:30</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172169">
    <title>[MediaWiki-commits] [Gerrit] SECURITY: Do checks on all uploadtypes - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172169</link>
    <description>&lt;pre&gt;jenkins-bot has submitted this change and it was merged.

Change subject: SECURITY: Do checks on all upload types
......................................................................


SECURITY: Do checks on all upload types

Also, verify file before stashing it

Based on change Ib2474cb778d53959a4f479e53d0392f916b18d83

Change-Id: I2b230af2f23c4303acdb695468608df19a88d16d
---
M includes/AutoLoader.php
M includes/api/ApiUpload.php
M includes/upload/UploadBase.php
M includes/upload/UploadFromChunks.php
M includes/upload/UploadFromStash.php
M includes/upload/UploadStash.php
6 files changed, 111 insertions(+), 30 deletions(-)

Approvals:
  CSteipp: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index 7611ed9..2bf134b 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -883,6 +883,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 # includes/upload
 'UploadBase' =&amp;gt; 'includes/upload/UploadBase.php',
+'UploadChunkVerificationException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadFromFile' =&amp;gt; 'includes/upload/UploadFromFile.php',
 'UploadFromChunks' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadFromStash' =&amp;gt; 'includes/upload/UploadFromStash.php',
diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php
index fdc1eff..922b89d 100644
--- a/includes/api/ApiUpload.php
+++ b/includes/api/ApiUpload.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -175,7 +175,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $chunkPath = $request-&amp;gt;getFileTempname( 'chunk' );
 $chunkSize = $request-&amp;gt;getUpload( 'chunk' )-&amp;gt;getSize();
 if ($this-&amp;gt;mParams['offset'] == 0) {
-$result['filekey'] = $this-&amp;gt;performStash();
+try {
+$result['filekey'] = $this-&amp;gt;performStash();
+} catch ( MWException $e ) {
+// FIXME: Error handling here is wrong/different from rest of this
+$this-&amp;gt;dieUsage( $e-&amp;gt;getMessage(), 'stashfailed' );
+}
 } else {
 $status = $this-&amp;gt;mUpload-&amp;gt;addChunk($chunkPath, $chunkSize,
 $this-&amp;gt;mParams['offset']);
diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php
index 3995519..5f09c04 100644
--- a/includes/upload/UploadBase.php
+++ b/includes/upload/UploadBase.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -301,6 +301,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 /**
  * Verify the mime type
  *
+ * &amp;lt; at &amp;gt;note Only checks that it is not an evil mime. The does it have
+ *  correct extension given its mime type check is in verifyFile.
  * &amp;lt; at &amp;gt;param $mime string representing the mime
  * &amp;lt; at &amp;gt;return mixed true if the file is verified, an array otherwise
  */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -311,11 +313,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 global $wgMimeTypeBlacklist;
 if ( $this-&amp;gt;checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
 return array( 'filetype-badmime', $mime );
-}
-
-# XXX: Missing extension will be caught by validateName() via getTitle()
-if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
-return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
 }
 
 # Check IE type
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -342,6 +339,56 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * &amp;lt; at &amp;gt;return mixed true of the file is verified, array otherwise.
  */
 protected function verifyFile() {
+global $wgVerifyMimeType;
+wfProfileIn( __METHOD__ );
+
+$status = $this-&amp;gt;verifyPartialFile();
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+if ( $wgVerifyMimeType ) {
+$this-&amp;gt;mFileProps = FSFile::getPropsFromPath( $this-&amp;gt;mTempPath, $this-&amp;gt;mFinalExtension );
+$mime = $this-&amp;gt;mFileProps['file-mime'];
+
+# XXX: Missing extension will be caught by validateName() via getTitle()
+if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
+wfProfileOut( __METHOD__ );
+return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
+}
+}
+
+$handler = MediaHandler::getHandler( $mime );
+if ( $handler ) {
+$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
+if ( !$handlerStatus-&amp;gt;isOK() ) {
+$errors = $handlerStatus-&amp;gt;getErrorsArray();
+wfProfileOut( __METHOD__ );
+return reset( $errors );
+}
+}
+
+wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+wfDebug( __METHOD__ . ": all clear; passing.\n" );
+wfProfileOut( __METHOD__ );
+return true;
+}
+
+/**
+ * A verification routine suitable for partial files
+ *
+ * Runs the blacklist checks, but not any checks that may
+ * assume the entire file is present.
+ *
+ * &amp;lt; at &amp;gt;return Mixed true for valid or array with error message key.
+ */
+protected function verifyPartialFile() {
 global $wgAllowJavaUploads, $wgDisableUploadScriptChecks;
 # get the title, even though we are doing nothing with it, because
 # we need to populate mFinalExtension
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -392,21 +439,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return array( 'uploadvirus', $virus );
 }
 
-$handler = MediaHandler::getHandler( $mime );
-if ( $handler ) {
-$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
-if ( !$handlerStatus-&amp;gt;isOK() ) {
-$errors = $handlerStatus-&amp;gt;getErrorsArray();
-return reset( $errors );
-}
-}
-
-wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
-if ( $status !== true ) {
-return $status;
-}
-
-wfDebug( __METHOD__ . ": all clear; passing.\n" );
 return true;
 }
 
diff --git a/includes/upload/UploadFromChunks.php b/includes/upload/UploadFromChunks.php
index ec83f7d..a76f03d 100644
--- a/includes/upload/UploadFromChunks.php
+++ b/includes/upload/UploadFromChunks.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -47,6 +47,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 // Stash file is the called on creating a new chunk session: 
 $this-&amp;gt;mChunkIndex = 0;
 $this-&amp;gt;mOffset = 0;
+
+$this-&amp;gt;verifyChunk();
 // Create a local stash target
 $this-&amp;gt;mLocalFile = parent::stashFile();
 // Update the initial file offset ( based on file size ) 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -105,9 +107,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if( !$status-&amp;gt;isOk() ){
 return $status; 
 }
+
+$this-&amp;gt;mTempPath = $tmpPath; // file system path
+$this-&amp;gt;mFileSize = filesize( $this-&amp;gt;mTempPath ); //Since this was set for the last chunk previously
+$ret = $this-&amp;gt;verifyUpload();
+if ( $ret['status'] !== UploadBase::OK ) {
+wfDebugLog( 'fileconcatenate', "Verification failed for chunked upload" );
+$status-&amp;gt;fatal( $this-&amp;gt;getVerificationErrorCode( $ret['status'] ) );
+return $status;
+}
+
 // Update the mTempPath and mLocalFile
 // ( for FileUpload or normal Stash to take over )  
-$this-&amp;gt;mTempPath = $tmpPath; // file system path
 $this-&amp;gt;mLocalFile = parent::stashFile();
 
 return $status;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -157,6 +168,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $preAppendOffset == $offset ) {
 // Update local chunk index for the current chunk   
 $this-&amp;gt;mChunkIndex++;
+try {
+# For some reason mTempPath is set to first part
+$oldTemp = $this-&amp;gt;mTempPath;
+$this-&amp;gt;mTempPath = $chunkPath;
+$this-&amp;gt;verifyChunk();
+$this-&amp;gt;mTempPath = $oldTemp;
+} catch ( UploadChunkVerificationException $e ) {
+return Status::newFatal( $e-&amp;gt;getMessage() );
+}
 $status = $this-&amp;gt;outputChunk( $chunkPath );
 if( $status-&amp;gt;isGood() ){
 // Update local offset: 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -270,7 +290,26 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 return $this-&amp;gt;mFileKey . '.' . $index ;
 }
+
+/**
+ * Verify that the chunk isn't really an evil html file
+ *
+ * &amp;lt; at &amp;gt;throws UploadChunkVerificationException
+ */
+private function verifyChunk() {
+// Rest mDesiredDestName here so we verify the name as if it were mFileKey
+$oldDesiredDestName = $this-&amp;gt;mDesiredDestName;
+$this-&amp;gt;mDesiredDestName = $this-&amp;gt;mFileKey;
+$this-&amp;gt;mTitle = false;
+$res = $this-&amp;gt;verifyPartialFile();
+$this-&amp;gt;mDesiredDestName = $oldDesiredDestName;
+$this-&amp;gt;mTitle = false;
+if( is_array( $res ) ) {
+throw new UploadChunkVerificationException( $res[0] );
+}
+}
 }
 
 class UploadChunkZeroLengthFileException extends MWException {};
 class UploadChunkFileException extends MWException {};
+class UploadChunkVerificationException extends MWException {};
diff --git a/includes/upload/UploadFromStash.php b/includes/upload/UploadFromStash.php
index f7589bd..014aa53 100644
--- a/includes/upload/UploadFromStash.php
+++ b/includes/upload/UploadFromStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -109,14 +109,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return $this-&amp;gt;mSourceType;
 }
 
-/**
- * File has been previously verified so no need to do so again.
- *
- * &amp;lt; at &amp;gt;return bool
+/*
+ * protected function verifyFile() inherited
  */
-protected function verifyFile() {
-return true;
-}
 
 /**
  * Stash the file.
diff --git a/includes/upload/UploadStash.php b/includes/upload/UploadStash.php
index ad153d2..73e3811 100644
--- a/includes/upload/UploadStash.php
+++ b/includes/upload/UploadStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -393,6 +393,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * uploads versus the desired filename. Maybe we can get that passed to us...
  */
 public static function getExtensionForPath( $path ) {
+global $wgFileBlacklist;
 // Does this have an extension?
 $n = strrpos( $path, '.' );
 $extension = null;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -412,7 +413,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 throw new UploadStashFileException( "extension is null" );
 }
 
-return File::normalizeExtension( $extension );
+$extension = File::normalizeExtension( $extension );
+if ( in_array( $extension, $wgFileBlacklist ) ) {
+// The file should already be checked for being evil.
+// However, if somehow we got here, we definitely
+// don't want to give it an extension of .php and
+// put it in a web accesible directory.
+return '';
+}
+return $extension;
 }
 
 /**

&lt;/pre&gt;</description>
    <dc:creator>jenkins-bot (Code Review</dc:creator>
    <dc:date>2013-05-21T20:38:25</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172168">
    <title>[MediaWiki-commits] [Gerrit] hide flickr upload if multiple uploadis disabled - change (mediawiki...UploadWizard)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172168</link>
    <description>&lt;pre&gt;Nischayn22 has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/64855


Change subject: hide flickr upload if multiple upload is disabled
......................................................................

hide flickr upload if multiple upload is disabled

Hides flickr upload button if enableMultipleFiles is false and one file is
already uploading.

Change-Id: Ifcf4c016be25be2edebc20b6d575de1a914e33b8
---
M resources/mw.UploadWizard.js
1 file changed, 1 insertion(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/UploadWizard refs/changes/55/64855/1

diff --git a/resources/mw.UploadWizard.js b/resources/mw.UploadWizard.js
index e6005d8..b61bb87 100644
--- a/resources/mw.UploadWizard.js
+++ b/resources/mw.UploadWizard.js
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -952,6 +952,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 _this.$addFile.hide();
 _this.$fileInput = this.$fileInput || $j( '.mwe-upwiz-file-input' );
 _this.$fileInput.hide();
+$j( '#mwe-upwiz-upload-ctrl-flickr-container, #mwe-upwiz-flickr-select-list-container' ).hide();
 }
 
 // add the styling to the filelist, so it has rounded corners and is visible and all.

&lt;/pre&gt;</description>
    <dc:creator>Nischayn22 (Code Review</dc:creator>
    <dc:date>2013-05-21T20:37:24</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172167">
    <title>[MediaWiki-commits] [Gerrit] SECURITY: Do checks on all uploadtypes - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172167</link>
    <description>&lt;pre&gt;jenkins-bot has submitted this change and it was merged.

Change subject: SECURITY: Do checks on all upload types
......................................................................


SECURITY: Do checks on all upload types

Also, verify file before stashing it

Change-Id: I5dd027acc994cf7308c9e4d85a61237d802ccee8
---
M includes/AutoLoader.php
M includes/api/ApiUpload.php
M includes/upload/UploadBase.php
M includes/upload/UploadFromChunks.php
M includes/upload/UploadFromStash.php
M includes/upload/UploadStash.php
6 files changed, 111 insertions(+), 33 deletions(-)

Approvals:
  CSteipp: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index 9bdfcd2..a8b2202 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -965,6 +965,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 'UnwatchedpagesPage' =&amp;gt; 'includes/specials/SpecialUnwatchedpages.php',
 'UploadChunkFileException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadChunkZeroLengthFileException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
+'UploadChunkVerificationException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadForm' =&amp;gt; 'includes/specials/SpecialUpload.php',
 'UploadSourceField' =&amp;gt; 'includes/specials/SpecialUpload.php',
 'UserrightsPage' =&amp;gt; 'includes/specials/SpecialUserrights.php',
diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php
index 3a9b5c5..e7a7849 100644
--- a/includes/api/ApiUpload.php
+++ b/includes/api/ApiUpload.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -187,7 +187,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $chunkPath = $request-&amp;gt;getFileTempname( 'chunk' );
 $chunkSize = $request-&amp;gt;getUpload( 'chunk' )-&amp;gt;getSize();
 if ($this-&amp;gt;mParams['offset'] == 0) {
-$result['filekey'] = $this-&amp;gt;performStash();
+try {
+$result['filekey'] = $this-&amp;gt;performStash();
+} catch ( MWException $e ) {
+// FIXME: Error handling here is wrong/different from rest of this
+$this-&amp;gt;dieUsage( $e-&amp;gt;getMessage(), 'stashfailed' );
+}
 } else {
 $status = $this-&amp;gt;mUpload-&amp;gt;addChunk($chunkPath, $chunkSize,
 $this-&amp;gt;mParams['offset']);
diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php
index 3a5733c..0848780 100644
--- a/includes/upload/UploadBase.php
+++ b/includes/upload/UploadBase.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -345,6 +345,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 /**
  * Verify the mime type
  *
+ * &amp;lt; at &amp;gt;note Only checks that it is not an evil mime. The does it have
+ *  correct extension given its mime type check is in verifyFile.
  * &amp;lt; at &amp;gt;param $mime string representing the mime
  * &amp;lt; at &amp;gt;return mixed true if the file is verified, an array otherwise
  */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -357,12 +359,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $this-&amp;gt;checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
 wfProfileOut( __METHOD__ );
 return array( 'filetype-badmime', $mime );
-}
-
-# XXX: Missing extension will be caught by validateName() via getTitle()
-if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
-wfProfileOut( __METHOD__ );
-return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
 }
 
 # Check IE type
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -391,6 +387,56 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * &amp;lt; at &amp;gt;return mixed true of the file is verified, array otherwise.
  */
 protected function verifyFile() {
+global $wgVerifyMimeType;
+wfProfileIn( __METHOD__ );
+
+$status = $this-&amp;gt;verifyPartialFile();
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+if ( $wgVerifyMimeType ) {
+$this-&amp;gt;mFileProps = FSFile::getPropsFromPath( $this-&amp;gt;mTempPath, $this-&amp;gt;mFinalExtension );
+$mime = $this-&amp;gt;mFileProps['file-mime'];
+
+# XXX: Missing extension will be caught by validateName() via getTitle()
+if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
+wfProfileOut( __METHOD__ );
+return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
+}
+}
+
+$handler = MediaHandler::getHandler( $mime );
+if ( $handler ) {
+$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
+if ( !$handlerStatus-&amp;gt;isOK() ) {
+$errors = $handlerStatus-&amp;gt;getErrorsArray();
+wfProfileOut( __METHOD__ );
+return reset( $errors );
+}
+}
+
+wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+wfDebug( __METHOD__ . ": all clear; passing.\n" );
+wfProfileOut( __METHOD__ );
+return true;
+}
+
+/**
+ * A verification routine suitable for partial files
+ *
+ * Runs the blacklist checks, but not any checks that may
+ * assume the entire file is present.
+ *
+ * &amp;lt; at &amp;gt;return Mixed true for valid or array with error message key.
+ */
+protected function verifyPartialFile() {
 global $wgAllowJavaUploads, $wgDisableUploadScriptChecks;
 wfProfileIn( __METHOD__ );
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -449,23 +495,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return array( 'uploadvirus', $virus );
 }
 
-$handler = MediaHandler::getHandler( $mime );
-if ( $handler ) {
-$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
-if ( !$handlerStatus-&amp;gt;isOK() ) {
-$errors = $handlerStatus-&amp;gt;getErrorsArray();
-wfProfileOut( __METHOD__ );
-return reset( $errors );
-}
-}
-
-wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
-if ( $status !== true ) {
-wfProfileOut( __METHOD__ );
-return $status;
-}
-
-wfDebug( __METHOD__ . ": all clear; passing.\n" );
 wfProfileOut( __METHOD__ );
 return true;
 }
diff --git a/includes/upload/UploadFromChunks.php b/includes/upload/UploadFromChunks.php
index 0542bba..531f7be 100644
--- a/includes/upload/UploadFromChunks.php
+++ b/includes/upload/UploadFromChunks.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -69,6 +69,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 // Stash file is the called on creating a new chunk session:
 $this-&amp;gt;mChunkIndex = 0;
 $this-&amp;gt;mOffset = 0;
+
+$this-&amp;gt;verifyChunk();
 // Create a local stash target
 $this-&amp;gt;mLocalFile = parent::stashFile();
 // Update the initial file offset ( based on file size )
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -127,9 +129,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if( !$status-&amp;gt;isOk() ){
 return $status;
 }
+
+$this-&amp;gt;mTempPath = $tmpPath; // file system path
+$this-&amp;gt;mFileSize = filesize( $this-&amp;gt;mTempPath ); //Since this was set for the last chunk previously
+$ret = $this-&amp;gt;verifyUpload();
+if ( $ret['status'] !== UploadBase::OK ) {
+wfDebugLog( 'fileconcatenate', "Verification failed for chunked upload" );
+$status-&amp;gt;fatal( $this-&amp;gt;getVerificationErrorCode( $ret['status'] ) );
+return $status;
+}
+
 // Update the mTempPath and mLocalFile
 // ( for FileUpload or normal Stash to take over )
-$this-&amp;gt;mTempPath = $tmpPath; // file system path
 $this-&amp;gt;mLocalFile = parent::stashFile();
 
 return $status;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -181,6 +192,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $preAppendOffset == $offset ) {
 // Update local chunk index for the current chunk
 $this-&amp;gt;mChunkIndex++;
+try {
+# For some reason mTempPath is set to first part
+$oldTemp = $this-&amp;gt;mTempPath;
+$this-&amp;gt;mTempPath = $chunkPath;
+$this-&amp;gt;verifyChunk();
+$this-&amp;gt;mTempPath = $oldTemp;
+} catch ( UploadChunkVerificationException $e ) {
+return Status::newFatal( $e-&amp;gt;getMessage() );
+}
 $status = $this-&amp;gt;outputChunk( $chunkPath );
 if( $status-&amp;gt;isGood() ){
 // Update local offset:
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -300,7 +320,26 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 return $this-&amp;gt;mFileKey . '.' . $index ;
 }
+
+/**
+ * Verify that the chunk isn't really an evil html file
+ *
+ * &amp;lt; at &amp;gt;throws UploadChunkVerificationException
+ */
+private function verifyChunk() {
+// Rest mDesiredDestName here so we verify the name as if it were mFileKey
+$oldDesiredDestName = $this-&amp;gt;mDesiredDestName;
+$this-&amp;gt;mDesiredDestName = $this-&amp;gt;mFileKey;
+$this-&amp;gt;mTitle = false;
+$res = $this-&amp;gt;verifyPartialFile();
+$this-&amp;gt;mDesiredDestName = $oldDesiredDestName;
+$this-&amp;gt;mTitle = false;
+if( is_array( $res ) ) {
+throw new UploadChunkVerificationException( $res[0] );
+}
+}
 }
 
 class UploadChunkZeroLengthFileException extends MWException {};
 class UploadChunkFileException extends MWException {};
+class UploadChunkVerificationException extends MWException {};
diff --git a/includes/upload/UploadFromStash.php b/includes/upload/UploadFromStash.php
index 607965f..d79641c 100644
--- a/includes/upload/UploadFromStash.php
+++ b/includes/upload/UploadFromStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -129,14 +129,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return $this-&amp;gt;mSourceType;
 }
 
-/**
- * File has been previously verified so no need to do so again.
- *
- * &amp;lt; at &amp;gt;return bool
+/*
+ * protected function verifyFile() inherited
  */
-protected function verifyFile() {
-return true;
-}
 
 /**
  * Stash the file.
diff --git a/includes/upload/UploadStash.php b/includes/upload/UploadStash.php
index c7fd23a..53a9058 100644
--- a/includes/upload/UploadStash.php
+++ b/includes/upload/UploadStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -422,6 +422,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * &amp;lt; at &amp;gt;return string
  */
 public static function getExtensionForPath( $path ) {
+global $wgFileBlacklist;
 // Does this have an extension?
 $n = strrpos( $path, '.' );
 $extension = null;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -441,7 +442,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 throw new UploadStashFileException( "extension is null" );
 }
 
-return File::normalizeExtension( $extension );
+$extension = File::normalizeExtension( $extension );
+if ( in_array( $extension, $wgFileBlacklist ) ) {
+// The file should already be checked for being evil.
+// However, if somehow we got here, we definitely
+// don't want to give it an extension of .php and
+// put it in a web accesible directory.
+return '';
+}
+return $extension;
 }
 
 /**

&lt;/pre&gt;</description>
    <dc:creator>jenkins-bot (Code Review</dc:creator>
    <dc:date>2013-05-21T20:35:28</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172166">
    <title>[MediaWiki-commits] [Gerrit] jquery.byteLimit: Improve unit tests -change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172166</link>
    <description>&lt;pre&gt;Krinkle has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/64854


Change subject: jquery.byteLimit: Improve unit tests
......................................................................

jquery.byteLimit: Improve unit tests

* Update oudated documentation
* Remove hasLimit and limit properties of the test helper
  function. These just repeated data already provided
  (hasLimit if input != output, limit == expected.length)
* Add tests for a filter that increases the length
  (currently only a decreasing filter was tested).

Change-Id: Ib4c19f4d49ed9d19117bbbaccedb0fccaeb34719
---
M tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js
1 file changed, 43 insertions(+), 48 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core refs/changes/54/64854/1

diff --git a/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js b/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js
index c21844e..96186ff 100644
--- a/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js
+++ b/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -31,22 +31,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 /**
  * Test factory for $.fn.byteLimit
  *
- * &amp;lt; at &amp;gt;param $input {jQuery} jQuery object in an input element
- * &amp;lt; at &amp;gt;param hasLimit {Boolean} Wether a limit should apply at all
- * &amp;lt; at &amp;gt;param limit {Number} Limit (if used) otherwise undefined
- * The limit should be less than 20 (the sample data's length)
+ * &amp;lt; at &amp;gt;param {Object} options
+ * &amp;lt; at &amp;gt;param {string} options.description Test name
+ * &amp;lt; at &amp;gt;param {jQuery} options.$input jQuery object in an input element
+ * &amp;lt; at &amp;gt;param {string} options.sample Sequence of characters to simulate being
+ *  added one by one
+ * &amp;lt; at &amp;gt;param {string} options.expected Expected final value of `$input`
  */
 function byteLimitTest( options ) {
 var opt = $.extend( {
 description: '',
 $input: null,
 sample: '',
-hasLimit: false,
-expected: '',
-limit: null
+expected: ''
 }, options );
 
-QUnit.asyncTest( opt.description, opt.hasLimit ? 3 : 2, function ( assert ) {
+QUnit.asyncTest( opt.description, 1, function ( assert ) {
 setTimeout( function () {
 var rawVal, fn, effectiveVal;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -55,31 +55,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 // Simulate pressing keys for each of the sample characters
 addChars( opt.$input, opt.sample );
 
-rawVal = opt.$input.val();
-fn = opt.$input.data( 'byteLimit.callback' );
-effectiveVal = fn ? fn( rawVal ) : rawVal;
+assert.equal(
+opt.$input.val(),
+opt.expected,
+'New value matches the expected string'
+);
 
-if ( opt.hasLimit ) {
-assert.ltOrEq(
-$.byteLength( effectiveVal ),
-opt.limit,
-'Prevent keypresses after byteLimit was reached, length never exceeded the limit'
-);
-assert.equal(
-$.byteLength( rawVal ),
-$.byteLength( opt.expected ),
-'Not preventing keypresses too early, length has reached the expected length'
-);
-assert.equal( rawVal, opt.expected, 'New value matches the expected string' );
-
-} else {
-assert.equal(
-$.byteLength( effectiveVal ),
-$.byteLength( opt.expected ),
-'Unlimited scenarios are not affected, expected length reached'
-);
-assert.equal( rawVal, opt.expected, 'New value matches the expected string' );
-}
 QUnit.start();
 }, 10 );
 } );
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -89,7 +70,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 description: 'Plain text input',
 $input: $( '&amp;lt;input type="text"/&amp;gt;' ),
 sample: simpleSample,
-hasLimit: false,
 expected: simpleSample
 } );
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -98,7 +78,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $input: $( '&amp;lt;input type="text"/&amp;gt;' )
 .byteLimit(),
 sample: simpleSample,
-hasLimit: false,
 expected: simpleSample
 } );
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -108,8 +87,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .attr( 'maxlength', '10' )
 .byteLimit(),
 sample: simpleSample,
-hasLimit: true,
-limit: 10,
 expected: '1234567890'
 } );
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -118,8 +95,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $input: $( '&amp;lt;input type="text"/&amp;gt;' )
 .byteLimit( 10 ),
 sample: simpleSample,
-hasLimit: true,
-limit: 10,
 expected: '1234567890'
 } );
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -129,8 +104,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .attr( 'maxlength', '10' )
 .byteLimit( 15 ),
 sample: simpleSample,
-hasLimit: true,
-limit: 15,
 expected: '123456789012345'
 } );
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -139,8 +112,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $input: $( '&amp;lt;input type="text"/&amp;gt;' )
 .byteLimit( 14 ),
 sample: mbSample,
-hasLimit: true,
-limit: 14,
 expected: '1234567890' + U_20AC + '1'
 } );
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -149,8 +120,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $input: $( '&amp;lt;input type="text"/&amp;gt;' )
 .byteLimit( 12 ),
 sample: mbSample,
-hasLimit: true,
-limit: 12,
 expected: '1234567890' + '12'
 } );
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -167,8 +136,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return new mw.Title( String( val ) ).getMain();
 } ),
 sample: 'User:Sample',
-hasLimit: true,
-limit: 6, // 'Sample' length
 expected: 'User:Sample'
 } );
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -186,11 +153,39 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return new mw.Title( String( val ) ).getMain();
 } ),
 sample: 'User:Sample',
-hasLimit: true,
-limit: 6, // 'Sample' length
 expected: 'User:Sample'
 } );
 
+byteLimitTest( {
+description: 'Pass the limit and a callback as input filter',
+$input: $( '&amp;lt;input type="text"/&amp;gt;' )
+.byteLimit( 6, function ( val ) {
+// Invalid title
+if ( val === '' ) {
+return '';
+}
+
+// Return without namespace prefix
+return new mw.Title( String( val ) ).getMain();
+} ),
+sample: 'User:Example',
+// The callback alters the value to be used to calculeate
+// the length. The altered value is "Exampl" which has
+// a length of 6, the "e" would exceed the limit.
+expected: 'User:Exampl'
+} );
+
+byteLimitTest( {
+description: 'Input filter that increases the length',
+$input: $( '&amp;lt;input type="text"/&amp;gt;' )
+.byteLimit( 10, function ( text ) {
+return 'prefix' + text;
+} ),
+sample: simpleSample,
+// Prefix adds 6 characters, limit is reached after 4
+expected: '1234'
+} );
+
 QUnit.test( 'Confirm properties and attributes set', 4, function ( assert ) {
 var $el, $elA, $elB;
 

&lt;/pre&gt;</description>
    <dc:creator>Krinkle (Code Review</dc:creator>
    <dc:date>2013-05-21T20:33:50</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172165">
    <title>[MediaWiki-commits] [Gerrit] SECURITY: Do checks on all uploadtypes - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172165</link>
    <description>&lt;pre&gt;jenkins-bot has submitted this change and it was merged.

Change subject: SECURITY: Do checks on all upload types
......................................................................


SECURITY: Do checks on all upload types

Also, verify file before stashing it

Change-Id: Ib2474cb778d53959a4f479e53d0392f916b18d83
---
M includes/AutoLoader.php
M includes/api/ApiUpload.php
M includes/upload/UploadBase.php
M includes/upload/UploadFromChunks.php
M includes/upload/UploadFromStash.php
M includes/upload/UploadStash.php
6 files changed, 117 insertions(+), 38 deletions(-)

Approvals:
  CSteipp: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index 326fb5c..3e08e74 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -996,6 +996,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 'UnwatchedpagesPage' =&amp;gt; 'includes/specials/SpecialUnwatchedpages.php',
 'UploadChunkFileException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadChunkZeroLengthFileException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
+'UploadChunkVerificationException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadForm' =&amp;gt; 'includes/specials/SpecialUpload.php',
 'UploadSourceField' =&amp;gt; 'includes/specials/SpecialUpload.php',
 'UserrightsPage' =&amp;gt; 'includes/specials/SpecialUserrights.php',
diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php
index 5563087..e04c762 100644
--- a/includes/api/ApiUpload.php
+++ b/includes/api/ApiUpload.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -88,9 +88,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( !$this-&amp;gt;mUpload-&amp;gt;getTitle() ) {
 $this-&amp;gt;dieUsage( 'Invalid file title supplied', 'internal-error' );
 }
-} elseif ( $this-&amp;gt;mParams['async'] ) {
+} elseif ( $this-&amp;gt;mParams['async'] &amp;amp;&amp;amp; $this-&amp;gt;mParams['filekey'] ) {
 // defer verification to background process
 } else {
+wfDebug( __METHOD__ . 'about to verify' );
 $this-&amp;gt;verifyUpload();
 }
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -195,7 +196,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $chunkPath = $request-&amp;gt;getFileTempname( 'chunk' );
 $chunkSize = $request-&amp;gt;getUpload( 'chunk' )-&amp;gt;getSize();
 if ( $this-&amp;gt;mParams['offset'] == 0 ) {
-$filekey = $this-&amp;gt;performStash();
+try {
+$filekey = $this-&amp;gt;performStash();
+} catch ( MWException $e ) {
+// FIXME: Error handling here is wrong/different from rest of this
+$this-&amp;gt;dieUsage( $e-&amp;gt;getMessage(), 'stashfailed' );
+}
 } else {
 $filekey = $this-&amp;gt;mParams['filekey'];
 /** &amp;lt; at &amp;gt;var $status Status */
diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php
index 17da80e..2ed20c5 100644
--- a/includes/upload/UploadBase.php
+++ b/includes/upload/UploadBase.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -356,8 +356,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 
 /**
- * Verify the mime type
+ * Verify the mime type.
  *
+ * &amp;lt; at &amp;gt;note Only checks that it is not an evil mime. The does it have
+ *  correct extension given its mime type check is in verifyFile.
  * &amp;lt; at &amp;gt;param string $mime representing the mime
  * &amp;lt; at &amp;gt;return mixed true if the file is verified, an array otherwise
  */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -370,12 +372,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $this-&amp;gt;checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
 wfProfileOut( __METHOD__ );
 return array( 'filetype-badmime', $mime );
-}
-
-# XXX: Missing extension will be caught by validateName() via getTitle()
-if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
-wfProfileOut( __METHOD__ );
-return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
 }
 
 # Check IE type
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -398,17 +394,68 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return true;
 }
 
+
 /**
  * Verifies that it's ok to include the uploaded file
  *
  * &amp;lt; at &amp;gt;return mixed true of the file is verified, array otherwise.
  */
 protected function verifyFile() {
+global $wgVerifyMimeType;
+wfProfileIn( __METHOD__ );
+
+$status = $this-&amp;gt;verifyPartialFile();
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+if ( $wgVerifyMimeType ) {
+$this-&amp;gt;mFileProps = FSFile::getPropsFromPath( $this-&amp;gt;mTempPath, $this-&amp;gt;mFinalExtension );
+$mime = $this-&amp;gt;mFileProps['file-mime'];
+
+# XXX: Missing extension will be caught by validateName() via getTitle()
+if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
+wfProfileOut( __METHOD__ );
+return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
+}
+}
+
+
+$handler = MediaHandler::getHandler( $mime );
+if ( $handler ) {
+$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
+if ( !$handlerStatus-&amp;gt;isOK() ) {
+$errors = $handlerStatus-&amp;gt;getErrorsArray();
+wfProfileOut( __METHOD__ );
+return reset( $errors );
+}
+}
+
+wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+wfDebug( __METHOD__ . ": all clear; passing.\n" );
+wfProfileOut( __METHOD__ );
+return true;
+}
+
+/**
+ * A verification routine suitable for partial files
+ *
+ * Runs the blacklist checks, but not any checks that may
+ * assume the entire file is present.
+ *
+ * &amp;lt; at &amp;gt;return Mixed true for valid or array with error message key.
+ */
+protected function verifyPartialFile() {
 global $wgAllowJavaUploads, $wgDisableUploadScriptChecks;
 wfProfileIn( __METHOD__ );
 
-# get the title, even though we are doing nothing with it, because
-# we need to populate mFinalExtension
+# getTitle() sets some internal parameters like $this-&amp;gt;mFinalExtension
 $this-&amp;gt;getTitle();
 
 $this-&amp;gt;mFileProps = FSFile::getPropsFromPath( $this-&amp;gt;mTempPath, $this-&amp;gt;mFinalExtension );
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -462,23 +509,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return array( 'uploadvirus', $virus );
 }
 
-$handler = MediaHandler::getHandler( $mime );
-if ( $handler ) {
-$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
-if ( !$handlerStatus-&amp;gt;isOK() ) {
-$errors = $handlerStatus-&amp;gt;getErrorsArray();
-wfProfileOut( __METHOD__ );
-return reset( $errors );
-}
-}
-
-wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
-if ( $status !== true ) {
-wfProfileOut( __METHOD__ );
-return $status;
-}
-
-wfDebug( __METHOD__ . ": all clear; passing.\n" );
 wfProfileOut( __METHOD__ );
 return true;
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -677,7 +707,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $this-&amp;gt;mTitle !== false ) {
 return $this-&amp;gt;mTitle;
 }
-
 /* Assume that if a user specified File:Something.jpg, this is an error
  * and that the namespace prefix needs to be stripped of.
  */
diff --git a/includes/upload/UploadFromChunks.php b/includes/upload/UploadFromChunks.php
index 37db688..1746206 100644
--- a/includes/upload/UploadFromChunks.php
+++ b/includes/upload/UploadFromChunks.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -70,6 +70,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 // Stash file is the called on creating a new chunk session:
 $this-&amp;gt;mChunkIndex = 0;
 $this-&amp;gt;mOffset = 0;
+
+$this-&amp;gt;verifyChunk();
 // Create a local stash target
 $this-&amp;gt;mLocalFile = parent::stashFile();
 // Update the initial file offset (based on file size)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -131,9 +133,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return $status;
 }
 wfDebugLog( 'fileconcatenate', "Combined $i chunks in $tAmount seconds.\n" );
+
+$this-&amp;gt;mTempPath = $tmpPath; // file system path
+$this-&amp;gt;mFileSize = filesize( $this-&amp;gt;mTempPath ); //Since this was set for the last chunk previously
+$ret = $this-&amp;gt;verifyUpload();
+if ( $ret['status'] !== UploadBase::OK ) {
+wfDebugLog( 'fileconcatenate', "Verification failed for chunked upload" );
+$status-&amp;gt;fatal( $this-&amp;gt;getVerificationErrorCode( $ret['status'] ) );
+return $status;
+}
+
 // Update the mTempPath and mLocalFile
 // (for FileUpload or normal Stash to take over)
-$this-&amp;gt;mTempPath = $tmpPath; // file system path
 $tStart = microtime( true );
 $this-&amp;gt;mLocalFile = parent::stashFile( $this-&amp;gt;user );
 $tAmount = microtime( true ) - $tStart;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -189,6 +200,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $preAppendOffset == $offset ) {
 // Update local chunk index for the current chunk
 $this-&amp;gt;mChunkIndex++;
+try {
+# For some reason mTempPath is set to first part
+$oldTemp = $this-&amp;gt;mTempPath;
+$this-&amp;gt;mTempPath = $chunkPath;
+$this-&amp;gt;verifyChunk();
+$this-&amp;gt;mTempPath = $oldTemp;
+} catch ( UploadChunkVerificationException $e ) {
+return Status::newFatal( $e-&amp;gt;getMessage() );
+}
 $status = $this-&amp;gt;outputChunk( $chunkPath );
 if ( $status-&amp;gt;isGood() ) {
 // Update local offset:
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -312,7 +332,26 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 return $this-&amp;gt;mFileKey . '.' . $index;
 }
+
+/**
+ * Verify that the chunk isn't really an evil html file
+ *
+ * &amp;lt; at &amp;gt;throws UploadChunkVerificationException
+ */
+private function verifyChunk() {
+// Rest mDesiredDestName here so we verify the name as if it were mFileKey
+$oldDesiredDestName = $this-&amp;gt;mDesiredDestName;
+$this-&amp;gt;mDesiredDestName = $this-&amp;gt;mFileKey;
+$this-&amp;gt;mTitle = false;
+$res = $this-&amp;gt;verifyPartialFile();
+$this-&amp;gt;mDesiredDestName = $oldDesiredDestName;
+$this-&amp;gt;mTitle = false;
+if( is_array( $res ) ) {
+throw new UploadChunkVerificationException( $res[0] );
+}
+}
 }
 
 class UploadChunkZeroLengthFileException extends MWException {};
 class UploadChunkFileException extends MWException {};
+class UploadChunkVerificationException extends MWException {};
diff --git a/includes/upload/UploadFromStash.php b/includes/upload/UploadFromStash.php
index 9276b53..cb85fc6 100644
--- a/includes/upload/UploadFromStash.php
+++ b/includes/upload/UploadFromStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -137,14 +137,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return $this-&amp;gt;mFileProps['sha1'];
 }
 
-/**
- * File has been previously verified so no need to do so again.
- *
- * &amp;lt; at &amp;gt;return bool
+/*
+ * protected function verifyFile() inherited
  */
-protected function verifyFile() {
-return true;
-}
 
 /**
  * Stash the file.
diff --git a/includes/upload/UploadStash.php b/includes/upload/UploadStash.php
index 1ee4627..8a6d766 100644
--- a/includes/upload/UploadStash.php
+++ b/includes/upload/UploadStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -422,6 +422,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * &amp;lt; at &amp;gt;return string
  */
 public static function getExtensionForPath( $path ) {
+global $wgFileBlacklist;
 // Does this have an extension?
 $n = strrpos( $path, '.' );
 $extension = null;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -441,7 +442,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 throw new UploadStashFileException( "extension is null" );
 }
 
-return File::normalizeExtension( $extension );
+$extension = File::normalizeExtension( $extension );
+if ( in_array( $extension, $wgFileBlacklist ) ) {
+// The file should already be checked for being evil.
+// However, if somehow we got here, we definitely
+// don't want to give it an extension of .php and
+// put it in a web accesible directory.
+return '';
+}
+return $extension;
 }
 
 /**

&lt;/pre&gt;</description>
    <dc:creator>jenkins-bot (Code Review</dc:creator>
    <dc:date>2013-05-21T20:33:38</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172164">
    <title>[MediaWiki-commits] [Gerrit] Updated release notes and versionnumber - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172164</link>
    <description>&lt;pre&gt;CSteipp has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/64853


Change subject: Updated release notes and version number
......................................................................

Updated release notes and version number

Change-Id: I1fb122b2e946df330578474ace5c1da7e163f5b1
---
M RELEASE-NOTES-1.19
M includes/DefaultSettings.php
2 files changed, 9 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core refs/changes/53/64853/1

diff --git a/RELEASE-NOTES-1.19 b/RELEASE-NOTES-1.19
index a61c237..560ee3b 100644
--- a/RELEASE-NOTES-1.19
+++ b/RELEASE-NOTES-1.19
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -3,6 +3,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 Security reminder: MediaWiki does not require PHP's register_globals
 setting since version 1.2.0. If you have it on, turn it '''off''' if you can.
 
+== MediaWiki 1.19.7 ==
+
+This is a security and maintenance release of the MediaWiki 1.19 branch
+
+=== Changes since 1.19.6 ===
+* (bug 48306) SECURITY: Run file validation checks on  chunked uploads, and chunks
+  of upload, during the upload process.
+
 == MediaWiki 1.19.6 ==
 
 This is a security and maintenance release of the MediaWiki 1.19 branch
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index 6aa5c9e..84cc9c2 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -33,7 +33,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 /** &amp;lt; at &amp;gt;endcond */
 
 /** MediaWiki version number */
-$wgVersion = '1.19.6';
+$wgVersion = '1.19.7';
 
 /** Name of the site. It must be changed in LocalSettings.php */
 $wgSitename = 'MediaWiki';

&lt;/pre&gt;</description>
    <dc:creator>CSteipp (Code Review</dc:creator>
    <dc:date>2013-05-21T20:25:43</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172163">
    <title>[MediaWiki-commits] [Gerrit] SECURITY: Do checks on all uploadtypes - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172163</link>
    <description>&lt;pre&gt;CSteipp has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/64852


Change subject: SECURITY: Do checks on all upload types
......................................................................

SECURITY: Do checks on all upload types

Also, verify file before stashing it

Change-Id: I2b230af2f23c4303acdb695468608df19a88d16d
---
M includes/AutoLoader.php
M includes/api/ApiUpload.php
M includes/upload/UploadBase.php
M includes/upload/UploadFromChunks.php
M includes/upload/UploadFromStash.php
M includes/upload/UploadStash.php
6 files changed, 111 insertions(+), 30 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core refs/changes/52/64852/1

diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index 7611ed9..2bf134b 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -883,6 +883,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 # includes/upload
 'UploadBase' =&amp;gt; 'includes/upload/UploadBase.php',
+'UploadChunkVerificationException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadFromFile' =&amp;gt; 'includes/upload/UploadFromFile.php',
 'UploadFromChunks' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadFromStash' =&amp;gt; 'includes/upload/UploadFromStash.php',
diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php
index fdc1eff..922b89d 100644
--- a/includes/api/ApiUpload.php
+++ b/includes/api/ApiUpload.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -175,7 +175,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $chunkPath = $request-&amp;gt;getFileTempname( 'chunk' );
 $chunkSize = $request-&amp;gt;getUpload( 'chunk' )-&amp;gt;getSize();
 if ($this-&amp;gt;mParams['offset'] == 0) {
-$result['filekey'] = $this-&amp;gt;performStash();
+try {
+$result['filekey'] = $this-&amp;gt;performStash();
+} catch ( MWException $e ) {
+// FIXME: Error handling here is wrong/different from rest of this
+$this-&amp;gt;dieUsage( $e-&amp;gt;getMessage(), 'stashfailed' );
+}
 } else {
 $status = $this-&amp;gt;mUpload-&amp;gt;addChunk($chunkPath, $chunkSize,
 $this-&amp;gt;mParams['offset']);
diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php
index 3995519..5f09c04 100644
--- a/includes/upload/UploadBase.php
+++ b/includes/upload/UploadBase.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -301,6 +301,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 /**
  * Verify the mime type
  *
+ * &amp;lt; at &amp;gt;note Only checks that it is not an evil mime. The does it have
+ *  correct extension given its mime type check is in verifyFile.
  * &amp;lt; at &amp;gt;param $mime string representing the mime
  * &amp;lt; at &amp;gt;return mixed true if the file is verified, an array otherwise
  */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -311,11 +313,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 global $wgMimeTypeBlacklist;
 if ( $this-&amp;gt;checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
 return array( 'filetype-badmime', $mime );
-}
-
-# XXX: Missing extension will be caught by validateName() via getTitle()
-if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
-return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
 }
 
 # Check IE type
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -342,6 +339,56 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * &amp;lt; at &amp;gt;return mixed true of the file is verified, array otherwise.
  */
 protected function verifyFile() {
+global $wgVerifyMimeType;
+wfProfileIn( __METHOD__ );
+
+$status = $this-&amp;gt;verifyPartialFile();
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+if ( $wgVerifyMimeType ) {
+$this-&amp;gt;mFileProps = FSFile::getPropsFromPath( $this-&amp;gt;mTempPath, $this-&amp;gt;mFinalExtension );
+$mime = $this-&amp;gt;mFileProps['file-mime'];
+
+# XXX: Missing extension will be caught by validateName() via getTitle()
+if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
+wfProfileOut( __METHOD__ );
+return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
+}
+}
+
+$handler = MediaHandler::getHandler( $mime );
+if ( $handler ) {
+$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
+if ( !$handlerStatus-&amp;gt;isOK() ) {
+$errors = $handlerStatus-&amp;gt;getErrorsArray();
+wfProfileOut( __METHOD__ );
+return reset( $errors );
+}
+}
+
+wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+wfDebug( __METHOD__ . ": all clear; passing.\n" );
+wfProfileOut( __METHOD__ );
+return true;
+}
+
+/**
+ * A verification routine suitable for partial files
+ *
+ * Runs the blacklist checks, but not any checks that may
+ * assume the entire file is present.
+ *
+ * &amp;lt; at &amp;gt;return Mixed true for valid or array with error message key.
+ */
+protected function verifyPartialFile() {
 global $wgAllowJavaUploads, $wgDisableUploadScriptChecks;
 # get the title, even though we are doing nothing with it, because
 # we need to populate mFinalExtension
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -392,21 +439,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return array( 'uploadvirus', $virus );
 }
 
-$handler = MediaHandler::getHandler( $mime );
-if ( $handler ) {
-$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
-if ( !$handlerStatus-&amp;gt;isOK() ) {
-$errors = $handlerStatus-&amp;gt;getErrorsArray();
-return reset( $errors );
-}
-}
-
-wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
-if ( $status !== true ) {
-return $status;
-}
-
-wfDebug( __METHOD__ . ": all clear; passing.\n" );
 return true;
 }
 
diff --git a/includes/upload/UploadFromChunks.php b/includes/upload/UploadFromChunks.php
index ec83f7d..a76f03d 100644
--- a/includes/upload/UploadFromChunks.php
+++ b/includes/upload/UploadFromChunks.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -47,6 +47,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 // Stash file is the called on creating a new chunk session: 
 $this-&amp;gt;mChunkIndex = 0;
 $this-&amp;gt;mOffset = 0;
+
+$this-&amp;gt;verifyChunk();
 // Create a local stash target
 $this-&amp;gt;mLocalFile = parent::stashFile();
 // Update the initial file offset ( based on file size ) 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -105,9 +107,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if( !$status-&amp;gt;isOk() ){
 return $status; 
 }
+
+$this-&amp;gt;mTempPath = $tmpPath; // file system path
+$this-&amp;gt;mFileSize = filesize( $this-&amp;gt;mTempPath ); //Since this was set for the last chunk previously
+$ret = $this-&amp;gt;verifyUpload();
+if ( $ret['status'] !== UploadBase::OK ) {
+wfDebugLog( 'fileconcatenate', "Verification failed for chunked upload" );
+$status-&amp;gt;fatal( $this-&amp;gt;getVerificationErrorCode( $ret['status'] ) );
+return $status;
+}
+
 // Update the mTempPath and mLocalFile
 // ( for FileUpload or normal Stash to take over )  
-$this-&amp;gt;mTempPath = $tmpPath; // file system path
 $this-&amp;gt;mLocalFile = parent::stashFile();
 
 return $status;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -157,6 +168,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $preAppendOffset == $offset ) {
 // Update local chunk index for the current chunk   
 $this-&amp;gt;mChunkIndex++;
+try {
+# For some reason mTempPath is set to first part
+$oldTemp = $this-&amp;gt;mTempPath;
+$this-&amp;gt;mTempPath = $chunkPath;
+$this-&amp;gt;verifyChunk();
+$this-&amp;gt;mTempPath = $oldTemp;
+} catch ( UploadChunkVerificationException $e ) {
+return Status::newFatal( $e-&amp;gt;getMessage() );
+}
 $status = $this-&amp;gt;outputChunk( $chunkPath );
 if( $status-&amp;gt;isGood() ){
 // Update local offset: 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -270,7 +290,26 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 return $this-&amp;gt;mFileKey . '.' . $index ;
 }
+
+/**
+ * Verify that the chunk isn't really an evil html file
+ *
+ * &amp;lt; at &amp;gt;throws UploadChunkVerificationException
+ */
+private function verifyChunk() {
+// Rest mDesiredDestName here so we verify the name as if it were mFileKey
+$oldDesiredDestName = $this-&amp;gt;mDesiredDestName;
+$this-&amp;gt;mDesiredDestName = $this-&amp;gt;mFileKey;
+$this-&amp;gt;mTitle = false;
+$res = $this-&amp;gt;verifyPartialFile();
+$this-&amp;gt;mDesiredDestName = $oldDesiredDestName;
+$this-&amp;gt;mTitle = false;
+if( is_array( $res ) ) {
+throw new UploadChunkVerificationException( $res[0] );
+}
+}
 }
 
 class UploadChunkZeroLengthFileException extends MWException {};
 class UploadChunkFileException extends MWException {};
+class UploadChunkVerificationException extends MWException {};
diff --git a/includes/upload/UploadFromStash.php b/includes/upload/UploadFromStash.php
index f7589bd..014aa53 100644
--- a/includes/upload/UploadFromStash.php
+++ b/includes/upload/UploadFromStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -109,14 +109,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return $this-&amp;gt;mSourceType;
 }
 
-/**
- * File has been previously verified so no need to do so again.
- *
- * &amp;lt; at &amp;gt;return bool
+/*
+ * protected function verifyFile() inherited
  */
-protected function verifyFile() {
-return true;
-}
 
 /**
  * Stash the file.
diff --git a/includes/upload/UploadStash.php b/includes/upload/UploadStash.php
index ad153d2..73e3811 100644
--- a/includes/upload/UploadStash.php
+++ b/includes/upload/UploadStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -393,6 +393,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * uploads versus the desired filename. Maybe we can get that passed to us...
  */
 public static function getExtensionForPath( $path ) {
+global $wgFileBlacklist;
 // Does this have an extension?
 $n = strrpos( $path, '.' );
 $extension = null;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -412,7 +413,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 throw new UploadStashFileException( "extension is null" );
 }
 
-return File::normalizeExtension( $extension );
+$extension = File::normalizeExtension( $extension );
+if ( in_array( $extension, $wgFileBlacklist ) ) {
+// The file should already be checked for being evil.
+// However, if somehow we got here, we definitely
+// don't want to give it an extension of .php and
+// put it in a web accesible directory.
+return '';
+}
+return $extension;
 }
 
 /**

&lt;/pre&gt;</description>
    <dc:creator>CSteipp (Code Review</dc:creator>
    <dc:date>2013-05-21T20:25:42</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172162">
    <title>[MediaWiki-commits] [Gerrit] disable multiple file upload on Safari- change (mediawiki...UploadWizard)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172162</link>
    <description>&lt;pre&gt;Nischayn22 has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/64851


Change subject: disable multiple file upload on Safari
......................................................................

disable multiple file upload on Safari

Bug: 44772
Change-Id: Ib60dd151965310d0a567c7d888b4638cc48a696d
---
M UploadWizardPage.js
1 file changed, 5 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/UploadWizard refs/changes/51/64851/1

diff --git a/UploadWizardPage.js b/UploadWizardPage.js
index 85d51a1..4d1792b 100644
--- a/UploadWizardPage.js
+++ b/UploadWizardPage.js
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -16,6 +16,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 mw.log.level = mw.log.NONE;
 }
 
+// hack for Safari bug, see https://bugzilla.wikimedia.org/show_bug.cgi?id=44772
+if ( navigator.userAgent.indexOf( "Safari" ) &amp;gt; -1 ) {
+config.enableMultipleFiles = false;
+}
+
 var uploadWizard = new mw.UploadWizard( config );
 uploadWizard.createInterface( '#upload-wizard' );
 

&lt;/pre&gt;</description>
    <dc:creator>Nischayn22 (Code Review</dc:creator>
    <dc:date>2013-05-21T20:25:03</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172161">
    <title>[MediaWiki-commits] [Gerrit] Updated release notes and versionnumber - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172161</link>
    <description>&lt;pre&gt;CSteipp has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/64850


Change subject: Updated release notes and version number
......................................................................

Updated release notes and version number

Change-Id: I630010e6371ac4ba9ea24e5f2f48e891d3e41c2f
---
M RELEASE-NOTES-1.20
M includes/DefaultSettings.php
2 files changed, 6 insertions(+), 3 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core refs/changes/50/64850/1

diff --git a/RELEASE-NOTES-1.20 b/RELEASE-NOTES-1.20
index 2da9e35..d4f399a 100644
--- a/RELEASE-NOTES-1.20
+++ b/RELEASE-NOTES-1.20
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6,11 +6,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 == MediaWiki 1.20.6 ==
 
-This is a maintenance release of the MediaWiki 1.20 branch.
+This is a security and maintenance release of the MediaWiki 1.20 branch.
 
 === Changes since 1.20.5 ===
+* (bug 48306) SECURITY: Run file validation checks on chunked uploads, and chunks
+  of upload, during the upload process.
+* (bug 44327) mediawiki.user: Use session ID instead of 1-year cross-session cookies
 * (bug 47202) wikibits: FF2Fixes.css should not be loaded in Firefox 20.
-
+* (bug 31044) Make ResourceLoader behave in read-only mode
 
 == MediaWiki 1.20.5 ==
 
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index 6abc2b1..710605a 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -59,7 +59,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $wgConf = new SiteConfiguration;
 
 /** MediaWiki version number */
-$wgVersion = '1.20.5';
+$wgVersion = '1.20.6';
 
 /** Name of the site. It must be changed in LocalSettings.php */
 $wgSitename = 'MediaWiki';

&lt;/pre&gt;</description>
    <dc:creator>CSteipp (Code Review</dc:creator>
    <dc:date>2013-05-21T20:24:41</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172160">
    <title>[MediaWiki-commits] [Gerrit] SECURITY: Do checks on all uploadtypes - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172160</link>
    <description>&lt;pre&gt;CSteipp has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/64849


Change subject: SECURITY: Do checks on all upload types
......................................................................

SECURITY: Do checks on all upload types

Also, verify file before stashing it

Change-Id: I5dd027acc994cf7308c9e4d85a61237d802ccee8
---
M includes/AutoLoader.php
M includes/api/ApiUpload.php
M includes/upload/UploadBase.php
M includes/upload/UploadFromChunks.php
M includes/upload/UploadFromStash.php
M includes/upload/UploadStash.php
6 files changed, 111 insertions(+), 33 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core refs/changes/49/64849/1

diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index 9bdfcd2..a8b2202 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -965,6 +965,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 'UnwatchedpagesPage' =&amp;gt; 'includes/specials/SpecialUnwatchedpages.php',
 'UploadChunkFileException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadChunkZeroLengthFileException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
+'UploadChunkVerificationException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadForm' =&amp;gt; 'includes/specials/SpecialUpload.php',
 'UploadSourceField' =&amp;gt; 'includes/specials/SpecialUpload.php',
 'UserrightsPage' =&amp;gt; 'includes/specials/SpecialUserrights.php',
diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php
index 3a9b5c5..e7a7849 100644
--- a/includes/api/ApiUpload.php
+++ b/includes/api/ApiUpload.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -187,7 +187,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $chunkPath = $request-&amp;gt;getFileTempname( 'chunk' );
 $chunkSize = $request-&amp;gt;getUpload( 'chunk' )-&amp;gt;getSize();
 if ($this-&amp;gt;mParams['offset'] == 0) {
-$result['filekey'] = $this-&amp;gt;performStash();
+try {
+$result['filekey'] = $this-&amp;gt;performStash();
+} catch ( MWException $e ) {
+// FIXME: Error handling here is wrong/different from rest of this
+$this-&amp;gt;dieUsage( $e-&amp;gt;getMessage(), 'stashfailed' );
+}
 } else {
 $status = $this-&amp;gt;mUpload-&amp;gt;addChunk($chunkPath, $chunkSize,
 $this-&amp;gt;mParams['offset']);
diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php
index 3a5733c..0848780 100644
--- a/includes/upload/UploadBase.php
+++ b/includes/upload/UploadBase.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -345,6 +345,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 /**
  * Verify the mime type
  *
+ * &amp;lt; at &amp;gt;note Only checks that it is not an evil mime. The does it have
+ *  correct extension given its mime type check is in verifyFile.
  * &amp;lt; at &amp;gt;param $mime string representing the mime
  * &amp;lt; at &amp;gt;return mixed true if the file is verified, an array otherwise
  */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -357,12 +359,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $this-&amp;gt;checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
 wfProfileOut( __METHOD__ );
 return array( 'filetype-badmime', $mime );
-}
-
-# XXX: Missing extension will be caught by validateName() via getTitle()
-if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
-wfProfileOut( __METHOD__ );
-return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
 }
 
 # Check IE type
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -391,6 +387,56 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * &amp;lt; at &amp;gt;return mixed true of the file is verified, array otherwise.
  */
 protected function verifyFile() {
+global $wgVerifyMimeType;
+wfProfileIn( __METHOD__ );
+
+$status = $this-&amp;gt;verifyPartialFile();
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+if ( $wgVerifyMimeType ) {
+$this-&amp;gt;mFileProps = FSFile::getPropsFromPath( $this-&amp;gt;mTempPath, $this-&amp;gt;mFinalExtension );
+$mime = $this-&amp;gt;mFileProps['file-mime'];
+
+# XXX: Missing extension will be caught by validateName() via getTitle()
+if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
+wfProfileOut( __METHOD__ );
+return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
+}
+}
+
+$handler = MediaHandler::getHandler( $mime );
+if ( $handler ) {
+$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
+if ( !$handlerStatus-&amp;gt;isOK() ) {
+$errors = $handlerStatus-&amp;gt;getErrorsArray();
+wfProfileOut( __METHOD__ );
+return reset( $errors );
+}
+}
+
+wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+wfDebug( __METHOD__ . ": all clear; passing.\n" );
+wfProfileOut( __METHOD__ );
+return true;
+}
+
+/**
+ * A verification routine suitable for partial files
+ *
+ * Runs the blacklist checks, but not any checks that may
+ * assume the entire file is present.
+ *
+ * &amp;lt; at &amp;gt;return Mixed true for valid or array with error message key.
+ */
+protected function verifyPartialFile() {
 global $wgAllowJavaUploads, $wgDisableUploadScriptChecks;
 wfProfileIn( __METHOD__ );
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -449,23 +495,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return array( 'uploadvirus', $virus );
 }
 
-$handler = MediaHandler::getHandler( $mime );
-if ( $handler ) {
-$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
-if ( !$handlerStatus-&amp;gt;isOK() ) {
-$errors = $handlerStatus-&amp;gt;getErrorsArray();
-wfProfileOut( __METHOD__ );
-return reset( $errors );
-}
-}
-
-wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
-if ( $status !== true ) {
-wfProfileOut( __METHOD__ );
-return $status;
-}
-
-wfDebug( __METHOD__ . ": all clear; passing.\n" );
 wfProfileOut( __METHOD__ );
 return true;
 }
diff --git a/includes/upload/UploadFromChunks.php b/includes/upload/UploadFromChunks.php
index 0542bba..531f7be 100644
--- a/includes/upload/UploadFromChunks.php
+++ b/includes/upload/UploadFromChunks.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -69,6 +69,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 // Stash file is the called on creating a new chunk session:
 $this-&amp;gt;mChunkIndex = 0;
 $this-&amp;gt;mOffset = 0;
+
+$this-&amp;gt;verifyChunk();
 // Create a local stash target
 $this-&amp;gt;mLocalFile = parent::stashFile();
 // Update the initial file offset ( based on file size )
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -127,9 +129,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if( !$status-&amp;gt;isOk() ){
 return $status;
 }
+
+$this-&amp;gt;mTempPath = $tmpPath; // file system path
+$this-&amp;gt;mFileSize = filesize( $this-&amp;gt;mTempPath ); //Since this was set for the last chunk previously
+$ret = $this-&amp;gt;verifyUpload();
+if ( $ret['status'] !== UploadBase::OK ) {
+wfDebugLog( 'fileconcatenate', "Verification failed for chunked upload" );
+$status-&amp;gt;fatal( $this-&amp;gt;getVerificationErrorCode( $ret['status'] ) );
+return $status;
+}
+
 // Update the mTempPath and mLocalFile
 // ( for FileUpload or normal Stash to take over )
-$this-&amp;gt;mTempPath = $tmpPath; // file system path
 $this-&amp;gt;mLocalFile = parent::stashFile();
 
 return $status;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -181,6 +192,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $preAppendOffset == $offset ) {
 // Update local chunk index for the current chunk
 $this-&amp;gt;mChunkIndex++;
+try {
+# For some reason mTempPath is set to first part
+$oldTemp = $this-&amp;gt;mTempPath;
+$this-&amp;gt;mTempPath = $chunkPath;
+$this-&amp;gt;verifyChunk();
+$this-&amp;gt;mTempPath = $oldTemp;
+} catch ( UploadChunkVerificationException $e ) {
+return Status::newFatal( $e-&amp;gt;getMessage() );
+}
 $status = $this-&amp;gt;outputChunk( $chunkPath );
 if( $status-&amp;gt;isGood() ){
 // Update local offset:
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -300,7 +320,26 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 return $this-&amp;gt;mFileKey . '.' . $index ;
 }
+
+/**
+ * Verify that the chunk isn't really an evil html file
+ *
+ * &amp;lt; at &amp;gt;throws UploadChunkVerificationException
+ */
+private function verifyChunk() {
+// Rest mDesiredDestName here so we verify the name as if it were mFileKey
+$oldDesiredDestName = $this-&amp;gt;mDesiredDestName;
+$this-&amp;gt;mDesiredDestName = $this-&amp;gt;mFileKey;
+$this-&amp;gt;mTitle = false;
+$res = $this-&amp;gt;verifyPartialFile();
+$this-&amp;gt;mDesiredDestName = $oldDesiredDestName;
+$this-&amp;gt;mTitle = false;
+if( is_array( $res ) ) {
+throw new UploadChunkVerificationException( $res[0] );
+}
+}
 }
 
 class UploadChunkZeroLengthFileException extends MWException {};
 class UploadChunkFileException extends MWException {};
+class UploadChunkVerificationException extends MWException {};
diff --git a/includes/upload/UploadFromStash.php b/includes/upload/UploadFromStash.php
index 607965f..d79641c 100644
--- a/includes/upload/UploadFromStash.php
+++ b/includes/upload/UploadFromStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -129,14 +129,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return $this-&amp;gt;mSourceType;
 }
 
-/**
- * File has been previously verified so no need to do so again.
- *
- * &amp;lt; at &amp;gt;return bool
+/*
+ * protected function verifyFile() inherited
  */
-protected function verifyFile() {
-return true;
-}
 
 /**
  * Stash the file.
diff --git a/includes/upload/UploadStash.php b/includes/upload/UploadStash.php
index c7fd23a..53a9058 100644
--- a/includes/upload/UploadStash.php
+++ b/includes/upload/UploadStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -422,6 +422,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * &amp;lt; at &amp;gt;return string
  */
 public static function getExtensionForPath( $path ) {
+global $wgFileBlacklist;
 // Does this have an extension?
 $n = strrpos( $path, '.' );
 $extension = null;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -441,7 +442,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 throw new UploadStashFileException( "extension is null" );
 }
 
-return File::normalizeExtension( $extension );
+$extension = File::normalizeExtension( $extension );
+if ( in_array( $extension, $wgFileBlacklist ) ) {
+// The file should already be checked for being evil.
+// However, if somehow we got here, we definitely
+// don't want to give it an extension of .php and
+// put it in a web accesible directory.
+return '';
+}
+return $extension;
 }
 
 /**

&lt;/pre&gt;</description>
    <dc:creator>CSteipp (Code Review</dc:creator>
    <dc:date>2013-05-21T20:24:40</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172159">
    <title>[MediaWiki-commits] [Gerrit] SECURITY: Do checks on all uploadtypes - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172159</link>
    <description>&lt;pre&gt;CSteipp has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/64848


Change subject: SECURITY: Do checks on all upload types
......................................................................

SECURITY: Do checks on all upload types

Also, verify file before stashing it

Change-Id: Ib2474cb778d53959a4f479e53d0392f916b18d83
---
M includes/AutoLoader.php
M includes/api/ApiUpload.php
M includes/upload/UploadBase.php
M includes/upload/UploadFromChunks.php
M includes/upload/UploadFromStash.php
M includes/upload/UploadStash.php
6 files changed, 117 insertions(+), 38 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core refs/changes/48/64848/1

diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index 326fb5c..3e08e74 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -996,6 +996,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 'UnwatchedpagesPage' =&amp;gt; 'includes/specials/SpecialUnwatchedpages.php',
 'UploadChunkFileException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadChunkZeroLengthFileException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
+'UploadChunkVerificationException' =&amp;gt; 'includes/upload/UploadFromChunks.php',
 'UploadForm' =&amp;gt; 'includes/specials/SpecialUpload.php',
 'UploadSourceField' =&amp;gt; 'includes/specials/SpecialUpload.php',
 'UserrightsPage' =&amp;gt; 'includes/specials/SpecialUserrights.php',
diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php
index 5563087..e04c762 100644
--- a/includes/api/ApiUpload.php
+++ b/includes/api/ApiUpload.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -88,9 +88,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( !$this-&amp;gt;mUpload-&amp;gt;getTitle() ) {
 $this-&amp;gt;dieUsage( 'Invalid file title supplied', 'internal-error' );
 }
-} elseif ( $this-&amp;gt;mParams['async'] ) {
+} elseif ( $this-&amp;gt;mParams['async'] &amp;amp;&amp;amp; $this-&amp;gt;mParams['filekey'] ) {
 // defer verification to background process
 } else {
+wfDebug( __METHOD__ . 'about to verify' );
 $this-&amp;gt;verifyUpload();
 }
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -195,7 +196,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $chunkPath = $request-&amp;gt;getFileTempname( 'chunk' );
 $chunkSize = $request-&amp;gt;getUpload( 'chunk' )-&amp;gt;getSize();
 if ( $this-&amp;gt;mParams['offset'] == 0 ) {
-$filekey = $this-&amp;gt;performStash();
+try {
+$filekey = $this-&amp;gt;performStash();
+} catch ( MWException $e ) {
+// FIXME: Error handling here is wrong/different from rest of this
+$this-&amp;gt;dieUsage( $e-&amp;gt;getMessage(), 'stashfailed' );
+}
 } else {
 $filekey = $this-&amp;gt;mParams['filekey'];
 /** &amp;lt; at &amp;gt;var $status Status */
diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php
index 17da80e..2ed20c5 100644
--- a/includes/upload/UploadBase.php
+++ b/includes/upload/UploadBase.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -356,8 +356,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 
 /**
- * Verify the mime type
+ * Verify the mime type.
  *
+ * &amp;lt; at &amp;gt;note Only checks that it is not an evil mime. The does it have
+ *  correct extension given its mime type check is in verifyFile.
  * &amp;lt; at &amp;gt;param string $mime representing the mime
  * &amp;lt; at &amp;gt;return mixed true if the file is verified, an array otherwise
  */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -370,12 +372,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $this-&amp;gt;checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
 wfProfileOut( __METHOD__ );
 return array( 'filetype-badmime', $mime );
-}
-
-# XXX: Missing extension will be caught by validateName() via getTitle()
-if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
-wfProfileOut( __METHOD__ );
-return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
 }
 
 # Check IE type
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -398,17 +394,68 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return true;
 }
 
+
 /**
  * Verifies that it's ok to include the uploaded file
  *
  * &amp;lt; at &amp;gt;return mixed true of the file is verified, array otherwise.
  */
 protected function verifyFile() {
+global $wgVerifyMimeType;
+wfProfileIn( __METHOD__ );
+
+$status = $this-&amp;gt;verifyPartialFile();
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+if ( $wgVerifyMimeType ) {
+$this-&amp;gt;mFileProps = FSFile::getPropsFromPath( $this-&amp;gt;mTempPath, $this-&amp;gt;mFinalExtension );
+$mime = $this-&amp;gt;mFileProps['file-mime'];
+
+# XXX: Missing extension will be caught by validateName() via getTitle()
+if ( $this-&amp;gt;mFinalExtension != '' &amp;amp;&amp;amp; !$this-&amp;gt;verifyExtension( $mime, $this-&amp;gt;mFinalExtension ) ) {
+wfProfileOut( __METHOD__ );
+return array( 'filetype-mime-mismatch', $this-&amp;gt;mFinalExtension, $mime );
+}
+}
+
+
+$handler = MediaHandler::getHandler( $mime );
+if ( $handler ) {
+$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
+if ( !$handlerStatus-&amp;gt;isOK() ) {
+$errors = $handlerStatus-&amp;gt;getErrorsArray();
+wfProfileOut( __METHOD__ );
+return reset( $errors );
+}
+}
+
+wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
+if ( $status !== true ) {
+wfProfileOut( __METHOD__ );
+return $status;
+}
+
+wfDebug( __METHOD__ . ": all clear; passing.\n" );
+wfProfileOut( __METHOD__ );
+return true;
+}
+
+/**
+ * A verification routine suitable for partial files
+ *
+ * Runs the blacklist checks, but not any checks that may
+ * assume the entire file is present.
+ *
+ * &amp;lt; at &amp;gt;return Mixed true for valid or array with error message key.
+ */
+protected function verifyPartialFile() {
 global $wgAllowJavaUploads, $wgDisableUploadScriptChecks;
 wfProfileIn( __METHOD__ );
 
-# get the title, even though we are doing nothing with it, because
-# we need to populate mFinalExtension
+# getTitle() sets some internal parameters like $this-&amp;gt;mFinalExtension
 $this-&amp;gt;getTitle();
 
 $this-&amp;gt;mFileProps = FSFile::getPropsFromPath( $this-&amp;gt;mTempPath, $this-&amp;gt;mFinalExtension );
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -462,23 +509,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return array( 'uploadvirus', $virus );
 }
 
-$handler = MediaHandler::getHandler( $mime );
-if ( $handler ) {
-$handlerStatus = $handler-&amp;gt;verifyUpload( $this-&amp;gt;mTempPath );
-if ( !$handlerStatus-&amp;gt;isOK() ) {
-$errors = $handlerStatus-&amp;gt;getErrorsArray();
-wfProfileOut( __METHOD__ );
-return reset( $errors );
-}
-}
-
-wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &amp;amp;$status ) );
-if ( $status !== true ) {
-wfProfileOut( __METHOD__ );
-return $status;
-}
-
-wfDebug( __METHOD__ . ": all clear; passing.\n" );
 wfProfileOut( __METHOD__ );
 return true;
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -677,7 +707,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $this-&amp;gt;mTitle !== false ) {
 return $this-&amp;gt;mTitle;
 }
-
 /* Assume that if a user specified File:Something.jpg, this is an error
  * and that the namespace prefix needs to be stripped of.
  */
diff --git a/includes/upload/UploadFromChunks.php b/includes/upload/UploadFromChunks.php
index 37db688..1746206 100644
--- a/includes/upload/UploadFromChunks.php
+++ b/includes/upload/UploadFromChunks.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -70,6 +70,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 // Stash file is the called on creating a new chunk session:
 $this-&amp;gt;mChunkIndex = 0;
 $this-&amp;gt;mOffset = 0;
+
+$this-&amp;gt;verifyChunk();
 // Create a local stash target
 $this-&amp;gt;mLocalFile = parent::stashFile();
 // Update the initial file offset (based on file size)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -131,9 +133,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return $status;
 }
 wfDebugLog( 'fileconcatenate', "Combined $i chunks in $tAmount seconds.\n" );
+
+$this-&amp;gt;mTempPath = $tmpPath; // file system path
+$this-&amp;gt;mFileSize = filesize( $this-&amp;gt;mTempPath ); //Since this was set for the last chunk previously
+$ret = $this-&amp;gt;verifyUpload();
+if ( $ret['status'] !== UploadBase::OK ) {
+wfDebugLog( 'fileconcatenate', "Verification failed for chunked upload" );
+$status-&amp;gt;fatal( $this-&amp;gt;getVerificationErrorCode( $ret['status'] ) );
+return $status;
+}
+
 // Update the mTempPath and mLocalFile
 // (for FileUpload or normal Stash to take over)
-$this-&amp;gt;mTempPath = $tmpPath; // file system path
 $tStart = microtime( true );
 $this-&amp;gt;mLocalFile = parent::stashFile( $this-&amp;gt;user );
 $tAmount = microtime( true ) - $tStart;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -189,6 +200,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if ( $preAppendOffset == $offset ) {
 // Update local chunk index for the current chunk
 $this-&amp;gt;mChunkIndex++;
+try {
+# For some reason mTempPath is set to first part
+$oldTemp = $this-&amp;gt;mTempPath;
+$this-&amp;gt;mTempPath = $chunkPath;
+$this-&amp;gt;verifyChunk();
+$this-&amp;gt;mTempPath = $oldTemp;
+} catch ( UploadChunkVerificationException $e ) {
+return Status::newFatal( $e-&amp;gt;getMessage() );
+}
 $status = $this-&amp;gt;outputChunk( $chunkPath );
 if ( $status-&amp;gt;isGood() ) {
 // Update local offset:
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -312,7 +332,26 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 return $this-&amp;gt;mFileKey . '.' . $index;
 }
+
+/**
+ * Verify that the chunk isn't really an evil html file
+ *
+ * &amp;lt; at &amp;gt;throws UploadChunkVerificationException
+ */
+private function verifyChunk() {
+// Rest mDesiredDestName here so we verify the name as if it were mFileKey
+$oldDesiredDestName = $this-&amp;gt;mDesiredDestName;
+$this-&amp;gt;mDesiredDestName = $this-&amp;gt;mFileKey;
+$this-&amp;gt;mTitle = false;
+$res = $this-&amp;gt;verifyPartialFile();
+$this-&amp;gt;mDesiredDestName = $oldDesiredDestName;
+$this-&amp;gt;mTitle = false;
+if( is_array( $res ) ) {
+throw new UploadChunkVerificationException( $res[0] );
+}
+}
 }
 
 class UploadChunkZeroLengthFileException extends MWException {};
 class UploadChunkFileException extends MWException {};
+class UploadChunkVerificationException extends MWException {};
diff --git a/includes/upload/UploadFromStash.php b/includes/upload/UploadFromStash.php
index 9276b53..cb85fc6 100644
--- a/includes/upload/UploadFromStash.php
+++ b/includes/upload/UploadFromStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -137,14 +137,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return $this-&amp;gt;mFileProps['sha1'];
 }
 
-/**
- * File has been previously verified so no need to do so again.
- *
- * &amp;lt; at &amp;gt;return bool
+/*
+ * protected function verifyFile() inherited
  */
-protected function verifyFile() {
-return true;
-}
 
 /**
  * Stash the file.
diff --git a/includes/upload/UploadStash.php b/includes/upload/UploadStash.php
index 1ee4627..8a6d766 100644
--- a/includes/upload/UploadStash.php
+++ b/includes/upload/UploadStash.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -422,6 +422,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * &amp;lt; at &amp;gt;return string
  */
 public static function getExtensionForPath( $path ) {
+global $wgFileBlacklist;
 // Does this have an extension?
 $n = strrpos( $path, '.' );
 $extension = null;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -441,7 +442,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 throw new UploadStashFileException( "extension is null" );
 }
 
-return File::normalizeExtension( $extension );
+$extension = File::normalizeExtension( $extension );
+if ( in_array( $extension, $wgFileBlacklist ) ) {
+// The file should already be checked for being evil.
+// However, if somehow we got here, we definitely
+// don't want to give it an extension of .php and
+// put it in a web accesible directory.
+return '';
+}
+return $extension;
 }
 
 /**

&lt;/pre&gt;</description>
    <dc:creator>CSteipp (Code Review</dc:creator>
    <dc:date>2013-05-21T20:20:50</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172158">
    <title>[MediaWiki-commits] [Gerrit] Add script sql to Tools. - change(operations/puppet)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172158</link>
    <description>&lt;pre&gt;Tim Landscheidt has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/64847


Change subject: Add script sql to Tools.
......................................................................

Add script sql to Tools.

The script allows users to just name the database they want to connect
to without having to look up the server it is stored on.

Bug: 48627
Change-Id: Ie111a5adad4c6378ed71825394548f47d4991eaf
---
A modules/toollabs/files/sql
M modules/toollabs/manifests/exec_environ.pp
2 files changed, 46 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/operations/puppet refs/changes/47/64847/1

diff --git a/modules/toollabs/files/sql b/modules/toollabs/files/sql
new file mode 100755
index 0000000..6dde329
--- /dev/null
+++ b/modules/toollabs/files/sql
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,40 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+#!/bin/bash
+
+function check_host () {
+    for HOST_I in enwiki bgwiki bgwiktionary cswiki enwikiquote \
+                  enwiktionary eowiki fiwiki idwiki itwiki nlwiki \
+                  nowiki plwiki ptwiki svwiki thwiki trwiki zhwiki \
+                  commonswiki dewiki wikidatawiki; do
+        if [ "$1" = "$HOST_I" ]; then
+            return 0
+        fi
+    done
+
+    return 1
+}
+
+# No database name or extra parameters given?
+if [ $# -eq 0 ] || [ $# -gt 2 ]; then
+    echo "Usage: $0 DATABASE [COMMAND]" &amp;gt;&amp;amp;2
+    exit 1
+fi
+
+# Database name doesn't end up with "_p"?
+HOST="${1%_p}"
+if [ "$1" = "$HOST" ]; then
+    echo "$0: Database name '$1' doesn't end with '_p'." &amp;gt;&amp;amp;2
+    exit 1
+fi
+
+# Host in list of replicated databases?
+if ! check_host "$HOST"; then
+    echo "$0: Database '$1' hasn't been replicated to Tools yet." &amp;gt;&amp;amp;2
+    exit 1
+fi
+
+# Call mysql.
+if [ $# -eq 1 ]; then
+    exec mysql -ch "$HOST.labsdb" "$1"
+else
+    exec mysql -ch "$HOST.labsdb" "$1" -e "$2"
+fi
diff --git a/modules/toollabs/manifests/exec_environ.pp b/modules/toollabs/manifests/exec_environ.pp
index 75461dd..f2732cf 100644
--- a/modules/toollabs/manifests/exec_environ.pp
+++ b/modules/toollabs/manifests/exec_environ.pp
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -94,6 +94,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   sysctl { "vm.overcommit_memory": value =&amp;gt; 2 }
   sysctl { "vm.overcommit_ratio": value =&amp;gt; 95 }
 
+  file { "/usr/local/bin/sql":
+    ensure =&amp;gt; file,
+    mode =&amp;gt; "0555",
+    source =&amp;gt; "puppet:///files/toollabs/sql";
+  }
+
   # TODO: quotas
 }
 

&lt;/pre&gt;</description>
    <dc:creator>Tim Landscheidt (Code Review</dc:creator>
    <dc:date>2013-05-21T20:10:29</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172157">
    <title>[MediaWiki-commits] [Gerrit] Update MobileFrontend to productiontip - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172157</link>
    <description>&lt;pre&gt;jenkins-bot has submitted this change and it was merged.

Change subject: Update MobileFrontend to production tip
......................................................................


Update MobileFrontend to production tip

Change-Id: I07182a924c62fc9141a5c946b8552806ca00d0c4
---
M extensions/MobileFrontend
1 file changed, 0 insertions(+), 0 deletions(-)

Approvals:
  awjrichards: Verified; Looks good to me, approved
  jenkins-bot: Verified



diff --git a/extensions/MobileFrontend b/extensions/MobileFrontend
index 05d3a18..8ee5fdf 160000
--- a/extensions/MobileFrontend
+++ b/extensions/MobileFrontend
-Subproject commit 05d3a1821cf77bda90f7bbab9eb6be7c5cdd9b22
+Subproject commit 8ee5fdf6954e2feaad42b35012e5230e92ad9bae

&lt;/pre&gt;</description>
    <dc:creator>jenkins-bot (Code Review</dc:creator>
    <dc:date>2013-05-21T20:10:25</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172156">
    <title>[MediaWiki-commits] [Gerrit] TitleSquidURLs hook for changing theURLs to purge - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172156</link>
    <description>&lt;pre&gt;jenkins-bot has submitted this change and it was merged.

Change subject: TitleSquidURLs hook for changing the URLs to purge
......................................................................


TitleSquidURLs hook for changing the URLs to purge

This allows extensions to purge derivative resources that need
updating when a wiki page is changed.

Change-Id: Ic28ce7f57f29376b041627288979981fcb218a44
---
M RELEASE-NOTES-1.22
M docs/hooks.txt
M includes/Title.php
3 files changed, 7 insertions(+), 0 deletions(-)

Approvals:
  Aaron Schulz: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/RELEASE-NOTES-1.22 b/RELEASE-NOTES-1.22
index 168f2f7..6b13e01 100644
--- a/RELEASE-NOTES-1.22
+++ b/RELEASE-NOTES-1.22
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -79,6 +79,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   which can be cascading (previously 'sysop' was hard-coded as the only one).
 * XHTML5 support has been improved. If you set $wgMimeType = 'application/xhtml+xml'
   MediaWiki will try outputting markup acording to XHTML5 rules.
+* New hook 'TitleSquidURLs' for manipulating the list of URLs to be purged from
+  HTTP caches when a page is changed.
 
 === Bug fixes in 1.22 ===
 * Disable Special:PasswordReset when $wgEnableEmail is false. Previously one
diff --git a/docs/hooks.txt b/docs/hooks.txt
index a292997..f94a1b0 100644
--- a/docs/hooks.txt
+++ b/docs/hooks.txt
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2379,6 +2379,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 $user: Current user object
 &amp;amp;$whitelisted: Boolean value of whether this title is whitelisted
 
+'TitleSquidURLs': Called to determine which URLs to purge from HTTP caches.
+$this: Title object to purge
+&amp;amp;$urls: An array of URLs to purge from the caches, to be manipulated.
+
 'UndeleteForm::showHistory': Called in UndeleteForm::showHistory, after a
 PageArchive object has been created but before any further processing is done.
 &amp;amp;$archive: PageArchive object
diff --git a/includes/Title.php b/includes/Title.php
index 14915e5..8a37f68 100644
--- a/includes/Title.php
+++ b/includes/Title.php
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -3448,6 +3448,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 }
 
+wfRunHooks( 'TitleSquidURLs', array( $this, &amp;amp;$urls ) );
 return $urls;
 }
 

&lt;/pre&gt;</description>
    <dc:creator>jenkins-bot (Code Review</dc:creator>
    <dc:date>2013-05-21T20:06:12</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172155">
    <title>[MediaWiki-commits] [Gerrit] Update MobileFrontend to productiontip - change (mediawiki/core)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172155</link>
    <description>&lt;pre&gt;awjrichards has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/64846


Change subject: Update MobileFrontend to production tip
......................................................................

Update MobileFrontend to production tip

Change-Id: I07182a924c62fc9141a5c946b8552806ca00d0c4
---
M extensions/MobileFrontend
1 file changed, 0 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core refs/changes/46/64846/1

diff --git a/extensions/MobileFrontend b/extensions/MobileFrontend
index 05d3a18..8ee5fdf 160000
--- a/extensions/MobileFrontend
+++ b/extensions/MobileFrontend
-Subproject commit 05d3a1821cf77bda90f7bbab9eb6be7c5cdd9b22
+Subproject commit 8ee5fdf6954e2feaad42b35012e5230e92ad9bae

&lt;/pre&gt;</description>
    <dc:creator>awjrichards (Code Review</dc:creator>
    <dc:date>2013-05-21T20:05:48</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172154">
    <title>[MediaWiki-commits] [Gerrit] Restrict Verified/Submit to JenkinsBotand l10n-bot - change (mediawiki...TranslationNotifications)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172154</link>
    <description>&lt;pre&gt;Krinkle has submitted this change and it was merged.

Change subject: Restrict Verified/Submit to JenkinsBot and l10n-bot
......................................................................


Restrict Verified/Submit to JenkinsBot and l10n-bot

Change-Id: Ifa6c9509e6506a34da346046a5dd6005a01315ea
---
M groups
M project.config
2 files changed, 10 insertions(+), 0 deletions(-)

Approvals:
  Krinkle: Verified; Looks good to me, approved



diff --git a/groups b/groups
index c69ed7f..d5839f1 100644
--- a/groups
+++ b/groups
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,3 +1,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 # UUID                                  Group Name
 #
+2bc47fcadf4e44ec9a1a73bcfa06232554f47ce2JenkinsBot
+cc37d98e3a4301744a0c0a9249173ae170696072l10n-bot
+global:Registered-Users                 Registered Users
 c626276deb0c8cac1c73820eb6e88184b55e4a9dl10n-team
diff --git a/project.config b/project.config
index 262af0b..442e947 100644
--- a/project.config
+++ b/project.config
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -3,6 +3,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 description = MediaWiki extension TranslationNotifications.
 [access "refs/*"]
 owner = group l10n-team
+[access "refs/heads/master"]
+label-Verified = -1..+2 group JenkinsBot
+label-Verified = -1..+2 group l10n-bot
+label-Verified = -1..+0 group Registered Users
+submit = deny group Registered Users
+submit = group JenkinsBot
+submit = group l10n-bot
 [receive]
 requireChangeId = true
 [submit]

&lt;/pre&gt;</description>
    <dc:creator>Krinkle (Code Review</dc:creator>
    <dc:date>2013-05-21T20:00:36</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172153">
    <title>[MediaWiki-commits] [Gerrit] Restrict Verified/Submit to JenkinsBotand l10n-bot - change (mediawiki...Translate)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172153</link>
    <description>&lt;pre&gt;Krinkle has submitted this change and it was merged.

Change subject: Restrict Verified/Submit to JenkinsBot and l10n-bot
......................................................................


Restrict Verified/Submit to JenkinsBot and l10n-bot

Change-Id: I49af1c9526655097229ed0cb154f0df1450fa8a8
---
M groups
M project.config
2 files changed, 10 insertions(+), 0 deletions(-)

Approvals:
  Krinkle: Verified; Looks good to me, approved



diff --git a/groups b/groups
index fa2a5b2..48a0455 100644
--- a/groups
+++ b/groups
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,4 +1,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 # UUID                                  Group Name
 #
+2bc47fcadf4e44ec9a1a73bcfa06232554f47ce2JenkinsBot
+cc37d98e3a4301744a0c0a9249173ae170696072l10n-bot
+global:Registered-Users                 Registered Users
 39bc276be2b012b959b981bd8609aafdf450ec84extension-Translate
 c626276deb0c8cac1c73820eb6e88184b55e4a9dl10n-team
diff --git a/project.config b/project.config
index 0d92c1a..7d822f2 100644
--- a/project.config
+++ b/project.config
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6,6 +6,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 [access "refs/*"]
 owner = group extension-Translate
 owner = group l10n-team
+[access "refs/heads/master"]
+label-Verified = -1..+2 group JenkinsBot
+label-Verified = -1..+2 group l10n-bot
+label-Verified = -1..+0 group Registered Users
+submit = deny group Registered Users
+submit = group JenkinsBot
+submit = group l10n-bot
 [receive]
 requireChangeId = true
 [submit]

&lt;/pre&gt;</description>
    <dc:creator>Krinkle (Code Review</dc:creator>
    <dc:date>2013-05-21T20:00:20</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172152">
    <title>[MediaWiki-commits] [Gerrit] Restrict Verified/Submit to JenkinsBotand l10n-bot - change (mediawiki...TwnMainPage)</title>
    <link>http://permalink.gmane.org/gmane.org.wikimedia.mediawiki.cvs/172152</link>
    <description>&lt;pre&gt;Krinkle has submitted this change and it was merged.

Change subject: Restrict Verified/Submit to JenkinsBot and l10n-bot
......................................................................


Restrict Verified/Submit to JenkinsBot and l10n-bot

Change-Id: I3edbcee0852be98c041d15a25f1e657b6f352e49
---
M groups
M project.config
2 files changed, 10 insertions(+), 0 deletions(-)

Approvals:
  Krinkle: Verified; Looks good to me, approved



diff --git a/groups b/groups
index c69ed7f..d5839f1 100644
--- a/groups
+++ b/groups
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,3 +1,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 # UUID                                  Group Name
 #
+2bc47fcadf4e44ec9a1a73bcfa06232554f47ce2JenkinsBot
+cc37d98e3a4301744a0c0a9249173ae170696072l10n-bot
+global:Registered-Users                 Registered Users
 c626276deb0c8cac1c73820eb6e88184b55e4a9dl10n-team
diff --git a/project.config b/project.config
index f608ee3..adb1dba 100644
--- a/project.config
+++ b/project.config
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,5 +1,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 [access]
 inheritFrom = mediawiki/extensions
+[access "refs/heads/master"]
+label-Verified = -1..+2 group JenkinsBot
+label-Verified = -1..+2 group l10n-bot
+label-Verified = -1..+0 group Registered Users
+submit = deny group Registered Users
+submit = group JenkinsBot
+submit = group l10n-bot
 [project]
 state = active
 description = MediaWiki extension TwnMainPage

&lt;/pre&gt;</description>
    <dc:creator>Krinkle (Code Review</dc:creator>
    <dc:date>2013-05-21T19:59:53</dc:date>
  </item>
  <textinput rdf:about="http://search.gmane.org/?group=$group=gmane.org.wikimedia.mediawiki.cvs">
    <title>Search Engine</title>
    <description>Search the mailing list at Gmane</description>
    <name>query</name>
    <link>http://search.gmane.org/?group=$group=gmane.org.wikimedia.mediawiki.cvs</link>
  </textinput>
</rdf:RDF>
