12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541 |
- <?php
- declare(strict_types=1);
- /**
- * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
- * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
- * SPDX-License-Identifier: AGPL-3.0-only
- */
- namespace OC;
- use InvalidArgumentException;
- use JsonException;
- use OCP\DB\Exception as DBException;
- use OCP\DB\QueryBuilder\IQueryBuilder;
- use OCP\Exceptions\AppConfigIncorrectTypeException;
- use OCP\Exceptions\AppConfigTypeConflictException;
- use OCP\Exceptions\AppConfigUnknownKeyException;
- use OCP\IAppConfig;
- use OCP\IConfig;
- use OCP\IDBConnection;
- use OCP\Security\ICrypto;
- use Psr\Log\LoggerInterface;
- /**
- * This class provides an easy way for apps to store config values in the
- * database.
- *
- * **Note:** since 29.0.0, it supports **lazy loading**
- *
- * ### What is lazy loading ?
- * In order to avoid loading useless config values into memory for each request,
- * only non-lazy values are now loaded.
- *
- * Once a value that is lazy is requested, all lazy values will be loaded.
- *
- * Similarly, some methods from this class are marked with a warning about ignoring
- * lazy loading. Use them wisely and only on parts of the code that are called
- * during specific requests or actions to avoid loading the lazy values all the time.
- *
- * @since 7.0.0
- * @since 29.0.0 - Supporting types and lazy loading
- */
- class AppConfig implements IAppConfig {
- private const APP_MAX_LENGTH = 32;
- private const KEY_MAX_LENGTH = 64;
- private const ENCRYPTION_PREFIX = '$AppConfigEncryption$';
- private const ENCRYPTION_PREFIX_LENGTH = 21; // strlen(self::ENCRYPTION_PREFIX)
- /** @var array<string, array<string, mixed>> ['app_id' => ['config_key' => 'config_value']] */
- private array $fastCache = []; // cache for normal config keys
- /** @var array<string, array<string, mixed>> ['app_id' => ['config_key' => 'config_value']] */
- private array $lazyCache = []; // cache for lazy config keys
- /** @var array<string, array<string, int>> ['app_id' => ['config_key' => bitflag]] */
- private array $valueTypes = []; // type for all config values
- private bool $fastLoaded = false;
- private bool $lazyLoaded = false;
- /**
- * $migrationCompleted is only needed to manage the previous structure
- * of the database during the upgrading process to nc29.
- *
- * only when upgrading from a version prior 28.0.2
- *
- * @TODO: remove this value in Nextcloud 30+
- */
- private bool $migrationCompleted = true;
- public function __construct(
- protected IDBConnection $connection,
- protected LoggerInterface $logger,
- protected ICrypto $crypto,
- ) {
- }
- /**
- * @inheritDoc
- *
- * @return string[] list of app ids
- * @since 7.0.0
- */
- public function getApps(): array {
- $this->loadConfigAll();
- $apps = array_merge(array_keys($this->fastCache), array_keys($this->lazyCache));
- sort($apps);
- return array_values(array_unique($apps));
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- *
- * @return string[] list of stored config keys
- * @since 29.0.0
- */
- public function getKeys(string $app): array {
- $this->assertParams($app);
- $this->loadConfigAll();
- $keys = array_merge(array_keys($this->fastCache[$app] ?? []), array_keys($this->lazyCache[$app] ?? []));
- 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
- *
- * @return bool TRUE if key exists
- * @since 7.0.0
- * @since 29.0.0 Added the $lazy argument
- */
- public function hasKey(string $app, string $key, ?bool $lazy = false): bool {
- $this->assertParams($app, $key);
- $this->loadConfig($lazy);
- if ($lazy === null) {
- $appCache = $this->getAllValues($app);
- return isset($appCache[$key]);
- }
- if ($lazy) {
- return isset($this->lazyCache[$app][$key]);
- }
- return isset($this->fastCache[$app][$key]);
- }
- /**
- * @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
- *
- * @return bool
- * @throws AppConfigUnknownKeyException if config key is not known
- * @since 29.0.0
- */
- public function isSensitive(string $app, string $key, ?bool $lazy = false): bool {
- $this->assertParams($app, $key);
- $this->loadConfig($lazy);
- if (!isset($this->valueTypes[$app][$key])) {
- throw new AppConfigUnknownKeyException('unknown config key');
- }
- return $this->isTyped(self::VALUE_SENSITIVE, $this->valueTypes[$app][$key]);
- }
- /**
- * @inheritDoc
- *
- * @param string $app if of the app
- * @param string $key config key
- *
- * @return bool TRUE if config is lazy loaded
- * @throws AppConfigUnknownKeyException if config key is not known
- * @see IAppConfig for details about lazy loading
- * @since 29.0.0
- */
- public function isLazy(string $app, string $key): bool {
- // there is a huge probability the non-lazy config are already loaded
- if ($this->hasKey($app, $key, false)) {
- return false;
- }
- // key not found, we search in the lazy config
- if ($this->hasKey($app, $key, true)) {
- return true;
- }
- throw new AppConfigUnknownKeyException('unknown config key');
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $prefix config keys prefix to search
- * @param bool $filtered TRUE to hide sensitive config values. Value are replaced by {@see IConfig::SENSITIVE_VALUE}
- *
- * @return array<string, string|int|float|bool|array> [configKey => configValue]
- * @since 29.0.0
- */
- public function getAllValues(string $app, string $prefix = '', bool $filtered = false): array {
- $this->assertParams($app, $prefix);
- // if we want to filter values, we need to get sensitivity
- $this->loadConfigAll();
- // array_merge() will remove numeric keys (here config keys), so addition arrays instead
- $values = $this->formatAppValues($app, ($this->fastCache[$app] ?? []) + ($this->lazyCache[$app] ?? []));
- $values = array_filter(
- $values,
- function (string $key) use ($prefix): bool {
- return str_starts_with($key, $prefix); // filter values based on $prefix
- }, ARRAY_FILTER_USE_KEY
- );
- if (!$filtered) {
- return $values;
- }
- /**
- * Using the old (deprecated) list of sensitive values.
- */
- foreach ($this->getSensitiveKeys($app) as $sensitiveKeyExp) {
- $sensitiveKeys = preg_grep($sensitiveKeyExp, array_keys($values));
- foreach ($sensitiveKeys as $sensitiveKey) {
- $this->valueTypes[$app][$sensitiveKey] = ($this->valueTypes[$app][$sensitiveKey] ?? 0) | self::VALUE_SENSITIVE;
- }
- }
- $result = [];
- foreach ($values as $key => $value) {
- $result[$key] = $this->isTyped(self::VALUE_SENSITIVE, $this->valueTypes[$app][$key] ?? 0) ? IConfig::SENSITIVE_VALUE : $value;
- }
- return $result;
- }
- /**
- * @inheritDoc
- *
- * @param string $key config key
- * @param bool $lazy search within lazy loaded config
- * @param int|null $typedAs enforce type for the returned values ({@see self::VALUE_STRING} and others)
- *
- * @return array<string, string|int|float|bool|array> [appId => configValue]
- * @since 29.0.0
- */
- public function searchValues(string $key, bool $lazy = false, ?int $typedAs = null): array {
- $this->assertParams('', $key, true);
- $this->loadConfig($lazy);
- /** @var array<array-key, array<array-key, mixed>> $cache */
- if ($lazy) {
- $cache = $this->lazyCache;
- } else {
- $cache = $this->fastCache;
- }
- $values = [];
- foreach (array_keys($cache) as $app) {
- if (isset($cache[$app][$key])) {
- $values[$app] = $this->convertTypedValue($cache[$app][$key], $typedAs ?? $this->getValueType((string)$app, $key, $lazy));
- }
- }
- return $values;
- }
- /**
- * Get the config value as string.
- * If the value does not exist the given default will be returned.
- *
- * Set lazy to `null` to ignore it and get the value from either source.
- *
- * **WARNING:** Method is internal and **SHOULD** not be used, as it is better to get the value with a type.
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param string $default config value
- * @param null|bool $lazy get config as lazy loaded or not. can be NULL
- *
- * @return string the value or $default
- * @internal
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- * @see getValueString()
- * @see getValueInt()
- * @see getValueFloat()
- * @see getValueBool()
- * @see getValueArray()
- */
- public function getValueMixed(
- string $app,
- string $key,
- string $default = '',
- ?bool $lazy = false,
- ): string {
- try {
- $lazy = ($lazy === null) ? $this->isLazy($app, $key) : $lazy;
- } catch (AppConfigUnknownKeyException $e) {
- return $default;
- }
- return $this->getTypedValue(
- $app,
- $key,
- $default,
- $lazy,
- self::VALUE_MIXED
- );
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param string $default default value
- * @param bool $lazy search within lazy loaded config
- *
- * @return string stored config value or $default if not set in database
- * @throws InvalidArgumentException if one of the argument format is invalid
- * @throws AppConfigTypeConflictException in case of conflict with the value type set in database
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- */
- public function getValueString(
- string $app,
- string $key,
- string $default = '',
- bool $lazy = false,
- ): string {
- return $this->getTypedValue($app, $key, $default, $lazy, self::VALUE_STRING);
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param int $default default value
- * @param bool $lazy search within lazy loaded config
- *
- * @return int stored config value or $default if not set in database
- * @throws InvalidArgumentException if one of the argument format is invalid
- * @throws AppConfigTypeConflictException in case of conflict with the value type set in database
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- */
- public function getValueInt(
- string $app,
- string $key,
- int $default = 0,
- bool $lazy = false,
- ): int {
- return (int)$this->getTypedValue($app, $key, (string)$default, $lazy, self::VALUE_INT);
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param float $default default value
- * @param bool $lazy search within lazy loaded config
- *
- * @return float stored config value or $default if not set in database
- * @throws InvalidArgumentException if one of the argument format is invalid
- * @throws AppConfigTypeConflictException in case of conflict with the value type set in database
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- */
- public function getValueFloat(string $app, string $key, float $default = 0, bool $lazy = false): float {
- return (float)$this->getTypedValue($app, $key, (string)$default, $lazy, self::VALUE_FLOAT);
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param bool $default default value
- * @param bool $lazy search within lazy loaded config
- *
- * @return bool stored config value or $default if not set in database
- * @throws InvalidArgumentException if one of the argument format is invalid
- * @throws AppConfigTypeConflictException in case of conflict with the value type set in database
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- */
- public function getValueBool(string $app, string $key, bool $default = false, bool $lazy = false): bool {
- $b = strtolower($this->getTypedValue($app, $key, $default ? 'true' : 'false', $lazy, self::VALUE_BOOL));
- return in_array($b, ['1', 'true', 'yes', 'on']);
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param array $default default value
- * @param bool $lazy search within lazy loaded config
- *
- * @return array stored config value or $default if not set in database
- * @throws InvalidArgumentException if one of the argument format is invalid
- * @throws AppConfigTypeConflictException in case of conflict with the value type set in database
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- */
- public function getValueArray(
- string $app,
- string $key,
- array $default = [],
- bool $lazy = false,
- ): array {
- try {
- $defaultJson = json_encode($default, JSON_THROW_ON_ERROR);
- $value = json_decode($this->getTypedValue($app, $key, $defaultJson, $lazy, self::VALUE_ARRAY), true, flags: JSON_THROW_ON_ERROR);
- return is_array($value) ? $value : [];
- } catch (JsonException) {
- return [];
- }
- }
- /**
- * @param string $app id of the app
- * @param string $key config key
- * @param string $default default value
- * @param bool $lazy search within lazy loaded config
- * @param int $type value type {@see VALUE_STRING} {@see VALUE_INT}{@see VALUE_FLOAT} {@see VALUE_BOOL} {@see VALUE_ARRAY}
- *
- * @return string
- * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one
- * @throws InvalidArgumentException
- */
- private function getTypedValue(
- string $app,
- string $key,
- string $default,
- bool $lazy,
- int $type,
- ): string {
- $this->assertParams($app, $key, valueType: $type);
- $this->loadConfig($lazy);
- /**
- * We ignore check if mixed type is requested.
- * If type of stored value is set as mixed, we don't filter.
- * If type of stored value is defined, we compare with the one requested.
- */
- $knownType = $this->valueTypes[$app][$key] ?? 0;
- if (!$this->isTyped(self::VALUE_MIXED, $type)
- && $knownType > 0
- && !$this->isTyped(self::VALUE_MIXED, $knownType)
- && !$this->isTyped($type, $knownType)) {
- $this->logger->warning('conflict with value type from database', ['app' => $app, 'key' => $key, 'type' => $type, 'knownType' => $knownType]);
- throw new AppConfigTypeConflictException('conflict with value type from database');
- }
- /**
- * - the pair $app/$key cannot exist in both array,
- * - we should still return an existing non-lazy value even if current method
- * is called with $lazy is true
- *
- * This way, lazyCache will be empty until the load for lazy config value is requested.
- */
- if (isset($this->lazyCache[$app][$key])) {
- $value = $this->lazyCache[$app][$key];
- } elseif (isset($this->fastCache[$app][$key])) {
- $value = $this->fastCache[$app][$key];
- } else {
- return $default;
- }
- $sensitive = $this->isTyped(self::VALUE_SENSITIVE, $knownType);
- if ($sensitive && str_starts_with($value, self::ENCRYPTION_PREFIX)) {
- // Only decrypt values that are stored encrypted
- $value = $this->crypto->decrypt(substr($value, self::ENCRYPTION_PREFIX_LENGTH));
- }
- return $value;
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- *
- * @return int type of the value
- * @throws AppConfigUnknownKeyException if config key is not known
- * @since 29.0.0
- * @see VALUE_STRING
- * @see VALUE_INT
- * @see VALUE_FLOAT
- * @see VALUE_BOOL
- * @see VALUE_ARRAY
- */
- public function getValueType(string $app, string $key, ?bool $lazy = null): int {
- $this->assertParams($app, $key);
- $this->loadConfig($lazy);
- if (!isset($this->valueTypes[$app][$key])) {
- throw new AppConfigUnknownKeyException('unknown config key');
- }
- $type = $this->valueTypes[$app][$key];
- $type &= ~self::VALUE_SENSITIVE;
- return $type;
- }
- /**
- * Store a config key and its value in database as VALUE_MIXED
- *
- * **WARNING:** Method is internal and **MUST** not be used as it is best to set a real value type
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param string $value config value
- * @param bool $lazy set config as lazy loaded
- * @param bool $sensitive if TRUE value will be hidden when listing config values.
- *
- * @return bool TRUE if value was different, therefor updated in database
- * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED
- * @internal
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- * @see setValueString()
- * @see setValueInt()
- * @see setValueFloat()
- * @see setValueBool()
- * @see setValueArray()
- */
- public function setValueMixed(
- string $app,
- string $key,
- string $value,
- bool $lazy = false,
- bool $sensitive = false,
- ): bool {
- return $this->setTypedValue(
- $app,
- $key,
- $value,
- $lazy,
- self::VALUE_MIXED | ($sensitive ? self::VALUE_SENSITIVE : 0)
- );
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param string $value config value
- * @param bool $lazy set config as lazy loaded
- * @param bool $sensitive if TRUE value will be hidden when listing config values.
- *
- * @return bool TRUE if value was different, therefor updated in database
- * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- */
- public function setValueString(
- string $app,
- string $key,
- string $value,
- bool $lazy = false,
- bool $sensitive = false,
- ): bool {
- return $this->setTypedValue(
- $app,
- $key,
- $value,
- $lazy,
- self::VALUE_STRING | ($sensitive ? self::VALUE_SENSITIVE : 0)
- );
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param int $value config value
- * @param bool $lazy set config as lazy loaded
- * @param bool $sensitive if TRUE value will be hidden when listing config values.
- *
- * @return bool TRUE if value was different, therefor updated in database
- * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- */
- public function setValueInt(
- string $app,
- string $key,
- int $value,
- bool $lazy = false,
- bool $sensitive = false,
- ): bool {
- if ($value > 2000000000) {
- $this->logger->debug('You are trying to store an integer value around/above 2,147,483,647. This is a reminder that reaching this theoretical limit on 32 bits system will throw an exception.');
- }
- return $this->setTypedValue(
- $app,
- $key,
- (string)$value,
- $lazy,
- self::VALUE_INT | ($sensitive ? self::VALUE_SENSITIVE : 0)
- );
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param float $value config value
- * @param bool $lazy set config as lazy loaded
- * @param bool $sensitive if TRUE value will be hidden when listing config values.
- *
- * @return bool TRUE if value was different, therefor updated in database
- * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- */
- public function setValueFloat(
- string $app,
- string $key,
- float $value,
- bool $lazy = false,
- bool $sensitive = false,
- ): bool {
- return $this->setTypedValue(
- $app,
- $key,
- (string)$value,
- $lazy,
- self::VALUE_FLOAT | ($sensitive ? self::VALUE_SENSITIVE : 0)
- );
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param bool $value config value
- * @param bool $lazy set config as lazy loaded
- *
- * @return bool TRUE if value was different, therefor updated in database
- * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- */
- public function setValueBool(
- string $app,
- string $key,
- bool $value,
- bool $lazy = false,
- ): bool {
- return $this->setTypedValue(
- $app,
- $key,
- ($value) ? '1' : '0',
- $lazy,
- self::VALUE_BOOL
- );
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param array $value config value
- * @param bool $lazy set config as lazy loaded
- * @param bool $sensitive if TRUE value will be hidden when listing config values.
- *
- * @return bool TRUE if value was different, therefor updated in database
- * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one
- * @throws JsonException
- * @since 29.0.0
- * @see IAppConfig for explanation about lazy loading
- */
- public function setValueArray(
- string $app,
- string $key,
- array $value,
- bool $lazy = false,
- bool $sensitive = false,
- ): bool {
- try {
- return $this->setTypedValue(
- $app,
- $key,
- json_encode($value, JSON_THROW_ON_ERROR),
- $lazy,
- self::VALUE_ARRAY | ($sensitive ? self::VALUE_SENSITIVE : 0)
- );
- } catch (JsonException $e) {
- $this->logger->warning('could not setValueArray', ['app' => $app, 'key' => $key, 'exception' => $e]);
- throw $e;
- }
- }
- /**
- * Store a config key and its value in database
- *
- * If config key is already known with the exact same config value and same sensitive/lazy status, the
- * database is not updated. If config value was previously stored as sensitive, status will not be
- * altered.
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param string $value config value
- * @param bool $lazy config set as lazy loaded
- * @param int $type value type {@see VALUE_STRING} {@see VALUE_INT} {@see VALUE_FLOAT} {@see VALUE_BOOL} {@see VALUE_ARRAY}
- *
- * @return bool TRUE if value was updated in database
- * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one
- * @see IAppConfig for explanation about lazy loading
- */
- private function setTypedValue(
- string $app,
- string $key,
- string $value,
- bool $lazy,
- int $type,
- ): bool {
- $this->assertParams($app, $key);
- $this->loadConfig($lazy);
- $sensitive = $this->isTyped(self::VALUE_SENSITIVE, $type);
- $inserted = $refreshCache = false;
- $origValue = $value;
- if ($sensitive || ($this->hasKey($app, $key, $lazy) && $this->isSensitive($app, $key, $lazy))) {
- $value = self::ENCRYPTION_PREFIX . $this->crypto->encrypt($value);
- }
- if ($this->hasKey($app, $key, $lazy)) {
- /**
- * no update if key is already known with set lazy status and value is
- * not different, unless sensitivity is switched from false to true.
- */
- if ($origValue === $this->getTypedValue($app, $key, $value, $lazy, $type)
- && (!$sensitive || $this->isSensitive($app, $key, $lazy))) {
- return false;
- }
- } else {
- /**
- * if key is not known yet, we try to insert.
- * It might fail if the key exists with a different lazy flag.
- */
- try {
- $insert = $this->connection->getQueryBuilder();
- $insert->insert('appconfig')
- ->setValue('appid', $insert->createNamedParameter($app))
- ->setValue('lazy', $insert->createNamedParameter(($lazy) ? 1 : 0, IQueryBuilder::PARAM_INT))
- ->setValue('type', $insert->createNamedParameter($type, IQueryBuilder::PARAM_INT))
- ->setValue('configkey', $insert->createNamedParameter($key))
- ->setValue('configvalue', $insert->createNamedParameter($value));
- $insert->executeStatement();
- $inserted = true;
- } catch (DBException $e) {
- if ($e->getReason() !== DBException::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
- throw $e; // TODO: throw exception or just log and returns false !?
- }
- }
- }
- /**
- * We cannot insert a new row, meaning we need to update an already existing one
- */
- if (!$inserted) {
- $currType = $this->valueTypes[$app][$key] ?? 0;
- if ($currType === 0) { // this might happen when switching lazy loading status
- $this->loadConfigAll();
- $currType = $this->valueTypes[$app][$key] ?? 0;
- }
- /**
- * This should only happen during the upgrade process from 28 to 29.
- * We only log a warning and set it to VALUE_MIXED.
- */
- if ($currType === 0) {
- $this->logger->warning('Value type is set to zero (0) in database. This is fine only during the upgrade process from 28 to 29.', ['app' => $app, 'key' => $key]);
- $currType = self::VALUE_MIXED;
- }
- /**
- * we only accept a different type from the one stored in database
- * if the one stored in database is not-defined (VALUE_MIXED)
- */
- if (!$this->isTyped(self::VALUE_MIXED, $currType) &&
- ($type | self::VALUE_SENSITIVE) !== ($currType | self::VALUE_SENSITIVE)) {
- try {
- $currType = $this->convertTypeToString($currType);
- $type = $this->convertTypeToString($type);
- } catch (AppConfigIncorrectTypeException) {
- // can be ignored, this was just needed for a better exception message.
- }
- throw new AppConfigTypeConflictException('conflict between new type (' . $type . ') and old type (' . $currType . ')');
- }
- // we fix $type if the stored value, or the new value as it might be changed, is set as sensitive
- if ($sensitive || $this->isTyped(self::VALUE_SENSITIVE, $currType)) {
- $type |= self::VALUE_SENSITIVE;
- }
- if ($lazy !== $this->isLazy($app, $key)) {
- $refreshCache = true;
- }
- $update = $this->connection->getQueryBuilder();
- $update->update('appconfig')
- ->set('configvalue', $update->createNamedParameter($value))
- ->set('lazy', $update->createNamedParameter(($lazy) ? 1 : 0, IQueryBuilder::PARAM_INT))
- ->set('type', $update->createNamedParameter($type, IQueryBuilder::PARAM_INT))
- ->where($update->expr()->eq('appid', $update->createNamedParameter($app)))
- ->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key)));
- $update->executeStatement();
- }
- if ($refreshCache) {
- $this->clearCache();
- return true;
- }
- // update local cache
- if ($lazy) {
- $this->lazyCache[$app][$key] = $value;
- } else {
- $this->fastCache[$app][$key] = $value;
- }
- $this->valueTypes[$app][$key] = $type;
- return true;
- }
- /**
- * Change the type of config value.
- *
- * **WARNING:** Method is internal and **MUST** not be used as it may break things.
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param int $type value type {@see VALUE_STRING} {@see VALUE_INT} {@see VALUE_FLOAT} {@see VALUE_BOOL} {@see VALUE_ARRAY}
- *
- * @return bool TRUE if database update were necessary
- * @throws AppConfigUnknownKeyException if $key is now known in database
- * @throws AppConfigIncorrectTypeException if $type is not valid
- * @internal
- * @since 29.0.0
- */
- public function updateType(string $app, string $key, int $type = self::VALUE_MIXED): bool {
- $this->assertParams($app, $key);
- $this->loadConfigAll();
- $lazy = $this->isLazy($app, $key);
- // type can only be one type
- if (!in_array($type, [self::VALUE_MIXED, self::VALUE_STRING, self::VALUE_INT, self::VALUE_FLOAT, self::VALUE_BOOL, self::VALUE_ARRAY])) {
- throw new AppConfigIncorrectTypeException('Unknown value type');
- }
- $currType = $this->valueTypes[$app][$key];
- if (($type | self::VALUE_SENSITIVE) === ($currType | self::VALUE_SENSITIVE)) {
- return false;
- }
- // we complete with sensitive flag if the stored value is set as sensitive
- if ($this->isTyped(self::VALUE_SENSITIVE, $currType)) {
- $type = $type | self::VALUE_SENSITIVE;
- }
- $update = $this->connection->getQueryBuilder();
- $update->update('appconfig')
- ->set('type', $update->createNamedParameter($type, IQueryBuilder::PARAM_INT))
- ->where($update->expr()->eq('appid', $update->createNamedParameter($app)))
- ->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key)));
- $update->executeStatement();
- $this->valueTypes[$app][$key] = $type;
- return true;
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param bool $sensitive TRUE to set as sensitive, FALSE to unset
- *
- * @return bool TRUE if entry was found in database and an update was necessary
- * @since 29.0.0
- */
- public function updateSensitive(string $app, string $key, bool $sensitive): bool {
- $this->assertParams($app, $key);
- $this->loadConfigAll();
- try {
- if ($sensitive === $this->isSensitive($app, $key, null)) {
- return false;
- }
- } catch (AppConfigUnknownKeyException $e) {
- return false;
- }
- $lazy = $this->isLazy($app, $key);
- if ($lazy) {
- $cache = $this->lazyCache;
- } else {
- $cache = $this->fastCache;
- }
- if (!isset($cache[$app][$key])) {
- throw new AppConfigUnknownKeyException('unknown config key');
- }
- /**
- * type returned by getValueType() is already cleaned from sensitive flag
- * we just need to update it based on $sensitive and store it in database
- */
- $type = $this->getValueType($app, $key);
- $value = $cache[$app][$key];
- if ($sensitive) {
- $type |= self::VALUE_SENSITIVE;
- $value = self::ENCRYPTION_PREFIX . $this->crypto->encrypt($value);
- } else {
- $value = $this->crypto->decrypt(substr($value, self::ENCRYPTION_PREFIX_LENGTH));
- }
- $update = $this->connection->getQueryBuilder();
- $update->update('appconfig')
- ->set('type', $update->createNamedParameter($type, IQueryBuilder::PARAM_INT))
- ->set('configvalue', $update->createNamedParameter($value))
- ->where($update->expr()->eq('appid', $update->createNamedParameter($app)))
- ->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key)));
- $update->executeStatement();
- $this->valueTypes[$app][$key] = $type;
- return true;
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- * @param bool $lazy TRUE to set as lazy loaded, FALSE to unset
- *
- * @return bool TRUE if entry was found in database and an update was necessary
- * @since 29.0.0
- */
- public function updateLazy(string $app, string $key, bool $lazy): bool {
- $this->assertParams($app, $key);
- $this->loadConfigAll();
- try {
- if ($lazy === $this->isLazy($app, $key)) {
- return false;
- }
- } catch (AppConfigUnknownKeyException $e) {
- return false;
- }
- $update = $this->connection->getQueryBuilder();
- $update->update('appconfig')
- ->set('lazy', $update->createNamedParameter($lazy ? 1 : 0, IQueryBuilder::PARAM_INT))
- ->where($update->expr()->eq('appid', $update->createNamedParameter($app)))
- ->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key)));
- $update->executeStatement();
- // At this point, it is a lot safer to clean cache
- $this->clearCache();
- return true;
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- *
- * @return array
- * @throws AppConfigUnknownKeyException if config key is not known in database
- * @since 29.0.0
- */
- public function getDetails(string $app, string $key): array {
- $this->assertParams($app, $key);
- $this->loadConfigAll();
- $lazy = $this->isLazy($app, $key);
- if ($lazy) {
- $cache = $this->lazyCache;
- } else {
- $cache = $this->fastCache;
- }
- $type = $this->getValueType($app, $key);
- try {
- $typeString = $this->convertTypeToString($type);
- } catch (AppConfigIncorrectTypeException $e) {
- $this->logger->warning('type stored in database is not correct', ['exception' => $e, 'type' => $type]);
- $typeString = (string)$type;
- }
- if (!isset($cache[$app][$key])) {
- throw new AppConfigUnknownKeyException('unknown config key');
- }
- $value = $cache[$app][$key];
- $sensitive = $this->isSensitive($app, $key, null);
- if ($sensitive && str_starts_with($value, self::ENCRYPTION_PREFIX)) {
- $value = $this->crypto->decrypt(substr($value, self::ENCRYPTION_PREFIX_LENGTH));
- }
- return [
- 'app' => $app,
- 'key' => $key,
- 'value' => $value,
- 'type' => $type,
- 'lazy' => $lazy,
- 'typeString' => $typeString,
- 'sensitive' => $sensitive
- ];
- }
- /**
- * @param string $type
- *
- * @return int
- * @throws AppConfigIncorrectTypeException
- * @since 29.0.0
- */
- public function convertTypeToInt(string $type): int {
- return match (strtolower($type)) {
- 'mixed' => IAppConfig::VALUE_MIXED,
- 'string' => IAppConfig::VALUE_STRING,
- 'integer' => IAppConfig::VALUE_INT,
- 'float' => IAppConfig::VALUE_FLOAT,
- 'boolean' => IAppConfig::VALUE_BOOL,
- 'array' => IAppConfig::VALUE_ARRAY,
- default => throw new AppConfigIncorrectTypeException('Unknown type ' . $type)
- };
- }
- /**
- * @param int $type
- *
- * @return string
- * @throws AppConfigIncorrectTypeException
- * @since 29.0.0
- */
- public function convertTypeToString(int $type): string {
- $type &= ~self::VALUE_SENSITIVE;
- return match ($type) {
- IAppConfig::VALUE_MIXED => 'mixed',
- IAppConfig::VALUE_STRING => 'string',
- IAppConfig::VALUE_INT => 'integer',
- IAppConfig::VALUE_FLOAT => 'float',
- IAppConfig::VALUE_BOOL => 'boolean',
- IAppConfig::VALUE_ARRAY => 'array',
- default => throw new AppConfigIncorrectTypeException('Unknown numeric type ' . $type)
- };
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- * @param string $key config key
- *
- * @since 29.0.0
- */
- public function deleteKey(string $app, string $key): void {
- $this->assertParams($app, $key);
- $qb = $this->connection->getQueryBuilder();
- $qb->delete('appconfig')
- ->where($qb->expr()->eq('appid', $qb->createNamedParameter($app)))
- ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key)));
- $qb->executeStatement();
- unset($this->lazyCache[$app][$key]);
- unset($this->fastCache[$app][$key]);
- }
- /**
- * @inheritDoc
- *
- * @param string $app id of the app
- *
- * @since 29.0.0
- */
- public function deleteApp(string $app): void {
- $this->assertParams($app);
- $qb = $this->connection->getQueryBuilder();
- $qb->delete('appconfig')
- ->where($qb->expr()->eq('appid', $qb->createNamedParameter($app)));
- $qb->executeStatement();
- $this->clearCache();
- }
- /**
- * @inheritDoc
- *
- * @param bool $reload set to TRUE to refill cache instantly after clearing it
- *
- * @since 29.0.0
- */
- public function clearCache(bool $reload = false): void {
- $this->lazyLoaded = $this->fastLoaded = false;
- $this->lazyCache = $this->fastCache = $this->valueTypes = [];
- if (!$reload) {
- return;
- }
- $this->loadConfigAll();
- }
- /**
- * For debug purpose.
- * Returns the cached data.
- *
- * @return array
- * @since 29.0.0
- * @internal
- */
- public function statusCache(): array {
- return [
- 'fastLoaded' => $this->fastLoaded,
- 'fastCache' => $this->fastCache,
- 'lazyLoaded' => $this->lazyLoaded,
- 'lazyCache' => $this->lazyCache,
- ];
- }
- /**
- * @param int $needle bitflag to search
- * @param int $type known value
- *
- * @return bool TRUE if bitflag $needle is set in $type
- */
- private function isTyped(int $needle, int $type): bool {
- return (($needle & $type) !== 0);
- }
- /**
- * Confirm the string set for app and key fit the database description
- *
- * @param string $app assert $app fit in database
- * @param string $configKey assert config key fit in database
- * @param bool $allowEmptyApp $app can be empty string
- * @param int $valueType assert value type is only one type
- *
- * @throws InvalidArgumentException
- */
- private function assertParams(string $app = '', string $configKey = '', bool $allowEmptyApp = false, int $valueType = -1): void {
- if (!$allowEmptyApp && $app === '') {
- throw new InvalidArgumentException('app cannot be an empty string');
- }
- if (strlen($app) > self::APP_MAX_LENGTH) {
- throw new InvalidArgumentException(
- 'Value (' . $app . ') for app is too long (' . self::APP_MAX_LENGTH . ')'
- );
- }
- if (strlen($configKey) > self::KEY_MAX_LENGTH) {
- throw new InvalidArgumentException('Value (' . $configKey . ') for key is too long (' . self::KEY_MAX_LENGTH . ')');
- }
- if ($valueType > -1) {
- $valueType &= ~self::VALUE_SENSITIVE;
- if (!in_array($valueType, [self::VALUE_MIXED, self::VALUE_STRING, self::VALUE_INT, self::VALUE_FLOAT, self::VALUE_BOOL, self::VALUE_ARRAY])) {
- throw new InvalidArgumentException('Unknown value type');
- }
- }
- }
- private function loadConfigAll(): void {
- $this->loadConfig(null);
- }
- /**
- * Load normal config or config set as lazy loaded
- *
- * @param bool|null $lazy set to TRUE to load config set as lazy loaded, set to NULL to load all config
- */
- private function loadConfig(?bool $lazy = false): void {
- if ($this->isLoaded($lazy)) {
- return;
- }
- if (($lazy ?? true) !== false) { // if lazy is null or true, we debug log
- $this->logger->debug('The loading of lazy AppConfig values have been requested', ['exception' => new \RuntimeException('ignorable exception')]);
- }
- $qb = $this->connection->getQueryBuilder();
- $qb->from('appconfig');
- /**
- * The use of $this->>migrationCompleted is only needed to manage the
- * database during the upgrading process to nc29.
- */
- if (!$this->migrationCompleted) {
- $qb->select('appid', 'configkey', 'configvalue');
- } else {
- // we only need value from lazy when loadConfig does not specify it
- $qb->select('appid', 'configkey', 'configvalue', 'type');
- if ($lazy !== null) {
- $qb->where($qb->expr()->eq('lazy', $qb->createNamedParameter($lazy ? 1 : 0, IQueryBuilder::PARAM_INT)));
- } else {
- $qb->addSelect('lazy');
- }
- }
- try {
- $result = $qb->executeQuery();
- } catch (DBException $e) {
- /**
- * in case of issue with field name, it means that migration is not completed.
- * Falling back to a request without select on lazy.
- * This whole try/catch and the migrationCompleted variable can be removed in NC30.
- */
- if ($e->getReason() !== DBException::REASON_INVALID_FIELD_NAME) {
- throw $e;
- }
- $this->migrationCompleted = false;
- $this->loadConfig($lazy);
- return;
- }
- $rows = $result->fetchAll();
- foreach ($rows as $row) {
- // most of the time, 'lazy' is not in the select because its value is already known
- if (($row['lazy'] ?? ($lazy ?? 0) ? 1 : 0) === 1) {
- $this->lazyCache[$row['appid']][$row['configkey']] = $row['configvalue'] ?? '';
- } else {
- $this->fastCache[$row['appid']][$row['configkey']] = $row['configvalue'] ?? '';
- }
- $this->valueTypes[$row['appid']][$row['configkey']] = (int)($row['type'] ?? 0);
- }
- $result->closeCursor();
- $this->setAsLoaded($lazy);
- }
- /**
- * if $lazy is:
- * - false: will returns true if fast config is loaded
- * - true : will returns true if lazy config is loaded
- * - null : will returns true if both config are loaded
- *
- * @param bool $lazy
- *
- * @return bool
- */
- private function isLoaded(?bool $lazy): bool {
- if ($lazy === null) {
- return $this->lazyLoaded && $this->fastLoaded;
- }
- return $lazy ? $this->lazyLoaded : $this->fastLoaded;
- }
- /**
- * if $lazy is:
- * - false: set fast config as loaded
- * - true : set lazy config as loaded
- * - null : set both config as loaded
- *
- * @param bool $lazy
- */
- private function setAsLoaded(?bool $lazy): void {
- if ($lazy === null) {
- $this->fastLoaded = true;
- $this->lazyLoaded = true;
- return;
- }
- if ($lazy) {
- $this->lazyLoaded = true;
- } else {
- $this->fastLoaded = true;
- }
- }
- /**
- * Gets the config value
- *
- * @param string $app app
- * @param string $key key
- * @param string $default = null, default value if the key does not exist
- *
- * @return string the value or $default
- * @deprecated 29.0.0 use getValue*()
- *
- * This function gets a value from the appconfig table. If the key does
- * not exist the default value will be returned
- */
- public function getValue($app, $key, $default = null) {
- $this->loadConfig();
- return $this->fastCache[$app][$key] ?? $default;
- }
- /**
- * Sets a value. If the key did not exist before it will be created.
- *
- * @param string $app app
- * @param string $key key
- * @param string|float|int $value value
- *
- * @return bool True if the value was inserted or updated, false if the value was the same
- * @throws AppConfigTypeConflictException
- * @throws AppConfigUnknownKeyException
- * @deprecated 29.0.0
- */
- public function setValue($app, $key, $value) {
- /**
- * TODO: would it be overkill, or decently improve performance, to catch
- * call to this method with $key='enabled' and 'hide' config value related
- * to $app when the app is disabled (by modifying entry in database: lazy=lazy+2)
- * or enabled (lazy=lazy-2)
- *
- * this solution would remove the loading of config values from disabled app
- * unless calling the method {@see loadConfigAll()}
- */
- return $this->setTypedValue($app, $key, (string)$value, false, self::VALUE_MIXED);
- }
- /**
- * get multiple values, either the app or key can be used as wildcard by setting it to false
- *
- * @param string|false $app
- * @param string|false $key
- *
- * @return array|false
- * @deprecated 29.0.0 use {@see getAllValues()}
- */
- public function getValues($app, $key) {
- if (($app !== false) === ($key !== false)) {
- return false;
- }
- $key = ($key === false) ? '' : $key;
- if (!$app) {
- return $this->searchValues($key, false, self::VALUE_MIXED);
- } else {
- return $this->getAllValues($app, $key);
- }
- }
- /**
- * get all values of the app or and filters out sensitive data
- *
- * @param string $app
- *
- * @return array
- * @deprecated 29.0.0 use {@see getAllValues()}
- */
- public function getFilteredValues($app) {
- return $this->getAllValues($app, filtered: true);
- }
- /**
- * **Warning:** avoid default NULL value for $lazy as this will
- * load all lazy values from the database
- *
- * @param string $app
- * @param array<string, string> $values ['key' => 'value']
- * @param bool|null $lazy
- *
- * @return array<string, string|int|float|bool|array>
- */
- private function formatAppValues(string $app, array $values, ?bool $lazy = null): array {
- foreach ($values as $key => $value) {
- try {
- $type = $this->getValueType($app, $key, $lazy);
- } catch (AppConfigUnknownKeyException $e) {
- continue;
- }
- $values[$key] = $this->convertTypedValue($value, $type);
- }
- return $values;
- }
- /**
- * convert string value to the expected type
- *
- * @param string $value
- * @param int $type
- *
- * @return string|int|float|bool|array
- */
- private function convertTypedValue(string $value, int $type): string|int|float|bool|array {
- switch ($type) {
- case self::VALUE_INT:
- return (int)$value;
- case self::VALUE_FLOAT:
- return (float)$value;
- case self::VALUE_BOOL:
- return in_array(strtolower($value), ['1', 'true', 'yes', 'on']);
- case self::VALUE_ARRAY:
- try {
- return json_decode($value, true, flags: JSON_THROW_ON_ERROR);
- } catch (JsonException $e) {
- // ignoreable
- }
- break;
- }
- return $value;
- }
- /**
- * @param string $app
- *
- * @return string[]
- * @deprecated 29.0.0 data sensitivity should be set when calling setValue*()
- */
- private function getSensitiveKeys(string $app): array {
- $sensitiveValues = [
- 'circles' => [
- '/^key_pairs$/',
- '/^local_gskey$/',
- ],
- 'external' => [
- '/^sites$/',
- ],
- 'integration_discourse' => [
- '/^private_key$/',
- '/^public_key$/',
- ],
- 'integration_dropbox' => [
- '/^client_id$/',
- '/^client_secret$/',
- ],
- 'integration_github' => [
- '/^client_id$/',
- '/^client_secret$/',
- ],
- 'integration_gitlab' => [
- '/^client_id$/',
- '/^client_secret$/',
- '/^oauth_instance_url$/',
- ],
- 'integration_google' => [
- '/^client_id$/',
- '/^client_secret$/',
- ],
- 'integration_jira' => [
- '/^client_id$/',
- '/^client_secret$/',
- '/^forced_instance_url$/',
- ],
- 'integration_onedrive' => [
- '/^client_id$/',
- '/^client_secret$/',
- ],
- 'integration_openproject' => [
- '/^client_id$/',
- '/^client_secret$/',
- '/^oauth_instance_url$/',
- ],
- 'integration_reddit' => [
- '/^client_id$/',
- '/^client_secret$/',
- ],
- 'integration_suitecrm' => [
- '/^client_id$/',
- '/^client_secret$/',
- '/^oauth_instance_url$/',
- ],
- 'integration_twitter' => [
- '/^consumer_key$/',
- '/^consumer_secret$/',
- '/^followed_user$/',
- ],
- 'integration_zammad' => [
- '/^client_id$/',
- '/^client_secret$/',
- '/^oauth_instance_url$/',
- ],
- 'notify_push' => [
- '/^cookie$/',
- ],
- 'serverinfo' => [
- '/^token$/',
- ],
- 'spreed' => [
- '/^bridge_bot_password$/',
- '/^hosted-signaling-server-(.*)$/',
- '/^recording_servers$/',
- '/^signaling_servers$/',
- '/^signaling_ticket_secret$/',
- '/^signaling_token_privkey_(.*)$/',
- '/^signaling_token_pubkey_(.*)$/',
- '/^sip_bridge_dialin_info$/',
- '/^sip_bridge_shared_secret$/',
- '/^stun_servers$/',
- '/^turn_servers$/',
- '/^turn_server_secret$/',
- ],
- 'support' => [
- '/^last_response$/',
- '/^potential_subscription_key$/',
- '/^subscription_key$/',
- ],
- 'theming' => [
- '/^imprintUrl$/',
- '/^privacyUrl$/',
- '/^slogan$/',
- '/^url$/',
- ],
- 'user_ldap' => [
- '/^(s..)?ldap_agent_password$/',
- ],
- 'user_saml' => [
- '/^idp-x509cert$/',
- ],
- ];
- return $sensitiveValues[$app] ?? [];
- }
- /**
- * Clear all the cached app config values
- * New cache will be generated next time a config value is retrieved
- *
- * @deprecated 29.0.0 use {@see clearCache()}
- */
- public function clearCachedConfig(): void {
- $this->clearCache();
- }
- }
|