Merge "Special:Search: Remove token from URL when saving settings"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 18 Aug 2014 18:30:03 +0000 (18:30 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 18 Aug 2014 18:30:03 +0000 (18:30 +0000)
1  2 
includes/specials/SpecialSearch.php

@@@ -82,8 -82,7 +82,8 @@@ class SpecialSearch extends SpecialPag
                $out = $this->getOutput();
                $out->allowClickjacking();
                $out->addModuleStyles( array(
 -                      'mediawiki.special', 'mediawiki.special.search', 'mediawiki.ui', 'mediawiki.ui.button'
 +                      'mediawiki.special', 'mediawiki.special.search', 'mediawiki.ui', 'mediawiki.ui.button',
 +                      'mediawiki.ui.input',
                ) );
  
                // Strip underscores from title parameter; most of the time we'll want
                $search = str_replace( "\n", " ", $request->getText( 'search', $titleParam ) );
  
                $this->load();
+               if ( !is_null( $request->getVal( 'nsRemember' ) ) ) {
+                       $this->saveNamespaces();
+                       // Remove the token from the URL to prevent the user from inadvertently
+                       // exposing it (e.g. by pasting it into a public wiki page) or undoing
+                       // later settings changes (e.g. by reloading the page).
+                       $query = $request->getValues();
+                       unset( $query['title'], $query['nsRemember'] );
+                       $out->redirect( $this->getPageTitle()->getFullURL( $query ) );
+                       return;
+               }
  
                $this->searchEngineType = $request->getVal( 'srbackend' );
  
                # No match, generate an edit URL
                $title = Title::newFromText( $term );
                if ( !is_null( $title ) ) {
 -                      global $wgGoToEdit;
                        wfRunHooks( 'SpecialSearchNogomatch', array( &$title ) );
                        wfDebugLog( 'nogomatch', $title->getFullText(), 'private' );
  
                        # If the feature is enabled, go straight to the edit page
 -                      if ( $wgGoToEdit ) {
 +                      if ( $this->getConfig()->get( 'GoToEdit' ) ) {
                                $this->getOutput()->redirect( $title->getFullURL( array( 'action' => 'edit' ) ) );
  
                                return;
         * @param string $term
         */
        public function showResults( $term ) {
 -              global $wgDisableTextSearch, $wgSearchForwardUrl, $wgContLang, $wgScript;
 +              global $wgContLang;
  
                $profile = new ProfileSection( __METHOD__ );
                $search = $this->getSearchEngine();
                $search->setLimitOffset( $this->limit, $this->offset );
                $search->setNamespaces( $this->namespaces );
-               $this->saveNamespaces();
                $search->prefix = $this->mPrefix;
                $term = $search->transformSearchTerm( $term );
  
  
                $out = $this->getOutput();
  
 -              if ( $wgDisableTextSearch ) {
 -                      if ( $wgSearchForwardUrl ) {
 -                              $url = str_replace( '$1', urlencode( $term ), $wgSearchForwardUrl );
 +              if ( $this->getConfig()->get( 'DisableTextSearch' ) ) {
 +                      $searchFowardUrl = $this->getConfig()->get( 'SearchForwardUrl' );
 +                      if ( $searchFowardUrl ) {
 +                              $url = str_replace( '$1', urlencode( $term ), $searchFowardUrl );
                                $out->redirect( $url );
                        } else {
                                $out->addHTML(
                                array(
                                        'id' => ( $this->profile === 'advanced' ? 'powersearch' : 'search' ),
                                        'method' => 'get',
 -                                      'action' => $wgScript
 +                                      'action' => wfScript(),
                                )
                        )
                );
                        // Show the create link ahead
                        $this->showCreateLink( $title, $num, $titleMatches, $textMatches );
                        if ( $totalRes > $this->limit || $this->offset ) {
 +                              if ( $this->searchEngineType !== null ) {
 +                                      $this->setExtraParam( 'srbackend', $this->searchEngineType );
 +                              }
                                $prevnext = $this->getLanguage()->viewPrevNext(
                                        $this->getPageTitle(),
                                        $this->offset,
         * @param Title $title
         * @param int $num The number of search results found
         * @param null|SearchResultSet $titleMatches Results from title search
 -       * @param null|SearchResultSet $textMatches  Results from text search
 +       * @param null|SearchResultSet $textMatches Results from text search
         */
        protected function showCreateLink( $title, $num, $titleMatches, $textMatches ) {
                // show direct page/create link if applicable
                        return;
                }
  
 +              $linkClass = 'mw-search-createlink';
                if ( $title->isKnown() ) {
                        $messageName = 'searchmenu-exists';
 +                      $linkClass = 'mw-search-exists';
                } elseif ( $title->quickUserCan( 'create', $this->getUser() ) ) {
                        $messageName = 'searchmenu-new';
                } else {
  
                // Extensions using the hook might still return an empty $messageName
                if ( $messageName ) {
 -                      $this->getOutput()->wrapWikiMsg( "<p class=\"mw-search-createlink\">\n$1</p>", $params );
 +                      $this->getOutput()->wrapWikiMsg( "<p class=\"$linkClass\">\n$1</p>", $params );
                } else {
                        // preserve the paragraph for margins etc...
                        $this->getOutput()->addHtml( '<p></p>' );
                $request = $this->getRequest();
  
                if ( $user->isLoggedIn() &&
-                       !is_null( $request->getVal( 'nsRemember' ) ) &&
                        $user->matchEditToken(
-                               $request->getVal( 'nsToken' ),
+                               $request->getVal( 'nsRemember' ),
                                'searchnamespace',
                                $request
                        )
                        foreach ( MWNamespace::getValidNamespaces() as $n ) {
                                $user->setOption( 'searchNs' . $n, false );
                        }
-                       // The request parameters include all the namespaces we just searched.
+                       // The request parameters include all the namespaces to be searched.
                        // Even if they're the same as an existing profile, they're not eaten.
                        foreach ( $this->namespaces as $n ) {
                                $user->setOption( 'searchNs' . $n, true );
  
                $lang = $this->getLanguage();
  
 -              // format score
 -              if ( is_null( $result->getScore() ) ) {
 -                      // Search engine doesn't report scoring info
 -                      $score = '';
 -              } else {
 -                      $percent = sprintf( '%2.1f', $result->getScore() * 100 );
 -                      $score = $this->msg( 'search-result-score' )->numParams( $percent )->text()
 -                              . ' - ';
 -              }
 -
                // format description
                $byteSize = $result->getByteSize();
                $wordCount = $result->getWordCount();
                                                $thumb->toHtml( array( 'desc-link' => true ) ) .
                                                '</td>' .
                                                '<td style="vertical-align: top;">' .
 -                                              "{$link} {$fileMatch}" .
 +                                              "{$link} {$redirect} {$section} {$fileMatch}" .
                                                $extract .
 -                                              "<div class='mw-search-result-data'>{$score}{$desc} - {$date}{$related}</div>" .
 +                                              "<div class='mw-search-result-data'>{$desc} - {$date}{$related}</div>" .
                                                '</td>' .
                                                '</tr>' .
                                                '</table>' .
  
                $html = null;
  
 +              $score = '';
                if ( wfRunHooks( 'ShowSearchHit', array(
                        $this, $result, $terms,
                        &$link, &$redirect, &$section, &$extract,
                ) ) ) {
                        $html = "<li><div class='mw-search-result-heading'>" .
                                "{$link} {$redirect} {$section} {$fileMatch}</div> {$extract}\n" .
 -                              "<div class='mw-search-result-data'>{$score}{$size} - {$date}{$related}</div>" .
 +                              "<div class='mw-search-result-data'>{$size} - {$date}{$related}</div>" .
                                "</li>\n";
                }
  
         * @param SearchResult $result
         * @param string $lastInterwiki
         * @param string $query
 -       * @param array $customCaptions iw prefix -> caption
 +       * @param array $customCaptions Interwiki prefix -> caption
         *
         * @return string
         */
                        }
  
                        $rows[$subject] .=
 -                              Xml::openElement(
 -                                      'td', array( 'style' => 'white-space: nowrap' )
 -                              ) .
 +                              Xml::openElement( 'td' ) .
                                Xml::checkLabel(
                                        $name,
                                        "ns{$namespace}",
                $remember = '';
                $user = $this->getUser();
                if ( $user->isLoggedIn() ) {
-                       $remember .= Html::hidden(
-                               'nsToken',
-                               $user->getEditToken(
-                                       'searchnamespace',
-                                       $this->getRequest()
-                               )
-                       ) .
-                       Xml::checkLabel(
+                       $remember .= Xml::checkLabel(
                                wfMessage( 'powersearch-remember' )->text(),
                                'nsRemember',
                                'mw-search-powersearch-remember',
-                               false
+                               false,
+                               // The token goes here rather than in a hidden field so it
+                               // is only sent when necessary (not every form submission).
+                               array( 'value' => $user->getEditToken(
+                                       'searchnamespace',
+                                       $this->getRequest()
+                               ) )
                        );
                }
  
                // Return final output
 -              return Xml::openElement(
 -                      'fieldset',
 -                      array( 'id' => 'mw-searchoptions', 'style' => 'margin:0em;' )
 -              ) .
 +              return Xml::openElement( 'fieldset', array( 'id' => 'mw-searchoptions' ) ) .
                        Xml::element( 'legend', null, $this->msg( 'powersearch-legend' )->text() ) .
                        Xml::tags( 'h4', null, $this->msg( 'powersearch-ns' )->parse() ) .
 -                      Html::element( 'div', array( 'id' => 'mw-search-togglebox' ) ) .
 +                      Xml::element( 'div', array( 'id' => 'mw-search-togglebox' ), '', false ) .
                        Xml::element( 'div', array( 'class' => 'divider' ), '', false ) .
                        implode( Xml::element( 'div', array( 'class' => 'divider' ), '', false ), $showSections ) .
                        $hidden .
  
        /**
         * @param string $term
 +       * @param int $resultsShown
 +       * @param int $totalNum
         * @return string
         */
        protected function shortDialog( $term, $resultsShown, $totalNum ) {
                        'id' => $this->profile === 'advanced' ? 'powerSearchText' : 'searchText',
                        'size' => '50',
                        'autofocus',
 -                      'class' => 'mw-ui-input',
 +                      'class' => 'mw-ui-input mw-ui-input-inline',
                ) ) . "\n";
                $out .= Html::hidden( 'fulltext', 'Search' ) . "\n";
                $out .= Xml::submitButton(
                ) . "\n";
  
                // Results-info
 -              if ( $totalNum > 0 ) {
 +              if ( $totalNum > 0 && $this->offset < $totalNum ) {
                        $top = $this->msg( 'showingresultsheader' )
                                ->numParams( $this->offset + 1, $this->offset + $resultsShown, $totalNum )
                                ->params( wfEscapeWikiText( $term ) )
                                ->numParams( $resultsShown )
                                ->parse();
                        $out .= Xml::tags( 'div', array( 'class' => 'results-info' ), $top ) .
 -                              Xml::element( 'div', array( 'style' => 'clear:both' ) );
 +                              Xml::element( 'div', array( 'style' => 'clear:both' ), '', false );
                }
  
                return $out . $this->didYouMeanHtml;