Merge 43a6aa5279
into d22960d3ea
This commit is contained in:
commit
d121f908de
|
@ -14,6 +14,7 @@ SilverStripe\Core\Injector\Injector:
|
|||
ChangeDetectionMiddleware: '%$SilverStripe\Control\Middleware\ChangeDetectionMiddleware'
|
||||
HTTPCacheControleMiddleware: '%$SilverStripe\Control\Middleware\HTTPCacheControlMiddleware'
|
||||
CanonicalURLMiddleware: '%$SilverStripe\Control\Middleware\CanonicalURLMiddleware'
|
||||
RewriteHashLinksMiddleware: '%$SilverStripe\Control\Middleware\RewriteHashLinksMiddleware'
|
||||
SilverStripe\Control\Middleware\AllowedHostsMiddleware:
|
||||
properties:
|
||||
AllowedHosts: '`SS_ALLOWED_HOSTS`'
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Control\Middleware;
|
||||
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\Middleware\HTTPMiddleware;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Config\Configurable;
|
||||
|
||||
class RewriteHashLinksMiddleware implements HTTPMiddleware
|
||||
{
|
||||
use Configurable;
|
||||
|
||||
/**
|
||||
* Mime types to be handled by this middleware
|
||||
* @var array
|
||||
* @config SilverStripe\Control\Middleware\RewriteHashLinksMiddleware.handled_mime_types
|
||||
*/
|
||||
private static $handled_mime_types = [
|
||||
'text/html',
|
||||
'application/xhtml+xml',
|
||||
];
|
||||
|
||||
/**
|
||||
* Set if hash links should be rewritten
|
||||
* @var bool
|
||||
* @config SilverStripe\Control\Middleware\RewriteHashLinksMiddleware.rewrite_hash_links
|
||||
*/
|
||||
private static $rewrite_hash_links = true;
|
||||
|
||||
/**
|
||||
* Rewrites hash links in html responses
|
||||
* @param HTTPRequest $request
|
||||
* @param callable $delegate
|
||||
* @return \SilverStripe\Control\HTTPResponse
|
||||
*/
|
||||
public function process(HTTPRequest $request, callable $delegate)
|
||||
{
|
||||
/** @var \SilverStripe\Control\HTTPResponse $response **/
|
||||
$response = $delegate($request);
|
||||
|
||||
if (!$this->config()->rewrite_hash_links) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$contentType = explode(';', $response->getHeader('content-type'));
|
||||
$mimeType = strtolower(trim(array_shift($contentType)));
|
||||
if (!in_array($mimeType, $this->config()->handled_mime_types)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$body = $response->getBody();
|
||||
|
||||
if (stripos($body, '<base') === false) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$link = Convert::raw2att(preg_replace("/^(\\/)+/", "/", $_SERVER['REQUEST_URI']));
|
||||
$body = preg_replace('/(<a[^>]+href *= *)("|\')#/i', '\\1\\2' . $link . '#', $body);
|
||||
$response->setBody($body);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
|
@ -112,7 +112,7 @@ class SSViewer implements Flushable
|
|||
* @config
|
||||
* @var bool
|
||||
*/
|
||||
private static $rewrite_hash_links = true;
|
||||
private static $rewrite_hash_links = false;
|
||||
|
||||
/**
|
||||
* Overridden value of rewrite_hash_links config
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\Control\Tests\Middleware;
|
||||
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\Middleware\RewriteHashLinksMiddleware;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
|
||||
class RewriteHashLinksMiddlewareTest extends SapphireTest
|
||||
{
|
||||
protected $currentHost;
|
||||
protected $currentURI;
|
||||
|
||||
/**
|
||||
* Setup the test
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->currentHost = (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : false);
|
||||
$this->currentURI = (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up the test
|
||||
*/
|
||||
protected function tearDown()
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
if ($this->currentHost === false) {
|
||||
unset($_SERVER['HTTP_HOST']);
|
||||
} else {
|
||||
$_SERVER['HTTP_HOST'] = $this->currentHost;
|
||||
}
|
||||
|
||||
if ($this->currentURI === false) {
|
||||
unset($_SERVER['REQUEST_URI']);
|
||||
} else {
|
||||
$_SERVER['REQUEST_URI'] = $this->currentURI;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rewriting of HTML content types to ensure that it's properly rewriting anchors when the base tag is present
|
||||
*/
|
||||
public function testRewriteHTMLWithBase()
|
||||
{
|
||||
$_SERVER['HTTP_HOST'] = 'www.mysite.com';
|
||||
$_SERVER['REQUEST_URI'] = '//file.com?foo"onclick="alert(\'xss\')""';
|
||||
|
||||
$base = Convert::raw2att('/file.com?foo"onclick="alert(\'xss\')""');
|
||||
|
||||
$body = '<!DOCTYPE html>
|
||||
<html>
|
||||
<head><base href="' . Director::absoluteBaseURL() . '"><!--[if lte IE 6]></base><![endif]--></head>
|
||||
<body>
|
||||
<a class="external-inline" href="http://google.com#anchor">ExternalInlineLink</a>
|
||||
<a class="inline" href="#anchor">InlineLink</a>
|
||||
<svg><use xlink:href="#sprite"></use></svg>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
//Mock a request
|
||||
$request = new HTTPRequest('GET', $_SERVER['REQUEST_URI']);
|
||||
|
||||
//Hand through the Middleware to be "processed"
|
||||
$middleware = new RewriteHashLinksMiddleware();
|
||||
$result = $middleware->process($request, function (HTTPRequest $request) use ($body) {
|
||||
return HTTPResponse::create($body);
|
||||
})->getBody();
|
||||
|
||||
$this->assertContains(
|
||||
'<a class="inline" href="' . $base . '#anchor">InlineLink</a>',
|
||||
$result
|
||||
);
|
||||
|
||||
$this->assertContains(
|
||||
'<a class="external-inline" href="http://google.com#anchor">ExternalInlineLink</a>',
|
||||
$result
|
||||
);
|
||||
|
||||
$this->assertContains(
|
||||
'<svg><use xlink:href="#sprite"></use></svg>',
|
||||
$result,
|
||||
'RewriteHashLinksMiddleware should only rewrite anchor hrefs'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rewriting of HTML content types to ensure that it's not rewriting anchors when the base tag is not present
|
||||
*/
|
||||
public function testRewriteHTMLWithoutBase()
|
||||
{
|
||||
$_SERVER['HTTP_HOST'] = 'www.mysite.com';
|
||||
$_SERVER['REQUEST_URI'] = '//file.com?foo"onclick="alert(\'xss\')""';
|
||||
|
||||
$base = Convert::raw2att('/file.com?foo"onclick="alert(\'xss\')""');
|
||||
|
||||
$body = '<!DOCTYPE html>
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<a class="external-inline" href="http://google.com#anchor">ExternalInlineLink</a>
|
||||
<a class="inline" href="#anchor">InlineLink</a>
|
||||
<svg><use xlink:href="#sprite"></use></svg>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
//Mock a request
|
||||
$request = new HTTPRequest('GET', $_SERVER['REQUEST_URI']);
|
||||
|
||||
//Hand through the Middleware to be "processed"
|
||||
$middleware = new RewriteHashLinksMiddleware();
|
||||
$result = $middleware->process($request, function (HTTPRequest $request) use ($body) {
|
||||
return HTTPResponse::create($body);
|
||||
})->getBody();
|
||||
|
||||
$this->assertNotContains(
|
||||
'<a class="inline" href="' . $base . '#anchor">InlineLink</a>',
|
||||
$result
|
||||
);
|
||||
|
||||
$this->assertContains(
|
||||
'<a class="external-inline" href="http://google.com#anchor">ExternalInlineLink</a>',
|
||||
$result
|
||||
);
|
||||
|
||||
$this->assertContains(
|
||||
'<svg><use xlink:href="#sprite"></use></svg>',
|
||||
$result,
|
||||
'RewriteHashLinksMiddleware should only rewrite anchor hrefs'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rewriting of JSON content type to ensure that it's not rewriting anchors
|
||||
*/
|
||||
public function testRewriteJSONWithBase()
|
||||
{
|
||||
$_SERVER['HTTP_HOST'] = 'www.mysite.com';
|
||||
$_SERVER['REQUEST_URI'] = '//file.com?foo"onclick="alert(\'xss\')""';
|
||||
|
||||
$base = Convert::raw2att('/file.com?foo"onclick="alert(\'xss\')""');
|
||||
|
||||
$body = json_encode(['test' => '<!DOCTYPE html>
|
||||
<html>
|
||||
<head><base href="' . Director::absoluteBaseURL() . '"><!--[if lte IE 6]></base><![endif]--></head>
|
||||
<body>
|
||||
<a class="external-inline" href="http://google.com#anchor">ExternalInlineLink</a>
|
||||
<a class="inline" href="#anchor">InlineLink</a>
|
||||
<svg><use xlink:href="#sprite"></use></svg>
|
||||
</body>
|
||||
</html>']);
|
||||
|
||||
|
||||
//Mock a request
|
||||
$request = new HTTPRequest('GET', $_SERVER['REQUEST_URI']);
|
||||
|
||||
//Hand through the Middleware to be "processed"
|
||||
$middleware = new RewriteHashLinksMiddleware();
|
||||
$result = $middleware->process($request, function (HTTPRequest $request) use ($body) {
|
||||
return HTTPResponse::create($body)->addHeader('content-type', 'application/json; charset=utf-8');
|
||||
})->getBody();
|
||||
|
||||
$this->assertNotContains(
|
||||
'<a class=\\"inline\\" href=\\"' . $base . '#anchor\\">InlineLink<\\/a>',
|
||||
$result
|
||||
);
|
||||
|
||||
$this->assertContains(
|
||||
'<a class=\\"external-inline\\" href=\\"http:\\/\\/google.com#anchor\\">ExternalInlineLink<\\/a>',
|
||||
$result
|
||||
);
|
||||
|
||||
$this->assertContains(
|
||||
'<svg><use xlink:href=\\"#sprite\\"><\\/use><\\/svg>',
|
||||
$result,
|
||||
'RewriteHashLinksMiddleware should only rewrite anchor hrefs'
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue