Merge "Avoid making master connection from Skin::getUndeleteLink"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 31 Jan 2019 01:38:43 +0000 (01:38 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 31 Jan 2019 01:38:43 +0000 (01:38 +0000)
17 files changed:
.gitignore
RELEASE-NOTES-1.33
composer.json
docs/code-coverage/README [deleted file]
includes/DefaultSettings.php
includes/Setup.php
includes/auth/LocalPasswordPrimaryAuthenticationProvider.php
includes/auth/TemporaryPasswordPrimaryAuthenticationProvider.php
includes/password/InvalidPassword.php
includes/password/Password.php
includes/tidy/RemexCompatMunger.php
includes/user/BotPassword.php
tests/phpunit/Makefile
tests/phpunit/includes/TestUser.php
tests/phpunit/includes/password/LayeredParameterizedPasswordTest.php
tests/phpunit/includes/password/PasswordTestCase.php
tests/phpunit/includes/tidy/RemexDriverTest.php

index 2f17bc6..d25d525 100644 (file)
@@ -25,6 +25,7 @@ sftp-config.json
 
 # MediaWiki install & usage
 /cache
+/docs/coverage
 /docs/js
 /images/[0-9a-f]
 /images/archive
index 03a4a67..24032bd 100644 (file)
@@ -30,6 +30,9 @@ production.
   $wgTidyConf, $wgTidyOpts, $wgTidyInternal, and $wgDebugTidy, all
   deprecated since 1.26, have now all been removed. The $wgTidyConfig
   setting remains only for Remex experimental features or debugging.
+* $wgEnableParserCache, deprecated since 1.26, was removed.
+  If disabling the parser cache is still desirable,
+  set `$wgParserCacheType = CACHE_NONE;` instead.
 
 === New features in 1.33 ===
 * (T96041) __EXPECTUNUSEDCATEGORY__ on a category page causes the category
@@ -215,6 +218,7 @@ because of Phabricator reports.
 * The class WebInstallerOutput is now marked as @private.
 * (T209699) The jquery.async module has been deprecated. JavaScript code that
   needs asynchronous behaviour should use Promises.
+* Password::equals() is deprecated, use verify().
 
 === Other changes in 1.33 ===
 * (T208871) The hard-coded Google search form on the database error page was
index 2aceca8..845101d 100644 (file)
                "wikimedia/testing-access-wrapper": "~1.0",
                "wmde/hamcrest-html-matchers": "^0.1.0"
        },
