diff --git a/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php b/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php index 3ae6366fabe63..d276128958532 100644 --- a/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php +++ b/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php @@ -569,7 +569,10 @@ private function getFile(IUser $user, int $fileSource): array { $file = null; } $args = Filesystem::is_dir($file) ? ['dir' => $file] : ['dir' => dirname($file), 'scrollto' => $file]; - $link = Util::linkToAbsolute('files', 'index.php', $args); + $urlGenerator = Server::get(IURLGenerator::class); + $link = $urlGenerator->getAbsoluteURL( + $urlGenerator->linkTo('files', 'index.php', $args) + ); return [$file, $link]; } diff --git a/apps/settings/lib/Settings/Admin/Sharing.php b/apps/settings/lib/Settings/Admin/Sharing.php index ffc40790a0f12..d4ebf1fedd0d9 100644 --- a/apps/settings/lib/Settings/Admin/Sharing.php +++ b/apps/settings/lib/Settings/Admin/Sharing.php @@ -59,7 +59,7 @@ public function getForm() { 'restrictUserEnumerationFullMatchDisplayname' => $this->shareManager->matchDisplayName(), 'restrictUserEnumerationFullMatchEmail' => $this->shareManager->matchEmail(), 'restrictUserEnumerationFullMatchIgnoreSecondDN' => $this->shareManager->ignoreSecondDisplayName(), - 'enforceLinksPassword' => Util::isPublicLinkPasswordRequired(false), + 'enforceLinksPassword' => $this->shareManager->shareApiLinkEnforcePassword(false), 'enforceLinksPasswordExcludedGroups' => json_decode($excludedPasswordGroups) ?? [], 'enforceLinksPasswordExcludedGroupsEnabled' => $this->config->getSystemValueBool('sharing.allow_disabled_password_enforcement_groups', false), 'onlyShareWithGroupMembers' => $this->shareManager->shareWithGroupMembersOnly(), diff --git a/apps/updatenotification/lib/Controller/AdminController.php b/apps/updatenotification/lib/Controller/AdminController.php index 9b05b2974d33a..3402410536b41 100644 --- a/apps/updatenotification/lib/Controller/AdminController.php +++ b/apps/updatenotification/lib/Controller/AdminController.php @@ -20,7 +20,7 @@ use OCP\IL10N; use OCP\IRequest; use OCP\Security\ISecureRandom; -use OCP\Util; +use OCP\ServerVersion; use Psr\Log\LoggerInterface; class AdminController extends Controller { @@ -35,16 +35,16 @@ public function __construct( private ITimeFactory $timeFactory, private IL10N $l10n, private LoggerInterface $logger, + private ServerVersion $serverVersion, ) { parent::__construct($appName, $request); } /** - * @param string $channel - * @return DataResponse + * @param 'beta'|'stable'|'enterprise'|'git' $channel */ public function setChannel(string $channel): DataResponse { - Util::setChannel($channel); + $this->serverVersion->setChannel($channel); $this->appConfig->setValueInt('core', 'lastupdatedat', 0); return new DataResponse(['status' => 'success', 'data' => ['message' => $this->l10n->t('Channel updated')]]); } diff --git a/apps/updatenotification/tests/Controller/AdminControllerTest.php b/apps/updatenotification/tests/Controller/AdminControllerTest.php index 566d8cfa14637..a27b409490bbf 100644 --- a/apps/updatenotification/tests/Controller/AdminControllerTest.php +++ b/apps/updatenotification/tests/Controller/AdminControllerTest.php @@ -18,6 +18,7 @@ use OCP\IL10N; use OCP\IRequest; use OCP\Security\ISecureRandom; +use OCP\ServerVersion; use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; use Test\TestCase; @@ -56,6 +57,7 @@ protected function setUp(): void { $this->timeFactory, $this->l10n, $this->logger, + $this->createMock(ServerVersion::class), ); } diff --git a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php index 8731dab483538..c589d1f0dc547 100644 --- a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php @@ -18,6 +18,7 @@ use OC\AppFramework\Middleware\Security\Exceptions\NotLoggedInException; use OC\AppFramework\Middleware\Security\Exceptions\SecurityException; use OC\AppFramework\Middleware\Security\Exceptions\StrictCookieMissingException; +use OC\Security\CSRF\CsrfTokenManager; use OC\Settings\AuthorizedGroupMapper; use OC\User\Session; use OCA\Talk\Controller\PageController as TalkPageController; @@ -46,7 +47,7 @@ use OCP\IURLGenerator; use OCP\IUserSession; use OCP\Security\Ip\IRemoteAddress; -use OCP\Util; +use OCP\Server; use Psr\Log\LoggerInterface; use ReflectionMethod; @@ -195,7 +196,7 @@ public function beforeController($controller, $methodName) { } } // CSRF check - also registers the CSRF token since the session may be closed later - Util::callRegister(); + Server::get(CsrfTokenManager::class)->generateSessionToken(); if ($this->isInvalidCSRFRequired($reflectionMethod)) { /* * Only allow the CSRF check to fail on OCS Requests. This kind of diff --git a/lib/private/Security/CSRF/CsrfTokenManager.php b/lib/private/Security/CSRF/CsrfTokenManager.php index ab24de33a1de0..a9b3afcc40721 100644 --- a/lib/private/Security/CSRF/CsrfTokenManager.php +++ b/lib/private/Security/CSRF/CsrfTokenManager.php @@ -74,4 +74,8 @@ public function isTokenValid(CsrfToken $token): bool { $token->getDecryptedValue() ); } + + public function generateSessionToken(): void { + $this->getToken(); + } } diff --git a/lib/private/Template/Template.php b/lib/private/Template/Template.php index f7d14f9cbb5e8..5be76eac7d2a8 100644 --- a/lib/private/Template/Template.php +++ b/lib/private/Template/Template.php @@ -11,6 +11,7 @@ namespace OC\Template; use OC\Security\CSP\ContentSecurityPolicyNonceManager; +use OC\Security\CSRF\CsrfTokenManager; use OC\TemplateLayout; use OCP\App\AppPathNotFoundException; use OCP\App\IAppManager; @@ -40,7 +41,7 @@ public function __construct( ) { $theme = \OC_Util::getTheme(); - $requestToken = ($registerCall ? Util::callRegister() : ''); + $requestToken = ($registerCall ? Server::get(CsrfTokenManager::class)->getToken()->getEncryptedValue() : ''); $cspNonce = Server::get(ContentSecurityPolicyNonceManager::class)->getNonce(); // fix translation when app is something like core/lostpassword diff --git a/lib/private/URLGenerator.php b/lib/private/URLGenerator.php index 2c7070f1c2ded..e083886aae92c 100644 --- a/lib/private/URLGenerator.php +++ b/lib/private/URLGenerator.php @@ -19,6 +19,7 @@ use OCP\IURLGenerator; use OCP\IUserSession; use OCP\Server; +use Override; use RuntimeException; class URLGenerator implements IURLGenerator { @@ -326,4 +327,12 @@ public function getBaseUrl(): string { public function getWebroot(): string { return \OC::$WEBROOT; } + + #[Override] + public function linkToRemote(string $service): string { + $remoteBase = $this->linkTo('', 'remote.php') . '/' . $service; + return $this->getAbsoluteURL( + $remoteBase . (($service[strlen($service) - 1] !== '/') ? '/' : '') + ); + } } diff --git a/lib/private/legacy/OC_User.php b/lib/private/legacy/OC_User.php index ddd426da942e4..04f5960006224 100644 --- a/lib/private/legacy/OC_User.php +++ b/lib/private/legacy/OC_User.php @@ -6,6 +6,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ use OC\Authentication\Token\IProvider; +use OC\Security\CSRF\CsrfTokenManager; use OC\SystemConfig; use OC\User\Database; use OC\User\DisabledUserException; @@ -29,7 +30,6 @@ use OCP\User\Events\BeforeUserLoggedInEvent; use OCP\User\Events\UserLoggedInEvent; use OCP\UserInterface; -use OCP\Util; use Psr\Log\LoggerInterface; /** @@ -291,7 +291,7 @@ public static function getLogoutUrl(IURLGenerator $urlGenerator): string { } $logoutUrl = $urlGenerator->linkToRoute('core.login.logout'); - $logoutUrl .= '?requesttoken=' . urlencode(Util::callRegister()); + $logoutUrl .= '?requesttoken=' . urlencode(Server::get(CsrfTokenManager::class)->getToken()->getEncryptedValue()); return $logoutUrl; } diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index dafa0d4cc1345..b9c91a83aab36 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -525,44 +525,6 @@ public static function checkLoggedIn(): void { } } - /** - * Check if the user is a admin, redirects to home if not - * - * @deprecated 32.0.0 - */ - public static function checkAdminUser(): void { - self::checkLoggedIn(); - if (!OC_User::isAdminUser(OC_User::getUser())) { - header('Location: ' . Util::linkToAbsolute('', 'index.php')); - exit(); - } - } - - /** - * Returns the URL of the default page - * based on the system configuration and - * the apps visible for the current user - * - * @return string URL - * @deprecated 32.0.0 use IURLGenerator's linkToDefaultPageUrl directly - */ - public static function getDefaultPageUrl() { - /** @var IURLGenerator $urlGenerator */ - $urlGenerator = Server::get(IURLGenerator::class); - return $urlGenerator->linkToDefaultPageUrl(); - } - - /** - * Redirect to the user default page - * - * @deprecated 32.0.0 - */ - public static function redirectToDefaultPage(): void { - $location = self::getDefaultPageUrl(); - header('Location: ' . $location); - exit(); - } - /** * get an id unique for this instance * @@ -578,45 +540,6 @@ public static function getInstanceId(): string { return $id; } - /** - * Public function to sanitize HTML - * - * This function is used to sanitize HTML and should be applied on any - * string or array of strings before displaying it on a web page. - * - * @param string|string[] $value - * @return ($value is array ? string[] : string) - * @deprecated 32.0.0 use \OCP\Util::sanitizeHTML instead - */ - public static function sanitizeHTML($value) { - if (is_array($value)) { - $value = array_map(function ($value) { - return self::sanitizeHTML($value); - }, $value); - } else { - // Specify encoding for PHP<5.4 - $value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); - } - return $value; - } - - /** - * Public function to encode url parameters - * - * This function is used to encode path to file before output. - * Encoding is done according to RFC 3986 with one exception: - * Character '/' is preserved as is. - * - * @param string $component part of URI to encode - * @return string - * @deprecated 32.0.0 use \OCP\Util::encodePath instead - */ - public static function encodePath($component) { - $encoded = rawurlencode($component); - $encoded = str_replace('%2F', '/', $encoded); - return $encoded; - } - /** * Check if current locale is non-UTF8 * diff --git a/lib/public/IURLGenerator.php b/lib/public/IURLGenerator.php index a336d18b00fa9..e9a54f371f52b 100644 --- a/lib/public/IURLGenerator.php +++ b/lib/public/IURLGenerator.php @@ -8,10 +8,14 @@ */ namespace OCP; +use OCP\AppFramework\Attribute\Consumable; + /** * Class to generate URLs + * * @since 6.0.0 */ +#[Consumable(since: '6.0.0')] interface IURLGenerator { /** * Regex for matching http(s) urls @@ -115,4 +119,11 @@ public function getBaseUrl(): string; * @since 23.0.0 */ public function getWebroot(): string; + + /** + * Return the url to the remote DAV handler. + * + * @since 34.0.0 + */ + public function linkToRemote(string $service): string; } diff --git a/lib/public/ServerVersion.php b/lib/public/ServerVersion.php index e5df2515a86c3..90d008ccfbf40 100644 --- a/lib/public/ServerVersion.php +++ b/lib/public/ServerVersion.php @@ -91,6 +91,16 @@ public function getChannel(): string { return $this->channel; } + /** + * Set current update channel. + * + * @param 'beta'|'stable'|'enterprise'|'git' $channel + * @since 34.0.0 + */ + public function setChannel(string $channel): void { + Server::get(IConfig::class)->setSystemValue('updater.release.channel', $channel); + } + /** * @since 31.0.0 */ diff --git a/lib/public/Util.php b/lib/public/Util.php index a912a7baef67b..8731c628e92e9 100644 --- a/lib/public/Util.php +++ b/lib/public/Util.php @@ -48,16 +48,17 @@ public static function hasExtendedSupport(): bool { return $subscriptionRegistry->delegateHasExtendedSupport(); } catch (ContainerExceptionInterface $e) { } - return \OCP\Server::get(IConfig::class)->getSystemValueBool('extendedSupport', false); + return Server::get(IConfig::class)->getSystemValueBool('extendedSupport', false); } /** * Set current update channel * @param string $channel * @since 8.1.0 + * @deprecated 33.0.0 Use \OCP\ServerVersion::setChannel */ public static function setChannel($channel) { - \OCP\Server::get(IConfig::class)->setSystemValue('updater.release.channel', $channel); + Server::get(IConfig::class)->setSystemValue('updater.release.channel', $channel); } /** @@ -67,7 +68,7 @@ public static function setChannel($channel) { * @deprecated 31.0.0 Use \OCP\ServerVersion::getChannel */ public static function getChannel() { - return \OCP\Server::get(ServerVersion::class)->getChannel(); + return Server::get(ServerVersion::class)->getChannel(); } /** @@ -162,7 +163,7 @@ public static function addScript(string $application, ?string $file = null, stri */ public static function getScripts(): array { // Sort scriptDeps into sortedScriptDeps - $scriptSort = \OCP\Server::get(AppScriptSort::class); + $scriptSort = Server::get(AppScriptSort::class); $sortedScripts = $scriptSort->sort(self::$scripts, self::$scriptDeps); // Flatten array and remove duplicates @@ -200,7 +201,7 @@ private static function scriptOrderValue(string $name): int { */ public static function addTranslations($application, $languageCode = null, $init = false) { if (is_null($languageCode)) { - $languageCode = \OCP\Server::get(IFactory::class)->findLanguage($application); + $languageCode = Server::get(IFactory::class)->findLanguage($application); } if (!empty($application)) { $path = "$application/l10n/$languageCode"; @@ -236,9 +237,10 @@ public static function addHeader($tag, $attributes, $text = null) { * The value of $args will be urlencoded * @return string the url * @since 4.0.0 - parameter $args was added in 4.5.0 + * @deprecated 34.0.0 Use IUrlGenerator::getAbsoluteUrl and IUrlGenerator::linkTo */ public static function linkToAbsolute($app, $file, $args = []) { - $urlGenerator = \OCP\Server::get(IURLGenerator::class); + $urlGenerator = Server::get(IURLGenerator::class); return $urlGenerator->getAbsoluteURL( $urlGenerator->linkTo($app, $file, $args) ); @@ -246,16 +248,15 @@ public static function linkToAbsolute($app, $file, $args = []) { /** * Creates an absolute url for remote use. + * * @param string $service id * @return string the url * @since 4.0.0 + * @deprecated 34.0.0 Use IURlGenerator::linkToRemote */ - public static function linkToRemote($service) { - $urlGenerator = \OCP\Server::get(IURLGenerator::class); - $remoteBase = $urlGenerator->linkTo('', 'remote.php') . '/' . $service; - return $urlGenerator->getAbsoluteURL( - $remoteBase . (($service[strlen($service) - 1] !== '/') ? '/' : '') - ); + public static function linkToRemote(string $service): string { + $urlGenerator = Server::get(IURLGenerator::class); + return $urlGenerator->linkToRemote($service); } /** @@ -264,7 +265,7 @@ public static function linkToRemote($service) { * @since 5.0.0 */ public static function getServerHostName() { - $host_name = \OCP\Server::get(IRequest::class)->getServerHost(); + $host_name = Server::get(IRequest::class)->getServerHost(); // strip away port number (if existing) $colon_pos = strpos($host_name, ':'); if ($colon_pos !== false) { @@ -290,13 +291,13 @@ public static function getServerHostName() { * @since 5.0.0 */ public static function getDefaultEmailAddress(string $user_part): string { - $config = \OCP\Server::get(IConfig::class); + $config = Server::get(IConfig::class); $user_part = $config->getSystemValueString('mail_from_address', $user_part); $host_name = self::getServerHostName(); $host_name = $config->getSystemValueString('mail_domain', $host_name); $defaultEmailAddress = $user_part . '@' . $host_name; - $emailValidator = \OCP\Server::get(IEmailValidator::class); + $emailValidator = Server::get(IEmailValidator::class); if ($emailValidator->isValid($defaultEmailAddress)) { return $defaultEmailAddress; } @@ -429,7 +430,7 @@ public static function emitHook($signalclass, $signalname, $params = []) { * @deprecated 32.0.0 directly use CsrfTokenManager instead */ public static function callRegister() { - return \OCP\Server::get(CsrfTokenManager::class)->getToken()->getEncryptedValue(); + return Server::get(CsrfTokenManager::class)->getToken()->getEncryptedValue(); } /** @@ -438,12 +439,17 @@ public static function callRegister() { * This function is used to sanitize HTML and should be applied on any * string or array of strings before displaying it on a web page. * - * @param string|string[] $value + * @param string|string[]|null $value * @return ($value is array ? string[] : string) an array of sanitized strings or a single sanitized string, depends on the input parameter. * @since 4.5.0 */ - public static function sanitizeHTML($value) { - return \OC_Util::sanitizeHTML($value); + public static function sanitizeHTML(string|array|null $value): string|array { + if (is_array($value)) { + return array_map(function (string $value): string { + return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); + }, $value); + } + return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); } /** @@ -457,8 +463,9 @@ public static function sanitizeHTML($value) { * @return string * @since 6.0.0 */ - public static function encodePath($component) { - return \OC_Util::encodePath($component); + public static function encodePath(string $component): string { + $encoded = rawurlencode($component); + return str_replace('%2F', '/', $encoded); } /** @@ -547,15 +554,18 @@ public static function naturalSortCompare($a, $b) { * @param bool $checkGroupMembership Check group membership exclusion * @return boolean * @since 7.0.0 + * @deprecated 34.0.0 use OCP\Share\IManager's shareApiLinkEnforcePassword directly */ public static function isPublicLinkPasswordRequired(bool $checkGroupMembership = true) { return \OC_Util::isPublicLinkPasswordRequired($checkGroupMembership); } /** - * check if share API enforces a default expire date + * Check if share API enforces a default expire date + * * @return boolean * @since 8.0.0 + * @deprecated 34.0.0 use OCP\Share\IManager's shareApiLinkDefaultExpireDateEnforced directly */ public static function isDefaultExpireDateEnforced() { return \OC_Util::isDefaultExpireDateEnforced(); @@ -571,7 +581,7 @@ public static function isDefaultExpireDateEnforced() { */ public static function needUpgrade() { if (!isset(self::$needUpgradeCache)) { - self::$needUpgradeCache = \OC_Util::needUpgrade(\OCP\Server::get(\OC\SystemConfig::class)); + self::$needUpgradeCache = \OC_Util::needUpgrade(Server::get(\OC\SystemConfig::class)); } return self::$needUpgradeCache; } diff --git a/tests/lib/NavigationManagerTest.php b/tests/lib/NavigationManagerTest.php index 46d593db11881..4322791e29ea3 100644 --- a/tests/lib/NavigationManagerTest.php +++ b/tests/lib/NavigationManagerTest.php @@ -11,6 +11,7 @@ use OC\App\AppManager; use OC\Group\Manager; use OC\NavigationManager; +use OC\Security\CSRF\CsrfTokenManager; use OC\SubAdmin; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; @@ -21,7 +22,7 @@ use OCP\IUserSession; use OCP\L10N\IFactory; use OCP\Navigation\Events\LoadAdditionalEntriesEvent; -use OCP\Util; +use OCP\Server; use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; @@ -324,7 +325,7 @@ public static function providesNavigationConfig(): array { 'logout' => [ 'id' => 'logout', 'order' => 99999, - 'href' => 'https://example.com/logout?requesttoken=' . urlencode(Util::callRegister()), + 'href' => 'https://example.com/logout?requesttoken=' . urlencode(Server::get(CsrfTokenManager::class)->getToken()->getEncryptedValue()), 'icon' => '/apps/core/img/actions/logout.svg', 'name' => 'Log out', 'active' => false, diff --git a/tests/lib/UtilTest.php b/tests/lib/UtilTest.php index 1e493eb2a76b8..182796ea720fc 100644 --- a/tests/lib/UtilTest.php +++ b/tests/lib/UtilTest.php @@ -36,17 +36,11 @@ public function testSanitizeHTML(): void { 'While it is unusual to pass an array', 'this function actually supports it.', 'And therefore there needs to be a for it!', - [ - 'And It Even May Nest', - ], ]; $goodArray = [ 'While it is unusual to pass an array', 'this function actually <blink>supports</blink> it.', 'And therefore there needs to be a <script>alert("Unit"+'test')</script> for it!', - [ - 'And It Even May <strong>Nest</strong>' - ], ]; $result = Util::sanitizeHTML($badArray); $this->assertEquals($goodArray, $result);