aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/AllConfig.php6
-rw-r--r--lib/private/AppConfig.php92
-rw-r--r--lib/private/AppFramework/Bootstrap/Coordinator.php8
-rw-r--r--lib/private/AppFramework/Bootstrap/RegistrationContext.php8
-rw-r--r--lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php6
-rw-r--r--lib/private/BackgroundJob/JobList.php13
-rw-r--r--lib/private/Calendar/Manager.php10
-rw-r--r--lib/private/Config/ConfigManager.php38
-rw-r--r--lib/private/Config/Lexicon/CoreConfigLexicon.php22
-rw-r--r--lib/private/Config/UserConfig.php76
-rw-r--r--lib/private/ContextChat/ContentManager.php56
-rw-r--r--lib/private/DB/ConnectionFactory.php38
-rw-r--r--lib/private/Federation/CloudIdManager.php47
-rw-r--r--lib/private/Security/Ip/BruteforceAllowList.php5
-rw-r--r--lib/private/Server.php9
-rw-r--r--lib/private/Updater.php7
16 files changed, 325 insertions, 116 deletions
diff --git a/lib/private/AllConfig.php b/lib/private/AllConfig.php
index 8a6bb5a4723..c80ee52eb0d 100644
--- a/lib/private/AllConfig.php
+++ b/lib/private/AllConfig.php
@@ -7,11 +7,11 @@
*/
namespace OC;
-use NCU\Config\Exceptions\TypeConflictException;
-use NCU\Config\IUserConfig;
-use NCU\Config\ValueType;
use OC\Config\UserConfig;
use OCP\Cache\CappedMemoryCache;
+use OCP\Config\Exceptions\TypeConflictException;
+use OCP\Config\IUserConfig;
+use OCP\Config\ValueType;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\PreConditionNotMetException;
diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php
index 476adbb93e0..0a46109c9f9 100644
--- a/lib/private/AppConfig.php
+++ b/lib/private/AppConfig.php
@@ -11,11 +11,12 @@ namespace OC;
use InvalidArgumentException;
use JsonException;
-use NCU\Config\Lexicon\ConfigLexiconEntry;
-use NCU\Config\Lexicon\ConfigLexiconStrictness;
-use NCU\Config\Lexicon\IConfigLexicon;
use OC\AppFramework\Bootstrap\Coordinator;
use OC\Config\ConfigManager;
+use OCP\Config\Lexicon\Entry;
+use OCP\Config\Lexicon\ILexicon;
+use OCP\Config\Lexicon\Preset;
+use OCP\Config\Lexicon\Strictness;
use OCP\DB\Exception as DBException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Exceptions\AppConfigIncorrectTypeException;
@@ -61,15 +62,16 @@ class AppConfig implements IAppConfig {
private array $valueTypes = []; // type for all config values
private bool $fastLoaded = false;
private bool $lazyLoaded = false;
- /** @var array<string, array{entries: array<string, ConfigLexiconEntry>, aliases: array<string, string>, strictness: ConfigLexiconStrictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */
+ /** @var array<string, array{entries: array<string, Entry>, aliases: array<string, string>, strictness: Strictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */
private array $configLexiconDetails = [];
private bool $ignoreLexiconAliases = false;
-
+ private ?Preset $configLexiconPreset = null;
/** @var ?array<string, string> */
private ?array $appVersionsCache = null;
public function __construct(
protected IDBConnection $connection,
+ protected IConfig $config,
protected LoggerInterface $logger,
protected ICrypto $crypto,
) {
@@ -93,8 +95,9 @@ class AppConfig implements IAppConfig {
* @inheritDoc
*
* @param string $app id of the app
- *
* @return list<string> list of stored config keys
+ * @see searchKeys to not load lazy config keys
+ *
* @since 29.0.0
*/
public function getKeys(string $app): array {
@@ -110,6 +113,32 @@ class AppConfig implements IAppConfig {
* @inheritDoc
*
* @param string $app id of the app
+ * @param string $prefix returns only keys starting with this value
+ * @param bool $lazy TRUE to search in lazy config keys
+ * @return list<string> list of stored config keys
+ * @since 32.0.0
+ */
+ public function searchKeys(string $app, string $prefix = '', bool $lazy = false): array {
+ $this->assertParams($app);
+ $this->loadConfig($app, $lazy);
+ if ($lazy) {
+ $keys = array_keys($this->lazyCache[$app] ?? []);
+ } else {
+ $keys = array_keys($this->fastCache[$app] ?? []);
+ }
+
+ if ($prefix !== '') {
+ $keys = array_filter($keys, static fn (string $key): bool => str_starts_with($key, $prefix));
+ }
+
+ sort($keys);
+ return array_values(array_unique($keys));
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @param string $app id of the app
* @param string $key config key
* @param bool|null $lazy TRUE to search within lazy loaded config, NULL to search within all config
*
@@ -438,9 +467,17 @@ class AppConfig implements IAppConfig {
): string {
$this->assertParams($app, $key, valueType: $type);
$origKey = $key;
- if (!$this->matchAndApplyLexiconDefinition($app, $key, $lazy, $type, $default)) {
- return $default; // returns default if strictness of lexicon is set to WARNING (block and report)
+ $matched = $this->matchAndApplyLexiconDefinition($app, $key, $lazy, $type, $default);
+ if ($default === null) {
+ // there is no logical reason for it to be null
+ throw new \Exception('default cannot be null');
+ }
+
+ // returns default if strictness of lexicon is set to WARNING (block and report)
+ if (!$matched) {
+ return $default;
}
+
$this->loadConfig($app, $lazy);
/**
@@ -1146,7 +1183,8 @@ class AppConfig implements IAppConfig {
*/
public function clearCache(bool $reload = false): void {
$this->lazyLoaded = $this->fastLoaded = false;
- $this->lazyCache = $this->fastCache = $this->valueTypes = [];
+ $this->lazyCache = $this->fastCache = $this->valueTypes = $this->configLexiconDetails = [];
+ $this->configLexiconPreset = null;
if (!$reload) {
return;
@@ -1592,7 +1630,7 @@ class AppConfig implements IAppConfig {
string &$key,
?bool &$lazy = null,
int &$type = self::VALUE_MIXED,
- string &$default = '',
+ ?string &$default = null,
): bool {
if (in_array($key,
[
@@ -1617,7 +1655,7 @@ class AppConfig implements IAppConfig {
return true;
}
- /** @var ConfigLexiconEntry $configValue */
+ /** @var Entry $configValue */
$configValue = $configDetails['entries'][$key];
$type &= ~self::VALUE_SENSITIVE;
@@ -1629,7 +1667,11 @@ class AppConfig implements IAppConfig {
}
$lazy = $configValue->isLazy();
- $default = $configValue->getDefault() ?? $default; // default from Lexicon got priority
+ // only look for default if needed, default from Lexicon got priority
+ if ($default !== null) {
+ $default = $configValue->getDefault($this->getLexiconPreset()) ?? $default;
+ }
+
if ($configValue->isFlagged(self::FLAG_SENSITIVE)) {
$type |= self::VALUE_SENSITIVE;
}
@@ -1643,15 +1685,15 @@ class AppConfig implements IAppConfig {
/**
* manage ConfigLexicon behavior based on strictness set in IConfigLexicon
*
- * @param ConfigLexiconStrictness|null $strictness
+ * @param Strictness|null $strictness
* @param string $line
*
* @return bool TRUE if conflict can be fully ignored, FALSE if action should be not performed
* @throws AppConfigUnknownKeyException if strictness implies exception
- * @see IConfigLexicon::getStrictness()
+ * @see ILexicon::getStrictness()
*/
private function applyLexiconStrictness(
- ?ConfigLexiconStrictness $strictness,
+ ?Strictness $strictness,
string $line = '',
): bool {
if ($strictness === null) {
@@ -1659,12 +1701,12 @@ class AppConfig implements IAppConfig {
}
switch ($strictness) {
- case ConfigLexiconStrictness::IGNORE:
+ case Strictness::IGNORE:
return true;
- case ConfigLexiconStrictness::NOTICE:
+ case Strictness::NOTICE:
$this->logger->notice($line);
return true;
- case ConfigLexiconStrictness::WARNING:
+ case Strictness::WARNING:
$this->logger->warning($line);
return false;
}
@@ -1678,7 +1720,7 @@ class AppConfig implements IAppConfig {
* @param string $appId
* @internal
*
- * @return array{entries: array<string, ConfigLexiconEntry>, aliases: array<string, string>, strictness: ConfigLexiconStrictness}
+ * @return array{entries: array<string, Entry>, aliases: array<string, string>, strictness: Strictness}
*/
public function getConfigDetailsFromLexicon(string $appId): array {
if (!array_key_exists($appId, $this->configLexiconDetails)) {
@@ -1695,14 +1737,14 @@ class AppConfig implements IAppConfig {
$this->configLexiconDetails[$appId] = [
'entries' => $entries,
'aliases' => $aliases,
- 'strictness' => $configLexicon?->getStrictness() ?? ConfigLexiconStrictness::IGNORE
+ 'strictness' => $configLexicon?->getStrictness() ?? Strictness::IGNORE
];
}
return $this->configLexiconDetails[$appId];
}
- private function getLexiconEntry(string $appId, string $key): ?ConfigLexiconEntry {
+ private function getLexiconEntry(string $appId, string $key): ?Entry {
return $this->getConfigDetailsFromLexicon($appId)['entries'][$key] ?? null;
}
@@ -1715,6 +1757,14 @@ class AppConfig implements IAppConfig {
$this->ignoreLexiconAliases = $ignore;
}
+ private function getLexiconPreset(): Preset {
+ if ($this->configLexiconPreset === null) {
+ $this->configLexiconPreset = Preset::tryFrom($this->config->getSystemValueInt(ConfigManager::PRESET_CONFIGKEY, 0)) ?? Preset::NONE;
+ }
+
+ return $this->configLexiconPreset;
+ }
+
/**
* Returns the installed versions of all apps
*
diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php
index 64e3dbfd928..a31dd6a05e1 100644
--- a/lib/private/AppFramework/Bootstrap/Coordinator.php
+++ b/lib/private/AppFramework/Bootstrap/Coordinator.php
@@ -46,7 +46,13 @@ class Coordinator {
}
public function runInitialRegistration(): void {
- $this->registerApps(OC_App::getEnabledApps());
+ $apps = OC_App::getEnabledApps();
+ if (!empty($apps)) {
+ // make sure to also register the core app
+ $apps = ['core', ...$apps];
+ }
+
+ $this->registerApps($apps);
}
public function runLazyRegistration(string $appId): void {
diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
index 95ad129c466..94250aad37b 100644
--- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php
+++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
@@ -10,7 +10,6 @@ declare(strict_types=1);
namespace OC\AppFramework\Bootstrap;
use Closure;
-use NCU\Config\Lexicon\IConfigLexicon;
use OC\Config\Lexicon\CoreConfigLexicon;
use OC\Support\CrashReport\Registry;
use OCP\AppFramework\App;
@@ -23,6 +22,7 @@ use OCP\Calendar\Resource\IBackend as IResourceBackend;
use OCP\Calendar\Room\IBackend as IRoomBackend;
use OCP\Capabilities\ICapability;
use OCP\Collaboration\Reference\IReferenceProvider;
+use OCP\Config\Lexicon\ILexicon;
use OCP\Dashboard\IManager;
use OCP\Dashboard\IWidget;
use OCP\EventDispatcher\IEventDispatcher;
@@ -652,7 +652,7 @@ class RegistrationContext {
}
/**
- * @psalm-param class-string<IConfigLexicon> $configLexiconClass
+ * @psalm-param class-string<ILexicon> $configLexiconClass
*/
public function registerConfigLexicon(string $appId, string $configLexiconClass): void {
$this->configLexiconClasses[$appId] = $configLexiconClass;
@@ -1023,9 +1023,9 @@ class RegistrationContext {
*
* @param string $appId
*
- * @return IConfigLexicon|null
+ * @return ILexicon|null
*/
- public function getConfigLexicon(string $appId): ?IConfigLexicon {
+ public function getConfigLexicon(string $appId): ?ILexicon {
if (!array_key_exists($appId, $this->configLexiconClasses)) {
return null;
}
diff --git a/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php b/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php
index e4571dfc50e..b69b129f798 100644
--- a/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php
+++ b/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php
@@ -15,6 +15,7 @@ use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Middleware;
use OCP\ISession;
use OCP\IUserSession;
+use Psr\Log\LoggerInterface;
use ReflectionMethod;
// Will close the session if the user session is ephemeral.
@@ -24,6 +25,7 @@ class FlowV2EphemeralSessionsMiddleware extends Middleware {
private ISession $session,
private IUserSession $userSession,
private ControllerMethodReflector $reflector,
+ private LoggerInterface $logger,
) {
}
@@ -52,6 +54,10 @@ class FlowV2EphemeralSessionsMiddleware extends Middleware {
return;
}
+ $this->logger->info('Closing user and PHP session for ephemeral session', [
+ 'controller' => $controller::class,
+ 'method' => $methodName,
+ ]);
$this->userSession->logout();
$this->session->close();
}
diff --git a/lib/private/BackgroundJob/JobList.php b/lib/private/BackgroundJob/JobList.php
index 0d88200cff7..c00a51e3851 100644
--- a/lib/private/BackgroundJob/JobList.php
+++ b/lib/private/BackgroundJob/JobList.php
@@ -24,6 +24,9 @@ use function min;
use function strlen;
class JobList implements IJobList {
+ /** @var array<string, int> */
+ protected array $alreadyVisitedParallelBlocked = [];
+
public function __construct(
protected IDBConnection $connection,
protected IConfig $config,
@@ -198,6 +201,12 @@ class JobList implements IJobList {
$job = $this->buildJob($row);
if ($job instanceof IParallelAwareJob && !$job->getAllowParallelRuns() && $this->hasReservedJob(get_class($job))) {
+ if (!isset($this->alreadyVisitedParallelBlocked[get_class($job)])) {
+ $this->alreadyVisitedParallelBlocked[get_class($job)] = $job->getId();
+ } elseif ($this->alreadyVisitedParallelBlocked[get_class($job)] === $job->getId()) {
+ $this->logger->info('Skipped through all jobs and revisited a IParallelAwareJob blocked job again, giving up.', ['app' => 'cron']);
+ return null;
+ }
$this->logger->info('Skipping ' . get_class($job) . ' job with ID ' . $job->getId() . ' because another job with the same class is already running', ['app' => 'cron']);
$update = $this->connection->getQueryBuilder();
@@ -210,6 +219,10 @@ class JobList implements IJobList {
return $this->getNext($onlyTimeSensitive, $jobClasses);
}
+ if ($job !== null && isset($this->alreadyVisitedParallelBlocked[get_class($job)])) {
+ unset($this->alreadyVisitedParallelBlocked[get_class($job)]);
+ }
+
if ($job instanceof \OCP\BackgroundJob\TimedJob) {
$now = $this->timeFactory->getTime();
$nextPossibleRun = $job->getLastRun() + $job->getInterval();
diff --git a/lib/private/Calendar/Manager.php b/lib/private/Calendar/Manager.php
index 0e2a3f5f679..7da1379809d 100644
--- a/lib/private/Calendar/Manager.php
+++ b/lib/private/Calendar/Manager.php
@@ -403,7 +403,10 @@ class Manager implements IManager {
}
if (empty($found)) {
- $this->logger->warning('iMip message event could not be processed because no corresponding event was found in any calendar ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue());
+ $this->logger->warning('iMip message event could not be processed because no corresponding event was found in any calendar', [
+ 'principalUri' => $principalUri,
+ 'eventUid' => $vEvent->{'UID'}->getValue(),
+ ]);
return false;
}
@@ -518,7 +521,10 @@ class Manager implements IManager {
}
if (empty($found)) {
- $this->logger->warning('iMip message event could not be processed because no corresponding event was found in any calendar ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue());
+ $this->logger->warning('iMip message event could not be processed because no corresponding event was found in any calendar', [
+ 'principalUri' => $principalUri,
+ 'eventUid' => $vEvent->{'UID'}->getValue(),
+ ]);
return false;
}
diff --git a/lib/private/Config/ConfigManager.php b/lib/private/Config/ConfigManager.php
index 1980269e2ca..ed516abdcbf 100644
--- a/lib/private/Config/ConfigManager.php
+++ b/lib/private/Config/ConfigManager.php
@@ -9,13 +9,15 @@ declare(strict_types=1);
namespace OC\Config;
use JsonException;
-use NCU\Config\Exceptions\TypeConflictException;
-use NCU\Config\IUserConfig;
-use NCU\Config\Lexicon\ConfigLexiconEntry;
-use NCU\Config\ValueType;
use OC\AppConfig;
use OCP\App\IAppManager;
+use OCP\Config\Exceptions\TypeConflictException;
+use OCP\Config\IUserConfig;
+use OCP\Config\Lexicon\Entry;
+use OCP\Config\Lexicon\Preset;
+use OCP\Config\ValueType;
use OCP\IAppConfig;
+use OCP\IConfig;
use OCP\Server;
use Psr\Log\LoggerInterface;
@@ -25,12 +27,16 @@ use Psr\Log\LoggerInterface;
* @since 32.0.0
*/
class ConfigManager {
+ /** @since 32.0.0 */
+ public const PRESET_CONFIGKEY = 'config_preset';
+
/** @var AppConfig|null $appConfig */
private ?IAppConfig $appConfig = null;
/** @var UserConfig|null $userConfig */
private ?IUserConfig $userConfig = null;
public function __construct(
+ private readonly IConfig $config,
private readonly LoggerInterface $logger,
) {
}
@@ -44,10 +50,11 @@ class ConfigManager {
*
* This method should be mainly called during a new upgrade or when a new app is enabled.
*
- * @see ConfigLexiconEntry
+ * @param string|null $appId when set to NULL the method will be executed for all enabled apps of the instance
+ *
* @internal
* @since 32.0.0
- * @param string|null $appId when set to NULL the method will be executed for all enabled apps of the instance
+ * @see Entry
*/
public function migrateConfigLexiconKeys(?string $appId = null): void {
if ($appId === null) {
@@ -75,6 +82,17 @@ class ConfigManager {
}
/**
+ * store in config.php the new preset
+ * refresh cached preset
+ */
+ public function setLexiconPreset(Preset $preset): void {
+ $this->config->setSystemValue(self::PRESET_CONFIGKEY, $preset->value);
+ $this->loadConfigServices();
+ $this->appConfig->clearCache();
+ $this->userConfig->clearCacheAll();
+ }
+
+ /**
* config services cannot be load at __construct() or install will fail
*/
private function loadConfigServices(): void {
@@ -149,7 +167,7 @@ class ConfigManager {
*
* @throws TypeConflictException if previous value does not fit the expected type
*/
- private function migrateAppConfigValue(string $appId, ConfigLexiconEntry $entry): void {
+ private function migrateAppConfigValue(string $appId, Entry $entry): void {
$value = $this->appConfig->getValueMixed($appId, $entry->getRename(), lazy: null);
switch ($entry->getValueType()) {
case ValueType::STRING:
@@ -179,7 +197,7 @@ class ConfigManager {
*
* @throws TypeConflictException if previous value does not fit the expected type
*/
- private function migrateUserConfigValue(string $userId, string $appId, ConfigLexiconEntry $entry): void {
+ private function migrateUserConfigValue(string $userId, string $appId, Entry $entry): void {
$value = $this->userConfig->getValueMixed($userId, $appId, $entry->getRename(), lazy: null);
switch ($entry->getValueType()) {
case ValueType::STRING:
@@ -220,7 +238,7 @@ class ConfigManager {
return (float)$value;
}
- public function convertToBool(string $value, ?ConfigLexiconEntry $entry = null): bool {
+ public function convertToBool(string $value, ?Entry $entry = null): bool {
if (in_array(strtolower($value), ['true', '1', 'on', 'yes'])) {
$valueBool = true;
} elseif (in_array(strtolower($value), ['false', '0', 'off', 'no'])) {
@@ -228,7 +246,7 @@ class ConfigManager {
} else {
throw new TypeConflictException('Value cannot be converted to boolean');
}
- if ($entry?->hasOption(ConfigLexiconEntry::RENAME_INVERT_BOOLEAN) === true) {
+ if ($entry?->hasOption(Entry::RENAME_INVERT_BOOLEAN) === true) {
$valueBool = !$valueBool;
}
diff --git a/lib/private/Config/Lexicon/CoreConfigLexicon.php b/lib/private/Config/Lexicon/CoreConfigLexicon.php
index 34a0b883c54..de84a58131c 100644
--- a/lib/private/Config/Lexicon/CoreConfigLexicon.php
+++ b/lib/private/Config/Lexicon/CoreConfigLexicon.php
@@ -8,36 +8,36 @@ declare(strict_types=1);
namespace OC\Config\Lexicon;
-use NCU\Config\Lexicon\ConfigLexiconEntry;
-use NCU\Config\Lexicon\ConfigLexiconStrictness;
-use NCU\Config\Lexicon\IConfigLexicon;
-use NCU\Config\ValueType;
+use OCP\Config\Lexicon\Entry;
+use OCP\Config\Lexicon\ILexicon;
+use OCP\Config\Lexicon\Strictness;
+use OCP\Config\ValueType;
/**
* ConfigLexicon for 'core' app/user configs
*/
-class CoreConfigLexicon implements IConfigLexicon {
- public function getStrictness(): ConfigLexiconStrictness {
- return ConfigLexiconStrictness::IGNORE;
+class CoreConfigLexicon implements ILexicon {
+ public function getStrictness(): Strictness {
+ return Strictness::IGNORE;
}
/**
* @inheritDoc
- * @return ConfigLexiconEntry[]
+ * @return Entry[]
*/
public function getAppConfigs(): array {
return [
- new ConfigLexiconEntry('lastcron', ValueType::INT, 0, 'timestamp of last cron execution'),
+ new Entry('lastcron', ValueType::INT, 0, 'timestamp of last cron execution'),
];
}
/**
* @inheritDoc
- * @return ConfigLexiconEntry[]
+ * @return Entry[]
*/
public function getUserConfigs(): array {
return [
- new ConfigLexiconEntry('lang', ValueType::STRING, null, 'language'),
+ new Entry('lang', ValueType::STRING, null, 'language'),
];
}
}
diff --git a/lib/private/Config/UserConfig.php b/lib/private/Config/UserConfig.php
index 7848f1728e3..04ba0e29db0 100644
--- a/lib/private/Config/UserConfig.php
+++ b/lib/private/Config/UserConfig.php
@@ -11,14 +11,16 @@ namespace OC\Config;
use Generator;
use InvalidArgumentException;
use JsonException;
-use NCU\Config\Exceptions\IncorrectTypeException;
-use NCU\Config\Exceptions\TypeConflictException;
-use NCU\Config\Exceptions\UnknownKeyException;
-use NCU\Config\IUserConfig;
-use NCU\Config\Lexicon\ConfigLexiconEntry;
-use NCU\Config\Lexicon\ConfigLexiconStrictness;
-use NCU\Config\ValueType;
use OC\AppFramework\Bootstrap\Coordinator;
+use OCP\Config\Exceptions\IncorrectTypeException;
+use OCP\Config\Exceptions\TypeConflictException;
+use OCP\Config\Exceptions\UnknownKeyException;
+use OCP\Config\IUserConfig;
+use OCP\Config\Lexicon\Entry;
+use OCP\Config\Lexicon\ILexicon;
+use OCP\Config\Lexicon\Preset;
+use OCP\Config\Lexicon\Strictness;
+use OCP\Config\ValueType;
use OCP\DB\Exception as DBException;
use OCP\DB\IResult;
use OCP\DB\QueryBuilder\IQueryBuilder;
@@ -63,9 +65,10 @@ class UserConfig implements IUserConfig {
private array $fastLoaded = [];
/** @var array<string, boolean> ['user_id' => bool] */
private array $lazyLoaded = [];
- /** @var array<string, array{entries: array<string, ConfigLexiconEntry>, aliases: array<string, string>, strictness: ConfigLexiconStrictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */
+ /** @var array<string, array{entries: array<string, Entry>, aliases: array<string, string>, strictness: Strictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */
private array $configLexiconDetails = [];
private bool $ignoreLexiconAliases = false;
+ private ?Preset $configLexiconPreset = null;
public function __construct(
protected IDBConnection $connection,
@@ -721,10 +724,17 @@ class UserConfig implements IUserConfig {
): string {
$this->assertParams($userId, $app, $key);
$origKey = $key;
- if (!$this->matchAndApplyLexiconDefinition($userId, $app, $key, $lazy, $type, default: $default)) {
- // returns default if strictness of lexicon is set to WARNING (block and report)
+ $matched = $this->matchAndApplyLexiconDefinition($userId, $app, $key, $lazy, $type, default: $default);
+ if ($default === null) {
+ // there is no logical reason for it to be null
+ throw new \Exception('default cannot be null');
+ }
+
+ // returns default if strictness of lexicon is set to WARNING (block and report)
+ if (!$matched) {
return $default;
}
+
$this->loadConfig($userId, $lazy);
/**
@@ -1625,7 +1635,8 @@ class UserConfig implements IUserConfig {
*/
public function clearCacheAll(): void {
$this->lazyLoaded = $this->fastLoaded = [];
- $this->lazyCache = $this->fastCache = $this->valueDetails = [];
+ $this->lazyCache = $this->fastCache = $this->valueDetails = $this->configLexiconDetails = [];
+ $this->configLexiconPreset = null;
}
/**
@@ -1886,7 +1897,7 @@ class UserConfig implements IUserConfig {
?bool &$lazy = null,
ValueType &$type = ValueType::MIXED,
int &$flags = 0,
- string &$default = '',
+ ?string &$default = null,
): bool {
$configDetails = $this->getConfigDetailsFromLexicon($app);
if (array_key_exists($key, $configDetails['aliases']) && !$this->ignoreLexiconAliases) {
@@ -1903,7 +1914,7 @@ class UserConfig implements IUserConfig {
return true;
}
- /** @var ConfigLexiconEntry $configValue */
+ /** @var Entry $configValue */
$configValue = $configDetails['entries'][$key];
if ($type === ValueType::MIXED) {
// we overwrite if value was requested as mixed
@@ -1924,8 +1935,10 @@ class UserConfig implements IUserConfig {
return true;
}
- // default from Lexicon got priority but it can still be overwritten by admin
- $default = $this->getSystemDefault($app, $configValue) ?? $configValue->getDefault() ?? $default;
+ // only look for default if needed, default from Lexicon got priority if not overwritten by admin
+ if ($default !== null) {
+ $default = $this->getSystemDefault($app, $configValue) ?? $configValue->getDefault($this->getLexiconPreset()) ?? $default;
+ }
// returning false will make get() returning $default and set() not changing value in database
return !$enforcedValue;
@@ -1942,7 +1955,7 @@ class UserConfig implements IUserConfig {
*
* The entry is converted to string to fit the expected type when managing default value
*/
- private function getSystemDefault(string $appId, ConfigLexiconEntry $configValue): ?string {
+ private function getSystemDefault(string $appId, Entry $configValue): ?string {
$default = $this->config->getSystemValue('lexicon.default.userconfig', [])[$appId][$configValue->getKey()] ?? null;
if ($default === null) {
// no system default, using default default.
@@ -1955,28 +1968,28 @@ class UserConfig implements IUserConfig {
/**
* manage ConfigLexicon behavior based on strictness set in IConfigLexicon
*
- * @see IConfigLexicon::getStrictness()
- * @param ConfigLexiconStrictness|null $strictness
+ * @param Strictness|null $strictness
* @param string $line
*
* @return bool TRUE if conflict can be fully ignored
* @throws UnknownKeyException
+ *@see ILexicon::getStrictness()
*/
- private function applyLexiconStrictness(?ConfigLexiconStrictness $strictness, string $line = ''): bool {
+ private function applyLexiconStrictness(?Strictness $strictness, string $line = ''): bool {
if ($strictness === null) {
return true;
}
switch ($strictness) {
- case ConfigLexiconStrictness::IGNORE:
+ case Strictness::IGNORE:
return true;
- case ConfigLexiconStrictness::NOTICE:
+ case Strictness::NOTICE:
$this->logger->notice($line);
return true;
- case ConfigLexiconStrictness::WARNING:
+ case Strictness::WARNING:
$this->logger->warning($line);
return false;
- case ConfigLexiconStrictness::EXCEPTION:
+ case Strictness::EXCEPTION:
throw new UnknownKeyException($line);
}
@@ -1987,9 +2000,10 @@ class UserConfig implements IUserConfig {
* extract details from registered $appId's config lexicon
*
* @param string $appId
- * @internal
*
- * @return array{entries: array<string, ConfigLexiconEntry>, aliases: array<string, string>, strictness: ConfigLexiconStrictness}
+ * @return array{entries: array<string, Entry>, aliases: array<string, string>, strictness: Strictness}
+ *@internal
+ *
*/
public function getConfigDetailsFromLexicon(string $appId): array {
if (!array_key_exists($appId, $this->configLexiconDetails)) {
@@ -2006,14 +2020,14 @@ class UserConfig implements IUserConfig {
$this->configLexiconDetails[$appId] = [
'entries' => $entries,
'aliases' => $aliases,
- 'strictness' => $configLexicon?->getStrictness() ?? ConfigLexiconStrictness::IGNORE
+ 'strictness' => $configLexicon?->getStrictness() ?? Strictness::IGNORE
];
}
return $this->configLexiconDetails[$appId];
}
- private function getLexiconEntry(string $appId, string $key): ?ConfigLexiconEntry {
+ private function getLexiconEntry(string $appId, string $key): ?Entry {
return $this->getConfigDetailsFromLexicon($appId)['entries'][$key] ?? null;
}
@@ -2025,4 +2039,12 @@ class UserConfig implements IUserConfig {
public function ignoreLexiconAliases(bool $ignore): void {
$this->ignoreLexiconAliases = $ignore;
}
+
+ private function getLexiconPreset(): Preset {
+ if ($this->configLexiconPreset === null) {
+ $this->configLexiconPreset = Preset::tryFrom($this->config->getSystemValueInt(ConfigManager::PRESET_CONFIGKEY, 0)) ?? Preset::NONE;
+ }
+
+ return $this->configLexiconPreset;
+ }
}
diff --git a/lib/private/ContextChat/ContentManager.php b/lib/private/ContextChat/ContentManager.php
new file mode 100644
index 00000000000..3324ce6c700
--- /dev/null
+++ b/lib/private/ContextChat/ContentManager.php
@@ -0,0 +1,56 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024-2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\ContextChat;
+
+use OCA\ContextChat\Public\ContentManager as ContextChatContentManager;
+use OCP\ContextChat\IContentManager;
+
+class ContentManager implements IContentManager {
+ public function __construct(
+ private ?ContextChatContentManager $contentManager,
+ ) {
+ }
+
+ public function isContextChatAvailable(): bool {
+ return $this->contentManager !== null;
+ }
+
+ public function registerContentProvider(string $appId, string $providerId, string $providerClass): void {
+ $this->contentManager?->registerContentProvider($appId, $providerId, $providerClass);
+ }
+
+ public function collectAllContentProviders(): void {
+ $this->contentManager?->collectAllContentProviders();
+ }
+
+ public function submitContent(string $appId, array $items): void {
+ $this->contentManager?->submitContent($appId, $items);
+ }
+
+ public function updateAccess(string $appId, string $providerId, string $itemId, string $op, array $userIds): void {
+ $this->contentManager?->updateAccess($appId, $providerId, $itemId, $op, $userIds);
+ }
+
+ public function updateAccessProvider(string $appId, string $providerId, string $op, array $userIds): void {
+ $this->contentManager?->updateAccessProvider($appId, $providerId, $op, $userIds);
+ }
+
+ public function updateAccessDeclarative(string $appId, string $providerId, string $itemId, array $userIds): void {
+ $this->contentManager?->updateAccessDeclarative($appId, $providerId, $itemId, $op, $userIds);
+ }
+
+ public function deleteProvider(string $appId, string $providerId): void {
+ $this->contentManager?->deleteProvider($appId, $providerId);
+ }
+
+ public function deleteContent(string $appId, string $providerId, array $itemIds): void {
+ $this->contentManager?->deleteContent($appId, $providerId, $itemIds);
+ }
+}
diff --git a/lib/private/DB/ConnectionFactory.php b/lib/private/DB/ConnectionFactory.php
index 4d286cb3068..d9b80b81992 100644
--- a/lib/private/DB/ConnectionFactory.php
+++ b/lib/private/DB/ConnectionFactory.php
@@ -121,21 +121,9 @@ class ConnectionFactory {
case 'oci':
$eventManager->addEventSubscriber(new OracleSessionInit);
- // the driverOptions are unused in dbal and need to be mapped to the parameters
- if (isset($connectionParams['driverOptions'])) {
- $connectionParams = array_merge($connectionParams, $connectionParams['driverOptions']);
- }
- $host = $connectionParams['host'];
- $port = $connectionParams['port'] ?? null;
- $dbName = $connectionParams['dbname'];
-
- // we set the connect string as dbname and unset the host to coerce doctrine into using it as connect string
- if ($host === '') {
- $connectionParams['dbname'] = $dbName; // use dbname as easy connect name
- } else {
- $connectionParams['dbname'] = '//' . $host . (!empty($port) ? ":{$port}" : '') . '/' . $dbName;
- }
- unset($connectionParams['host']);
+ $connectionParams = $this->forceConnectionStringOracle($connectionParams);
+ $connectionParams['primary'] = $this->forceConnectionStringOracle($connectionParams['primary']);
+ $connectionParams['replica'] = array_map([$this, 'forceConnectionStringOracle'], $connectionParams['replica']);
break;
case 'sqlite3':
@@ -265,4 +253,24 @@ class ConnectionFactory {
return $params;
}
+
+ protected function forceConnectionStringOracle(array $connectionParams): array {
+ // the driverOptions are unused in dbal and need to be mapped to the parameters
+ if (isset($connectionParams['driverOptions'])) {
+ $connectionParams = array_merge($connectionParams, $connectionParams['driverOptions']);
+ }
+ $host = $connectionParams['host'];
+ $port = $connectionParams['port'] ?? null;
+ $dbName = $connectionParams['dbname'];
+
+ // we set the connect string as dbname and unset the host to coerce doctrine into using it as connect string
+ if ($host === '') {
+ $connectionParams['dbname'] = $dbName; // use dbname as easy connect name
+ } else {
+ $connectionParams['dbname'] = '//' . $host . (!empty($port) ? ":{$port}" : '') . '/' . $dbName;
+ }
+ unset($connectionParams['host']);
+
+ return $connectionParams;
+ }
}
diff --git a/lib/private/Federation/CloudIdManager.php b/lib/private/Federation/CloudIdManager.php
index 7e7adda3d39..c599d9046a6 100644
--- a/lib/private/Federation/CloudIdManager.php
+++ b/lib/private/Federation/CloudIdManager.php
@@ -14,6 +14,7 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Federation\ICloudId;
use OCP\Federation\ICloudIdManager;
+use OCP\Federation\ICloudIdResolver;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\IURLGenerator;
@@ -21,27 +22,19 @@ use OCP\IUserManager;
use OCP\User\Events\UserChangedEvent;
class CloudIdManager implements ICloudIdManager {
- /** @var IManager */
- private $contactsManager;
- /** @var IURLGenerator */
- private $urlGenerator;
- /** @var IUserManager */
- private $userManager;
private ICache $memCache;
private ICache $displayNameCache;
- /** @var array[] */
private array $cache = [];
+ /** @var ICloudIdResolver[] */
+ private array $cloudIdResolvers = [];
public function __construct(
- IManager $contactsManager,
- IURLGenerator $urlGenerator,
- IUserManager $userManager,
ICacheFactory $cacheFactory,
IEventDispatcher $eventDispatcher,
+ private IManager $contactsManager,
+ private IURLGenerator $urlGenerator,
+ private IUserManager $userManager,
) {
- $this->contactsManager = $contactsManager;
- $this->urlGenerator = $urlGenerator;
- $this->userManager = $userManager;
$this->memCache = $cacheFactory->createDistributed('cloud_id_');
$this->displayNameCache = $cacheFactory->createDistributed('cloudid_name_');
$eventDispatcher->addListener(UserChangedEvent::class, [$this, 'handleUserEvent']);
@@ -81,6 +74,12 @@ class CloudIdManager implements ICloudIdManager {
public function resolveCloudId(string $cloudId): ICloudId {
// TODO magic here to get the url and user instead of just splitting on @
+ foreach ($this->cloudIdResolvers as $resolver) {
+ if ($resolver->isValidCloudId($cloudId)) {
+ return $resolver->resolveCloudId($cloudId);
+ }
+ }
+
if (!$this->isValidCloudId($cloudId)) {
throw new \InvalidArgumentException('Invalid cloud id');
}
@@ -251,6 +250,26 @@ class CloudIdManager implements ICloudIdManager {
* @return bool
*/
public function isValidCloudId(string $cloudId): bool {
- return str_contains($cloudId, '@');
+ foreach ($this->cloudIdResolvers as $resolver) {
+ if ($resolver->isValidCloudId($cloudId)) {
+ return true;
+ }
+ }
+
+ return strpos($cloudId, '@') !== false;
+ }
+
+ public function createCloudId(string $id, string $user, string $remote, ?string $displayName = null): ICloudId {
+ return new CloudId($id, $user, $remote, $displayName);
+ }
+
+ public function registerCloudIdResolver(ICloudIdResolver $resolver): void {
+ array_unshift($this->cloudIdResolvers, $resolver);
+ }
+
+ public function unregisterCloudIdResolver(ICloudIdResolver $resolver): void {
+ if (($key = array_search($resolver, $this->cloudIdResolvers)) !== false) {
+ array_splice($this->cloudIdResolvers, $key, 1);
+ }
}
}
diff --git a/lib/private/Security/Ip/BruteforceAllowList.php b/lib/private/Security/Ip/BruteforceAllowList.php
index cc4f0ceebe5..fb837690a7b 100644
--- a/lib/private/Security/Ip/BruteforceAllowList.php
+++ b/lib/private/Security/Ip/BruteforceAllowList.php
@@ -36,10 +36,7 @@ class BruteforceAllowList {
return false;
}
- $keys = $this->appConfig->getKeys('bruteForce');
- $keys = array_filter($keys, static fn ($key): bool => str_starts_with($key, 'whitelist_'));
-
- foreach ($keys as $key) {
+ foreach ($this->appConfig->searchKeys('bruteForce', 'whitelist_') as $key) {
$rangeString = $this->appConfig->getValueString('bruteForce', $key);
try {
$range = $this->factory->rangeFromString($rangeString);
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 4b88a446405..171fee2afa1 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -8,7 +8,6 @@
namespace OC;
use bantu\IniGetWrapper\IniGetWrapper;
-use NCU\Config\IUserConfig;
use NCU\Security\Signature\ISignatureManager;
use OC\Accounts\AccountManager;
use OC\App\AppManager;
@@ -139,6 +138,7 @@ use OCP\BackgroundJob\IJobList;
use OCP\Collaboration\Reference\IReferenceManager;
use OCP\Command\IBus;
use OCP\Comments\ICommentsManager;
+use OCP\Config\IUserConfig;
use OCP\Contacts\ContactsMenu\IActionFactory;
use OCP\Contacts\ContactsMenu\IContactsStore;
use OCP\Defaults;
@@ -163,7 +163,6 @@ use OCP\Files\Storage\IStorageFactory;
use OCP\Files\Template\ITemplateManager;
use OCP\FilesMetadata\IFilesMetadataManager;
use OCP\FullTextSearch\IFullTextSearchManager;
-use OCP\GlobalScale\IConfig;
use OCP\Group\ISubAdmin;
use OCP\Http\Client\IClientService;
use OCP\IAppConfig;
@@ -277,6 +276,8 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerAlias(\OCP\Contacts\IManager::class, \OC\ContactsManager::class);
+ $this->registerAlias(\OCP\ContextChat\IContentManager::class, \OC\ContextChat\ContentManager::class);
+
$this->registerAlias(\OCP\DirectEditing\IManager::class, \OC\DirectEditing\Manager::class);
$this->registerAlias(ITemplateManager::class, TemplateManager::class);
$this->registerAlias(\OCP\Template\ITemplateManager::class, \OC\Template\TemplateManager::class);
@@ -1159,11 +1160,11 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService(ICloudIdManager::class, function (ContainerInterface $c) {
return new CloudIdManager(
+ $c->get(ICacheFactory::class),
+ $c->get(IEventDispatcher::class),
$c->get(\OCP\Contacts\IManager::class),
$c->get(IURLGenerator::class),
$c->get(IUserManager::class),
- $c->get(ICacheFactory::class),
- $c->get(IEventDispatcher::class),
);
});
diff --git a/lib/private/Updater.php b/lib/private/Updater.php
index 6495bad2da2..9cd33863612 100644
--- a/lib/private/Updater.php
+++ b/lib/private/Updater.php
@@ -385,6 +385,13 @@ class Updater extends BasicEmitter {
if ($this->installer->isUpdateAvailable($app)) {
$this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
$this->installer->updateAppstoreApp($app);
+ } elseif (!empty($previousEnableStates)) {
+ /**
+ * When updating a local app we still need to run updateApp
+ * so that repair steps and migrations are correctly executed
+ * Ref: https://github.com/nextcloud/server/issues/53985
+ */
+ \OC_App::updateApp($app);
}
$this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);