+       "replace": {
+               "symfony/polyfill-ctype": "1.99",
+               "symfony/polyfill-mbstring": "1.99"
+       },
        "suggest": {
                "ext-apcu": "Local data cache for greatly improved performance",
                "ext-curl": "Improved http communication abilities",
diff --git a/docs/code-coverage/README b/docs/code-coverage/README
deleted file mode 100644 (file)
index 76ce9bd..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-This directory is for the auto-generated phpunit code coverage.
-Run 'make coverage' in the tests/phpunit subdirectory to build.
index 9df4ab6..00ccc96 100644 (file)
@@ -2660,12 +2660,6 @@ $wgUseFileCache = false;
  */
 $wgFileCacheDepth = 2;
 
-/**
- * Kept for extension compatibility; see $wgParserCacheType
- * @deprecated since 1.26
- */
-$wgEnableParserCache = true;
-
 /**
  * Append a configured value to the parser cache and the sitenotice key so
  * that they can be kept separate for some class of activity.
index 4ebe426..23342e9 100644 (file)
@@ -194,10 +194,6 @@ if ( $wgGitInfoCacheDirectory === false && $wgCacheDirectory !== false ) {
        $wgGitInfoCacheDirectory = "{$wgCacheDirectory}/gitinfo";
 }
 
-if ( $wgEnableParserCache === false ) {
-       $wgParserCacheType = CACHE_NONE;
-}
-
 // Fix path to icon images after they were moved in 1.24
 if ( $wgRightsIcon ) {
        $wgRightsIcon = str_replace(
index c538ee7..e9adb7e 100644 (file)
@@ -120,12 +120,12 @@ class LocalPasswordPrimaryAuthenticationProvider
                }
 
                $pwhash = $this->getPassword( $row->user_password );
-               if ( !$pwhash->equals( $req->password ) ) {
+               if ( !$pwhash->verify( $req->password ) ) {
                        if ( $this->config->get( 'LegacyEncoding' ) ) {
                                // Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
                                // Check for this with iconv
                                $cp1252Password = iconv( 'UTF-8', 'WINDOWS-1252//TRANSLIT', $req->password );
-                               if ( $cp1252Password === $req->password || !$pwhash->equals( $cp1252Password ) ) {
+                               if ( $cp1252Password === $req->password || !$pwhash->verify( $cp1252Password ) ) {
                                        return $this->failResponse( $req );
                                }
                        } else {
index 0ef13b3..045f791 100644 (file)
@@ -146,7 +146,7 @@ class TemporaryPasswordPrimaryAuthenticationProvider
                }
 
                $pwhash = $this->getPassword( $row->user_newpassword );
-               if ( !$pwhash->equals( $req->password ) ) {
+               if ( !$pwhash->verify( $req->password ) ) {
                        return $this->failResponse( $req );
                }
 
index e45b774..978118f 100644 (file)
@@ -41,6 +41,10 @@ class InvalidPassword extends Password {
                return false;
        }
 
+       public function verify( $password ) {
+               return false;
+       }
+
        public function needsUpdate() {
                return false;
        }
index c8a0267..f167f95 100644 (file)
@@ -20,6 +20,8 @@
  * @file
  */
 
+use Wikimedia\Assert\Assert;
+
 /**
  * Represents a password hash for use in authentication
  *
@@ -147,21 +149,38 @@ abstract class Password {
         * Password::toString() for each object. This can be overridden to do
         * custom comparison, but it is not recommended unless necessary.
         *
+        * @deprecated since 1.33, use verify()
+        *
         * @param Password|string $other The other password
         * @return bool True if equal, false otherwise
         */
        public function equals( $other ) {
-               if ( !$other instanceof self ) {
-                       // No need to use the factory because we're definitely making
-                       // an object of the same type.
-                       $obj = clone $this;
-                       $obj->crypt( $other );
-                       $other = $obj;
+               if ( is_string( $other ) ) {
+                       return $this->verify( $other );
                }
 
                return hash_equals( $this->toString(), $other->toString() );
        }
 
+       /**
+        * Checks whether the given password matches the hash stored in this object.
+        *
+        * @param string $password Password to check
+        * @return bool
+        */
+       public function verify( $password ) {
+               Assert::parameter( is_string( $password ),
+                       '$password', 'must be string, actual: ' . gettype( $password )
+               );
+
+               // No need to use the factory because we're definitely making
+               // an object of the same type.
+               $obj = clone $this;
+               $obj->crypt( $password );
+
+               return hash_equals( $this->toString(), $obj->toString() );
+       }
+
        /**
         * Convert this hash to a string that can be stored in the database
         *
index 78a1104..df9bb96 100644 (file)
@@ -72,6 +72,21 @@ class RemexCompatMunger implements TreeHandler {
                "mark" => true,
        ];
 
+       /**
+        * For the purposes of this class, "metadata" elements are those that
+        * should neither trigger p-wrapping nor stop an outer p-wrapping,
+        * typically those that are themselves invisible in a browser's rendering.
+        * This isn't a complete list, it's just the tags that we're likely to
+        * encounter in practice.
+        * @var array
+        */
+       private static $metadataElements = [
+               'style' => true,
+               'script' => true,
+               'link' => true,
+               'meta' => true,
+       ];
+
        private static $formattingElements = [
                'a' => true,
                'b' => true,
@@ -261,7 +276,11 @@ class RemexCompatMunger implements TreeHandler {
                $under = $preposition === TreeBuilder::UNDER;
                $elementToEnd = null;
 
-               if ( $under && $parentData->isPWrapper && !$inline ) {
+               if ( isset( self::$metadataElements[$elementName] ) ) {
+                       // The element is a metadata element, that we allow to appear in
+                       // both inline and block contexts.
+                       $this->trace( 'insert metadata' );
+               } elseif ( $under && $parentData->isPWrapper && !$inline ) {
                        // [B/b] The element is non-inline and the parent is a p-wrapper,
                        // close the parent and insert into its parent instead
                        $this->trace( 'insert B/b' );
index b83c209..e8cd94a 100644 (file)
@@ -506,7 +506,7 @@ class BotPassword implements IDBAccessObject {
                        return self::loginHook( $user, $bp,
                                Status::newFatal( 'botpasswords-needs-reset', $name, $appId ) );
                }
-               if ( !$passwordObj->equals( $password ) ) {
+               if ( !$passwordObj->verify( $password ) ) {
                        return self::loginHook( $user, $bp, Status::newFatal( 'wrongpassword' ) );
                }
 
index d34e183..26d5217 100644 (file)
@@ -39,7 +39,7 @@ tap:
        ${PU} --tap
 
 coverage:
-       ${PU} --coverage-html ../../docs/code-coverage
+       ${PU} --coverage-html ../../docs/coverage
 
 parser:
        ${PU} --group Parser
index 952a662..773bd51 100644 (file)
@@ -143,7 +143,7 @@ class TestUser {
                }
 
                $passwordFactory = MediaWikiServices::getInstance()->getPasswordFactory();
-               if ( !$passwordFactory->newFromCiphertext( $row->user_password )->equals( $password ) ) {
+               if ( !$passwordFactory->newFromCiphertext( $row->user_password )->verify( $password ) ) {
                        $passwordHash = $passwordFactory->newFromPlaintext( $password );
                        $dbw->update(
                                'user',
index 6a965a0..0f848ab 100644 (file)
@@ -58,6 +58,6 @@ class LayeredParameterizedPasswordTest extends PasswordTestCase {
                $totalPassword = $this->passwordFactory->newFromType( 'testLargeLayeredTop' );
                $totalPassword->partialCrypt( $partialPassword );
 
-               $this->assertTrue( $totalPassword->equals( 'testPassword123' ) );
+               $this->assertTrue( $totalPassword->verify( 'testPassword123' ) );
        }
 }
index 7afdd0a..384db5f 100644 (file)
@@ -60,9 +60,9 @@ abstract class PasswordTestCase extends MediaWikiTestCase {
         * @dataProvider providePasswordTests
         */
        public function testHashing( $shouldMatch, $hash, $password ) {
-               $hash = $this->passwordFactory->newFromCiphertext( $hash );
-               $password = $this->passwordFactory->newFromPlaintext( $password, $hash );
-               $this->assertSame( $shouldMatch, $hash->equals( $password ) );
+               $fromHash = $this->passwordFactory->newFromCiphertext( $hash );
+               $fromPassword = $this->passwordFactory->newFromPlaintext( $password, $fromHash );
+               $this->assertSame( $shouldMatch, $fromHash->equals( $fromPassword ) );
        }
 
        /**
@@ -72,7 +72,7 @@ abstract class PasswordTestCase extends MediaWikiTestCase {
                $hashObj = $this->passwordFactory->newFromCiphertext( $hash );
                $serialized = $hashObj->toString();
                $unserialized = $this->passwordFactory->newFromCiphertext( $serialized );
-               $this->assertTrue( $hashObj->equals( $unserialized ) );
+               $this->assertEquals( $hashObj->toString(), $unserialized->toString() );
        }
 
        /**
index a5ebaa5..faa9aa1 100644 (file)
@@ -262,6 +262,26 @@ class RemexDriverTest extends MediaWikiTestCase {
                        '<i><blockquote><p></i>',
                        '<i></i><blockquote><p><i></i></p><p><i></i></p></blockquote>',
                ],
+               [
+                       'style tag isn\'t p-wrapped (T186965)',
+                       '<style>/* ... */</style>',
+                       '<style>/* ... */</style>',
+               ],
+               [
+                       'link tag isn\'t p-wrapped (T186965)',
+                       '<link rel="foo" href="bar" />',
+                       '<link rel="foo" href="bar" />',
+               ],
+               [
+                       'style tag doesn\'t split p-wrapping (T208901)',
+                       'foo <style>/* ... */</style> bar',
+                       '<p>foo <style>/* ... */</style> bar</p>',
+               ],
+               [
+                       'link tag doesn\'t split p-wrapping (T208901)',
+                       'foo <link rel="foo" href="bar" /> bar',
+                       '<p>foo <link rel="foo" href="bar" /> bar</p>',
+               ],
        ];
 
        public function provider() {