From 9a20c38e150366cf78d44689b1a92bc2de216fb2 Mon Sep 17 00:00:00 2001 From: TowyTowy Date: Mon, 13 Jul 2026 14:16:45 +0200 Subject: [PATCH] fix(core): block disabling the default language pack DefaultLanguagePackGuard is meant to stop an admin from disabling the language pack that `default_locale` points to, but its guard clause used `in_array('flarum-locale', $extension->extra)`, which searches the *values* of the composer `extra` object. Those values are arrays (`branch-alias`, `flarum-extension`, `flarum-locale`, ...), so the string is never found: the check is always false and the guard returned early, leaving the protection as dead code -- the default language pack could be disabled freely. The next line already treats `flarum-locale` as a key via `Arr::get($extra, 'flarum-locale.code')`, confirming a key lookup was intended. Switch the guard to `Arr::has(..., 'flarum-locale')` so the `PermissionDeniedException` fires when the default pack is disabled. Add DB-free unit tests covering the default pack (blocked), a non-default pack (allowed) and a non-language-pack extension (allowed). Co-Authored-By: Claude --- .../Extension/DefaultLanguagePackGuard.php | 2 +- .../DefaultLanguagePackGuardTest.php | 70 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 framework/core/tests/unit/Extension/DefaultLanguagePackGuardTest.php diff --git a/framework/core/src/Extension/DefaultLanguagePackGuard.php b/framework/core/src/Extension/DefaultLanguagePackGuard.php index 747b60b3f6..70bec1a5f6 100644 --- a/framework/core/src/Extension/DefaultLanguagePackGuard.php +++ b/framework/core/src/Extension/DefaultLanguagePackGuard.php @@ -23,7 +23,7 @@ public function __construct( public function handle(Disabling $event): void { - if (! in_array('flarum-locale', $event->extension->extra)) { + if (! Arr::has($event->extension->extra, 'flarum-locale')) { return; } diff --git a/framework/core/tests/unit/Extension/DefaultLanguagePackGuardTest.php b/framework/core/tests/unit/Extension/DefaultLanguagePackGuardTest.php new file mode 100644 index 0000000000..d020936b3d --- /dev/null +++ b/framework/core/tests/unit/Extension/DefaultLanguagePackGuardTest.php @@ -0,0 +1,70 @@ +createStub(SettingsRepositoryInterface::class); + $settings->method('get') + ->willReturnCallback(function ($key, $default = null) use ($defaultLocale) { + return $key === 'default_locale' ? $defaultLocale : $default; + }); + + return new DefaultLanguagePackGuard($settings); + } + + private function disabling(array $extra, string $name = 'flarum/lang-english'): Disabling + { + return new Disabling(new Extension('/tmp/ext', [ + 'name' => $name, + 'extra' => $extra, + ])); + } + + #[Test] + public function it_blocks_disabling_the_default_language_pack() + { + $this->expectException(PermissionDeniedException::class); + + $this->guard('en')->handle( + $this->disabling(['flarum-locale' => ['code' => 'en', 'title' => 'English']]) + ); + } + + #[Test] + public function it_allows_disabling_a_non_default_language_pack() + { + $this->expectNotToPerformAssertions(); + + $this->guard('en')->handle( + $this->disabling(['flarum-locale' => ['code' => 'fr', 'title' => 'French']]) + ); + } + + #[Test] + public function it_allows_disabling_a_non_language_pack_extension() + { + $this->expectNotToPerformAssertions(); + + $this->guard('en')->handle( + $this->disabling(['flarum-extension' => ['title' => 'Some Extension']], 'acme/some-extension') + ); + } +}