Browse Source
Merge pull request #13989 from owncloud/enhancment/security/11857
Merge pull request #13989 from owncloud/enhancment/security/11857
Allow AppFramework applications to specify a custom CSP headerremotes/origin/log-external-deletes
8 changed files with 529 additions and 22 deletions
-
9config/config.sample.php
-
15lib/private/response.php
-
241lib/public/appframework/http/contentsecuritypolicy.php
-
30lib/public/appframework/http/response.php
-
7tests/lib/appframework/controller/ControllerTest.php
-
215tests/lib/appframework/http/ContentSecurityPolicyTest.php
-
5tests/lib/appframework/http/DataResponseTest.php
-
29tests/lib/appframework/http/ResponseTest.php
@ -0,0 +1,241 @@ |
|||
<?php |
|||
/** |
|||
* Copyright (c) 2015 Lukas Reschke lukas@owncloud.com |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING-README file. |
|||
*/ |
|||
|
|||
namespace OCP\AppFramework\Http; |
|||
|
|||
use OCP\AppFramework\Http; |
|||
|
|||
/** |
|||
* Class ContentSecurityPolicy is a simple helper which allows applications to |
|||
* modify the Content-Security-Policy sent by ownCloud. Per default only JavaScript, |
|||
* stylesheets, images, fonts, media and connections from the same domain |
|||
* ('self') are allowed. |
|||
* |
|||
* Even if a value gets modified above defaults will still get appended. Please |
|||
* notice that ownCloud ships already with sensible defaults and those policies |
|||
* should require no modification at all for most use-cases. |
|||
* |
|||
* @package OCP\AppFramework\Http |
|||
*/ |
|||
class ContentSecurityPolicy { |
|||
/** @var bool Whether inline JS snippets are allowed */ |
|||
private $inlineScriptAllowed = false; |
|||
/** |
|||
* @var bool Whether eval in JS scripts is allowed |
|||
* TODO: Disallow per default |
|||
* @link https://github.com/owncloud/core/issues/11925 |
|||
*/ |
|||
private $evalScriptAllowed = true; |
|||
/** @var array Domains from which scripts can get loaded */ |
|||
private $allowedScriptDomains = [ |
|||
'\'self\'', |
|||
]; |
|||
/** |
|||
* @var bool Whether inline CSS is allowed |
|||
* TODO: Disallow per default |
|||
* @link https://github.com/owncloud/core/issues/13458 |
|||
*/ |
|||
private $inlineStyleAllowed = true; |
|||
/** @var array Domains from which CSS can get loaded */ |
|||
private $allowedStyleDomains = [ |
|||
'\'self\'', |
|||
]; |
|||
/** @var array Domains from which images can get loaded */ |
|||
private $allowedImageDomains = [ |
|||
'\'self\'', |
|||
]; |
|||
/** @var array Domains to which connections can be done */ |
|||
private $allowedConnectDomains = [ |
|||
'\'self\'', |
|||
]; |
|||
/** @var array Domains from which media elements can be loaded */ |
|||
private $allowedMediaDomains = [ |
|||
'\'self\'', |
|||
]; |
|||
/** @var array Domains from which object elements can be loaded */ |
|||
private $allowedObjectDomains = []; |
|||
/** @var array Domains from which iframes can be loaded */ |
|||
private $allowedFrameDomains = []; |
|||
/** @var array Domains from which fonts can be loaded */ |
|||
private $allowedFontDomains = [ |
|||
'\'self\'', |
|||
]; |
|||
|
|||
/** |
|||
* Whether inline JavaScript snippets are allowed or forbidden |
|||
* @param bool $state |
|||
* @return $this |
|||
*/ |
|||
public function allowInlineScript($state = false) { |
|||
$this->inlineScriptAllowed = $state; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* Whether eval in JavaScript is allowed or forbidden |
|||
* @param bool $state |
|||
* @return $this |
|||
*/ |
|||
public function allowEvalScript($state = true) { |
|||
$this->evalScriptAllowed= $state; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* Allows to execute JavaScript files from a specific domain. Use * to |
|||
* allow JavaScript from all domains. |
|||
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. |
|||
* @return $this |
|||
*/ |
|||
public function addAllowedScriptDomain($domain) { |
|||
$this->allowedScriptDomains[] = $domain; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* Whether inline CSS snippets are allowed or forbidden |
|||
* @param bool $state |
|||
* @return $this |
|||
*/ |
|||
public function allowInlineStyle($state = true) { |
|||
$this->inlineStyleAllowed = $state; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* Allows to execute CSS files from a specific domain. Use * to allow |
|||
* CSS from all domains. |
|||
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. |
|||
* @return $this |
|||
*/ |
|||
public function addAllowedStyleDomain($domain) { |
|||
$this->allowedStyleDomains[] = $domain; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* Allows using fonts from a specific domain. Use * to allow |
|||
* fonts from all domains. |
|||
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. |
|||
* @return $this |
|||
*/ |
|||
public function addAllowedFontDomain($domain) { |
|||
$this->allowedFontDomains[] = $domain; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* Allows embedding images from a specific domain. Use * to allow |
|||
* images from all domains. |
|||
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. |
|||
* @return $this |
|||
*/ |
|||
public function addAllowedImageDomain($domain) { |
|||
$this->allowedImageDomains[] = $domain; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* To which remote domains the JS connect to. |
|||
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. |
|||
* @return $this |
|||
*/ |
|||
public function addAllowedConnectDomain($domain) { |
|||
$this->allowedConnectDomains[] = $domain; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* From whoch domains media elements can be embedded. |
|||
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. |
|||
* @return $this |
|||
*/ |
|||
public function addAllowedMediaDomain($domain) { |
|||
$this->allowedMediaDomains[] = $domain; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* From which domains objects such as <object>, <embed> or <applet> are executed |
|||
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. |
|||
* @return $this |
|||
*/ |
|||
public function addAllowedObjectDomain($domain) { |
|||
$this->allowedObjectDomains[] = $domain; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* Which domains can be embedded in an iframe |
|||
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. |
|||
* @return $this |
|||
*/ |
|||
public function addAllowedFrameDomain($domain) { |
|||
$this->allowedFrameDomains[] = $domain; |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* Get the generated Content-Security-Policy as a string |
|||
* @return string |
|||
*/ |
|||
public function buildPolicy() { |
|||
$policy = "default-src 'none';"; |
|||
|
|||
if(!empty($this->allowedScriptDomains)) { |
|||
$policy .= 'script-src ' . implode(' ', $this->allowedScriptDomains); |
|||
if($this->inlineScriptAllowed) { |
|||
$policy .= ' \'unsafe-inline\''; |
|||
} |
|||
if($this->evalScriptAllowed) { |
|||
$policy .= ' \'unsafe-eval\''; |
|||
} |
|||
$policy .= ';'; |
|||
} |
|||
|
|||
if(!empty($this->allowedStyleDomains)) { |
|||
$policy .= 'style-src ' . implode(' ', $this->allowedStyleDomains); |
|||
if($this->inlineStyleAllowed) { |
|||
$policy .= ' \'unsafe-inline\''; |
|||
} |
|||
$policy .= ';'; |
|||
} |
|||
|
|||
if(!empty($this->allowedImageDomains)) { |
|||
$policy .= 'img-src ' . implode(' ', $this->allowedImageDomains); |
|||
$policy .= ';'; |
|||
} |
|||
|
|||
if(!empty($this->allowedFontDomains)) { |
|||
$policy .= 'font-src ' . implode(' ', $this->allowedFontDomains); |
|||
$policy .= ';'; |
|||
} |
|||
|
|||
if(!empty($this->allowedConnectDomains)) { |
|||
$policy .= 'connect-src ' . implode(' ', $this->allowedConnectDomains); |
|||
$policy .= ';'; |
|||
} |
|||
|
|||
if(!empty($this->allowedMediaDomains)) { |
|||
$policy .= 'media-src ' . implode(' ', $this->allowedMediaDomains); |
|||
$policy .= ';'; |
|||
} |
|||
|
|||
if(!empty($this->allowedObjectDomains)) { |
|||
$policy .= 'object-src ' . implode(' ', $this->allowedObjectDomains); |
|||
$policy .= ';'; |
|||
} |
|||
|
|||
if(!empty($this->allowedFrameDomains)) { |
|||
$policy .= 'frame-src ' . implode(' ', $this->allowedFrameDomains); |
|||
$policy .= ';'; |
|||
} |
|||
|
|||
return rtrim($policy, ';'); |
|||
} |
|||
} |
|||
@ -0,0 +1,215 @@ |
|||
<?php |
|||
/** |
|||
* Copyright (c) 2015 Lukas Reschke lukas@owncloud.com |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING-README file. |
|||
*/ |
|||
|
|||
|
|||
namespace OC\AppFramework\Http; |
|||
|
|||
use OCP\AppFramework\Http; |
|||
use OCP\AppFramework\Http\ContentSecurityPolicy; |
|||
|
|||
/** |
|||
* Class ContentSecurityPolicyTest |
|||
* |
|||
* @package OC\AppFramework\Http |
|||
*/ |
|||
class ContentSecurityPolicyTest extends \Test\TestCase { |
|||
|
|||
/** @var ContentSecurityPolicy */ |
|||
private $contentSecurityPolicy; |
|||
|
|||
public function setUp() { |
|||
parent::setUp(); |
|||
$this->contentSecurityPolicy = new ContentSecurityPolicy(); |
|||
} |
|||
|
|||
public function testGetPolicyDefault() { |
|||
$defaultPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'"; |
|||
$this->assertSame($defaultPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyScriptDomainValid() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' www.owncloud.com 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyScriptDomainValidMultiple() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' www.owncloud.com www.owncloud.org 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); |
|||
$this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.org'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyScriptAllowInline() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->allowInlineScript(true); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyScriptAllowInlineWithDomain() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' www.owncloud.com 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); |
|||
$this->contentSecurityPolicy->allowInlineScript(true); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyScriptDisallowInlineAndEval() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->allowInlineScript(false); |
|||
$this->contentSecurityPolicy->allowEvalScript(false); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyStyleDomainValid() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' www.owncloud.com 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyStyleDomainValidMultiple() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' www.owncloud.com www.owncloud.org 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); |
|||
$this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.org'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyStyleAllowInline() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->allowInlineStyle(true); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyStyleAllowInlineWithDomain() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' www.owncloud.com 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyStyleDisallowInline() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->allowInlineStyle(false); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyImageDomainValid() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' www.owncloud.com;font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyImageDomainValidMultiple() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' www.owncloud.com www.owncloud.org;font-src 'self';connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); |
|||
$this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.org'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyFontDomainValid() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self' www.owncloud.com;connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyFontDomainValidMultiple() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self' www.owncloud.com www.owncloud.org;connect-src 'self';media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); |
|||
$this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.org'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyConnectDomainValid() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self' www.owncloud.com;media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyConnectDomainValidMultiple() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self' www.owncloud.com www.owncloud.org;media-src 'self'"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); |
|||
$this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.org'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyMediaDomainValid() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self' www.owncloud.com"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyMediaDomainValidMultiple() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self' www.owncloud.com www.owncloud.org"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); |
|||
$this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.org'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyObjectDomainValid() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self';object-src www.owncloud.com"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyObjectDomainValidMultiple() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self';object-src www.owncloud.com www.owncloud.org"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); |
|||
$this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.org'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
|
|||
public function testGetAllowedFrameDomain() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self';frame-src www.owncloud.com"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testGetPolicyFrameDomainValidMultiple() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self';frame-src www.owncloud.com www.owncloud.org"; |
|||
|
|||
$this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); |
|||
$this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.org'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
|
|||
public function testConfigureStacked() { |
|||
$expectedPolicy = "default-src 'none';script-src 'self' script.owncloud.org;style-src 'self' style.owncloud.org;img-src 'self' img.owncloud.org;font-src 'self' font.owncloud.org;connect-src 'self' connect.owncloud.org;media-src 'self' media.owncloud.org;object-src objects.owncloud.org;frame-src frame.owncloud.org"; |
|||
|
|||
$this->contentSecurityPolicy->allowInlineStyle(false) |
|||
->allowEvalScript(false) |
|||
->addAllowedScriptDomain('script.owncloud.org') |
|||
->addAllowedStyleDomain('style.owncloud.org') |
|||
->addAllowedFontDomain('font.owncloud.org') |
|||
->addAllowedImageDomain('img.owncloud.org') |
|||
->addAllowedConnectDomain('connect.owncloud.org') |
|||
->addAllowedMediaDomain('media.owncloud.org') |
|||
->addAllowedObjectDomain('objects.owncloud.org') |
|||
->addAllowedFrameDomain('frame.owncloud.org'); |
|||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue