Merge pull request #58806 from nextcloud/carl/utils-cleanup

Multiple cleanups in OCP/Utils and OC_Utils
This commit is contained in:
Carl Schwan 2026-05-12 20:03:55 +02:00 committed by GitHub
commit 38d8eb5410
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 88 additions and 119 deletions

View file

@ -569,7 +569,10 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
$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];
}

View file

@ -59,7 +59,7 @@ class Sharing implements IDelegatedSettings {
'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(),

View file

@ -20,7 +20,7 @@ use OCP\IConfig;
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 @@ class AdminController extends Controller {
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')]]);
}

View file

@ -18,6 +18,7 @@ use OCP\IConfig;
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 @@ class AdminControllerTest extends TestCase {
$this->timeFactory,
$this->l10n,
$this->logger,
$this->createMock(ServerVersion::class),
);
}

View file

@ -18,6 +18,7 @@ use OC\AppFramework\Middleware\Security\Exceptions\NotConfirmedException;
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\IRequest;
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 @@ class SecurityMiddleware extends Middleware {
}
}
// 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

View file

@ -74,4 +74,8 @@ class CsrfTokenManager {
$token->getDecryptedValue()
);
}
public function generateSessionToken(): void {
$this->getToken();
}
}

View file

@ -11,6 +11,7 @@ declare(strict_types=1);
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 @@ class Template extends Base implements ITemplate {
) {
$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

View file

@ -19,6 +19,7 @@ use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUserSession;
use OCP\Server;
use Override;
use RuntimeException;
class URLGenerator implements IURLGenerator {
@ -326,4 +327,12 @@ class URLGenerator implements IURLGenerator {
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] !== '/') ? '/' : '')
);
}
}

View file

@ -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\Backend\ICustomLogout;
use OCP\User\Events\BeforeUserLoggedInEvent;
use OCP\User\Events\UserLoggedInEvent;
use OCP\UserInterface;
use OCP\Util;
use Psr\Log\LoggerInterface;
/**
@ -291,7 +291,7 @@ class OC_User {
}
$logoutUrl = $urlGenerator->linkToRoute('core.login.logout');
$logoutUrl .= '?requesttoken=' . urlencode(Util::callRegister());
$logoutUrl .= '?requesttoken=' . urlencode(Server::get(CsrfTokenManager::class)->getToken()->getEncryptedValue());
return $logoutUrl;
}

View file

@ -525,44 +525,6 @@ class OC_Util {
}
}
/**
* 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 @@ class OC_Util {
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
*

View file

@ -8,10 +8,14 @@ declare(strict_types=1);
*/
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 @@ interface IURLGenerator {
* @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;
}

View file

@ -91,6 +91,16 @@ readonly class ServerVersion {
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
*/

View file

@ -48,16 +48,17 @@ class Util {
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 @@ class Util {
* @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 @@ class Util {
*/
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 @@ class Util {
*/
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 @@ class Util {
* 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 @@ class Util {
/**
* 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 @@ class Util {
* @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 @@ class Util {
* @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 @@ class Util {
* @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 @@ class Util {
* 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 @@ class Util {
* @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 @@ class Util {
* @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 @@ class Util {
*/
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;
}

View file

@ -11,6 +11,7 @@ namespace Test;
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\IUser;
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 @@ class NavigationManagerTest extends TestCase {
'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,

View file

@ -36,17 +36,11 @@ class UtilTest extends \Test\TestCase {
'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>',
],
];
$goodArray = [
'While it is unusual to pass an array',
'this function actually &lt;blink&gt;supports&lt;/blink&gt; it.',
'And therefore there needs to be a &lt;script&gt;alert(&quot;Unit&quot;+&#039;test&#039;)&lt;/script&gt; for it!',
[
'And It Even May &lt;strong&gt;Nest&lt;/strong&gt;'
],
];
$result = Util::sanitizeHTML($badArray);
$this->assertEquals($goodArray, $result);