diff options
34 files changed, 686 insertions, 149 deletions
diff --git a/apps/dav/appinfo/application.php b/apps/dav/appinfo/application.php index 28b9a833456..7a201e1dd78 100644 --- a/apps/dav/appinfo/application.php +++ b/apps/dav/appinfo/application.php @@ -20,6 +20,7 @@ */ namespace OCA\Dav\AppInfo; +use OCA\DAV\CalDAV\BirthdayService; use OCA\DAV\CalDAV\CalDavBackend; use OCA\DAV\CardDAV\CardDavBackend; use OCA\DAV\CardDAV\ContactsManager; @@ -34,6 +35,7 @@ use \OCP\AppFramework\App; use OCP\AppFramework\IAppContainer; use OCP\Contacts\IManager; use OCP\IUser; +use Symfony\Component\EventDispatcher\GenericEvent; class Application extends App { @@ -74,12 +76,12 @@ class Application extends App { $container->registerService('CardDavBackend', function($c) { /** @var IAppContainer $c */ $db = $c->getServer()->getDatabaseConnection(); - $logger = $c->getServer()->getLogger(); + $dispatcher = $c->getServer()->getEventDispatcher(); $principal = new \OCA\DAV\Connector\Sabre\Principal( $c->getServer()->getUserManager(), $c->getServer()->getGroupManager() ); - return new CardDavBackend($db, $principal, $logger); + return new CardDavBackend($db, $principal, $dispatcher); }); $container->registerService('CalDavBackend', function($c) { @@ -109,6 +111,15 @@ class Application extends App { $c->query('CalDavBackend') ); }); + + $container->registerService('BirthdayService', function($c) { + /** @var IAppContainer $c */ + return new BirthdayService( + $c->query('CalDavBackend'), + $c->query('CardDavBackend') + ); + + }); } /** @@ -125,6 +136,30 @@ class Application extends App { /** @var HookManager $hm */ $hm = $this->getContainer()->query('HookManager'); $hm->setup(); + + $listener = function($event) { + if ($event instanceof GenericEvent) { + $b = $this->getContainer()->query('BirthdayService'); + $b->onCardChanged( + $event->getArgument('addressBookId'), + $event->getArgument('cardUri'), + $event->getArgument('cardData') + ); + } + }; + + $dispatcher = $this->getContainer()->getServer()->getEventDispatcher(); + $dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::createCard', $listener); + $dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::updateCard', $listener); + $dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::deleteCard', function($event) { + if ($event instanceof GenericEvent) { + $b = $this->getContainer()->query('BirthdayService'); + $b->onCardDeleted( + $event->getArgument('addressBookId'), + $event->getArgument('cardUri') + ); + } + }); } public function getSyncService() { diff --git a/apps/dav/appinfo/register_command.php b/apps/dav/appinfo/register_command.php index 4981cab9264..e07f6b4a25b 100644 --- a/apps/dav/appinfo/register_command.php +++ b/apps/dav/appinfo/register_command.php @@ -24,21 +24,21 @@ use OCA\DAV\Command\CreateAddressBook; use OCA\DAV\Command\CreateCalendar; use OCA\Dav\Command\MigrateAddressbooks; use OCA\Dav\Command\MigrateCalendars; +use OCA\DAV\Command\SyncBirthdayCalendar; use OCA\DAV\Command\SyncSystemAddressBook; -$config = \OC::$server->getConfig(); $dbConnection = \OC::$server->getDatabaseConnection(); $userManager = OC::$server->getUserManager(); $groupManager = OC::$server->getGroupManager(); $config = \OC::$server->getConfig(); -$logger = \OC::$server->getLogger(); $app = new Application(); /** @var Symfony\Component\Console\Application $application */ -$application->add(new CreateAddressBook($userManager, $groupManager, $dbConnection, $logger)); $application->add(new CreateCalendar($userManager, $groupManager, $dbConnection)); +$application->add(new CreateAddressBook($userManager, $app->getContainer()->query('CardDavBackend'))); $application->add(new SyncSystemAddressBook($app->getSyncService())); +$application->add(new SyncBirthdayCalendar($userManager, $app->getContainer()->query('BirthdayService'))); // the occ tool is *for now* only available in debug mode for developers to test if ($config->getSystemValue('debug', false)){ diff --git a/apps/dav/appinfo/v1/caldav.php b/apps/dav/appinfo/v1/caldav.php index f860ced3877..333e8bbb3c4 100644 --- a/apps/dav/appinfo/v1/caldav.php +++ b/apps/dav/appinfo/v1/caldav.php @@ -30,6 +30,7 @@ use Sabre\CalDAV\CalendarRoot; $authBackend = new Auth( \OC::$server->getSession(), \OC::$server->getUserSession(), + \OC::$server->getRequest(), 'principals/' ); $principalBackend = new Principal( diff --git a/apps/dav/appinfo/v1/carddav.php b/apps/dav/appinfo/v1/carddav.php index e0c79c75b72..54f0d259bb9 100644 --- a/apps/dav/appinfo/v1/carddav.php +++ b/apps/dav/appinfo/v1/carddav.php @@ -32,6 +32,7 @@ use Sabre\CardDAV\Plugin; $authBackend = new Auth( \OC::$server->getSession(), \OC::$server->getUserSession(), + \OC::$server->getRequest(), 'principals/' ); $principalBackend = new Principal( diff --git a/apps/dav/appinfo/v1/webdav.php b/apps/dav/appinfo/v1/webdav.php index 3d3e51e84bc..211ffabef84 100644 --- a/apps/dav/appinfo/v1/webdav.php +++ b/apps/dav/appinfo/v1/webdav.php @@ -41,6 +41,7 @@ $serverFactory = new \OCA\DAV\Connector\Sabre\ServerFactory( $authBackend = new \OCA\DAV\Connector\Sabre\Auth( \OC::$server->getSession(), \OC::$server->getUserSession(), + \OC::$server->getRequest(), 'principals/' ); $requestUri = \OC::$server->getRequest()->getRequestUri(); diff --git a/apps/dav/command/createaddressbook.php b/apps/dav/command/createaddressbook.php index 3d99afd4ba3..48302a2b439 100644 --- a/apps/dav/command/createaddressbook.php +++ b/apps/dav/command/createaddressbook.php @@ -36,33 +36,21 @@ use Symfony\Component\Console\Output\OutputInterface; class CreateAddressBook extends Command { /** @var IUserManager */ - protected $userManager; + private $userManager; - /** @var \OCP\IDBConnection */ - protected $dbConnection; - - /** @var ILogger */ - private $logger; - - /** @var IGroupManager $groupManager */ - private $groupManager; + /** @var CardDavBackend */ + private $cardDavBackend; /** * @param IUserManager $userManager - * @param IDBConnection $dbConnection - * @param IConfig $config - * @param ILogger $logger + * @param CardDavBackend $cardDavBackend */ function __construct(IUserManager $userManager, - IGroupManager $groupManager, - IDBConnection $dbConnection, - ILogger $logger + CardDavBackend $cardDavBackend ) { parent::__construct(); $this->userManager = $userManager; - $this->groupManager = $groupManager; - $this->dbConnection = $dbConnection; - $this->logger = $logger; + $this->cardDavBackend = $cardDavBackend; } protected function configure() { @@ -82,13 +70,8 @@ class CreateAddressBook extends Command { if (!$this->userManager->userExists($user)) { throw new \InvalidArgumentException("User <$user> in unknown."); } - $principalBackend = new Principal( - $this->userManager, - $this->groupManager - ); $name = $input->getArgument('name'); - $carddav = new CardDavBackend($this->dbConnection, $principalBackend, $this->logger); - $carddav->createAddressBook("principals/users/$user", $name, []); + $this->cardDavBackend->createAddressBook("principals/users/$user", $name, []); } } diff --git a/apps/dav/command/syncbirthdaycalendar.php b/apps/dav/command/syncbirthdaycalendar.php new file mode 100644 index 00000000000..66ab540b9ad --- /dev/null +++ b/apps/dav/command/syncbirthdaycalendar.php @@ -0,0 +1,85 @@ +<?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\Command; + +use OCA\DAV\CalDAV\BirthdayService; +use OCP\IUser; +use OCP\IUserManager; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class SyncBirthdayCalendar extends Command { + + /** @var BirthdayService */ + private $birthdayService; + + /** @var IUserManager */ + private $userManager; + + /** + * @param IUserManager $userManager + * @param BirthdayService $birthdayService + */ + function __construct(IUserManager $userManager, BirthdayService $birthdayService) { + parent::__construct(); + $this->birthdayService = $birthdayService; + $this->userManager = $userManager; + } + + protected function configure() { + $this + ->setName('dav:sync-birthday-calendar') + ->setDescription('Synchronizes the birthday calendar') + ->addArgument('user', + InputArgument::OPTIONAL, + 'User for whom the birthday calendar will be synchronized'); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + */ + protected function execute(InputInterface $input, OutputInterface $output) { + if ($input->hasArgument('user')) { + $user = $input->getArgument('user'); + if (!$this->userManager->userExists($user)) { + throw new \InvalidArgumentException("User <$user> in unknown."); + } + $output->writeln("Start birthday calendar sync for $user"); + $this->birthdayService->syncUser($user); + return; + } + $output->writeln("Start birthday calendar sync for all users ..."); + $p = new ProgressBar($output); + $p->start(); + $this->userManager->callForAllUsers(function($user) use ($p) { + $p->advance(); + /** @var IUser $user */ + $this->birthdayService->syncUser($user->getUID()); + }); + + $p->finish(); + $output->writeln(''); + } +} diff --git a/apps/dav/command/syncsystemaddressbook.php b/apps/dav/command/syncsystemaddressbook.php index b83a37131c3..b62a42d7b90 100644 --- a/apps/dav/command/syncsystemaddressbook.php +++ b/apps/dav/command/syncsystemaddressbook.php @@ -34,7 +34,6 @@ class SyncSystemAddressBook extends Command { private $syncService; /** - * @param IUserManager $userManager * @param SyncService $syncService */ function __construct(SyncService $syncService) { diff --git a/apps/dav/lib/caldav/birthdayservice.php b/apps/dav/lib/caldav/birthdayservice.php new file mode 100644 index 00000000000..3b0a2a10e1c --- /dev/null +++ b/apps/dav/lib/caldav/birthdayservice.php @@ -0,0 +1,187 @@ +<?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 Exception; +use OCA\DAV\CardDAV\CardDavBackend; +use Sabre\VObject\Component\VCalendar; +use Sabre\VObject\Reader; + +class BirthdayService { + + const BIRTHDAY_CALENDAR_URI = 'contact_birthdays'; + + /** + * BirthdayService constructor. + * + * @param CalDavBackend $calDavBackEnd + * @param CardDavBackend $cardDavBackEnd + */ + public function __construct($calDavBackEnd, $cardDavBackEnd) { + $this->calDavBackEnd = $calDavBackEnd; + $this->cardDavBackEnd = $cardDavBackEnd; + } + + /** + * @param int $addressBookId + * @param string $cardUri + * @param string $cardData + */ + public function onCardChanged($addressBookId, $cardUri, $cardData) { + + $book = $this->cardDavBackEnd->getAddressBookById($addressBookId); + $principalUri = $book['principaluri']; + $calendarUri = self::BIRTHDAY_CALENDAR_URI; + $calendar = $this->ensureCalendarExists($principalUri, $calendarUri, []); + $objectUri = $book['uri'] . '-' . $cardUri. '.ics'; + $calendarData = $this->buildBirthdayFromContact($cardData); + $existing = $this->calDavBackEnd->getCalendarObject($calendar['id'], $objectUri); + if (is_null($calendarData)) { + if (!is_null($existing)) { + $this->calDavBackEnd->deleteCalendarObject($calendar['id'], $objectUri); + } + } else { + if (is_null($existing)) { + $this->calDavBackEnd->createCalendarObject($calendar['id'], $objectUri, $calendarData->serialize()); + } else { + if ($this->birthdayEvenChanged($existing['calendardata'], $calendarData)) { + $this->calDavBackEnd->updateCalendarObject($calendar['id'], $objectUri, $calendarData->serialize()); + } + } + } + } + + /** + * @param int $addressBookId + * @param string $cardUri + */ + public function onCardDeleted($addressBookId, $cardUri) { + $book = $this->cardDavBackEnd->getAddressBookById($addressBookId); + $principalUri = $book['principaluri']; + $calendarUri = self::BIRTHDAY_CALENDAR_URI; + $calendar = $this->ensureCalendarExists($principalUri, $calendarUri, []); + $objectUri = $book['uri'] . '-' . $cardUri. '.ics'; + $this->calDavBackEnd->deleteCalendarObject($calendar['id'], $objectUri); + } + + /** + * @param string $principal + * @param string $id + * @param array $properties + * @return array|null + * @throws \Sabre\DAV\Exception\BadRequest + */ + public function ensureCalendarExists($principal, $id, $properties) { + $book = $this->calDavBackEnd->getCalendarByUri($principal, $id); + if (!is_null($book)) { + return $book; + } + $this->calDavBackEnd->createCalendar($principal, $id, $properties); + + return $this->calDavBackEnd->getCalendarByUri($principal, $id); + } + + /** + * @param string $cardData + * @return null|VCalendar + */ + public function buildBirthdayFromContact($cardData) { + if (empty($cardData)) { + return null; + } + try { + $doc = Reader::read($cardData); + } catch (Exception $e) { + return null; + } + + if (!isset($doc->BDAY)) { + return null; + } + $birthday = $doc->BDAY; + if (!(string)$birthday) { + return null; + } + $title = str_replace('{name}', + strtr((string)$doc->FN, array('\,' => ',', '\;' => ';')), + '{name}\'s Birthday' + ); + try { + $date = new \DateTime($birthday); + } catch (Exception $e) { + return null; + } + $vCal = new VCalendar(); + $vCal->VERSION = '2.0'; + $vEvent = $vCal->createComponent('VEVENT'); + $vEvent->add('DTSTART'); + $vEvent->DTSTART->setDateTime( + $date + ); + $vEvent->DTSTART['VALUE'] = 'DATE'; + $vEvent->add('DTEND'); + $date->add(new \DateInterval('P1D')); + $vEvent->DTEND->setDateTime( + $date + ); + $vEvent->DTEND['VALUE'] = 'DATE'; + $vEvent->{'UID'} = $doc->UID; + $vEvent->{'RRULE'} = 'FREQ=YEARLY'; + $vEvent->{'SUMMARY'} = $title . ' (' . $date->format('Y') . ')'; + $vEvent->{'TRANSP'} = 'TRANSPARENT'; + $vCal->add($vEvent); + return $vCal; + } + + /** + * @param string $user + */ + public function syncUser($user) { + $books = $this->cardDavBackEnd->getAddressBooksForUser('principals/users/'.$user); + foreach($books as $book) { + $cards = $this->cardDavBackEnd->getCards($book['id']); + foreach($cards as $card) { + $this->onCardChanged($book['id'], $card['uri'], $card['carddata']); + } + } + } + + /** + * @param string $existingCalendarData + * @param VCalendar $newCalendarData + * @return bool + */ + public function birthdayEvenChanged($existingCalendarData, $newCalendarData) { + try { + $existingBirthday = Reader::read($existingCalendarData); + } catch (Exception $ex) { + return true; + } + if ($newCalendarData->VEVENT->DTSTART->getValue() !== $existingBirthday->VEVENT->DTSTART->getValue() || + $newCalendarData->VEVENT->SUMMARY->getValue() !== $existingBirthday->VEVENT->SUMMARY->getValue() + ) { + return true; + } + return false; + } + +} diff --git a/apps/dav/lib/caldav/caldavbackend.php b/apps/dav/lib/caldav/caldavbackend.php index 775612487f9..c674876598d 100644 --- a/apps/dav/lib/caldav/caldavbackend.php +++ b/apps/dav/lib/caldav/caldavbackend.php @@ -235,6 +235,11 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription return array_values($calendars); } + /** + * @param string $principal + * @param string $uri + * @return array|null + */ public function getCalendarByUri($principal, $uri) { $fields = array_values($this->propertyMap); $fields[] = 'id'; @@ -1367,4 +1372,5 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription public function applyShareAcl($resourceId, $acl) { return $this->sharingBackend->applyShareAcl($resourceId, $acl); } + } diff --git a/apps/dav/lib/caldav/calendar.php b/apps/dav/lib/caldav/calendar.php index 8ed5b6563d0..6b34d570eb3 100644 --- a/apps/dav/lib/caldav/calendar.php +++ b/apps/dav/lib/caldav/calendar.php @@ -80,6 +80,10 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable { } function delete() { + if ($this->getName() === BirthdayService::BIRTHDAY_CALENDAR_URI) { + throw new Forbidden(); + } + if (isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal'])) { $principal = 'principal:' . parent::getOwner(); $shares = $this->getShares(); diff --git a/apps/dav/lib/carddav/carddavbackend.php b/apps/dav/lib/carddav/carddavbackend.php index 78706ae6bff..56fa652d798 100644 --- a/apps/dav/lib/carddav/carddavbackend.php +++ b/apps/dav/lib/carddav/carddavbackend.php @@ -37,6 +37,8 @@ use Sabre\DAV\Exception\BadRequest; use Sabre\HTTP\URLUtil; use Sabre\VObject\Component\VCard; use Sabre\VObject\Reader; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\GenericEvent; class CardDavBackend implements BackendInterface, SyncSupport { @@ -64,15 +66,22 @@ class CardDavBackend implements BackendInterface, SyncSupport { const ACCESS_READ_WRITE = 2; const ACCESS_READ = 3; + /** @var EventDispatcherInterface */ + private $dispatcher; + /** * CardDavBackend constructor. * * @param IDBConnection $db * @param Principal $principalBackend + * @param EventDispatcherInterface $dispatcher */ - public function __construct(IDBConnection $db, Principal $principalBackend) { + public function __construct(IDBConnection $db, + Principal $principalBackend, + $dispatcher ) { $this->db = $db; $this->principalBackend = $principalBackend; + $this->dispatcher = $dispatcher; $this->sharingBackend = new Backend($this->db, $principalBackend, 'addressbook'); } @@ -492,6 +501,14 @@ class CardDavBackend implements BackendInterface, SyncSupport { $this->addChange($addressBookId, $cardUri, 1); $this->updateProperties($addressBookId, $cardUri, $cardData); + if (!is_null($this->dispatcher)) { + $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::createCard', + new GenericEvent(null, [ + 'addressBookId' => $addressBookId, + 'cardUri' => $cardUri, + 'cardData' => $cardData])); + } + return '"' . $etag . '"'; } @@ -536,6 +553,14 @@ class CardDavBackend implements BackendInterface, SyncSupport { $this->addChange($addressBookId, $cardUri, 2); $this->updateProperties($addressBookId, $cardUri, $cardData); + if (!is_null($this->dispatcher)) { + $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::updateCard', + new GenericEvent(null, [ + 'addressBookId' => $addressBookId, + 'cardUri' => $cardUri, + 'cardData' => $cardData])); + } + return '"' . $etag . '"'; } @@ -560,6 +585,13 @@ class CardDavBackend implements BackendInterface, SyncSupport { $this->addChange($addressBookId, $cardUri, 3); + if (!is_null($this->dispatcher)) { + $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::deleteCard', + new GenericEvent(null, [ + 'addressBookId' => $addressBookId, + 'cardUri' => $cardUri])); + } + if ($ret === 1) { if ($cardId !== null) { $this->purgeProperties($addressBookId, $cardId); diff --git a/apps/dav/lib/connector/sabre/auth.php b/apps/dav/lib/connector/sabre/auth.php index a046e078482..4bb07c5f0ed 100644 --- a/apps/dav/lib/connector/sabre/auth.php +++ b/apps/dav/lib/connector/sabre/auth.php @@ -30,6 +30,7 @@ namespace OCA\DAV\Connector\Sabre; use Exception; +use OCP\IRequest; use OCP\ISession; use OCP\IUserSession; use Sabre\DAV\Auth\Backend\AbstractBasic; @@ -45,17 +46,22 @@ class Auth extends AbstractBasic { private $session; /** @var IUserSession */ private $userSession; + /** @var IRequest */ + private $request; /** * @param ISession $session * @param IUserSession $userSession + * @param IRequest $request * @param string $principalPrefix */ public function __construct(ISession $session, IUserSession $userSession, + IRequest $request, $principalPrefix = 'principals/users/') { $this->session = $session; $this->userSession = $userSession; + $this->request = $request; $this->principalPrefix = $principalPrefix; } @@ -107,26 +113,6 @@ class Auth extends AbstractBasic { } /** - * Returns information about the currently logged in username. - * - * If nobody is currently logged in, this method should return null. - * - * @return string|null - */ - public function getCurrentUser() { - $user = $this->userSession->getUser() ? $this->userSession->getUser()->getUID() : null; - if($user !== null && $this->isDavAuthenticated($user)) { - return $user; - } - - if($user !== null && is_null($this->session->get(self::DAV_AUTHENTICATED))) { - return $user; - } - - return null; - } - - /** * @param RequestInterface $request * @param ResponseInterface $response * @return array @@ -150,8 +136,19 @@ class Auth extends AbstractBasic { * @param RequestInterface $request * @param ResponseInterface $response * @return array + * @throws NotAuthenticated */ private function auth(RequestInterface $request, ResponseInterface $response) { + // If request is not GET and not authenticated via WebDAV a requesttoken is required + if($this->userSession->isLoggedIn() && + $this->request->getMethod() !== 'GET' && + !$this->isDavAuthenticated($this->userSession->getUser()->getUID())) { + if(!$this->request->passesCSRFCheck()) { + $response->setStatus(401); + throw new \Sabre\DAV\Exception\NotAuthenticated('CSRF check not passed.'); + } + } + if (\OC_User::handleApacheAuth() || //Fix for broken webdav clients ($this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED))) || diff --git a/apps/dav/lib/connector/sabre/filesplugin.php b/apps/dav/lib/connector/sabre/filesplugin.php index 2e913ee1077..eb9116d219b 100644 --- a/apps/dav/lib/connector/sabre/filesplugin.php +++ b/apps/dav/lib/connector/sabre/filesplugin.php @@ -193,11 +193,13 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin { // adds a 'Content-Disposition: attachment' header $response->addHeader('Content-Disposition', 'attachment'); - //Add OC-Checksum header - /** @var $node File */ - $checksum = $node->getChecksum(); - if ($checksum !== null) { - $response->addHeader('OC-Checksum', $checksum); + if ($node instanceof \OCA\DAV\Connector\Sabre\File) { + //Add OC-Checksum header + /** @var $node File */ + $checksum = $node->getChecksum(); + if ($checksum !== null) { + $response->addHeader('OC-Checksum', $checksum); + } } } diff --git a/apps/dav/lib/dav/sharing/plugin.php b/apps/dav/lib/dav/sharing/plugin.php index f6e2cceebd9..e6eab3539b3 100644 --- a/apps/dav/lib/dav/sharing/plugin.php +++ b/apps/dav/lib/dav/sharing/plugin.php @@ -129,9 +129,6 @@ class Plugin extends ServerPlugin { return; } - // CSRF protection - $this->protectAgainstCSRF(); - $requestBody = $request->getBodyAsString(); // If this request handler could not deal with this POST request, it @@ -201,18 +198,4 @@ class Plugin extends ServerPlugin { } } - private function protectAgainstCSRF() { - $user = $this->auth->getCurrentUser(); - if ($this->auth->isDavAuthenticated($user)) { - return true; - } - - if ($this->request->passesCSRFCheck()) { - return true; - } - - throw new BadRequest(); - } - - } diff --git a/apps/dav/lib/rootcollection.php b/apps/dav/lib/rootcollection.php index 2a8f63a2270..b3648e7ba38 100644 --- a/apps/dav/lib/rootcollection.php +++ b/apps/dav/lib/rootcollection.php @@ -36,6 +36,7 @@ class RootCollection extends SimpleCollection { public function __construct() { $config = \OC::$server->getConfig(); $db = \OC::$server->getDatabaseConnection(); + $dispatcher = \OC::$server->getEventDispatcher(); $userPrincipalBackend = new Principal( \OC::$server->getUserManager(), \OC::$server->getGroupManager() @@ -79,11 +80,11 @@ class RootCollection extends SimpleCollection { \OC::$server->getLogger() ); - $usersCardDavBackend = new CardDavBackend($db, $userPrincipalBackend); + $usersCardDavBackend = new CardDavBackend($db, $userPrincipalBackend, $dispatcher); $usersAddressBookRoot = new AddressBookRoot($userPrincipalBackend, $usersCardDavBackend, 'principals/users'); $usersAddressBookRoot->disableListing = $disableListing; - $systemCardDavBackend = new CardDavBackend($db, $userPrincipalBackend); + $systemCardDavBackend = new CardDavBackend($db, $userPrincipalBackend, $dispatcher); $systemAddressBookRoot = new AddressBookRoot(new SystemPrincipalBackend(), $systemCardDavBackend, 'principals/system'); $systemAddressBookRoot->disableListing = $disableListing; diff --git a/apps/dav/lib/server.php b/apps/dav/lib/server.php index f5f1875a480..ed1ee684049 100644 --- a/apps/dav/lib/server.php +++ b/apps/dav/lib/server.php @@ -53,7 +53,8 @@ class Server { // Backends $authBackend = new Auth( \OC::$server->getSession(), - \OC::$server->getUserSession() + \OC::$server->getUserSession(), + \OC::$server->getRequest() ); // Set URL explicitly due to reverse-proxy situations diff --git a/apps/dav/tests/travis/caldav/script.sh b/apps/dav/tests/travis/caldav/script.sh index aa5fc732922..7259372567c 100644 --- a/apps/dav/tests/travis/caldav/script.sh +++ b/apps/dav/tests/travis/caldav/script.sh @@ -10,6 +10,8 @@ sleep 30 # run the tests cd "$SCRIPTPATH/CalDAVTester" PYTHONPATH="$SCRIPTPATH/pycalendar/src" python testcaldav.py --print-details-onfail --basedir "$SCRIPTPATH/../caldavtest/" -o cdt.txt \ + "CalDAV/current-user-principal.xml" \ + "CalDAV/sync-report.xml" \ "CalDAV/sharing-calendars.xml" RESULT=$? diff --git a/apps/dav/tests/unit/caldav/calendartest.php b/apps/dav/tests/unit/caldav/calendartest.php index 93b3f4bff8c..4a3c94e8aba 100644 --- a/apps/dav/tests/unit/caldav/calendartest.php +++ b/apps/dav/tests/unit/caldav/calendartest.php @@ -37,7 +37,8 @@ class CalendarTest extends TestCase { $calendarInfo = [ '{http://owncloud.org/ns}owner-principal' => 'user1', 'principaluri' => 'user2', - 'id' => 666 + 'id' => 666, + 'uri' => 'cal', ]; $c = new Calendar($backend, $calendarInfo); $c->delete(); @@ -56,7 +57,8 @@ class CalendarTest extends TestCase { $calendarInfo = [ '{http://owncloud.org/ns}owner-principal' => 'user1', 'principaluri' => 'user2', - 'id' => 666 + 'id' => 666, + 'uri' => 'cal', ]; $c = new Calendar($backend, $calendarInfo); $c->delete(); diff --git a/apps/dav/tests/unit/carddav/birthdayservicetest.php b/apps/dav/tests/unit/carddav/birthdayservicetest.php new file mode 100644 index 00000000000..faf42d9e1b8 --- /dev/null +++ b/apps/dav/tests/unit/carddav/birthdayservicetest.php @@ -0,0 +1,171 @@ +<?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\CardDAV; + +use OCA\DAV\CalDAV\BirthdayService; +use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\CardDAV\CardDavBackend; +use Sabre\VObject\Component\VCalendar; +use Sabre\VObject\Reader; +use Test\TestCase; + +class BirthdayServiceTest extends TestCase { + + /** @var BirthdayService */ + private $service; + /** @var CalDavBackend | \PHPUnit_Framework_MockObject_MockObject */ + private $calDav; + /** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject */ + private $cardDav; + + public function setUp() { + parent::setUp(); + + $this->calDav = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock(); + $this->cardDav = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')->disableOriginalConstructor()->getMock(); + + $this->service = new BirthdayService($this->calDav, $this->cardDav); + } + + /** + * @dataProvider providesVCards + * @param boolean $nullExpected + * @param string | null $data + */ + public function testBuildBirthdayFromContact($nullExpected, $data) { + $cal = $this->service->buildBirthdayFromContact($data); + if ($nullExpected) { + $this->assertNull($cal); + } else { + $this->assertInstanceOf('Sabre\VObject\Component\VCalendar', $cal); + $this->assertTrue(isset($cal->VEVENT)); + $this->assertEquals('FREQ=YEARLY', $cal->VEVENT->RRULE->getValue()); + $this->assertEquals('12345\'s Birthday (1900)', $cal->VEVENT->SUMMARY->getValue()); + $this->assertEquals('TRANSPARENT', $cal->VEVENT->TRANSP->getValue()); + } + } + + public function testOnCardDeleted() { + $this->cardDav->expects($this->once())->method('getAddressBookById') + ->with(666) + ->willReturn([ + 'principaluri' => 'principals/users/user01', + 'uri' => 'default' + ]); + $this->calDav->expects($this->once())->method('getCalendarByUri') + ->with('principals/users/user01', 'contact_birthdays') + ->willReturn([ + 'id' => 1234 + ]); + $this->calDav->expects($this->once())->method('deleteCalendarObject')->with(1234, 'default-gump.vcf.ics'); + + $this->service->onCardDeleted(666, 'gump.vcf'); + } + + /** + * @dataProvider providesCardChanges + */ + public function testOnCardChanged($expectedOp) { + $this->cardDav->expects($this->once())->method('getAddressBookById') + ->with(666) + ->willReturn([ + 'principaluri' => 'principals/users/user01', + 'uri' => 'default' + ]); + $this->calDav->expects($this->once())->method('getCalendarByUri') + ->with('principals/users/user01', 'contact_birthdays') + ->willReturn([ + 'id' => 1234 + ]); + + /** @var BirthdayService | \PHPUnit_Framework_MockObject_MockObject $service */ + $service = $this->getMock('\OCA\DAV\CalDAV\BirthdayService', + ['buildBirthdayFromContact', 'birthdayEvenChanged'], [$this->calDav, $this->cardDav]); + + if ($expectedOp === 'delete') { + $this->calDav->expects($this->once())->method('getCalendarObject')->willReturn(''); + $service->expects($this->once())->method('buildBirthdayFromContact')->willReturn(null); + $this->calDav->expects($this->once())->method('deleteCalendarObject')->with(1234, 'default-gump.vcf.ics'); + } + if ($expectedOp === 'create') { + $service->expects($this->once())->method('buildBirthdayFromContact')->willReturn(new VCalendar()); + $this->calDav->expects($this->once())->method('createCalendarObject')->with(1234, 'default-gump.vcf.ics', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nEND:VCALENDAR\r\n"); + } + if ($expectedOp === 'update') { + $service->expects($this->once())->method('buildBirthdayFromContact')->willReturn(new VCalendar()); + $service->expects($this->once())->method('birthdayEvenChanged')->willReturn(true); + $this->calDav->expects($this->once())->method('getCalendarObject')->willReturn([ + 'calendardata' => '']); + $this->calDav->expects($this->once())->method('updateCalendarObject')->with(1234, 'default-gump.vcf.ics', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nEND:VCALENDAR\r\n"); + } + + $service->onCardChanged(666, 'gump.vcf', ''); + } + + /** + * @dataProvider providesBirthday + * @param $expected + * @param $old + * @param $new + */ + public function testBirthdayEvenChanged($expected, $old, $new) { + $new = Reader::read($new); + $this->assertEquals($expected, $this->service->birthdayEvenChanged($old, $new)); + } + + public function providesBirthday() { + return [ + [true, + '', + "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:12345\r\nDTSTAMP:20160218T133704Z\r\nDTSTART;VALUE=DATE:19000101\r\nDTEND;VALUE=DATE:19000102\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:12345's Birthday (1900)\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"], + [false, + "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:12345\r\nDTSTAMP:20160218T133704Z\r\nDTSTART;VALUE=DATE:19000101\r\nDTEND;VALUE=DATE:19000102\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:12345's Birthday (1900)\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", + "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:12345\r\nDTSTAMP:20160218T133704Z\r\nDTSTART;VALUE=DATE:19000101\r\nDTEND;VALUE=DATE:19000102\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:12345's Birthday (1900)\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"], + [true, + "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:12345\r\nDTSTAMP:20160218T133704Z\r\nDTSTART;VALUE=DATE:19000101\r\nDTEND;VALUE=DATE:19000102\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:4567's Birthday (1900)\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", + "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:12345\r\nDTSTAMP:20160218T133704Z\r\nDTSTART;VALUE=DATE:19000101\r\nDTEND;VALUE=DATE:19000102\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:12345's Birthday (1900)\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"], + [true, + "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:12345\r\nDTSTAMP:20160218T133704Z\r\nDTSTART;VALUE=DATE:19000101\r\nDTEND;VALUE=DATE:19000102\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:12345's Birthday (1900)\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", + "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:12345\r\nDTSTAMP:20160218T133704Z\r\nDTSTART;VALUE=DATE:19000102\r\nDTEND;VALUE=DATE:19000102\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:12345's Birthday (1900)\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"] + ]; + } + + public function providesCardChanges(){ + return[ + ['delete'], + ['create'], + ['update'] + ]; + } + + public function providesVCards() { + return [ + [true, null], + [true, ''], + [true, 'yasfewf'], + [true, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nEND:VCARD\r\n", "Dr. Foo Bar"], + [true, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:\r\nEND:VCARD\r\n", "Dr. Foo Bar"], + [true, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:someday\r\nEND:VCARD\r\n", "Dr. Foo Bar"], + [false, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.5.0//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:1900-01-01\r\nEND:VCARD\r\n", "Dr. Foo Bar"], + ]; + } +} diff --git a/apps/dav/tests/unit/carddav/carddavbackendtest.php b/apps/dav/tests/unit/carddav/carddavbackendtest.php index 3b5395fb09e..f920eb47b6e 100644 --- a/apps/dav/tests/unit/carddav/carddavbackendtest.php +++ b/apps/dav/tests/unit/carddav/carddavbackendtest.php @@ -77,7 +77,7 @@ class CardDavBackendTest extends TestCase { $this->db = \OC::$server->getDatabaseConnection(); - $this->backend = new CardDavBackend($this->db, $this->principal); + $this->backend = new CardDavBackend($this->db, $this->principal, null); // start every test with a empty cards_properties and cards table $query = $this->db->getQueryBuilder(); @@ -155,7 +155,7 @@ class CardDavBackendTest extends TestCase { /** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject $backend */ $backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend') - ->setConstructorArgs([$this->db, $this->principal]) + ->setConstructorArgs([$this->db, $this->principal, null]) ->setMethods(['updateProperties', 'purgeProperties'])->getMock(); // create a new address book @@ -201,7 +201,7 @@ class CardDavBackendTest extends TestCase { public function testMultiCard() { $this->backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend') - ->setConstructorArgs([$this->db, $this->principal]) + ->setConstructorArgs([$this->db, $this->principal, null]) ->setMethods(['updateProperties'])->getMock(); // create a new address book @@ -248,7 +248,7 @@ class CardDavBackendTest extends TestCase { public function testDeleteWithoutCard() { $this->backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend') - ->setConstructorArgs([$this->db, $this->principal]) + ->setConstructorArgs([$this->db, $this->principal, null]) ->setMethods([ 'getCardId', 'addChange', @@ -289,7 +289,7 @@ class CardDavBackendTest extends TestCase { public function testSyncSupport() { $this->backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend') - ->setConstructorArgs([$this->db, $this->principal]) + ->setConstructorArgs([$this->db, $this->principal, null]) ->setMethods(['updateProperties'])->getMock(); // create a new address book @@ -347,7 +347,7 @@ class CardDavBackendTest extends TestCase { $cardId = 2; $backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend') - ->setConstructorArgs([$this->db, $this->principal]) + ->setConstructorArgs([$this->db, $this->principal, null]) ->setMethods(['getCardId'])->getMock(); $backend->expects($this->any())->method('getCardId')->willReturn($cardId); diff --git a/apps/dav/tests/unit/connector/sabre/auth.php b/apps/dav/tests/unit/connector/sabre/auth.php index 5ff736664f3..57ed44f01c0 100644 --- a/apps/dav/tests/unit/connector/sabre/auth.php +++ b/apps/dav/tests/unit/connector/sabre/auth.php @@ -24,6 +24,7 @@ namespace OCA\DAV\Tests\Unit\Connector\Sabre; +use OCP\IRequest; use OCP\IUser; use Test\TestCase; use OCP\ISession; @@ -42,6 +43,8 @@ class Auth extends TestCase { private $auth; /** @var IUserSession */ private $userSession; + /** @var IRequest */ + private $request; public function setUp() { parent::setUp(); @@ -49,7 +52,13 @@ class Auth extends TestCase { ->disableOriginalConstructor()->getMock(); $this->userSession = $this->getMockBuilder('\OCP\IUserSession') ->disableOriginalConstructor()->getMock(); - $this->auth = new \OCA\DAV\Connector\Sabre\Auth($this->session, $this->userSession); + $this->request = $this->getMockBuilder('\OCP\IRequest') + ->disableOriginalConstructor()->getMock(); + $this->auth = new \OCA\DAV\Connector\Sabre\Auth( + $this->session, + $this->userSession, + $this->request + ); } public function testIsDavAuthenticatedWithoutDavSession() { @@ -189,51 +198,57 @@ class Auth extends TestCase { $this->assertFalse($this->invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword'])); } - public function testGetCurrentUserWithoutBeingLoggedIn() { - $this->assertSame(null, $this->auth->getCurrentUser()); - } - - public function testGetCurrentUserWithValidDAVLogin() { + /** + * @expectedException \Sabre\DAV\Exception\NotAuthenticated + * @expectedExceptionMessage CSRF check not passed. + */ + public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForNonGet() { + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->userSession + ->expects($this->once()) + ->method('isLoggedIn') + ->will($this->returnValue(true)); + $this->session + ->expects($this->once()) + ->method('get') + ->with('AUTHENTICATED_TO_DAV_BACKEND') + ->will($this->returnValue(null)); $user = $this->getMockBuilder('\OCP\IUser') ->disableOriginalConstructor() ->getMock(); $user->expects($this->once()) ->method('getUID') - ->will($this->returnValue('MyTestUser')); + ->will($this->returnValue('MyWrongDavUser')); $this->userSession - ->expects($this->exactly(2)) + ->expects($this->once()) ->method('getUser') ->will($this->returnValue($user)); - $this->session - ->expects($this->exactly(2)) - ->method('get') - ->with('AUTHENTICATED_TO_DAV_BACKEND') - ->will($this->returnValue('MyTestUser')); - $this->assertSame('MyTestUser', $this->auth->getCurrentUser()); + $response = $this->auth->check($request, $response); + $this->assertEquals([true, 'principals/users/MyWrongDavUser'], $response); } - public function testGetCurrentUserWithoutAnyDAVLogin() { - $user = $this->getMockBuilder('\OCP\IUser') + public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForGet() { + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') ->disableOriginalConstructor() ->getMock(); - $user->expects($this->once()) - ->method('getUID') - ->will($this->returnValue('MyTestUser')); $this->userSession ->expects($this->exactly(2)) - ->method('getUser') - ->will($this->returnValue($user)); + ->method('isLoggedIn') + ->will($this->returnValue(true)); $this->session - ->expects($this->exactly(2)) + ->expects($this->once()) ->method('get') ->with('AUTHENTICATED_TO_DAV_BACKEND') ->will($this->returnValue(null)); - - $this->assertSame('MyTestUser', $this->auth->getCurrentUser()); - } - - public function testGetCurrentUserWithWrongDAVUser() { $user = $this->getMockBuilder('\OCP\IUser') ->disableOriginalConstructor() ->getMock(); @@ -241,47 +256,49 @@ class Auth extends TestCase { ->method('getUID') ->will($this->returnValue('MyWrongDavUser')); $this->userSession - ->expects($this->exactly(2)) + ->expects($this->once()) ->method('getUser') ->will($this->returnValue($user)); - $this->session - ->expects($this->exactly(3)) - ->method('get') - ->with('AUTHENTICATED_TO_DAV_BACKEND') - ->will($this->returnValue('AnotherUser')); + $this->request + ->expects($this->once()) + ->method('getMethod') + ->willReturn('GET'); - $this->assertSame(null, $this->auth->getCurrentUser()); + $response = $this->auth->check($request, $response); + $this->assertEquals([true, 'principals/users/MyWrongDavUser'], $response); } - public function testAuthenticateAlreadyLoggedIn() { + + public function testAuthenticateAlreadyLoggedInWithCsrfTokenForGet() { $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') - ->disableOriginalConstructor() - ->getMock(); + ->disableOriginalConstructor() + ->getMock(); $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') - ->disableOriginalConstructor() - ->getMock(); + ->disableOriginalConstructor() + ->getMock(); $this->userSession - ->expects($this->once()) + ->expects($this->exactly(2)) ->method('isLoggedIn') ->will($this->returnValue(true)); $this->session - ->expects($this->once()) + ->expects($this->exactly(2)) ->method('get') ->with('AUTHENTICATED_TO_DAV_BACKEND') ->will($this->returnValue(null)); $user = $this->getMockBuilder('\OCP\IUser') ->disableOriginalConstructor() ->getMock(); - $user->expects($this->once()) + $user->expects($this->exactly(2)) ->method('getUID') ->will($this->returnValue('MyWrongDavUser')); $this->userSession - ->expects($this->once()) + ->expects($this->exactly(2)) ->method('getUser') ->will($this->returnValue($user)); - $this->session + $this->request ->expects($this->once()) - ->method('close'); + ->method('passesCSRFCheck') + ->willReturn(true); $response = $this->auth->check($request, $response); $this->assertEquals([true, 'principals/users/MyWrongDavUser'], $response); diff --git a/apps/files_external/lib/google.php b/apps/files_external/lib/google.php index f496fc77574..ee7a7383615 100644 --- a/apps/files_external/lib/google.php +++ b/apps/files_external/lib/google.php @@ -264,7 +264,7 @@ class Google extends \OC\Files\Storage\Common { foreach ($children->getItems() as $child) { $name = $child->getTitle(); // Check if this is a Google Doc i.e. no extension in name - if ($child->getFileExtension() === '' + if (empty($child->getFileExtension()) && $child->getMimeType() !== self::FOLDER ) { $name .= '.'.$this->getGoogleDocExtension($child->getMimeType()); @@ -368,8 +368,14 @@ class Google extends \OC\Files\Storage\Common { public function rename($path1, $path2) { $file = $this->getDriveFile($path1); if ($file) { + $newFile = $this->getDriveFile($path2); if (dirname($path1) === dirname($path2)) { - $file->setTitle(basename(($path2))); + if ($newFile) { + // rename to the name of the target file, could be an office file without extension + $file->setTitle($newFile->getTitle()); + } else { + $file->setTitle(basename(($path2))); + } } else { // Change file parent $parentFolder2 = $this->getDriveFile(dirname($path2)); @@ -394,8 +400,11 @@ class Google extends \OC\Files\Storage\Common { if ($result) { $this->setDriveFile($path1, false); $this->setDriveFile($path2, $result); - if ($oldfile) { - $this->service->files->delete($oldfile->getId()); + if ($oldfile && $newFile) { + // only delete if they have a different id (same id can happen for part files) + if ($newFile->getId() !== $oldfile->getId()) { + $this->service->files->delete($oldfile->getId()); + } } } return (bool)$result; diff --git a/core/js/files/client.js b/core/js/files/client.js index a7f393d325f..0bf5a69e19c 100644 --- a/core/js/files/client.js +++ b/core/js/files/client.js @@ -37,7 +37,10 @@ } url += options.host + this._root; - this._defaultHeaders = options.defaultHeaders || {'X-Requested-With': 'XMLHttpRequest'}; + this._defaultHeaders = options.defaultHeaders || { + 'X-Requested-With': 'XMLHttpRequest', + 'requesttoken': OC.requestToken + }; this._baseUrl = url; var clientOptions = { diff --git a/core/js/oc-backbone-webdav.js b/core/js/oc-backbone-webdav.js index ba678a32fcf..1c1b5c71d81 100644 --- a/core/js/oc-backbone-webdav.js +++ b/core/js/oc-backbone-webdav.js @@ -240,7 +240,8 @@ return options.url; }; var headers = _.extend({ - 'X-Requested-With': 'XMLHttpRequest' + 'X-Requested-With': 'XMLHttpRequest', + 'requesttoken': OC.requestToken }, options.headers); if (options.type === 'PROPFIND') { return callPropFind(client, options, model, headers); diff --git a/issue_template.md b/issue_template.md index 424f6c062a9..e19583977ef 100644 --- a/issue_template.md +++ b/issue_template.md @@ -1,3 +1,10 @@ +<!-- +Thanks for reporting issues back to ownCloud! This is the issue tracker of ownCloud, if you have any support question please check out https://owncloud.org/support + +This is the bug tracker for the Server component. Find other components at https://github.com/owncloud/core/blob/master/CONTRIBUTING.md#guidelines + +To make it possible for us to help you please fill out below information carefully. +--> ### Steps to reproduce 1. 2. diff --git a/lib/private/api.php b/lib/private/api.php index 6c6be233c9d..87f2aa9b118 100644 --- a/lib/private/api.php +++ b/lib/private/api.php @@ -188,7 +188,7 @@ class OC_API { /** * merge the returned result objects into one response * @param array $responses - * @return array|\OC_OCS_Result + * @return OC_OCS_Result */ public static function mergeResponses($responses) { // Sort into shipped and third-party @@ -442,6 +442,7 @@ class OC_API { /** * Based on the requested format the response content type is set + * @param string $format */ public static function setContentType($format = null) { $format = is_null($format) ? self::requestedFormat() : $format; diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php index 63949035b5a..37a1d75519d 100644 --- a/lib/private/files/stream/encryption.php +++ b/lib/private/files/stream/encryption.php @@ -183,7 +183,7 @@ class Encryption extends Wrapper { * * @param resource $source * @param string $mode - * @param array $context + * @param resource $context * @param string $protocol * @param string $class * @return resource diff --git a/lib/private/group/dummy.php b/lib/private/group/dummy.php index c0d206a34e1..97f00385954 100644 --- a/lib/private/group/dummy.php +++ b/lib/private/group/dummy.php @@ -114,6 +114,7 @@ class OC_Group_Dummy extends OC_Group_Backend { if(isset($this->groups[$gid])) { if(($index=array_search($uid, $this->groups[$gid]))!==false) { unset($this->groups[$gid][$index]); + return true; }else{ return false; } diff --git a/lib/private/group/manager.php b/lib/private/group/manager.php index 98e5551bcc5..7eca249c701 100644 --- a/lib/private/group/manager.php +++ b/lib/private/group/manager.php @@ -150,6 +150,10 @@ class Manager extends PublicEmitter implements IGroupManager { return $this->getGroupObject($gid); } + /** + * @param string $gid + * @return \OCP\IGroup + */ protected function getGroupObject($gid) { $backends = array(); foreach ($this->backends as $backend) { diff --git a/lib/private/memcache/factory.php b/lib/private/memcache/factory.php index 21149d8b6bf..204ded7d5ab 100644 --- a/lib/private/memcache/factory.php +++ b/lib/private/memcache/factory.php @@ -172,7 +172,7 @@ class Factory implements ICacheFactory { /** * @see \OC\Memcache\Factory::createLocal() * @param string $prefix - * @return \OC\Memcache\Cache|null + * @return Cache */ public function createLowLatency($prefix = '') { return $this->createLocal($prefix); diff --git a/lib/private/preview.php b/lib/private/preview.php index df6eeceddcb..4fca56dd984 100644 --- a/lib/private/preview.php +++ b/lib/private/preview.php @@ -202,7 +202,7 @@ class Preview { /** * returns the max width set in ownCloud's config * - * @return string + * @return integer */ public function getConfigMaxX() { return $this->configMaxWidth; @@ -211,7 +211,7 @@ class Preview { /** * returns the max height set in ownCloud's config * - * @return string + * @return integer */ public function getConfigMaxY() { return $this->configMaxHeight; @@ -546,7 +546,7 @@ class Preview { /** * Determines the size of the preview we should be looking for in the cache * - * @return int[] + * @return integer[] */ private function simulatePreviewDimensions() { $askedWidth = $this->getMaxX(); @@ -570,7 +570,7 @@ class Preview { * * @param int $originalWidth * @param int $originalHeight - * @return \int[] + * @return integer[] */ private function applyAspectRatio($askedWidth, $askedHeight, $originalWidth = 0, $originalHeight = 0) { if(!$originalWidth){ @@ -602,7 +602,7 @@ class Preview { * @param int $askedHeight * @param int $previewWidth * @param int $previewHeight - * @return \int[] + * @return integer[] */ private function applyCover($askedWidth, $askedHeight, $previewWidth, $previewHeight) { $originalRatio = $previewWidth / $previewHeight; @@ -628,7 +628,7 @@ class Preview { * @param int $askedWidth * @param int $askedHeight * - * @return \int[] + * @return integer[] */ private function fixSize($askedWidth, $askedHeight) { if ($this->scalingUp) { @@ -921,7 +921,7 @@ class Preview { * @param int $askedWidth * @param int $askedHeight * @param int $previewWidth - * @param null $previewHeight + * @param int $previewHeight * * @return int[] */ @@ -971,7 +971,7 @@ class Preview { * @param int $askedWidth * @param int $askedHeight * @param int $previewWidth - * @param null $previewHeight + * @param int $previewHeight */ private function crop($image, $askedWidth, $askedHeight, $previewWidth, $previewHeight = null) { $cropX = floor(abs($askedWidth - $previewWidth) * 0.5); @@ -990,7 +990,7 @@ class Preview { * @param int $askedWidth * @param int $askedHeight * @param int $previewWidth - * @param null $previewHeight + * @param int $previewHeight */ private function cropAndFill($image, $askedWidth, $askedHeight, $previewWidth, $previewHeight) { if ($previewWidth > $askedWidth) { @@ -1218,7 +1218,7 @@ class Preview { * @param int $maxDim * @param string $dimName * - * @return mixed + * @return integer */ private function limitMaxDim($dim, $maxDim, $dimName) { if (!is_null($maxDim)) { diff --git a/lib/public/appframework/utility/icontrollermethodreflector.php b/lib/public/appframework/utility/icontrollermethodreflector.php index b2f91fdb170..7bf422aa567 100644 --- a/lib/public/appframework/utility/icontrollermethodreflector.php +++ b/lib/public/appframework/utility/icontrollermethodreflector.php @@ -35,6 +35,7 @@ interface IControllerMethodReflector { /** * @param object $object an object or classname * @param string $method the method which we want to inspect + * @return void * @since 8.0.0 */ public function reflect($object, $method); diff --git a/lib/public/search/pagedprovider.php b/lib/public/search/pagedprovider.php index 93289a1bde4..c8530626e59 100644 --- a/lib/public/search/pagedprovider.php +++ b/lib/public/search/pagedprovider.php @@ -58,7 +58,7 @@ abstract class PagedProvider extends Provider { * Search for $query * @param string $query * @param int $page pages start at page 1 - * @param int $size, 0 = SIZE_ALL + * @param int $size 0 = SIZE_ALL * @return array An array of OCP\Search\Result's * @since 8.0.0 */ |