Merge "user: Allow "CAS update failed" exceptions to be normalised"
[lhc/web/wiklou.git] / includes / Title.php
index e74824c..bbc1d63 100644 (file)
@@ -134,8 +134,15 @@ class Title implements LinkTarget {
        /** @var bool Boolean for initialisation on demand */
        public $mRestrictionsLoaded = false;
 
-       /** @var string Text form including namespace/interwiki, initialised on demand */
-       protected $mPrefixedText = null;
+       /**
+        * Text form including namespace/interwiki, initialised on demand
+        *
+        * Only public to share cache with TitleFormatter
+        *
+        * @private
+        * @var string
+        */
+       public $prefixedText = null;
 
        /** @var mixed Cached value for getTitleProtection (create protection) */
        public $mTitleProtection;
@@ -1473,6 +1480,22 @@ class Title implements LinkTarget {
                );
        }
 
+       /**
+        * Is this a message which can contain raw HTML?
+        *
+        * @return bool
+        * @since 1.32
+        */
+       public function isRawHtmlMessage() {
+               global $wgRawHtmlMessages;
+
+               if ( !$this->inNamespace( NS_MEDIAWIKI ) ) {
+                       return false;
+               }
+               $message = lcfirst( $this->getRootTitle()->getDBkey() );
+               return in_array( $message, $wgRawHtmlMessages, true );
+       }
+
        /**
         * Is this a talk page of some sort?
         *
@@ -1642,7 +1665,7 @@ class Title implements LinkTarget {
                        if ( $nsText === false ) {
                                // See T165149. Awkward, but better than erroneously linking to the main namespace.
                                $nsText = MediaWikiServices::getInstance()->getContentLanguage()->
-                                       getNsText( NS_SPECIAL ) .  ":Badtitle/NS{$this->mNamespace}";
+                                       getNsText( NS_SPECIAL ) . ":Badtitle/NS{$this->mNamespace}";
                        }
 
                        $p .= $nsText . ':';
@@ -1669,12 +1692,12 @@ class Title implements LinkTarget {
         * @return string The prefixed title, with spaces
         */
        public function getPrefixedText() {
-               if ( $this->mPrefixedText === null ) {
+               if ( $this->prefixedText === null ) {
                        $s = $this->prefix( $this->mTextform );
                        $s = strtr( $s, '_', ' ' );
-                       $this->mPrefixedText = $s;
+                       $this->prefixedText = $s;
                }
-               return $this->mPrefixedText;
+               return $this->prefixedText;
        }
 
        /**
@@ -2385,6 +2408,13 @@ class Title implements LinkTarget {
                                $error = [ 'sitejsonprotected', $action ];
                        } elseif ( $this->isSiteJsConfigPage() && !$user->isAllowed( 'editsitejs' ) ) {
                                $error = [ 'sitejsprotected', $action ];
+                       } elseif ( $this->isRawHtmlMessage() ) {
+                               // Raw HTML can be used to deploy CSS or JS so require rights for both.
+                               if ( !$user->isAllowed( 'editsitejs' ) ) {
+                                       $error = [ 'sitejsprotected', $action ];
+                               } elseif ( !$user->isAllowed( 'editsitecss' ) ) {
+                                       $error = [ 'sitecssprotected', $action ];
+                               }
                        }
 
                        if ( $error ) {
@@ -2416,25 +2446,34 @@ class Title implements LinkTarget {
                # Protect css/json/js subpages of user pages
                # XXX: this might be better using restrictions
 
-               if ( $action != 'patrol' ) {
-                       if ( preg_match( '/^' . preg_quote( $user->getName(), '/' ) . '\//', $this->mTextform ) ) {
-                               if (
-                                       $this->isUserCssConfigPage()
-                                       && !$user->isAllowedAny( 'editmyusercss', 'editusercss' )
-                               ) {
-                                       $errors[] = [ 'mycustomcssprotected', $action ];
-                               } elseif (
-                                       $this->isUserJsonConfigPage()
-                                       && !$user->isAllowedAny( 'editmyuserjson', 'edituserjson' )
-                               ) {
-                                       $errors[] = [ 'mycustomjsonprotected', $action ];
-                               } elseif (
-                                       $this->isUserJsConfigPage()
-                                       && !$user->isAllowedAny( 'editmyuserjs', 'edituserjs' )
-                               ) {
-                                       $errors[] = [ 'mycustomjsprotected', $action ];
-                               }
-                       } else {
+               if ( $action === 'patrol' ) {
+                       return [];
+               }
+
+               if ( preg_match( '/^' . preg_quote( $user->getName(), '/' ) . '\//', $this->mTextform ) ) {
+                       // Users need editmyuser* to edit their own CSS/JSON/JS subpages.
+                       if (
+                               $this->isUserCssConfigPage()
+                               && !$user->isAllowedAny( 'editmyusercss', 'editusercss' )
+                       ) {
+                               $errors[] = [ 'mycustomcssprotected', $action ];
+                       } elseif (
+                               $this->isUserJsonConfigPage()
+                               && !$user->isAllowedAny( 'editmyuserjson', 'edituserjson' )
+                       ) {
+                               $errors[] = [ 'mycustomjsonprotected', $action ];
+                       } elseif (
+                               $this->isUserJsConfigPage()
+                               && !$user->isAllowedAny( 'editmyuserjs', 'edituserjs' )
+                       ) {
+                               $errors[] = [ 'mycustomjsprotected', $action ];
+                       }
+               } else {
+                       // Users need editmyuser* to edit their own CSS/JSON/JS subpages, except for
+                       // deletion/suppression which cannot be used for attacks and we want to avoid the
+                       // situation where an unprivileged user can post abusive content on their subpages
+                       // and only very highly privileged users could remove it.
+                       if ( !in_array( $action, [ 'delete', 'deleterevision', 'suppressrevision' ], true ) ) {
                                if (
                                        $this->isUserCssConfigPage()
                                        && !$user->isAllowed( 'editusercss' )