From ddc7149af9f910ef3c620b7b7eac779cdd7aede9 Mon Sep 17 00:00:00 2001 From: Mauricio Kruijer Date: Mon, 25 Oct 2021 14:49:35 +0200 Subject: [PATCH 1/4] Changed test values to Structured Field Value Technically, it's a structured Dictionary --- tests/AddFeaturePolicyHeadersTest.php | 14 +++++++------- tests/MiddlewareTest.php | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/AddFeaturePolicyHeadersTest.php b/tests/AddFeaturePolicyHeadersTest.php index ccf44ff..d5db4cf 100644 --- a/tests/AddFeaturePolicyHeadersTest.php +++ b/tests/AddFeaturePolicyHeadersTest.php @@ -29,7 +29,7 @@ public function it_sets_the_default_feature_policy_headers() { $headers = $this->getResponseHeaders(); - $this->assertStringContainsString("geolocation 'self'", $headers->get('Permissions-Policy')); + $this->assertStringContainsString("geolocation=self", $headers->get('Permissions-Policy')); } /** @test */ @@ -77,7 +77,7 @@ public function configure() $headers = $this->getResponseHeaders(); $this->assertEquals( - 'camera src-1 src-2;fullscreen src-3 src-4', + 'camera=("src-1" "src-2"),fullscreen=("src-3" "src-4")', $headers->get('Permissions-Policy') ); } @@ -97,7 +97,7 @@ public function configure() $headers = $this->getResponseHeaders(); $this->assertEquals( - 'camera src-1 src-2', + 'camera=("src-1" "src-2")', $headers->get('Permissions-Policy') ); } @@ -117,7 +117,7 @@ public function configure() $headers = $this->getResponseHeaders(); $this->assertEquals( - "camera 'self'", + "camera=self", $headers->get('Permissions-Policy') ); } @@ -137,7 +137,7 @@ public function configure() $headers = $this->getResponseHeaders(); $this->assertEquals( - "camera src-1 'self' src-2", + 'camera=("src-1" self "src-2")', $headers->get('Permissions-Policy') ); } @@ -157,7 +157,7 @@ public function configure() $headers = $this->getResponseHeaders(); $this->assertEquals( - "camera 'self'", + "camera=self", $headers->get('Permissions-Policy') ); } @@ -181,7 +181,7 @@ public function configure() $headers = $this->getResponseHeaders('other-route'); $this->assertEquals( - 'fullscreen custom-policy', + 'fullscreen="custom-policy"', $headers->get('Permissions-Policy') ); } diff --git a/tests/MiddlewareTest.php b/tests/MiddlewareTest.php index 13506f1..0778c84 100644 --- a/tests/MiddlewareTest.php +++ b/tests/MiddlewareTest.php @@ -25,7 +25,7 @@ public function it_sets_the_default_feature_policy_headers() { $headers = $this->getResponseHeaders(); - $this->assertStringContainsString("geolocation 'self'", $headers->get('Permissions-Policy')); + $this->assertStringContainsString('geolocation=self', $headers->get('Permissions-Policy')); } protected function getResponseHeaders(string $url = 'test-route'): HeaderBag From 215ae3456dd2f564beab141ae1acf5be6269a13f Mon Sep 17 00:00:00 2001 From: Mauricio Kruijer Date: Mon, 25 Oct 2021 14:51:04 +0200 Subject: [PATCH 2/4] Fixed common tests according rfc8941 spec --- src/Policies/Policy.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Policies/Policy.php b/src/Policies/Policy.php index 45975c4..2fb4615 100644 --- a/src/Policies/Policy.php +++ b/src/Policies/Policy.php @@ -58,8 +58,11 @@ public function __toString() ->map(function (array $values, string $directive) { $valueString = implode(' ', $values); - return "{$directive} {$valueString}"; - })->implode(';'); + return count($values) === 1 + ? "{$directive}={$valueString}" + : "{$directive}=({$valueString})"; + + })->implode(','); } protected function guardAgainstInvalidDirective(string $directive) @@ -83,9 +86,9 @@ protected function isSpecialDirectiveValue(string $value) protected function sanitizeValue(string $value): string { if ($this->isSpecialDirectiveValue($value)) { - return "'{$value}'"; + return $value; } - return $value; + return "\"{$value}\""; } } From 66c2b10da4b2fb131257a52245f761926f92d124 Mon Sep 17 00:00:00 2001 From: Mauricio Kruijer Date: Mon, 25 Oct 2021 14:51:29 +0200 Subject: [PATCH 3/4] None value changed from 'none' to () --- src/Value.php | 2 +- tests/AddFeaturePolicyHeadersTest.php | 44 +++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/Value.php b/src/Value.php index c7460ff..eb96f7c 100644 --- a/src/Value.php +++ b/src/Value.php @@ -6,5 +6,5 @@ abstract class Value { const ALL = '*'; const SELF = 'self'; - const NONE = 'none'; + const NONE = '()'; } diff --git a/tests/AddFeaturePolicyHeadersTest.php b/tests/AddFeaturePolicyHeadersTest.php index d5db4cf..5e00187 100644 --- a/tests/AddFeaturePolicyHeadersTest.php +++ b/tests/AddFeaturePolicyHeadersTest.php @@ -103,7 +103,7 @@ public function configure() } /** @test */ - public function it_quotes_special_directive_values() + public function it_doesnt_quotes_special_directive_values() { $policy = new class extends Policy { public function configure() @@ -157,7 +157,47 @@ public function configure() $headers = $this->getResponseHeaders(); $this->assertEquals( - "camera=self", + 'camera=self', + $headers->get('Permissions-Policy') + ); + } + + /** @test */ + public function it_will_render_none_value() + { + $policy = new class extends Policy { + public function configure() + { + $this->addDirective(Directive::CAMERA, [Value::NONE]); + } + }; + + config(['feature-policy.policy' => get_class($policy)]); + + $headers = $this->getResponseHeaders(); + + $this->assertEquals( + 'camera=()', + $headers->get('Permissions-Policy') + ); + } + + /** @test */ + public function it_will_render_all_value() + { + $policy = new class extends Policy { + public function configure() + { + $this->addDirective(Directive::CAMERA, [Value::ALL]); + } + }; + + config(['feature-policy.policy' => get_class($policy)]); + + $headers = $this->getResponseHeaders(); + + $this->assertEquals( + 'camera=*', $headers->get('Permissions-Policy') ); } From 9d60643f9fbe9581986a2fc206c4109c3b0ebb92 Mon Sep 17 00:00:00 2001 From: Mauricio Kruijer Date: Mon, 25 Oct 2021 15:32:53 +0200 Subject: [PATCH 4/4] Updated readme and change log --- CHANGELOG.md | 4 ++++ README.md | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47e5d42..44ff4a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-feature-policy` will be documented in this file +## 1.2.0 - 2021-10-25 + +- implemented [RFC-8941](https://datatracker.ietf.org/doc/html/rfc8941) Structured Field Values for directive values + ## 1.1.2 - 2021-01-02 - add PHP 8 support diff --git a/README.md b/README.md index afa9978..5ea23cc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Set Feature-Policy headers in a Laravel app +# Set Permissions-Policy headers in a Laravel app **NOW WITH PHP 8 SUPPORT** @@ -8,7 +8,7 @@ This package is strongly inspired by [Spaties](https://spatie.be) [laravel-csp](https://github.com/spatie/laravel-csp) package. Thanks to [Freek van der Herten](https://github.com/freekmurze) and [Thomas Verhelst](https://github.com/TVke) for creating such an awesome package and doing all the heavy lifting! -With Feature-Policy you can control which web platform features to allow and disallow within your web applications. Feature-Policy is a Security Header (like Content-Security-Policy) that is brand new. The list of things you can restrict isn't final yet, I'll add them in time when the specification evolves. +With Permissions-Policy you can control which web platform permissions to allow and disallow within your web applications. Permissions-Policy is a Security Header (like Content-Security-Policy) that is brand new. The list of things you can restrict isn't final yet, I'll add them in time when the specification evolves. ## Installation @@ -31,7 +31,7 @@ The contents of the `config/feature-policy.php` file look like this: return [ /* - * A policy will determine which Feature-Policy headers will be set. + * A policy will determine which Permissions-Policy headers will be set. * A valid policy extends `Mazedlx\FeaturePolicy\Policies\Policy` */ 'policy' => Mazedlx\FeaturePolicy\Policies\Basic::class, @@ -60,7 +60,7 @@ protected $middlewareGroups = [ ]; ``` -Alternatively you can add the middleware to the a single route and route group: +Alternatively you can add the middleware to a single route and route group: ```php // in a routes file @@ -76,15 +76,15 @@ Route::get('/home', 'HomeController')->middleware(Mazedlx\FeaturePolicy\AddFeatu ## Usage -This package allows you to define Feature-Policy policies. A Feature-Policy policy determines which Feature-Policy directives will be set in the headers of the response. +This package allows you to define Permissions-Policy policies. A Feature-Policy policy determines which Permissions-Policy directives will be set in the headers of the response. -An example of a Feature-Policy directive is `microphone`: +An example of a Permissions-Policy directive is `microphone`: -`Feature-Policy: microphone 'self' https://spatie.be` +`Permissions-Policy: microphone=(self "https://spatie.be")` -In the above example by specifying `microphone` and allowing it for `'self'` the feature is diabled for all origins except our own and https://spatie.be. +In the above example by specifying `microphone` and allowing it for `self` makes the permission disabled for all origins except our own and https://spatie.be. -The full list of restrictable directives isn't final yet, but here are some of the things you have access to: +The full list of directives isn't final yet, but here are some of the things you have access to: - accelerometer - ambient-light-sensor @@ -105,7 +105,7 @@ The full list of restrictable directives isn't final yet, but here are some of t You can find the feature definitions at https://github.com/WICG/feature-policy/blob/master/features.md -You can add multiple policy options as an array or as a single string with space-sepearated options: +You can add multiple policy options as an array or as a single string with space-separated options: ```php // in a policy