diff --git a/config/config.sample.php b/config/config.sample.php index c21291cd3da03..47bc87d128a26 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -1962,7 +1962,7 @@ /** * Blacklist characters from being used in filenames. This is useful if you * have a filesystem or OS which does not support certain characters like windows. - * + * * The '/' and '\' characters are always forbidden. * * Example for windows systems: ``array('?', '<', '>', ':', '*', '|', '"', chr(0), "\n", "\r")`` @@ -2431,4 +2431,20 @@ * Defaults to ``true`` */ 'enable_non-accessible_features' => true, + +/** + * Directories where nextcloud looks for binaries. + * This is used to find external binaries like libreoffice, sendmail, ffmpeg and more. + * + * Defaults to ``['/usr/local/sbin','/usr/local/bin','/usr/sbin','/usr/bin','/sbin','/bin','/opt/bin']`` + */ +'binary_search_paths' => [ + '/usr/local/sbin', + '/usr/local/bin', + '/usr/sbin', + '/usr/bin', + '/sbin', + '/bin', + '/opt/bin', +], ]; diff --git a/lib/private/BinaryFinder.php b/lib/private/BinaryFinder.php index 17427e9261932..30c80d8987c70 100644 --- a/lib/private/BinaryFinder.php +++ b/lib/private/BinaryFinder.php @@ -3,6 +3,7 @@ declare(strict_types = 1); /** * @copyright 2022 Carl Schwan + * @copyright 2024 Reno Reckling * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify @@ -25,15 +26,28 @@ use OCP\IBinaryFinder; use OCP\ICache; use OCP\ICacheFactory; +use OCP\IConfig; use Symfony\Component\Process\ExecutableFinder; /** * Service that find the binary path for a program */ class BinaryFinder implements IBinaryFinder { + public const DEFAULT_BINARY_SEARCH_PATHS = [ + '/usr/local/sbin', + '/usr/local/bin', + '/usr/sbin', + '/usr/bin', + '/sbin', + '/bin', + '/opt/bin', + ]; private ICache $cache; - public function __construct(ICacheFactory $cacheFactory) { + public function __construct( + ICacheFactory $cacheFactory, + private IConfig $config + ) { $this->cache = $cacheFactory->createLocal('findBinaryPath'); } @@ -51,15 +65,10 @@ public function findBinaryPath(string $program) { if (\OCP\Util::isFunctionEnabled('exec')) { $exeSniffer = new ExecutableFinder(); // Returns null if nothing is found - $result = $exeSniffer->find($program, null, [ - '/usr/local/sbin', - '/usr/local/bin', - '/usr/sbin', - '/usr/bin', - '/sbin', - '/bin', - '/opt/bin', - ]); + $result = $exeSniffer->find( + $program, + null, + $this->config->getSystemValue('binary_search_paths', self::DEFAULT_BINARY_SEARCH_PATHS)); if ($result === null) { $result = false; } diff --git a/tests/lib/BinaryFinderTest.php b/tests/lib/BinaryFinderTest.php new file mode 100644 index 0000000000000..1734ff385a7d9 --- /dev/null +++ b/tests/lib/BinaryFinderTest.php @@ -0,0 +1,92 @@ + + * @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 . + * + */ + +namespace Test; + +use OC\BinaryFinder; +use OCP\ICache; +use OCP\ICacheFactory; +use OCP\IConfig; + +class BinaryFinderTest extends TestCase { + private ICache $cache; + private array $cacheMap; + private ICacheFactory $cacheFactory; + + protected function setUp(): void { + $this->cacheMap = []; + $this->cacheFactory = $this->createMock(ICacheFactory::class); + $this->cache = $this->createMock(ICache::class); + $this->cache->method('get')->will($this->returnCallback(function ($key) { + return array_key_exists($key, $this->cacheMap) ? $this->cacheMap[$key] : null; + })); + $this->cache->method('set')->will($this->returnCallback(function ($key, $val, $expires) { + $this->cacheMap[$key] = $val; + })); + $this->cacheFactory->method('createLocal')->with('findBinaryPath')->willReturn($this->cache); + + } + + public function testDefaultFindsCat() { + $config = $this->createMock(IConfig::class); + $config + ->method('getSystemValue') + ->with('binary_search_paths', $this->anything()) + ->will($this->returnCallback(function ($key, $default) { + return $default; + })); + $finder = new BinaryFinder($this->cacheFactory, $config); + $this->assertEquals($finder->findBinaryPath('cat'), '/usr/bin/cat'); + } + + public function testDefaultDoesNotFindCata() { + $config = $this->createMock(IConfig::class); + $config + ->method('getSystemValue') + ->with('binary_search_paths', $this->anything()) + ->will($this->returnCallback(function ($key, $default) { + return $default; + })); + $finder = new BinaryFinder($this->cacheFactory, $config); + $this->assertFalse($finder->findBinaryPath('cata')); + } + + public function testCustomPathFindsCat() { + $config = $this->createMock(IConfig::class); + $config + ->method('getSystemValue') + ->with('binary_search_paths', $this->anything()) + ->willReturn(['/usr/bin']); + $finder = new BinaryFinder($this->cacheFactory, $config); + $this->assertEquals($finder->findBinaryPath('cat'), '/usr/bin/cat'); + } + + public function testWrongCustomPathDoesNotFindCat() { + $config = $this->createMock(IConfig::class); + $config + ->method('getSystemValue') + ->with('binary_search_paths') + ->willReturn(['/wrong']); + $finder = new BinaryFinder($this->cacheFactory, $config); + $this->assertFalse($finder->findBinaryPath('cats')); + } +}