Skip to content

Commit

Permalink
feat: make search path for BinaryFinder customizable.
Browse files Browse the repository at this point in the history
This feature is important for nextcloud running on
distributions like NixOS, where all the standard
search paths do not exist.

Also added tests.

This fixes issue nextcloud#43922

Signed-off-by: Reno Reckling <[email protected]>
  • Loading branch information
exi authored and skjnldsv committed Mar 7, 2024
1 parent 8a6ac51 commit 0c2509b
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 11 deletions.
18 changes: 17 additions & 1 deletion config/config.sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -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")``
Expand Down Expand Up @@ -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',
],
];
29 changes: 19 additions & 10 deletions lib/private/BinaryFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
declare(strict_types = 1);
/**
* @copyright 2022 Carl Schwan <[email protected]>
* @copyright 2024 Reno Reckling <[email protected]>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
Expand All @@ -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');
}

Expand All @@ -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;
}
Expand Down
92 changes: 92 additions & 0 deletions tests/lib/BinaryFinderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

declare(strict_types = 1);
/**
* @copyright 2024 Reno Reckling <[email protected]>
* @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 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'));
}
}

0 comments on commit 0c2509b

Please sign in to comment.