diff options
Diffstat (limited to 'lib')
49 files changed, 313 insertions, 101 deletions
diff --git a/lib/base.php b/lib/base.php index 0ed282eff00..aa463e206a3 100644 --- a/lib/base.php +++ b/lib/base.php @@ -7,6 +7,7 @@ declare(strict_types=1); * SPDX-License-Identifier: AGPL-3.0-only */ use OC\Encryption\HookManager; +use OC\Profiler\BuiltInProfiler; use OC\Share20\GroupDeletedListener; use OC\Share20\Hooks; use OC\Share20\UserDeletedListener; @@ -14,6 +15,7 @@ use OC\Share20\UserRemovedListener; use OCP\EventDispatcher\IEventDispatcher; use OCP\Group\Events\GroupDeletedEvent; use OCP\Group\Events\UserRemovedEvent; +use OCP\IConfig; use OCP\ILogger; use OCP\IRequest; use OCP\IURLGenerator; @@ -126,7 +128,6 @@ class OC { } } - if (OC::$CLI) { OC::$WEBROOT = self::$config->getValue('overwritewebroot', ''); } else { @@ -522,7 +523,7 @@ class OC { * We use an additional cookie since we want to protect logout CSRF and * also we can't directly interfere with PHP's session mechanism. */ - private static function performSameSiteCookieProtection(\OCP\IConfig $config): void { + private static function performSameSiteCookieProtection(IConfig $config): void { $request = Server::get(IRequest::class); // Some user agents are notorious and don't really properly follow HTTP @@ -635,6 +636,16 @@ class OC { self::$server = new \OC\Server(\OC::$WEBROOT, self::$config); self::$server->boot(); + try { + $profiler = new BuiltInProfiler( + Server::get(IConfig::class), + Server::get(IRequest::class), + ); + $profiler->start(); + } catch (\Throwable $e) { + logger('core')->error('Failed to start profiler: ' . $e->getMessage(), ['app' => 'base']); + } + if (self::$CLI && in_array('--' . \OCP\Console\ReservedOptions::DEBUG_LOG, $_SERVER['argv'])) { \OC\Core\Listener\BeforeMessageLoggedEventListener::setup(); } @@ -654,7 +665,7 @@ class OC { // initialize intl fallback if necessary OC_Util::isSetLocaleWorking(); - $config = Server::get(\OCP\IConfig::class); + $config = Server::get(IConfig::class); if (!defined('PHPUNIT_RUN')) { $errorHandler = new OC\Log\ErrorHandler( \OCP\Server::get(\Psr\Log\LoggerInterface::class), diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 670a719c9fb..1f3d9d3813b 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -1852,6 +1852,7 @@ return array( 'OC\\Profile\\Actions\\WebsiteAction' => $baseDir . '/lib/private/Profile/Actions/WebsiteAction.php', 'OC\\Profile\\ProfileManager' => $baseDir . '/lib/private/Profile/ProfileManager.php', 'OC\\Profile\\TProfileHelper' => $baseDir . '/lib/private/Profile/TProfileHelper.php', + 'OC\\Profiler\\BuiltInProfiler' => $baseDir . '/lib/private/Profiler/BuiltInProfiler.php', 'OC\\Profiler\\FileProfilerStorage' => $baseDir . '/lib/private/Profiler/FileProfilerStorage.php', 'OC\\Profiler\\Profile' => $baseDir . '/lib/private/Profiler/Profile.php', 'OC\\Profiler\\Profiler' => $baseDir . '/lib/private/Profiler/Profiler.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index c15d9d5b53c..8c87d90156d 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -1893,6 +1893,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Profile\\Actions\\WebsiteAction' => __DIR__ . '/../../..' . '/lib/private/Profile/Actions/WebsiteAction.php', 'OC\\Profile\\ProfileManager' => __DIR__ . '/../../..' . '/lib/private/Profile/ProfileManager.php', 'OC\\Profile\\TProfileHelper' => __DIR__ . '/../../..' . '/lib/private/Profile/TProfileHelper.php', + 'OC\\Profiler\\BuiltInProfiler' => __DIR__ . '/../../..' . '/lib/private/Profiler/BuiltInProfiler.php', 'OC\\Profiler\\FileProfilerStorage' => __DIR__ . '/../../..' . '/lib/private/Profiler/FileProfilerStorage.php', 'OC\\Profiler\\Profile' => __DIR__ . '/../../..' . '/lib/private/Profiler/Profile.php', 'OC\\Profiler\\Profiler' => __DIR__ . '/../../..' . '/lib/private/Profiler/Profiler.php', diff --git a/lib/l10n/cs.js b/lib/l10n/cs.js index 34ca14240eb..06f4631fa3c 100644 --- a/lib/l10n/cs.js +++ b/lib/l10n/cs.js @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "Je třeba zadat platné přihlašovací jméno", "Login contains whitespace at the beginning or at the end" : "Přihlašovací jméno je chybné – na jeho začátku či konci se nachází prázdný znak (mezera, tabulátor, atp.)", "Login must not consist of dots only" : "Přihlašovací jméno se nemůže skládat pouze ze samých teček", + "Login is too long" : "Přihlašovací jméno je příliš dlouhé", "Login is invalid because files already exist for this user" : "Přihlašovací jméno není platné, protože protože pro tohoto uživatele už existují soubory", "Account disabled" : "Účet znepřístupněn", "Login canceled by app" : "Přihlášení zrušeno aplikací", diff --git a/lib/l10n/cs.json b/lib/l10n/cs.json index df05f9e91f9..0fd7ca64748 100644 --- a/lib/l10n/cs.json +++ b/lib/l10n/cs.json @@ -271,6 +271,7 @@ "A valid Login must be provided" : "Je třeba zadat platné přihlašovací jméno", "Login contains whitespace at the beginning or at the end" : "Přihlašovací jméno je chybné – na jeho začátku či konci se nachází prázdný znak (mezera, tabulátor, atp.)", "Login must not consist of dots only" : "Přihlašovací jméno se nemůže skládat pouze ze samých teček", + "Login is too long" : "Přihlašovací jméno je příliš dlouhé", "Login is invalid because files already exist for this user" : "Přihlašovací jméno není platné, protože protože pro tohoto uživatele už existují soubory", "Account disabled" : "Účet znepřístupněn", "Login canceled by app" : "Přihlášení zrušeno aplikací", diff --git a/lib/l10n/da.js b/lib/l10n/da.js index 6cd7bef6a20..05e77f8d59e 100644 --- a/lib/l10n/da.js +++ b/lib/l10n/da.js @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "Et gyldigt login skal angives", "Login contains whitespace at the beginning or at the end" : "Login indeholder mellemrum i begyndelsen eller slutningen", "Login must not consist of dots only" : "Login må ikke kun bestå af prikker", + "Login is too long" : "Login er for lang", "Login is invalid because files already exist for this user" : "Login er ugyldigt, fordi filer allerede eksisterer for denne bruger", "Account disabled" : "Konto deaktiveret", "Login canceled by app" : "Login annulleret af app", diff --git a/lib/l10n/da.json b/lib/l10n/da.json index 7a290e23567..107ff24a9fb 100644 --- a/lib/l10n/da.json +++ b/lib/l10n/da.json @@ -271,6 +271,7 @@ "A valid Login must be provided" : "Et gyldigt login skal angives", "Login contains whitespace at the beginning or at the end" : "Login indeholder mellemrum i begyndelsen eller slutningen", "Login must not consist of dots only" : "Login må ikke kun bestå af prikker", + "Login is too long" : "Login er for lang", "Login is invalid because files already exist for this user" : "Login er ugyldigt, fordi filer allerede eksisterer for denne bruger", "Account disabled" : "Konto deaktiveret", "Login canceled by app" : "Login annulleret af app", diff --git a/lib/l10n/de.js b/lib/l10n/de.js index 80ee4b12c26..565432632e8 100644 --- a/lib/l10n/de.js +++ b/lib/l10n/de.js @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "Ein gültiger Anmeldename muss eingegeben werden.", "Login contains whitespace at the beginning or at the end" : "Anmeldename enthält Leerzeichen am Anfang oder am Ende", "Login must not consist of dots only" : "Der Anmeldename darf nicht nur aus Punkten bestehen", + "Login is too long" : "Die Anmeldung dauert zu lange", "Login is invalid because files already exist for this user" : "Der Anmeldename ist ungültig, da bereits Dateien von diesem Konto existieren", "Account disabled" : "Konto deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", diff --git a/lib/l10n/de.json b/lib/l10n/de.json index 1377f4020cd..f9b01867ab0 100644 --- a/lib/l10n/de.json +++ b/lib/l10n/de.json @@ -271,6 +271,7 @@ "A valid Login must be provided" : "Ein gültiger Anmeldename muss eingegeben werden.", "Login contains whitespace at the beginning or at the end" : "Anmeldename enthält Leerzeichen am Anfang oder am Ende", "Login must not consist of dots only" : "Der Anmeldename darf nicht nur aus Punkten bestehen", + "Login is too long" : "Die Anmeldung dauert zu lange", "Login is invalid because files already exist for this user" : "Der Anmeldename ist ungültig, da bereits Dateien von diesem Konto existieren", "Account disabled" : "Konto deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", diff --git a/lib/l10n/de_DE.js b/lib/l10n/de_DE.js index 9b074d7053c..d43d052a549 100644 --- a/lib/l10n/de_DE.js +++ b/lib/l10n/de_DE.js @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "Ein gültiger Anmeldename muss angegeben werden.", "Login contains whitespace at the beginning or at the end" : "Anmeldename enthält Leerzeichen am Anfang oder am Ende", "Login must not consist of dots only" : "Der Anmeldename darf nicht nur aus Punkten bestehen", + "Login is too long" : "Die Anmeldung dauert zu lange", "Login is invalid because files already exist for this user" : "Der Anmeldename ist ungültig, da bereits Dateien von diesem Benutzer existieren", "Account disabled" : "Konto deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", diff --git a/lib/l10n/de_DE.json b/lib/l10n/de_DE.json index 4317c73a212..9e974ad5fac 100644 --- a/lib/l10n/de_DE.json +++ b/lib/l10n/de_DE.json @@ -271,6 +271,7 @@ "A valid Login must be provided" : "Ein gültiger Anmeldename muss angegeben werden.", "Login contains whitespace at the beginning or at the end" : "Anmeldename enthält Leerzeichen am Anfang oder am Ende", "Login must not consist of dots only" : "Der Anmeldename darf nicht nur aus Punkten bestehen", + "Login is too long" : "Die Anmeldung dauert zu lange", "Login is invalid because files already exist for this user" : "Der Anmeldename ist ungültig, da bereits Dateien von diesem Benutzer existieren", "Account disabled" : "Konto deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", diff --git a/lib/l10n/es.js b/lib/l10n/es.js index 4d7b8700c51..94e52dbc724 100644 --- a/lib/l10n/es.js +++ b/lib/l10n/es.js @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "Se debe proporcionar un usuario válido", "Login contains whitespace at the beginning or at the end" : "El usuario contiene espacios en blanco al inicio o al final", "Login must not consist of dots only" : "El usuario no debe consistir sólo de puntos", + "Login is too long" : "El nombre de inicio de sesión es demasiado largo", "Login is invalid because files already exist for this user" : "El nombre de inicio de sesión es inválido porque ya existen archivos para este usuario", "Account disabled" : "Cuenta deshabilitada", "Login canceled by app" : "Login cancelado por la app", diff --git a/lib/l10n/es.json b/lib/l10n/es.json index 3d9f223880a..61f519db2a7 100644 --- a/lib/l10n/es.json +++ b/lib/l10n/es.json @@ -271,6 +271,7 @@ "A valid Login must be provided" : "Se debe proporcionar un usuario válido", "Login contains whitespace at the beginning or at the end" : "El usuario contiene espacios en blanco al inicio o al final", "Login must not consist of dots only" : "El usuario no debe consistir sólo de puntos", + "Login is too long" : "El nombre de inicio de sesión es demasiado largo", "Login is invalid because files already exist for this user" : "El nombre de inicio de sesión es inválido porque ya existen archivos para este usuario", "Account disabled" : "Cuenta deshabilitada", "Login canceled by app" : "Login cancelado por la app", diff --git a/lib/l10n/et_EE.js b/lib/l10n/et_EE.js index c75e79941dd..7a32b1cec33 100644 --- a/lib/l10n/et_EE.js +++ b/lib/l10n/et_EE.js @@ -153,10 +153,19 @@ OC.L10N.register( "%1$s shared %2$s with you and wants to add:" : "%1$s jagas sinuga %2$s ning soovib lisada:", "%1$s shared %2$s with you and wants to add" : "%1$s jagas sinuga %2$s ning soovib lisada", "%s added a note to a file shared with you" : "%s jagas koos sulle jagatud failiga ka märget", + "Share recipient is not a valid user" : "Jaosmeedia vastuvõtja pole korrektne kasutaja", + "Share recipient is not a valid group" : "Jaosmeedia vastuvõtja pole korrektne grupp", + "Share recipient should be empty" : "Jaosmeedia vastuvõtja peaks jääma tühjaks", + "Share recipient should not be empty" : "Jaosmeedia vastuvõtja ei tohi jääda tühjaks", + "Share recipient is not a valid circle" : "Jaosmeedia vastuvõtja pole korrektne tiim", "Unknown share type" : "Tundmatu jagamise tüüp", + "Share initiator must be set" : "Jagamise alustaja peab olema määratud", "Cannot share with yourself" : "Sa ei saa iseendale jagada", + "Shared path must be set" : "Jagamise asukoht peab olema teada", + "Shared path must be either a file or a folder" : "Jagamise asukoht peab olema kas kaust või fail", "You cannot share your root folder" : "Sa ei saa juurkausta jagada", "You are not allowed to share %s" : "Sul pole lubatud %s jagada", + "Valid permissions are required for sharing" : "Jagamiseks peavad olema korrektsed õigused", "File shares cannot have create or delete permissions" : "Jaosfailidel ei saa olla loomis- või kustutamisõigusi", "Cannot increase permissions of %s" : "Ei saa %s õigusi suurendada", "Shares need at least read permissions" : "Jaosmeedial peab olema vähemalt lugemisõigus", @@ -175,6 +184,7 @@ OC.L10N.register( "Sharing is disabled for you" : "Jagamine pole sinu jaoks kasutusel", "Cannot share with the share owner" : "Sa ei saa jagada jaosmeedia omanikule", "Cannot change share type" : "Sa ei saa muuta jaosmeedia tüüpi", + "Invalid share recipient" : "Vigane jaosmeedia vastuvõtja", "Group \"%s\" does not exist" : "„%s“ gruppi pole olemas", "The requested share does not exist anymore" : "Soovitud jagamist enam ei eksisteeri", "Could not find category \"%s\"" : "Ei leia kategooriat \"%s\"", @@ -228,6 +238,7 @@ OC.L10N.register( "A valid password must be provided" : "Sisesta nõuetele vastav parool", "The Login is already being used" : "See kasutajanimi on juba kasutusel", "Could not create account" : "Kasutajakonto loomine ei õnnestunud", + "Login is too long" : "Kasutajanimi on liiga pikk", "Login canceled by app" : "Rakendus katkestas sisselogimise", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "„%1$s“ rakendust ei saa paigaldada, sest järgnev sõltuvus on puudu: %2$s", "a safe home for all your data" : "turvaline koht sinu andmetele", diff --git a/lib/l10n/et_EE.json b/lib/l10n/et_EE.json index f6f1fcfa660..e8db1891012 100644 --- a/lib/l10n/et_EE.json +++ b/lib/l10n/et_EE.json @@ -151,10 +151,19 @@ "%1$s shared %2$s with you and wants to add:" : "%1$s jagas sinuga %2$s ning soovib lisada:", "%1$s shared %2$s with you and wants to add" : "%1$s jagas sinuga %2$s ning soovib lisada", "%s added a note to a file shared with you" : "%s jagas koos sulle jagatud failiga ka märget", + "Share recipient is not a valid user" : "Jaosmeedia vastuvõtja pole korrektne kasutaja", + "Share recipient is not a valid group" : "Jaosmeedia vastuvõtja pole korrektne grupp", + "Share recipient should be empty" : "Jaosmeedia vastuvõtja peaks jääma tühjaks", + "Share recipient should not be empty" : "Jaosmeedia vastuvõtja ei tohi jääda tühjaks", + "Share recipient is not a valid circle" : "Jaosmeedia vastuvõtja pole korrektne tiim", "Unknown share type" : "Tundmatu jagamise tüüp", + "Share initiator must be set" : "Jagamise alustaja peab olema määratud", "Cannot share with yourself" : "Sa ei saa iseendale jagada", + "Shared path must be set" : "Jagamise asukoht peab olema teada", + "Shared path must be either a file or a folder" : "Jagamise asukoht peab olema kas kaust või fail", "You cannot share your root folder" : "Sa ei saa juurkausta jagada", "You are not allowed to share %s" : "Sul pole lubatud %s jagada", + "Valid permissions are required for sharing" : "Jagamiseks peavad olema korrektsed õigused", "File shares cannot have create or delete permissions" : "Jaosfailidel ei saa olla loomis- või kustutamisõigusi", "Cannot increase permissions of %s" : "Ei saa %s õigusi suurendada", "Shares need at least read permissions" : "Jaosmeedial peab olema vähemalt lugemisõigus", @@ -173,6 +182,7 @@ "Sharing is disabled for you" : "Jagamine pole sinu jaoks kasutusel", "Cannot share with the share owner" : "Sa ei saa jagada jaosmeedia omanikule", "Cannot change share type" : "Sa ei saa muuta jaosmeedia tüüpi", + "Invalid share recipient" : "Vigane jaosmeedia vastuvõtja", "Group \"%s\" does not exist" : "„%s“ gruppi pole olemas", "The requested share does not exist anymore" : "Soovitud jagamist enam ei eksisteeri", "Could not find category \"%s\"" : "Ei leia kategooriat \"%s\"", @@ -226,6 +236,7 @@ "A valid password must be provided" : "Sisesta nõuetele vastav parool", "The Login is already being used" : "See kasutajanimi on juba kasutusel", "Could not create account" : "Kasutajakonto loomine ei õnnestunud", + "Login is too long" : "Kasutajanimi on liiga pikk", "Login canceled by app" : "Rakendus katkestas sisselogimise", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "„%1$s“ rakendust ei saa paigaldada, sest järgnev sõltuvus on puudu: %2$s", "a safe home for all your data" : "turvaline koht sinu andmetele", diff --git a/lib/l10n/ga.js b/lib/l10n/ga.js index 0adb89eb57b..4c1832afec9 100644 --- a/lib/l10n/ga.js +++ b/lib/l10n/ga.js @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "Ní mór Logáil Isteach bailí a sholáthar", "Login contains whitespace at the beginning or at the end" : "Tá spás bán sa logáil isteach ag an tús nó ag an deireadh", "Login must not consist of dots only" : "Níor cheart go gcuimseodh logáil isteach poncanna amháin", + "Login is too long" : "Tá logáil isteach ró-fhada", "Login is invalid because files already exist for this user" : "Tá logáil isteach neamhbhailí toisc go bhfuil comhaid ann cheana don úsáideoir seo", "Account disabled" : "Díchumasaíodh an cuntas", "Login canceled by app" : "Cealaíodh logáil isteach ag an aip", diff --git a/lib/l10n/ga.json b/lib/l10n/ga.json index 80b707a55d3..9c680309924 100644 --- a/lib/l10n/ga.json +++ b/lib/l10n/ga.json @@ -271,6 +271,7 @@ "A valid Login must be provided" : "Ní mór Logáil Isteach bailí a sholáthar", "Login contains whitespace at the beginning or at the end" : "Tá spás bán sa logáil isteach ag an tús nó ag an deireadh", "Login must not consist of dots only" : "Níor cheart go gcuimseodh logáil isteach poncanna amháin", + "Login is too long" : "Tá logáil isteach ró-fhada", "Login is invalid because files already exist for this user" : "Tá logáil isteach neamhbhailí toisc go bhfuil comhaid ann cheana don úsáideoir seo", "Account disabled" : "Díchumasaíodh an cuntas", "Login canceled by app" : "Cealaíodh logáil isteach ag an aip", diff --git a/lib/l10n/ja.js b/lib/l10n/ja.js index e3f2e7ea7cd..c3c82dc9b17 100644 --- a/lib/l10n/ja.js +++ b/lib/l10n/ja.js @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "ログイン名を提供する必要があります", "Login contains whitespace at the beginning or at the end" : "ログイン名の最初か最後に空白が含まれています", "Login must not consist of dots only" : "ログイン名はドットのみで構成されてはいけません", + "Login is too long" : "ログインが長すぎます", "Login is invalid because files already exist for this user" : "このユーザのファイルが既に存在するため、このログイン名は使用できません", "Account disabled" : "アカウントは無効", "Login canceled by app" : "アプリによりログインが中止されました", diff --git a/lib/l10n/ja.json b/lib/l10n/ja.json index 5419c0da23d..cd55a7d7703 100644 --- a/lib/l10n/ja.json +++ b/lib/l10n/ja.json @@ -271,6 +271,7 @@ "A valid Login must be provided" : "ログイン名を提供する必要があります", "Login contains whitespace at the beginning or at the end" : "ログイン名の最初か最後に空白が含まれています", "Login must not consist of dots only" : "ログイン名はドットのみで構成されてはいけません", + "Login is too long" : "ログインが長すぎます", "Login is invalid because files already exist for this user" : "このユーザのファイルが既に存在するため、このログイン名は使用できません", "Account disabled" : "アカウントは無効", "Login canceled by app" : "アプリによりログインが中止されました", diff --git a/lib/l10n/lv.js b/lib/l10n/lv.js index 4144a89751c..a201c8c6081 100644 --- a/lib/l10n/lv.js +++ b/lib/l10n/lv.js @@ -20,6 +20,7 @@ OC.L10N.register( "%sbit or higher PHP required." : "Nepieciešams %sbit vai jaunāks PHP.", "The command line tool %s could not be found" : "Komandrindas rīku %s nevarēja atrast", "The library %s is not available." : "Bibliotēka %s nav pieejama.", + "The following platforms are supported: %s" : "Tiek atbalstītas šīs platformas: %s", "Server version %s or higher is required." : "Ir nepieciešama servera versija %s vai jaunāka.", "Server version %s or lower is required." : "Ir nepieciešama servera versija %s vai vecāka.", "Authentication" : "Autentifikācija", diff --git a/lib/l10n/lv.json b/lib/l10n/lv.json index ce7a6fcf83d..6ae08bbf873 100644 --- a/lib/l10n/lv.json +++ b/lib/l10n/lv.json @@ -18,6 +18,7 @@ "%sbit or higher PHP required." : "Nepieciešams %sbit vai jaunāks PHP.", "The command line tool %s could not be found" : "Komandrindas rīku %s nevarēja atrast", "The library %s is not available." : "Bibliotēka %s nav pieejama.", + "The following platforms are supported: %s" : "Tiek atbalstītas šīs platformas: %s", "Server version %s or higher is required." : "Ir nepieciešama servera versija %s vai jaunāka.", "Server version %s or lower is required." : "Ir nepieciešama servera versija %s vai vecāka.", "Authentication" : "Autentifikācija", diff --git a/lib/l10n/pt_BR.js b/lib/l10n/pt_BR.js index fb3b36789cf..8e242ad9340 100644 --- a/lib/l10n/pt_BR.js +++ b/lib/l10n/pt_BR.js @@ -73,15 +73,15 @@ OC.L10N.register( "next month" : "Mês que vem", "last month" : "último mês", "_in %n month_::_in %n months_" : ["em %n mês","em %n meses","em %n meses"], - "_%n month ago_::_%n months ago_" : ["há %n mês atrás","há %n meses","há %n meses"], + "_%n month ago_::_%n months ago_" : ["%n mês atrás","%n meses atrás","%n meses atrás"], "next year" : "próximo ano", "last year" : "último ano", "_in %n year_::_in %n years_" : ["em %n ano","em %n anos","em %n anos"], "_%n year ago_::_%n years ago_" : ["%n ano atrás","%n anos atrás","%n anos atrás"], "_in %n hour_::_in %n hours_" : ["em %n hora","em %n horas","em %n horas"], - "_%n hour ago_::_%n hours ago_" : ["há %n hora atrás","há %n horas","há %n horas"], + "_%n hour ago_::_%n hours ago_" : ["%n hora atrás","%n horas atrás","%n horas atrás"], "_in %n minute_::_in %n minutes_" : ["em %n minuto","em %n minutos","em %n minutos"], - "_%n minute ago_::_%n minutes ago_" : ["há %n minuto atrás","há %n minutos","há %n minutos"], + "_%n minute ago_::_%n minutes ago_" : ["%n minuto atrás","%n minutos atrás","%n minutos atrás"], "in a few seconds" : "Em alguns segundos", "seconds ago" : "segundos atrás", "Empty file" : "Arquivo vazio", @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "Um Login válido deve ser fornecido", "Login contains whitespace at the beginning or at the end" : "O login contém espaços em branco no início ou no final", "Login must not consist of dots only" : "O login não deve consistir apenas de pontos", + "Login is too long" : "O login é muito longo", "Login is invalid because files already exist for this user" : "O login é inválido porque já existem arquivos para este usuário", "Account disabled" : "Conta desativada", "Login canceled by app" : "Login cancelado pelo aplicativo", diff --git a/lib/l10n/pt_BR.json b/lib/l10n/pt_BR.json index f9be2dc1d1a..6353e34b450 100644 --- a/lib/l10n/pt_BR.json +++ b/lib/l10n/pt_BR.json @@ -71,15 +71,15 @@ "next month" : "Mês que vem", "last month" : "último mês", "_in %n month_::_in %n months_" : ["em %n mês","em %n meses","em %n meses"], - "_%n month ago_::_%n months ago_" : ["há %n mês atrás","há %n meses","há %n meses"], + "_%n month ago_::_%n months ago_" : ["%n mês atrás","%n meses atrás","%n meses atrás"], "next year" : "próximo ano", "last year" : "último ano", "_in %n year_::_in %n years_" : ["em %n ano","em %n anos","em %n anos"], "_%n year ago_::_%n years ago_" : ["%n ano atrás","%n anos atrás","%n anos atrás"], "_in %n hour_::_in %n hours_" : ["em %n hora","em %n horas","em %n horas"], - "_%n hour ago_::_%n hours ago_" : ["há %n hora atrás","há %n horas","há %n horas"], + "_%n hour ago_::_%n hours ago_" : ["%n hora atrás","%n horas atrás","%n horas atrás"], "_in %n minute_::_in %n minutes_" : ["em %n minuto","em %n minutos","em %n minutos"], - "_%n minute ago_::_%n minutes ago_" : ["há %n minuto atrás","há %n minutos","há %n minutos"], + "_%n minute ago_::_%n minutes ago_" : ["%n minuto atrás","%n minutos atrás","%n minutos atrás"], "in a few seconds" : "Em alguns segundos", "seconds ago" : "segundos atrás", "Empty file" : "Arquivo vazio", @@ -271,6 +271,7 @@ "A valid Login must be provided" : "Um Login válido deve ser fornecido", "Login contains whitespace at the beginning or at the end" : "O login contém espaços em branco no início ou no final", "Login must not consist of dots only" : "O login não deve consistir apenas de pontos", + "Login is too long" : "O login é muito longo", "Login is invalid because files already exist for this user" : "O login é inválido porque já existem arquivos para este usuário", "Account disabled" : "Conta desativada", "Login canceled by app" : "Login cancelado pelo aplicativo", diff --git a/lib/l10n/sr.js b/lib/l10n/sr.js index 7d9c5dbf19c..187721eeb2a 100644 --- a/lib/l10n/sr.js +++ b/lib/l10n/sr.js @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "Морате да унесете исправно име за пријаву", "Login contains whitespace at the beginning or at the end" : "Име за пријаву садржи белине на почетку или на крају", "Login must not consist of dots only" : "Име за пријаву не може да се састоји само од тачака", + "Login is too long" : "Име за пријаву је сувише дугачко", "Login is invalid because files already exist for this user" : "Име за пријаву није исправно пошто већ постоје фајлови овог корисника", "Account disabled" : "Налог је искључен", "Login canceled by app" : "Пријава отказана од стране апликације", diff --git a/lib/l10n/sr.json b/lib/l10n/sr.json index 8ca7ac52409..fc38faab174 100644 --- a/lib/l10n/sr.json +++ b/lib/l10n/sr.json @@ -271,6 +271,7 @@ "A valid Login must be provided" : "Морате да унесете исправно име за пријаву", "Login contains whitespace at the beginning or at the end" : "Име за пријаву садржи белине на почетку или на крају", "Login must not consist of dots only" : "Име за пријаву не може да се састоји само од тачака", + "Login is too long" : "Име за пријаву је сувише дугачко", "Login is invalid because files already exist for this user" : "Име за пријаву није исправно пошто већ постоје фајлови овог корисника", "Account disabled" : "Налог је искључен", "Login canceled by app" : "Пријава отказана од стране апликације", diff --git a/lib/l10n/sv.js b/lib/l10n/sv.js index 6e25e5562b5..bc31d5b4acd 100644 --- a/lib/l10n/sv.js +++ b/lib/l10n/sv.js @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "En giltig inloggning måste anges", "Login contains whitespace at the beginning or at the end" : "Inloggningen innehåller blanksteg i början eller slutet", "Login must not consist of dots only" : "Inloggningen får inte innehålla enbart punkter", + "Login is too long" : "Inloggningen är för lång", "Login is invalid because files already exist for this user" : "Inloggningen är ogiltigt eftersom det redan finns filer för den här användaren", "Account disabled" : "Konto inaktiverat", "Login canceled by app" : "Inloggningen avbruten av appen", @@ -333,8 +334,15 @@ OC.L10N.register( "Chat message" : "Chattmeddelande", "A chat message to send to the agent." : "Ett chattmeddelande att skicka till agenten.", "Confirmation" : "Bekräftelse", + "Whether to confirm previously requested actions: 0 for denial and 1 for confirmation." : "Om tidigare begärda åtgärder ska bekräftas: 0 för avslag och 1 för bekräftelse.", + "Conversation token" : "Konversationstoken", + "A token representing the conversation." : "En token som representerar konversationen.", "Generated response" : "Genererat svar", "The response from the chat model." : "Svaret från chattmodellen.", + "The new conversation token" : "Den nya konversationstoken", + "Send this along with the next interaction." : "Skicka detta tillsammans med nästa interaktion.", + "Requested actions by the agent" : "Begärda åtgärder av agenten", + "Actions that the agent would like to carry out in JSON format." : "Åtgärder som agenten vill utföra i JSON-format.", "Context write" : "Kontextuell skrivning", "Writes text in a given style based on the provided source material." : "Skriver text i en given stil baserat på det tillhandahållna källmaterialet.", "Writing style" : "Skrivstil", @@ -365,6 +373,8 @@ OC.L10N.register( "Change the tone of a piece of text." : "Ändra tonfallet i ett stycke text.", "Write a text that you want the assistant to rewrite in another tone." : "Skriv text som du vill att assistenten ska omformulera med ett annat tonfall.", "Desired tone" : "Önskat tonfall", + "In which tone should your text be rewritten?" : "I vilken ton ska din text skrivas om?", + "The rewritten text in the desired tone, written by the assistant:" : "Den omskrivna texten i önskad ton, skriven av assistenten:", "Chat" : "Chatt", "Chat with the assistant" : "Chatta med assistenten", "System prompt" : "Systemuppmaning", @@ -373,6 +383,15 @@ OC.L10N.register( "The history of chat messages before the current message, starting with a message by the user" : "Historiken för chattmeddelanden före det aktuella meddelandet, som börjar med ett meddelande från användaren", "Response message" : "Svarsmeddelande", "The generated response as part of the conversation" : "Det genererade svaret som en del av konversationen", + "Chat with tools" : "Chatt med verktyg", + "Chat with the language model with tool calling support." : "Chatt med språkmodellen med stöd för verktygsanrop.", + "Tool message" : "Verktygsmeddelande", + "The result of tool calls in the last interaction" : "Resultatet av verktygsanropen i den senaste interaktionen", + "Available tools" : "Tillgängliga verktyg", + "The available tools in JSON format" : "Tillgängliga verktyg i JSON-format", + "The response from the chat model" : "Svaret från chattmodellen", + "Tool calls" : "Verktagsanrop", + "Tools call instructions from the model in JSON format" : "Verktygsanrop och instruktioner från modellen i JSON-format", "Formalize text" : "Formalisera text", "Takes a text and makes it sound more formal" : "Tar en text och får det att låta mer formellt", "Write a text that you want the assistant to formalize" : "Skriv en text som du vill att assistenten ska formalisera", @@ -384,7 +403,11 @@ OC.L10N.register( "The original text to generate a headline for" : "Den ursprungliga texten att skapa en rubrik för", "The generated headline" : "Den skapade rubriken", "Proofread" : "Korrekturläs", + "Proofreads a text and lists corrections" : "Korrekturläser en text och listar korrigeringar", "Text" : "Text", + "The text to proofread" : "Texten som ska korrekturläsas", + "Corrections" : "Korrigeringar", + "The corrections that should be made in your text" : "Korrigeringarna som bör göras i din text", "Reformulate text" : "Omformulera text", "Takes a text and reformulates it" : "Tar en text och omformulerar den", "Write a text that you want the assistant to reformulate" : "Skriv en text som du vill att assistenten ska formulera om", diff --git a/lib/l10n/sv.json b/lib/l10n/sv.json index 528a325f2f2..cc1b5183b80 100644 --- a/lib/l10n/sv.json +++ b/lib/l10n/sv.json @@ -271,6 +271,7 @@ "A valid Login must be provided" : "En giltig inloggning måste anges", "Login contains whitespace at the beginning or at the end" : "Inloggningen innehåller blanksteg i början eller slutet", "Login must not consist of dots only" : "Inloggningen får inte innehålla enbart punkter", + "Login is too long" : "Inloggningen är för lång", "Login is invalid because files already exist for this user" : "Inloggningen är ogiltigt eftersom det redan finns filer för den här användaren", "Account disabled" : "Konto inaktiverat", "Login canceled by app" : "Inloggningen avbruten av appen", @@ -331,8 +332,15 @@ "Chat message" : "Chattmeddelande", "A chat message to send to the agent." : "Ett chattmeddelande att skicka till agenten.", "Confirmation" : "Bekräftelse", + "Whether to confirm previously requested actions: 0 for denial and 1 for confirmation." : "Om tidigare begärda åtgärder ska bekräftas: 0 för avslag och 1 för bekräftelse.", + "Conversation token" : "Konversationstoken", + "A token representing the conversation." : "En token som representerar konversationen.", "Generated response" : "Genererat svar", "The response from the chat model." : "Svaret från chattmodellen.", + "The new conversation token" : "Den nya konversationstoken", + "Send this along with the next interaction." : "Skicka detta tillsammans med nästa interaktion.", + "Requested actions by the agent" : "Begärda åtgärder av agenten", + "Actions that the agent would like to carry out in JSON format." : "Åtgärder som agenten vill utföra i JSON-format.", "Context write" : "Kontextuell skrivning", "Writes text in a given style based on the provided source material." : "Skriver text i en given stil baserat på det tillhandahållna källmaterialet.", "Writing style" : "Skrivstil", @@ -363,6 +371,8 @@ "Change the tone of a piece of text." : "Ändra tonfallet i ett stycke text.", "Write a text that you want the assistant to rewrite in another tone." : "Skriv text som du vill att assistenten ska omformulera med ett annat tonfall.", "Desired tone" : "Önskat tonfall", + "In which tone should your text be rewritten?" : "I vilken ton ska din text skrivas om?", + "The rewritten text in the desired tone, written by the assistant:" : "Den omskrivna texten i önskad ton, skriven av assistenten:", "Chat" : "Chatt", "Chat with the assistant" : "Chatta med assistenten", "System prompt" : "Systemuppmaning", @@ -371,6 +381,15 @@ "The history of chat messages before the current message, starting with a message by the user" : "Historiken för chattmeddelanden före det aktuella meddelandet, som börjar med ett meddelande från användaren", "Response message" : "Svarsmeddelande", "The generated response as part of the conversation" : "Det genererade svaret som en del av konversationen", + "Chat with tools" : "Chatt med verktyg", + "Chat with the language model with tool calling support." : "Chatt med språkmodellen med stöd för verktygsanrop.", + "Tool message" : "Verktygsmeddelande", + "The result of tool calls in the last interaction" : "Resultatet av verktygsanropen i den senaste interaktionen", + "Available tools" : "Tillgängliga verktyg", + "The available tools in JSON format" : "Tillgängliga verktyg i JSON-format", + "The response from the chat model" : "Svaret från chattmodellen", + "Tool calls" : "Verktagsanrop", + "Tools call instructions from the model in JSON format" : "Verktygsanrop och instruktioner från modellen i JSON-format", "Formalize text" : "Formalisera text", "Takes a text and makes it sound more formal" : "Tar en text och får det att låta mer formellt", "Write a text that you want the assistant to formalize" : "Skriv en text som du vill att assistenten ska formalisera", @@ -382,7 +401,11 @@ "The original text to generate a headline for" : "Den ursprungliga texten att skapa en rubrik för", "The generated headline" : "Den skapade rubriken", "Proofread" : "Korrekturläs", + "Proofreads a text and lists corrections" : "Korrekturläser en text och listar korrigeringar", "Text" : "Text", + "The text to proofread" : "Texten som ska korrekturläsas", + "Corrections" : "Korrigeringar", + "The corrections that should be made in your text" : "Korrigeringarna som bör göras i din text", "Reformulate text" : "Omformulera text", "Takes a text and reformulates it" : "Tar en text och omformulerar den", "Write a text that you want the assistant to reformulate" : "Skriv en text som du vill att assistenten ska formulera om", diff --git a/lib/l10n/zh_CN.js b/lib/l10n/zh_CN.js index ccfec5d5b3a..818f0fdad18 100644 --- a/lib/l10n/zh_CN.js +++ b/lib/l10n/zh_CN.js @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "必须提供有效的登录名", "Login contains whitespace at the beginning or at the end" : "登录名开头或结尾包含空格", "Login must not consist of dots only" : "登录名不能仅由点组成", + "Login is too long" : "登录名太长", "Login is invalid because files already exist for this user" : "登录无效,因为此用户的文件已存在", "Account disabled" : "帐户已禁用", "Login canceled by app" : "已通过应用取消登录", diff --git a/lib/l10n/zh_CN.json b/lib/l10n/zh_CN.json index 14609466bc0..bc3d5081fdc 100644 --- a/lib/l10n/zh_CN.json +++ b/lib/l10n/zh_CN.json @@ -271,6 +271,7 @@ "A valid Login must be provided" : "必须提供有效的登录名", "Login contains whitespace at the beginning or at the end" : "登录名开头或结尾包含空格", "Login must not consist of dots only" : "登录名不能仅由点组成", + "Login is too long" : "登录名太长", "Login is invalid because files already exist for this user" : "登录无效,因为此用户的文件已存在", "Account disabled" : "帐户已禁用", "Login canceled by app" : "已通过应用取消登录", diff --git a/lib/l10n/zh_TW.js b/lib/l10n/zh_TW.js index 9e48c3dd6ab..95a20523c8f 100644 --- a/lib/l10n/zh_TW.js +++ b/lib/l10n/zh_TW.js @@ -273,6 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "必須提供有效帳號", "Login contains whitespace at the beginning or at the end" : "帳號的開頭或結尾有空白", "Login must not consist of dots only" : "帳號不能只包含小數點", + "Login is too long" : "帳號太長了", "Login is invalid because files already exist for this user" : "帳號無效,因為使用者的檔案已經存在", "Account disabled" : "帳號已停用", "Login canceled by app" : "應用程式取消了登入", diff --git a/lib/l10n/zh_TW.json b/lib/l10n/zh_TW.json index 55cad52a465..b9af7705ef9 100644 --- a/lib/l10n/zh_TW.json +++ b/lib/l10n/zh_TW.json @@ -271,6 +271,7 @@ "A valid Login must be provided" : "必須提供有效帳號", "Login contains whitespace at the beginning or at the end" : "帳號的開頭或結尾有空白", "Login must not consist of dots only" : "帳號不能只包含小數點", + "Login is too long" : "帳號太長了", "Login is invalid because files already exist for this user" : "帳號無效,因為使用者的檔案已經存在", "Account disabled" : "帳號已停用", "Login canceled by app" : "應用程式取消了登入", diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 740da31770d..f6494fa946d 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -8,7 +8,6 @@ namespace OC\App; use OC\AppConfig; use OC\AppFramework\Bootstrap\Coordinator; -use OC\ServerNotAvailableException; use OCP\Activity\IManager as IActivityManager; use OCP\App\AppPathNotFoundException; use OCP\App\Events\AppDisableEvent; @@ -251,7 +250,7 @@ class AppManager implements IAppManager { } } - // prevent app.php from printing output + // prevent app loading from printing output ob_start(); foreach ($apps as $app) { if (!$this->isAppLoaded($app) && ($types === [] || $this->isType($app, $types))) { @@ -452,43 +451,13 @@ class AppManager implements IAppManager { // in case someone calls loadApp() directly \OC_App::registerAutoloading($app, $appPath); - /** @var Coordinator $coordinator */ - $coordinator = \OC::$server->get(Coordinator::class); - $isBootable = $coordinator->isBootable($app); - - $hasAppPhpFile = is_file($appPath . '/appinfo/app.php'); - - if ($isBootable && $hasAppPhpFile) { - $this->logger->error('/appinfo/app.php is not loaded when \OCP\AppFramework\Bootstrap\IBootstrap on the application class is used. Migrate everything from app.php to the Application class.', [ + if (is_file($appPath . '/appinfo/app.php')) { + $this->logger->error('/appinfo/app.php is not supported anymore, use \OCP\AppFramework\Bootstrap\IBootstrap on the application class instead.', [ 'app' => $app, ]); - } elseif ($hasAppPhpFile) { - $eventLogger->start("bootstrap:load_app:$app:app.php", "Load legacy app.php app $app"); - $this->logger->debug('/appinfo/app.php is deprecated, use \OCP\AppFramework\Bootstrap\IBootstrap on the application class instead.', [ - 'app' => $app, - ]); - try { - self::requireAppFile($appPath); - } catch (\Throwable $ex) { - if ($ex instanceof ServerNotAvailableException) { - throw $ex; - } - if (!$this->isShipped($app) && !$this->isType($app, ['authentication'])) { - $this->logger->error("App $app threw an error during app.php load and will be disabled: " . $ex->getMessage(), [ - 'exception' => $ex, - ]); - - // Only disable apps which are not shipped and that are not authentication apps - $this->disableApp($app, true); - } else { - $this->logger->error("App $app threw an error during app.php load: " . $ex->getMessage(), [ - 'exception' => $ex, - ]); - } - } - $eventLogger->end("bootstrap:load_app:$app:app.php"); } + $coordinator = \OCP\Server::get(Coordinator::class); $coordinator->bootApp($app); $eventLogger->start("bootstrap:load_app:$app:info", "Load info.xml for $app and register any services defined in it"); @@ -560,6 +529,7 @@ class AppManager implements IAppManager { $eventLogger->end("bootstrap:load_app:$app"); } + /** * Check if an app is loaded * @param string $app app id @@ -570,17 +540,6 @@ class AppManager implements IAppManager { } /** - * Load app.php from the given app - * - * @param string $app app name - * @throws \Error - */ - private static function requireAppFile(string $app): void { - // encapsulated here to avoid variable scope conflicts - require_once $app . '/appinfo/app.php'; - } - - /** * Enable an app for every user * * @param string $appId diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php index 4e78450fa04..2b04d291730 100644 --- a/lib/private/AppFramework/Bootstrap/Coordinator.php +++ b/lib/private/AppFramework/Bootstrap/Coordinator.php @@ -30,8 +30,8 @@ class Coordinator { /** @var RegistrationContext|null */ private $registrationContext; - /** @var string[] */ - private $bootedApps = []; + /** @var array<string,true> */ + private array $bootedApps = []; public function __construct( private IServerContainer $serverContainer, diff --git a/lib/private/AppFramework/Http/Dispatcher.php b/lib/private/AppFramework/Http/Dispatcher.php index d63a9108b47..d129a7d770b 100644 --- a/lib/private/AppFramework/Http/Dispatcher.php +++ b/lib/private/AppFramework/Http/Dispatcher.php @@ -90,9 +90,11 @@ class Dispatcher { * @param Controller $controller the controller which will be called * @param string $methodName the method name which will be called on * the controller - * @return array $array[0] contains a string with the http main header, - * $array[1] contains headers in the form: $key => value, $array[2] contains - * the response output + * @return array $array[0] contains the http status header as a string, + * $array[1] contains response headers as an array, + * $array[2] contains response cookies as an array, + * $array[3] contains the response output as a string, + * $array[4] contains the response object * @throws \Exception */ public function dispatch(Controller $controller, string $methodName): array { diff --git a/lib/private/Federation/CloudIdManager.php b/lib/private/Federation/CloudIdManager.php index a7d36eda4a0..7e7adda3d39 100644 --- a/lib/private/Federation/CloudIdManager.php +++ b/lib/private/Federation/CloudIdManager.php @@ -106,7 +106,10 @@ class CloudIdManager implements ICloudIdManager { $user = substr($id, 0, $lastValidAtPos); $remote = substr($id, $lastValidAtPos + 1); - $this->userManager->validateUserId($user); + // We accept slightly more chars when working with federationId than with a local userId. + // We remove those eventual chars from the UserId before using + // the IUserManager API to confirm its format. + $this->userManager->validateUserId(str_replace('=', '-', $user)); if (!empty($user) && !empty($remote)) { $remote = $this->ensureDefaultProtocol($remote); diff --git a/lib/private/Files/ObjectStore/S3ConnectionTrait.php b/lib/private/Files/ObjectStore/S3ConnectionTrait.php index 7ddf2abed1d..b7017583dc2 100644 --- a/lib/private/Files/ObjectStore/S3ConnectionTrait.php +++ b/lib/private/Files/ObjectStore/S3ConnectionTrait.php @@ -106,6 +106,10 @@ trait S3ConnectionTrait { 'connect_timeout' => 5 ], 'use_aws_shared_config_files' => false, + 'retries' => [ + 'mode' => 'standard', + 'max_attempts' => 5, + ], ]; if ($this->params['s3-accelerate']) { diff --git a/lib/private/Log/LogDetails.php b/lib/private/Log/LogDetails.php index bd18eb983db..b3ae23a3770 100644 --- a/lib/private/Log/LogDetails.php +++ b/lib/private/Log/LogDetails.php @@ -37,7 +37,7 @@ abstract class LogDetails { $url = ($request->getRequestUri() !== '') ? $request->getRequestUri() : '--'; $method = is_string($request->getMethod()) ? $request->getMethod() : '--'; if ($this->config->getValue('installed', false)) { - $user = \OC_User::getUser() ?? '--'; + $user = \OC_User::getUser() ?: '--'; } else { $user = '--'; } diff --git a/lib/private/Mail/EMailTemplate.php b/lib/private/Mail/EMailTemplate.php index 2cb222fd137..1d19f00b0a1 100644 --- a/lib/private/Mail/EMailTemplate.php +++ b/lib/private/Mail/EMailTemplate.php @@ -523,7 +523,7 @@ EOF; $this->ensureBodyListClosed(); $color = $this->themingDefaults->getDefaultColorPrimary(); - $textColor = $this->themingDefaults->getTextColorPrimary(); + $textColor = $this->themingDefaults->getDefaultTextColorPrimary(); $this->htmlBody .= vsprintf($this->buttonGroup, [$color, $color, $urlLeft, $color, $textColor, $textColor, $textLeft, $urlRight, $textRight]); $this->plainBody .= PHP_EOL . $plainTextLeft . ': ' . $urlLeft . PHP_EOL; @@ -554,7 +554,7 @@ EOF; } $color = $this->themingDefaults->getDefaultColorPrimary(); - $textColor = $this->themingDefaults->getTextColorPrimary(); + $textColor = $this->themingDefaults->getDefaultTextColorPrimary(); $this->htmlBody .= vsprintf($this->button, [$color, $color, $url, $color, $textColor, $textColor, $text]); if ($plainText !== false) { diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php index ef68c17b896..66069beaecc 100644 --- a/lib/private/Preview/Generator.php +++ b/lib/private/Preview/Generator.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -20,34 +21,20 @@ use OCP\IStreamImage; use OCP\Preview\BeforePreviewFetchedEvent; use OCP\Preview\IProviderV2; use OCP\Preview\IVersionedPreviewFile; +use Psr\Log\LoggerInterface; class Generator { public const SEMAPHORE_ID_ALL = 0x0a11; public const SEMAPHORE_ID_NEW = 0x07ea; - /** @var IPreview */ - private $previewManager; - /** @var IConfig */ - private $config; - /** @var IAppData */ - private $appData; - /** @var GeneratorHelper */ - private $helper; - /** @var IEventDispatcher */ - private $eventDispatcher; - public function __construct( - IConfig $config, - IPreview $previewManager, - IAppData $appData, - GeneratorHelper $helper, - IEventDispatcher $eventDispatcher, + private IConfig $config, + private IPreview $previewManager, + private IAppData $appData, + private GeneratorHelper $helper, + private IEventDispatcher $eventDispatcher, + private LoggerInterface $logger, ) { - $this->config = $config; - $this->previewManager = $previewManager; - $this->appData = $appData; - $this->helper = $helper; - $this->eventDispatcher = $eventDispatcher; } /** @@ -83,6 +70,16 @@ class Generator { $mimeType, )); + $this->logger->debug('Requesting preview for {path} with width={width}, height={height}, crop={crop}, mode={mode}, mimeType={mimeType}', [ + 'path' => $file->getPath(), + 'width' => $width, + 'height' => $height, + 'crop' => $crop, + 'mode' => $mode, + 'mimeType' => $mimeType, + ]); + + // since we only ask for one preview, and the generate method return the last one it created, it returns the one we want return $this->generatePreviews($file, [$specification], $mimeType); } @@ -100,6 +97,7 @@ class Generator { public function generatePreviews(File $file, array $specifications, $mimeType = null) { //Make sure that we can read the file if (!$file->isReadable()) { + $this->logger->warning('Cannot read file: {path}, skipping preview generation.', ['path' => $file->getPath()]); throw new NotFoundException('Cannot read file'); } @@ -121,6 +119,7 @@ class Generator { $maxPreviewImage = null; // only load the image when we need it if ($maxPreview->getSize() === 0) { $maxPreview->delete(); + $this->logger->error("Max preview generated for file {$file->getPath()} has size 0, deleting and throwing exception."); throw new NotFoundException('Max preview size 0, invalid!'); } @@ -167,6 +166,7 @@ class Generator { $maxPreviewImage = $this->helper->getImage($maxPreview); } + $this->logger->warning('Cached preview not found for file {path}, generating a new preview.', ['path' => $file->getPath()]); $preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion); // New file, augment our array $previewFiles[] = $preview; @@ -335,6 +335,11 @@ class Generator { $previewConcurrency = $this->getNumConcurrentPreviews('preview_concurrency_new'); $sem = self::guardWithSemaphore(self::SEMAPHORE_ID_NEW, $previewConcurrency); try { + $this->logger->debug('Calling preview provider for {mimeType} with width={width}, height={height}', [ + 'mimeType' => $mimeType, + 'width' => $width, + 'height' => $height, + ]); $preview = $this->helper->getThumbnail($provider, $file, $width, $height); } finally { self::unguardWithSemaphore($sem); @@ -558,6 +563,7 @@ class Generator { $path = $this->generatePath($width, $height, $crop, false, $mimeType, $prefix); foreach ($files as $file) { if ($file->getName() === $path) { + $this->logger->debug('Found cached preview: {path}', ['path' => $path]); return $file; } } diff --git a/lib/private/PreviewManager.php b/lib/private/PreviewManager.php index 8417554566e..bc77dcfe483 100644 --- a/lib/private/PreviewManager.php +++ b/lib/private/PreviewManager.php @@ -21,8 +21,10 @@ use OCP\Files\SimpleFS\ISimpleFile; use OCP\IBinaryFinder; use OCP\IConfig; use OCP\IPreview; -use OCP\IServerContainer; use OCP\Preview\IProviderV2; +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; + use function array_key_exists; class PreviewManager implements IPreview { @@ -47,7 +49,7 @@ class PreviewManager implements IPreview { * @psalm-var array<string, null> */ private array $loadedBootstrapProviders = []; - private IServerContainer $container; + private ContainerInterface $container; private IBinaryFinder $binaryFinder; private IMagickSupport $imagickSupport; private bool $enablePreviews; @@ -60,7 +62,7 @@ class PreviewManager implements IPreview { GeneratorHelper $helper, ?string $userId, Coordinator $bootstrapCoordinator, - IServerContainer $container, + ContainerInterface $container, IBinaryFinder $binaryFinder, IMagickSupport $imagickSupport, ) { @@ -136,7 +138,8 @@ class PreviewManager implements IPreview { $this->rootFolder, $this->config ), - $this->eventDispatcher + $this->eventDispatcher, + $this->container->get(LoggerInterface::class), ); } return $this->generator; diff --git a/lib/private/Profile/ProfileManager.php b/lib/private/Profile/ProfileManager.php index 9d3d94fab21..13860286356 100644 --- a/lib/private/Profile/ProfileManager.php +++ b/lib/private/Profile/ProfileManager.php @@ -12,6 +12,7 @@ namespace OC\Profile; use OC\AppFramework\Bootstrap\Coordinator; use OC\Core\Db\ProfileConfig; use OC\Core\Db\ProfileConfigMapper; +use OC\Core\ResponseDefinitions; use OC\KnownUser\KnownUserService; use OC\Profile\Actions\EmailAction; use OC\Profile\Actions\FediverseAction; @@ -33,6 +34,9 @@ use Psr\Log\LoggerInterface; use function array_flip; use function usort; +/** + * @psalm-import-type CoreProfileFields from ResponseDefinitions + */ class ProfileManager implements IProfileManager { /** @var ILinkAction[] */ private array $actions = []; @@ -223,7 +227,7 @@ class ProfileManager implements IProfileManager { /** * Return the profile parameters of the target user that are visible to the visiting user * in an associative array - * @return array{userId: string, address?: string|null, biography?: string|null, displayname?: string|null, headline?: string|null, isUserAvatarVisible?: bool, organisation?: string|null, pronouns?: string|null, role?: string|null, actions: list<array{id: string, icon: string, title: string, target: ?string}>} + * @psalm-return CoreProfileFields */ public function getProfileFields(IUser $targetUser, ?IUser $visitingUser): array { $account = $this->accountManager->getAccount($targetUser); diff --git a/lib/private/Profiler/BuiltInProfiler.php b/lib/private/Profiler/BuiltInProfiler.php new file mode 100644 index 00000000000..0a62365e901 --- /dev/null +++ b/lib/private/Profiler/BuiltInProfiler.php @@ -0,0 +1,95 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace OC\Profiler; + +use DateTime; +use OCP\IConfig; +use OCP\IRequest; + +class BuiltInProfiler { + private \ExcimerProfiler $excimer; + + public function __construct( + private IConfig $config, + private IRequest $request, + ) { + } + + public function start(): void { + if (!extension_loaded('excimer')) { + return; + } + + $shouldProfileSingleRequest = $this->shouldProfileSingleRequest(); + $shouldSample = $this->config->getSystemValueBool('profiling.sample') && !$shouldProfileSingleRequest; + + + if (!$shouldProfileSingleRequest && !$shouldSample) { + return; + } + + $requestRate = $this->config->getSystemValue('profiling.request.rate', 0.001); + $sampleRate = $this->config->getSystemValue('profiling.sample.rate', 1.0); + $eventType = $this->config->getSystemValue('profiling.event_type', EXCIMER_REAL); + + + $this->excimer = new \ExcimerProfiler(); + $this->excimer->setPeriod($shouldProfileSingleRequest ? $requestRate : $sampleRate); + $this->excimer->setEventType($eventType); + $this->excimer->setMaxDepth(250); + + if ($shouldSample) { + $this->excimer->setFlushCallback([$this, 'handleSampleFlush'], 1); + } + + $this->excimer->start(); + register_shutdown_function([$this, 'handleShutdown']); + } + + public function handleSampleFlush(\ExcimerLog $log): void { + file_put_contents($this->getSampleFilename(), $log->formatCollapsed(), FILE_APPEND); + } + + public function handleShutdown(): void { + $this->excimer->stop(); + + if (!$this->shouldProfileSingleRequest()) { + $this->excimer->flush(); + return; + } + + $request = \OCP\Server::get(IRequest::class); + $data = $this->excimer->getLog()->getSpeedscopeData(); + + $data['profiles'][0]['name'] = $request->getMethod() . ' ' . $request->getRequestUri() . ' ' . $request->getId(); + + file_put_contents($this->getProfileFilename(), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); + } + + private function shouldProfileSingleRequest(): bool { + $shouldProfileSingleRequest = $this->config->getSystemValueBool('profiling.request', false); + $profileSecret = $this->config->getSystemValueString('profiling.secret', ''); + $secretParam = $this->request->getParam('profile_secret') ?? null; + return $shouldProfileSingleRequest || (!empty($profileSecret) && $profileSecret === $secretParam); + } + + private function getSampleFilename(): string { + $profilePath = $this->config->getSystemValueString('profiling.path', '/tmp'); + $sampleRotation = $this->config->getSystemValueInt('profiling.sample.rotation', 60); + $timestamp = floor(time() / ($sampleRotation * 60)) * ($sampleRotation * 60); + $sampleName = date('Y-m-d_Hi', (int)$timestamp); + return $profilePath . '/sample-' . $sampleName . '.log'; + } + + private function getProfileFilename(): string { + $profilePath = $this->config->getSystemValueString('profiling.path', '/tmp'); + $requestId = $this->request->getId(); + return $profilePath . '/profile-' . (new DateTime)->format('Y-m-d_His_v') . '-' . $requestId . '.json'; + } +} diff --git a/lib/private/Security/Normalizer/IpAddress.php b/lib/private/Security/Normalizer/IpAddress.php index 6ef8763f6d9..e40dc9ba96b 100644 --- a/lib/private/Security/Normalizer/IpAddress.php +++ b/lib/private/Security/Normalizer/IpAddress.php @@ -8,6 +8,8 @@ declare(strict_types=1); */ namespace OC\Security\Normalizer; +use OCP\IConfig; + /** * Class IpAddress is used for normalizing IPv4 and IPv6 addresses in security * relevant contexts in Nextcloud. @@ -24,7 +26,8 @@ class IpAddress { } /** - * Return the given subnet for an IPv6 address (48 first bits) + * Return the given subnet for an IPv6 address + * Rely on security.ipv6_normalized_subnet_size, defaults to 56 */ private function getIPv6Subnet(string $ip): string { if ($ip[0] === '[' && $ip[-1] === ']') { // If IP is with brackets, for example [::1] @@ -35,10 +38,14 @@ class IpAddress { $ip = substr($ip, 0, $pos - 1); } + $config = \OCP\Server::get(IConfig::class); + $maskSize = min(64, $config->getSystemValueInt('security.ipv6_normalized_subnet_size', 56)); + $maskSize = max(32, $maskSize); + $mask = pack('VVP', (1 << 32) - 1, (1 << $maskSize - 32) - 1, 0); + $binary = \inet_pton($ip); - $mask = inet_pton('FFFF:FFFF:FFFF::'); - return inet_ntop($binary & $mask) . '/48'; + return inet_ntop($binary & $mask) . '/' . $maskSize; } /** @@ -63,7 +70,7 @@ class IpAddress { /** - * Gets either the /32 (IPv4) or the /48 (IPv6) subnet of an IP address + * Gets either the /32 (IPv4) or the /56 (default for IPv6) subnet of an IP address */ public function getSubnet(): string { if (filter_var($this->ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { diff --git a/lib/private/Template/JSConfigHelper.php b/lib/private/Template/JSConfigHelper.php index 93f5d7a5866..de9df04ae4b 100644 --- a/lib/private/Template/JSConfigHelper.php +++ b/lib/private/Template/JSConfigHelper.php @@ -67,7 +67,7 @@ class JSConfigHelper { $backend = $this->currentUser->getBackend(); if ($backend instanceof IPasswordConfirmationBackend) { - $userBackendAllowsPasswordConfirmation = $backend->canConfirmPassword($uid); + $userBackendAllowsPasswordConfirmation = $backend->canConfirmPassword($uid) && $this->canUserValidatePassword(); } elseif (isset($this->excludedUserBackEnds[$this->currentUser->getBackendClassName()])) { $userBackendAllowsPasswordConfirmation = false; } diff --git a/lib/private/User/DisplayNameCache.php b/lib/private/User/DisplayNameCache.php index 34db783de68..40e1c752589 100644 --- a/lib/private/User/DisplayNameCache.php +++ b/lib/private/User/DisplayNameCache.php @@ -11,6 +11,7 @@ use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\ICache; use OCP\ICacheFactory; +use OCP\IUser; use OCP\IUserManager; use OCP\User\Events\UserChangedEvent; use OCP\User\Events\UserDeletedEvent; @@ -37,6 +38,11 @@ class DisplayNameCache implements IEventListener { if (isset($this->cache[$userId])) { return $this->cache[$userId]; } + + if (strlen($userId) > IUser::MAX_USERID_LENGTH) { + return null; + } + $displayName = $this->memCache->get($userId); if ($displayName) { $this->cache[$userId] = $displayName; diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index 1f23a9ae9fd..ca5d90f8c00 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -118,6 +118,10 @@ class Manager extends PublicEmitter implements IUserManager { return $this->cachedUsers[$uid]; } + if (strlen($uid) > IUser::MAX_USERID_LENGTH) { + return null; + } + $cachedBackend = $this->cache->get(sha1($uid)); if ($cachedBackend !== null && isset($this->backends[$cachedBackend])) { // Cache has the info of the user backend already, so ask that one directly @@ -177,6 +181,10 @@ class Manager extends PublicEmitter implements IUserManager { * @return bool */ public function userExists($uid) { + if (strlen($uid) > IUser::MAX_USERID_LENGTH) { + return false; + } + $user = $this->get($uid); return ($user !== null); } @@ -692,14 +700,14 @@ class Manager extends PublicEmitter implements IUserManager { public function validateUserId(string $uid, bool $checkDataDirectory = false): void { $l = Server::get(IFactory::class)->get('lib'); - // Check the name for bad characters + // Check the ID for bad characters // Allowed are: "a-z", "A-Z", "0-9", spaces and "_.@-'" if (preg_match('/[^a-zA-Z0-9 _.@\-\']/', $uid)) { throw new \InvalidArgumentException($l->t('Only the following characters are allowed in an Login:' . ' "a-z", "A-Z", "0-9", spaces and "_.@-\'"')); } - // No empty username + // No empty user ID if (trim($uid) === '') { throw new \InvalidArgumentException($l->t('A valid Login must be provided')); } @@ -709,11 +717,16 @@ class Manager extends PublicEmitter implements IUserManager { throw new \InvalidArgumentException($l->t('Login contains whitespace at the beginning or at the end')); } - // Username only consists of 1 or 2 dots (directory traversal) + // User ID only consists of 1 or 2 dots (directory traversal) if ($uid === '.' || $uid === '..') { throw new \InvalidArgumentException($l->t('Login must not consist of dots only')); } + // User ID is too long + if (strlen($uid) > IUser::MAX_USERID_LENGTH) { + throw new \InvalidArgumentException($l->t('Login is too long')); + } + if (!$this->verifyUid($uid, $checkDataDirectory)) { throw new \InvalidArgumentException($l->t('Login is invalid because files already exist for this user')); } diff --git a/lib/public/AppFramework/Bootstrap/IBootstrap.php b/lib/public/AppFramework/Bootstrap/IBootstrap.php index 81c34524191..7260d2b77a1 100644 --- a/lib/public/AppFramework/Bootstrap/IBootstrap.php +++ b/lib/public/AppFramework/Bootstrap/IBootstrap.php @@ -25,8 +25,6 @@ interface IBootstrap { * At this stage you can assume that all services are registered and the DI * container(s) are ready to be queried. * - * This is also the state where an optional `appinfo/app.php` was loaded. - * * @param IBootContext $context * * @since 20.0.0 diff --git a/lib/public/IUser.php b/lib/public/IUser.php index 227e4f902c7..52f79083dc1 100644 --- a/lib/public/IUser.php +++ b/lib/public/IUser.php @@ -16,6 +16,11 @@ use InvalidArgumentException; */ interface IUser { /** + * @since 32.0.0 + */ + public const MAX_USERID_LENGTH = 64; + + /** * get the user id * * @return string diff --git a/lib/public/Profile/IProfileManager.php b/lib/public/Profile/IProfileManager.php index 0a1e6733e58..f4e90e39d12 100644 --- a/lib/public/Profile/IProfileManager.php +++ b/lib/public/Profile/IProfileManager.php @@ -9,10 +9,12 @@ declare(strict_types=1); namespace OCP\Profile; +use OC\Core\ResponseDefinitions; use OCP\Accounts\IAccountManager; use OCP\IUser; /** + * @psalm-import-type CoreProfileFields from ResponseDefinitions * @since 28.0.0 */ interface IProfileManager { @@ -83,7 +85,7 @@ interface IProfileManager { * Return the profile parameters of the target user that are visible to the visiting user * in an associative array * - * @return array{userId: string, address?: string|null, biography?: string|null, displayname?: string|null, headline?: string|null, isUserAvatarVisible?: bool, organisation?: string|null, pronouns?: string|null, role?: string|null, actions: list<array{id: string, icon: string, title: string, target: ?string}>} + * @psalm-return CoreProfileFields * @since 28.0.0 */ public function getProfileFields(IUser $targetUser, ?IUser $visitingUser): array; |