API: Add "standard" header and hook for lacksSameOriginSecurity()
[lhc/web/wiklou.git] / includes / api / ApiMain.php
index 685a9ef..b4354b9 100644 (file)
@@ -49,8 +49,14 @@ class ApiMain extends ApiBase {
         */
        private static $Modules = [
                'login' => 'ApiLogin',
+               'clientlogin' => 'ApiClientLogin',
                'logout' => 'ApiLogout',
-               'createaccount' => 'ApiCreateAccount',
+               'createaccount' => 'ApiAMCreateAccount',
+               'linkaccount' => 'ApiLinkAccount',
+               'unlinkaccount' => 'ApiRemoveAuthenticationData',
+               'changeauthenticationdata' => 'ApiChangeAuthenticationData',
+               'removeauthenticationdata' => 'ApiRemoveAuthenticationData',
+               'resetpassword' => 'ApiResetPassword',
                'query' => 'ApiQuery',
                'expandtemplates' => 'ApiExpandTemplates',
                'parse' => 'ApiParse',
@@ -142,6 +148,9 @@ class ApiMain extends ApiBase {
        private $mCacheControl = [];
        private $mParamsUsed = [];
 
+       /** @var bool|null Cached return value from self::lacksSameOriginSecurity() */
+       private $lacksSameOriginSecurity = null;
+
        /**
         * Constructs an instance of ApiMain that utilizes the module and format specified by $request.
         *
@@ -239,6 +248,36 @@ class ApiMain extends ApiBase {
                return $this->mResult;
        }
 
+       /**
+        * Get the security flag for the current request
+        * @return bool
+        */
+       public function lacksSameOriginSecurity() {
+               if ( $this->lacksSameOriginSecurity !== null ) {
+                       return $this->lacksSameOriginSecurity;
+               }
+
+               $request = $this->getRequest();
+
+               // JSONP mode
+               if ( $request->getVal( 'callback' ) !== null ) {
+                       $this->lacksSameOriginSecurity = true;
+                       return true;
+               }
+
+               // Header to be used from XMLHTTPRequest when the request might
+               // otherwise be used for XSS.
+               if ( $request->getHeader( 'Treat-as-Untrusted' ) !== false ) {
+                       $this->lacksSameOriginSecurity = true;
+                       return true;
+               }
+
+               // Allow extensions to override.
+               $this->lacksSameOriginSecurity = !Hooks::run( 'RequestHasSameOriginSecurity', array( $request ) );
+               return $this->lacksSameOriginSecurity;
+       }
+
+
        /**
         * Get the ApiErrorFormatter object associated with current request
         * @return ApiErrorFormatter
@@ -724,6 +763,8 @@ class ApiMain extends ApiBase {
                $response = $this->getRequest()->response();
                $out = $this->getOutput();
 
+               $out->addVaryHeader( 'Treat-as-Untrusted' );
+
                $config = $this->getConfig();
 
                if ( $config->get( 'VaryOnXFP' ) ) {
@@ -1135,7 +1176,7 @@ class ApiMain extends ApiBase {
                                                                        TS_MW, time() - $this->getConfig()->get( 'SquidMaxage' )
                                                                );
                                                        }
-                                                       Hooks::run( 'OutputPageCheckLastModified', [ &$modifiedTimes ] );
+                                                       Hooks::run( 'OutputPageCheckLastModified', [ &$modifiedTimes, $this->getOutput() ] );
                                                        $lastMod = max( $modifiedTimes );
                                                        $return304 = wfTimestamp( TS_MW, $lastMod ) <= $ts->getTimestamp( TS_MW );
                                                }
@@ -1438,6 +1479,14 @@ class ApiMain extends ApiBase {
                return array_keys( $this->mParamsUsed );
        }
 
+       /**
+        * Mark parameters as used
+        * @param string|string[] $params
+        */
+       public function markParamsUsed( $params ) {
+               $this->mParamsUsed += array_fill_keys( (array)$params, true );
+       }
+
        /**
         * Get a request value, and register the fact that it was used, for logging.
         * @param string $name
@@ -1631,9 +1680,14 @@ class ApiMain extends ApiBase {
                        $tocnumber = &$options['tocnumber'];
 
                        $header = $this->msg( 'api-help-datatypes-header' )->parse();
+
+                       // Add an additional span with sanitized ID
+                       if ( !$this->getConfig()->get( 'ExperimentalHtmlIds' ) ) {
+                               $header = Html::element( 'span', [ 'id' => Sanitizer::escapeId( 'main/datatypes' ) ] ) .
+                                       $header;
+                       }
                        $help['datatypes'] .= Html::rawElement( 'h' . min( 6, $level ),
                                [ 'id' => 'main/datatypes', 'class' => 'apihelp-header' ],
-                               Html::element( 'span', [ 'id' => Sanitizer::escapeId( 'main/datatypes' ) ] ) .
                                $header
                        );
                        $help['datatypes'] .= $this->msg( 'api-help-datatypes' )->parseAsBlock();
@@ -1649,10 +1703,14 @@ class ApiMain extends ApiBase {
                                ];
                        }
 
+                       // Add an additional span with sanitized ID
+                       if ( !$this->getConfig()->get( 'ExperimentalHtmlIds' ) ) {
+                               $header = Html::element( 'span', [ 'id' => Sanitizer::escapeId( 'main/credits' ) ] ) .
+                                       $header;
+                       }
                        $header = $this->msg( 'api-credits-header' )->parse();
                        $help['credits'] .= Html::rawElement( 'h' . min( 6, $level ),
                                [ 'id' => 'main/credits', 'class' => 'apihelp-header' ],
-                               Html::element( 'span', [ 'id' => Sanitizer::escapeId( 'main/credits' ) ] ) .
                                $header
                        );
                        $help['credits'] .= $this->msg( 'api-credits' )->useDatabase( false )->parseAsBlock();