diff options
author | Roeland Jago Douma <roeland@famdouma.nl> | 2019-07-27 15:33:55 +0200 |
---|---|---|
committer | Roeland Jago Douma <roeland@famdouma.nl> | 2019-08-10 14:26:22 +0200 |
commit | b8c5008acf0e2bd04d9a72241943311db99cc833 (patch) | |
tree | 0a9ff07f363cf1aa07b9f928c622b56906e301af /lib/public/AppFramework | |
parent | 5d94590cee2b6d4733d4d1c788a882f67d2ae75d (diff) | |
download | nextcloud-server-b8c5008acf0e2bd04d9a72241943311db99cc833.tar.gz nextcloud-server-b8c5008acf0e2bd04d9a72241943311db99cc833.zip |
Add feature policy header
This adds the events and the classes to modify the feature policy.
It also adds a default restricted feature policy.
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
Diffstat (limited to 'lib/public/AppFramework')
-rw-r--r-- | lib/public/AppFramework/Http/EmptyFeaturePolicy.php | 183 | ||||
-rw-r--r-- | lib/public/AppFramework/Http/FeaturePolicy.php | 59 | ||||
-rw-r--r-- | lib/public/AppFramework/Http/Response.php | 23 | ||||
-rw-r--r-- | lib/public/AppFramework/Http/TemplateResponse.php | 1 |
4 files changed, 266 insertions, 0 deletions
diff --git a/lib/public/AppFramework/Http/EmptyFeaturePolicy.php b/lib/public/AppFramework/Http/EmptyFeaturePolicy.php new file mode 100644 index 00000000000..4b8a4f30531 --- /dev/null +++ b/lib/public/AppFramework/Http/EmptyFeaturePolicy.php @@ -0,0 +1,183 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\AppFramework\Http; + +/** + * Class EmptyFeaturePolicy is a simple helper which allows applications + * to modify the FeaturePolicy sent by Nextcloud. Per default the policy + * is forbidding everything. + * + * As alternative with sane exemptions look at FeaturePolicy + * + * @see \OCP\AppFramework\Http\FeaturePolicy + * @package OCP\AppFramework\Http + * @since 17.0.0 + */ +class EmptyFeaturePolicy { + + /** @var string[] of allowed domains to autoplay media */ + protected $autoplayDomains = null; + + /** @var string[] of allowed domains that can access the camera */ + protected $cameraDomains = null; + + /** @var string[] of allowed domains that can use fullscreen */ + protected $fullscreenDomains = null; + + /** @var string[] of allowed domains that can use the geolocation of the device */ + protected $geolocationDomains = null; + + /** @var string[] of allowed domains that can use the microphone */ + protected $microphoneDomains = null; + + /** @var string[] of allowed domains that can use the payment API */ + protected $paymentDomains = null; + + /** + * Allows to use autoplay from a specific domain. Use * to allow from all domains. + * + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 17.0.0 + */ + public function addAllowedAutoplayDomain(string $domain): self { + $this->autoplayDomains[] = $domain; + return $this; + } + + /** + * Allows to use the camera on a specific domain. Use * to allow from all domains + * + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 17.0.0 + */ + public function addAllowedCameraDomain(string $domain): self { + $this->cameraDomains[] = $domain; + return $this; + } + + /** + * Allows the full screen functionality to be used on a specific domain. Use * to allow from all domains + * + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 17.0.0 + */ + public function addAllowedFullScreenDomain(string $domain): self { + $this->fullscreenDomains[] = $domain; + return $this; + } + + /** + * Allows to use the geolocation on a specific domain. Use * to allow from all domains + * + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 17.0.0 + */ + public function addAllowedGeoLocationDomain(string $domain): self { + $this->geolocationDomains[] = $domain; + return $this; + } + + /** + * Allows to use the microphone on a specific domain. Use * to allow from all domains + * + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 17.0.0 + */ + public function addAllowedMicrophoneDomain(string $domain): self { + $this->microphoneDomains[] = $domain; + return $this; + } + + /** + * Allows to use the payment API on a specific domain. Use * to allow from all domains + * + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 17.0.0 + */ + public function addAllowedPaymentDomain(string $domain): self { + $this->paymentDomains[] = $domain; + return $this; + } + + /** + * Get the generated Feature-Policy as a string + * + * @return string + * @since 17.0.0 + */ + public function buildPolicy(): string { + $policy = ''; + + if (empty($this->autoplayDomains)) { + $policy .= "autoplay 'none';"; + } else { + $policy .= 'autoplay ' . implode(' ', $this->autoplayDomains); + $policy .= ';'; + } + + if (empty($this->cameraDomains)) { + $policy .= "camera 'none';"; + } else { + $policy .= 'camera ' . implode(' ', $this->cameraDomains); + $policy .= ';'; + } + + if (empty($this->fullscreenDomains)) { + $policy .= "fullscreen 'none';"; + } else { + $policy .= 'fullscreen ' . implode(' ', $this->fullscreenDomains); + $policy .= ';'; + } + + if (empty($this->geolocationDomains)) { + $policy .= "geolocation 'none';"; + } else { + $policy .= 'geolocation ' . implode(' ', $this->geolocationDomains); + $policy .= ';'; + } + + if (empty($this->microphoneDomains)) { + $policy .= "microphone 'none';"; + } else { + $policy .= 'microphone ' . implode(' ', $this->microphoneDomains); + $policy .= ';'; + } + + if (empty($this->paymentDomains)) { + $policy .= "payment 'none';"; + } else { + $policy .= 'payment ' . implode(' ', $this->paymentDomains); + $policy .= ';'; + } + + return rtrim($policy, ';'); + } +} diff --git a/lib/public/AppFramework/Http/FeaturePolicy.php b/lib/public/AppFramework/Http/FeaturePolicy.php new file mode 100644 index 00000000000..98cfae8b2f9 --- /dev/null +++ b/lib/public/AppFramework/Http/FeaturePolicy.php @@ -0,0 +1,59 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\AppFramework\Http; + +/** + * Class FeaturePolicy is a simple helper which allows applications to + * modify the Feature-Policy sent by Nextcloud. Per default only autoplay is allowed + * from the same domain and full screen as well from the same domain. + * + * Even if a value gets modified above defaults will still get appended. Please + * notice that Nextcloud ships already with sensible defaults and those policies + * should require no modification at all for most use-cases. + * + * @package OCP\AppFramework\Http + * @since 17.0.0 + */ +class FeaturePolicy extends EmptyFeaturePolicy { + protected $autoplayDomains = [ + '\'self\'', + ]; + + /** @var string[] of allowed domains that can access the camera */ + protected $cameraDomains = []; + + protected $fullscreenDomains = [ + '\'self\'', + ]; + + /** @var string[] of allowed domains that can use the geolocation of the device */ + protected $geolocationDomains = []; + + /** @var string[] of allowed domains that can use the microphone */ + protected $microphoneDomains = []; + + /** @var string[] of allowed domains that can use the payment API */ + protected $paymentDomains = []; +} diff --git a/lib/public/AppFramework/Http/Response.php b/lib/public/AppFramework/Http/Response.php index 98c0a7f5f70..bfee7d51549 100644 --- a/lib/public/AppFramework/Http/Response.php +++ b/lib/public/AppFramework/Http/Response.php @@ -84,6 +84,9 @@ class Response { /** @var ContentSecurityPolicy|null Used Content-Security-Policy */ private $contentSecurityPolicy = null; + /** @var FeaturePolicy */ + private $featurePolicy; + /** @var bool */ private $throttled = false; /** @var array */ @@ -96,6 +99,7 @@ class Response { */ public function __construct() { $this->setContentSecurityPolicy(new EmptyContentSecurityPolicy()); + $this->setFeaturePolicy(new EmptyFeaturePolicy()); } /** @@ -242,6 +246,7 @@ class Response { $this->setContentSecurityPolicy(new ContentSecurityPolicy()); } $this->headers['Content-Security-Policy'] = $this->contentSecurityPolicy->buildPolicy(); + $this->headers['Feature-Policy'] = $this->featurePolicy->buildPolicy(); if($this->ETag) { $mergeWith['ETag'] = '"' . $this->ETag . '"'; @@ -296,6 +301,24 @@ class Response { /** + * @since 17.0.0 + */ + public function getFeaturePolicy(): EmptyFeaturePolicy { + return $this->featurePolicy; + } + + /** + * @since 17.0.0 + */ + public function setFeaturePolicy(EmptyFeaturePolicy $featurePolicy): self { + $this->featurePolicy = $featurePolicy; + + return $this; + } + + + + /** * Get response status * @since 6.0.0 */ diff --git a/lib/public/AppFramework/Http/TemplateResponse.php b/lib/public/AppFramework/Http/TemplateResponse.php index 334928cc03c..da6f93584b6 100644 --- a/lib/public/AppFramework/Http/TemplateResponse.php +++ b/lib/public/AppFramework/Http/TemplateResponse.php @@ -83,6 +83,7 @@ class TemplateResponse extends Response { $this->renderAs = $renderAs; $this->setContentSecurityPolicy(new ContentSecurityPolicy()); + $this->setFeaturePolicy(new FeaturePolicy()); } |