From 693ec8b76ab5e14669a8f7f8bc7ebc9cda5165f5 Mon Sep 17 00:00:00 2001 From: Ricordisamoa Date: Wed, 17 Dec 2014 11:09:04 +0000 Subject: [PATCH] New convenience method ApiBase::lacksSameOriginSecurity() For consistent handling of API requests with the 'callback' argument. Change-Id: Ic6e3483f5e8819498c693650a11728efc1bafcc0 --- RELEASE-NOTES-1.25 | 3 +++ includes/api/ApiBase.php | 14 ++++++++++++++ includes/api/ApiCreateAccount.php | 9 ++++++--- includes/api/ApiLogin.php | 7 ++++--- includes/api/ApiMain.php | 8 ++++---- includes/api/ApiQueryDeletedrevs.php | 5 +++-- includes/api/ApiQueryInfo.php | 5 +++-- includes/api/ApiQueryRecentChanges.php | 5 +++-- includes/api/ApiQueryRevisions.php | 5 +++-- includes/api/ApiQueryTokens.php | 4 ++-- includes/api/ApiQueryUserInfo.php | 2 +- includes/api/ApiQueryUsers.php | 5 +++-- includes/api/ApiTokens.php | 5 +++-- 13 files changed, 52 insertions(+), 25 deletions(-) diff --git a/RELEASE-NOTES-1.25 b/RELEASE-NOTES-1.25 index f365d7008d..45e669a00a 100644 --- a/RELEASE-NOTES-1.25 +++ b/RELEASE-NOTES-1.25 @@ -261,6 +261,9 @@ production. to allow generators to include data in the action=query result. * New hooks 'ApiMain::moduleManager' and 'ApiQuery::moduleManager', can be used for conditional registration of API modules. +* Added ApiBase::lacksSameOriginSecurity() to allow modules to easily check if + the current request was sent with the 'callback' parameter (or any future + method that breaks the same-origin policy). * The following methods have been deprecated and may be removed in a future release: * ApiBase::getDescription diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php index 3a31b2aeeb..be5a9c3bba 100644 --- a/includes/api/ApiBase.php +++ b/includes/api/ApiBase.php @@ -380,6 +380,20 @@ abstract class ApiBase extends ContextSource { return $this->isMain() ? null : $this->getMain(); } + /** + * Returns true if the current request breaks the same-origin policy. + * + * For example, json with callbacks. + * + * https://en.wikipedia.org/wiki/Same-origin_policy + * + * @since 1.25 + * @return bool + */ + public function lacksSameOriginSecurity() { + return $this->getMain()->getRequest()->getVal( 'callback' ) !== null; + } + /** * Get the path to this module * diff --git a/includes/api/ApiCreateAccount.php b/includes/api/ApiCreateAccount.php index a7ba48a102..b56a24441d 100644 --- a/includes/api/ApiCreateAccount.php +++ b/includes/api/ApiCreateAccount.php @@ -29,9 +29,12 @@ */ class ApiCreateAccount extends ApiBase { public function execute() { - // If we're in JSON callback mode, no tokens can be obtained - if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { - $this->dieUsage( 'Cannot create account when using a callback', 'aborted' ); + // If we're in a mode that breaks the same-origin policy, no tokens can + // be obtained + if ( $this->lacksSameOriginSecurity() ) { + $this->dieUsage( + 'Cannot create account when the same-origin policy is not applied', 'aborted' + ); } // $loginForm->addNewaccountInternal will throw exceptions diff --git a/includes/api/ApiLogin.php b/includes/api/ApiLogin.php index 920dbbfa24..5480d9400b 100644 --- a/includes/api/ApiLogin.php +++ b/includes/api/ApiLogin.php @@ -46,11 +46,12 @@ class ApiLogin extends ApiBase { * is reached. The expiry is $this->mLoginThrottle. */ public function execute() { - // If we're in JSON callback mode, no tokens can be obtained - if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { + // If we're in a mode that breaks the same-origin policy, no tokens can + // be obtained + if ( $this->lacksSameOriginSecurity() ) { $this->getResult()->addValue( null, 'login', array( 'result' => 'Aborted', - 'reason' => 'Cannot log in when using a callback', + 'reason' => 'Cannot log in when the same-origin policy is not applied', ) ); return; diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php index fe01f114c4..d5cd475a5f 100644 --- a/includes/api/ApiMain.php +++ b/includes/api/ApiMain.php @@ -181,10 +181,10 @@ class ApiMain extends ApiBase { // Remove all modules other than login global $wgUser; - if ( $this->getVal( 'callback' ) !== null ) { - // JSON callback allows cross-site reads. - // For safety, strip user credentials. - wfDebug( "API: stripping user credentials for JSON callback\n" ); + if ( $this->lacksSameOriginSecurity() ) { + // If we're in a mode that breaks the same-origin policy, strip + // user credentials for security. + wfDebug( "API: stripping user credentials when the same-origin policy is not applied\n" ); $wgUser = new User(); $this->getContext()->setUser( $wgUser ); } diff --git a/includes/api/ApiQueryDeletedrevs.php b/includes/api/ApiQueryDeletedrevs.php index f828255bf1..f46fb34f5a 100644 --- a/includes/api/ApiQueryDeletedrevs.php +++ b/includes/api/ApiQueryDeletedrevs.php @@ -75,8 +75,9 @@ class ApiQueryDeletedrevs extends ApiQueryBase { ); } - // If we're in JSON callback mode, no tokens can be obtained - if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { + // If we're in a mode that breaks the same-origin policy, no tokens can + // be obtained + if ( $this->lacksSameOriginSecurity() ) { $fld_token = false; } diff --git a/includes/api/ApiQueryInfo.php b/includes/api/ApiQueryInfo.php index 02c88c4fc6..5af44eea21 100644 --- a/includes/api/ApiQueryInfo.php +++ b/includes/api/ApiQueryInfo.php @@ -90,8 +90,9 @@ class ApiQueryInfo extends ApiQueryBase { return $this->tokenFunctions; } - // If we're in JSON callback mode, no tokens can be obtained - if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { + // If we're in a mode that breaks the same-origin policy, no tokens can + // be obtained + if ( $this->lacksSameOriginSecurity() ) { return array(); } diff --git a/includes/api/ApiQueryRecentChanges.php b/includes/api/ApiQueryRecentChanges.php index bfdc5abb40..14820340ed 100644 --- a/includes/api/ApiQueryRecentChanges.php +++ b/includes/api/ApiQueryRecentChanges.php @@ -56,8 +56,9 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase { return $this->tokenFunctions; } - // If we're in JSON callback mode, no tokens can be obtained - if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { + // If we're in a mode that breaks the same-origin policy, no tokens can + // be obtained + if ( $this->lacksSameOriginSecurity() ) { return array(); } diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php index 7092fc43d3..552ca3b4e9 100644 --- a/includes/api/ApiQueryRevisions.php +++ b/includes/api/ApiQueryRevisions.php @@ -53,8 +53,9 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase { return $this->tokenFunctions; } - // If we're in JSON callback mode, no tokens can be obtained - if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { + // If we're in a mode that breaks the same-origin policy, no tokens can + // be obtained + if ( $this->lacksSameOriginSecurity() ) { return array(); } diff --git a/includes/api/ApiQueryTokens.php b/includes/api/ApiQueryTokens.php index 2e107acb88..f8eee8dfcd 100644 --- a/includes/api/ApiQueryTokens.php +++ b/includes/api/ApiQueryTokens.php @@ -37,8 +37,8 @@ class ApiQueryTokens extends ApiQueryBase { $params = $this->extractRequestParams(); $res = array(); - if ( $this->getMain()->getRequest()->getVal( 'callback' ) !== null ) { - $this->setWarning( 'Tokens may not be obtained when using a callback' ); + if ( $this->lacksSameOriginSecurity() ) { + $this->setWarning( 'Tokens may not be obtained when the same-origin policy is not applied' ); return; } diff --git a/includes/api/ApiQueryUserInfo.php b/includes/api/ApiQueryUserInfo.php index 7fc0ba88b7..1e3a4320aa 100644 --- a/includes/api/ApiQueryUserInfo.php +++ b/includes/api/ApiQueryUserInfo.php @@ -115,7 +115,7 @@ class ApiQueryUserInfo extends ApiQueryBase { ); } if ( isset( $this->prop['preferencestoken'] ) && - is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) && + !$this->lacksSameOriginSecurity() && $user->isAllowed( 'editmyoptions' ) ) { $vals['preferencestoken'] = $user->getEditToken( '', $this->getMain()->getRequest() ); diff --git a/includes/api/ApiQueryUsers.php b/includes/api/ApiQueryUsers.php index b7f2f9ac53..52636ccdd6 100644 --- a/includes/api/ApiQueryUsers.php +++ b/includes/api/ApiQueryUsers.php @@ -67,8 +67,9 @@ class ApiQueryUsers extends ApiQueryBase { return $this->tokenFunctions; } - // If we're in JSON callback mode, no tokens can be obtained - if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { + // If we're in a mode that breaks the same-origin policy, no tokens can + // be obtained + if ( $this->lacksSameOriginSecurity() ) { return array(); } diff --git a/includes/api/ApiTokens.php b/includes/api/ApiTokens.php index 073495c070..9eb40209e6 100644 --- a/includes/api/ApiTokens.php +++ b/includes/api/ApiTokens.php @@ -54,8 +54,9 @@ class ApiTokens extends ApiBase { } private function getTokenTypes() { - // If we're in JSON callback mode, no tokens can be obtained - if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { + // If we're in a mode that breaks the same-origin policy, no tokens can + // be obtained + if ( $this->lacksSameOriginSecurity() ) { return array(); } -- 2.20.1