diff --git a/apps/files/lib/Command/TransferOwnership.php b/apps/files/lib/Command/TransferOwnership.php index e91d2ef98175..5fe8743f1ecc 100644 --- a/apps/files/lib/Command/TransferOwnership.php +++ b/apps/files/lib/Command/TransferOwnership.php @@ -40,6 +40,8 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\GenericEvent; class TransferOwnership extends Command { @@ -61,6 +63,9 @@ class TransferOwnership extends Command { /** @var ProviderFactory */ private $shareProviderFactory; + /** @var EventDispatcherInterface */ + private $eventDispatcher; + /** @var bool */ private $filesExist = false; @@ -85,13 +90,20 @@ class TransferOwnership extends Command { /** @var string */ private $finalTarget; - public function __construct(IUserManager $userManager, IManager $shareManager, IMountManager $mountManager, Manager $encryptionManager, ILogger $logger, ProviderFactory $shareProviderFactory) { + /** @var array , Files affected with signature mismatch */ + private $affectedFiles = []; + + public function __construct(IUserManager $userManager, IManager $shareManager, + IMountManager $mountManager, Manager $encryptionManager, + ILogger $logger, ProviderFactory $shareProviderFactory, + EventDispatcherInterface $eventDispatcher) { $this->userManager = $userManager; $this->shareManager = $shareManager; $this->mountManager = $mountManager; $this->encryptionManager = $encryptionManager; $this->logger = $logger; $this->shareProviderFactory = $shareProviderFactory; + $this->eventDispatcher = $eventDispatcher; parent::__construct(); } @@ -287,7 +299,20 @@ protected function transfer(OutputInterface $output) { } } + $this->eventDispatcher->addListener('files.aftersignaturemismatch', function (GenericEvent $event) { + if ($event->hasArgument('signatureMismatch') && $event->hasArgument('fileName')) { + $fileName = $event->getArgument('fileName'); + if (!isset($this->affectedFiles[$fileName])) { + $this->affectedFiles[$fileName] = 1; + } + } + }, 10); + $view->rename($sourcePath, $this->finalTarget); + if (\count($this->affectedFiles) >= 1) { + $glueString = (\count($this->affectedFiles) > 1) ? ", " : ""; + $output->writeln("The affected files are : " . \implode($glueString, \array_keys($this->affectedFiles)) . ""); + } if (!\is_dir("$this->sourceUser/files")) { // because the files folder is moved away we need to recreate it diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php index 2a9bff7e2fbd..a0668853ebc3 100644 --- a/lib/private/Files/Storage/Wrapper/Encryption.php +++ b/lib/private/Files/Storage/Wrapper/Encryption.php @@ -42,6 +42,8 @@ use OCP\Files\Storage; use OCP\ILogger; use OCP\Files\Cache\ICacheEntry; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\GenericEvent; class Encryption extends Wrapper { use LocalTempFileTrait; @@ -85,6 +87,9 @@ class Encryption extends Wrapper { /** @var ArrayCache */ private $arrayCache; + /** @var EventDispatcherInterface */ + private $eventDispatcher; + /** @var array which has information of sourcePath during rename operation */ private $sourcePath; @@ -112,7 +117,8 @@ public function __construct( IStorage $keyStorage = null, Update $update = null, Manager $mountManager = null, - ArrayCache $arrayCache = null + ArrayCache $arrayCache = null, + EventDispatcherInterface $eventDispatcher = null ) { $this->mountPoint = $parameters['mountPoint']; $this->mount = $parameters['mount']; @@ -126,6 +132,7 @@ public function __construct( $this->update = $update; $this->mountManager = $mountManager; $this->arrayCache = $arrayCache; + $this->eventDispatcher = ($eventDispatcher === null) ? \OC::$server->getEventDispatcher() : $eventDispatcher; parent::__construct($parameters); } @@ -774,6 +781,13 @@ private function copyBetweenStorage(Storage\IStorage $sourceStorage, $sourceInte } } else { try { + $signatureMismatch = false; + $this->eventDispatcher->addListener('files.aftersignaturemismatch', function (GenericEvent $event) use ($sourceInternalPath, &$signatureMismatch) { + if ($event->hasArgument('signatureMismatch') && ($event->getArgument('signatureMismatch') === true)) { + $event->setArgument('fileName', $sourceInternalPath); + $signatureMismatch = true; + } + }, 20); $source = $sourceStorage->fopen($sourceInternalPath, 'r'); if ($isRename && (\count($mount) === 1)) { $sourceStorageMountPoint = $mount[0]->getMountPoint(); @@ -785,6 +799,9 @@ private function copyBetweenStorage(Storage\IStorage $sourceStorage, $sourceInte list(, $result) = \OC_Helper::streamCopy($source, $target); \fclose($source); \fclose($target); + if ($signatureMismatch === true) { + $this->logger->warning("The file $sourceInternalPath has signature mismatch"); + } } catch (\Exception $e) { Encryption::setDisableWriteEncryption(false); \fclose($source); diff --git a/lib/private/Files/Stream/Encryption.php b/lib/private/Files/Stream/Encryption.php index f59ba9d641ad..6e66712dfc43 100644 --- a/lib/private/Files/Stream/Encryption.php +++ b/lib/private/Files/Stream/Encryption.php @@ -28,6 +28,7 @@ use Icewind\Streams\Wrapper; use OC\Encryption\Exceptions\EncryptionHeaderKeyExistsException; +use Symfony\Component\EventDispatcher\GenericEvent; class Encryption extends Wrapper { @@ -281,6 +282,7 @@ public function stream_eof() { public function stream_read($count) { $result = ''; + $genericEvent = new GenericEvent('SignatureMismatch', []); $count = \min($count, $this->unencryptedSize - $this->position); while ($count > 0) { @@ -302,6 +304,7 @@ public function stream_read($count) { $count -= ($this->unencryptedBlockSize - $blockPosition); } } + \OC::$server->getEventDispatcher()->dispatch('files.aftersignaturemismatch', $genericEvent); return $result; } diff --git a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php index f2fdca552911..ed55545b58ae 100644 --- a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php +++ b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php @@ -7,6 +7,8 @@ use OC\Files\View; use OC\User\Manager; use OCP\Files\Storage\IStorage; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\GenericEvent; use Test\Files\Storage\Storage; use OC\Files\Storage\Wrapper\Encryption; use OC\Files\Cache\Cache; @@ -101,6 +103,9 @@ class EncryptionTest extends Storage { /** @var \OC\Memcache\ArrayCache | \PHPUnit_Framework_MockObject_MockObject */ private $arrayCache; + /** @var EventDispatcherInterface | \PHPUnit_Framework_MockObject_MockObject */ + private $eventDisaptcher; + /** @var integer dummy unencrypted size */ private $dummySize = -1; @@ -178,6 +183,8 @@ protected function setUp() { ->disableOriginalConstructor()->getMock(); $this->mountManager->expects($this->any())->method('findByStorageId')->willReturn([]); + $this->eventDisaptcher = $this->createMock(EventDispatcherInterface::class); + $this->instance = $this->getMockBuilder(Encryption::class) ->setConstructorArgs( [ @@ -187,7 +194,9 @@ protected function setUp() { 'mountPoint' => '/', 'mount' => $this->mount ], - $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + $this->encryptionManager, $this->util, $this->logger, + $this->file, null, $this->keyStore, $this->update, + $this->mountManager, $this->arrayCache, $this->eventDisaptcher ] ) ->setMethods(['getMetaData', 'getCache', 'getEncryptionModule'])