Avoid CORS by mirroring API endpoints
authorAlexander Ebert <ebert@woltlab.com>
Thu, 15 Dec 2016 12:59:16 +0000 (13:59 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Thu, 15 Dec 2016 12:59:16 +0000 (13:59 +0100)
com.woltlab.wcf/templates/headIncludeJavaScript.tpl
wcfsetup/install/files/acp/templates/header.tpl
wcfsetup/install/files/lib/system/WCF.class.php
wcfsetup/install/files/lib/system/WCFACP.class.php
wcfsetup/install/files/lib/system/request/ControllerMap.class.php

index 91df60c4f56987e25152ca298e6d7359b8494411..7dfb376b97d04c4b1e14392a1f05ff2e9437d505 100644 (file)
@@ -5,7 +5,7 @@
 <script>
        var SID_ARG_2ND = '';
        var WCF_PATH = '{@$__wcf->getPath()}';
-       var WSC_API_URL = '{@$__wcf->getPath()}';
+       var WSC_API_URL = '{@$__wcf->getActivePath()}';
        var SECURITY_TOKEN = '{@SECURITY_TOKEN}';
        var LANGUAGE_ID = {@$__wcf->getLanguage()->languageID};
        var LANGUAGE_USE_INFORMAL_VARIANT = {if LANGUAGE_USE_INFORMAL_VARIANT}true{else}false{/if};
index 36e978405de12469e4b7c347b5416a74a755e337..09407f1ddc4f9758b9bfc4f6e6cce2ac5ddfafd7 100644 (file)
@@ -18,7 +18,7 @@
        <script>
                var SID_ARG_2ND = '';
                var WCF_PATH = '{@$__wcf->getPath()}';
-               var WSC_API_URL = '{@$__wcf->getPath()}acp/';
+               var WSC_API_URL = '{@$__wcf->getActivePath()}acp/';
                var SECURITY_TOKEN = '{@SECURITY_TOKEN}';
                var LANGUAGE_ID = {@$__wcf->getLanguage()->languageID};
                var LANGUAGE_USE_INFORMAL_VARIANT = {if LANGUAGE_USE_INFORMAL_VARIANT}true{else}false{/if};
index 28d70129b5628fb412d04741dc1238533bd7e944..a74ec00388d50ae86d5f9fafd186e030cb7167be 100644 (file)
@@ -147,7 +147,6 @@ class WCF {
                // start initialization
                $this->initDB();
                $this->loadOptions();
-               $this->initCors();
                $this->initSession();
                $this->initLanguage();
                $this->initTPL();
@@ -445,36 +444,6 @@ class WCF {
                }
        }
        
-       /**
-        * Responds with proper CORS headers.
-        */
-       protected function initCors() {
-               // Nothing to do here.
-               if (!isset($_SERVER['HTTP_ORIGIN'])) return;
-               
-               $allowed = array_reduce(ApplicationHandler::getInstance()->getApplications(), function ($carry, $item) {
-                       if ($_SERVER['HTTP_ORIGIN'] == RouteHandler::getProtocol().$item->domainName) return true;
-                       
-                       return $carry;
-               }, false);
-               
-               if (!$allowed) return;
-               
-               header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
-               header('Access-Control-Allow-Credentials: true');
-               header('Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers');
-               
-               if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
-                       if (!isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) return;
-                       if (!isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) return;
-                       
-                       header('Access-Control-Allow-Methods: GET, HEAD, POST, OPTIONS');
-                       header('Access-Control-Allow-Headers: '.$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
-                       header('Access-Control-Max-Age: 5');
-                       exit;
-               }
-       }
-       
        /**
         * Initializes applications.
         */
@@ -822,6 +791,20 @@ class WCF {
                return self::$applications[$abbreviation]->getPageURL();
        }
        
+       /**
+        * Returns the domain path for the currently active application,
+        * used to avoid CORS requests.
+        * 
+        * @return      string
+        */
+       public static function getActivePath() {
+               if (!PACKAGE_ID) {
+                       return self::getPath();
+               }
+               
+               return self::getPath(ApplicationHandler::getInstance()->getAbbreviation(ApplicationHandler::getInstance()->getActiveApplication()->packageID));
+       }
+       
        /**
         * Returns a fully qualified anchor for current page.
         * 
index c8f29841359d95fd7708ac3966764a86b71e2a2c..f2cb24d6e0ad6c0062803a92e7c52b9980b2c974 100644 (file)
@@ -53,7 +53,6 @@ class WCFACP extends WCF {
                // start initialization
                $this->initDB();
                $this->loadOptions();
-               $this->initCors();
                $this->initPackage();
                $this->initSession();
                $this->initLanguage();
index 99f27da6d1d3f01346819b3ab1f4bb02beb08a67..068d03b930fd953bca0635fa3c695e57b1e66d77 100644 (file)
@@ -72,8 +72,10 @@ class ControllerMap extends SingletonFactory {
                        $parts = array_map('ucfirst', $parts);
                        $controller = implode('', $parts);
                        
-                       // work-around for upgrade path 2.1 -> 3.0
+                       // work-around for legacy action controllers for upgrade and CORS avoidance
                        if ($controller === 'AjaxProxy') $controller = 'AJAXProxy';
+                       else if ($controller === 'AjaxUpload') $controller = 'AJAXUpload';
+                       else if ($controller === 'AjaxInvoke') $controller = 'AJAXInvoke';
                        
                        // work-around for package installation during upgrade 2.1 -> 3.0
                        if ($isAcpRequest && $controller === 'InstallPackage') $application = 'wcf';
@@ -329,7 +331,16 @@ class ControllerMap extends SingletonFactory {
        protected function getClassData($application, $controller, $isAcpRequest, $pageType) {
                $className = $application . '\\' . ($isAcpRequest ? 'acp\\' : '') . $pageType . '\\' . $controller . ucfirst($pageType);
                if (!class_exists($className)) {
-                       return null;
+                       // avoid CORS by allowing action classes invoked form every application domain
+                       if ($pageType === 'action' && $application !== 'wcf') {
+                               $className = 'wcf\\' . ($isAcpRequest ? 'acp\\' : '') . $pageType . '\\' . $controller . ucfirst($pageType);
+                               if (!class_exists($className)) {
+                                       return null;
+                               }
+                       }
+                       else {
+                               return null;
+                       }
                }
                
                // check for abstract classes