Removes deprecated API endpoints and modules for dealing with CSRF tokens. Note: i18n messages are removed in a followup for ease of revert. Bug: T280806 Depends-On: Ic83f44587db119ff2e3e6d5ff33a10894e0695e7 Change-Id: I58aedec6942ac5d3c21574cb0072f00ef365098c
203 lines
5.5 KiB
PHP
203 lines
5.5 KiB
PHP
<?php
|
|
|
|
use MediaWiki\MediaWikiServices;
|
|
use MediaWiki\Permissions\Authority;
|
|
use MediaWiki\Session\SessionManager;
|
|
use PHPUnit\Framework\Assert;
|
|
use PHPUnit\Util\Test;
|
|
|
|
abstract class ApiTestCase extends MediaWikiLangTestCase {
|
|
protected static $apiUrl;
|
|
|
|
protected static $errorFormatter = null;
|
|
|
|
/**
|
|
* @var ApiTestContext
|
|
*/
|
|
protected $apiContext;
|
|
|
|
protected function setUp(): void {
|
|
global $wgServer;
|
|
|
|
parent::setUp();
|
|
self::$apiUrl = $wgServer . wfScript( 'api' );
|
|
|
|
self::$users = [
|
|
'sysop' => static::getTestSysop(),
|
|
'uploader' => static::getTestUser(),
|
|
];
|
|
|
|
$this->setRequest( new FauxRequest( [] ) );
|
|
|
|
$this->apiContext = new ApiTestContext();
|
|
}
|
|
|
|
protected function tearDown(): void {
|
|
// Avoid leaking session over tests
|
|
MediaWiki\Session\SessionManager::getGlobalSession()->clear();
|
|
|
|
parent::tearDown();
|
|
}
|
|
|
|
/**
|
|
* Does the API request and returns the result.
|
|
*
|
|
* @param array $params
|
|
* @param array|null $session
|
|
* @param bool $appendModule
|
|
* @param Authority|null $performer
|
|
* @param string|null $tokenType Set to a string like 'csrf' to send an
|
|
* appropriate token
|
|
* @return array List of:
|
|
* - the result data (array)
|
|
* - the request (WebRequest)
|
|
* - the session data of the request (array)
|
|
* - if $appendModule is true, the Api module $module
|
|
* @throws ApiUsageException
|
|
*/
|
|
protected function doApiRequest( array $params, array $session = null,
|
|
$appendModule = false, Authority $performer = null, $tokenType = null
|
|
) {
|
|
global $wgRequest;
|
|
|
|
if ( $session === null ) {
|
|
// re-use existing global session by default
|
|
$session = $wgRequest->getSessionArray();
|
|
}
|
|
|
|
$sessionObj = SessionManager::singleton()->getEmptySession();
|
|
|
|
if ( $session !== null ) {
|
|
foreach ( $session as $key => $value ) {
|
|
$sessionObj->set( $key, $value );
|
|
}
|
|
}
|
|
|
|
// set up global environment
|
|
if ( $performer ) {
|
|
$legacyUser = $this->getServiceContainer()->getUserFactory()->newFromAuthority( $performer );
|
|
$contextUser = $legacyUser;
|
|
} else {
|
|
$contextUser = self::$users['sysop']->getUser();
|
|
$performer = $contextUser;
|
|
}
|
|
|
|
$sessionObj->setUser( $contextUser );
|
|
if ( $tokenType !== null ) {
|
|
if ( $tokenType === 'auto' ) {
|
|
$tokenType = ( new ApiMain() )->getModuleManager()
|
|
->getModule( $params['action'], 'action' )->needsToken();
|
|
}
|
|
if ( $tokenType !== false ) {
|
|
$params['token'] = ApiQueryTokens::getToken(
|
|
$contextUser,
|
|
$sessionObj,
|
|
ApiQueryTokens::getTokenTypeSalts()[$tokenType]
|
|
)->toString();
|
|
}
|
|
}
|
|
|
|
$wgRequest = $this->buildFauxRequest( $params, $sessionObj );
|
|
RequestContext::getMain()->setRequest( $wgRequest );
|
|
RequestContext::getMain()->setAuthority( $performer );
|
|
|
|
// set up local environment
|
|
$context = $this->apiContext->newTestContext( $wgRequest, $performer );
|
|
|
|
$module = new ApiMain( $context, true );
|
|
|
|
// run it!
|
|
$module->execute();
|
|
|
|
// construct result
|
|
$results = [
|
|
$module->getResult()->getResultData( null, [ 'Strip' => 'all' ] ),
|
|
$context->getRequest(),
|
|
$context->getRequest()->getSessionArray()
|
|
];
|
|
|
|
if ( $appendModule ) {
|
|
$results[] = $module;
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* @since 1.37
|
|
* @param array $params
|
|
* @param MediaWiki\Session\Session|array|null $session
|
|
* @return FauxRequest
|
|
*/
|
|
protected function buildFauxRequest( $params, $session ) {
|
|
return new FauxRequest( $params, true, $session );
|
|
}
|
|
|
|
/**
|
|
* Convenience function to access the token parameter of doApiRequest()
|
|
* more succinctly.
|
|
*
|
|
* @param array $params Key-value API params
|
|
* @param array|null $session Session array
|
|
* @param Authority|null $performer A User object for the context
|
|
* @param string $tokenType Which token type to pass
|
|
* @return array Result of the API call
|
|
*/
|
|
protected function doApiRequestWithToken( array $params, array $session = null,
|
|
Authority $performer = null, $tokenType = 'auto'
|
|
) {
|
|
return $this->doApiRequest( $params, $session, false, $performer, $tokenType );
|
|
}
|
|
|
|
protected static function getErrorFormatter() {
|
|
if ( self::$errorFormatter === null ) {
|
|
self::$errorFormatter = new ApiErrorFormatter(
|
|
new ApiResult( false ),
|
|
MediaWikiServices::getInstance()->getLanguageFactory()->getLanguage( 'en' ),
|
|
'none'
|
|
);
|
|
}
|
|
return self::$errorFormatter;
|
|
}
|
|
|
|
public static function apiExceptionHasCode( ApiUsageException $ex, $code ) {
|
|
return (bool)array_filter(
|
|
self::getErrorFormatter()->arrayFromStatus( $ex->getStatusValue() ),
|
|
static function ( $e ) use ( $code ) {
|
|
return is_array( $e ) && $e['code'] === $code;
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @coversNothing
|
|
*/
|
|
public function testApiTestGroup() {
|
|
$groups = Test::getGroups( static::class );
|
|
$constraint = Assert::logicalOr(
|
|
$this->contains( 'medium' ),
|
|
$this->contains( 'large' )
|
|
);
|
|
$this->assertThat( $groups, $constraint,
|
|
'ApiTestCase::setUp can be slow, tests must be "medium" or "large"'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Expect an ApiUsageException to be thrown with the given parameters, which are the same as
|
|
* ApiUsageException::newWithMessage()'s parameters. This allows checking for an exception
|
|
* whose text is given by a message key instead of text, so as not to hard-code the message's
|
|
* text into test code.
|
|
* @param string|array|Message $msg
|
|
* @param string|null $code
|
|
* @param array|null $data
|
|
* @param int $httpCode
|
|
*/
|
|
protected function setExpectedApiException(
|
|
$msg, $code = null, array $data = null, $httpCode = 0
|
|
) {
|
|
$expected = ApiUsageException::newWithMessage( null, $msg, $code, $data, $httpCode );
|
|
$this->expectException( ApiUsageException::class );
|
|
$this->expectExceptionMessage( $expected->getMessage() );
|
|
}
|
|
}
|