diff options
-rw-r--r-- | lib/Controller/MatterbridgeSettingsController.php | 13 | ||||
-rw-r--r-- | lib/Exceptions/WrongPermissionsException.php | 28 | ||||
-rw-r--r-- | lib/MatterbridgeManager.php | 28 | ||||
-rw-r--r-- | lib/Settings/Admin/AdminSettings.php | 17 | ||||
-rw-r--r-- | src/components/AdminSettings/MatterbridgeIntegration.vue | 23 |
5 files changed, 102 insertions, 7 deletions
diff --git a/lib/Controller/MatterbridgeSettingsController.php b/lib/Controller/MatterbridgeSettingsController.php index 0c0a8a77e..f1882c783 100644 --- a/lib/Controller/MatterbridgeSettingsController.php +++ b/lib/Controller/MatterbridgeSettingsController.php @@ -27,6 +27,7 @@ namespace OCA\Talk\Controller; use OCA\Talk\MatterbridgeManager; use OCA\Talk\Exceptions\ImpossibleToKillException; +use OCA\Talk\Exceptions\WrongPermissionsException; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCSController; @@ -49,10 +50,16 @@ class MatterbridgeSettingsController extends OCSController { * @return DataResponse */ public function getMatterbridgeVersion(): DataResponse { - $version = $this->bridgeManager->getCurrentVersionFromBinary(); - if ($version === null) { + try { + $version = $this->bridgeManager->getCurrentVersionFromBinary(); + if ($version === null) { + return new DataResponse([ + 'error' => 'binary', + ], Http::STATUS_BAD_REQUEST); + } + } catch (WrongPermissionsException $e) { return new DataResponse([ - 'error' => 'binary', + 'error' => 'binary_permissions', ], Http::STATUS_BAD_REQUEST); } diff --git a/lib/Exceptions/WrongPermissionsException.php b/lib/Exceptions/WrongPermissionsException.php new file mode 100644 index 000000000..8e04ad760 --- /dev/null +++ b/lib/Exceptions/WrongPermissionsException.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Julien Veyssier <eneiluj@posteo.net> + * + * @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 OCA\Talk\Exceptions; + +class WrongPermissionsException extends \Exception { +} diff --git a/lib/MatterbridgeManager.php b/lib/MatterbridgeManager.php index bab70dbdf..85c968103 100644 --- a/lib/MatterbridgeManager.php +++ b/lib/MatterbridgeManager.php @@ -40,6 +40,7 @@ use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use Psr\Log\LoggerInterface; use OCA\Talk\Exceptions\ImpossibleToKillException; +use OCA\Talk\Exceptions\WrongPermissionsException; use OCA\Talk\Exceptions\ParticipantNotFoundException; class MatterbridgeManager { @@ -642,6 +643,33 @@ class MatterbridgeManager { return null; } + // is www user the file owner? + $user = posix_getpwuid(posix_getuid()); + $fileOwner = posix_getpwuid(fileowner($binaryPath)); + $userIsOwner = $user['name'] === $fileOwner['name']; + + // get file group and user groups + $fileGid = filegroup($binaryPath); + $myGids = posix_getgroups(); + + // check permissions + $perms = fileperms($binaryPath); + $uExec = (($perms & 0x0040) && !($perms & 0x0800)); + $gExec = (($perms & 0x0008) && !($perms & 0x0400)); + $aExec = (($perms & 0x0001) && !($perms & 0x0200)); + + // 3 ways to have the permission : + // * be the owner and have u+x perm + // * not be the owner, be in the file group and have g+x perm + // * have o+x perm + $execPerm = $aExec + || ($user['name'] === $fileOwner['name'] && $uExec) + || ($user['name'] !== $fileOwner['name'] && in_array($fileGid, $myGids) && $gExec); + + if (!$execPerm) { + throw new WrongPermissionsException(); + } + $cmd = escapeshellcmd($binaryPath) . ' ' . escapeshellarg('-version'); @exec($cmd, $output, $returnCode); diff --git a/lib/Settings/Admin/AdminSettings.php b/lib/Settings/Admin/AdminSettings.php index ec47c257f..94b69e246 100644 --- a/lib/Settings/Admin/AdminSettings.php +++ b/lib/Settings/Admin/AdminSettings.php @@ -29,6 +29,7 @@ use OCA\Talk\Model\Command; use OCA\Talk\Participant; use OCA\Talk\Room; use OCA\Talk\Service\CommandService; +use OCA\Talk\Exceptions\WrongPermissionsException; use OCP\AppFramework\Http\TemplateResponse; use OCP\ICacheFactory; use OCP\IConfig; @@ -119,9 +120,21 @@ class AdminSettings implements ISettings { } protected function initMatterbridge(): void { + $error = ''; + try { + $version = (string) $this->bridgeManager->getCurrentVersionFromBinary(); + if ($version === '') { + $error = 'binary'; + } + } catch (WrongPermissionsException $e) { + $version = ''; + $error = 'binary_permissions'; + } + $this->initialStateService->provideInitialState( + 'talk', 'matterbridge_error', $error + ); $this->initialStateService->provideInitialState( - 'talk', 'matterbridge_version', - (string) $this->bridgeManager->getCurrentVersionFromBinary() + 'talk', 'matterbridge_version', $version ); $this->initialStateService->provideInitialState( diff --git a/src/components/AdminSettings/MatterbridgeIntegration.vue b/src/components/AdminSettings/MatterbridgeIntegration.vue index bbf1ce34b..f9d16d7bb 100644 --- a/src/components/AdminSettings/MatterbridgeIntegration.vue +++ b/src/components/AdminSettings/MatterbridgeIntegration.vue @@ -49,6 +49,10 @@ <template v-else> <p class="settings-hint" v-html="description" /> + <p v-if="errorText" class="settings-hint"> + {{ errorText }} + </p> + <p> <button v-if="isInstalling"> <span class="icon icon-loading-small" /> @@ -82,6 +86,7 @@ export default { matterbridgeEnabled: loadState('talk', 'matterbridge_enable'), matterbridgeVersion: loadState('talk', 'matterbridge_version'), isInstalling: false, + error: loadState('talk', 'matterbridge_error'), } }, @@ -97,6 +102,15 @@ export default { .replace('{linkstart2}', '<a target="_blank" rel="noreferrer nofollow" class="external" href="https://apps.nextcloud.com/apps/talk_matterbridge">') .replace(/{linkend}/g, ' ↗</a>') }, + errorText() { + if (this.error === 'binary_permissions') { + return t('spreed', 'Matterbridge binary has incorrect permissions. Please make sure the Matterbridge binary file is owned by the correct user and can be executed. It can be found in "/.../nextcloud/apps/talk_matterbridge/bin/".') + } else if (this.error === 'binary') { + return t('spreed', 'Matterbridge binary was not found or couldn\'t be executed.') + } else { + return '' + } + }, }, methods: { @@ -138,12 +152,17 @@ export default { this.matterbridgeVersion = response.data.ocs.data.version this.matterbridgeEnabled = true this.saveMatterbridgeEnabled() - - this.isInstalling = false + this.error = '' } catch (e) { console.error(e) showError(t('spreed', 'Failed to execute Matterbridge binary.')) + if (e.response && e.response.data && e.response.data.ocs && e.response.data.ocs.data && e.response.data.ocs.data.error) { + this.error = e.response.data.ocs.data.error + } else { + this.error = 'binary' + } } + this.isInstalling = false }, }, } |