Files
Git'Fellow 4920bd1725 refactor: add PHP 8.3 types to BC-safe class constants
PHP 8.3 allows class constants to declare a type. Adopt it where doing so
cannot break third-party apps.

Typing an inheritable constant is a hard BC break: a subclass that
redeclares it untyped fails to load with "Type of C::FOO must be
compatible with P::FOO of type string". Changes are therefore limited to
constants that cannot be redeclared by a subclass:

  - private const (not inherited)
  - final public/protected const
  - constants declared in a final class or an enum

Interface constants, trait constants, and public/protected constants in
non-final (including abstract) classes are left untyped, as is all of
lib/public (OCP) and lib/unstable (NCU).

One review-requested exception: the public OBJECT_PREFIX/OBJECT_SUFFIX
constants of the app-internal CalDAV import helpers (TextImporter,
XmlImporter) are typed as well; these classes are not public API and
have no subclasses.

Only string, int and array are used. float is avoided because it would
silently coerce an int literal and change === comparisons. No constant
name or value is modified: every changed line adds only the type token,
so runtime behaviour is unchanged.

Signed-off-by: Git'Fellow <12234510+solracsf@users.noreply.github.com>
2026-08-11 13:52:52 +01:00

107 lines
2.7 KiB
PHP

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Config;
use OCP\Config\IUserConfig;
use OCP\Config\ValueType;
use OCP\Security\ICrypto;
class UserConfigEntry {
private const string ENCRYPTION_PREFIX = '$UserConfigEncryption$';
private const int ENCRYPTION_PREFIX_LENGTH = 22; // strlen(self::ENCRYPTION_PREFIX)
/** @var string $decryptedValue Cached decrypted value, if any */
private ?string $decryptedValue = null;
public function __construct(
private ValueType $type,
private int $flags,
private string $value,
private ICrypto $crypto,
) {
}
public function getRawValue(): string {
return $this->value;
}
public function getType(): ValueType {
return $this->type;
}
public function setType(ValueType $type): void {
$this->type = $type;
}
public function getFlags(): int {
return $this->flags;
}
public function isFlagged(int $mask): bool {
return (($mask & $this->flags) === $mask);
}
public function isSensitive(): bool {
return $this->isFlagged(IUserConfig::FLAG_SENSITIVE);
}
public function isIndexed(): bool {
return $this->isFlagged(IUserConfig::FLAG_INDEXED);
}
/**
* will change referenced $value with the decrypted value in case of encrypted (sensitive value)
*
* @param array{type: ValueType, flags: int, value: string} $valueDetail
*/
public function getDecryptedSensitiveValue(): string {
if (!$this->isFlagged(IUserConfig::FLAG_SENSITIVE)) {
return $this->value;
}
if ($this->decryptedValue !== null) {
return $this->decryptedValue;
}
if (!str_starts_with($this->value, self::ENCRYPTION_PREFIX)) {
return $this->value;
}
$this->decryptedValue = $this->crypto->decrypt(substr($this->value, self::ENCRYPTION_PREFIX_LENGTH));
return $this->decryptedValue;
}
public function setSensitive(bool $sensitive): void {
if ($sensitive) {
$this->flags |= IUserConfig::FLAG_SENSITIVE;
$this->decryptedValue = $this->value;
$this->value = self::ENCRYPTION_PREFIX . $this->crypto->encrypt($this->value);
} else {
$clearValue = $this->getDecryptedSensitiveValue();
$this->flags &= ~IUserConfig::FLAG_SENSITIVE;
$this->value = $clearValue;
$this->decryptedValue = null;
}
}
public function setIndexed(bool $indexed): void {
if ($indexed) {
$this->flags |= IUserConfig::FLAG_INDEXED;
$this->decryptedValue = $this->value;
$this->value = self::ENCRYPTION_PREFIX . $this->crypto->encrypt($this->value);
} else {
$clearValue = $this->getDecryptedSensitiveValue();
$this->flags &= ~IUserConfig::FLAG_INDEXED;
$this->value = $clearValue;
$this->decryptedValue = null;
}
}
}