Skip to content
This repository has been archived by the owner on Aug 8, 2022. It is now read-only.

Commit

Permalink
Merge pull request #218 from thomaszbz/dev/210-ajax-suppress-schema-r…
Browse files Browse the repository at this point in the history
…edirect

[BUGFIX] Mitigate browsers to block mixed content for ajax requests
  • Loading branch information
thomaszbz committed Feb 21, 2016
2 parents cf013c6 + 4068382 commit c07a211
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 1 deletion.
133 changes: 133 additions & 0 deletions Classes/Frontend/Controller/BackendCompliantTsfeController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php

/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <[email protected]> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <[email protected]> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/

namespace Metaseo\Metaseo\Frontend\Controller;

use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;

/**
* Fakes default scheme (protocol, e.g. http/https) in page properties when the
* TypoScriptFrontendController's determineId() function is executed by Ajax requests from the backend
*
* This class can be used instead of TYPO3's TypoScriptFrontendController and can be put in place via XCLASSes
* declaration in the extension's ext_localconf.php (e.g. for backend-only request with some request header):
*
* if (TYPO3_MODE == 'BE' && isset($_SERVER['HTTP_X_TX_MYEXT_AJAX'])) {
* $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects']
* ['TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController'] = array(
* 'className' => 'Metaseo\\Metaseo\\Frontend\\Controller\\BackendCompliantTsfeController'
* );
* }
*
* Usage: no code change required, but you can toggle between original behaviour and using this workaround (=default):
*
* setIsAjaxCall(false) disabled: Gives you the original behaviour of the TypoScriptFrontendController
* setIsAjaxCall(true) enabled: Fakes the default scheme in a page's page properties during execution of
* the fetch_the_id() function which is called from the determineId() function.
* Thereby it suppresses redirect via http headers for the scheme from page properties
* to ensure that TYPO3 does not redirect the Ajax request to some other scheme.
* This is intentionally useful to avoid mixed content for Ajax requests and to
* prevent browsers to block these requests client-side. Plus, does it not expose
* Ajax tokens in the URI via non-encrypted http (non-blocking older browsers).
*/

class BackendCompliantTsfeController extends TypoScriptFrontendController
{
/**
* @var boolean
*/
protected $isAjaxCall = true;

/**
* @var boolean
*/
protected $isFetchingId = false;

/**
* @var int
*/
protected $originalScheme;

/**
* {@inheritDoc}
*/
public function fetch_the_id()
{
$this->isFetchingId = true;

parent::fetch_the_id(); //void function

if ($this->isAjaxCall === true
&& $this->isPageSchemeFetched() === true
&& isset($this->originalScheme) === true
) {
// restore original scheme
$this->page['url_scheme'] = $this->originalScheme;
}
$this->isFetchingId = false;
}


/**
* {@inheritDoc}
*/
public function getPageAndRootlineWithDomain($domainStartPage)
{
parent::getPageAndRootlineWithDomain($domainStartPage); // void function

// remember original scheme
if ($this->isAjaxCall === true
&& $this->isFetchingId === true
&& $this->isPageSchemeFetched() === true
) {
$this->originalScheme = $this->page['url_scheme'];
// fake scheme with default scheme (0 = same scheme as request -> does not send http headers for redirect)
$this->page['url_scheme'] = 0;
}
}

/**
* @return bool true if the page's scheme is available
*/
protected function isPageSchemeFetched()
{
return is_array($this->page) && array_key_exists('url_scheme', $this->page);
}

/**
* @param boolean $isAjaxCall toggle behaviour:
* true if http redirect is to be suppressed,
* false for TSFEController's original behaviour
*
* @return $this
*/
public function setIsAjaxCall($isAjaxCall)
{
$this->isAjaxCall = $isAjaxCall;

return $this;
}
}
3 changes: 2 additions & 1 deletion Classes/Utility/FrontendUtility.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ public static function init(
if ($lastTsSetupPid !== $pageUid) {
// Cache TSFE if possible to prevent reinit (is still slow but we need the TSFE)
if (empty($cacheTSFE[$pageUid])) {
/** @var \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController $tsfeController */
// suppress http redirect headers via BackendCompliantTsfeController, loaded via ext_localconf.php
/** @var \Metaseo\Metaseo\Frontend\Controller\BackendCompliantTsfeController $tsfeController */
$tsfeController = $objectManager->get(
'TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController',
$GLOBALS['TYPO3_CONF_VARS'],
Expand Down
1 change: 1 addition & 0 deletions Resources/Public/Backend/JavaScript/MetaSeo.overview.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
Ext.ns('MetaSeo.overview');

Ext.onReady(function () {
Ext.Ajax.defaultHeaders = {'X-Tx-Metaseo-Ajax': 1};
Ext.QuickTips.init();
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());

Expand Down
1 change: 1 addition & 0 deletions Resources/Public/Backend/JavaScript/MetaSeo.sitemap.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
Ext.ns('MetaSeo.sitemap');

Ext.onReady(function () {
Ext.Ajax.defaultHeaders = {'X-Tx-Metaseo-Ajax': 1};
Ext.QuickTips.init();
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());

Expand Down
11 changes: 11 additions & 0 deletions ext_localconf.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@
// Field validations
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals']['tx_metaseo_backend_validation_float']
= 'EXT:metaseo/Classes/Backend/Validator/ValidatorImport.php';

/*
* BackendCompliantTsfeController suppresses redirect http headers sent by TypoScriptFrontendController
* by faking default scheme for pages processed by TypoScriptFrontendController (use for Ajax requests only)
*/
if (isset($_SERVER['HTTP_X_TX_METASEO_AJAX'])) { //original header is 'X-Tx-Metaseo-Ajax' (prefixed by webserver)
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects']
['TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController'] = array(
'className' => 'Metaseo\\Metaseo\\Frontend\\Controller\\BackendCompliantTsfeController'
);
}
}

// ##############################################
Expand Down

0 comments on commit c07a211

Please sign in to comment.