aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/Config/UserConfig.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/Config/UserConfig.php')
-rw-r--r--lib/private/Config/UserConfig.php91
1 files changed, 81 insertions, 10 deletions
diff --git a/lib/private/Config/UserConfig.php b/lib/private/Config/UserConfig.php
index 77a86a5e1c7..f8c59a13d3d 100644
--- a/lib/private/Config/UserConfig.php
+++ b/lib/private/Config/UserConfig.php
@@ -25,6 +25,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\Security\ICrypto;
+use OCP\Server;
use Psr\Log\LoggerInterface;
/**
@@ -62,8 +63,9 @@ class UserConfig implements IUserConfig {
private array $fastLoaded = [];
/** @var array<string, boolean> ['user_id' => bool] */
private array $lazyLoaded = [];
- /** @var array<array-key, array{entries: array<array-key, ConfigLexiconEntry>, strictness: ConfigLexiconStrictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */
+ /** @var array<string, array{entries: array<string, ConfigLexiconEntry>, aliases: array<string, string>, strictness: ConfigLexiconStrictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */
private array $configLexiconDetails = [];
+ private bool $ignoreLexiconAliases = false;
public function __construct(
protected IDBConnection $connection,
@@ -150,6 +152,7 @@ class UserConfig implements IUserConfig {
public function hasKey(string $userId, string $app, string $key, ?bool $lazy = false): bool {
$this->assertParams($userId, $app, $key);
$this->loadConfig($userId, $lazy);
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
if ($lazy === null) {
$appCache = $this->getValues($userId, $app);
@@ -178,6 +181,7 @@ class UserConfig implements IUserConfig {
public function isSensitive(string $userId, string $app, string $key, ?bool $lazy = false): bool {
$this->assertParams($userId, $app, $key);
$this->loadConfig($userId, $lazy);
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
if (!isset($this->valueDetails[$userId][$app][$key])) {
throw new UnknownKeyException('unknown config key');
@@ -201,6 +205,7 @@ class UserConfig implements IUserConfig {
public function isIndexed(string $userId, string $app, string $key, ?bool $lazy = false): bool {
$this->assertParams($userId, $app, $key);
$this->loadConfig($userId, $lazy);
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
if (!isset($this->valueDetails[$userId][$app][$key])) {
throw new UnknownKeyException('unknown config key');
@@ -222,6 +227,8 @@ class UserConfig implements IUserConfig {
* @since 31.0.0
*/
public function isLazy(string $userId, string $app, string $key): bool {
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
+
// there is a huge probability the non-lazy config are already loaded
// meaning that we can start by only checking if a current non-lazy key exists
if ($this->hasKey($userId, $app, $key, false)) {
@@ -349,6 +356,7 @@ class UserConfig implements IUserConfig {
?array $userIds = null,
): array {
$this->assertParams('', $app, $key, allowEmptyUser: true);
+ $this->matchAndApplyLexiconDefinition('', $app, $key);
$qb = $this->connection->getQueryBuilder();
$qb->select('userid', 'configvalue', 'type')
@@ -464,6 +472,7 @@ class UserConfig implements IUserConfig {
*/
private function searchUsersByTypedValue(string $app, string $key, string|array $value, bool $caseInsensitive = false): Generator {
$this->assertParams('', $app, $key, allowEmptyUser: true);
+ $this->matchAndApplyLexiconDefinition('', $app, $key);
$qb = $this->connection->getQueryBuilder();
$qb->from('preferences');
@@ -541,6 +550,7 @@ class UserConfig implements IUserConfig {
string $default = '',
?bool $lazy = false,
): string {
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
try {
$lazy ??= $this->isLazy($userId, $app, $key);
} catch (UnknownKeyException) {
@@ -710,6 +720,7 @@ class UserConfig implements IUserConfig {
ValueType $type,
): 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)
return $default;
@@ -746,6 +757,15 @@ class UserConfig implements IUserConfig {
}
$this->decryptSensitiveValue($userId, $app, $key, $value);
+
+ // in case the key was modified while running matchAndApplyLexiconDefinition() we are
+ // interested to check options in case a modification of the value is needed
+ // ie inverting value from previous key when using lexicon option RENAME_INVERT_BOOLEAN
+ if ($origKey !== $key && $type === ValueType::BOOL) {
+ $configManager = Server::get(ConfigManager::class);
+ $value = ($configManager->convertToBool($value, $this->getLexiconEntry($app, $key))) ? '1' : '0';
+ }
+
return $value;
}
@@ -764,6 +784,7 @@ class UserConfig implements IUserConfig {
public function getValueType(string $userId, string $app, string $key, ?bool $lazy = null): ValueType {
$this->assertParams($userId, $app, $key);
$this->loadConfig($userId, $lazy);
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
if (!isset($this->valueDetails[$userId][$app][$key]['type'])) {
throw new UnknownKeyException('unknown config key');
@@ -788,6 +809,7 @@ class UserConfig implements IUserConfig {
public function getValueFlags(string $userId, string $app, string $key, bool $lazy = false): int {
$this->assertParams($userId, $app, $key);
$this->loadConfig($userId, $lazy);
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
if (!isset($this->valueDetails[$userId][$app][$key])) {
throw new UnknownKeyException('unknown config key');
@@ -1045,6 +1067,11 @@ class UserConfig implements IUserConfig {
int $flags,
ValueType $type,
): bool {
+ // Primary email addresses are always(!) expected to be lowercase
+ if ($app === 'settings' && $key === 'email') {
+ $value = strtolower($value);
+ }
+
$this->assertParams($userId, $app, $key);
if (!$this->matchAndApplyLexiconDefinition($userId, $app, $key, $lazy, $type, $flags)) {
// returns false as database is not updated
@@ -1197,8 +1224,8 @@ class UserConfig implements IUserConfig {
public function updateType(string $userId, string $app, string $key, ValueType $type = ValueType::MIXED): bool {
$this->assertParams($userId, $app, $key);
$this->loadConfigAll($userId);
- // confirm key exists
- $this->isLazy($userId, $app, $key);
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
+ $this->isLazy($userId, $app, $key); // confirm key exists
$update = $this->connection->getQueryBuilder();
$update->update('preferences')
@@ -1227,6 +1254,7 @@ class UserConfig implements IUserConfig {
public function updateSensitive(string $userId, string $app, string $key, bool $sensitive): bool {
$this->assertParams($userId, $app, $key);
$this->loadConfigAll($userId);
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
try {
if ($sensitive === $this->isSensitive($userId, $app, $key, null)) {
@@ -1282,6 +1310,8 @@ class UserConfig implements IUserConfig {
*/
public function updateGlobalSensitive(string $app, string $key, bool $sensitive): void {
$this->assertParams('', $app, $key, allowEmptyUser: true);
+ $this->matchAndApplyLexiconDefinition('', $app, $key);
+
foreach (array_keys($this->getValuesByUsers($app, $key)) as $userId) {
try {
$this->updateSensitive($userId, $app, $key, $sensitive);
@@ -1311,6 +1341,7 @@ class UserConfig implements IUserConfig {
public function updateIndexed(string $userId, string $app, string $key, bool $indexed): bool {
$this->assertParams($userId, $app, $key);
$this->loadConfigAll($userId);
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
try {
if ($indexed === $this->isIndexed($userId, $app, $key, null)) {
@@ -1366,6 +1397,8 @@ class UserConfig implements IUserConfig {
*/
public function updateGlobalIndexed(string $app, string $key, bool $indexed): void {
$this->assertParams('', $app, $key, allowEmptyUser: true);
+ $this->matchAndApplyLexiconDefinition('', $app, $key);
+
foreach (array_keys($this->getValuesByUsers($app, $key)) as $userId) {
try {
$this->updateIndexed($userId, $app, $key, $indexed);
@@ -1392,6 +1425,7 @@ class UserConfig implements IUserConfig {
public function updateLazy(string $userId, string $app, string $key, bool $lazy): bool {
$this->assertParams($userId, $app, $key);
$this->loadConfigAll($userId);
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
try {
if ($lazy === $this->isLazy($userId, $app, $key)) {
@@ -1426,6 +1460,7 @@ class UserConfig implements IUserConfig {
*/
public function updateGlobalLazy(string $app, string $key, bool $lazy): void {
$this->assertParams('', $app, $key, allowEmptyUser: true);
+ $this->matchAndApplyLexiconDefinition('', $app, $key);
$update = $this->connection->getQueryBuilder();
$update->update('preferences')
@@ -1451,6 +1486,8 @@ class UserConfig implements IUserConfig {
public function getDetails(string $userId, string $app, string $key): array {
$this->assertParams($userId, $app, $key);
$this->loadConfigAll($userId);
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
+
$lazy = $this->isLazy($userId, $app, $key);
if ($lazy) {
@@ -1498,6 +1535,8 @@ class UserConfig implements IUserConfig {
*/
public function deleteUserConfig(string $userId, string $app, string $key): void {
$this->assertParams($userId, $app, $key);
+ $this->matchAndApplyLexiconDefinition($userId, $app, $key);
+
$qb = $this->connection->getQueryBuilder();
$qb->delete('preferences')
->where($qb->expr()->eq('userid', $qb->createNamedParameter($userId)))
@@ -1520,6 +1559,8 @@ class UserConfig implements IUserConfig {
*/
public function deleteKey(string $app, string $key): void {
$this->assertParams('', $app, $key, allowEmptyUser: true);
+ $this->matchAndApplyLexiconDefinition('', $app, $key);
+
$qb = $this->connection->getQueryBuilder();
$qb->delete('preferences')
->where($qb->expr()->eq('appid', $qb->createNamedParameter($app)))
@@ -1538,6 +1579,7 @@ class UserConfig implements IUserConfig {
*/
public function deleteApp(string $app): void {
$this->assertParams('', $app, allowEmptyUser: true);
+
$qb = $this->connection->getQueryBuilder();
$qb->delete('preferences')
->where($qb->expr()->eq('appid', $qb->createNamedParameter($app)));
@@ -1830,7 +1872,8 @@ class UserConfig implements IUserConfig {
}
/**
- * match and apply current use of config values with defined lexicon
+ * Match and apply current use of config values with defined lexicon.
+ * Set $lazy to NULL only if only interested into checking that $key is alias.
*
* @throws UnknownKeyException
* @throws TypeConflictException
@@ -1839,17 +1882,27 @@ class UserConfig implements IUserConfig {
private function matchAndApplyLexiconDefinition(
string $userId,
string $app,
- string $key,
- bool &$lazy,
- ValueType &$type,
+ string &$key,
+ ?bool &$lazy = null,
+ ValueType &$type = ValueType::MIXED,
int &$flags = 0,
string &$default = '',
): bool {
$configDetails = $this->getConfigDetailsFromLexicon($app);
+ if (array_key_exists($key, $configDetails['aliases']) && !$this->ignoreLexiconAliases) {
+ // in case '$rename' is set in ConfigLexiconEntry, we use the new config key
+ $key = $configDetails['aliases'][$key];
+ }
+
if (!array_key_exists($key, $configDetails['entries'])) {
return $this->applyLexiconStrictness($configDetails['strictness'], 'The user config key ' . $app . '/' . $key . ' is not defined in the config lexicon');
}
+ // if lazy is NULL, we ignore all check on the type/lazyness/default from Lexicon
+ if ($lazy === null) {
+ return true;
+ }
+
/** @var ConfigLexiconEntry $configValue */
$configValue = $configDetails['entries'][$key];
if ($type === ValueType::MIXED) {
@@ -1934,24 +1987,42 @@ class UserConfig implements IUserConfig {
* extract details from registered $appId's config lexicon
*
* @param string $appId
+ * @internal
*
- * @return array{entries: array<array-key, ConfigLexiconEntry>, strictness: ConfigLexiconStrictness}
+ * @return array{entries: array<string, ConfigLexiconEntry>, aliases: array<string, string>, strictness: ConfigLexiconStrictness}
*/
- private function getConfigDetailsFromLexicon(string $appId): array {
+ public function getConfigDetailsFromLexicon(string $appId): array {
if (!array_key_exists($appId, $this->configLexiconDetails)) {
- $entries = [];
+ $entries = $aliases = [];
$bootstrapCoordinator = \OCP\Server::get(Coordinator::class);
$configLexicon = $bootstrapCoordinator->getRegistrationContext()?->getConfigLexicon($appId);
foreach ($configLexicon?->getUserConfigs() ?? [] as $configEntry) {
$entries[$configEntry->getKey()] = $configEntry;
+ if ($configEntry->getRename() !== null) {
+ $aliases[$configEntry->getRename()] = $configEntry->getKey();
+ }
}
$this->configLexiconDetails[$appId] = [
'entries' => $entries,
+ 'aliases' => $aliases,
'strictness' => $configLexicon?->getStrictness() ?? ConfigLexiconStrictness::IGNORE
];
}
return $this->configLexiconDetails[$appId];
}
+
+ private function getLexiconEntry(string $appId, string $key): ?ConfigLexiconEntry {
+ return $this->getConfigDetailsFromLexicon($appId)['entries'][$key] ?? null;
+ }
+
+ /**
+ * if set to TRUE, ignore aliases defined in Config Lexicon during the use of the methods of this class
+ *
+ * @internal
+ */
+ public function ignoreLexiconAliases(bool $ignore): void {
+ $this->ignoreLexiconAliases = $ignore;
+ }
}