* Respect read-only mode on block removals
[lhc/web/wiklou.git] / includes / EditPage.php
index 1726381..544e2bc 100644 (file)
@@ -150,11 +150,13 @@ class EditPage {
                        $wgOut->readOnlyPage( $this->mArticle->getContent( true ), true );
                        return;
                }
-               if ( $wgUser->isBlocked() ) {
+               if ( !$this->preview && $wgUser->isBlocked( !$this->save ) ) {
+                       # When previewing, don't check blocked state - will get caught at save time.
+                       # Also, check when starting edition is done against slave to improve performance.
                        $this->blockedIPpage();
                        return;
                }
-               if ( !$wgUser->getID() && $wgWhitelistEdit ) {
+               if ( $wgUser->isAnon() && $wgWhitelistEdit ) {
                        $this->userNotLoggedInPage();
                        return;
                }
@@ -184,21 +186,51 @@ class EditPage {
         * @todo document
         */
        function importFormData( &$request ) {
-               # These fields need to be checked for encoding.
-               # Also remove trailing whitespace, but don't remove _initial_
-               # whitespace from the text boxes. This may be significant formatting.
-               $this->textbox1 = rtrim( $request->getText( 'wpTextbox1' ) );
-               $this->textbox2 = rtrim( $request->getText( 'wpTextbox2' ) );
-               $this->mMetaData = rtrim( $request->getText( 'metadata' ) );
-               $this->summary = trim( $request->getText( 'wpSummary' ) );
-
-               $this->edittime = $request->getVal( 'wpEdittime' );
-               if( !preg_match( '/^\d{14}$/', $this->edittime )) $this->edittime = '';
-
-               $this->preview = $request->getCheck( 'wpPreview' );
-               $this->save = $request->wasPosted() && !$this->preview;
-               $this->minoredit = $request->getCheck( 'wpMinoredit' );
-               $this->watchthis = $request->getCheck( 'wpWatchthis' );
+               if( $request->wasPosted() ) {
+                       # These fields need to be checked for encoding.
+                       # Also remove trailing whitespace, but don't remove _initial_
+                       # whitespace from the text boxes. This may be significant formatting.
+                       $this->textbox1  = rtrim( $request->getText( 'wpTextbox1' ) );
+                       $this->textbox2  = rtrim( $request->getText( 'wpTextbox2' ) );
+                       $this->mMetaData = rtrim( $request->getText( 'metadata'   ) );
+                       $this->summary   =  trim( $request->getText( 'wpSummary'  ) );
+       
+                       $this->edittime = $request->getVal( 'wpEdittime' );
+                       if( is_null( $this->edittime ) ) {
+                               # If the form is incomplete, force to preview.
+                               $this->preview  = true;
+                       } else {
+                               if( $this->tokenOk( $request ) ) {
+                                       # Some browsers will not report any submit button
+                                       # if the user hits enter in the comment box.
+                                       # The unmarked state will be assumed to be a save,
+                                       # if the form seems otherwise complete.
+                                       $this->preview = $request->getCheck( 'wpPreview' );
+                               } else {
+                                       # Page might be a hack attempt posted from
+                                       # an external site. Preview instead of saving.
+                                       $this->preview = true;
+                               }
+                       }
+                       $this->save    = !$this->preview;
+                       if( !preg_match( '/^\d{14}$/', $this->edittime )) {
+                               $this->edittime = null;
+                       }
+       
+                       $this->minoredit = $request->getCheck( 'wpMinoredit' );
+                       $this->watchthis = $request->getCheck( 'wpWatchthis' );
+               } else {
+                       # Not a posted form? Start with nothing.
+                       $this->textbox1  = '';
+                       $this->textbox2  = '';
+                       $this->mMetaData = '';
+                       $this->summary   = '';
+                       $this->edittime  = '';
+                       $this->preview   = false;
+                       $this->save      = false;
+                       $this->minoredit = false;
+                       $this->watchthis = false;
+               }
 
                $this->oldid = $request->getInt( 'oldid' );
 
@@ -209,15 +241,24 @@ class EditPage {
        }
 
        /**
-        * Since there is only one text field on the edit form,
-        * pressing <enter> will cause the form to be submitted, but
-        * the submit button value won't appear in the query, so we
-        * Fake it here before going back to edit().  This is kind of
-        * ugly, but it helps some old URLs to still work.
+        * Make sure the form isn't faking a user's credentials.
+        *
+        * @param WebRequest $request
+        * @return bool
+        * @access private
         */
+       function tokenOk( &$request ) {
+               global $wgUser;
+               if( $wgUser->isAnon() ) {
+                       # Anonymous users may not have a session
+                       # open. Don't tokenize.
+                       return true;
+               } else {
+                       return $wgUser->matchEditToken( $request->getVal( 'wpEditToken' ) );
+               }
+       }
+       
        function submit() {
-               if( !$this->preview ) $this->save = true;
-
                $this->edit();
        }
 
@@ -242,13 +283,14 @@ class EditPage {
                $sk = $wgUser->getSkin();
                $isConflict = false;
                // css / js subpages of user pages get a special treatment
-               $isCssJsSubpage = (Namespace::getUser() == $wgTitle->getNamespace() and preg_match("/\\.(css|js)$/", $wgTitle->getText() ));
+               $isCssJsSubpage = $wgTitle->isCssJsSubpage();
+               
 
                if(!$this->mTitle->getArticleID()) { # new article
                        $wgOut->addWikiText(wfmsg('newarticletext'));
                }
 
-               if( Namespace::isTalk( $this->mTitle->getNamespace() ) ) {
+               if( $this->mTitle->isTalkPage() ) {
                        $wgOut->addWikiText(wfmsg('talkpagetext'));
                }
 
@@ -271,11 +313,12 @@ class EditPage {
                                # Error messages or other handling should be performed by the filter function
                                return;
                        }
-                       if ( $wgUser->isBlocked() ) {
+                       if ( $wgUser->isBlocked( false ) ) {
+                               # Check block state against master, thus 'false'.
                                $this->blockedIPpage();
                                return;
                        }
-                       if ( !$wgUser->getID() && $wgWhitelistEdit ) {
+                       if ( $wgUser->isAnon() && $wgWhitelistEdit ) {
                                $this->userNotLoggedInPage();
                                return;
                        }
@@ -498,7 +541,7 @@ class EditPage {
 
                $minoredithtml = '';
 
-               if ( 0 != $wgUser->getID() || $wgAllowAnonymousMinor ) {
+               if ( $wgUser->isLoggedIn() || $wgAllowAnonymousMinor ) {
                        $minoredithtml =
                                "<input tabindex='3' type='checkbox' value='1' name='wpMinoredit'".($this->minoredit?" checked='checked'":"").
                                " accesskey='".wfMsg('accesskey-minoredit')."' id='wpMinoredit' />".
@@ -507,7 +550,7 @@ class EditPage {
 
                $watchhtml = '';
 
-               if ( 0 != $wgUser->getID() ) {
+               if ( $wgUser->isLoggedIn() ) {
                        $watchhtml = "<input tabindex='4' type='checkbox' name='wpWatchthis'".($this->watchthis?" checked='checked'":"").
                                " accesskey='".wfMsg('accesskey-watch')."' id='wpWatchthis'  />".
                                "<label for='wpWatchthis' title='".wfMsg('tooltip-watch')."'>{$watchthis}</label>";
@@ -541,24 +584,27 @@ class EditPage {
                        $wgOut->setOnloadHandler( 'document.editform.wpTextbox1.focus()' );
                }
                # Prepare a list of templates used by this page
-               $db =& wfGetDB( DB_SLAVE );
-               $page = $db->tableName( 'page' );
-               $links = $db->tableName( 'links' );
+               $templates = '';
                $id = $this->mTitle->getArticleID();
-               $sql = "SELECT page_namespace,page_title,page_id ".
-                       "FROM $page,$links WHERE l_to=page_id AND l_from={$id} and page_namespace=".NS_TEMPLATE;
-               $res = $db->query( $sql, "EditPage::editform" );
-
-               if ( $db->numRows( $res ) ) {
-                       $templates = '<br />'. wfMsg( 'templatesused' ) . '<ul>';
-                       while ( $row = $db->fetchObject( $res ) ) {
-                               if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) {
-                                       $templates .= '<li>' . $sk->makeLinkObj( $titleObj ) . '</li>';
+               if ( 0 !== $id ) {
+                       $db =& wfGetDB( DB_SLAVE );
+                       $page = $db->tableName( 'page' );
+                       $links = $db->tableName( 'links' );
+                       $sql = "SELECT page_namespace,page_title,page_id ".
+                               "FROM $page,$links WHERE l_to=page_id AND l_from={$id} and page_namespace=".NS_TEMPLATE;
+                       $res = $db->query( $sql, "EditPage::editform" );
+                       if ( false !== $res ) {
+                               if ( $db->numRows( $res ) ) {
+                                       $templates = '<br />'. wfMsg( 'templatesused' ) . '<ul>';
+                                       while ( $row = $db->fetchObject( $res ) ) {
+                                               if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) {
+                                                       $templates .= '<li>' . $sk->makeLinkObj( $titleObj ) . '</li>';
+                                               }
+                                       }
+                                       $templates .= '</ul>';
                                }
+                               $db->freeResult( $res );
                        }
-                       $templates .= '</ul>';
-               } else {        
-                       $templates = '';
                }
                
                global $wgLivePreview, $wgStylePath;
@@ -617,6 +663,21 @@ END
 <input type='hidden' value=\"" . htmlspecialchars( $this->section ) . "\" name=\"wpSection\" />
 <input type='hidden' value=\"{$this->edittime}\" name=\"wpEdittime\" />\n" );
 
+               if ( $wgUser->isLoggedIn() ) {
+                       /**
+                        * To make it harder for someone to slip a user a page
+                        * which submits an edit form to the wiki without their
+                        * knowledge, a random token is associated with the login
+                        * session. If it's not passed back with the submission,
+                        * we won't save the page, or render user JavaScript and
+                        * CSS previews.
+                        */
+                       $token = htmlspecialchars( $wgUser->editToken() );
+                       $wgOut->addHTML( "
+<input type='hidden' value=\"$token\" name=\"wpEditToken\" />\n" );
+               }
+               
+               
                if ( $isConflict ) {
                        require_once( "DifferenceEngine.php" );
                        $wgOut->addHTML( "<h2>" . wfMsg( "yourdiff" ) . "</h2>\n" );
@@ -637,10 +698,10 @@ END
 
        function getPreviewText( $isConflict, $isCssJsSubpage ) {
                global $wgOut, $wgUser, $wgTitle, $wgParser;
-               $previewhead='<h2>' . wfMsg( 'preview' ) . "</h2>\n<p><center><font color=\"#cc0000\">" .
-                       wfMsg( 'note' ) . wfMsg( 'previewnote' ) . "</font></center></p>\n";
+               $previewhead = '<h2>' . htmlspecialchars( wfMsg( 'preview' ) ) . "</h2>\n" .
+                       "<p class='previewnote'>" . htmlspecialchars( wfMsg( 'previewnote' ) ) . "</p>\n";
                if ( $isConflict ) {
-                       $previewhead.='<h2>' . wfMsg( 'previewconflict' ) .
+                       $previewhead.='<h2>' . htmlspecialchars( wfMsg( 'previewconflict' ) ) .
                                "</h2>\n";
                }
 
@@ -659,6 +720,7 @@ END
                        }
                        $parserOutput = $wgParser->parse( $previewtext , $wgTitle, $parserOptions );
                        $wgOut->addHTML( $parserOutput->mText );
+                       return $previewhead;
                } else {
                        # if user want to see preview when he edit an article
                        if( $wgUser->getOption('previewonfirst') and ($this->textbox1 == '')) {
@@ -674,8 +736,8 @@ END
                        $previewHTML = $parserOutput->mText;
                        $wgOut->addCategoryLinks($parserOutput->getCategoryLinks());
                        $wgOut->addLanguageLinks($parserOutput->getLanguageLinks());
+                       return $previewhead . $previewHTML;
                }
-               return $previewhead . $previewHTML;
        }
        
        /**
@@ -697,7 +759,7 @@ END
                } else {
                        $name = $id;
                }
-               $link = '[[' . $wgContLang->getNsText( Namespace::getUser() ) .
+               $link = '[[' . $wgContLang->getNsText( NS_USER ) .
                  ":{$name}|{$name}]]";
 
                $wgOut->addWikiText( wfMsg( 'blockedtext', $link, $reason, $ip, $name ) );
@@ -708,7 +770,7 @@ END
         * @todo document
         */
        function userNotLoggedInPage() {
-               global $wgOut, $wgUser;
+               global $wgOut;
 
                $wgOut->setPageTitle( wfMsg( 'whitelistedittitle' ) );
                $wgOut->setRobotpolicy( 'noindex,nofollow' );