diff --git a/composer.json b/composer.json index 7610338aff..1ba7d07b8f 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "The Kirby 3 core", "license": "proprietary", "type": "kirby-cms", - "version": "3.9.6", + "version": "3.9.6.1", "keywords": [ "kirby", "cms", diff --git a/composer.lock b/composer.lock index 1407d9d6a1..fc04e4fd34 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "71f213866ce84f54adbb09cab0316cd5", + "content-hash": "4e1278304c8c88cbb866838dbf281668", "packages": [ { "name": "claviska/simpleimage", diff --git a/config/components.php b/config/components.php index 135ceef91d..b13d94c009 100644 --- a/config/components.php +++ b/config/components.php @@ -140,8 +140,8 @@ 'search' => function ( App $kirby, Collection $collection, - string $query = '', - $params = [] + string|null $query = '', + array|string $params = [] ): Collection|bool { if (is_string($params) === true) { $params = ['fields' => Str::split($params, '|')]; @@ -154,9 +154,8 @@ 'words' => false, ]; - $collection = clone $collection; - $options = array_merge($defaults, $params); - $query = trim($query); + $options = array_merge($defaults, $params); + $query = trim($query ?? ''); // empty or too short search query if (Str::length($query) < $options['minlength']) { diff --git a/i18n/translations/de.json b/i18n/translations/de.json index eec3033f47..b202fe48d0 100644 --- a/i18n/translations/de.json +++ b/i18n/translations/de.json @@ -183,7 +183,7 @@ "error.user.email.invalid": "Bitte gib eine gültige E-Mailadresse an", "error.user.language.invalid": "Bitte gib eine gültige Sprache an", "error.user.notFound": "Der Account \"{name}\" wurde nicht gefunden", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.excessive": "Bitte gib ein gültiges Passwort ein. Passwörter dürfen nicht länger als 1000 Zeichen sein.", "error.user.password.invalid": "Bitte gib ein gültiges Passwort ein. Passwörter müssen mindestens 8 Zeichen lang sein.", "error.user.password.notSame": "Die Passwörter stimmen nicht überein", "error.user.password.undefined": "Der Account hat kein Passwort", diff --git a/i18n/translations/tr.json b/i18n/translations/tr.json index 02b183f575..c19d13a0b2 100644 --- a/i18n/translations/tr.json +++ b/i18n/translations/tr.json @@ -183,7 +183,7 @@ "error.user.email.invalid": "Lütfen geçerli bir e-posta adresi girin", "error.user.language.invalid": "Lütfen geçerli bir dil girin", "error.user.notFound": "\"{name}\" kullanıcısı bulunamadı", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.excessive": "Lütfen geçerli bir şifre girin. Şifreler 1000 karakterden uzun olmamalıdır.", "error.user.password.invalid": "Lütfen geçerli bir şifre giriniz. Şifreler en az 8 karakter uzunluğunda olmalıdır.", "error.user.password.notSame": "L\u00fctfen \u015fifreyi do\u011frulay\u0131n", "error.user.password.undefined": "Bu kullanıcının şifresi yok", diff --git a/src/Panel/Document.php b/src/Panel/Document.php index 4d9d026d53..ee2a62d8a7 100644 --- a/src/Panel/Document.php +++ b/src/Panel/Document.php @@ -278,8 +278,16 @@ public static function response(array $fiber): Response 'panelUrl' => $uri->path()->toString(true) . '/', ]); + $frameAncestors = $kirby->option('panel.frameAncestors'); + $frameAncestors = match (true) { + $frameAncestors === true => "'self'", + is_array($frameAncestors) => "'self' " . implode(' ', $frameAncestors), + is_string($frameAncestors) => $frameAncestors, + default => "'none'" + }; + return new Response($body, 'text/html', $code, [ - 'Content-Security-Policy' => "frame-ancestors 'none'" + 'Content-Security-Policy' => 'frame-ancestors ' . $frameAncestors ]); } } diff --git a/tests/Cms/Api/routes/AccountRoutesTest.php b/tests/Cms/Api/routes/AccountRoutesTest.php index 5e06417dd9..5e758be317 100644 --- a/tests/Cms/Api/routes/AccountRoutesTest.php +++ b/tests/Cms/Api/routes/AccountRoutesTest.php @@ -48,6 +48,7 @@ public function setUp(): void public function tearDown(): void { + $this->app->session()->destroy(); App::destroy(); Field::$types = []; Section::$types = []; diff --git a/tests/Cms/Auth/AuthTest.php b/tests/Cms/Auth/AuthTest.php index 7a81a09696..3ffea737e5 100644 --- a/tests/Cms/Auth/AuthTest.php +++ b/tests/Cms/Auth/AuthTest.php @@ -305,8 +305,7 @@ public function testUserSessionManualSession() } /** - * @covers ::status - * @covers ::user + * @covers ::currentUserFromSession */ public function testUserSessionOldTimestamp() { @@ -326,8 +325,7 @@ public function testUserSessionOldTimestamp() } /** - * @covers ::status - * @covers ::user + * @covers ::currentUserFromSession */ public function testUserSessionNoTimestamp() { diff --git a/tests/Cms/Collections/SearchTest.php b/tests/Cms/Collections/SearchTest.php index 136b19a8bb..4435e2f58c 100644 --- a/tests/Cms/Collections/SearchTest.php +++ b/tests/Cms/Collections/SearchTest.php @@ -39,6 +39,12 @@ public function testCollection() $search = Search::collection($collection, ' '); $this->assertCount(0, $search); + + $search = Search::collection($collection, null); + $this->assertCount(0, $search); + + $search = Search::collection($collection); + $this->assertCount(0, $search); } diff --git a/tests/Cms/Users/UserActionsTest.php b/tests/Cms/Users/UserActionsTest.php index c9c803dd45..237de09fd9 100644 --- a/tests/Cms/Users/UserActionsTest.php +++ b/tests/Cms/Users/UserActionsTest.php @@ -44,6 +44,7 @@ public function tearDown(): void { $this->app->session()->destroy(); Dir::remove($this->tmp); + App::destroy(); } public function testChangeEmail() @@ -303,7 +304,7 @@ public function testChangeEmailHooks() $calls = 0; $phpunit = $this; - $app = $this->app->clone([ + $this->app = $this->app->clone([ 'hooks' => [ 'user.changeEmail:before' => function (User $user, $email) use ($phpunit, &$calls) { $phpunit->assertSame('editor@domain.com', $user->email()); @@ -318,7 +319,7 @@ public function testChangeEmailHooks() ] ]); - $user = $app->user('editor@domain.com'); + $user = $this->app->user('editor@domain.com'); $user->changeEmail('another@domain.com'); $this->assertSame(2, $calls); @@ -329,7 +330,7 @@ public function testChangeLanguageHooks() $calls = 0; $phpunit = $this; - $app = $this->app->clone([ + $this->app = $this->app->clone([ 'hooks' => [ 'user.changeLanguage:before' => function (User $user, $language) use ($phpunit, &$calls) { $phpunit->assertSame('en', $user->language()); @@ -344,7 +345,7 @@ public function testChangeLanguageHooks() ] ]); - $user = $app->user('editor@domain.com'); + $user = $this->app->user('editor@domain.com'); $user->changeLanguage('de'); $this->assertSame(2, $calls); @@ -355,7 +356,7 @@ public function testChangeNameHooks() $calls = 0; $phpunit = $this; - $app = $this->app->clone([ + $this->app = $this->app->clone([ 'hooks' => [ 'user.changeName:before' => function (User $user, $name) use ($phpunit, &$calls) { $phpunit->assertNull($user->name()->value()); @@ -370,7 +371,7 @@ public function testChangeNameHooks() ] ]); - $user = $app->user('editor@domain.com'); + $user = $this->app->user('editor@domain.com'); $user->changeName('Edith Thor'); $this->assertSame(2, $calls); @@ -381,7 +382,7 @@ public function testChangePasswordHooks() $calls = 0; $phpunit = $this; - $app = $this->app->clone([ + $this->app = $this->app->clone([ 'hooks' => [ 'user.changePassword:before' => function (User $user, $password) use ($phpunit, &$calls) { $phpunit->assertEmpty($user->password()); @@ -402,7 +403,7 @@ public function testChangePasswordHooks() ] ]); - $user = $app->user('editor@domain.com'); + $user = $this->app->user('editor@domain.com'); $user->changePassword('topsecret2018'); $this->assertSame(3, $calls); @@ -445,7 +446,7 @@ public function testChangeRoleHooks() $calls = 0; $phpunit = $this; - $app = $this->app->clone([ + $this->app = $this->app->clone([ 'hooks' => [ 'user.changeRole:before' => function (User $user, $role) use ($phpunit, &$calls) { $phpunit->assertSame('editor', $user->role()->name()); @@ -460,7 +461,7 @@ public function testChangeRoleHooks() ] ]); - $user = $app->user('editor@domain.com'); + $user = $this->app->user('editor@domain.com'); $user->changeRole('admin'); $this->assertSame(2, $calls); @@ -476,7 +477,7 @@ public function testCreateHooks() 'model' => 'admin', ]; - $this->app->clone([ + $this->app = $this->app->clone([ 'hooks' => [ 'user.create:before' => function (User $user, $input) use ($phpunit, $userInput, &$calls) { $phpunit->assertSame('new@domain.com', $user->email()); @@ -502,7 +503,7 @@ public function testDeleteHooks() $calls = 0; $phpunit = $this; - $app = $this->app->clone([ + $this->app = $this->app->clone([ 'hooks' => [ 'user.delete:before' => function (User $user) use ($phpunit, &$calls) { $phpunit->assertSame('editor@domain.com', $user->email()); @@ -518,7 +519,7 @@ public function testDeleteHooks() ] ]); - $user = $app->user('editor@domain.com'); + $user = $this->app->user('editor@domain.com'); $user->delete(); $this->assertSame(2, $calls); @@ -532,7 +533,7 @@ public function testUpdateHooks() 'website' => 'https://getkirby.com' ]; - $app = $this->app->clone([ + $this->app = $this->app->clone([ 'hooks' => [ 'user.update:before' => function (User $user, $values, $strings) use ($phpunit, $input, &$calls) { $phpunit->assertNull($user->website()->value()); @@ -548,7 +549,7 @@ public function testUpdateHooks() ] ]); - $user = $app->user('editor@domain.com'); + $user = $this->app->user('editor@domain.com'); $user->update($input); $this->assertSame(2, $calls); diff --git a/tests/Cms/Users/UserAuthTest.php b/tests/Cms/Users/UserAuthTest.php index 6bfde4e5f7..23204cb8a1 100644 --- a/tests/Cms/Users/UserAuthTest.php +++ b/tests/Cms/Users/UserAuthTest.php @@ -30,7 +30,9 @@ public function setUp(): void public function tearDown(): void { + $this->app->session()->destroy(); Dir::remove($this->tmp); + App::destroy(); } public function testGlobalUserState() @@ -50,7 +52,7 @@ public function testLoginLogoutHooks() $calls = 0; $logoutSession = false; - $app = $this->app->clone([ + $this->app = $this->app->clone([ 'hooks' => [ 'user.login:before' => function ($user, $session) use ($phpunit, &$calls) { $phpunit->assertSame('test@getkirby.com', $user->email()); @@ -86,7 +88,7 @@ public function testLoginLogoutHooks() ]); // without prepopulated session - $user = $app->user('test@getkirby.com'); + $user = $this->app->user('test@getkirby.com'); $user->loginPasswordless(); $user->logout(); diff --git a/tests/Filesystem/FTest.php b/tests/Filesystem/FTest.php index adc5140423..8297141770 100644 --- a/tests/Filesystem/FTest.php +++ b/tests/Filesystem/FTest.php @@ -493,7 +493,15 @@ public function testMove() */ public function testMoveAcrossDevices() { - $tmpDir = sys_get_temp_dir(); + // try to find a suitable path on a different device (filesystem) + if (is_dir('/dev/shm') === true) { + // use tmpfs mount point on GitHub Actions + $tmpDir = '/dev/shm'; + } else { + // no luck, try the system temp dir, + // which often also uses tmpfs + $tmpDir = sys_get_temp_dir(); + } if (stat($this->tmp)['dev'] === stat($tmpDir)['dev']) { $this->markTestSkipped('Temporary directory "' . $tmpDir . '" is on the same filesystem'); diff --git a/tests/Panel/DocumentTest.php b/tests/Panel/DocumentTest.php index fd4afe548b..f9d2e42d77 100644 --- a/tests/Panel/DocumentTest.php +++ b/tests/Panel/DocumentTest.php @@ -361,4 +361,97 @@ public function testResponse(): void $this->assertSame("frame-ancestors 'none'", $response->header('Content-Security-Policy')); $this->assertNotNull($response->body()); } + + /** + * @covers ::response + */ + public function testResponseFrameAncestorsSelf(): void + { + $this->app = $this->app->clone([ + 'options' => [ + 'panel' => [ + 'frameAncestors' => true + ] + ] + ]); + + // create panel dist files first to avoid redirect + Document::link($this->app); + + // get panel response + $response = Document::response([ + 'test' => 'Test' + ]); + + $this->assertInstanceOf(Response::class, $response); + $this->assertSame(200, $response->code()); + $this->assertSame('text/html', $response->type()); + $this->assertSame('UTF-8', $response->charset()); + $this->assertSame("frame-ancestors 'self'", $response->header('Content-Security-Policy')); + $this->assertNotNull($response->body()); + } + + /** + * @covers ::response + */ + public function testResponseFrameAncestorsArray(): void + { + $this->app = $this->app->clone([ + 'options' => [ + 'panel' => [ + 'frameAncestors' => ['*.example.com', 'https://example.com'] + ] + ] + ]); + + // create panel dist files first to avoid redirect + Document::link($this->app); + + // get panel response + $response = Document::response([ + 'test' => 'Test' + ]); + + $this->assertInstanceOf(Response::class, $response); + $this->assertSame(200, $response->code()); + $this->assertSame('text/html', $response->type()); + $this->assertSame('UTF-8', $response->charset()); + $this->assertSame( + "frame-ancestors 'self' *.example.com https://example.com", + $response->header('Content-Security-Policy') + ); + $this->assertNotNull($response->body()); + } + + /** + * @covers ::response + */ + public function testResponseFrameAncestorsString(): void + { + $this->app = $this->app->clone([ + 'options' => [ + 'panel' => [ + 'frameAncestors' => '*.example.com https://example.com' + ] + ] + ]); + + // create panel dist files first to avoid redirect + Document::link($this->app); + + // get panel response + $response = Document::response([ + 'test' => 'Test' + ]); + + $this->assertInstanceOf(Response::class, $response); + $this->assertSame(200, $response->code()); + $this->assertSame('text/html', $response->type()); + $this->assertSame('UTF-8', $response->charset()); + $this->assertSame( + 'frame-ancestors *.example.com https://example.com', + $response->header('Content-Security-Policy') + ); + $this->assertNotNull($response->body()); + } } diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 726061e427..d7b3cd58f1 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -143,6 +143,10 @@ 'Kirby\\Cms\\UserRules' => $baseDir . '/src/Cms/UserRules.php', 'Kirby\\Cms\\Users' => $baseDir . '/src/Cms/Users.php', 'Kirby\\Cms\\Visitor' => $baseDir . '/src/Cms/Visitor.php', + 'Kirby\\ComposerInstaller\\CmsInstaller' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php', + 'Kirby\\ComposerInstaller\\Installer' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/Installer.php', + 'Kirby\\ComposerInstaller\\Plugin' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/Plugin.php', + 'Kirby\\ComposerInstaller\\PluginInstaller' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php', 'Kirby\\Data\\Data' => $baseDir . '/src/Data/Data.php', 'Kirby\\Data\\Handler' => $baseDir . '/src/Data/Handler.php', 'Kirby\\Data\\Json' => $baseDir . '/src/Data/Json.php', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 4758e0599b..8e0ba8efb6 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -256,6 +256,10 @@ class ComposerStaticInita8011b477bb239488e5d139cdeb7b31e 'Kirby\\Cms\\UserRules' => __DIR__ . '/../..' . '/src/Cms/UserRules.php', 'Kirby\\Cms\\Users' => __DIR__ . '/../..' . '/src/Cms/Users.php', 'Kirby\\Cms\\Visitor' => __DIR__ . '/../..' . '/src/Cms/Visitor.php', + 'Kirby\\ComposerInstaller\\CmsInstaller' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php', + 'Kirby\\ComposerInstaller\\Installer' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/Installer.php', + 'Kirby\\ComposerInstaller\\Plugin' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/Plugin.php', + 'Kirby\\ComposerInstaller\\PluginInstaller' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php', 'Kirby\\Data\\Data' => __DIR__ . '/../..' . '/src/Data/Data.php', 'Kirby\\Data\\Handler' => __DIR__ . '/../..' . '/src/Data/Handler.php', 'Kirby\\Data\\Json' => __DIR__ . '/../..' . '/src/Data/Json.php', diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 5addb0b1ab..0ed7fab225 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -1,8 +1,8 @@ array( 'name' => 'getkirby/cms', - 'pretty_version' => '3.9.6', - 'version' => '3.9.6.0', + 'pretty_version' => '3.9.6.1', + 'version' => '3.9.6.1', 'reference' => NULL, 'type' => 'kirby-cms', 'install_path' => __DIR__ . '/../../', @@ -38,8 +38,8 @@ 'dev_requirement' => false, ), 'getkirby/cms' => array( - 'pretty_version' => '3.9.6', - 'version' => '3.9.6.0', + 'pretty_version' => '3.9.6.1', + 'version' => '3.9.6.1', 'reference' => NULL, 'type' => 'kirby-cms', 'install_path' => __DIR__ . '/../../',