Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ protected function setupUser($name, $password): View {
$this->loginWithEncryption($name);
return new View('/' . $name . '/files');
}

protected function tearDown(): void {
$this->tearDownEncryptionTrait();
parent::tearDown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ protected function setupUser($name, $password): View {
$this->loginWithEncryption($name);
return new View('/' . $name . '/files');
}

protected function tearDown(): void {
$this->tearDownEncryptionTrait();
parent::tearDown();
}
}
5 changes: 5 additions & 0 deletions apps/encryption/tests/Command/FixEncryptedVersionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -390,4 +390,9 @@ public function testExecuteWithNoMasterKey(): void {

$this->assertStringContainsString('only works with master key', $output);
}

protected function tearDown(): void {
$this->tearDownEncryptionTrait();
parent::tearDown();
}
}
5 changes: 5 additions & 0 deletions apps/encryption/tests/EncryptedStorageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,9 @@ public function testMoveFromEncrypted(): void {
$this->assertEquals('bar', $unencryptedStorage->file_get_contents('foo.txt'));
$this->assertFalse($unencryptedCache->get('foo.txt')->isEncrypted());
}

protected function tearDown(): void {
$this->tearDownEncryptionTrait();
parent::tearDown();
}
}
5 changes: 5 additions & 0 deletions apps/files_sharing/tests/EncryptedSizePropagationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,9 @@ protected function loginHelper($user, $create = false, $password = false) {
$this->setupForUser($user, $password);
parent::loginHelper($user, $create, $password);
}

protected function tearDown(): void {
$this->tearDownEncryptionTrait();
parent::tearDown();
}
}
16 changes: 0 additions & 16 deletions build/psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2920,19 +2920,6 @@
<code><![CDATA[\OC_Util::tearDownFS()]]></code>
</DeprecatedMethod>
</file>
<file src="core/Command/Encryption/Disable.php">
<DeprecatedMethod>
<code><![CDATA[getAppValue]]></code>
<code><![CDATA[setAppValue]]></code>
</DeprecatedMethod>
</file>
<file src="core/Command/Encryption/Enable.php">
<DeprecatedMethod>
<code><![CDATA[getAppValue]]></code>
<code><![CDATA[getAppValue]]></code>
<code><![CDATA[setAppValue]]></code>
</DeprecatedMethod>
</file>
<file src="core/Command/Encryption/MigrateKeyStorage.php">
<DeprecatedClass>
<code><![CDATA[\OC_Util::setupFS($uid)]]></code>
Expand Down Expand Up @@ -4187,9 +4174,6 @@
</DeprecatedMethod>
</file>
<file src="tests/lib/TestCase.php">
<DeprecatedMethod>
<code><![CDATA[$container]]></code>
</DeprecatedMethod>
<InternalMethod>
<code><![CDATA[lockFile]]></code>
<code><![CDATA[unlockFile]]></code>
Expand Down
6 changes: 4 additions & 2 deletions core/Command/Encryption/Disable.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/
namespace OC\Core\Command\Encryption;

