aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Pchelko <ppchelko@wikimedia.org>2021-06-01 11:43:35 -0700
committerPetr Pchelko <ppchelko@wikimedia.org>2021-07-12 14:19:15 -0700
commit0d75fdb4f73ddbf4ad5f29e14258d58e507d55b4 (patch)
tree9e17f616f0b17370c219c3e4a339c0f3476155e7
parent4e7ac57b46e5397f88d1de723bee345bf9d83e8f (diff)
downloadmediawikicore-0d75fdb4f73ddbf4ad5f29e14258d58e507d55b4.tar.gz
mediawikicore-0d75fdb4f73ddbf4ad5f29e14258d58e507d55b4.zip
Use CsrfTokenSet as CSRF token source
Change-Id: I079d2c802d9b48d6abf7f37fa9ef7dafac631345
-rw-r--r--includes/EditPage.php10
-rw-r--r--includes/FileDeleteForm.php11
-rw-r--r--includes/Linker.php2
-rw-r--r--includes/OutputPage.php2
-rw-r--r--includes/ProtectionForm.php22
-rw-r--r--includes/Rest/Handler/EditHandler.php2
-rw-r--r--includes/actions/RollbackAction.php2
-rw-r--r--includes/actions/WatchAction.php5
-rw-r--r--includes/api/ApiBase.php6
-rw-r--r--includes/api/ApiEditPage.php3
-rw-r--r--includes/api/ApiQueryDeletedrevs.php2
-rw-r--r--includes/api/ApiQueryInfo.php21
-rw-r--r--includes/api/ApiQueryRecentChanges.php4
-rw-r--r--includes/api/ApiQueryRevisions.php4
-rw-r--r--includes/api/ApiQueryUserInfo.php2
-rw-r--r--includes/api/ApiQueryUsers.php5
-rw-r--r--includes/context/DerivativeContext.php11
-rw-r--r--includes/htmlform/HTMLForm.php11
-rw-r--r--includes/htmlform/HTMLFormField.php5
-rw-r--r--includes/htmlform/fields/HTMLFormFieldCloner.php9
-rw-r--r--includes/page/Article.php16
-rw-r--r--includes/page/ImageHistoryList.php2
-rw-r--r--includes/resourceloader/ResourceLoaderUserOptionsModule.php10
-rw-r--r--includes/revisiondelete/RevDelArchivedFileItem.php4
-rw-r--r--includes/revisiondelete/RevDelFileItem.php9
-rw-r--r--includes/search/searchwidgets/SearchFormWidget.php11
-rw-r--r--includes/specials/SpecialEditTags.php12
-rw-r--r--includes/specials/SpecialEmailUser.php3
-rw-r--r--includes/specials/SpecialExpandTemplates.php2
-rw-r--r--includes/specials/SpecialImport.php2
-rw-r--r--includes/specials/SpecialMergeHistory.php8
-rw-r--r--includes/specials/SpecialMovepage.php8
-rw-r--r--includes/specials/SpecialRevisionDelete.php20
-rw-r--r--includes/specials/SpecialSearch.php7
-rw-r--r--includes/specials/SpecialTags.php4
-rw-r--r--includes/specials/SpecialUndelete.php23
-rw-r--r--includes/specials/SpecialUpload.php3
-rw-r--r--includes/specials/SpecialUserrights.php11
-rw-r--r--includes/specials/SpecialWatchlist.php4
-rw-r--r--tests/phpunit/includes/EditPageConstraintsTest.php16
-rw-r--r--tests/phpunit/includes/EditPageTest.php24
-rw-r--r--tests/phpunit/includes/OutputPageTest.php53
-rw-r--r--tests/phpunit/includes/actions/RollbackActionTest.php10
-rw-r--r--tests/phpunit/includes/actions/WatchActionTest.php8
-rw-r--r--tests/phpunit/includes/api/ApiDeleteTest.php5
-rw-r--r--tests/phpunit/includes/api/ApiLogoutTest.php3
-rw-r--r--tests/phpunit/includes/api/ApiUserrightsTest.php22
-rw-r--r--tests/phpunit/includes/api/ApiWatchTest.php5
-rw-r--r--tests/phpunit/includes/specials/SpecialPageExecutor.php6
-rw-r--r--tests/phpunit/includes/upload/UploadFromUrlTest.php23
-rw-r--r--tests/phpunit/integration/includes/Storage/UndoIntegrationTest.php17
-rw-r--r--tests/phpunit/unit/includes/Rest/Handler/ActionModuleBasedHandlerTestTrait.php7
-rw-r--r--tests/phpunit/unit/includes/context/DerivativeContextTest.php22
53 files changed, 303 insertions, 216 deletions
diff --git a/includes/EditPage.php b/includes/EditPage.php
index d5399eb4b1d0..30b64d0b860b 100644
--- a/includes/EditPage.php
+++ b/includes/EditPage.php
@@ -55,6 +55,7 @@ use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\RevisionStore;
use MediaWiki\Revision\RevisionStoreRecord;
use MediaWiki\Revision\SlotRecord;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\User\UserIdentity;
use MediaWiki\User\UserNameUtils;
use MediaWiki\Watchlist\WatchlistManager;
@@ -1624,9 +1625,7 @@ class EditPage implements IEditObject {
* @internal
*/
public function tokenOk( &$request ) {
- $token = $request->getVal( 'wpEditToken' );
- $user = $this->context->getUser();
- $this->mTokenOk = $user->matchEditToken( $token );
+ $this->mTokenOk = ( new CsrfTokenSet( $request ) )->matchTokenField();
return $this->mTokenOk;
}
@@ -3490,7 +3489,10 @@ class EditPage implements IEditObject {
*/
$this->context->getOutput()->addHTML(
"\n" .
- Html::hidden( "wpEditToken", $this->context->getUser()->getEditToken() ) .
+ Html::hidden(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->context->getCsrfTokenSet()->getToken()->toString()
+ ) .
"\n"
);
}
diff --git a/includes/FileDeleteForm.php b/includes/FileDeleteForm.php
index 8d2828df87b0..3e7a6e235a71 100644
--- a/includes/FileDeleteForm.php
+++ b/includes/FileDeleteForm.php
@@ -25,6 +25,7 @@
use MediaWiki\Linker\LinkRenderer;
use MediaWiki\MediaWikiServices;
use MediaWiki\Permissions\PermissionStatus;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\User\UserIdentity;
use MediaWiki\User\UserOptionsLookup;
use MediaWiki\Watchlist\WatchlistManager;
@@ -111,7 +112,6 @@ class FileDeleteForm {
$request = $this->context->getRequest();
$this->oldimage = $request->getText( 'oldimage', '' );
- $token = $request->getText( 'wpEditToken' );
# Flag to hide all contents of the archived revisions
$suppress = $request->getCheck( 'wpSuppress' ) &&
$this->context->getAuthority()->isAllowed( 'suppressrevision' );
@@ -130,7 +130,10 @@ class FileDeleteForm {
}
// Perform the deletion if appropriate
- if ( $request->wasPosted() && $this->context->getUser()->matchEditToken( $token, $this->oldimage ) ) {
+ if ( $request->wasPosted() &&
+ $this->context->getCsrfTokenSet()
+ ->matchTokenField( CsrfTokenSet::DEFAULT_FIELD_NAME, $this->oldimage )
+ ) {
$permissionStatus = PermissionStatus::newEmpty();
if ( !$this->context->getAuthority()->authorizeWrite(
'delete', $this->title, $permissionStatus
@@ -431,8 +434,8 @@ class FileDeleteForm {
$fieldset,
new OOUI\HtmlSnippet(
Html::hidden(
- 'wpEditToken',
- $this->context->getUser()->getEditToken( $this->oldimage )
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->context->getCsrfTokenSet()->getToken( $this->oldimage )->toString()
)
)
);
diff --git a/includes/Linker.php b/includes/Linker.php
index 00be6c204c5c..2fc52084cfca 100644
--- a/includes/Linker.php
+++ b/includes/Linker.php
@@ -2184,7 +2184,7 @@ class Linker {
$query = [
'action' => 'rollback',
'from' => $revUserText,
- 'token' => $context->getUser()->getEditToken( 'rollback' ),
+ 'token' => $context->getCsrfTokenSet()->getToken( 'rollback' )->toString(),
];
$attrs = [
diff --git a/includes/OutputPage.php b/includes/OutputPage.php
index bfa6aea66f5f..4986dd0a4cc3 100644
--- a/includes/OutputPage.php
+++ b/includes/OutputPage.php
@@ -3487,7 +3487,7 @@ class OutputPage extends ContextSource {
// Anons have predictable edit tokens
return false;
}
- if ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ) ) ) {
+ if ( !$this->getCsrfTokenSet()->matchTokenField() ) {
return false;
}
diff --git a/includes/ProtectionForm.php b/includes/ProtectionForm.php
index f1abbfca3ef0..ea237f8d0a17 100644
--- a/includes/ProtectionForm.php
+++ b/includes/ProtectionForm.php
@@ -28,6 +28,7 @@ use MediaWiki\MediaWikiServices;
use MediaWiki\Permissions\Authority;
use MediaWiki\Permissions\PermissionManager;
use MediaWiki\Permissions\PermissionStatus;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\Watchlist\WatchlistManager;
/**
@@ -327,11 +328,10 @@ class ProtectionForm {
return false;
}
- $token = $this->mRequest->getVal( 'wpEditToken' );
- $legacyUser = MediaWikiServices::getInstance()
- ->getUserFactory()
- ->newFromAuthority( $this->mPerformer );
- if ( !$legacyUser->matchEditToken( $token, [ 'protect', $this->mTitle->getPrefixedDBkey() ] ) ) {
+ if ( !$this->mContext->getCsrfTokenSet()->matchTokenField(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ [ 'protect', $this->mTitle->getPrefixedDBkey() ]
+ ) ) {
$this->show( [ 'sessionfailure' ] );
return false;
}
@@ -585,13 +585,13 @@ class ProtectionForm {
}
if ( !$this->disabled ) {
- $legacyUser = MediaWikiServices::getInstance()
- ->getUserFactory()
- ->newFromAuthority( $this->mPerformer );
- $fields['wpEditToken'] = [
- 'name' => 'wpEditToken',
+ $fields[CsrfTokenSet::DEFAULT_FIELD_NAME] = [
+ 'name' => CsrfTokenSet::DEFAULT_FIELD_NAME,
'type' => 'hidden',
- 'default' => $legacyUser->getEditToken( [ 'protect', $this->mTitle->getPrefixedDBkey() ] ),
+ 'default' => $this->mContext
+ ->getCsrfTokenSet()
+ ->getToken( [ 'protect', $this->mTitle->getPrefixedDBkey() ] )
+ ->toString(),
];
}
diff --git a/includes/Rest/Handler/EditHandler.php b/includes/Rest/Handler/EditHandler.php
index 9c28ad210b2b..83a6a7ecf1a7 100644
--- a/includes/Rest/Handler/EditHandler.php
+++ b/includes/Rest/Handler/EditHandler.php
@@ -175,7 +175,7 @@ abstract class EditHandler extends ActionModuleBasedHandler {
}
// Since the session is safe against CSRF, just use a known-good token.
- return $this->getUser()->getEditToken();
+ return $this->getApiMain()->getCsrfTokenSet()->getToken()->toString();
} else {
return $body['token'] ?? '';
}
diff --git a/includes/actions/RollbackAction.php b/includes/actions/RollbackAction.php
index 970a20350878..974321ce4a8a 100644
--- a/includes/actions/RollbackAction.php
+++ b/includes/actions/RollbackAction.php
@@ -115,7 +115,7 @@ class RollbackAction extends FormAction {
] );
}
- if ( !$user->matchEditToken( $request->getVal( 'token' ), 'rollback' ) ) {
+ if ( !$this->getContext()->getCsrfTokenSet()->matchTokenField( 'token', 'rollback' ) ) {
throw new ErrorPageError( 'sessionfailure-title', 'sessionfailure' );
}
diff --git a/includes/actions/WatchAction.php b/includes/actions/WatchAction.php
index c1dc7644284e..4860a9549bed 100644
--- a/includes/actions/WatchAction.php
+++ b/includes/actions/WatchAction.php
@@ -23,6 +23,7 @@
use MediaWiki\MediaWikiServices;
use MediaWiki\Page\PageIdentity;
use MediaWiki\Permissions\Authority;
+use MediaWiki\Session\CsrfTokenSet;
use Wikimedia\ParamValidator\TypeDef\ExpiryDef;
/**
@@ -332,7 +333,9 @@ class WatchAction extends FormAction {
$action = 'watch';
}
// This must match ApiWatch and ResourceLoaderUserOptionsModule
- return $user->getEditToken( $action );
+ return ( new CsrfTokenSet( $user->getRequest() ) )
+ ->getToken( $action )
+ ->toString();
}
public function doesWrites() {
diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php
index 92b4d26e63c9..b9cccc0c3454 100644
--- a/includes/api/ApiBase.php
+++ b/includes/api/ApiBase.php
@@ -1097,11 +1097,7 @@ abstract class ApiBase extends ContextSource {
}
$webUiSalt = $this->getWebUITokenSalt( $params );
- if ( $webUiSalt !== null && $this->getUser()->matchEditToken(
- $token,
- $webUiSalt,
- $this->getRequest()
- ) ) {
+ if ( $webUiSalt !== null && $this->getCsrfTokenSet()->matchToken( $token, $webUiSalt ) ) {
return true;
}
diff --git a/includes/api/ApiEditPage.php b/includes/api/ApiEditPage.php
index a30285909598..1c95c958300f 100644
--- a/includes/api/ApiEditPage.php
+++ b/includes/api/ApiEditPage.php
@@ -26,6 +26,7 @@ use MediaWiki\Page\WikiPageFactory;
use MediaWiki\Revision\RevisionLookup;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\SlotRecord;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\User\UserOptionsLookup;
use MediaWiki\Watchlist\WatchlistManager;
@@ -347,7 +348,7 @@ class ApiEditPage extends ApiBase {
'wpTextbox1' => $params['text'],
'format' => $contentFormat,
'model' => $contentModel,
- 'wpEditToken' => $params['token'],
+ CsrfTokenSet::DEFAULT_FIELD_NAME => $params['token'],
'wpIgnoreBlankSummary' => true,
'wpIgnoreBlankArticle' => true,
'wpIgnoreSelfRedirect' => true,
diff --git a/includes/api/ApiQueryDeletedrevs.php b/includes/api/ApiQueryDeletedrevs.php
index 043e2af43927..022b34cfbccc 100644
--- a/includes/api/ApiQueryDeletedrevs.php
+++ b/includes/api/ApiQueryDeletedrevs.php
@@ -191,7 +191,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
if ( $fld_token ) {
// Undelete tokens are identical for all pages, so we cache one here
- $token = $user->getEditToken( '', $this->getMain()->getRequest() );
+ $token = $this->getCsrfTokenSet()->getToken()->toString();
}
$dir = $params['dir'];
diff --git a/includes/api/ApiQueryInfo.php b/includes/api/ApiQueryInfo.php
index 2efcfcce7e65..c6612a92b811 100644
--- a/includes/api/ApiQueryInfo.php
+++ b/includes/api/ApiQueryInfo.php
@@ -24,6 +24,7 @@ use MediaWiki\Languages\LanguageConverterFactory;
use MediaWiki\Linker\LinkTarget;
use MediaWiki\ParamValidator\TypeDef\TitleDef;
use MediaWiki\Permissions\PermissionStatus;
+use MediaWiki\Session\CsrfTokenSet;
/**
* A query module to show basic page information.
@@ -208,7 +209,9 @@ class ApiQueryInfo extends ApiQueryBase {
// The token is always the same, let's exploit that
if ( !isset( self::$cachedTokens['edit'] ) ) {
- self::$cachedTokens['edit'] = $user->getEditToken();
+ self::$cachedTokens['edit'] = ( new CsrfTokenSet( $user->getRequest() ) )
+ ->getToken()
+ ->toString();
}
return self::$cachedTokens['edit'];
@@ -281,7 +284,9 @@ class ApiQueryInfo extends ApiQueryBase {
// The token is always the same, let's exploit that
if ( !isset( self::$cachedTokens['email'] ) ) {
- self::$cachedTokens['email'] = $user->getEditToken();
+ self::$cachedTokens['email'] = ( new CsrfTokenSet( $user->getRequest() ) )
+ ->getToken()
+ ->toString();
}
return self::$cachedTokens['email'];
@@ -299,7 +304,9 @@ class ApiQueryInfo extends ApiQueryBase {
// The token is always the same, let's exploit that
if ( !isset( self::$cachedTokens['import'] ) ) {
- self::$cachedTokens['import'] = $user->getEditToken();
+ self::$cachedTokens['import'] = ( new CsrfTokenSet( $user->getRequest() ) )
+ ->getToken()
+ ->toString();
}
return self::$cachedTokens['import'];
@@ -317,7 +324,9 @@ class ApiQueryInfo extends ApiQueryBase {
// The token is always the same, let's exploit that
if ( !isset( self::$cachedTokens['watch'] ) ) {
- self::$cachedTokens['watch'] = $user->getEditToken( 'watch' );
+ self::$cachedTokens['watch'] = ( new CsrfTokenSet( $user->getRequest() ) )
+ ->getToken( 'watch' )
+ ->toString();
}
return self::$cachedTokens['watch'];
@@ -335,7 +344,9 @@ class ApiQueryInfo extends ApiQueryBase {
// The token is always the same, let's exploit that
if ( !isset( self::$cachedTokens['options'] ) ) {
- self::$cachedTokens['options'] = $user->getEditToken();
+ self::$cachedTokens['options'] = ( new CsrfTokenSet( $user->getRequest() ) )
+ ->getToken()
+ ->toString();
}
return self::$cachedTokens['options'];
diff --git a/includes/api/ApiQueryRecentChanges.php b/includes/api/ApiQueryRecentChanges.php
index bfcb833f07d3..37f16b1b704b 100644
--- a/includes/api/ApiQueryRecentChanges.php
+++ b/includes/api/ApiQueryRecentChanges.php
@@ -23,6 +23,7 @@
use MediaWiki\ParamValidator\TypeDef\UserDef;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\SlotRoleRegistry;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\Storage\NameTableAccessException;
use MediaWiki\Storage\NameTableStore;
@@ -126,7 +127,8 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
static $cachedPatrolToken = null;
if ( $cachedPatrolToken === null ) {
- $cachedPatrolToken = $user->getEditToken( 'patrol' );
+ $cachedPatrolToken = ( new CsrfTokenSet( $user->getRequest() ) )
+ ->getToken( 'patrol' )->toString();
}
return $cachedPatrolToken;
diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php
index c843ecf6c705..ef9b4faa777a 100644
--- a/includes/api/ApiQueryRevisions.php
+++ b/includes/api/ApiQueryRevisions.php
@@ -25,6 +25,7 @@ use MediaWiki\ParamValidator\TypeDef\UserDef;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\RevisionStore;
use MediaWiki\Revision\SlotRoleRegistry;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\Storage\NameTableAccessException;
use MediaWiki\Storage\NameTableStore;
@@ -119,7 +120,8 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
return false;
}
- return $user->getEditToken( 'rollback' );
+ return ( new CsrfTokenSet( $user->getRequest() ) )
+ ->getToken( 'rollback' )->toString();
}
protected function run( ApiPageSet $resultPageSet = null ) {
diff --git a/includes/api/ApiQueryUserInfo.php b/includes/api/ApiQueryUserInfo.php
index b736da1ece7f..6dc1f212d913 100644
--- a/includes/api/ApiQueryUserInfo.php
+++ b/includes/api/ApiQueryUserInfo.php
@@ -211,7 +211,7 @@ class ApiQueryUserInfo extends ApiQueryBase {
!$this->lacksSameOriginSecurity() &&
$this->getAuthority()->isAllowed( 'editmyoptions' )
) {
- $vals['preferencestoken'] = $user->getEditToken( '', $this->getMain()->getRequest() );
+ $vals['preferencestoken'] = $this->getCsrfTokenSet()->getToken()->toString();
}
if ( isset( $this->prop['editcount'] ) ) {
diff --git a/includes/api/ApiQueryUsers.php b/includes/api/ApiQueryUsers.php
index 5dd07292416a..fecc56c9f55f 100644
--- a/includes/api/ApiQueryUsers.php
+++ b/includes/api/ApiQueryUsers.php
@@ -22,6 +22,7 @@
use MediaWiki\Auth\AuthManager;
use MediaWiki\Block\DatabaseBlock;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\User\UserFactory;
use MediaWiki\User\UserGroupManager;
use MediaWiki\User\UserNameUtils;
@@ -133,7 +134,9 @@ class ApiQueryUsers extends ApiQueryBase {
public static function getUserrightsToken( User $actingUser, $targetUser ) {
// Since the permissions check for userrights is non-trivial,
// don't bother with it here
- return $actingUser->getEditToken( $targetUser->getName() );
+ return ( new CsrfTokenSet( $actingUser->getRequest() ) )
+ ->getToken( $targetUser->getName() )
+ ->toString();
}
public function execute() {
diff --git a/includes/context/DerivativeContext.php b/includes/context/DerivativeContext.php
index 3a90335190a3..e40fd9b7fc7d 100644
--- a/includes/context/DerivativeContext.php
+++ b/includes/context/DerivativeContext.php
@@ -20,6 +20,7 @@
*/
use MediaWiki\MediaWikiServices;
use MediaWiki\Permissions\Authority;
+use MediaWiki\Session\CsrfTokenSet;
/**
* An IContextSource implementation which will inherit context from another source
@@ -287,4 +288,14 @@ class DerivativeContext extends ContextSource implements MutableContext {
// phpcs:ignore MediaWiki.Usage.ExtendClassUsage.FunctionVarUsage
return wfMessage( $key, ...$params )->setContext( $this );
}
+
+ /**
+ * Get a repository to obtain and match CSRF tokens.
+ *
+ * @return CsrfTokenSet
+ * @since 1.37
+ */
+ public function getCsrfTokenSet() : CsrfTokenSet {
+ return new CsrfTokenSet( $this->getRequest() );
+ }
}
diff --git a/includes/htmlform/HTMLForm.php b/includes/htmlform/HTMLForm.php
index 7a74cbf8fb19..e0128aa7b168 100644
--- a/includes/htmlform/HTMLForm.php
+++ b/includes/htmlform/HTMLForm.php
@@ -24,6 +24,7 @@
use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
use MediaWiki\Linker\LinkTarget;
use MediaWiki\Page\PageReference;
+use MediaWiki\Session\CsrfTokenSet;
/**
* Object handling generic submission, CSRF protection, layout and
@@ -592,12 +593,12 @@ class HTMLForm extends ContextSource {
if ( $this->getMethod() !== 'post' ) {
$tokenOkay = true; // no session check needed
} elseif ( $this->getRequest()->wasPosted() ) {
- $editToken = $this->getRequest()->getVal( 'wpEditToken' );
+ $editToken = $this->getRequest()->getVal( CsrfTokenSet::DEFAULT_FIELD_NAME );
if ( $this->getUser()->isRegistered() || $editToken !== null ) {
// Session tokens for logged-out users have no security value.
// However, if the user gave one, check it in order to give a nice
// "session expired" error instead of "permission denied" or such.
- $tokenOkay = $this->getUser()->matchEditToken( $editToken, $this->mTokenSalt );
+ $tokenOkay = $this->getCsrfTokenSet()->matchToken( $editToken, $this->mTokenSalt );
} else {
$tokenOkay = true;
}
@@ -1194,9 +1195,9 @@ class HTMLForm extends ContextSource {
}
if ( $this->getMethod() === 'post' ) {
$html .= Html::hidden(
- 'wpEditToken',
- $this->getUser()->getEditToken( $this->mTokenSalt ),
- [ 'id' => 'wpEditToken' ]
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->getCsrfTokenSet()->getToken( $this->mTokenSalt )->toString(),
+ [ 'id' => CsrfTokenSet::DEFAULT_FIELD_NAME ]
) . "\n";
$html .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n";
}
diff --git a/includes/htmlform/HTMLFormField.php b/includes/htmlform/HTMLFormField.php
index 43cb401330c6..bf5782ba1372 100644
--- a/includes/htmlform/HTMLFormField.php
+++ b/includes/htmlform/HTMLFormField.php
@@ -1,5 +1,7 @@
<?php
+use MediaWiki\Session\CsrfTokenSet;
+
/**
* The parent class to generate form fields. Any field type should
* be a subclass of this.
@@ -376,7 +378,8 @@ abstract class HTMLFormField {
* @return bool
*/
protected function isSubmitAttempt( WebRequest $request ) {
- return $request->getCheck( 'wpEditToken' ) || $request->getCheck( 'wpFormIdentifier' );
+ return $request->getCheck( CsrfTokenSet::DEFAULT_FIELD_NAME ) ||
+ $request->getCheck( 'wpFormIdentifier' );
}
/**
diff --git a/includes/htmlform/fields/HTMLFormFieldCloner.php b/includes/htmlform/fields/HTMLFormFieldCloner.php
index 65a33cfcaef0..9d93729dfca6 100644
--- a/includes/htmlform/fields/HTMLFormFieldCloner.php
+++ b/includes/htmlform/fields/HTMLFormFieldCloner.php
@@ -1,5 +1,7 @@
<?php
+use MediaWiki\Session\CsrfTokenSet;
+
/**
* A container for HTMLFormFields that allows for multiple copies of the set of
* fields to be displayed to and entered by the user.
@@ -144,7 +146,9 @@ class HTMLFormFieldCloner extends HTMLFormField {
public function loadDataFromRequest( $request ) {
// It's possible that this might be posted with no fields. Detect that
// by looking for an edit token.
- if ( !$request->getCheck( 'wpEditToken' ) && $request->getArray( $this->mName ) === null ) {
+ if ( !$request->getCheck( CsrfTokenSet::DEFAULT_FIELD_NAME ) &&
+ $request->getArray( $this->mName ) === null
+ ) {
return $this->getDefault();
}
@@ -160,8 +164,7 @@ class HTMLFormFieldCloner extends HTMLFormField {
continue;
}
- // Add back in $request->getValues() so things that look for e.g.
- // wpEditToken don't fail.
+ // Add back in $request->getValues() so things that look for e.g. wpEditToken don't fail.
$data = $this->rekeyValuesArray( $key, $value ) + $request->getValues();
$fields = $this->createFieldsForKey( $key );
diff --git a/includes/page/Article.php b/includes/page/Article.php
index 7a109e9d2ce4..203d34e088bb 100644
--- a/includes/page/Article.php
+++ b/includes/page/Article.php
@@ -30,6 +30,7 @@ use MediaWiki\Permissions\PermissionStatus;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\RevisionStore;
use MediaWiki\Revision\SlotRecord;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\User\UserIdentity;
use MediaWiki\User\UserNameUtils;
use MediaWiki\Watchlist\WatchlistManager;
@@ -1896,8 +1897,11 @@ class Article implements Page {
$reason = $deleteReasonList;
}
- if ( $request->wasPosted() && $user->matchEditToken( $request->getVal( 'wpEditToken' ),
- [ 'delete', $this->getTitle()->getPrefixedText() ] )
+ if ( $request->wasPosted() &&
+ $this->getContext()->getCsrfTokenSet()->matchTokenField(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ [ 'delete', $this->getTitle()->getPrefixedText() ]
+ )
) {
# Flag to hide all contents of the archived revisions
@@ -2126,7 +2130,13 @@ class Article implements Page {
$form->appendContent(
$fieldset,
new OOUI\HtmlSnippet(
- Html::hidden( 'wpEditToken', $user->getEditToken( [ 'delete', $title->getPrefixedText() ] ) )
+ Html::hidden(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->getContext()
+ ->getCsrfTokenSet()
+ ->getToken( [ 'delete', $title->getPrefixedText() ] )
+ ->toString()
+ )
)
);
diff --git a/includes/page/ImageHistoryList.php b/includes/page/ImageHistoryList.php
index c686199f47e6..340f4f48f3f0 100644
--- a/includes/page/ImageHistoryList.php
+++ b/includes/page/ImageHistoryList.php
@@ -214,7 +214,7 @@ class ImageHistoryList extends ContextSource {
[
'target' => $this->title->getPrefixedText(),
'file' => $img,
- 'token' => $user->getEditToken( $img )
+ 'token' => $this->getCsrfTokenSet()->getToken( $img )->toString(),
]
);
} else {
diff --git a/includes/resourceloader/ResourceLoaderUserOptionsModule.php b/includes/resourceloader/ResourceLoaderUserOptionsModule.php
index 06496702324d..2cacb560c9d3 100644
--- a/includes/resourceloader/ResourceLoaderUserOptionsModule.php
+++ b/includes/resourceloader/ResourceLoaderUserOptionsModule.php
@@ -50,15 +50,15 @@ class ResourceLoaderUserOptionsModule extends ResourceLoaderModule {
* @return string JavaScript code
*/
public function getScript( ResourceLoaderContext $context ) {
- $user = $context->getUserObj();
-
+ $tokenSet = RequestContext::getMain()->getCsrfTokenSet();
$tokens = [
- 'patrolToken' => $user->getEditToken( 'patrol' ),
- 'watchToken' => $user->getEditToken( 'watch' ),
- 'csrfToken' => $user->getEditToken(),
+ 'patrolToken' => $tokenSet->getToken( 'patrol' )->toString(),
+ 'watchToken' => $tokenSet->getToken( 'watch' )->toString(),
+ 'csrfToken' => $tokenSet->getToken()->toString(),
];
$script = 'mw.user.tokens.set(' . $context->encodeJson( $tokens ) . ');';
+ $user = $context->getUserObj();
$userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
$options = $userOptionsLookup->getOptions( $user, UserOptionsLookup::EXCLUDE_DEFAULTS );
// Optimisation: Only output this function call if the user has non-default settings.
diff --git a/includes/revisiondelete/RevDelArchivedFileItem.php b/includes/revisiondelete/RevDelArchivedFileItem.php
index 3a710e839ffc..34879caadd8b 100644
--- a/includes/revisiondelete/RevDelArchivedFileItem.php
+++ b/includes/revisiondelete/RevDelArchivedFileItem.php
@@ -94,7 +94,7 @@ class RevDelArchivedFileItem extends RevDelFileItem {
[
'target' => $this->list->getPageName(),
'file' => $key,
- 'token' => $this->list->getUser()->getEditToken( $key )
+ 'token' => $this->list->getCsrfTokenSet()->getToken( $key )->toString(),
]
);
}
@@ -124,7 +124,7 @@ class RevDelArchivedFileItem extends RevDelFileItem {
[
'target' => $this->list->getPageName(),
'file' => $file->getKey(),
- 'token' => $user->getEditToken( $file->getKey() )
+ 'token' => $this->list->getCsrfTokenSet()->getToken( $file->getKey() )->toString(),
]
),
];
diff --git a/includes/revisiondelete/RevDelFileItem.php b/includes/revisiondelete/RevDelFileItem.php
index 4b51cfd93718..ac8d07408b45 100644
--- a/includes/revisiondelete/RevDelFileItem.php
+++ b/includes/revisiondelete/RevDelFileItem.php
@@ -154,8 +154,9 @@ class RevDelFileItem extends RevDelItem {
[
'target' => $this->list->getPageName(),
'file' => $this->file->getArchiveName(),
- 'token' => $this->list->getUser()->getEditToken(
- $this->file->getArchiveName() )
+ 'token' => $this->list->getCsrfTokenSet()
+ ->getToken( $this->file->getArchiveName() )
+ ->toString(),
]
);
}
@@ -235,7 +236,9 @@ class RevDelFileItem extends RevDelItem {
[
'target' => $this->list->getPageName(),
'file' => $file->getArchiveName(),
- 'token' => $user->getEditToken( $file->getArchiveName() )
+ 'token' => $this->list->getCsrfTokenSet()
+ ->getToken( $file->getArchiveName() )
+ ->toString(),
]
),
];
diff --git a/includes/search/searchwidgets/SearchFormWidget.php b/includes/search/searchwidgets/SearchFormWidget.php
index 56f791fbc70b..9c8ee5417e12 100644
--- a/includes/search/searchwidgets/SearchFormWidget.php
+++ b/includes/search/searchwidgets/SearchFormWidget.php
@@ -317,10 +317,13 @@ class SearchFormWidget {
false,
// The token goes here rather than in a hidden field so it
// is only sent when necessary (not every form submission)
- [ 'value' => $user->getEditToken(
- 'searchnamespace',
- $this->specialSearch->getRequest()
- ) ]
+ [
+ 'value' => $this->specialSearch
+ ->getContext()
+ ->getCsrfTokenSet()
+ ->getToken( 'searchnamespace' )
+ ->toString(),
+ ]
);
}
diff --git a/includes/specials/SpecialEditTags.php b/includes/specials/SpecialEditTags.php
index 65b94d4534d2..732c67e366cd 100644
--- a/includes/specials/SpecialEditTags.php
+++ b/includes/specials/SpecialEditTags.php
@@ -20,6 +20,7 @@
*/
use MediaWiki\Permissions\PermissionManager;
+use MediaWiki\Session\CsrfTokenSet;
/**
* Special page for adding and removing change tags to individual revisions.
@@ -288,7 +289,13 @@ class SpecialEditTags extends UnlistedSpecialPage {
'</td>' .
"</tr>\n" .
Xml::closeElement( 'table' ) .
- Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() ) .
+ Html::hidden(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->getContext()
+ ->getCsrfTokenSet()
+ ->getToken()
+ ->toString()
+ ) .
Html::hidden( 'target', $this->targetObj->getPrefixedText() ) .
Html::hidden( 'type', $this->typeName ) .
Html::hidden( 'ids', implode( ',', $this->ids ) ) .
@@ -400,8 +407,7 @@ class SpecialEditTags extends UnlistedSpecialPage {
protected function submit() {
// Check edit token on submission
$request = $this->getRequest();
- $token = $request->getVal( 'wpEditToken' );
- if ( $this->submitClicked && !$this->getUser()->matchEditToken( $token ) ) {
+ if ( $this->submitClicked && !$this->getContext()->getCsrfTokenSet()->matchTokenField() ) {
$this->getOutput()->addWikiMsg( 'sessionfailure' );
return false;
}
diff --git a/includes/specials/SpecialEmailUser.php b/includes/specials/SpecialEmailUser.php
index 0a7d4cac0790..e613e54b61e1 100644
--- a/includes/specials/SpecialEmailUser.php
+++ b/includes/specials/SpecialEmailUser.php
@@ -23,6 +23,7 @@
use MediaWiki\MediaWikiServices;
use MediaWiki\Preferences\MultiUsernameFilter;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\User\UserNamePrefixSearch;
use MediaWiki\User\UserNameUtils;
use MediaWiki\User\UserOptionsLookup;
@@ -146,7 +147,7 @@ class SpecialEmailUser extends UnlistedSpecialPage {
// error out if sending user cannot do this
$error = self::getPermissionsError(
$this->getUser(),
- $this->getRequest()->getVal( 'wpEditToken' ),
+ $this->getRequest()->getVal( CsrfTokenSet::DEFAULT_FIELD_NAME ),
$this->getConfig()
);
diff --git a/includes/specials/SpecialExpandTemplates.php b/includes/specials/SpecialExpandTemplates.php
index 2c13058ac51b..5b6bbd4443ba 100644
--- a/includes/specials/SpecialExpandTemplates.php
+++ b/includes/specials/SpecialExpandTemplates.php
@@ -293,7 +293,7 @@ class SpecialExpandTemplates extends SpecialPage {
// do not show the preview unless anonymous editing is allowed.
if ( $user->isAnon() && !$this->getAuthority()->isAllowed( 'edit' ) ) {
$error = [ 'expand_templates_preview_fail_html_anon' ];
- } elseif ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ), '', $request ) ) {
+ } elseif ( !$this->getContext()->getCsrfTokenSet()->matchTokenField() ) {
$error = [ 'expand_templates_preview_fail_html' ];
} else {
$error = false;
diff --git a/includes/specials/SpecialImport.php b/includes/specials/SpecialImport.php
index 7d7fafdc216f..0e7a2e285aa0 100644
--- a/includes/specials/SpecialImport.php
+++ b/includes/specials/SpecialImport.php
@@ -139,7 +139,7 @@ class SpecialImport extends SpecialPage {
$user = $this->getUser();
$fullInterwikiPrefix = null;
- if ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ) ) ) {
+ if ( !$this->getContext()->getCsrfTokenSet()->matchTokenField() ) {
$source = Status::newFatal( 'import-token-mismatch' );
} elseif ( $sourceName === 'upload' ) {
$isUpload = true;
diff --git a/includes/specials/SpecialMergeHistory.php b/includes/specials/SpecialMergeHistory.php
index a683e6f144ef..67aed2520e68 100644
--- a/includes/specials/SpecialMergeHistory.php
+++ b/includes/specials/SpecialMergeHistory.php
@@ -25,6 +25,7 @@ use MediaWiki\Cache\LinkBatchFactory;
use MediaWiki\Page\MergeHistoryFactory;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\RevisionStore;
+use MediaWiki\Session\CsrfTokenSet;
use Wikimedia\Rdbms\ILoadBalancer;
/**
@@ -124,7 +125,7 @@ class SpecialMergeHistory extends SpecialPage {
$this->mComment = $request->getText( 'wpComment' );
$this->mMerge = $request->wasPosted()
- && $this->getUser()->matchEditToken( $request->getVal( 'wpEditToken' ) );
+ && $this->getContext()->getCsrfTokenSet()->matchTokenField();
// target page
if ( $this->mSubmitted ) {
@@ -306,7 +307,10 @@ class SpecialMergeHistory extends SpecialPage {
$misc .= Html::hidden( 'destID', $this->mDestObj->getArticleID() );
$misc .= Html::hidden( 'target', $this->mTarget );
$misc .= Html::hidden( 'dest', $this->mDest );
- $misc .= Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() );
+ $misc .= Html::hidden(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->getContext()->getCsrfTokenSet()->getToken()->toString()
+ );
$misc .= Xml::closeElement( 'form' );
$out->addHTML( $misc );
diff --git a/includes/specials/SpecialMovepage.php b/includes/specials/SpecialMovepage.php
index 526790021568..395c82ffb9ba 100644
--- a/includes/specials/SpecialMovepage.php
+++ b/includes/specials/SpecialMovepage.php
@@ -27,6 +27,7 @@ use MediaWiki\MediaWikiServices;
use MediaWiki\Page\MovePageFactory;
use MediaWiki\Page\WikiPageFactory;
use MediaWiki\Permissions\PermissionManager;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\User\UserOptionsLookup;
use MediaWiki\Watchlist\WatchlistManager;
use Wikimedia\Rdbms\ILoadBalancer;
@@ -206,7 +207,7 @@ class MovePageForm extends UnlistedSpecialPage {
$this->watch = $request->getCheck( 'wpWatch' ) && $user->isRegistered();
if ( $request->getVal( 'action' ) == 'submit' && $request->wasPosted()
- && $user->matchEditToken( $request->getVal( 'wpEditToken' ) )
+ && $this->getContext()->getCsrfTokenSet()->matchTokenField()
) {
$this->doSubmit();
} else {
@@ -596,7 +597,10 @@ class MovePageForm extends UnlistedSpecialPage {
new OOUI\HtmlSnippet(
$hiddenFields .
Html::hidden( 'wpOldTitle', $this->oldTitle->getPrefixedText() ) .
- Html::hidden( 'wpEditToken', $user->getEditToken() )
+ Html::hidden(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->getContext()->getCsrfTokenSet()->getToken()->toString()
+ )
)
);
diff --git a/includes/specials/SpecialRevisionDelete.php b/includes/specials/SpecialRevisionDelete.php
index efb0f04dc014..1da6b275efe6 100644
--- a/includes/specials/SpecialRevisionDelete.php
+++ b/includes/specials/SpecialRevisionDelete.php
@@ -23,6 +23,7 @@
use MediaWiki\Permissions\PermissionManager;
use MediaWiki\Revision\RevisionRecord;
+use MediaWiki\Session\CsrfTokenSet;
/**
* Special page allowing users with the appropriate permissions to view
@@ -43,9 +44,6 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
/** @var string Archive name, for reviewing deleted files */
private $archiveName;
- /** @var string Edit token for securing image views against XSS */
- private $token;
-
/** @var Title Title object for target parameter */
private $targetObj;
@@ -161,7 +159,6 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
# For reviewing deleted files...
$this->archiveName = $request->getVal( 'file' );
- $this->token = $request->getVal( 'token' );
if ( $this->archiveName && $this->targetObj ) {
$this->tryShowFile( $this->archiveName );
@@ -343,7 +340,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
throw new PermissionsError( 'deletedtext' );
}
}
- if ( !$user->matchEditToken( $this->token, $archiveName ) ) {
+ if ( !$this->getContext()->getCsrfTokenSet()->matchTokenField( 'token', $archiveName ) ) {
$lang = $this->getLanguage();
$this->getOutput()->addWikiMsg( 'revdelete-show-file-confirm',
$this->targetObj->getText(),
@@ -355,7 +352,10 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
'action' => $this->getPageTitle()->getLocalURL( [
'target' => $this->targetObj->getPrefixedDBkey(),
'file' => $archiveName,
- 'token' => $user->getEditToken( $archiveName ),
+ 'token' => $this->getContext()
+ ->getCsrfTokenSet()
+ ->getToken( $archiveName )
+ ->toString(),
] )
]
) .
@@ -494,7 +494,10 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
'</td>' .
"</tr>\n" .
Xml::closeElement( 'table' ) .
- Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() ) .
+ Html::hidden(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->getContext()->getCsrfTokenSet()->getToken()->toString()
+ ) .
Html::hidden( 'target', $this->targetObj->getPrefixedText() ) .
Html::hidden( 'type', $this->typeName ) .
Html::hidden( 'ids', implode( ',', $this->ids ) ) .
@@ -624,8 +627,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
*/
protected function submit() {
# Check edit token on submission
- $token = $this->getRequest()->getVal( 'wpEditToken' );
- if ( $this->submitClicked && !$this->getUser()->matchEditToken( $token ) ) {
+ if ( $this->submitClicked && !$this->getContext()->getCsrfTokenSet()->matchTokenField() ) {
$this->getOutput()->addWikiMsg( 'sessionfailure' );
return false;
diff --git a/includes/specials/SpecialSearch.php b/includes/specials/SpecialSearch.php
index 5d64cc6ad8e0..5916cdf01faa 100644
--- a/includes/specials/SpecialSearch.php
+++ b/includes/specials/SpecialSearch.php
@@ -728,11 +728,8 @@ class SpecialSearch extends SpecialPage {
$request = $this->getRequest();
if ( $user->isRegistered() &&
- $user->matchEditToken(
- $request->getVal( 'nsRemember' ),
- 'searchnamespace',
- $request
- ) && !$this->readOnlyMode->isReadOnly()
+ $this->getContext()->getCsrfTokenSet()->matchTokenField( 'nsRemember', 'searchnamespace' ) &&
+ !$this->readOnlyMode->isReadOnly()
) {
// Reset namespace preferences: namespaces are not searched
// when they're not mentioned in the URL parameters.
diff --git a/includes/specials/SpecialTags.php b/includes/specials/SpecialTags.php
index fdc2a41e2898..5276049b13a8 100644
--- a/includes/specials/SpecialTags.php
+++ b/includes/specials/SpecialTags.php
@@ -21,6 +21,8 @@
* @ingroup SpecialPage
*/
+use MediaWiki\Session\CsrfTokenSet;
+
/**
* A special page that lists tags for edits
*
@@ -314,7 +316,7 @@ class SpecialTags extends SpecialPage {
// fool HTMLForm into thinking the form hasn't been submitted yet. Otherwise
// we get into an infinite loop!
- $context->getRequest()->unsetVal( 'wpEditToken' );
+ $context->getRequest()->unsetVal( CsrfTokenSet::DEFAULT_FIELD_NAME );
$headerText = $this->msg( 'tags-create-warnings-above', $tag,
count( $status->getWarningsArray() ) )->parseAsBlock() .
diff --git a/includes/specials/SpecialUndelete.php b/includes/specials/SpecialUndelete.php
index 7f38bb8d6e93..bc116da09548 100644
--- a/includes/specials/SpecialUndelete.php
+++ b/includes/specials/SpecialUndelete.php
@@ -29,6 +29,7 @@ use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\RevisionRenderer;
use MediaWiki\Revision\RevisionStore;
use MediaWiki\Revision\SlotRecord;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\Storage\NameTableAccessException;
use MediaWiki\Storage\NameTableStore;
use MediaWiki\User\UserOptionsLookup;
@@ -171,8 +172,7 @@ class SpecialUndelete extends SpecialPage {
$this->mTimestamp = $time ? wfTimestamp( TS_MW, $time ) : '';
$this->mFilename = $request->getVal( 'file' );
- $posted = $request->wasPosted() &&
- $user->matchEditToken( $request->getVal( 'wpEditToken' ) );
+ $posted = $request->wasPosted() && $this->getContext()->getCsrfTokenSet()->matchTokenField();
$this->mRestore = $request->getCheck( 'restore' ) && $posted;
$this->mRevdel = $request->getCheck( 'revdel' ) && $posted;
$this->mInvert = $request->getCheck( 'invert' ) && $posted;
@@ -314,7 +314,7 @@ class SpecialUndelete extends SpecialPage {
} else {
throw new PermissionsError( 'deletedtext' );
}
- } elseif ( !$user->matchEditToken( $this->mToken, $this->mFilename ) ) {
+ } elseif ( !$this->getContext()->getCsrfTokenSet()->matchToken( $this->mToken, $this->mFilename ) ) {
$this->showFileConfirmationForm( $this->mFilename );
} else {
$this->showFile( $this->mFilename );
@@ -666,8 +666,8 @@ class SpecialUndelete extends SpecialPage {
'value' => $timestamp ] ) .
Xml::element( 'input', [
'type' => 'hidden',
- 'name' => 'wpEditToken',
- 'value' => $user->getEditToken() ] ) .
+ 'name' => CsrfTokenSet::DEFAULT_FIELD_NAME,
+ 'value' => $this->getContext()->getCsrfTokenSet()->getToken()->toString() ] ) .
new OOUI\FieldLayout(
new OOUI\Widget( [
'content' => new OOUI\HorizontalLayout( [
@@ -809,7 +809,7 @@ class SpecialUndelete extends SpecialPage {
'action' => $this->getPageTitle()->getLocalURL( [
'target' => $this->mTarget,
'file' => $key,
- 'token' => $user->getEditToken( $key ),
+ 'token' => $this->getContext()->getCsrfTokenSet()->getToken()->toString(),
] ),
]
) .
@@ -988,7 +988,9 @@ class SpecialUndelete extends SpecialPage {
] ),
new OOUI\HtmlSnippet(
Html::hidden( 'target', $this->mTarget ) .
- Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() )
+ Html::hidden(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->getContext()->getCsrfTokenSet()->getToken()->toString() )
)
);
}
@@ -1039,7 +1041,10 @@ class SpecialUndelete extends SpecialPage {
if ( $this->mAllowed ) {
# Slip in the hidden controls here
$misc = Html::hidden( 'target', $this->mTarget );
- $misc .= Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() );
+ $misc .= Html::hidden(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->getContext()->getCsrfTokenSet()->getToken()->toString()
+ );
$history .= $misc;
$form->appendContent( new OOUI\HtmlSnippet( $history ) );
@@ -1251,7 +1256,7 @@ class SpecialUndelete extends SpecialPage {
[
'target' => $this->mTargetObj->getPrefixedText(),
'file' => $key,
- 'token' => $user->getEditToken( $key )
+ 'token' => $this->getContext()->getCsrfTokenSet()->getToken( $key )->toString(),
]
);
diff --git a/includes/specials/SpecialUpload.php b/includes/specials/SpecialUpload.php
index e1abe163a64b..909052dd3259 100644
--- a/includes/specials/SpecialUpload.php
+++ b/includes/specials/SpecialUpload.php
@@ -156,8 +156,7 @@ class SpecialUpload extends SpecialPage {
|| $request->getCheck( 'wpReUpload' ); // b/w compat
// If it was posted check for the token (no remote POST'ing with user credentials)
- $token = $request->getVal( 'wpEditToken' );
- $this->mTokenOk = $this->getUser()->matchEditToken( $token );
+ $this->mTokenOk = $this->getContext()->getCsrfTokenSet()->matchTokenField();
$this->uploadFormTextTop = '';
$this->uploadFormTextAfterSummary = '';
diff --git a/includes/specials/SpecialUserrights.php b/includes/specials/SpecialUserrights.php
index 96d20fa92983..92660b42fc60 100644
--- a/includes/specials/SpecialUserrights.php
+++ b/includes/specials/SpecialUserrights.php
@@ -22,6 +22,7 @@
*/
use MediaWiki\MediaWikiServices;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\User\UserGroupManager;
use MediaWiki\User\UserGroupManagerFactory;
use MediaWiki\User\UserNamePrefixSearch;
@@ -186,7 +187,10 @@ class UserrightsPage extends SpecialPage {
$request->wasPosted() &&
$request->getCheck( 'saveusergroups' ) &&
$this->mTarget !== null &&
- $user->matchEditToken( $request->getVal( 'wpEditToken' ), $this->mTarget )
+ $this->getContext()->getCsrfTokenSet()->matchTokenField(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->mTarget
+ )
) {
/*
* If the user is blocked and they only have "partial" access
@@ -770,7 +774,10 @@ class UserrightsPage extends SpecialPage {
]
) .
Html::hidden( 'user', $this->mTarget ) .
- Html::hidden( 'wpEditToken', $this->getUser()->getEditToken( $this->mTarget ) ) .
+ Html::hidden(
+ CsrfTokenSet::DEFAULT_FIELD_NAME,
+ $this->getContext()->getCsrfTokenSet()->getToken( $this->mTarget )->toString()
+ ) .
Html::hidden(
'conflictcheck-originalgroups',
implode( ',', $user->getGroups() )
diff --git a/includes/specials/SpecialWatchlist.php b/includes/specials/SpecialWatchlist.php
index 16c54d0858d2..af53ee03c8f5 100644
--- a/includes/specials/SpecialWatchlist.php
+++ b/includes/specials/SpecialWatchlist.php
@@ -117,7 +117,7 @@ class SpecialWatchlist extends ChangesListSpecialPage {
if ( ( $config->get( 'EnotifWatchlist' ) || $config->get( 'ShowUpdatedMarker' ) )
&& $request->getVal( 'reset' )
&& $request->wasPosted()
- && $user->matchEditToken( $request->getVal( 'token' ) )
+ && $this->getContext()->getCsrfTokenSet()->matchTokenField( 'token' )
) {
$this->watchlistManager->clearAllUserNotifications( $user );
$output->redirect( $this->getPageTitle()->getFullURL( $opts->getChangedValues() ) );
@@ -863,7 +863,7 @@ class SpecialWatchlist extends ChangesListSpecialPage {
'id' => 'mw-watchlist-resetbutton' ] ) . "\n" .
Xml::submitButton( $this->msg( 'enotif_reset' )->text(),
[ 'name' => 'mw-watchlist-reset-submit' ] ) . "\n" .
- Html::hidden( 'token', $user->getEditToken() ) . "\n" .
+ Html::hidden( 'token', $this->getContext()->getCsrfTokenSet()->getToken()->toString() ) . "\n" .
Html::hidden( 'reset', 'all' ) . "\n";
foreach ( $nondefaults as $key => $value ) {
$form .= Html::hidden( $key, $value ) . "\n";
diff --git a/tests/phpunit/includes/EditPageConstraintsTest.php b/tests/phpunit/includes/EditPageConstraintsTest.php
index 1bc904983786..95f6e4ee3886 100644
--- a/tests/phpunit/includes/EditPageConstraintsTest.php
+++ b/tests/phpunit/includes/EditPageConstraintsTest.php
@@ -2,6 +2,7 @@
use MediaWiki\EditPage\SpamChecker;
use MediaWiki\Permissions\PermissionManager;
+use MediaWiki\Session\CsrfTokenSet;
/**
* Integration tests for the various edit constraints, ensuring
@@ -102,14 +103,6 @@ class EditPageConstraintsTest extends MediaWikiLangTestCase {
);
}
- if ( !isset( $edit['wpEditToken'] ) ) {
- $edit['wpEditToken'] = $user->getEditToken();
- }
-
- if ( !isset( $edit['wpEdittime'] ) && !isset( $edit['editRevId'] ) ) {
- $edit['wpEdittime'] = $page->exists() ? $page->getTimestamp() : '';
- }
-
if ( !isset( $edit['wpStarttime'] ) ) {
$edit['wpStarttime'] = wfTimestampNow();
}
@@ -119,7 +112,12 @@ class EditPageConstraintsTest extends MediaWikiLangTestCase {
}
$req = new FauxRequest( $edit, true ); // session ??
-
+ if ( !isset( $edit['wpEditToken'] ) ) {
+ $req->setVal(
+ 'wpEditToken',
+ ( new CsrfTokenSet( $req ) )->getToken()->toString()
+ );
+ }
$context = new RequestContext();
$context->setRequest( $req );
$context->setTitle( $title );
diff --git a/tests/phpunit/includes/EditPageTest.php b/tests/phpunit/includes/EditPageTest.php
index 2725b8c61eb5..d8aebe2e573b 100644
--- a/tests/phpunit/includes/EditPageTest.php
+++ b/tests/phpunit/includes/EditPageTest.php
@@ -2,6 +2,7 @@
use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\RevisionRecord;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\Storage\EditResult;
use MediaWiki\User\UserIdentity;
use Wikimedia\TestingAccessWrapper;
@@ -157,10 +158,6 @@ class EditPageTest extends MediaWikiLangTestCase {
$this->assertEditedTextEquals( $baseText, $currentText );
}
- if ( !isset( $edit['wpEditToken'] ) ) {
- $edit['wpEditToken'] = $user->getEditToken();
- }
-
if ( !isset( $edit['wpEdittime'] ) && !isset( $edit['editRevId'] ) ) {
$edit['wpEdittime'] = $page->exists() ? $page->getTimestamp() : '';
}
@@ -174,6 +171,12 @@ class EditPageTest extends MediaWikiLangTestCase {
}
$req = new FauxRequest( $edit, true ); // session ??
+ if ( !isset( $edit['wpEditToken'] ) ) {
+ $req->setVal(
+ 'wpEditToken',
+ ( new CsrfTokenSet( $req ) )->getToken()->toString()
+ );
+ }
$context = new RequestContext();
$context->setRequest( $req );
@@ -781,11 +784,8 @@ hello
* @covers EditPage
*/
public function testCheckDirectEditingDisallowed_forNonTextContent() {
- $user = $this->getTestUser()->getUser();
-
$edit = [
'wpTextbox1' => serialize( 'non-text content' ),
- 'wpEditToken' => $user->getEditToken(),
'wpEdittime' => '',
'editRevId' => 0,
'wpStarttime' => wfTimestampNow(),
@@ -810,11 +810,8 @@ hello
}
} );
- $user = $this->getTestUser()->getUser();
-
$status = $this->doEditDummyNonTextPage( [
'wpTextbox1' => 'some text',
- 'wpEditToken' => $user->getEditToken(),
'wpEdittime' => '',
'editRevId' => 0,
'wpStarttime' => wfTimestampNow(),
@@ -837,11 +834,8 @@ hello
}
} );
- $user = $this->getTestUser()->getUser();
-
$status = $this->doEditDummyNonTextPage( [
'wpTextbox1' => 'some text',
- 'wpEditToken' => $user->getEditToken(),
'wpEdittime' => '',
'editRevId' => 0,
'wpStarttime' => wfTimestampNow(),
@@ -863,6 +857,10 @@ hello
$ep->setContextTitle( $title );
$req = new FauxRequest( $edit, true );
+ $req->setVal(
+ 'wpEditToken',
+ ( new CsrfTokenSet( $req ) )->getToken()->toString()
+ );
$ep->importFormData( $req );
return $ep->internalAttemptSave( $result, false );
diff --git a/tests/phpunit/includes/OutputPageTest.php b/tests/phpunit/includes/OutputPageTest.php
index 5929684df72d..e4f98150c18b 100644
--- a/tests/phpunit/includes/OutputPageTest.php
+++ b/tests/phpunit/includes/OutputPageTest.php
@@ -8,7 +8,6 @@ use MediaWiki\Page\PageReferenceValue;
use MediaWiki\Page\PageStoreRecord;
use MediaWiki\Permissions\Authority;
use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait;
-use PHPUnit\Framework\MockObject\MockObject;
use Wikimedia\DependencyStore\KeyValueDependencyStore;
use Wikimedia\TestingAccessWrapper;
@@ -3206,64 +3205,40 @@ class OutputPageTest extends MediaWikiIntegrationTestCase {
$this->assertArraySubmapSame( $expectedEditableConfig, $op->getJSVars() );
}
- /**
- * @param bool $registered
- * @param bool $matchToken
- * @return MockObject|User
- */
- private function mockUser( bool $registered, bool $matchToken ) {
- $user = $this->createNoOpMock( User::class, [ 'isRegistered', 'matchEditToken' ] );
- $user->method( 'isRegistered' )->willReturn( $registered );
- $user->method( 'matchEditToken' )->willReturn( $matchToken );
- return $user;
- }
-
public function provideUserCanPreview() {
yield 'all good' => [
- 'performer' => $this->mockUserAuthorityWithPermissions(
- $this->mockUser( true, true ),
- [ 'edit' ]
- ),
+ 'performer' => $this->mockRegisteredAuthorityWithPermissions( [ 'edit' ] ),
+ 'matchToken' => true,
'request' => new FauxRequest( [ 'action' => 'submit' ], true ),
true
];
yield 'get request' => [
- 'performer' => $this->mockUserAuthorityWithPermissions(
- $this->mockUser( true, true ),
- [ 'edit' ]
- ),
+ 'performer' => $this->mockRegisteredAuthorityWithPermissions( [ 'edit' ] ),
+ 'matchToken' => true,
'request' => new FauxRequest( [ 'action' => 'submit' ], false ),
false
];
yield 'not a submit action' => [
- 'performer' => $this->mockUserAuthorityWithPermissions(
- $this->mockUser( true, true ),
- [ 'edit' ]
- ),
+ 'performer' => $this->mockRegisteredAuthorityWithPermissions( [ 'edit' ] ),
+ 'matchToken' => true,
'request' => new FauxRequest( [ 'action' => 'something' ], true ),
false
];
yield 'anon can not' => [
- 'performer' => $this->mockUserAuthorityWithPermissions(
- $this->mockUser( false, true ),
- [ 'edit' ]
- ),
+ 'performer' => $this->mockAnonAuthorityWithPermissions( [ 'edit' ] ),
+ 'matchToken' => true,
'request' => new FauxRequest( [ 'action' => 'submit' ], true ),
false
];
yield 'token not match' => [
- 'performer' => $this->mockUserAuthorityWithPermissions(
- $this->mockUser( true, false ),
- [ 'edit' ]
- ),
+ 'performer' => $this->mockRegisteredAuthorityWithPermissions( [ 'edit' ] ),
+ 'matchToken' => false,
'request' => new FauxRequest( [ 'action' => 'submit' ], true ),
false
];
yield 'no permission' => [
- 'performer' => $this->mockUserAuthorityWithoutPermissions(
- $this->mockUser( true, true ),
- [ 'edit' ]
- ),
+ 'performer' => $this->mockRegisteredAuthorityWithoutPermissions( [ 'edit' ] ),
+ 'matchToken' => true,
'request' => new FauxRequest( [ 'action' => 'submit' ], true ),
false
];
@@ -3273,7 +3248,9 @@ class OutputPageTest extends MediaWikiIntegrationTestCase {
* @dataProvider provideUserCanPreview
* @covers OutputPage::userCanPreview
*/
- public function testUserCanPreview( Authority $performer, WebRequest $request, bool $expected ) {
+ public function testUserCanPreview( Authority $performer, bool $matchToken, WebRequest $request, bool $expected ) {
+ // We don't set the user in the session, so we logged out token should be good enough.
+ $request->setVal( 'wpEditToken', $matchToken ? new LoggedOutEditToken() : 'invalid' );
$op = $this->newInstance( [], $request, null, $performer );
$this->assertSame( $expected, $op->userCanPreview() );
}
diff --git a/tests/phpunit/includes/actions/RollbackActionTest.php b/tests/phpunit/includes/actions/RollbackActionTest.php
index 4c53d4bfe6c5..eed131b77647 100644
--- a/tests/phpunit/includes/actions/RollbackActionTest.php
+++ b/tests/phpunit/includes/actions/RollbackActionTest.php
@@ -6,6 +6,7 @@ use Article;
use DerivativeContext;
use ErrorPageError;
use FauxRequest;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWikiIntegrationTestCase;
use RequestContext;
use RollbackAction;
@@ -43,6 +44,13 @@ class RollbackActionTest extends MediaWikiIntegrationTestCase {
private function getRollbackAction( WebRequest $request ) {
$context = new DerivativeContext( RequestContext::getMain() );
$context->setTitle( $this->testPage );
+ $request->getSession()->setUser( $this->sysop );
+ if ( !$request->getVal( 'token' ) ) {
+ $request->setVal(
+ 'token',
+ ( new CsrfTokenSet( $request ) )->getToken( 'rollback' )->toString()
+ );
+ }
$context->setRequest( $request );
$context->setUser( $this->sysop );
return new RollbackAction( Article::newFromTitle( $this->testPage, $context ), $context );
@@ -94,7 +102,6 @@ class RollbackActionTest extends MediaWikiIntegrationTestCase {
public function testRollback() {
$request = new FauxRequest( [
'from' => $this->vandal->getName(),
- 'token' => $this->sysop->getEditToken( 'rollback' ),
] );
$rollbackAction = $this->getRollbackAction( $request );
$rollbackAction->handleRollbackRequest();
@@ -118,7 +125,6 @@ class RollbackActionTest extends MediaWikiIntegrationTestCase {
public function testRollbackMarkBot() {
$request = new FauxRequest( [
'from' => $this->vandal->getName(),
- 'token' => $this->sysop->getEditToken( 'rollback' ),
'bot' => true,
] );
$rollbackAction = $this->getRollbackAction( $request );
diff --git a/tests/phpunit/includes/actions/WatchActionTest.php b/tests/phpunit/includes/actions/WatchActionTest.php
index 6180a0106394..4526eee64c31 100644
--- a/tests/phpunit/includes/actions/WatchActionTest.php
+++ b/tests/phpunit/includes/actions/WatchActionTest.php
@@ -443,8 +443,8 @@ class WatchActionTest extends MediaWikiIntegrationTestCase {
$this->hideDeprecated( 'WatchAction::getWatchToken' );
$user = $this->createMock( User::class );
$user->expects( $this->once() )
- ->method( 'getEditToken' )
- ->with( 'watch' );
+ ->method( 'getRequest' )
+ ->willReturn( new FauxRequest() );
WatchAction::getWatchToken( $this->watchAction->getTitle(), $user, 'INVALID_ACTION' );
}
@@ -456,7 +456,9 @@ class WatchActionTest extends MediaWikiIntegrationTestCase {
public function testGetWatchTokenProxiesUserGetEditToken() {
$this->hideDeprecated( 'WatchAction::getWatchToken' );
$user = $this->createMock( User::class );
- $user->expects( $this->once() )->method( 'getEditToken' );
+ $user->expects( $this->once() )
+ ->method( 'getRequest' )
+ ->willReturn( new FauxRequest() );
WatchAction::getWatchToken( $this->watchAction->getTitle(), $user );
}
diff --git a/tests/phpunit/includes/api/ApiDeleteTest.php b/tests/phpunit/includes/api/ApiDeleteTest.php
index 742ee349a4c9..647d2e34c5d1 100644
--- a/tests/phpunit/includes/api/ApiDeleteTest.php
+++ b/tests/phpunit/includes/api/ApiDeleteTest.php
@@ -98,11 +98,10 @@ class ApiDeleteTest extends ApiTestCase {
// test deletion without permission
try {
$user = new User();
- $apiResult = $this->doApiRequest( [
+ $apiResult = $this->doApiRequestWithToken( [
'action' => 'delete',
'title' => $name,
- 'token' => $user->getEditToken(),
- ], null, null, $user );
+ ], null, $user );
} finally {
$this->assertTrue( Title::newFromText( $name )->exists() );
}
diff --git a/tests/phpunit/includes/api/ApiLogoutTest.php b/tests/phpunit/includes/api/ApiLogoutTest.php
index 066cbc478a06..446c07469c0b 100644
--- a/tests/phpunit/includes/api/ApiLogoutTest.php
+++ b/tests/phpunit/includes/api/ApiLogoutTest.php
@@ -46,8 +46,7 @@ class ApiLogoutTest extends ApiTestCase {
$user = $this->getTestSysop()->getUser();
$this->assertTrue( $user->isRegistered(), 'sanity check' );
- // Logic copied from SkinTemplate.
- $token = $user->getEditToken( 'logoutToken', $wgRequest );
+ $token = $wgRequest->getSession()->getToken( 'logoutToken' )->toString();
$this->doUserLogout( $token, $user );
$this->assertFalse( $user->isRegistered() );
diff --git a/tests/phpunit/includes/api/ApiUserrightsTest.php b/tests/phpunit/includes/api/ApiUserrightsTest.php
index 2d617e176446..9d115868546e 100644
--- a/tests/phpunit/includes/api/ApiUserrightsTest.php
+++ b/tests/phpunit/includes/api/ApiUserrightsTest.php
@@ -2,6 +2,7 @@
use MediaWiki\Block\DatabaseBlock;
use MediaWiki\MediaWikiServices;
+use MediaWiki\Session\CsrfTokenSet;
/**
* @group API
@@ -244,14 +245,11 @@ class ApiUserrightsTest extends ApiTestCase {
$sysop = $this->getTestSysop()->getUser();
$user = $this->getMutableTestUser()->getUser();
- $token = $sysop->getEditToken( $user->getName() );
-
- $res = $this->doApiRequest( [
+ $res = $this->doApiRequestWithToken( [
'action' => 'userrights',
'user' => $user->getName(),
'add' => 'sysop',
- 'token' => $token,
- ] );
+ ], null, $sysop );
$user->clearInstanceCache();
$this->assertSame( [ 'sysop' ], $user->getGroups() );
@@ -269,17 +267,17 @@ class ApiUserrightsTest extends ApiTestCase {
* @return ApiUserrights
*/
private function getMockForProcessingExpiries( $canProcessExpiries ) {
- $sysop = $this->getTestSysop()->getUser();
$user = $this->getMutableTestUser()->getUser();
-
- $token = $sysop->getEditToken( 'userrights' );
-
- $main = new ApiMain( new FauxRequest( [
+ $request = new FauxRequest( [
'action' => 'userrights',
'user' => $user->getName(),
'add' => 'sysop',
- 'token' => $token,
- ] ) );
+ ] );
+ $request->setVal(
+ 'token',
+ ( new CsrfTokenSet( $request ) )->getToken( 'userrights' )->toString()
+ );
+ $main = new ApiMain( $request );
$mockUserRightsPage = $this->getMockBuilder( UserrightsPage::class )
->onlyMethods( [ 'canProcessExpiries' ] )
diff --git a/tests/phpunit/includes/api/ApiWatchTest.php b/tests/phpunit/includes/api/ApiWatchTest.php
index 7f31b61e10e7..381b130a2a3d 100644
--- a/tests/phpunit/includes/api/ApiWatchTest.php
+++ b/tests/phpunit/includes/api/ApiWatchTest.php
@@ -235,13 +235,12 @@ class ApiWatchTest extends ApiTestCase {
// This (and assertTrue below) are mostly for completeness.
$this->assertFalse( $watchlistManager->isWatched( $contextUser, $title ) );
- $data = $this->doApiRequest( [
+ $data = $this->doApiRequestWithToken( [
'action' => 'rollback',
'title' => 'Help:UTPage',
'user' => $revUser,
- 'token' => $contextUser->getEditToken( 'rollback' ),
'watchlist' => 'watch'
- ] );
+ ], null, $contextUser );
$this->assertArrayHasKey( 'rollback', $data[0] );
$this->assertArrayHasKey( 'title', $data[0]['rollback'] );
diff --git a/tests/phpunit/includes/specials/SpecialPageExecutor.php b/tests/phpunit/includes/specials/SpecialPageExecutor.php
index 887d11d43dc9..650fdf494a5e 100644
--- a/tests/phpunit/includes/specials/SpecialPageExecutor.php
+++ b/tests/phpunit/includes/specials/SpecialPageExecutor.php
@@ -92,11 +92,13 @@ class SpecialPageExecutor {
*/
private function setEditTokenFromUser( DerivativeContext $context ) {
$request = $context->getRequest();
-
// Edits via GET are a security issue and should not succeed. On the other hand, not all
// POST requests are edits, but should ignore unused parameters.
if ( !$request->getCheck( 'wpEditToken' ) && $request->wasPosted() ) {
- $request->setVal( 'wpEditToken', $context->getUser()->getEditToken() );
+ $request->setVal(
+ 'wpEditToken',
+ $context->getCsrfTokenSet()->getToken()->toString()
+ );
}
}
diff --git a/tests/phpunit/includes/upload/UploadFromUrlTest.php b/tests/phpunit/includes/upload/UploadFromUrlTest.php
index 62d7a6cc85ee..0e9c26b0a44b 100644
--- a/tests/phpunit/includes/upload/UploadFromUrlTest.php
+++ b/tests/phpunit/includes/upload/UploadFromUrlTest.php
@@ -105,7 +105,6 @@ class UploadFromUrlTest extends ApiTestCase {
* @depends testClearQueue
*/
public function testSetupUrlDownload( $data ) {
- $token = $this->user->getEditToken();
$exception = false;
try {
@@ -120,10 +119,9 @@ class UploadFromUrlTest extends ApiTestCase {
$exception = false;
try {
- $this->doApiRequest( [
+ $this->doApiRequestWithToken( [
'action' => 'upload',
- 'token' => $token,
- ], $data );
+ ], $data, $this->user );
} catch ( ApiUsageException $e ) {
$exception = true;
$this->assertEquals( 'One of the parameters "filekey", "file" and "url" is required.',
@@ -133,11 +131,10 @@ class UploadFromUrlTest extends ApiTestCase {
$exception = false;
try {
- $this->doApiRequest( [
+ $this->doApiRequestWithToken( [
'action' => 'upload',
'url' => 'http://www.example.com/test.png',
- 'token' => $token,
- ], $data );
+ ], $data, $this->user );
} catch ( ApiUsageException $e ) {
$exception = true;
$this->assertEquals( 'The "filename" parameter must be set.', $e->getMessage() );
@@ -147,12 +144,11 @@ class UploadFromUrlTest extends ApiTestCase {
$this->user->removeGroup( 'sysop' );
$exception = false;
try {
- $this->doApiRequest( [
+ $this->doApiRequestWithToken( [
'action' => 'upload',
'url' => 'http://www.example.com/test.png',
'filename' => 'UploadFromUrlTest.png',
- 'token' => $token,
- ], $data );
+ ], $data, $this->user );
} catch ( ApiUsageException $e ) {
$exception = true;
// Two error messages are possible depending on the number of groups in the wiki with upload rights:
@@ -183,16 +179,13 @@ class UploadFromUrlTest extends ApiTestCase {
$file = __DIR__ . '/../../data/upload/png-plain.png';
$this->installMockHttp( file_get_contents( $file ) );
- $token = $this->user->getEditToken();
-
$this->user->addGroup( 'users' );
- $data = $this->doApiRequest( [
+ $data = $this->doApiRequestWithToken( [
'action' => 'upload',
'filename' => 'UploadFromUrlTest.png',
'url' => 'http://upload.wikimedia.org/wikipedia/mediawiki/b/bc/Wiki.png',
'ignorewarnings' => true,
- 'token' => $token,
- ], $data );
+ ], $data, $this->user );
$this->assertEquals( 'Success', $data[0]['upload']['result'] );
$this->deleteFile( 'UploadFromUrlTest.png' );
diff --git a/tests/phpunit/integration/includes/Storage/UndoIntegrationTest.php b/tests/phpunit/integration/includes/Storage/UndoIntegrationTest.php
index 6c2bfab432e3..2fe68c18ddbc 100644
--- a/tests/phpunit/integration/includes/Storage/UndoIntegrationTest.php
+++ b/tests/phpunit/integration/includes/Storage/UndoIntegrationTest.php
@@ -7,6 +7,7 @@ use EditPage;
use FauxRequest;
use McrUndoAction;
use MediaWiki\Revision\RevisionStoreRecord;
+use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\Storage\EditResult;
use MediaWiki\Storage\SlotRecord;
use MediaWikiIntegrationTestCase;
@@ -419,7 +420,6 @@ class UndoIntegrationTest extends MediaWikiIntegrationTestCase {
// after the undo, but automatic conflict resolution is not the point of
// this test anyway.
'wpTextbox1' => $newContent,
- 'wpEditToken' => $this->getTestSysop()->getUser()->getEditToken(),
// These two parameters are the important ones here
'wpUndidRevision' => $revisionIds[$undoIndex],
'wpUndoAfter' => $revisionIds[$undoafterIndex],
@@ -430,6 +430,10 @@ class UndoIntegrationTest extends MediaWikiIntegrationTestCase {
],
true
);
+ $request->setVal(
+ 'wpEditToken',
+ ( new CsrfTokenSet( $request ) )->getToken()->toString()
+ );
$editPage = new EditPage( $article );
$editPage->importFormData( $request );
@@ -472,7 +476,6 @@ class UndoIntegrationTest extends MediaWikiIntegrationTestCase {
[
// We emulate the user applying additional changes on top of the undo.
'wpTextbox1' => "line 1\n\nline 2\n\nline3 more content\n\neven more",
- 'wpEditToken' => $this->getTestSysop()->getUser()->getEditToken(),
'wpUndidRevision' => $revisionIds[1],
'wpUndoAfter' => $revisionIds[0],
'wpStarttime' => wfTimestampNow(),
@@ -482,7 +485,10 @@ class UndoIntegrationTest extends MediaWikiIntegrationTestCase {
],
true
);
-
+ $request->setVal(
+ 'wpEditToken',
+ ( new CsrfTokenSet( $request ) )->getToken()->toString()
+ );
$editPage = new EditPage( $article );
$editPage->importFormData( $request );
$editPage->internalAttemptSave( $result, false );
@@ -528,7 +534,6 @@ class UndoIntegrationTest extends MediaWikiIntegrationTestCase {
[
// We leave the "top" content in the textbox, as the undo should have failed
'wpTextbox1' => "line 1\n\nvandalism good content\n\nline3 more content",
- 'wpEditToken' => $this->getTestSysop()->getUser()->getEditToken(),
'wpUndidRevision' => $revisionIds[1],
'wpUndoAfter' => $revisionIds[0],
'wpStarttime' => wfTimestampNow(),
@@ -538,6 +543,10 @@ class UndoIntegrationTest extends MediaWikiIntegrationTestCase {
],
true
);
+ $request->setVal(
+ 'wpEditToken',
+ ( new CsrfTokenSet( $request ) )->getToken()->toString()
+ );
$editPage = new EditPage( $article );
$editPage->importFormData( $request );
diff --git a/tests/phpunit/unit/includes/Rest/Handler/ActionModuleBasedHandlerTestTrait.php b/tests/phpunit/unit/includes/Rest/Handler/ActionModuleBasedHandlerTestTrait.php
index 760c5c954de3..193eb685384d 100644
--- a/tests/phpunit/unit/includes/Rest/Handler/ActionModuleBasedHandlerTestTrait.php
+++ b/tests/phpunit/unit/includes/Rest/Handler/ActionModuleBasedHandlerTestTrait.php
@@ -76,15 +76,18 @@ trait ActionModuleBasedHandlerTestTrait {
* @return ApiMain
*/
private function getApiMain( $csrfSafe = false ) {
+ $testContext = RequestContext::getMain();
+
/** @var SessionProviderInterface|MockObject $session */
$sessionProvider =
$this->createNoOpMock( SessionProviderInterface::class, [ 'safeAgainstCsrf' ] );
$sessionProvider->method( 'safeAgainstCsrf' )->willReturn( $csrfSafe );
/** @var Session|MockObject $session */
- $session = $this->createNoOpMock( Session::class, [ 'getSessionId', 'getProvider' ] );
+ $session = $this->createNoOpMock( Session::class, [ 'getSessionId', 'getProvider', 'getUser' ] );
$session->method( 'getSessionId' )->willReturn( new SessionId( 'test' ) );
$session->method( 'getProvider' )->willReturn( $sessionProvider );
+ $session->method( 'getUser' )->willReturn( $testContext->getUser() );
// NOTE: This being a FauxRequest instance triggers special case behavior
// in ApiMain, causing ApiMain::isInternalMode() to return true. Among other things,
@@ -96,8 +99,6 @@ trait ActionModuleBasedHandlerTestTrait {
$fauxRequest->method( 'getSession' )->willReturn( $session );
$fauxRequest->method( 'getSessionId' )->willReturn( $session->getSessionId() );
- $testContext = RequestContext::getMain();
-
$fauxContext = new RequestContext();
$fauxContext->setRequest( $fauxRequest );
$fauxContext->setUser( $testContext->getUser() );
diff --git a/tests/phpunit/unit/includes/context/DerivativeContextTest.php b/tests/phpunit/unit/includes/context/DerivativeContextTest.php
index 82f9493ac0f7..e37ed65a58bd 100644
--- a/tests/phpunit/unit/includes/context/DerivativeContextTest.php
+++ b/tests/phpunit/unit/includes/context/DerivativeContextTest.php
@@ -7,10 +7,13 @@ use FauxRequest;
use HashConfig;
use IContextSource;
use Language;
+use MediaWiki\Session\Session;
+use MediaWiki\User\UserIdentityValue;
use MediaWikiUnitTestCase;
use OutputPage;
use RequestContext;
use User;
+use WebRequest;
/**
* @coversDefaultClass DerivativeContext
@@ -102,4 +105,23 @@ class DerivativeContextTest extends MediaWikiUnitTestCase {
$derivativeContext->$setter( $newValue );
$this->assertSame( $newValue, $derivativeContext->$getter() );
}
+
+ /**
+ * @covers ::getCsrfTokenSet
+ */
+ public function testGetCsrfTokeSetRespectsRequest() {
+ $context = new RequestContext();
+ $context->setRequest( $this->createNoOpMock( WebRequest::class ) );
+ $derivativeContext = new DerivativeContext( $context );
+ $sessionMock = $this->createNoOpMock( Session::class, [ 'getUser' ] );
+ $sessionMock
+ ->method( 'getUser' )
+ ->willReturn( UserIdentityValue::newAnonymous( '127.0.0.1' ) );
+ $requestMock = $this->createNoOpMock( WebRequest::class, [ 'getSession' ] );
+ $requestMock
+ ->method( 'getSession' )
+ ->willReturn( $sessionMock );
+ $derivativeContext->setRequest( $requestMock );
+ $this->assertNotNull( $derivativeContext->getCsrfTokenSet()->getToken() );
+ }
}