diff options
author | Arthur Schiwon <blizzz@arthur-schiwon.de> | 2016-06-11 16:34:43 +0300 |
---|---|---|
committer | Arthur Schiwon <blizzz@arthur-schiwon.de> | 2016-06-11 16:34:43 +0300 |
commit | 42c66efea5ef512d3a3442112f820168e6499265 (patch) | |
tree | 97ef44632d653656608e71e096fd537bbd609936 /apps/dav | |
parent | 75f37f550bb7895757325d3f9a3215bcc4471065 (diff) | |
parent | 52a0c939ab8674857bbfe9a9fb0ee7308eee960e (diff) |
Merge branch 'master' of https://github.com/owncloud/core into downstream-160611
Diffstat (limited to 'apps/dav')
19 files changed, 857 insertions, 166 deletions
diff --git a/apps/dav/appinfo/database.xml b/apps/dav/appinfo/database.xml index f79ea07ae76..9578526a705 100644 --- a/apps/dav/appinfo/database.xml +++ b/apps/dav/appinfo/database.xml @@ -272,6 +272,12 @@ CREATE TABLE calendarobjects ( <type>text</type> <length>255</length> </field> + <field> + <comments>0 - public, 1 - private, 2 - confidential</comments> + <name>classification</name> + <type>integer</type> + <default>0</default> + </field> <index> <name>calobjects_index</name> <unique>true</unique> diff --git a/apps/dav/appinfo/info.xml b/apps/dav/appinfo/info.xml index ca456b03089..26e37e6bb86 100644 --- a/apps/dav/appinfo/info.xml +++ b/apps/dav/appinfo/info.xml @@ -5,7 +5,7 @@ <description>ownCloud WebDAV endpoint</description> <licence>AGPL</licence> <author>owncloud.org</author> - <version>0.2.4</version> + <version>0.2.5</version> <default_enable/> <types> <filesystem/> @@ -20,4 +20,9 @@ <background-jobs> <job>OCA\DAV\CardDAV\Sync\SyncJob</job> </background-jobs> + <repair-steps> + <post-migration> + <job>OCA\DAV\Migration\Classification</job> + </post-migration> + </repair-steps> </info> diff --git a/apps/dav/appinfo/v1/publicwebdav.php b/apps/dav/appinfo/v1/publicwebdav.php index c6c319aa36d..261a4d4b96d 100644 --- a/apps/dav/appinfo/v1/publicwebdav.php +++ b/apps/dav/appinfo/v1/publicwebdav.php @@ -66,7 +66,6 @@ $server = $serverFactory->createServer($baseuri, $requestUri, $authBackend, func $share = $authBackend->getShare(); $owner = $share->getShareOwner(); - $isWritable = $share->getPermissions() & (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_CREATE); $isReadable = $share->getPermissions() & \OCP\Constants::PERMISSION_READ; $fileId = $share->getNodeId(); @@ -74,11 +73,9 @@ $server = $serverFactory->createServer($baseuri, $requestUri, $authBackend, func return false; } - if (!$isWritable) { - \OC\Files\Filesystem::addStorageWrapper('readonly', function ($mountPoint, $storage) { - return new \OC\Files\Storage\Wrapper\PermissionsMask(array('storage' => $storage, 'mask' => \OCP\Constants::PERMISSION_READ + \OCP\Constants::PERMISSION_SHARE)); - }); - } + \OC\Files\Filesystem::addStorageWrapper('sharePermissions', function ($mountPoint, $storage) use ($share) { + return new \OC\Files\Storage\Wrapper\PermissionsMask(array('storage' => $storage, 'mask' => $share->getPermissions() | \OCP\Constants::PERMISSION_SHARE)); + }); OC_Util::setupFS($owner); $ownerView = \OC\Files\Filesystem::getView(); diff --git a/apps/dav/lib/AppInfo/Application.php b/apps/dav/lib/AppInfo/Application.php index ba0ef421f97..9e0d2da4e17 100644 --- a/apps/dav/lib/AppInfo/Application.php +++ b/apps/dav/lib/AppInfo/Application.php @@ -31,10 +31,12 @@ use OCA\DAV\CardDAV\SyncService; use OCA\DAV\Connector\Sabre\Principal; use OCA\DAV\DAV\GroupPrincipalBackend; use OCA\DAV\HookManager; +use OCA\DAV\Migration\Classification; use \OCP\AppFramework\App; use OCP\AppFramework\IAppContainer; use OCP\Contacts\IManager; use OCP\IUser; +use Sabre\VObject\Reader; use Symfony\Component\EventDispatcher\GenericEvent; class Application extends App { @@ -106,6 +108,14 @@ class Application extends App { $g ); }); + + $container->registerService('OCA\DAV\Migration\Classification', function ($c) { + /** @var IAppContainer $c */ + return new Classification( + $c->query('CalDavBackend'), + $c->getServer()->getUserManager() + ); + }); } /** diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 64fdf0f7ebe..ce494082976 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -37,10 +37,11 @@ use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp; use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet; use Sabre\DAV; use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\PropPatch; use Sabre\HTTP\URLUtil; use Sabre\VObject\DateTimeParser; use Sabre\VObject\Reader; -use Sabre\VObject\RecurrenceIterator; +use Sabre\VObject\Recur\EventIterator; /** * Class CalDavBackend @@ -61,6 +62,10 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription */ const MAX_DATE = '2038-01-01'; + const CLASSIFICATION_PUBLIC = 0; + const CLASSIFICATION_PRIVATE = 1; + const CLASSIFICATION_CONFIDENTIAL = 2; + /** * List of CalDAV properties, and how they map to database field names * Add your own properties by simply adding on to this array. @@ -395,10 +400,10 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription * * Read the PropPatch documentation for more info and examples. * - * @param \Sabre\DAV\PropPatch $propPatch + * @param PropPatch $propPatch * @return void */ - function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch) { + function updateCalendar($calendarId, PropPatch $propPatch) { $supportedProperties = array_keys($this->propertyMap); $supportedProperties[] = '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp'; @@ -484,7 +489,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription */ function getCalendarObjects($calendarId) { $query = $this->db->getQueryBuilder(); - $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'componenttype']) + $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'componenttype', 'classification']) ->from('calendarobjects') ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))); $stmt = $query->execute(); @@ -499,6 +504,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription 'calendarid' => $row['calendarid'], 'size' => (int)$row['size'], 'component' => strtolower($row['componenttype']), + 'classification'=> (int)$row['classification'] ]; } @@ -524,7 +530,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription function getCalendarObject($calendarId, $objectUri) { $query = $this->db->getQueryBuilder(); - $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype']) + $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype', 'classification']) ->from('calendarobjects') ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))) ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri))); @@ -542,6 +548,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription 'size' => (int)$row['size'], 'calendardata' => $this->readBlob($row['calendardata']), 'component' => strtolower($row['componenttype']), + 'classification'=> (int)$row['classification'] ]; } @@ -559,7 +566,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription */ function getMultipleCalendarObjects($calendarId, array $uris) { $query = $this->db->getQueryBuilder(); - $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype']) + $query->select(['id', 'uri', 'lastmodified', 'etag', 'calendarid', 'size', 'calendardata', 'componenttype', 'classification']) ->from('calendarobjects') ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))) ->andWhere($query->expr()->in('uri', $query->createParameter('uri'))) @@ -579,6 +586,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription 'size' => (int)$row['size'], 'calendardata' => $this->readBlob($row['calendardata']), 'component' => strtolower($row['componenttype']), + 'classification' => (int)$row['classification'] ]; } @@ -618,6 +626,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription 'componenttype' => $query->createNamedParameter($extraData['componentType']), 'firstoccurence' => $query->createNamedParameter($extraData['firstOccurence']), 'lastoccurence' => $query->createNamedParameter($extraData['lastOccurence']), + 'classification' => $query->createNamedParameter($extraData['classification']), 'uid' => $query->createNamedParameter($extraData['uid']), ]) ->execute(); @@ -657,6 +666,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription ->set('componenttype', $query->createNamedParameter($extraData['componentType'])) ->set('firstoccurence', $query->createNamedParameter($extraData['firstOccurence'])) ->set('lastoccurence', $query->createNamedParameter($extraData['lastOccurence'])) + ->set('classification', $query->createNamedParameter($extraData['classification'])) ->set('uid', $query->createNamedParameter($extraData['uid'])) ->where($query->expr()->eq('calendarid', $query->createNamedParameter($calendarId))) ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($objectUri))) @@ -668,6 +678,23 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription } /** + * @param int $calendarObjectId + * @param int $classification + */ + public function setClassification($calendarObjectId, $classification) { + if (!in_array($classification, [ + self::CLASSIFICATION_PUBLIC, self::CLASSIFICATION_PRIVATE, self::CLASSIFICATION_CONFIDENTIAL + ])) { + throw new \InvalidArgumentException(); + } + $query = $this->db->getQueryBuilder(); + $query->update('calendarobjects') + ->set('classification', $query->createNamedParameter($classification)) + ->where($query->expr()->eq('id', $query->createNamedParameter($calendarObjectId))) + ->execute(); + } + + /** * Deletes an existing calendar object. * * The object uri is only the basename, or filename and not a full path. @@ -1086,10 +1113,10 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription * Read the PropPatch documentation for more info and examples. * * @param mixed $subscriptionId - * @param \Sabre\DAV\PropPatch $propPatch + * @param PropPatch $propPatch * @return void */ - function updateSubscription($subscriptionId, DAV\PropPatch $propPatch) { + function updateSubscription($subscriptionId, PropPatch $propPatch) { $supportedProperties = array_keys($this->subscriptionPropertyMap); $supportedProperties[] = '{http://calendarserver.org/ns/}source'; @@ -1280,14 +1307,15 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription * @param string $calendarData * @return array */ - protected function getDenormalizedData($calendarData) { + public function getDenormalizedData($calendarData) { $vObject = Reader::read($calendarData); $componentType = null; $component = null; - $firstOccurence = null; - $lastOccurence = null; + $firstOccurrence = null; + $lastOccurrence = null; $uid = null; + $classification = self::CLASSIFICATION_PUBLIC; foreach($vObject->getComponents() as $component) { if ($component->name!=='VTIMEZONE') { $componentType = $component->name; @@ -1299,27 +1327,27 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription throw new \Sabre\DAV\Exception\BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component'); } if ($componentType === 'VEVENT' && $component->DTSTART) { - $firstOccurence = $component->DTSTART->getDateTime()->getTimeStamp(); + $firstOccurrence = $component->DTSTART->getDateTime()->getTimeStamp(); // Finding the last occurrence is a bit harder if (!isset($component->RRULE)) { if (isset($component->DTEND)) { - $lastOccurence = $component->DTEND->getDateTime()->getTimeStamp(); + $lastOccurrence = $component->DTEND->getDateTime()->getTimeStamp(); } elseif (isset($component->DURATION)) { $endDate = clone $component->DTSTART->getDateTime(); $endDate->add(DateTimeParser::parse($component->DURATION->getValue())); - $lastOccurence = $endDate->getTimeStamp(); + $lastOccurrence = $endDate->getTimeStamp(); } elseif (!$component->DTSTART->hasTime()) { $endDate = clone $component->DTSTART->getDateTime(); $endDate->modify('+1 day'); - $lastOccurence = $endDate->getTimeStamp(); + $lastOccurrence = $endDate->getTimeStamp(); } else { - $lastOccurence = $firstOccurence; + $lastOccurrence = $firstOccurrence; } } else { - $it = new RecurrenceIterator($vObject, (string)$component->UID); + $it = new EventIterator($vObject, (string)$component->UID); $maxDate = new \DateTime(self::MAX_DATE); if ($it->isInfinite()) { - $lastOccurence = $maxDate->getTimeStamp(); + $lastOccurrence = $maxDate->getTimeStamp(); } else { $end = $it->getDtEnd(); while($it->valid() && $end < $maxDate) { @@ -1327,19 +1355,31 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription $it->next(); } - $lastOccurence = $end->getTimeStamp(); + $lastOccurrence = $end->getTimeStamp(); } } } + if ($component->CLASS) { + $classification = CalDavBackend::CLASSIFICATION_PRIVATE; + switch ($component->CLASS->getValue()) { + case 'PUBLIC': + $classification = CalDavBackend::CLASSIFICATION_PUBLIC; + break; + case 'CONFIDENTIAL': + $classification = CalDavBackend::CLASSIFICATION_CONFIDENTIAL; + break; + } + } return [ - 'etag' => md5($calendarData), - 'size' => strlen($calendarData), - 'componentType' => $componentType, - 'firstOccurence' => is_null($firstOccurence) ? null : max(0, $firstOccurence), - 'lastOccurence' => $lastOccurence, - 'uid' => $uid, + 'etag' => md5($calendarData), + 'size' => strlen($calendarData), + 'componentType' => $componentType, + 'firstOccurence' => is_null($firstOccurrence) ? null : max(0, $firstOccurrence), + 'lastOccurence' => $lastOccurrence, + 'uid' => $uid, + 'classification' => $classification ]; } diff --git a/apps/dav/lib/CalDAV/Calendar.php b/apps/dav/lib/CalDAV/Calendar.php index 73b3957a9b0..785bb5699e2 100644 --- a/apps/dav/lib/CalDAV/Calendar.php +++ b/apps/dav/lib/CalDAV/Calendar.php @@ -26,6 +26,7 @@ use OCA\DAV\DAV\Sharing\IShareable; use OCP\IL10N; use Sabre\CalDAV\Backend\BackendInterface; use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; use Sabre\DAV\PropPatch; class Calendar extends \Sabre\CalDAV\Calendar implements IShareable { @@ -162,6 +163,78 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable { parent::propPatch($propPatch); } + function getChild($name) { + + $obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $name); + + if (!$obj) { + throw new NotFound('Calendar object not found'); + } + + if ($this->isShared() && $obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE) { + throw new NotFound('Calendar object not found'); + } + + $obj['acl'] = $this->getChildACL(); + + return new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj); + + } + + function getChildren() { + + $objs = $this->caldavBackend->getCalendarObjects($this->calendarInfo['id']); + $children = []; + foreach ($objs as $obj) { + if ($this->isShared() && $obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE) { + continue; + } + $obj['acl'] = $this->getChildACL(); + $children[] = new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj); + } + return $children; + + } + + function getMultipleChildren(array $paths) { + + $objs = $this->caldavBackend->getMultipleCalendarObjects($this->calendarInfo['id'], $paths); + $children = []; + foreach ($objs as $obj) { + if ($this->isShared() && $obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE) { + continue; + } + $obj['acl'] = $this->getChildACL(); + $children[] = new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj); + } + return $children; + + } + + function childExists($name) { + $obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $name); + if (!$obj) { + return false; + } + if ($this->isShared() && $obj['classification'] === CalDavBackend::CLASSIFICATION_PRIVATE) { + return false; + } + + return true; + } + + function calendarQuery(array $filters) { + + $uris = $this->caldavBackend->calendarQuery($this->calendarInfo['id'], $filters); + if ($this->isShared()) { + return array_filter($uris, function ($uri) { + return $this->childExists($uri); + }); + } + + return $uris; + } + private function canWrite() { if (isset($this->calendarInfo['{http://owncloud.org/ns}read-only'])) { return !$this->calendarInfo['{http://owncloud.org/ns}read-only']; @@ -169,4 +242,8 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable { return true; } + private function isShared() { + return isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal']); + } + } diff --git a/apps/dav/lib/CalDAV/CalendarObject.php b/apps/dav/lib/CalDAV/CalendarObject.php new file mode 100644 index 00000000000..b4a58b52093 --- /dev/null +++ b/apps/dav/lib/CalDAV/CalendarObject.php @@ -0,0 +1,92 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @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 <http://www.gnu.org/licenses/> + * + */ + + +namespace OCA\DAV\CalDAV; + + +use Sabre\VObject\Component; +use Sabre\VObject\Property; +use Sabre\VObject\Reader; + +class CalendarObject extends \Sabre\CalDAV\CalendarObject { + + /** + * @inheritdoc + */ + function get() { + $data = parent::get(); + if ($this->isShared() && $this->objectData['classification'] === CalDavBackend::CLASSIFICATION_CONFIDENTIAL) { + return $this->createConfidentialObject($data); + } + return $data; + } + + private function isShared() { + return isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal']); + } + + /** + * @param string $calData + * @return string + */ + private static function createConfidentialObject($calData) { + + $vObject = Reader::read($calData); + + /** @var Component $vElement */ + $vElement = null; + if(isset($vObject->VEVENT)) { + $vElement = $vObject->VEVENT; + } + if(isset($vObject->VJOURNAL)) { + $vElement = $vObject->VJOURNAL; + } + if(isset($vObject->VTODO)) { + $vElement = $vObject->VTODO; + } + if(!is_null($vElement)) { + foreach ($vElement->children as &$property) { + /** @var Property $property */ + switch($property->name) { + case 'CREATED': + case 'DTSTART': + case 'RRULE': + case 'DURATION': + case 'DTEND': + case 'CLASS': + case 'UID': + break; + case 'SUMMARY': + $property->setValue('Busy'); + break; + default: + $vElement->__unset($property->name); + unset($property); + break; + } + } + } + + return $vObject->serialize(); + } + +} diff --git a/apps/dav/lib/Connector/PublicAuth.php b/apps/dav/lib/Connector/PublicAuth.php index 2716ca29107..4e63ca1d29e 100644 --- a/apps/dav/lib/Connector/PublicAuth.php +++ b/apps/dav/lib/Connector/PublicAuth.php @@ -31,13 +31,14 @@ use OCP\IRequest; use OCP\ISession; use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IManager; +use Sabre\DAV\Auth\Backend\AbstractBasic; /** * Class PublicAuth * * @package OCA\DAV\Connector */ -class PublicAuth extends \Sabre\DAV\Auth\Backend\AbstractBasic { +class PublicAuth extends AbstractBasic { /** @var \OCP\Share\IShare */ private $share; @@ -62,6 +63,10 @@ class PublicAuth extends \Sabre\DAV\Auth\Backend\AbstractBasic { $this->request = $request; $this->shareManager = $shareManager; $this->session = $session; + + // setup realm + $defaults = new \OC_Defaults(); + $this->realm = $defaults->getName(); } /** @@ -99,7 +104,7 @@ class PublicAuth extends \Sabre\DAV\Auth\Backend\AbstractBasic { if (in_array('XMLHttpRequest', explode(',', $this->request->getHeader('X-Requested-With')))) { // do not re-authenticate over ajax, use dummy auth name to prevent browser popup http_response_code(401); - header('WWW-Authenticate', 'DummyBasic real="ownCloud"'); + header('WWW-Authenticate','DummyBasic realm="' . $this->realm . '"'); throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls'); } return false; diff --git a/apps/dav/lib/Connector/Sabre/Auth.php b/apps/dav/lib/Connector/Sabre/Auth.php index 27900cc1cad..653da10bc3c 100644 --- a/apps/dav/lib/Connector/Sabre/Auth.php +++ b/apps/dav/lib/Connector/Sabre/Auth.php @@ -74,6 +74,10 @@ class Auth extends AbstractBasic { $this->twoFactorManager = $twoFactorManager; $this->request = $request; $this->principalPrefix = $principalPrefix; + + // setup realm + $defaults = new \OC_Defaults(); + $this->realm = $defaults->getName(); } /** diff --git a/apps/dav/lib/Connector/Sabre/FilesPlugin.php b/apps/dav/lib/Connector/Sabre/FilesPlugin.php index dc47416cca8..0a2e6713cb4 100644 --- a/apps/dav/lib/Connector/Sabre/FilesPlugin.php +++ b/apps/dav/lib/Connector/Sabre/FilesPlugin.php @@ -42,6 +42,7 @@ use \Sabre\HTTP\RequestInterface; use \Sabre\HTTP\ResponseInterface; use OCP\Files\StorageNotAvailableException; use OCP\IConfig; +use OCP\IRequest; class FilesPlugin extends ServerPlugin { @@ -96,19 +97,28 @@ class FilesPlugin extends ServerPlugin { private $config; /** + * @var IRequest + */ + private $request; + + /** * @param Tree $tree * @param View $view + * @param IConfig $config + * @param IRequest $request * @param bool $isPublic * @param bool $downloadAttachment */ public function __construct(Tree $tree, View $view, IConfig $config, + IRequest $request, $isPublic = false, $downloadAttachment = true) { $this->tree = $tree; $this->fileView = $view; $this->config = $config; + $this->request = $request; $this->isPublic = $isPublic; $this->downloadAttachment = $downloadAttachment; } @@ -225,7 +235,18 @@ class FilesPlugin extends ServerPlugin { // adds a 'Content-Disposition: attachment' header if ($this->downloadAttachment) { - $response->addHeader('Content-Disposition', 'attachment'); + $filename = $node->getName(); + if ($this->request->isUserAgent( + [ + \OC\AppFramework\Http\Request::USER_AGENT_IE, + \OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME, + \OC\AppFramework\Http\Request::USER_AGENT_FREEBOX, + ])) { + $response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"'); + } else { + $response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename) + . '; filename="' . rawurlencode($filename) . '"'); + } } if ($node instanceof \OCA\DAV\Connector\Sabre\File) { diff --git a/apps/dav/lib/Connector/Sabre/ServerFactory.php b/apps/dav/lib/Connector/Sabre/ServerFactory.php index b193bfc76c7..c5b4f6a9352 100644 --- a/apps/dav/lib/Connector/Sabre/ServerFactory.php +++ b/apps/dav/lib/Connector/Sabre/ServerFactory.php @@ -100,10 +100,9 @@ class ServerFactory { $server->setBaseUri($baseUri); // Load plugins - $defaults = new \OC_Defaults(); $server->addPlugin(new \OCA\DAV\Connector\Sabre\MaintenancePlugin($this->config)); $server->addPlugin(new \OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin($this->config)); - $server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, $defaults->getName())); + $server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend)); // FIXME: The following line is a workaround for legacy components relying on being able to send a GET to / $server->addPlugin(new \OCA\DAV\Connector\Sabre\DummyGetResponsePlugin()); $server->addPlugin(new \OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin('webdav', $this->logger)); @@ -144,6 +143,7 @@ class ServerFactory { $objectTree, $view, $this->config, + $this->request, false, !$this->config->getSystemValue('debug', false) ) diff --git a/apps/dav/lib/Migration/Classification.php b/apps/dav/lib/Migration/Classification.php new file mode 100644 index 00000000000..b793f790af5 --- /dev/null +++ b/apps/dav/lib/Migration/Classification.php @@ -0,0 +1,93 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @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 <http://www.gnu.org/licenses/> + * + */ + + +namespace OCA\DAV\Migration; + +use OCA\DAV\CalDAV\CalDavBackend; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class Classification implements IRepairStep { + + /** @var CalDavBackend */ + private $calDavBackend; + + /** @var IUserManager */ + private $userManager; + + /** + * Classification constructor. + * + * @param CalDavBackend $calDavBackend + */ + public function __construct(CalDavBackend $calDavBackend, IUserManager $userManager) { + $this->calDavBackend = $calDavBackend; + $this->userManager = $userManager; + } + + /** + * @param IUser $user + */ + public function runForUser($user) { + $principal = 'principals/users/' . $user->getUID(); + $calendars = $this->calDavBackend->getCalendarsForUser($principal); + foreach ($calendars as $calendar) { + $objects = $this->calDavBackend->getCalendarObjects($calendar['id']); + foreach ($objects as $object) { + $calObject = $this->calDavBackend->getCalendarObject($calendar['id'], $object['uri']); + $classification = $this->extractClassification($calObject['calendardata']); + $this->calDavBackend->setClassification($object['id'], $classification); + } + } + } + + /** + * @param $calendarData + * @return integer + * @throws \Sabre\DAV\Exception\BadRequest + */ + protected function extractClassification($calendarData) { + return $this->calDavBackend->getDenormalizedData($calendarData)['classification']; + } + + /** + * @inheritdoc + */ + public function getName() { + return 'Fix classification for calendar objects'; + } + + /** + * @inheritdoc + */ + public function run(IOutput $output) { + $output->startProgress(); + $this->userManager->callForAllUsers(function($user) use ($output) { + /** @var IUser $user */ + $output->advance(1, $user->getDisplayName()); + $this->runForUser($user); + }); + $output->finishProgress(); + } +} diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php index 179558e97ae..e150f441b82 100644 --- a/apps/dav/lib/Server.php +++ b/apps/dav/lib/Server.php @@ -141,6 +141,7 @@ class Server { $this->server->tree, $view, \OC::$server->getConfig(), + $this->request, false, !\OC::$server->getConfig()->getSystemValue('debug', false) ) diff --git a/apps/dav/tests/unit/CalDAV/AbstractCalDavBackendTest.php b/apps/dav/tests/unit/CalDAV/AbstractCalDavBackendTest.php new file mode 100644 index 00000000000..49e5e5a2bcc --- /dev/null +++ b/apps/dav/tests/unit/CalDAV/AbstractCalDavBackendTest.php @@ -0,0 +1,163 @@ +<?php +/** + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @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 <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\DAV\Tests\unit\CalDAV; + +use DateTime; +use DateTimeZone; +use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\CalDAV\Calendar; +use OCA\DAV\Connector\Sabre\Principal; +use OCP\IL10N; +use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet; +use Sabre\DAV\PropPatch; +use Sabre\DAV\Xml\Property\Href; +use Sabre\DAVACL\IACL; +use Test\TestCase; + +/** + * Class CalDavBackendTest + * + * @group DB + * + * @package OCA\DAV\Tests\unit\CalDAV + */ +abstract class AbstractCalDavBackendTest extends TestCase { + + /** @var CalDavBackend */ + protected $backend; + + /** @var Principal | \PHPUnit_Framework_MockObject_MockObject */ + protected $principal; + + const UNIT_TEST_USER = 'principals/users/caldav-unit-test'; + const UNIT_TEST_USER1 = 'principals/users/caldav-unit-test1'; + const UNIT_TEST_GROUP = 'principals/groups/caldav-unit-test-group'; + + public function setUp() { + parent::setUp(); + + $this->principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal') + ->disableOriginalConstructor() + ->setMethods(['getPrincipalByPath', 'getGroupMembership']) + ->getMock(); + $this->principal->expects($this->any())->method('getPrincipalByPath') + ->willReturn([ + 'uri' => 'principals/best-friend' + ]); + $this->principal->expects($this->any())->method('getGroupMembership') + ->withAnyParameters() + ->willReturn([self::UNIT_TEST_GROUP]); + + $db = \OC::$server->getDatabaseConnection(); + $this->backend = new CalDavBackend($db, $this->principal); + + $this->tearDown(); + } + + public function tearDown() { + parent::tearDown(); + + if (is_null($this->backend)) { + return; + } + $books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER); + foreach ($books as $book) { + $this->backend->deleteCalendar($book['id']); + } + $subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER); + foreach ($subscriptions as $subscription) { + $this->backend->deleteSubscription($subscription['id']); + } + } + + protected function createTestCalendar() { + $this->backend->createCalendar(self::UNIT_TEST_USER, 'Example', [ + '{http://apple.com/ns/ical/}calendar-color' => '#1C4587FF' + ]); + $calendars = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER); + $this->assertEquals(1, count($calendars)); + $this->assertEquals(self::UNIT_TEST_USER, $calendars[0]['principaluri']); + /** @var SupportedCalendarComponentSet $components */ + $components = $calendars[0]['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']; + $this->assertEquals(['VEVENT','VTODO'], $components->getValue()); + $color = $calendars[0]['{http://apple.com/ns/ical/}calendar-color']; + $this->assertEquals('#1C4587FF', $color); + $this->assertEquals('Example', $calendars[0]['uri']); + $this->assertEquals('Example', $calendars[0]['{DAV:}displayname']); + $calendarId = $calendars[0]['id']; + + return $calendarId; + } + + protected function createEvent($calendarId, $start = '20130912T130000Z', $end = '20130912T140000Z') { + + $calData = <<<EOD +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:ownCloud Calendar +BEGIN:VEVENT +CREATED;VALUE=DATE-TIME:20130910T125139Z +UID:47d15e3ec8 +LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z +DTSTAMP;VALUE=DATE-TIME:20130910T125139Z +SUMMARY:Test Event +DTSTART;VALUE=DATE-TIME:$start +DTEND;VALUE=DATE-TIME:$end +CLASS:PUBLIC +END:VEVENT +END:VCALENDAR +EOD; + $uri0 = $this->getUniqueID('event'); + $this->backend->createCalendarObject($calendarId, $uri0, $calData); + + return $uri0; + } + + protected function assertAcl($principal, $privilege, $acl) { + foreach($acl as $a) { + if ($a['principal'] === $principal && $a['privilege'] === $privilege) { + $this->assertTrue(true); + return; + } + } + $this->fail("ACL does not contain $principal / $privilege"); + } + + protected function assertNotAcl($principal, $privilege, $acl) { + foreach($acl as $a) { + if ($a['principal'] === $principal && $a['privilege'] === $privilege) { + $this->fail("ACL contains $principal / $privilege"); + return; + } + } + $this->assertTrue(true); + } + + protected function assertAccess($shouldHaveAcl, $principal, $privilege, $acl) { + if ($shouldHaveAcl) { + $this->assertAcl($principal, $privilege, $acl); + } else { + $this->assertNotAcl($principal, $privilege, $acl); + } + } +} diff --git a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php index c3e32e436d9..977bdf15c8e 100644 --- a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php +++ b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php @@ -26,13 +26,10 @@ use DateTime; use DateTimeZone; use OCA\DAV\CalDAV\CalDavBackend; use OCA\DAV\CalDAV\Calendar; -use OCA\DAV\Connector\Sabre\Principal; use OCP\IL10N; -use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet; use Sabre\DAV\PropPatch; use Sabre\DAV\Xml\Property\Href; use Sabre\DAVACL\IACL; -use Test\TestCase; /** * Class CalDavBackendTest @@ -41,54 +38,7 @@ use Test\TestCase; * * @package OCA\DAV\Tests\unit\CalDAV */ -class CalDavBackendTest extends TestCase { - - /** @var CalDavBackend */ - private $backend; - - /** @var Principal | \PHPUnit_Framework_MockObject_MockObject */ - private $principal; - - const UNIT_TEST_USER = 'principals/users/caldav-unit-test'; - const UNIT_TEST_USER1 = 'principals/users/caldav-unit-test1'; - const UNIT_TEST_GROUP = 'principals/groups/caldav-unit-test-group'; - - public function setUp() { - parent::setUp(); - - $this->principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal') - ->disableOriginalConstructor() - ->setMethods(['getPrincipalByPath', 'getGroupMembership']) - ->getMock(); - $this->principal->expects($this->any())->method('getPrincipalByPath') - ->willReturn([ - 'uri' => 'principals/best-friend' - ]); - $this->principal->expects($this->any())->method('getGroupMembership') - ->withAnyParameters() - ->willReturn([self::UNIT_TEST_GROUP]); - - $db = \OC::$server->getDatabaseConnection(); - $this->backend = new CalDavBackend($db, $this->principal); - - $this->tearDown(); - } - - public function tearDown() { - parent::tearDown(); - - if (is_null($this->backend)) { - return; - } - $books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER); - foreach ($books as $book) { - $this->backend->deleteCalendar($book['id']); - } - $subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER); - foreach ($subscriptions as $subscription) { - $this->backend->deleteSubscription($subscription['id']); - } - } +class CalDavBackendTest extends AbstractCalDavBackendTest { public function testCalendarOperations() { @@ -232,6 +182,7 @@ EOD; $calendarObjects = $this->backend->getCalendarObjects($calendarId); $this->assertEquals(1, count($calendarObjects)); $this->assertEquals($calendarId, $calendarObjects[0]['calendarid']); + $this->assertArrayHasKey('classification', $calendarObjects[0]); // get the cards $calendarObject = $this->backend->getCalendarObject($calendarId, $uri); @@ -241,6 +192,7 @@ EOD; $this->assertArrayHasKey('lastmodified', $calendarObject); $this->assertArrayHasKey('etag', $calendarObject); $this->assertArrayHasKey('size', $calendarObject); + $this->assertArrayHasKey('classification', $calendarObject); $this->assertEquals($calData, $calendarObject['calendardata']); // update the card @@ -310,6 +262,7 @@ EOD; $this->assertArrayHasKey('lastmodified', $card); $this->assertArrayHasKey('etag', $card); $this->assertArrayHasKey('size', $card); + $this->assertArrayHasKey('classification', $card); $this->assertEquals($calData, $card['calendardata']); } @@ -363,49 +316,6 @@ EOD; ]; } - private function createTestCalendar() { - $this->backend->createCalendar(self::UNIT_TEST_USER, 'Example', [ - '{http://apple.com/ns/ical/}calendar-color' => '#1C4587FF' - ]); - $calendars = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER); - $this->assertEquals(1, count($calendars)); - $this->assertEquals(self::UNIT_TEST_USER, $calendars[0]['principaluri']); - /** @var SupportedCalendarComponentSet $components */ - $components = $calendars[0]['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']; - $this->assertEquals(['VEVENT','VTODO'], $components->getValue()); - $color = $calendars[0]['{http://apple.com/ns/ical/}calendar-color']; - $this->assertEquals('#1C4587FF', $color); - $this->assertEquals('Example', $calendars[0]['uri']); - $this->assertEquals('Example', $calendars[0]['{DAV:}displayname']); - $calendarId = $calendars[0]['id']; - - return $calendarId; - } - - private function createEvent($calendarId, $start = '20130912T130000Z', $end = '20130912T140000Z') { - - $calData = <<<EOD -BEGIN:VCALENDAR -VERSION:2.0 -PRODID:ownCloud Calendar -BEGIN:VEVENT -CREATED;VALUE=DATE-TIME:20130910T125139Z -UID:47d15e3ec8 -LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z -DTSTAMP;VALUE=DATE-TIME:20130910T125139Z -SUMMARY:Test Event -DTSTART;VALUE=DATE-TIME:$start -DTEND;VALUE=DATE-TIME:$end -CLASS:PUBLIC -END:VEVENT -END:VCALENDAR -EOD; - $uri0 = $this->getUniqueID('event'); - $this->backend->createCalendarObject($calendarId, $uri0, $calData); - - return $uri0; - } - public function testSyncSupport() { $calendarId = $this->createTestCalendar(); @@ -464,43 +374,20 @@ EOD; /** * @dataProvider providesCalDataForGetDenormalizedData */ - public function testGetDenormalizedData($expectedFirstOccurance, $calData) { - $actual = $this->invokePrivate($this->backend, 'getDenormalizedData', [$calData]); - $this->assertEquals($expectedFirstOccurance, $actual['firstOccurence']); + public function testGetDenormalizedData($expected, $key, $calData) { + $actual = $this->backend->getDenormalizedData($calData); + $this->assertEquals($expected, $actual[$key]); } public function providesCalDataForGetDenormalizedData() { return [ - [0, "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nDTSTART;VALUE=DATE:16040222\r\nDTEND;VALUE=DATE:16040223\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"], - [null, "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"] + 'first occurrence before unix epoch starts' => [0, 'firstOccurence', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nDTSTART;VALUE=DATE:16040222\r\nDTEND;VALUE=DATE:16040223\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"], + 'no first occurrence because yearly' => [null, 'firstOccurence', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"], + 'CLASS:PRIVATE' => [CalDavBackend::CLASSIFICATION_PRIVATE, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:PRIVATE\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"], + 'CLASS:PUBLIC' => [CalDavBackend::CLASSIFICATION_PUBLIC, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:PUBLIC\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"], + 'CLASS:CONFIDENTIAL' => [CalDavBackend::CLASSIFICATION_CONFIDENTIAL, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:CONFIDENTIAL\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"], + 'no class set -> public' => [CalDavBackend::CLASSIFICATION_PUBLIC, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nTRANSP:OPAQUE\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"], + 'unknown class -> private' => [CalDavBackend::CLASSIFICATION_PRIVATE, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:VERTRAULICH\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"], ]; } - - private function assertAcl($principal, $privilege, $acl) { - foreach($acl as $a) { - if ($a['principal'] === $principal && $a['privilege'] === $privilege) { - $this->assertTrue(true); - return; - } - } - $this->fail("ACL does not contain $principal / $privilege"); - } - - private function assertNotAcl($principal, $privilege, $acl) { - foreach($acl as $a) { - if ($a['principal'] === $principal && $a['privilege'] === $privilege) { - $this->fail("ACL contains $principal / $privilege"); - return; - } - } - $this->assertTrue(true); - } - - private function assertAccess($shouldHaveAcl, $principal, $privilege, $acl) { - if ($shouldHaveAcl) { - $this->assertAcl($principal, $privilege, $acl); - } else { - $this->assertNotAcl($principal, $privilege, $acl); - } - } } diff --git a/apps/dav/tests/unit/CalDAV/CalendarTest.php b/apps/dav/tests/unit/CalDAV/CalendarTest.php index 73d85e82bbc..56a2d4fcba7 100644 --- a/apps/dav/tests/unit/CalDAV/CalendarTest.php +++ b/apps/dav/tests/unit/CalDAV/CalendarTest.php @@ -27,6 +27,7 @@ use OCA\DAV\CalDAV\CalDavBackend; use OCA\DAV\CalDAV\Calendar; use OCP\IL10N; use Sabre\DAV\PropPatch; +use Sabre\VObject\Reader; use Test\TestCase; class CalendarTest extends TestCase { @@ -189,4 +190,153 @@ class CalendarTest extends TestCase { 'birthday calendar' => [false, false, false, BirthdayService::BIRTHDAY_CALENDAR_URI] ]; } + + /** + * @dataProvider providesConfidentialClassificationData + * @param $expectedChildren + * @param $isShared + */ + public function testPrivateClassification($expectedChildren, $isShared) { + + $calObject0 = ['uri' => 'event-0', 'classification' => CalDavBackend::CLASSIFICATION_PUBLIC]; + $calObject1 = ['uri' => 'event-1', 'classification' => CalDavBackend::CLASSIFICATION_CONFIDENTIAL]; + $calObject2 = ['uri' => 'event-2', 'classification' => CalDavBackend::CLASSIFICATION_PRIVATE]; + + /** @var \PHPUnit_Framework_MockObject_MockObject | CalDavBackend $backend */ + $backend = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock(); + $backend->expects($this->any())->method('getCalendarObjects')->willReturn([ + $calObject0, $calObject1, $calObject2 + ]); + $backend->expects($this->any())->method('getMultipleCalendarObjects') + ->with(666, ['event-0', 'event-1', 'event-2']) + ->willReturn([ + $calObject0, $calObject1, $calObject2 + ]); + $backend->expects($this->any())->method('getCalendarObject') + ->willReturn($calObject2)->with(666, 'event-2'); + + $calendarInfo = [ + 'principaluri' => 'user2', + 'id' => 666, + 'uri' => 'cal', + ]; + + if ($isShared) { + $calendarInfo['{http://owncloud.org/ns}owner-principal'] = 'user1'; + + } + $c = new Calendar($backend, $calendarInfo, $this->l10n); + $children = $c->getChildren(); + $this->assertEquals($expectedChildren, count($children)); + $children = $c->getMultipleChildren(['event-0', 'event-1', 'event-2']); + $this->assertEquals($expectedChildren, count($children)); + + $this->assertEquals(!$isShared, $c->childExists('event-2')); + } + + /** + * @dataProvider providesConfidentialClassificationData + * @param $expectedChildren + * @param $isShared + */ + public function testConfidentialClassification($expectedChildren, $isShared) { + $start = '20160609'; + $end = '20160610'; + + $calData = <<<EOD +BEGIN:VCALENDAR +PRODID:-//ownCloud calendar v1.2.2 +BEGIN:VEVENT +CREATED:20160602T133732 +DTSTAMP:20160602T133732 +LAST-MODIFIED:20160602T133732 +UID:wej2z68l9h +SUMMARY:Test Event +LOCATION:Somewhere ... +ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;CUTYPE=INDIVIDUAL;CN=de + epdiver:MAILTO:thomas.mueller@tmit.eu +ORGANIZER;CN=deepdiver:MAILTO:thomas.mueller@tmit.eu +DESCRIPTION:maybe .... +DTSTART;TZID=Europe/Berlin;VALUE=DATE:$start +DTEND;TZID=Europe/Berlin;VALUE=DATE:$end +RRULE:FREQ=DAILY +BEGIN:VALARM +ACTION:AUDIO +TRIGGER:-PT15M +END:VALARM +END:VEVENT +BEGIN:VTIMEZONE +TZID:Europe/Berlin +BEGIN:DAYLIGHT +DTSTART:19810329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +TZNAME:MESZ +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +END:DAYLIGHT +BEGIN:STANDARD +DTSTART:19961027T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +TZNAME:MEZ +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +END:STANDARD +END:VTIMEZONE +END:VCALENDAR +EOD; + + $calObject0 = ['uri' => 'event-0', 'classification' => CalDavBackend::CLASSIFICATION_PUBLIC]; + $calObject1 = ['uri' => 'event-1', 'classification' => CalDavBackend::CLASSIFICATION_CONFIDENTIAL, 'calendardata' => $calData]; + $calObject2 = ['uri' => 'event-2', 'classification' => CalDavBackend::CLASSIFICATION_PRIVATE]; + + /** @var \PHPUnit_Framework_MockObject_MockObject | CalDavBackend $backend */ + $backend = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock(); + $backend->expects($this->any())->method('getCalendarObjects')->willReturn([ + $calObject0, $calObject1, $calObject2 + ]); + $backend->expects($this->any())->method('getMultipleCalendarObjects') + ->with(666, ['event-0', 'event-1', 'event-2']) + ->willReturn([ + $calObject0, $calObject1, $calObject2 + ]); + $backend->expects($this->any())->method('getCalendarObject') + ->willReturn($calObject1)->with(666, 'event-1'); + + $calendarInfo = [ + 'principaluri' => 'user2', + 'id' => 666, + 'uri' => 'cal', + ]; + + if ($isShared) { + $calendarInfo['{http://owncloud.org/ns}owner-principal'] = 'user1'; + + } + $c = new Calendar($backend, $calendarInfo, $this->l10n); + + // test private event + $privateEvent = $c->getChild('event-1'); + $calData = $privateEvent->get(); + $event = Reader::read($calData); + + $this->assertEquals($start, $event->VEVENT->DTSTART->getValue()); + $this->assertEquals($end, $event->VEVENT->DTEND->getValue()); + + if ($isShared) { + $this->assertEquals('Busy', $event->VEVENT->SUMMARY->getValue()); + $this->assertArrayNotHasKey('ATTENDEE', $event->VEVENT); + $this->assertArrayNotHasKey('LOCATION', $event->VEVENT); + $this->assertArrayNotHasKey('DESCRIPTION', $event->VEVENT); + $this->assertArrayNotHasKey('ORGANIZER', $event->VEVENT); + } else { + $this->assertEquals('Test Event', $event->VEVENT->SUMMARY->getValue()); + } + } + + public function providesConfidentialClassificationData() { + return [ + [3, false], + [2, true] + ]; + } } diff --git a/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php index 80f284e470e..2b3f3e15d1a 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php @@ -73,6 +73,11 @@ class FilesPluginTest extends TestCase { */ private $config; + /** + * @var \OCP\IRequest | \PHPUnit_Framework_MockObject_MockObject + */ + private $request; + public function setUp() { parent::setUp(); $this->server = $this->getMockBuilder('\Sabre\DAV\Server') @@ -88,11 +93,13 @@ class FilesPluginTest extends TestCase { $this->config->expects($this->any())->method('getSystemValue') ->with($this->equalTo('data-fingerprint'), $this->equalTo('')) ->willReturn('my_fingerprint'); + $this->request = $this->getMock('\OCP\IRequest'); $this->plugin = new FilesPlugin( $this->tree, $this->view, - $this->config + $this->config, + $this->request ); $this->plugin->initialize($this->server); } @@ -268,6 +275,7 @@ class FilesPluginTest extends TestCase { $this->tree, $this->view, $this->config, + $this->getMock('\OCP\IRequest'), true); $this->plugin->initialize($this->server); @@ -484,4 +492,60 @@ class FilesPluginTest extends TestCase { $this->plugin->checkMove('FolderA/test.txt', 'test.txt'); } + + public function downloadHeadersProvider() { + return [ + [ + false, + 'attachment; filename*=UTF-8\'\'somefile.xml; filename="somefile.xml"' + ], + [ + true, + 'attachment; filename="somefile.xml"' + ], + ]; + } + + /** + * @dataProvider downloadHeadersProvider + */ + public function testDownloadHeaders($isClumsyAgent, $contentDispositionHeader) { + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') + ->disableOriginalConstructor() + ->getMock(); + + $request + ->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('test/somefile.xml')); + + $node = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\File') + ->disableOriginalConstructor() + ->getMock(); + $node + ->expects($this->once()) + ->method('getName') + ->will($this->returnValue('somefile.xml')); + + $this->tree + ->expects($this->once()) + ->method('getNodeForPath') + ->with('test/somefile.xml') + ->will($this->returnValue($node)); + + $this->request + ->expects($this->once()) + ->method('isUserAgent') + ->will($this->returnValue($isClumsyAgent)); + + $response + ->expects($this->once()) + ->method('addHeader') + ->with('Content-Disposition', $contentDispositionHeader); + + $this->plugin->httpGet($request, $response); + } } diff --git a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php index 41d44efd89c..baf4259b215 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php @@ -343,7 +343,8 @@ class FilesReportPluginTest extends \Test\TestCase { new \OCA\DAV\Connector\Sabre\FilesPlugin( $this->tree, $this->view, - $config + $config, + $this->getMock('\OCP\IRequest') ) ); $this->plugin->initialize($this->server); diff --git a/apps/dav/tests/unit/Migration/ClassificationTest.php b/apps/dav/tests/unit/Migration/ClassificationTest.php new file mode 100644 index 00000000000..5c7fa627226 --- /dev/null +++ b/apps/dav/tests/unit/Migration/ClassificationTest.php @@ -0,0 +1,75 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @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 <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\DAV\Tests\unit\DAV\Migration; + +use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\Migration\Classification; +use OCA\DAV\Tests\unit\CalDAV\AbstractCalDavBackendTest; +use OCP\IUser; + +/** + * Class ClassificationTest + * + * @group DB + * + * @package OCA\DAV\Tests\unit\DAV + */ +class ClassificationTest extends AbstractCalDavBackendTest { + + /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IUserManager */ + private $userManager; + + public function setUp() { + parent::setUp(); + + $this->userManager = $this->getMockBuilder('OCP\IUserManager') + ->disableOriginalConstructor()->getMock(); + } + + public function test() { + // setup data + $calendarId = $this->createTestCalendar(); + $eventUri = $this->createEvent($calendarId, '20130912T130000Z', '20130912T140000Z'); + $object = $this->backend->getCalendarObject($calendarId, $eventUri); + + // assert proper classification + $this->assertEquals(CalDavBackend::CLASSIFICATION_PUBLIC, $object['classification']); + $this->backend->setClassification($object['id'], CalDavBackend::CLASSIFICATION_CONFIDENTIAL); + $object = $this->backend->getCalendarObject($calendarId, $eventUri); + $this->assertEquals(CalDavBackend::CLASSIFICATION_CONFIDENTIAL, $object['classification']); + + // run migration + $c = new Classification($this->backend, $this->userManager); + + /** @var IUser | \PHPUnit_Framework_MockObject_MockObject $user */ + $user = $this->getMockBuilder('OCP\IUser') + ->disableOriginalConstructor() + ->getMock(); + $user->expects($this->once())->method('getUID')->willReturn('caldav-unit-test'); + + $c->runForUser($user); + + // assert classification after migration + $object = $this->backend->getCalendarObject($calendarId, $eventUri); + $this->assertEquals(CalDavBackend::CLASSIFICATION_PUBLIC, $object['classification']); + } +} |