diff --git a/apps/comments/lib/Notification/Listener.php b/apps/comments/lib/Notification/Listener.php index d30c59c93d555..365f93ce8dd85 100644 --- a/apps/comments/lib/Notification/Listener.php +++ b/apps/comments/lib/Notification/Listener.php @@ -23,7 +23,6 @@ use OCP\Comments\CommentsEvent; use OCP\Comments\IComment; -use OCP\IURLGenerator; use OCP\IUserManager; use OCP\Notification\IManager; @@ -34,25 +33,19 @@ class Listener { /** @var IUserManager */ protected $userManager; - /** @var IURLGenerator */ - protected $urlGenerator; - /** * Listener constructor. * * @param IManager $notificationManager * @param IUserManager $userManager - * @param IURLGenerator $urlGenerator */ public function __construct( IManager $notificationManager, - IUserManager $userManager, - IURLGenerator $urlGenerator + IUserManager $userManager ) { $this->notificationManager = $notificationManager; $this->userManager = $userManager; - $this->urlGenerator = $urlGenerator; } /** @@ -100,11 +93,7 @@ public function instantiateNotification(IComment $comment) { ->setApp('comments') ->setObject('comment', $comment->getId()) ->setSubject('mention', [ $comment->getObjectType(), $comment->getObjectId() ]) - ->setDateTime($comment->getCreationDateTime()) - ->setLink($this->urlGenerator->linkToRouteAbsolute( - 'comments.Notifications.view', - ['id' => $comment->getId()]) - ); + ->setDateTime($comment->getCreationDateTime()); return $notification; } diff --git a/apps/comments/lib/Notification/Notifier.php b/apps/comments/lib/Notification/Notifier.php index 170538512d8f3..a9daef3031fca 100644 --- a/apps/comments/lib/Notification/Notifier.php +++ b/apps/comments/lib/Notification/Notifier.php @@ -139,7 +139,11 @@ public function prepare(INotification $notification, $languageCode) { ] ); } - $notification->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/comment.svg'))); + $notification->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/comment.svg'))) + ->setLink($this->url->linkToRouteAbsolute( + 'comments.Notifications.view', + ['id' => $comment->getId()]) + ); return $notification; break; diff --git a/apps/comments/tests/Unit/Notification/ListenerTest.php b/apps/comments/tests/Unit/Notification/ListenerTest.php index 3007b78cb3d77..ef84d1c60de33 100644 --- a/apps/comments/tests/Unit/Notification/ListenerTest.php +++ b/apps/comments/tests/Unit/Notification/ListenerTest.php @@ -46,14 +46,12 @@ class ListenerTest extends TestCase { protected function setUp() { parent::setUp(); - $this->notificationManager = $this->getMockBuilder('\OCP\Notification\IManager')->getMock(); - $this->userManager = $this->getMockBuilder('\OCP\IUserManager')->getMock(); - $this->urlGenerator = $this->getMockBuilder('OCP\IURLGenerator')->getMock(); + $this->notificationManager = $this->createMock(\OCP\Notification\IManager::class); + $this->userManager = $this->createMock(\OCP\IUserManager::class); $this->listener = new Listener( $this->notificationManager, - $this->userManager, - $this->urlGenerator + $this->userManager ); } diff --git a/apps/files_external/lib/Lib/Storage/AmazonS3.php b/apps/files_external/lib/Lib/Storage/AmazonS3.php index e6e26e3547ab4..9dab25f7197a6 100644 --- a/apps/files_external/lib/Lib/Storage/AmazonS3.php +++ b/apps/files_external/lib/Lib/Storage/AmazonS3.php @@ -42,6 +42,7 @@ use Aws\S3\S3Client; use Aws\S3\Exception\S3Exception; +use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use OC\Files\ObjectStore\S3ConnectionTrait; @@ -366,14 +367,15 @@ public function fopen($path, $mode) { $ext = ''; } $tmpFile = \OCP\Files::tmpFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); if ($this->file_exists($path)) { $source = $this->fopen($path, 'r'); file_put_contents($tmpFile, $source); } - self::$tmpFiles[$tmpFile] = $path; - return fopen('close://' . $tmpFile, $mode); + $handle = fopen($tmpFile, $mode); + return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) { + $this->writeBack($tmpFile, $path); + }); } return false; } @@ -514,15 +516,11 @@ public function getId() { return $this->id; } - public function writeBack($tmpFile) { - if (!isset(self::$tmpFiles[$tmpFile])) { - return false; - } - + public function writeBack($tmpFile, $path) { try { $this->getConnection()->putObject(array( 'Bucket' => $this->bucket, - 'Key' => $this->cleanKey(self::$tmpFiles[$tmpFile]), + 'Key' => $this->cleanKey($path), 'SourceFile' => $tmpFile, 'ContentType' => \OC::$server->getMimeTypeDetector()->detect($tmpFile), 'ContentLength' => filesize($tmpFile) diff --git a/apps/files_external/lib/Lib/Storage/Dropbox.php b/apps/files_external/lib/Lib/Storage/Dropbox.php index 45bc6cd0e9870..d2ba1cca7510f 100644 --- a/apps/files_external/lib/Lib/Storage/Dropbox.php +++ b/apps/files_external/lib/Lib/Storage/Dropbox.php @@ -31,6 +31,7 @@ namespace OCA\Files_External\Lib\Storage; use GuzzleHttp\Exception\RequestException; +use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use Icewind\Streams\RetryWrapper; use OCP\Files\StorageNotAvailableException; @@ -45,8 +46,6 @@ class Dropbox extends \OC\Files\Storage\Common { private $metaData = array(); private $oauth; - private static $tempFiles = array(); - public function __construct($params) { if (isset($params['configured']) && $params['configured'] == 'true' && isset($params['app_key']) @@ -305,27 +304,26 @@ public function fopen($path, $mode) { $ext = ''; } $tmpFile = \OCP\Files::tmpFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); if ($this->file_exists($path)) { $source = $this->fopen($path, 'r'); file_put_contents($tmpFile, $source); } - self::$tempFiles[$tmpFile] = $path; - return fopen('close://'.$tmpFile, $mode); + $handle = fopen($tmpFile, $mode); + return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) { + $this->writeBack($tmpFile, $path); + }); } return false; } - public function writeBack($tmpFile) { - if (isset(self::$tempFiles[$tmpFile])) { - $handle = fopen($tmpFile, 'r'); - try { - $this->dropbox->putFile(self::$tempFiles[$tmpFile], $handle); - unlink($tmpFile); - $this->deleteMetaData(self::$tempFiles[$tmpFile]); - } catch (\Exception $exception) { - \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); - } + public function writeBack($tmpFile, $path) { + $handle = fopen($tmpFile, 'r'); + try { + $this->dropbox->putFile($path, $handle); + unlink($tmpFile); + $this->deleteMetaData($path); + } catch (\Exception $exception) { + \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); } } diff --git a/apps/files_external/lib/Lib/Storage/FTP.php b/apps/files_external/lib/Lib/Storage/FTP.php index 6f34416d11198..22fe2090f305d 100644 --- a/apps/files_external/lib/Lib/Storage/FTP.php +++ b/apps/files_external/lib/Lib/Storage/FTP.php @@ -33,6 +33,7 @@ namespace OCA\Files_External\Lib\Storage; +use Icewind\Streams\CallbackWrapper; use Icewind\Streams\RetryWrapper; class FTP extends StreamWrapper{ @@ -127,21 +128,20 @@ public function fopen($path,$mode) { $ext=''; } $tmpFile=\OCP\Files::tmpFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); if ($this->file_exists($path)) { $this->getFile($path, $tmpFile); } - self::$tempFiles[$tmpFile]=$path; - return fopen('close://'.$tmpFile, $mode); + $handle = fopen($tmpFile, $mode); + return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) { + $this->writeBack($tmpFile, $path); + }); } return false; } - public function writeBack($tmpFile) { - if (isset(self::$tempFiles[$tmpFile])) { - $this->uploadFile($tmpFile, self::$tempFiles[$tmpFile]); - unlink($tmpFile); - } + public function writeBack($tmpFile, $path) { + $this->uploadFile($tmpFile, $path); + unlink($tmpFile); } /** diff --git a/apps/files_external/lib/Lib/Storage/Google.php b/apps/files_external/lib/Lib/Storage/Google.php index a3133cb4743dc..b22b0c29263c2 100644 --- a/apps/files_external/lib/Lib/Storage/Google.php +++ b/apps/files_external/lib/Lib/Storage/Google.php @@ -36,6 +36,7 @@ namespace OCA\Files_External\Lib\Storage; use GuzzleHttp\Exception\RequestException; +use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use Icewind\Streams\RetryWrapper; @@ -50,8 +51,6 @@ class Google extends \OC\Files\Storage\Common { private $service; private $driveFiles; - private static $tempFiles = array(); - // Google Doc mimetypes const FOLDER = 'application/vnd.google-apps.folder'; const DOCUMENT = 'application/vnd.google-apps.document'; @@ -495,94 +494,91 @@ public function fopen($path, $mode) { case 'c': case 'c+': $tmpFile = \OCP\Files::tmpFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); if ($this->file_exists($path)) { $source = $this->fopen($path, 'rb'); file_put_contents($tmpFile, $source); } - self::$tempFiles[$tmpFile] = $path; - return fopen('close://'.$tmpFile, $mode); + $handle = fopen($tmpFile, $mode); + return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) { + $this->writeBack($tmpFile, $path); + }); } } - public function writeBack($tmpFile) { - if (isset(self::$tempFiles[$tmpFile])) { - $path = self::$tempFiles[$tmpFile]; - $parentFolder = $this->getDriveFile(dirname($path)); - if ($parentFolder) { - $mimetype = \OC::$server->getMimeTypeDetector()->detect($tmpFile); - $params = array( - 'mimeType' => $mimetype, - 'uploadType' => 'media' - ); - $result = false; + public function writeBack($tmpFile, $path) { + $parentFolder = $this->getDriveFile(dirname($path)); + if ($parentFolder) { + $mimetype = \OC::$server->getMimeTypeDetector()->detect($tmpFile); + $params = array( + 'mimeType' => $mimetype, + 'uploadType' => 'media' + ); + $result = false; + + $chunkSizeBytes = 10 * 1024 * 1024; + + $useChunking = false; + $size = filesize($tmpFile); + if ($size > $chunkSizeBytes) { + $useChunking = true; + } else { + $params['data'] = file_get_contents($tmpFile); + } - $chunkSizeBytes = 10 * 1024 * 1024; + if ($this->file_exists($path)) { + $file = $this->getDriveFile($path); + $this->client->setDefer($useChunking); + $request = $this->service->files->update($file->getId(), $file, $params); + } else { + $file = new \Google_Service_Drive_DriveFile(); + $file->setTitle(basename($path)); + $file->setMimeType($mimetype); + $parent = new \Google_Service_Drive_ParentReference(); + $parent->setId($parentFolder->getId()); + $file->setParents(array($parent)); + $this->client->setDefer($useChunking); + $request = $this->service->files->insert($file, $params); + } - $useChunking = false; - $size = filesize($tmpFile); - if ($size > $chunkSizeBytes) { - $useChunking = true; - } else { - $params['data'] = file_get_contents($tmpFile); + if ($useChunking) { + // Create a media file upload to represent our upload process. + $media = new \Google_Http_MediaFileUpload( + $this->client, + $request, + 'text/plain', + null, + true, + $chunkSizeBytes + ); + $media->setFileSize($size); + + // Upload the various chunks. $status will be false until the process is + // complete. + $status = false; + $handle = fopen($tmpFile, 'rb'); + while (!$status && !feof($handle)) { + $chunk = fread($handle, $chunkSizeBytes); + $status = $media->nextChunk($chunk); } - if ($this->file_exists($path)) { - $file = $this->getDriveFile($path); - $this->client->setDefer($useChunking); - $request = $this->service->files->update($file->getId(), $file, $params); - } else { - $file = new \Google_Service_Drive_DriveFile(); - $file->setTitle(basename($path)); - $file->setMimeType($mimetype); - $parent = new \Google_Service_Drive_ParentReference(); - $parent->setId($parentFolder->getId()); - $file->setParents(array($parent)); - $this->client->setDefer($useChunking); - $request = $this->service->files->insert($file, $params); + // The final value of $status will be the data from the API for the object + // that has been uploaded. + $result = false; + if ($status !== false) { + $result = $status; } - if ($useChunking) { - // Create a media file upload to represent our upload process. - $media = new \Google_Http_MediaFileUpload( - $this->client, - $request, - 'text/plain', - null, - true, - $chunkSizeBytes - ); - $media->setFileSize($size); - - // Upload the various chunks. $status will be false until the process is - // complete. - $status = false; - $handle = fopen($tmpFile, 'rb'); - while (!$status && !feof($handle)) { - $chunk = fread($handle, $chunkSizeBytes); - $status = $media->nextChunk($chunk); - } - - // The final value of $status will be the data from the API for the object - // that has been uploaded. - $result = false; - if ($status !== false) { - $result = $status; - } - - fclose($handle); - } else { - $result = $request; - } + fclose($handle); + } else { + $result = $request; + } - // Reset to the client to execute requests immediately in the future. - $this->client->setDefer(false); + // Reset to the client to execute requests immediately in the future. + $this->client->setDefer(false); - if ($result) { - $this->setDriveFile($path, $result); - } + if ($result) { + $this->setDriveFile($path, $result); } - unlink($tmpFile); } } diff --git a/apps/files_external/lib/Lib/Storage/Swift.php b/apps/files_external/lib/Lib/Storage/Swift.php index ba0b4898e2ec9..5fec278ef3de0 100644 --- a/apps/files_external/lib/Lib/Storage/Swift.php +++ b/apps/files_external/lib/Lib/Storage/Swift.php @@ -37,6 +37,7 @@ use Guzzle\Http\Url; use Guzzle\Http\Exception\ClientErrorResponseException; +use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use OpenCloud; use OpenCloud\Common\Exceptions; @@ -410,7 +411,6 @@ public function fopen($path, $mode) { $ext = ''; } $tmpFile = \OCP\Files::tmpFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); // Fetch existing file if required if ($mode[0] !== 'w' && $this->file_exists($path)) { if ($mode[0] === 'x') { @@ -424,9 +424,10 @@ public function fopen($path, $mode) { fseek($tmpFile, 0, SEEK_END); } } - self::$tmpFiles[$tmpFile] = $path; - - return fopen('close://' . $tmpFile, $mode); + $handle = fopen($tmpFile, $mode); + return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) { + $this->writeBack($tmpFile, $path); + }); } } @@ -615,12 +616,9 @@ public function getContainer() { return $this->container; } - public function writeBack($tmpFile) { - if (!isset(self::$tmpFiles[$tmpFile])) { - return false; - } + public function writeBack($tmpFile, $path) { $fileData = fopen($tmpFile, 'r'); - $this->getContainer()->uploadObject(self::$tmpFiles[$tmpFile], $fileData); + $this->getContainer()->uploadObject($path, $fileData); // invalidate target object to force repopulation on fetch $this->objectCache->remove(self::$tmpFiles[$tmpFile]); unlink($tmpFile); diff --git a/apps/updatenotification/lib/Notification/BackgroundJob.php b/apps/updatenotification/lib/Notification/BackgroundJob.php index 7bcc0e869050a..83a9bdb599ae1 100644 --- a/apps/updatenotification/lib/Notification/BackgroundJob.php +++ b/apps/updatenotification/lib/Notification/BackgroundJob.php @@ -30,8 +30,6 @@ use OCP\IConfig; use OCP\IGroup; use OCP\IGroupManager; -use OCP\IURLGenerator; -use OCP\IUser; use OCP\Notification\IManager; class BackgroundJob extends TimedJob { @@ -51,10 +49,7 @@ class BackgroundJob extends TimedJob { /** @var IClientService */ protected $client; - /** @var IURLGenerator */ - protected $urlGenerator; - - /** @var IUser[] */ + /** @var string[] */ protected $users; /** @@ -65,9 +60,8 @@ class BackgroundJob extends TimedJob { * @param IGroupManager $groupManager * @param IAppManager $appManager * @param IClientService $client - * @param IURLGenerator $urlGenerator */ - public function __construct(IConfig $config, IManager $notificationManager, IGroupManager $groupManager, IAppManager $appManager, IClientService $client, IURLGenerator $urlGenerator) { + public function __construct(IConfig $config, IManager $notificationManager, IGroupManager $groupManager, IAppManager $appManager, IClientService $client) { // Run once a day $this->setInterval(60 * 60 * 24); @@ -76,7 +70,6 @@ public function __construct(IConfig $config, IManager $notificationManager, IGro $this->groupManager = $groupManager; $this->appManager = $appManager; $this->client = $client; - $this->urlGenerator = $urlGenerator; } protected function run($argument) { @@ -97,8 +90,7 @@ protected function checkCoreUpdate() { $status = $updater->check(); if (isset($status['version'])) { - $url = $this->urlGenerator->linkToRouteAbsolute('settings.AdminSettings.index') . '#updater'; - $this->createNotifications('core', $status['version'], $url, $status['versionstring']); + $this->createNotifications('core', $status['version'], $status['versionstring']); } } @@ -110,8 +102,7 @@ protected function checkAppUpdates() { foreach ($apps as $app) { $update = $this->isUpdateAvailable($app); if ($update !== false) { - $url = $this->urlGenerator->linkToRouteAbsolute('settings.AppSettings.viewApps') . '#app-' . $app; - $this->createNotifications($app, $update, $url); + $this->createNotifications($app, $update); } } } @@ -121,10 +112,9 @@ protected function checkAppUpdates() { * * @param string $app * @param string $version - * @param string $url * @param string $visibleVersion */ - protected function createNotifications($app, $version, $url, $visibleVersion = '') { + protected function createNotifications($app, $version, $visibleVersion = '') { $lastNotification = $this->config->getAppValue('updatenotification', $app, false); if ($lastNotification === $version) { // We already notified about this update @@ -138,8 +128,7 @@ protected function createNotifications($app, $version, $url, $visibleVersion = ' $notification = $this->notificationManager->createNotification(); $notification->setApp('updatenotification') ->setDateTime(new \DateTime()) - ->setObject($app, $version) - ->setLink($url); + ->setObject($app, $version); if ($visibleVersion !== '') { $notification->setSubject('update_available', ['version' => $visibleVersion]); diff --git a/apps/updatenotification/lib/Notification/Notifier.php b/apps/updatenotification/lib/Notification/Notifier.php index 00cc94095ca1d..079ec4c5e0ae8 100644 --- a/apps/updatenotification/lib/Notification/Notifier.php +++ b/apps/updatenotification/lib/Notification/Notifier.php @@ -24,7 +24,10 @@ namespace OCA\UpdateNotification\Notification; +use OCP\IGroupManager; use OCP\IURLGenerator; +use OCP\IUser; +use OCP\IUserSession; use OCP\L10N\IFactory; use OCP\Notification\IManager; use OCP\Notification\INotification; @@ -41,6 +44,12 @@ class Notifier implements INotifier { /** @var IFactory */ protected $l10NFactory; + /** @var IUserSession */ + protected $userSession; + + /** @var IGroupManager */ + protected $groupManager; + /** @var string[] */ protected $appVersions; @@ -50,11 +59,15 @@ class Notifier implements INotifier { * @param IURLGenerator $url * @param IManager $notificationManager * @param IFactory $l10NFactory + * @param IUserSession $userSession + * @param IGroupManager $groupManager */ - public function __construct(IURLGenerator $url, IManager $notificationManager, IFactory $l10NFactory) { + public function __construct(IURLGenerator $url, IManager $notificationManager, IFactory $l10NFactory, IUserSession $userSession, IGroupManager $groupManager) { $this->url = $url; $this->notificationManager = $notificationManager; $this->l10NFactory = $l10NFactory; + $this->userSession = $userSession; + $this->groupManager = $groupManager; $this->appVersions = $this->getAppVersions(); } @@ -76,6 +89,10 @@ public function prepare(INotification $notification, $languageCode) { $parameters = $notification->getSubjectParameters(); $notification->setParsedSubject($l->t('Update to %1$s is available.', [$parameters['version']])); + + if ($this->isAdmin()) { + $notification->setLink($this->url->linkToRouteAbsolute('settings.AdminSettings.index') . '#updater'); + } } else { $appInfo = $this->getAppInfo($notification->getObjectType()); $appName = ($appInfo === null) ? $notification->getObjectType() : $appInfo['name']; @@ -92,6 +109,10 @@ public function prepare(INotification $notification, $languageCode) { 'name' => $appName, ] ]); + + if ($this->isAdmin()) { + $notification->setLink($this->url->linkToRouteAbsolute('settings.AppSettings.viewApps') . '#app-' . $notification->getObjectType()); + } } $notification->setIcon($this->url->getAbsoluteURL($this->url->imagePath('updatenotification', 'notification.svg'))); @@ -113,6 +134,19 @@ protected function updateAlreadyInstalledCheck(INotification $notification, $ins } } + /** + * @return bool + */ + protected function isAdmin() { + $user = $this->userSession->getUser(); + + if ($user instanceof IUser) { + return $this->groupManager->isAdmin($user->getUID()); + } + + return false; + } + protected function getCoreVersions() { return implode('.', \OCP\Util::getVersion()); } diff --git a/apps/updatenotification/tests/Notification/BackgroundJobTest.php b/apps/updatenotification/tests/Notification/BackgroundJobTest.php index 911b1cc8e2f0e..57771ec0ae903 100644 --- a/apps/updatenotification/tests/Notification/BackgroundJobTest.php +++ b/apps/updatenotification/tests/Notification/BackgroundJobTest.php @@ -45,18 +45,15 @@ class BackgroundJobTest extends TestCase { protected $appManager; /** @var IClientService|\PHPUnit_Framework_MockObject_MockObject */ protected $client; - /** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */ - protected $urlGenerator; public function setUp() { parent::setUp(); - $this->config = $this->getMockBuilder('OCP\IConfig')->getMock(); - $this->notificationManager = $this->getMockBuilder('OCP\Notification\IManager')->getMock(); - $this->groupManager = $this->getMockBuilder('OCP\IGroupManager')->getMock(); - $this->appManager = $this->getMockBuilder('OCP\App\IAppManager')->getMock(); - $this->client = $this->getMockBuilder('OCP\Http\Client\IClientService')->getMock(); - $this->urlGenerator = $this->getMockBuilder('OCP\IURLGenerator')->getMock(); + $this->config = $this->createMock(\OCP\IConfig::class); + $this->notificationManager = $this->createMock(\OCP\Notification\IManager::class); + $this->groupManager = $this->createMock(\OCP\IGroupManager::class); + $this->appManager = $this->createMock(\OCP\App\IAppManager::class); + $this->client = $this->createMock(\OCP\Http\Client\IClientService::class); } /** @@ -70,8 +67,7 @@ protected function getJob(array $methods = []) { $this->notificationManager, $this->groupManager, $this->appManager, - $this->client, - $this->urlGenerator + $this->client ); } { return $this->getMockBuilder('OCA\UpdateNotification\Notification\BackgroundJob') @@ -81,7 +77,6 @@ protected function getJob(array $methods = []) { $this->groupManager, $this->appManager, $this->client, - $this->urlGenerator, ]) ->setMethods($methods) ->getMock(); @@ -160,20 +155,12 @@ public function testCheckCoreUpdate($channel, $versionCheck, $notification, $rea } if ($notification === null) { - $this->urlGenerator->expects($this->never()) - ->method('linkToRouteAbsolute'); - $job->expects($this->never()) ->method('createNotifications'); } else { - $this->urlGenerator->expects($this->once()) - ->method('linkToRouteAbsolute') - ->with('settings.AdminSettings.index') - ->willReturn('admin-url'); - $job->expects($this->once()) ->method('createNotifications') - ->willReturn('core', $notification, 'admin-url#updater', $readableVersion); + ->willReturn('core', $notification, $readableVersion); } $this->invokePrivate($job, 'checkCoreUpdate'); @@ -188,7 +175,7 @@ public function dataCheckAppUpdates() { ['app2', '1.9.2'], ], [ - ['app2', '1.9.2', 'apps-url#app-app2'], + ['app2', '1.9.2'], ], ], ]; @@ -215,11 +202,6 @@ public function testCheckAppUpdates(array $apps, array $isUpdateAvailable, array ->method('isUpdateAvailable') ->willReturnMap($isUpdateAvailable); - $this->urlGenerator->expects($this->exactly(sizeof($notifications))) - ->method('linkToRouteAbsolute') - ->with('settings.AppSettings.viewApps') - ->willReturn('apps-url'); - $mockedMethod = $job->expects($this->exactly(sizeof($notifications))) ->method('createNotifications'); call_user_func_array([$mockedMethod, 'withConsecutive'], $notifications); @@ -229,9 +211,9 @@ public function testCheckAppUpdates(array $apps, array $isUpdateAvailable, array public function dataCreateNotifications() { return [ - ['app1', '1.0.0', 'link1', '1.0.0', false, false, null, null], - ['app2', '1.0.1', 'link2', '1.0.0', '1.0.0', true, ['user1'], [['user1']]], - ['app3', '1.0.1', 'link3', false, false, true, ['user2', 'user3'], [['user2'], ['user3']]], + ['app1', '1.0.0', '1.0.0', false, false, null, null], + ['app2', '1.0.1', '1.0.0', '1.0.0', true, ['user1'], [['user1']]], + ['app3', '1.0.1', false, false, true, ['user2', 'user3'], [['user2'], ['user3']]], ]; } @@ -240,14 +222,13 @@ public function dataCreateNotifications() { * * @param string $app * @param string $version - * @param string $url * @param string|false $lastNotification * @param string|false $callDelete * @param bool $createNotification * @param string[]|null $users * @param array|null $userNotifications */ - public function testCreateNotifications($app, $version, $url, $lastNotification, $callDelete, $createNotification, $users, $userNotifications) { + public function testCreateNotifications($app, $version, $lastNotification, $callDelete, $createNotification, $users, $userNotifications) { $job = $this->getJob([ 'deleteOutdatedNotifications', 'getUsersToNotify', @@ -299,10 +280,6 @@ public function testCreateNotifications($app, $version, $url, $lastNotification, ->method('setSubject') ->with('update_available') ->willReturnSelf(); - $notification->expects($this->once()) - ->method('setLink') - ->with($url) - ->willReturnSelf(); if ($userNotifications !== null) { $mockedMethod = $notification->expects($this->exactly(sizeof($userNotifications))) @@ -323,7 +300,7 @@ public function testCreateNotifications($app, $version, $url, $lastNotification, ->method('createNotification'); } - $this->invokePrivate($job, 'createNotifications', [$app, $version, $url]); + $this->invokePrivate($job, 'createNotifications', [$app, $version]); } public function dataGetUsersToNotify() { diff --git a/apps/updatenotification/tests/Notification/NotifierTest.php b/apps/updatenotification/tests/Notification/NotifierTest.php index 421fcada68944..e809ce1163569 100644 --- a/apps/updatenotification/tests/Notification/NotifierTest.php +++ b/apps/updatenotification/tests/Notification/NotifierTest.php @@ -24,7 +24,9 @@ use OCA\UpdateNotification\Notification\Notifier; +use OCP\IGroupManager; use OCP\IURLGenerator; +use OCP\IUserSession; use OCP\L10N\IFactory; use OCP\Notification\IManager; use OCP\Notification\INotification; @@ -38,6 +40,10 @@ class NotifierTest extends TestCase { protected $notificationManager; /** @var IFactory|\PHPUnit_Framework_MockObject_MockObject */ protected $l10nFactory; + /** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */ + protected $userSession; + /** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */ + protected $groupManager; public function setUp() { parent::setUp(); @@ -45,6 +51,8 @@ public function setUp() { $this->urlGenerator = $this->createMock(IURLGenerator::class); $this->notificationManager = $this->createMock(IManager::class); $this->l10nFactory = $this->createMock(IFactory::class); + $this->userSession = $this->createMock(IUserSession::class); + $this->groupManager = $this->createMock(IGroupManager::class); } /** @@ -56,7 +64,9 @@ protected function getNotifier(array $methods = []) { return new Notifier( $this->urlGenerator, $this->notificationManager, - $this->l10nFactory + $this->l10nFactory, + $this->userSession, + $this->groupManager ); } { return $this->getMockBuilder(Notifier::class) @@ -64,6 +74,8 @@ protected function getNotifier(array $methods = []) { $this->urlGenerator, $this->notificationManager, $this->l10nFactory, + $this->userSession, + $this->groupManager, ]) ->setMethods($methods) ->getMock(); diff --git a/lib/base.php b/lib/base.php index 4a9158eff64bd..dc8b29932eff2 100644 --- a/lib/base.php +++ b/lib/base.php @@ -669,9 +669,6 @@ public static function init() { OC\Log\ErrorHandler::register($debug); } - // register the stream wrappers - stream_wrapper_register('close', 'OC\Files\Stream\Close'); - \OC::$server->getEventLogger()->start('init_session', 'Initialize session'); OC_App::loadApps(array('session')); if (!self::$CLI) { @@ -791,23 +788,31 @@ public static function init() { && !\OC::$server->getTrustedDomainHelper()->isTrustedDomain($host) && self::$server->getConfig()->getSystemValue('installed', false) ) { - header('HTTP/1.1 400 Bad Request'); - header('Status: 400 Bad Request'); + // Allow access to CSS resources + $isScssRequest = false; + if(strpos($request->getPathInfo(), '/css/') === 0) { + $isScssRequest = true; + } - \OC::$server->getLogger()->warning( + if (!$isScssRequest) { + header('HTTP/1.1 400 Bad Request'); + header('Status: 400 Bad Request'); + + \OC::$server->getLogger()->warning( 'Trusted domain error. "{remoteAddress}" tried to access using "{host}" as host.', [ 'app' => 'core', 'remoteAddress' => $request->getRemoteAddress(), 'host' => $host, ] - ); + ); - $tmpl = new OCP\Template('core', 'untrustedDomain', 'guest'); - $tmpl->assign('domain', $host); - $tmpl->printPage(); + $tmpl = new OCP\Template('core', 'untrustedDomain', 'guest'); + $tmpl->assign('domain', $host); + $tmpl->printPage(); - exit(); + exit(); + } } \OC::$server->getEventLogger()->end('boot'); } diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index c32383521fd64..48b457bbabe64 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -554,7 +554,6 @@ 'OC\\Files\\Storage\\Wrapper\\PermissionsMask' => $baseDir . '/lib/private/Files/Storage/Wrapper/PermissionsMask.php', 'OC\\Files\\Storage\\Wrapper\\Quota' => $baseDir . '/lib/private/Files/Storage/Wrapper/Quota.php', 'OC\\Files\\Storage\\Wrapper\\Wrapper' => $baseDir . '/lib/private/Files/Storage/Wrapper/Wrapper.php', - 'OC\\Files\\Stream\\Close' => $baseDir . '/lib/private/Files/Stream/Close.php', 'OC\\Files\\Stream\\Encryption' => $baseDir . '/lib/private/Files/Stream/Encryption.php', 'OC\\Files\\Stream\\Quota' => $baseDir . '/lib/private/Files/Stream/Quota.php', 'OC\\Files\\Type\\Detection' => $baseDir . '/lib/private/Files/Type/Detection.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index ad5e39326ab79..7c14ad7e847a3 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -584,7 +584,6 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Files\\Storage\\Wrapper\\PermissionsMask' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/PermissionsMask.php', 'OC\\Files\\Storage\\Wrapper\\Quota' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Quota.php', 'OC\\Files\\Storage\\Wrapper\\Wrapper' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Wrapper.php', - 'OC\\Files\\Stream\\Close' => __DIR__ . '/../../..' . '/lib/private/Files/Stream/Close.php', 'OC\\Files\\Stream\\Encryption' => __DIR__ . '/../../..' . '/lib/private/Files/Stream/Encryption.php', 'OC\\Files\\Stream\\Quota' => __DIR__ . '/../../..' . '/lib/private/Files/Stream/Quota.php', 'OC\\Files\\Type\\Detection' => __DIR__ . '/../../..' . '/lib/private/Files/Type/Detection.php', diff --git a/lib/private/App/AppStore/Fetcher/AppFetcher.php b/lib/private/App/AppStore/Fetcher/AppFetcher.php index 9ebc12dbc27c7..7c5efafc92fac 100644 --- a/lib/private/App/AppStore/Fetcher/AppFetcher.php +++ b/lib/private/App/AppStore/Fetcher/AppFetcher.php @@ -59,11 +59,14 @@ public function __construct(IAppData $appData, /** * Only returns the latest compatible app release in the releases array * + * @param string $ETag + * @param string $content + * * @return array */ - protected function fetch() { + protected function fetch($ETag, $content) { /** @var mixed[] $response */ - $response = parent::fetch(); + $response = parent::fetch($ETag, $content); $ncVersion = $this->config->getSystemValue('version'); $ncMajorVersion = explode('.', $ncVersion)[0]; diff --git a/lib/private/App/AppStore/Fetcher/Fetcher.php b/lib/private/App/AppStore/Fetcher/Fetcher.php index 2067242e81725..dab79e11821dd 100644 --- a/lib/private/App/AppStore/Fetcher/Fetcher.php +++ b/lib/private/App/AppStore/Fetcher/Fetcher.php @@ -21,6 +21,7 @@ namespace OC\App\AppStore\Fetcher; +use OCP\AppFramework\Http; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Files\IAppData; use OCP\Files\NotFoundException; @@ -62,15 +63,37 @@ public function __construct(IAppData $appData, /** * Fetches the response from the server * + * @param string $ETag + * @param string $content + * * @return array */ - protected function fetch() { + protected function fetch($ETag, $content) { + $options = []; + + if ($ETag !== '') { + $options['headers'] = [ + 'If-None-Match' => $ETag, + ]; + } + $client = $this->clientService->newClient(); - $response = $client->get($this->endpointUrl); + $response = $client->get($this->endpointUrl, $options); + $responseJson = []; - $responseJson['data'] = json_decode($response->getBody(), true); + if ($response->getStatusCode() === Http::STATUS_NOT_MODIFIED) { + $responseJson['data'] = json_decode($content, true); + } else { + $responseJson['data'] = json_decode($response->getBody(), true); + $ETag = $response->getHeader('ETag'); + } + $responseJson['timestamp'] = $this->timeFactory->getTime(); $responseJson['ncversion'] = $this->config->getSystemValue('version'); + if ($ETag !== '') { + $responseJson['ETag'] = $ETag; + } + return $responseJson; } @@ -82,6 +105,9 @@ protected function fetch() { public function get() { $rootFolder = $this->appData->getFolder('/'); + $ETag = ''; + $content = ''; + try { // File does already exists $file = $rootFolder->getFile($this->fileName); @@ -95,6 +121,11 @@ public function get() { isset($jsonBlob['ncversion']) && $jsonBlob['ncversion'] === $this->config->getSystemValue('version', '0.0.0')) { return $jsonBlob['data']; } + + if (isset($jsonBlob['ETag'])) { + $ETag = $jsonBlob['ETag']; + $content = json_encode($jsonBlob['data']); + } } } catch (NotFoundException $e) { // File does not already exists @@ -103,7 +134,7 @@ public function get() { // Refresh the file content try { - $responseJson = $this->fetch(); + $responseJson = $this->fetch($ETag, $content); $file->putContent(json_encode($responseJson)); return json_decode($file->getContent(), true)['data']; } catch (\Exception $e) { diff --git a/lib/private/Archive/TAR.php b/lib/private/Archive/TAR.php index bbd24bd05a1fe..07ccd09f3996f 100644 --- a/lib/private/Archive/TAR.php +++ b/lib/private/Archive/TAR.php @@ -33,6 +33,8 @@ namespace OC\Archive; +use Icewind\Streams\CallbackWrapper; + class TAR extends Archive { const PLAIN = 0; const GZIP = 1; @@ -359,22 +361,19 @@ function getStream($path, $mode) { if ($mode == 'r' or $mode == 'rb') { return fopen($tmpFile, $mode); } else { - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); - self::$tempFiles[$tmpFile] = $path; - return fopen('close://' . $tmpFile, $mode); + $handle = fopen($tmpFile, $mode); + return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) { + $this->writeBack($tmpFile, $path); + }); } } - private static $tempFiles = array(); - /** * write back temporary files */ - function writeBack($tmpFile) { - if (isset(self::$tempFiles[$tmpFile])) { - $this->addFile(self::$tempFiles[$tmpFile], $tmpFile); - unlink($tmpFile); - } + function writeBack($tmpFile, $path) { + $this->addFile($path, $tmpFile); + unlink($tmpFile); } /** diff --git a/lib/private/Archive/ZIP.php b/lib/private/Archive/ZIP.php index 9e9fe40b2b471..0ed0f48acc459 100644 --- a/lib/private/Archive/ZIP.php +++ b/lib/private/Archive/ZIP.php @@ -31,6 +31,8 @@ namespace OC\Archive; +use Icewind\Streams\CallbackWrapper; + class ZIP extends Archive{ /** * @var \ZipArchive zip @@ -198,24 +200,22 @@ function getStream($path, $mode) { $ext=''; } $tmpFile=\OCP\Files::tmpFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); if($this->fileExists($path)) { $this->extractFile($path, $tmpFile); } - self::$tempFiles[$tmpFile]=$path; - return fopen('close://'.$tmpFile, $mode); + $handle = fopen($tmpFile, $mode); + return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) { + $this->writeBack($tmpFile, $path); + }); } } - private static $tempFiles=array(); /** * write back temporary files */ - function writeBack($tmpFile) { - if(isset(self::$tempFiles[$tmpFile])) { - $this->addFile(self::$tempFiles[$tmpFile], $tmpFile); - unlink($tmpFile); - } + function writeBack($tmpFile, $path) { + $this->addFile($path, $tmpFile); + unlink($tmpFile); } /** diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index 2dcf830cc1e7f..ab77c21e6c483 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -25,16 +25,12 @@ namespace OC\Files\ObjectStore; +use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use OC\Files\Cache\CacheEntry; use OCP\Files\ObjectStore\IObjectStore; class ObjectStoreStorage extends \OC\Files\Storage\Common { - - /** - * @var array - */ - private static $tmpFiles = array(); /** * @var \OCP\Files\ObjectStore\IObjectStore $objectStore */ @@ -291,14 +287,14 @@ public function fopen($path, $mode) { $ext = ''; } $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); if ($this->file_exists($path)) { $source = $this->fopen($path, 'r'); file_put_contents($tmpFile, $source); } - self::$tmpFiles[$tmpFile] = $path; - - return fopen('close://' . $tmpFile, $mode); + $handle = fopen($tmpFile, $mode); + return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) { + $this->writeBack($tmpFile, $path); + }); } return false; } @@ -368,12 +364,7 @@ public function touch($path, $mtime = null) { return true; } - public function writeBack($tmpFile) { - if (!isset(self::$tmpFiles[$tmpFile])) { - return; - } - - $path = self::$tmpFiles[$tmpFile]; + public function writeBack($tmpFile, $path) { $stat = $this->stat($path); if (empty($stat)) { // create new file diff --git a/lib/private/Files/Storage/DAV.php b/lib/private/Files/Storage/DAV.php index ea4bbba2748c0..62906f9355b84 100644 --- a/lib/private/Files/Storage/DAV.php +++ b/lib/private/Files/Storage/DAV.php @@ -36,6 +36,7 @@ use Exception; use GuzzleHttp\Exception\RequestException; use GuzzleHttp\Message\ResponseInterface; +use Icewind\Streams\CallbackWrapper; use OC\Files\Filesystem; use OC\Files\Stream\Close; use Icewind\Streams\IteratorDirectory; @@ -77,8 +78,6 @@ class DAV extends Common { private $client; /** @var ArrayCache */ private $statCache; - /** @var array */ - private static $tempFiles = []; /** @var \OCP\Http\Client\IClientService */ private $httpClientService; @@ -409,20 +408,19 @@ public function fopen($path, $mode) { } $tmpFile = $tempManager->getTemporaryFile($ext); } - Close::registerCallback($tmpFile, array($this, 'writeBack')); - self::$tempFiles[$tmpFile] = $path; - return fopen('close://' . $tmpFile, $mode); + $handle = fopen($tmpFile, $mode); + return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) { + $this->writeBack($tmpFile, $path); + }); } } /** * @param string $tmpFile */ - public function writeBack($tmpFile) { - if (isset(self::$tempFiles[$tmpFile])) { - $this->uploadFile($tmpFile, self::$tempFiles[$tmpFile]); - unlink($tmpFile); - } + public function writeBack($tmpFile, $path) { + $this->uploadFile($tmpFile, $path); + unlink($tmpFile); } /** {@inheritdoc} */ diff --git a/lib/private/Files/Stream/Close.php b/lib/private/Files/Stream/Close.php deleted file mode 100644 index 7cc9903c9124b..0000000000000 --- a/lib/private/Files/Stream/Close.php +++ /dev/null @@ -1,119 +0,0 @@ - - * @author Morris Jobke - * @author Robin Appelman - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OC\Files\Stream; - -/** - * stream wrapper that provides a callback on stream close - */ -class Close { - private static $callBacks = array(); - private $path = ''; - private $source; - private static $open = array(); - - public function stream_open($path, $mode, $options, &$opened_path) { - $path = substr($path, strlen('close://')); - $this->path = $path; - $this->source = fopen($path, $mode); - if (is_resource($this->source)) { - $this->meta = stream_get_meta_data($this->source); - } - self::$open[] = $path; - return is_resource($this->source); - } - - public function stream_seek($offset, $whence = SEEK_SET) { - return fseek($this->source, $offset, $whence) === 0; - } - - public function stream_tell() { - return ftell($this->source); - } - - public function stream_read($count) { - return fread($this->source, $count); - } - - public function stream_write($data) { - return fwrite($this->source, $data); - } - - public function stream_set_option($option, $arg1, $arg2) { - switch ($option) { - case STREAM_OPTION_BLOCKING: - stream_set_blocking($this->source, $arg1); - break; - case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout($this->source, $arg1, $arg2); - break; - case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer($this->source, $arg1, $arg2); - } - } - - public function stream_stat() { - return fstat($this->source); - } - - public function stream_lock($mode) { - flock($this->source, $mode); - } - - public function stream_flush() { - return fflush($this->source); - } - - public function stream_eof() { - return feof($this->source); - } - - public function url_stat($path) { - $path = substr($path, strlen('close://')); - if (file_exists($path)) { - return stat($path); - } else { - return false; - } - } - - public function stream_close() { - fclose($this->source); - if (isset(self::$callBacks[$this->path])) { - call_user_func(self::$callBacks[$this->path], $this->path); - } - } - - public function unlink($path) { - $path = substr($path, strlen('close://')); - return unlink($path); - } - - /** - * @param string $path - */ - public static function registerCallback($path, $callback) { - self::$callBacks[$path] = $callback; - } -} diff --git a/lib/private/Security/CertificateManager.php b/lib/private/Security/CertificateManager.php index f7bf0df58c5ff..461ef9457a7e1 100644 --- a/lib/private/Security/CertificateManager.php +++ b/lib/private/Security/CertificateManager.php @@ -30,6 +30,7 @@ use OC\Files\Filesystem; use OCP\ICertificateManager; use OCP\IConfig; +use OCP\ILogger; /** * Manage trusted certificates for users @@ -50,15 +51,22 @@ class CertificateManager implements ICertificateManager { */ protected $config; + /** + * @var ILogger + */ + protected $logger; + /** * @param string $uid * @param \OC\Files\View $view relative to data/ * @param IConfig $config + * @param ILogger $logger */ - public function __construct($uid, \OC\Files\View $view, IConfig $config) { + public function __construct($uid, \OC\Files\View $view, IConfig $config, ILogger $logger) { $this->uid = $uid; $this->view = $view; $this->config = $config; + $this->logger = $logger; } /** @@ -104,6 +112,13 @@ public function createCertificateBundle() { $this->view->mkdir($path); } + $defaultCertificates = file_get_contents(\OC::$SERVERROOT . '/resources/config/ca-bundle.crt'); + if (strlen($defaultCertificates) < 1024) { // sanity check to verify that we have some content for our bundle + // log as exception so we have a stacktrace + $this->logger->logException(new \Exception('Shipped ca-bundle is empty, refusing to create certificate bundle')); + return; + } + $fhCerts = $this->view->fopen($path . '/rootcerts.crt', 'w'); // Write user certificates @@ -117,7 +132,6 @@ public function createCertificateBundle() { } // Append the default certificates - $defaultCertificates = file_get_contents(\OC::$SERVERROOT . '/resources/config/ca-bundle.crt'); fwrite($fhCerts, $defaultCertificates); // Append the system certificate bundle @@ -203,7 +217,7 @@ public function getAbsoluteBundlePath($uid = '') { } if ($this->needsRebundling($uid)) { if (is_null($uid)) { - $manager = new CertificateManager(null, $this->view, $this->config); + $manager = new CertificateManager(null, $this->view, $this->config, $this->logger); $manager->createCertificateBundle(); } else { $this->createCertificateBundle(); diff --git a/lib/private/Server.php b/lib/private/Server.php index cc295dccd17c2..147fa89582a62 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -482,7 +482,7 @@ public function __construct($webRoot, \OC\Config $config) { $uid = $user ? $user : null; return new ClientService( $c->getConfig(), - new \OC\Security\CertificateManager($uid, new View(), $c->getConfig()) + new \OC\Security\CertificateManager($uid, new View(), $c->getConfig(), $c->getLogger()) ); }); $this->registerService('EventLogger', function (Server $c) { @@ -1220,7 +1220,7 @@ public function getCertificateManager($userId = '') { } $userId = $user->getUID(); } - return new CertificateManager($userId, new View(), $this->getConfig()); + return new CertificateManager($userId, new View(), $this->getConfig(), $this->getLogger()); } /** diff --git a/lib/private/TemplateLayout.php b/lib/private/TemplateLayout.php index 67ba831dfafeb..bc6a485ad4369 100644 --- a/lib/private/TemplateLayout.php +++ b/lib/private/TemplateLayout.php @@ -166,9 +166,9 @@ public function __construct( $renderAs, $appId = '' ) { $cssFiles = self::findStylesheetFiles(\OC_Util::$styles); } else { $cssFiles = array( - [\OC::$SERVERROOT, '', 'core/css/global.css'], - [\OC::$SERVERROOT, '', 'core/css/fonts.css'], - [\OC::$SERVERROOT, '', 'core/css/installation.css'] + [\OC::$SERVERROOT, \OC::$WEBROOT, 'core/css/global.css'], + [\OC::$SERVERROOT, \OC::$WEBROOT, 'core/css/fonts.css'], + [\OC::$SERVERROOT, \OC::$WEBROOT, 'core/css/installation.css'] ); } $this->assign('cssfiles', array()); diff --git a/lib/private/User/Database.php b/lib/private/User/Database.php index 28cb330285848..69826f49be30f 100644 --- a/lib/private/User/Database.php +++ b/lib/private/User/Database.php @@ -75,6 +75,7 @@ class Database extends Backend implements IUserBackend { */ public function __construct($eventDispatcher = null) { $this->cache = new CappedMemoryCache(); + $this->cache[null] = false; $this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->getEventDispatcher(); } diff --git a/tests/lib/App/AppStore/Fetcher/AppFetcherTest.php b/tests/lib/App/AppStore/Fetcher/AppFetcherTest.php index 3affab2dbaa4b..9d09898bb95c9 100644 --- a/tests/lib/App/AppStore/Fetcher/AppFetcherTest.php +++ b/tests/lib/App/AppStore/Fetcher/AppFetcherTest.php @@ -105,6 +105,9 @@ public function testGetWithFilter() { ->expects($this->once()) ->method('getBody') ->willReturn(self::$responseJson); + $response->method('getHeader') + ->with($this->equalTo('ETag')) + ->willReturn('"myETag"'); $this->timeFactory ->expects($this->once()) ->method('getTime') @@ -1884,6 +1887,7 @@ public function testGetWithFilter() { ), 'timestamp' => 1234, 'ncversion' => '11.0.0.2', + 'ETag' => '"myETag"', ); $dataToPut = $expected; diff --git a/tests/lib/App/AppStore/Fetcher/FetcherBase.php b/tests/lib/App/AppStore/Fetcher/FetcherBase.php index cb47d0e08ac6c..73fcbbaab6f55 100644 --- a/tests/lib/App/AppStore/Fetcher/FetcherBase.php +++ b/tests/lib/App/AppStore/Fetcher/FetcherBase.php @@ -127,7 +127,10 @@ public function testGetWithNotExistingFileAndUpToDateTimestampAndVersion() { ->expects($this->once()) ->method('getBody') ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]'); - $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502,"ncversion":"11.0.0.2"}'; + $response->method('getHeader') + ->with($this->equalTo('ETag')) + ->willReturn('"myETag"'); + $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; $file ->expects($this->at(0)) ->method('putContent') @@ -189,7 +192,10 @@ public function testGetWithAlreadyExistingFileAndOutdatedTimestamp() { ->expects($this->once()) ->method('getBody') ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]'); - $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502,"ncversion":"11.0.0.2"}'; + $response->method('getHeader') + ->with($this->equalTo('ETag')) + ->willReturn('"myETag"'); + $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; $file ->expects($this->at(1)) ->method('putContent') @@ -251,7 +257,10 @@ public function testGetWithAlreadyExistingFileAndNoVersion() { ->expects($this->once()) ->method('getBody') ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]'); - $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1201,"ncversion":"11.0.0.2"}'; + $response->method('getHeader') + ->with($this->equalTo('ETag')) + ->willReturn('"myETag"'); + $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1201,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; $file ->expects($this->at(1)) ->method('putContent') @@ -289,7 +298,7 @@ public function testGetWithAlreadyExistingFileAndOutdatedVersion() { $file ->expects($this->at(0)) ->method('getContent') - ->willReturn('{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}},"ncversion":"11.0.0.1"}'); + ->willReturn('{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}},"ncversion":"11.0.0.1"'); $this->timeFactory ->method('getTime') ->willReturn(1201); @@ -308,7 +317,10 @@ public function testGetWithAlreadyExistingFileAndOutdatedVersion() { ->expects($this->once()) ->method('getBody') ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]'); - $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1201,"ncversion":"11.0.0.2"}'; + $response->method('getHeader') + ->with($this->equalTo('ETag')) + ->willReturn('"myETag"'); + $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1201,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; $file ->expects($this->at(1)) ->method('putContent') @@ -364,4 +376,147 @@ public function testGetWithExceptionInClient() { $this->assertSame([], $this->fetcher->get()); } + + public function testGetMatchingETag() { + $folder = $this->createMock(ISimpleFolder::class); + $file = $this->createMock(ISimpleFile::class); + $this->appData + ->expects($this->once()) + ->method('getFolder') + ->with('/') + ->willReturn($folder); + $folder + ->expects($this->once()) + ->method('getFile') + ->with($this->fileName) + ->willReturn($file); + $origData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1200,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; + $file + ->expects($this->at(0)) + ->method('getContent') + ->willReturn($origData); + $this->timeFactory + ->expects($this->at(0)) + ->method('getTime') + ->willReturn(1501); + $this->timeFactory + ->expects($this->at(1)) + ->method('getTime') + ->willReturn(1502); + $client = $this->createMock(IClient::class); + $this->clientService + ->expects($this->once()) + ->method('newClient') + ->willReturn($client); + $response = $this->createMock(IResponse::class); + $client + ->expects($this->once()) + ->method('get') + ->with( + $this->equalTo($this->endpoint), + $this->equalTo([ + 'headers' => [ + 'If-None-Match' => '"myETag"' + ] + ]) + )->willReturn($response); + $response->method('getStatusCode') + ->willReturn(304); + + $newData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; + $file + ->expects($this->at(1)) + ->method('putContent') + ->with($newData); + $file + ->expects($this->at(2)) + ->method('getContent') + ->willReturn($newData); + + $expected = [ + [ + 'id' => 'MyNewApp', + 'foo' => 'foo', + ], + [ + 'id' => 'bar', + ], + ]; + + $this->assertSame($expected, $this->fetcher->get()); + } + + public function testGetNoMatchingETag() { + $folder = $this->createMock(ISimpleFolder::class); + $file = $this->createMock(ISimpleFile::class); + $this->appData + ->expects($this->once()) + ->method('getFolder') + ->with('/') + ->willReturn($folder); + $folder + ->expects($this->at(0)) + ->method('getFile') + ->with($this->fileName) + ->willReturn($file); + $file + ->expects($this->at(0)) + ->method('getContent') + ->willReturn('{"data":[{"id":"MyOldApp","abc":"def"}],"timestamp":1200,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'); + $client = $this->createMock(IClient::class); + $this->clientService + ->expects($this->once()) + ->method('newClient') + ->willReturn($client); + $response = $this->createMock(IResponse::class); + $client + ->expects($this->once()) + ->method('get') + ->with( + $this->equalTo($this->endpoint), + $this->equalTo([ + 'headers' => [ + 'If-None-Match' => '"myETag"', + ] + ]) + ) + ->willReturn($response); + $response->method('getStatusCode') + ->willReturn(200); + $response + ->expects($this->once()) + ->method('getBody') + ->willReturn('[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}]'); + $response->method('getHeader') + ->with($this->equalTo('ETag')) + ->willReturn('"newETag"'); + $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502,"ncversion":"11.0.0.2","ETag":"\"newETag\""}'; + $file + ->expects($this->at(1)) + ->method('putContent') + ->with($fileData); + $file + ->expects($this->at(2)) + ->method('getContent') + ->willReturn($fileData); + $this->timeFactory + ->expects($this->at(0)) + ->method('getTime') + ->willReturn(1501); + $this->timeFactory + ->expects($this->at(1)) + ->method('getTime') + ->willReturn(1502); + + $expected = [ + [ + 'id' => 'MyNewApp', + 'foo' => 'foo', + ], + [ + 'id' => 'bar', + ], + ]; + $this->assertSame($expected, $this->fetcher->get()); + } } diff --git a/tests/lib/Security/CertificateManagerTest.php b/tests/lib/Security/CertificateManagerTest.php index 92a063d47c705..408e65c676605 100644 --- a/tests/lib/Security/CertificateManagerTest.php +++ b/tests/lib/Security/CertificateManagerTest.php @@ -8,8 +8,10 @@ namespace Test\Security; +use OC\Files\Storage\Temporary; use \OC\Security\CertificateManager; use OCP\IConfig; +use OCP\ILogger; /** * Class CertificateManagerTest @@ -43,7 +45,7 @@ protected function setUp() { $config->expects($this->any())->method('getSystemValue') ->with('installed', false)->willReturn(true); - $this->certificateManager = new CertificateManager($this->username, new \OC\Files\View(), $config); + $this->certificateManager = new CertificateManager($this->username, new \OC\Files\View(), $config, $this->createMock(ILogger::class)); } protected function tearDown() { @@ -143,7 +145,7 @@ function testNeedRebundling($uid, /** @var CertificateManager | \PHPUnit_Framework_MockObject_MockObject $certificateManager */ $certificateManager = $this->getMockBuilder('OC\Security\CertificateManager') - ->setConstructorArgs([$uid, $view, $config]) + ->setConstructorArgs([$uid, $view, $config, $this->createMock(ILogger::class)]) ->setMethods(['getFilemtimeOfCaBundle', 'getCertificateBundle']) ->getMock(); @@ -210,5 +212,4 @@ function dataTestNeedRebundling() { [null, 10, 5, 8, false, true], ]; } - } diff --git a/tests/lib/StreamWrappersTest.php b/tests/lib/StreamWrappersTest.php deleted file mode 100644 index ee2f6a8b0b25e..0000000000000 --- a/tests/lib/StreamWrappersTest.php +++ /dev/null @@ -1,68 +0,0 @@ -. - * - */ - -namespace Test; - -/** - * Class StreamWrappersTest - * - * @group DB - */ -class StreamWrappersTest extends \Test\TestCase { - - private static $trashBinStatus; - - public static function setUpBeforeClass() { - self::$trashBinStatus = \OC_App::isEnabled('files_trashbin'); - \OC_App::disable('files_trashbin'); - } - - public static function tearDownAfterClass() { - if (self::$trashBinStatus) { - (new \OC_App())->enable('files_trashbin'); - } - } - - public function testCloseStream() { - //ensure all basic stream stuff works - $sourceFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; - $tmpFile = \OC::$server->getTempManager()->getTemporaryFile('.txt'); - $file = 'close://' . $tmpFile; - $this->assertTrue(file_exists($file)); - file_put_contents($file, file_get_contents($sourceFile)); - $this->assertEquals(file_get_contents($sourceFile), file_get_contents($file)); - unlink($file); - clearstatcache(); - $this->assertFalse(file_exists($file)); - - //test callback - $tmpFile = \OC::$server->getTempManager()->getTemporaryFile('.txt'); - $file = 'close://' . $tmpFile; - $actual = false; - $callback = function($path) use (&$actual) { $actual = $path; }; - \OC\Files\Stream\Close::registerCallback($tmpFile, $callback); - $fh = fopen($file, 'w'); - fwrite($fh, 'asd'); - fclose($fh); - $this->assertSame($tmpFile, $actual); - } -}