guests/lib/AppWhitelist.php

160 строки
4.7 KiB
PHP

<?php
/**
* @author Ilja Neumann <ineumann@owncloud.com>
*
* @copyright Copyright (c) 2017, ownCloud GmbH
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
namespace OCA\Guests;
use OCP\App\IAppManager;
use OCP\IL10N;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\Template;
use Psr\Log\LoggerInterface;
/**
* Only allow whitelisted apps to be accessed by guests
*
* @package OCA\Guests
*/
class AppWhitelist {
private string $baseUrl;
private int $baseUrlLength;
public const WHITELIST_ALWAYS = ',core,theming,settings,avatar,files,heartbeat,dav,guests,impersonate,accessibility,terms_of_service,dashboard,weather_status,user_status,apporder';
public const DEFAULT_WHITELIST = 'files_trashbin,files_versions,files_sharing,files_texteditor,text,activity,firstrunwizard,photos,notifications,dashboard,user_status,weather_status';
/**
* AppWhitelist constructor.
*
* @param Config $config
* @param GuestManager $guestManager
* @param IL10N $l10n
* @param IAppManager $appManager
* @param IURLGenerator $urlGenerator
* @param LoggerInterface $logger
*/
public function __construct(
IURLGenerator $urlGenerator,
private Config $config,
private GuestManager $guestManager,
private IL10N $l10n,
private IAppManager $appManager,
private LoggerInterface $logger,
) {
$this->baseUrl = $urlGenerator->getBaseUrl();
$this->baseUrlLength = strlen($this->baseUrl);
}
public function isAppWhitelisted($appId): bool {
$whitelist = $this->config->getAppWhitelist();
$alwaysEnabled = explode(',', self::WHITELIST_ALWAYS);
return in_array($appId, array_merge($whitelist, $alwaysEnabled), true);
}
public function isWhitelistEnabled(): bool {
return $this->config->useWhitelist();
}
public function isUrlAllowed(IUser $user, $url): bool {
if ($this->guestManager->isGuest($user) && $this->isWhitelistEnabled()) {
$app = $this->getRequestedApp($url);
if ($this->isAppWhitelisted($app)) {
return true;
} else {
if ($url === '/apps/files_external/api/v1/mounts') {
// fake successful response
echo "[]";
exit;
}
$this->logger->notice("Blocking access to non-whitelisted app ($app) for guest", ['app' => 'guests']);
return false;
}
} else {
return true;
}
}
public function verifyAccess(IUser $user, IRequest $request): void {
if (!$this->isUrlAllowed($user, $request->getPathInfo())) {
header('HTTP/1.0 403 Forbidden');
Template::printErrorPage($this->l10n->t(
'Access to this resource is forbidden for guests.'
));
exit;
}
}
/**
* Core has \OC::$REQUESTEDAPP but it isn't set until the routes are matched
* taken from \OC\Route\Router::match()
*/
private function getRequestedApp($url): string {
if (substr($url, 0, $this->baseUrlLength) === $this->baseUrl) {
$url = substr($url, $this->baseUrlLength);
}
if (strpos($url, '/index.php/') === 0) {
$url = substr($url, 10);
}
if (substr($url, 0, 6) === '/apps/') {
// empty string / 'apps' / $app / rest of the route
[, , $app,] = explode('/', $url, 4);
return \OC_App::cleanAppId($app);
} elseif ($url === '/cron.php') {
return 'core';
} elseif (substr($url, 0, 6) === '/core/') {
return 'core';
} elseif (substr($url, 0, 4) === '/js/') {
return 'core';
} elseif (substr($url, 0, 5) === '/css/') {
return 'core';
} elseif (substr($url, 0, 6) === '/login') {
return 'core';
} elseif (substr($url, 0, 7) === '/logout') {
return 'core';
} elseif (substr($url, 0, 3) === '/f/') {
return 'files';
} elseif (substr($url, 0, 8) === '/webdav/') {
return 'dav';
} elseif (substr($url, 0, 5) === '/dav/') {
return 'dav';
} elseif (substr($url, 0, 6) === '/call/') {
return 'spreed';
} elseif (substr($url, 0, 10) === '/settings/') {
return 'settings';
} elseif (substr($url, 0, 8) === '/avatar/') {
return 'avatar';
} elseif (substr($url, 0, 10) === '/heartbeat') {
return 'heartbeat';
}
return 'core';
}
public function getWhitelistAbleApps(): array {
return array_values(array_diff(
$this->appManager->getInstalledApps(),
explode(',', self::WHITELIST_ALWAYS)
));
}
}