use OCP\IAppConfig;
use OCP\IConfig;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
Expand All @@ -15,6 +16,7 @@
class Disable extends Command {
public function __construct(
protected IConfig $config,
protected IAppConfig $appConfig,
) {
parent::__construct();
}
Expand All @@ -27,10 +29,10 @@ protected function configure() {
}

protected function execute(InputInterface $input, OutputInterface $output): int {
if ($this->config->getAppValue('core', 'encryption_enabled', 'no') !== 'yes') {
if ($this->appConfig->getValueString('core', 'encryption_enabled', 'no') !== 'yes') {
$output->writeln('Encryption is already disabled');
} else {
$this->config->setAppValue('core', 'encryption_enabled', 'no');
$this->appConfig->setValueString('core', 'encryption_enabled', 'no');
$output->writeln('<info>Encryption disabled</info>');
}
return 0;
Expand Down
8 changes: 5 additions & 3 deletions core/Command/Encryption/Enable.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace OC\Core\Command\Encryption;

use OCP\Encryption\IManager;
use OCP\IAppConfig;
use OCP\IConfig;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
Expand All @@ -16,6 +17,7 @@
class Enable extends Command {
public function __construct(
protected IConfig $config,
protected IAppConfig $appConfig,
protected IManager $encryptionManager,
) {
parent::__construct();
Expand All @@ -29,10 +31,10 @@ protected function configure() {
}

protected function execute(InputInterface $input, OutputInterface $output): int {
if ($this->config->getAppValue('core', 'encryption_enabled', 'no') === 'yes') {
if ($this->appConfig->getValueString('core', 'encryption_enabled', 'no') === 'yes') {
$output->writeln('Encryption is already enabled');
} else {
$this->config->setAppValue('core', 'encryption_enabled', 'yes');
$this->appConfig->setValueString('core', 'encryption_enabled', 'yes');
$output->writeln('<info>Encryption enabled</info>');
}
$output->writeln('');
Expand All @@ -42,7 +44,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$output->writeln('<error>No encryption module is loaded</error>');
return 1;
}
$defaultModule = $this->config->getAppValue('core', 'default_encryption_module');
$defaultModule = $this->appConfig->getValueString('core', 'default_encryption_module', '');
if ($defaultModule === '') {
$output->writeln('<error>No default module is set</error>');
return 1;
Expand Down
67 changes: 42 additions & 25 deletions lib/private/Encryption/EncryptionWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace OC\Encryption;

use OC\Files\Filesystem;
use OC\Files\Mount\HomeMountPoint;
use OC\Files\Storage\Wrapper\Encryption;
use OC\Files\View;
use OC\Memcache\ArrayCache;
Expand Down Expand Up @@ -62,32 +63,48 @@ public function wrapStorage(string $mountPoint, IStorage $storage, IMountPoint $
'mount' => $mount
];

if ($force || (!$storage->instanceOfStorage(IDisableEncryptionStorage::class) && $mountPoint !== '/')) {
$user = \OC::$server->getUserSession()->getUser();
$mountManager = Filesystem::getMountManager();
$uid = $user ? $user->getUID() : null;
$fileHelper = \OC::$server->get(IFile::class);
$keyStorage = \OC::$server->get(EncryptionKeysStorage::class);
// Only evaluate other conditions if not forced
if (!$force) {
// If a disabled storage medium, return basic storage
if ($storage->instanceOfStorage(IDisableEncryptionStorage::class)) {
return $storage;
}

$util = new Util(
new View(),
\OC::$server->getUserManager(),
\OC::$server->getGroupManager(),
\OC::$server->getConfig()
);
return new Encryption(
$parameters,
$this->manager,
$util,
$this->logger,
$fileHelper,
$uid,
$keyStorage,
$mountManager,
$this->arrayCache
);
} else {
return $storage;
// Root mount point handling: skip encryption wrapper
if ($mountPoint === '/') {
return $storage;
}

// Skip encryption for home mounts if encryptHomeStorage is disabled
if ($mount instanceof HomeMountPoint
&& \OC::$server->getConfig()->getAppValue('encryption', 'encryptHomeStorage', '1') !== '1') {
return $storage;
}
}

// Apply encryption wrapper
$user = \OC::$server->getUserSession()->getUser();
$mountManager = Filesystem::getMountManager();
$uid = $user ? $user->getUID() : null;
$fileHelper = \OC::$server->get(IFile::class);
$keyStorage = \OC::$server->get(EncryptionKeysStorage::class);

$util = new Util(
new View(),
\OC::$server->getUserManager(),
\OC::$server->getGroupManager(),
\OC::$server->getConfig()
);
return new Encryption(
$parameters,
$this->manager,
$util,
$this->logger,
$fileHelper,
$uid,
$keyStorage,
$mountManager,
$this->arrayCache
);
}
}
2 changes: 1 addition & 1 deletion lib/private/Files/Cache/CacheEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public function __clone() {
}

public function getUnencryptedSize(): int {
if ($this->data['encrypted'] && isset($this->data['unencrypted_size']) && $this->data['unencrypted_size'] > 0) {
if ($this->data['encrypted'] && isset($this->data['unencrypted_size'])) {
return $this->data['unencrypted_size'];
} else {
return $this->data['size'] ?? 0;
Expand Down
15 changes: 12 additions & 3 deletions lib/private/Files/Cache/Scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,12 @@ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData =
}
}

// we only updated unencrypted_size if it's already set
if (isset($cacheData['unencrypted_size']) && $cacheData['unencrypted_size'] === 0) {
// Only skip updating unencrypted_size if both cached and new values are 0
// This allows updating from incorrect cached 0 to correct non-zero value
// while avoiding unnecessary updates when both are legitimately 0
if (isset($cacheData['unencrypted_size'])
&& $cacheData['unencrypted_size'] === 0
&& (!isset($data['unencrypted_size']) || $data['unencrypted_size'] === 0)) {
unset($data['unencrypted_size']);
}

Expand All @@ -216,7 +220,12 @@ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData =
$data['etag_changed'] = true;
}
} else {
unset($data['unencrypted_size']);
// For new files, only unset unencrypted_size if the file is not encrypted
// or if unencrypted_size is 0/not set (not a valid encrypted file)
if (!isset($data['encrypted']) || !$data['encrypted']
|| !isset($data['unencrypted_size']) || $data['unencrypted_size'] === 0) {
unset($data['unencrypted_size']);
}
$newData = $data;
$fileId = -1;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/private/Files/FileInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public function getSize($includeMounts = true) {
if ($includeMounts) {
$this->updateEntryFromSubMounts();

if ($this->isEncrypted() && isset($this->data['unencrypted_size']) && $this->data['unencrypted_size'] > 0) {
if ($this->isEncrypted() && isset($this->data['unencrypted_size'])) {
return $this->data['unencrypted_size'];
} else {
return isset($this->data['size']) ? 0 + $this->data['size'] : 0;
Expand Down
1 change: 1 addition & 0 deletions lib/private/Files/Storage/Wrapper/Encryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ protected function verifyUnencryptedSize(string $path, int $unencryptedSize): in
if ($unencryptedSize < 0
|| ($size > 0 && $unencryptedSize === $size)
|| $unencryptedSize > $size
|| ($unencryptedSize === 0 && $size > 0)
) {
// check if we already calculate the unencrypted size for the
// given path to avoid recursions
Expand Down
2 changes: 1 addition & 1 deletion lib/private/Files/Stream/Encryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Encryption extends Wrapper {
protected string $cache;
protected ?int $size = null;
protected int $position;
protected ?int $unencryptedSize = null;
protected int|float|null $unencryptedSize = null;
protected int $headerSize;
protected int $unencryptedBlockSize;
protected array $header;
Expand Down
19 changes: 13 additions & 6 deletions tests/Core/Command/Encryption/DisableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace Tests\Core\Command\Encryption;

use OC\Core\Command\Encryption\Disable;
use OCP\IAppConfig;
use OCP\IConfig;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
Expand All @@ -18,6 +19,8 @@ class DisableTest extends TestCase {
/** @var \PHPUnit\Framework\MockObject\MockObject */
protected $config;
/** @var \PHPUnit\Framework\MockObject\MockObject */
protected $appConfig;
/** @var \PHPUnit\Framework\MockObject\MockObject */
protected $consoleInput;
/** @var \PHPUnit\Framework\MockObject\MockObject */
protected $consoleOutput;
Expand All @@ -31,11 +34,15 @@ protected function setUp(): void {
$config = $this->config = $this->getMockBuilder(IConfig::class)
->disableOriginalConstructor()
->getMock();
$appConfig = $this->appConfig = $this->getMockBuilder(IAppConfig::class)
->disableOriginalConstructor()
->getMock();
$this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock();
$this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock();

/** @var IConfig $config */
$this->command = new Disable($config);
/** @var IAppConfig $appConfig */
$this->command = new Disable($config, $appConfig);
}


Expand All @@ -54,18 +61,18 @@ public static function dataDisable(): array {
*/
#[\PHPUnit\Framework\Attributes\DataProvider('dataDisable')]
public function testDisable($oldStatus, $isUpdating, $expectedString): void {
$this->config->expects($this->once())
->method('getAppValue')
->with('core', 'encryption_enabled', $this->anything())
$this->appConfig->expects($this->once())
->method('getValueString')
->with('core', 'encryption_enabled', 'no')
->willReturn($oldStatus);

$this->consoleOutput->expects($this->once())
->method('writeln')
->with($this->stringContains($expectedString));

if ($isUpdating) {
$this->config->expects($this->once())
->method('setAppValue')
$this->appConfig->expects($this->once())
->method('setValueString')
->with('core', 'encryption_enabled', 'no');
}

Expand Down
Loading
Loading