Merge "filebackend: Use HTTPFileStreamer::send404Message() in caller instead"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 13 Sep 2019 02:33:15 +0000 (02:33 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 13 Sep 2019 02:33:15 +0000 (02:33 +0000)
12 files changed:
includes/ServiceWiring.php
includes/StreamFile.php
includes/export/WikiExporter.php
includes/libs/filebackend/FSFileBackend.php
includes/libs/rdbms/lbfactory/LBFactoryMulti.php
includes/mail/UserMailer.php
includes/preferences/DefaultPreferencesFactory.php
resources/Resources.php
resources/src/mediawiki.ForeignApi.core.js
tests/phpunit/includes/preferences/DefaultPreferencesFactoryTest.php
tests/phpunit/maintenance/MWDoxygenFilterTest.php
tests/qunit/suites/resources/mediawiki.api/mediawiki.ForeignApi.test.js

index c7ad75c..689a98e 100644 (file)
@@ -542,7 +542,8 @@ return [
                        $services->getContentLanguage(),
                        AuthManager::singleton(),
                        $services->getLinkRendererFactory()->create(),
-                       $services->getNamespaceInfo()
+                       $services->getNamespaceInfo(),
+                       $services->getPermissionManager()
                );
                $factory->setLogger( LoggerFactory::getInstance( 'preferences' ) );
 
index dfe6bad..2afd651 100644 (file)
@@ -107,7 +107,6 @@ class StreamFile {
                                case 'png':
                                        return 'image/png';
                                case 'jpg':
-                                       return 'image/jpeg';
                                case 'jpeg':
                                        return 'image/jpeg';
                        }
index ec0b344..c1b3595 100644 (file)
@@ -30,6 +30,7 @@
 use MediaWiki\MediaWikiServices as MediaWikiServicesAlias;
 use MediaWiki\Storage\RevisionRecord;
 use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
 
 /**
  * @ingroup SpecialPage Dump
@@ -67,7 +68,7 @@ class WikiExporter {
        /** @var XmlDumpWriter */
        private $writer;
 
-       /** @var Database */
+       /** @var IDatabase */
        protected $db;
 
        /** @var array|int */
@@ -86,7 +87,7 @@ class WikiExporter {
        }
 
        /**
-        * @param Database $db
+        * @param IDatabase $db
         * @param int|array $history One of WikiExporter::FULL, WikiExporter::CURRENT,
         *   WikiExporter::RANGE or WikiExporter::STABLE, or an associative array:
         *   - offset: non-inclusive offset at which to start the query
@@ -303,29 +304,36 @@ class WikiExporter {
                if ( $cond ) {
                        $where[] = $cond;
                }
-               # Get logging table name for logging.* clause
-               $logging = $this->db->tableName( 'logging' );
-
                $result = null; // Assuring $result is not undefined, if exception occurs early
 
                $commentQuery = CommentStore::getStore()->getJoin( 'log_comment' );
                $actorQuery = ActorMigration::newMigration()->getJoin( 'log_user' );
 
+               $tables = array_merge(
+                       [ 'logging' ], $commentQuery['tables'], $actorQuery['tables'], [ 'user' ]
+               );
+               $fields = [
+                       'log_id', 'log_type', 'log_action', 'log_timestamp', 'log_namespace',
+                       'log_title', 'log_params', 'log_deleted', 'user_name'
+               ] + $commentQuery['fields'] + $actorQuery['fields'];
+               $options = [
+                       'ORDER BY' => 'log_id',
+                       'USE INDEX' => [ 'logging' => 'PRIMARY' ],
+                       'LIMIT' => self::BATCH_SIZE,
+               ];
+               $joins = [
+                       'user' => [ 'JOIN', 'user_id = ' . $actorQuery['fields']['log_user'] ]
+               ] + $commentQuery['joins'] + $actorQuery['joins'];
+
                $lastLogId = 0;
                while ( true ) {
                        $result = $this->db->select(
-                               array_merge( [ 'logging' ], $commentQuery['tables'], $actorQuery['tables'], [ 'user' ] ),
-                               [ "{$logging}.*", 'user_name' ] + $commentQuery['fields'] + $actorQuery['fields'],
+                               $tables,
+                               $fields,
                                array_merge( $where, [ 'log_id > ' . intval( $lastLogId ) ] ),
                                __METHOD__,
-                               [
-                                       'ORDER BY' => 'log_id',
-                                       'USE INDEX' => [ 'logging' => 'PRIMARY' ],
-                                       'LIMIT' => self::BATCH_SIZE,
-                               ],
-                               [
-                                       'user' => [ 'JOIN', 'user_id = ' . $actorQuery['fields']['log_user'] ]
-                               ] + $commentQuery['joins'] + $actorQuery['joins']
+                               $options,
+                               $joins
                        );
 
                        if ( !$result->numRows() ) {
index 9ed7ae3..26f3d3a 100644 (file)
@@ -73,7 +73,7 @@ class FSFileBackend extends FileBackendStore {
        /** @var string Required OS username to own files */
        protected $fileOwner;
 
-       /** @var bool Whether the OS is Windows (otherwise assumed Unix-like)*/
+       /** @var bool Whether the OS is Windows (otherwise assumed Unix-like) */
        protected $isWindows;
        /** @var string OS username running this script */
        protected $currentUser;
index 77b029f..5d33e69 100644 (file)
@@ -60,7 +60,7 @@ class LBFactoryMulti extends LBFactory {
        private $masterTemplateOverrides = [];
        /** @var array[] Map of (host => server config map overrides) for main and external servers */
        private $templateOverridesByServer = [];
-       /**  @var string[]|bool[] A map of section name to read-only message */
+       /** @var string[]|bool[] A map of section name to read-only message */
        private $readOnlyBySection = [];
 
        /** @var string An ILoadMonitor class */
@@ -85,7 +85,7 @@ class LBFactoryMulti extends LBFactory {
         * data can be before the load balancer tries to avoid using it. The map can have 'is static'
         * set to disable blocking  replication sync checks (intended for archive servers with
         * unchanging data).
-
+        *
         * @see LBFactory::__construct()
         * @param array $conf Additional parameters include:
         *   - hostsByName                 Optional (hostname => IP address) map.
index 47fa16f..0783068 100644 (file)
@@ -34,8 +34,8 @@ class UserMailer {
         * Send mail using a PEAR mailer
         *
         * @param Mail_smtp $mailer
-        * @param string $dest
-        * @param string $headers
+        * @param string[]|string $dest
+        * @param array $headers
         * @param string $body
         *
         * @return Status
@@ -382,6 +382,8 @@ class UserMailer {
                                throw new MWException( 'PEAR mail package is not installed' );
                        }
 
+                       $recips = array_map( 'strval', $to );
+
                        Wikimedia\suppressWarnings();
 
                        // Create the mail object using the Mail::factory method
@@ -397,13 +399,13 @@ class UserMailer {
                        $headers['Subject'] = self::quotedPrintable( $subject );
 
                        // When sending only to one recipient, shows it its email using To:
-                       if ( count( $to ) == 1 ) {
-                               $headers['To'] = $to[0]->toString();
+                       if ( count( $recips ) == 1 ) {
+                               $headers['To'] = $recips[0];
                        }
 
                        // Split jobs since SMTP servers tends to limit the maximum
                        // number of possible recipients.
-                       $chunks = array_chunk( $to, $wgEnotifMaxRecips );
+                       $chunks = array_chunk( $recips, $wgEnotifMaxRecips );
                        foreach ( $chunks as $chunk ) {
                                $status = self::sendWithPear( $mail_object, $chunk, $headers, $body );
                                // FIXME : some chunks might be sent while others are not!
index 66c2bc3..56db812 100644 (file)
@@ -20,7 +20,6 @@
 
 namespace MediaWiki\Preferences;
 
-use Config;
 use DateTime;
 use DateTimeZone;
 use Exception;
@@ -37,6 +36,7 @@ use MediaWiki\Auth\PasswordAuthenticationRequest;
 use MediaWiki\Config\ServiceOptions;
 use MediaWiki\Linker\LinkRenderer;
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Permissions\PermissionManager;
 use MessageLocalizer;
 use MWException;
 use MWTimestamp;
@@ -77,6 +77,9 @@ class DefaultPreferencesFactory implements PreferencesFactory {
        /** @var NamespaceInfo */
        protected $nsInfo;
 
+       /** @var PermissionManager */
+       protected $permissionManager;
+
        /**
         * TODO Make this a const when we drop HHVM support (T192166)
         *
@@ -114,35 +117,34 @@ class DefaultPreferencesFactory implements PreferencesFactory {
        /**
         * Do not call this directly.  Get it from MediaWikiServices.
         *
-        * @param ServiceOptions|Config $options Config accepted for backwards compatibility
+        * @param ServiceOptions $options
         * @param Language $contLang
         * @param AuthManager $authManager
         * @param LinkRenderer $linkRenderer
-        * @param NamespaceInfo|null $nsInfo
+        * @param NamespaceInfo $nsInfo
+        * @param PermissionManager|null $permissionManager
         */
        public function __construct(
-               $options,
+               ServiceOptions $options,
                Language $contLang,
                AuthManager $authManager,
                LinkRenderer $linkRenderer,
-               NamespaceInfo $nsInfo = null
+               NamespaceInfo $nsInfo,
+               PermissionManager $permissionManager = null
        ) {
-               if ( $options instanceof Config ) {
-                       wfDeprecated( __METHOD__ . ' with Config parameter', '1.34' );
-                       $options = new ServiceOptions( self::$constructorOptions, $options );
-               }
-
                $options->assertRequiredOptions( self::$constructorOptions );
 
-               if ( !$nsInfo ) {
-                       wfDeprecated( __METHOD__ . ' with no NamespaceInfo argument', '1.34' );
-                       $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               if ( !$permissionManager ) {
+                       // TODO: this is actually hard-deprecated, left for jenkins to pass
+                       // together with GlobalPreferences extension. Will be removed in a followup.
+                       $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
                }
                $this->options = $options;
                $this->contLang = $contLang;
                $this->authManager = $authManager;
                $this->linkRenderer = $linkRenderer;
                $this->nsInfo = $nsInfo;
+               $this->permissionManager = $permissionManager;
                $this->logger = new NullLogger();
        }
 
@@ -209,7 +211,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                # # Make sure that form fields have their parent set. See T43337.
                $dummyForm = new HTMLForm( [], $context );
 
-               $disable = !$user->isAllowed( 'editmyoptions' );
+               $disable = !$this->permissionManager->userHasRight( $user, 'editmyoptions' );
 
                $defaultOptions = User::getDefaultOptions();
                $userOptions = $user->getOptions();
@@ -390,8 +392,8 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        ];
                }
 
-               $canViewPrivateInfo = $user->isAllowed( 'viewmyprivateinfo' );
-               $canEditPrivateInfo = $user->isAllowed( 'editmyprivateinfo' );
+               $canViewPrivateInfo = $this->permissionManager->userHasRight( $user, 'viewmyprivateinfo' );
+               $canEditPrivateInfo = $this->permissionManager->userHasRight( $user, 'editmyprivateinfo' );
 
                // Actually changeable stuff
                $defaultPreferences['realname'] = [
@@ -631,7 +633,9 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                                ];
                        }
 
-                       if ( $this->options->get( 'EnableUserEmail' ) && $user->isAllowed( 'sendemail' ) ) {
+                       if ( $this->options->get( 'EnableUserEmail' ) &&
+                               $this->permissionManager->userHasRight( $user, 'sendemail' )
+                       ) {
                                $defaultPreferences['disablemail'] = [
                                        'id' => 'wpAllowEmail',
                                        'type' => 'toggle',
@@ -921,7 +925,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        'label-message' => 'tog-numberheadings',
                ];
 
-               if ( $user->isAllowed( 'rollback' ) ) {
+               if ( $this->permissionManager->userHasRight( $user, 'rollback' ) ) {
                        $defaultPreferences['showrollbackconfirmation'] = [
                                'type' => 'toggle',
                                'section' => 'rendering/advancedrendering',
@@ -961,7 +965,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        ];
                }
 
-               if ( $user->isAllowed( 'minoredit' ) ) {
+               if ( $this->permissionManager->userHasRight( $user, 'minoredit' ) ) {
                        $defaultPreferences['minordefault'] = [
                                'type' => 'toggle',
                                'section' => 'editing/editor',
@@ -1107,7 +1111,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                $watchlistdaysMax = ceil( $this->options->get( 'RCMaxAge' ) / ( 3600 * 24 ) );
 
                # # Watchlist #####################################
-               if ( $user->isAllowed( 'editmywatchlist' ) ) {
+               if ( $this->permissionManager->userHasRight( $user, 'editmywatchlist' ) ) {
                        $editWatchlistLinks = '';
                        $editWatchlistModes = [
                                'edit' => [ 'subpage' => false, 'flags' => [] ],
@@ -1221,20 +1225,20 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                ];
 
                // Kinda hacky
-               if ( $user->isAllowed( 'createpage' ) || $user->isAllowed( 'createtalk' ) ) {
+               if ( $this->permissionManager->userHasAnyRight( $user, 'createpage', 'createtalk' ) ) {
                        $watchTypes['read'] = 'watchcreations';
                }
 
-               if ( $user->isAllowed( 'rollback' ) ) {
+               if ( $this->permissionManager->userHasRight( $user, 'rollback' ) ) {
                        $watchTypes['rollback'] = 'watchrollback';
                }
 
-               if ( $user->isAllowed( 'upload' ) ) {
+               if ( $this->permissionManager->userHasRight( $user, 'upload' ) ) {
                        $watchTypes['upload'] = 'watchuploads';
                }
 
                foreach ( $watchTypes as $action => $pref ) {
-                       if ( $user->isAllowed( $action ) ) {
+                       if ( $this->permissionManager->userHasRight( $user, $action ) ) {
                                // Messages:
                                // tog-watchdefault, tog-watchmoves, tog-watchdeletion, tog-watchcreations, tog-watchuploads
                                // tog-watchrollback
@@ -1606,7 +1610,9 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                $hiddenPrefs = $this->options->get( 'HiddenPrefs' );
                $result = true;
 
-               if ( !$user->isAllowedAny( 'editmyprivateinfo', 'editmyoptions' ) ) {
+               if ( !$this->permissionManager
+                               ->userHasAnyRight( $user, 'editmyprivateinfo', 'editmyoptions' )
+               ) {
                        return Status::newFatal( 'mypreferencesprotected' );
                }
 
@@ -1617,14 +1623,14 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                // (not really "private", but still shouldn't be edited without permission)
 
                if ( !in_array( 'realname', $hiddenPrefs )
-                       && $user->isAllowed( 'editmyprivateinfo' )
+                       && $this->permissionManager->userHasRight( $user, 'editmyprivateinfo' )
                        && array_key_exists( 'realname', $formData )
                ) {
                        $realName = $formData['realname'];
                        $user->setRealName( $realName );
                }
 
-               if ( $user->isAllowed( 'editmyoptions' ) ) {
+               if ( $this->permissionManager->userHasRight( $user, 'editmyoptions' ) ) {
                        $oldUserOptions = $user->getOptions();
 
                        foreach ( $this->getSaveBlacklist() as $b ) {
index 726a3fe..180ed65 100644 (file)
@@ -894,6 +894,7 @@ return [
                'dependencies' => [
                        'mediawiki.api',
                        'oojs',
+                       'mediawiki.Uri',
                ],
                'targets' => [ 'desktop', 'mobile' ],
        ],
@@ -1254,8 +1255,8 @@ return [
                ]
        ],
        'mediawiki.util' => [
-               'localBasePath' => "$IP/resources/src/mediawiki.util/",
-               'remoteBasePath' => "$wgResourceBasePath/resources/src/mediawiki.util/",
+               'localBasePath' => "$IP/resources/src/mediawiki.util",
+               'remoteBasePath' => "$wgResourceBasePath/resources/src/mediawiki.util",
                'packageFiles' => [
                        'util.js',
                        'jquery.accessKeyLabel.js',
index 4b6313b..83ea0ce 100644 (file)
@@ -59,7 +59,6 @@
                                        }
                                },
                                parameters: {
-                                       // Add 'origin' query parameter to all requests.
                                        origin: this.getOrigin()
                                }
                        },
         * any).
         *
         * @protected
-        * @return {string}
+        * @return {string|undefined}
         */
        CoreForeignApi.prototype.getOrigin = function () {
-               var origin;
+               var origin, apiUri, apiOrigin;
                if ( this.anonymous ) {
                        return '*';
                }
+
                origin = location.protocol + '//' + location.hostname;
                if ( location.port ) {
                        origin += ':' + location.port;
                }
+
+               apiUri = new mw.Uri( this.apiUrl );
+               apiOrigin = apiUri.protocol + '://' + apiUri.getAuthority();
+               if ( origin === apiOrigin ) {
+                       // requests are not cross-origin, omit parameter
+                       return undefined;
+               }
+
                return origin;
        };
 
                if ( ajaxOptions.type === 'POST' ) {
                        url = ( ajaxOptions && ajaxOptions.url ) || this.defaults.ajax.url;
                        origin = ( parameters && parameters.origin ) || this.defaults.parameters.origin;
-                       url += ( url.indexOf( '?' ) !== -1 ? '&' : '?' ) +
-                               // Depending on server configuration, MediaWiki may forbid periods in URLs, due to an IE 6
-                               // XSS bug. So let's escape them here. See WebRequest::checkUrlExtension() and T30235.
-                               'origin=' + encodeURIComponent( origin ).replace( /\./g, '%2E' );
+                       if ( origin !== undefined ) {
+                               url += ( url.indexOf( '?' ) !== -1 ? '&' : '?' ) +
+                                       // Depending on server configuration, MediaWiki may forbid periods in URLs, due to an IE 6
+                                       // XSS bug. So let's escape them here. See WebRequest::checkUrlExtension() and T30235.
+                                       'origin=' + encodeURIComponent( origin ).replace( /\./g, '%2E' );
+                       }
                        newAjaxOptions = $.extend( {}, ajaxOptions, { url: url } );
                } else {
                        newAjaxOptions = ajaxOptions;
index e7f7067..a459441 100644 (file)
@@ -2,6 +2,7 @@
 
 use MediaWiki\Auth\AuthManager;
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Permissions\PermissionManager;
 use MediaWiki\Preferences\DefaultPreferencesFactory;
 use Wikimedia\TestingAccessWrapper;
 
@@ -49,9 +50,10 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
 
        /**
         * Get a basic PreferencesFactory for testing with.
+        * @param PermissionManager|null $manager
         * @return DefaultPreferencesFactory
         */
-       protected function getPreferencesFactory() {
+       protected function getPreferencesFactory( PermissionManager $manager = null ) {
                $mockNsInfo = $this->createMock( NamespaceInfo::class );
                $mockNsInfo->method( 'getValidNamespaces' )->willReturn( [
                        NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK
@@ -59,13 +61,16 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
                $mockNsInfo->expects( $this->never() )
                        ->method( $this->anythingBut( 'getValidNamespaces', '__destruct' ) );
 
+               $mockPermissionManager = $manager ?? $this->createMock( PermissionManager::class );
+
                return new DefaultPreferencesFactory(
                        new LoggedServiceOptions( self::$serviceOptionsAccessLog,
                                DefaultPreferencesFactory::$constructorOptions, $this->config ),
                        new Language(),
                        AuthManager::singleton(),
                        MediaWikiServices::getInstance()->getLinkRenderer(),
-                       $mockNsInfo
+                       $mockNsInfo,
+                       $mockPermissionManager
                );
        }
 
@@ -88,7 +93,9 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
         * @dataProvider emailAuthenticationProvider
         */
        public function testEmailAuthentication( $user, $cssClass ) {
-               $prefs = $this->getPreferencesFactory()->getFormDescriptor( $user, $this->context );
+               $pm = $this->createMock( PermissionManager::class );
+               $pm->method( 'userHasRight' )->willReturn( true );
+               $prefs = $this->getPreferencesFactory( $pm )->getFormDescriptor( $user, $this->context );
                $this->assertArrayHasKey( 'cssclass', $prefs['emailauthentication'] );
                $this->assertEquals( $cssClass, $prefs['emailauthentication']['cssclass'] );
        }
@@ -100,16 +107,18 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
                $userMock = $this->getMockBuilder( User::class )
                        ->disableOriginalConstructor()
                        ->getMock();
-               $userMock->method( 'isAllowed' )
-                       ->willReturn( false );
                $userMock->method( 'getEffectiveGroups' )
                        ->willReturn( [] );
                $userMock->method( 'getGroupMemberships' )
                        ->willReturn( [] );
                $userMock->method( 'getOptions' )
                        ->willReturn( [ 'test' => 'yes' ] );
-
-               $prefs = $this->getPreferencesFactory()->getFormDescriptor( $userMock, $this->context );
+               $pm = $this->createMock( PermissionManager::class );
+               $pm->method( 'userHasRight' )
+                       ->will( $this->returnValueMap( [
+                               [ $userMock, 'editmyoptions', true ]
+                       ] ) );
+               $prefs = $this->getPreferencesFactory( $pm )->getFormDescriptor( $userMock, $this->context );
                $this->assertArrayNotHasKey( 'showrollbackconfirmation', $prefs );
        }
 
@@ -120,16 +129,19 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
                $userMock = $this->getMockBuilder( User::class )
                        ->disableOriginalConstructor()
                        ->getMock();
-               $userMock->method( 'isAllowed' )
-                       ->willReturn( true );
                $userMock->method( 'getEffectiveGroups' )
                        ->willReturn( [] );
                $userMock->method( 'getGroupMemberships' )
                        ->willReturn( [] );
                $userMock->method( 'getOptions' )
                        ->willReturn( [ 'test' => 'yes' ] );
-
-               $prefs = $this->getPreferencesFactory()->getFormDescriptor( $userMock, $this->context );
+               $pm = $this->createMock( PermissionManager::class );
+               $pm->method( 'userHasRight' )
+                       ->will( $this->returnValueMap( [
+                               [ $userMock, 'editmyoptions', true ],
+                               [ $userMock, 'rollback', true ]
+                       ] ) );
+               $prefs = $this->getPreferencesFactory( $pm )->getFormDescriptor( $userMock, $this->context );
                $this->assertArrayHasKey( 'showrollbackconfirmation', $prefs );
                $this->assertEquals(
                        'rendering/advancedrendering',
@@ -181,10 +193,6 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
                        ->getMock();
                $userMock->method( 'getOptions' )
                        ->willReturn( $oldOptions );
-               $userMock->method( 'isAllowedAny' )
-                       ->willReturn( true );
-               $userMock->method( 'isAllowed' )
-                       ->willReturn( true );
 
                $userMock->expects( $this->exactly( 2 ) )
                        ->method( 'setOption' )
@@ -193,18 +201,25 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
                                [ $this->equalTo( 'option' ), $this->equalTo( $newOptions[ 'option' ] ) ]
                        );
 
-               $form->expects( $this->any() )
-                       ->method( 'getModifiedUser' )
+               $form->method( 'getModifiedUser' )
                        ->willReturn( $userMock );
 
-               $form->expects( $this->any() )
-                       ->method( 'getContext' )
+               $form->method( 'getContext' )
                        ->willReturn( $this->context );
 
-               $form->expects( $this->any() )
-                       ->method( 'getConfig' )
+               $form->method( 'getConfig' )
                        ->willReturn( $configMock );
 
+               $pm = $this->createMock( PermissionManager::class );
+               $pm->method( 'userHasAnyRight' )
+                       ->will( $this->returnValueMap( [
+                               [ $userMock, 'editmyprivateinfo', 'editmyoptions', true ]
+                       ] ) );
+               $pm->method( 'userHasRight' )
+                       ->will( $this->returnValueMap( [
+                               [ $userMock, 'editmyoptions', true ]
+                       ] ) );
+
                $this->setTemporaryHook( 'PreferencesFormPreSave',
                        function ( $formData, $form, $user, &$result, $oldUserOptions )
                                use ( $newOptions, $oldOptions, $userMock ) {
@@ -220,7 +235,7 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
                );
 
                /** @var DefaultPreferencesFactory $factory */
-               $factory = TestingAccessWrapper::newFromObject( $this->getPreferencesFactory() );
+               $factory = TestingAccessWrapper::newFromObject( $this->getPreferencesFactory( $pm ) );
                $factory->saveFormData( $newOptions, $form, [] );
        }
 
@@ -233,7 +248,14 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
                // Test a string with leading zeros (i.e. not octal) and spaces.
                $this->context->getRequest()->setVal( 'wprclimit', ' 0012 ' );
                $user = new User;
-               $form = $this->getPreferencesFactory()->getForm( $user, $this->context );
+               $pm = $this->createMock( PermissionManager::class );
+               $pm->method( 'userHasAnyRight' )
+                       ->willReturn( true );
+               $pm->method( 'userHasRight' )
+                       ->will( $this->returnValueMap( [
+                               [ $user, 'editmyoptions', true ]
+                       ] ) );
+               $form = $this->getPreferencesFactory( $pm )->getForm( $user, $this->context );
                $form->show();
                $form->trySubmit();
                $this->assertEquals( 12, $user->getOption( 'rclimit' ) );
index 22b5938..edb7618 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-* @covers MWDoxygenFilter
+ * @covers MWDoxygenFilter
  */
 class MWDoxygenFilterTest extends \PHPUnit\Framework\TestCase {
 
index 541c610..22a3a4b 100644 (file)
                return api.post( {} );
        } );
 
+       QUnit.test( 'origin is not included in same-origin GET requests', function ( assert ) {
+               var apiUrl = location.protocol + '//' + location.host + '/w/api.php',
+                       api = new mw.ForeignApi( apiUrl );
+
+               this.server.respond( function ( request ) {
+                       assert.strictEqual( request.url.match( /origin=.*?(?:&|$)/ ), null, 'origin is not included in GET requests' );
+                       request.respond( 200, { 'Content-Type': 'application/json' }, '[]' );
+               } );
+
+               return api.get( {} );
+       } );
+
+       QUnit.test( 'origin is not included in same-origin POST requests', function ( assert ) {
+               var apiUrl = location.protocol + '//' + location.host + '/w/api.php',
+                       api = new mw.ForeignApi( apiUrl );
+
+               this.server.respond( function ( request ) {
+                       assert.strictEqual( request.requestBody.match( /origin=.*?(?:&|$)/ ), null, 'origin is not included in POST request body' );
+                       assert.strictEqual( request.url.match( /origin=.*?(?:&|$)/ ), null, 'origin is not included in POST request URL, either' );
+                       request.respond( 200, { 'Content-Type': 'application/json' }, '[]' );
+               } );
+
+               return api.post( {} );
+       } );
+
 }() );