mirror of https://github.com/nextcloud/server.git
Merge branch 'master' into issue_20427
commit
dcfbbe4737
@ -1 +1 @@
|
||||
Subproject commit be700d4918627e06eb3e8c5f3b025911061badff
|
||||
Subproject commit a7b34d6f831c8fa363f389d27acd0150128fc0b9
|
@ -1,8 +1,15 @@
|
||||
<?php
|
||||
|
||||
use OCA\DAV\Command\CreateAddressBook;
|
||||
use OCA\DAV\Command\CreateCalendar;
|
||||
use OCA\DAV\Command\SyncSystemAddressBook;
|
||||
|
||||
$config = \OC::$server->getConfig();
|
||||
$dbConnection = \OC::$server->getDatabaseConnection();
|
||||
$userManager = OC::$server->getUserManager();
|
||||
$config = \OC::$server->getConfig();
|
||||
|
||||
/** @var Symfony\Component\Console\Application $application */
|
||||
$application->add(new CreateAddressBook($userManager, $dbConnection));
|
||||
$application->add(new CreateAddressBook($userManager, $dbConnection, $config));
|
||||
$application->add(new CreateCalendar($userManager, $dbConnection));
|
||||
$application->add(new SyncSystemAddressBook($userManager, $dbConnection, $config));
|
||||
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace OCA\DAV\Command;
|
||||
|
||||
use OCA\DAV\CalDAV\CalDavBackend;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IUserManager;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class CreateCalendar extends Command {
|
||||
|
||||
/** @var IUserManager */
|
||||
protected $userManager;
|
||||
|
||||
/** @var \OCP\IDBConnection */
|
||||
protected $dbConnection;
|
||||
|
||||
/**
|
||||
* @param IUserManager $userManager
|
||||
* @param IDBConnection $dbConnection
|
||||
*/
|
||||
function __construct(IUserManager $userManager, IDBConnection $dbConnection) {
|
||||
parent::__construct();
|
||||
$this->userManager = $userManager;
|
||||
$this->dbConnection = $dbConnection;
|
||||
}
|
||||
|
||||
protected function configure() {
|
||||
$this
|
||||
->setName('dav:create-calendar')
|
||||
->setDescription('Create a dav calendar')
|
||||
->addArgument('user',
|
||||
InputArgument::REQUIRED,
|
||||
'User for whom the calendar will be created')
|
||||
->addArgument('name',
|
||||
InputArgument::REQUIRED,
|
||||
'Name of the calendar');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$user = $input->getArgument('user');
|
||||
if (!$this->userManager->userExists($user)) {
|
||||
throw new \InvalidArgumentException("User <$user> in unknown.");
|
||||
}
|
||||
$name = $input->getArgument('name');
|
||||
$caldav = new CalDavBackend($this->dbConnection);
|
||||
$caldav->createCalendar("principals/users/$user", $name, []);
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace OCA\DAV\Command;
|
||||
|
||||
use OCA\DAV\CardDAV\CardDavBackend;
|
||||
use OCA\DAV\CardDAV\Converter;
|
||||
use OCA\DAV\Connector\Sabre\Principal;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use Sabre\CardDAV\Plugin;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Property\Text;
|
||||
use Sabre\VObject\Reader;
|
||||
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 SyncSystemAddressBook extends Command {
|
||||
|
||||
/** @var IUserManager */
|
||||
protected $userManager;
|
||||
|
||||
/** @var \OCP\IDBConnection */
|
||||
protected $dbConnection;
|
||||
|
||||
/** @var IConfig */
|
||||
protected $config;
|
||||
|
||||
/** @var CardDavBackend */
|
||||
private $backend;
|
||||
|
||||
/**
|
||||
* @param IUserManager $userManager
|
||||
* @param IDBConnection $dbConnection
|
||||
* @param IConfig $config
|
||||
*/
|
||||
function __construct(IUserManager $userManager, IDBConnection $dbConnection, IConfig $config) {
|
||||
parent::__construct();
|
||||
$this->userManager = $userManager;
|
||||
$this->dbConnection = $dbConnection;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
protected function configure() {
|
||||
$this
|
||||
->setName('dav:sync-system-addressbook')
|
||||
->setDescription('Synchronizes users to the system addressbook');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$principalBackend = new Principal(
|
||||
$this->config,
|
||||
$this->userManager
|
||||
);
|
||||
|
||||
$this->backend = new CardDavBackend($this->dbConnection, $principalBackend);
|
||||
|
||||
// ensure system addressbook exists
|
||||
$systemAddressBook = $this->ensureSystemAddressBookExists();
|
||||
$converter = new Converter();
|
||||
|
||||
$output->writeln('Syncing users ...');
|
||||
$progress = new ProgressBar($output);
|
||||
$progress->start();
|
||||
$this->userManager->callForAllUsers(function($user) use ($systemAddressBook, $converter, $progress) {
|
||||
/** @var IUser $user */
|
||||
$name = $user->getBackendClassName();
|
||||
$userId = $user->getUID();
|
||||
|
||||
$cardId = "$name:$userId.vcf";
|
||||
$card = $this->backend->getCard($systemAddressBook['id'], $cardId);
|
||||
if ($card === false) {
|
||||
$vCard = $converter->createCardFromUser($user);
|
||||
$this->backend->createCard($systemAddressBook['id'], $cardId, $vCard->serialize());
|
||||
} else {
|
||||
$vCard = Reader::read($card['carddata']);
|
||||
if ($converter->updateCard($vCard, $user)) {
|
||||
$this->backend->updateCard($systemAddressBook['id'], $cardId, $vCard->serialize());
|
||||
}
|
||||
}
|
||||
$progress->advance();
|
||||
});
|
||||
$progress->finish();
|
||||
$output->writeln('');
|
||||
}
|
||||
|
||||
protected function ensureSystemAddressBookExists() {
|
||||
$book = $this->backend->getAddressBooksByUri('system');
|
||||
if (!is_null($book)) {
|
||||
return $book;
|
||||
}
|
||||
$systemPrincipal = "principals/system/system";
|
||||
$this->backend->createAddressBook($systemPrincipal, 'system', [
|
||||
'{' . Plugin::NS_CARDDAV . '}addressbook-description' => 'System addressbook which holds all users of this instance'
|
||||
]);
|
||||
|
||||
return $this->backend->getAddressBooksByUri('system');
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace OCA\DAV\CardDAV;
|
||||
|
||||
use OCA\DAV\CardDAV\Sharing\IShareableAddressBook;
|
||||
use Sabre\DAV\Exception\NotFound;
|
||||
|
||||
class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareableAddressBook {
|
||||
|
||||
public function __construct(CardDavBackend $carddavBackend, array $addressBookInfo) {
|
||||
parent::__construct($carddavBackend, $addressBookInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the list of shares.
|
||||
*
|
||||
* The first array is a list of people that are to be added to the
|
||||
* addressbook.
|
||||
*
|
||||
* Every element in the add array has the following properties:
|
||||
* * href - A url. Usually a mailto: address
|
||||
* * commonName - Usually a first and last name, or false
|
||||
* * summary - A description of the share, can also be false
|
||||
* * readOnly - A boolean value
|
||||
*
|
||||
* Every element in the remove array is just the address string.
|
||||
*
|
||||
* @param array $add
|
||||
* @param array $remove
|
||||
* @return void
|
||||
*/
|
||||
function updateShares(array $add, array $remove) {
|
||||
/** @var CardDavBackend $carddavBackend */
|
||||
$carddavBackend = $this->carddavBackend;
|
||||
$carddavBackend->updateShares($this->getName(), $add, $remove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of people whom this addressbook is shared with.
|
||||
*
|
||||
* Every element in this array should have the following properties:
|
||||
* * href - Often a mailto: address
|
||||
* * commonName - Optional, for example a first + last name
|
||||
* * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
|
||||
* * readOnly - boolean
|
||||
* * summary - Optional, a description for the share
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getShares() {
|
||||
/** @var CardDavBackend $carddavBackend */
|
||||
$carddavBackend = $this->carddavBackend;
|
||||
$carddavBackend->getShares($this->getName());
|
||||
}
|
||||
|
||||
function getACL() {
|
||||
$acl = parent::getACL();
|
||||
if ($this->getOwner() === 'principals/system/system') {
|
||||
$acl[] = [
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => '{DAV:}authenticated',
|
||||
'protected' => true,
|
||||
];
|
||||
}
|
||||
|
||||
return $acl;
|
||||
}
|
||||
|
||||
function getChildACL() {
|
||||
$acl = parent::getChildACL();
|
||||
if ($this->getOwner() === 'principals/system/system') {
|
||||
$acl[] = [
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => '{DAV:}authenticated',
|
||||
'protected' => true,
|
||||
];
|
||||
}
|
||||
|
||||
return $acl;
|
||||
}
|
||||
|
||||
function getChild($name) {
|
||||
$obj = $this->carddavBackend->getCard($this->addressBookInfo['id'], $name);
|
||||
if (!$obj) {
|
||||
throw new NotFound('Card not found');
|
||||
}
|
||||
return new Card($this->carddavBackend, $this->addressBookInfo, $obj);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace OCA\DAV\CardDAV;
|
||||
|
||||
class AddressBookRoot extends \Sabre\CardDAV\AddressBookRoot {
|
||||
|
||||
/**
|
||||
* This method returns a node for a principal.
|
||||
*
|
||||
* The passed array contains principal information, and is guaranteed to
|
||||
* at least contain a uri item. Other properties may or may not be
|
||||
* supplied by the authentication backend.
|
||||
*
|
||||
* @param array $principal
|
||||
* @return \Sabre\DAV\INode
|
||||
*/
|
||||
function getChildForPrincipal(array $principal) {
|
||||
|
||||
return new UserAddressBooks($this->carddavBackend, $principal['uri']);
|
||||
|
||||
}
|
||||
|
||||
function getName() {
|
||||
|
||||
// Grabbing all the components of the principal path.
|
||||
$parts = explode('/', $this->principalPrefix);
|
||||
|
||||
// We are only interested in the second part.
|
||||
return $parts[1];
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\CardDAV;
|
||||
|
||||
class Card extends \Sabre\CardDAV\Card {
|
||||
|
||||
function getACL() {
|
||||
$acl = parent::getACL();
|
||||
if ($this->getOwner() === 'principals/system/system') {
|
||||
$acl[] = [
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => '{DAV:}authenticated',
|
||||
'protected' => true,
|
||||
];
|
||||
}
|
||||
|
||||
return $acl;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\CardDAV;
|
||||
|
||||
use OCP\IImage;
|
||||
use OCP\IUser;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Property\Text;
|
||||
|
||||
class Converter {
|
||||
|
||||
/**
|
||||
* @param IUser $user
|
||||
* @return VCard
|
||||
*/
|
||||
public function createCardFromUser(IUser $user) {
|
||||
|
||||
$uid = $user->getUID();
|
||||
$displayName = $user->getDisplayName();
|
||||
$displayName = empty($displayName ) ? $uid : $displayName;
|
||||
$emailAddress = $user->getEMailAddress();
|
||||
$cloudId = $user->getCloudId();
|
||||
$image = $user->getAvatarImage(-1);
|
||||
|
||||
$vCard = new VCard();
|
||||
$vCard->add(new Text($vCard, 'UID', $uid));
|
||||
if (!empty($displayName)) {
|
||||
$vCard->add(new Text($vCard, 'FN', $displayName));
|
||||
$vCard->add(new Text($vCard, 'N', $this->splitFullName($displayName)));
|
||||
}
|
||||
if (!empty($emailAddress)) {
|
||||
$vCard->add(new Text($vCard, 'EMAIL', $emailAddress, ['TYPE' => 'OTHER']));
|
||||
}
|
||||
if (!empty($cloudId)) {
|
||||
$vCard->add(new Text($vCard, 'CLOUD', $cloudId));
|
||||
}
|
||||
if ($image) {
|
||||
$vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType()]);
|
||||
}
|
||||
$vCard->validate();
|
||||
|
||||
return $vCard;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param VCard $vCard
|
||||
* @param IUser $user
|
||||
* @return bool
|
||||
*/
|
||||
public function updateCard(VCard $vCard, IUser $user) {
|
||||
$uid = $user->getUID();
|
||||
$displayName = $user->getDisplayName();
|
||||
$displayName = empty($displayName ) ? $uid : $displayName;
|
||||
$emailAddress = $user->getEMailAddress();
|
||||
$cloudId = $user->getCloudId();
|
||||
$image = $user->getAvatarImage(-1);
|
||||
|
||||
$updated = false;
|
||||
if($this->propertyNeedsUpdate($vCard, 'FN', $displayName)) {
|
||||
$vCard->FN = new Text($vCard, 'FN', $displayName);
|
||||
unset($vCard->N);
|
||||
$vCard->add(new Text($vCard, 'N', $this->splitFullName($displayName)));
|
||||
$updated = true;
|
||||
}
|
||||
if($this->propertyNeedsUpdate($vCard, 'EMAIL', $emailAddress)) {
|
||||
$vCard->EMAIL = new Text($vCard, 'EMAIL', $emailAddress);
|
||||
$updated = true;
|
||||
}
|
||||
if($this->propertyNeedsUpdate($vCard, 'CLOUD', $cloudId)) {
|
||||
$vCard->CLOUD = new Text($vCard, 'CLOUD', $cloudId);
|
||||
$updated = true;
|
||||
}
|
||||
|
||||
if($this->propertyNeedsUpdate($vCard, 'PHOTO', $image)) {
|
||||
$vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType()]);
|
||||
$updated = true;
|
||||
}
|
||||
|
||||
if (empty($emailAddress) && !is_null($vCard->EMAIL)) {
|
||||
unset($vCard->EMAIL);
|
||||
$updated = true;
|
||||
}
|
||||
if (empty($cloudId) && !is_null($vCard->CLOUD)) {
|
||||
unset($vCard->CLOUD);
|
||||
$updated = true;
|
||||
}
|
||||
if (empty($image) && !is_null($vCard->PHOTO)) {
|
||||
unset($vCard->PHOTO);
|
||||
$updated = true;
|
||||
}
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param VCard $vCard
|
||||
* @param string $name
|
||||
* @param string|IImage $newValue
|
||||
* @return bool
|
||||
*/
|
||||
private function propertyNeedsUpdate(VCard $vCard, $name, $newValue) {
|
||||
if (is_null($newValue)) {
|
||||
return false;
|
||||
}
|
||||
$value = $vCard->__get($name);
|
||||
if (!is_null($value)) {
|
||||
$value = $value->getValue();
|
||||
$newValue = $newValue instanceof IImage ? $newValue->data() : $newValue;
|
||||
|
||||
return $value !== $newValue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fullName
|
||||
* @return string[]
|
||||
*/
|
||||
public function splitFullName($fullName) {
|
||||
// Very basic western style parsing. I'm not gonna implement
|
||||
// https://github.com/android/platform_packages_providers_contactsprovider/blob/master/src/com/android/providers/contacts/NameSplitter.java ;)
|
||||
|
||||
$elements = explode(' ', $fullName);
|
||||
$result = ['', '', '', '', ''];
|
||||
if (count($elements) > 2) {
|
||||
$result[0] = implode(' ', array_slice($elements, count($elements)-1));
|
||||
$result[1] = $elements[0];
|
||||
$result[2] = implode(' ', array_slice($elements, 1, count($elements)-2));
|
||||
} elseif (count($elements) === 2) {
|
||||
$result[0] = $elements[1];
|
||||
$result[1] = $elements[0];
|
||||
} else {
|
||||
$result[0] = $elements[0];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\CardDAV;
|
||||
|
||||
use Sabre\HTTP\URLUtil;
|
||||
|
||||
class Plugin extends \Sabre\CardDAV\Plugin {
|
||||
|
||||
/**
|
||||
* Returns the addressbook home for a given principal
|
||||
*
|
||||
* @param string $principal
|
||||
* @return string
|
||||
*/
|
||||
protected function getAddressbookHomeForPrincipal($principal) {
|
||||
|
||||
if (strrpos($principal, 'principals/users', -strlen($principal)) !== FALSE) {
|
||||
list(, $principalId) = URLUtil::splitPath($principal);
|
||||
return self::ADDRESSBOOK_ROOT . '/users/' . $principalId;
|
||||
}
|
||||
if (strrpos($principal, 'principals/system', -strlen($principal)) !== FALSE) {
|
||||
list(, $principalId) = URLUtil::splitPath($principal);
|
||||
return self::ADDRESSBOOK_ROOT . '/system/' . $principalId;
|
||||
}
|
||||
|
||||
throw new \LogicException('This is not supposed to happen');
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace OCA\DAV\CardDAV\Sharing;
|
||||
use Sabre\CardDAV\IAddressBook;
|
||||
|
||||
/**
|
||||
* This interface represents a Calendar that can be shared with other users.
|
||||
*
|
||||
*/
|
||||
interface IShareableAddressBook extends IAddressBook {
|
||||
|
||||
/**
|
||||
* Updates the list of shares.
|
||||
*
|
||||
* The first array is a list of people that are to be added to the
|
||||
* addressbook.
|
||||
*
|
||||
* Every element in the add array has the following properties:
|
||||
* * href - A url. Usually a mailto: address
|
||||
* * commonName - Usually a first and last name, or false
|
||||
* * summary - A description of the share, can also be false
|
||||
* * readOnly - A boolean value
|
||||
*
|
||||
* Every element in the remove array is just the address string.
|
||||
*
|
||||
* @param array $add
|
||||
* @param array $remove
|
||||
* @return void
|
||||
*/
|
||||
function updateShares(array $add, array $remove);
|
||||
|
||||
/**
|
||||
* Returns the list of people whom this addressbook is shared with.
|
||||
*
|
||||
* Every element in this array should have the following properties:
|
||||
* * href - Often a mailto: address
|
||||
* * commonName - Optional, for example a first + last name
|
||||
* * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
|
||||
* * readOnly - boolean
|
||||
* * summary - Optional, a description for the share
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getShares();
|
||||
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
namespace OCA\DAV\CardDAV\Sharing;
|
||||
|
||||
use OCA\DAV\Connector\Sabre\Auth;
|
||||
use OCP\IRequest;
|
||||
use Sabre\DAV\Exception\BadRequest;
|
||||
use Sabre\DAV\Exception\NotFound;
|
||||
use Sabre\DAV\Server;
|
||||
use Sabre\DAV\ServerPlugin;
|
||||
use Sabre\DAV\XMLUtil;
|
||||
use Sabre\HTTP\RequestInterface;
|
||||
use Sabre\HTTP\ResponseInterface;
|
||||
|
||||
class Plugin extends ServerPlugin {
|
||||
|
||||
public function __construct(Auth $authBackEnd, IRequest $request) {
|
||||
$this->auth = $authBackEnd;
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference to SabreDAV server object.
|
||||
*
|
||||
* @var \Sabre\DAV\Server
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* This method should return a list of server-features.
|
||||
*
|
||||
* This is for example 'versioning' and is added to the DAV: header
|
||||
* in an OPTIONS response.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
function getFeatures() {
|
||||
|
||||
return ['oc-addressbook-sharing'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a plugin name.
|
||||
*
|
||||
* Using this name other plugins will be able to access other plugins
|
||||
* using Sabre\DAV\Server::getPlugin
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getPluginName() {
|
||||
|
||||
return 'carddav-sharing';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This initializes the plugin.
|
||||
*
|
||||
* This function is called by Sabre\DAV\Server, after
|
||||
* addPlugin is called.
|
||||
*
|
||||
* This method should set up the required event subscriptions.
|
||||
*
|
||||
* @param Server $server
|
||||
* @return void
|
||||
*/
|
||||
function initialize(Server $server) {
|
||||
$this->server = $server;
|
||||
$server->resourceTypeMapping['OCA\\DAV\CardDAV\\ISharedAddressbook'] = '{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}shared';
|
||||
|
||||
$this->server->on('method:POST', [$this, 'httpPost']);
|
||||
}
|
||||
|
||||
/**
|
||||
* We intercept this to handle POST requests on calendars.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return null|false
|
||||
*/
|
||||
function httpPost(RequestInterface $request, ResponseInterface $response) {
|
||||
|
||||
$path = $request->getPath();
|
||||
|
||||
// Only handling xml
|
||||
$contentType = $request->getHeader('Content-Type');
|
||||
if (strpos($contentType, 'application/xml') === false && strpos($contentType, 'text/xml') === false)
|
||||
return;
|
||||
|
||||
// Making sure the node exists
|
||||
try {
|
||||
$node = $this->server->tree->getNodeForPath($path);
|
||||
} catch (NotFound $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF protection
|
||||
$this->protectAgainstCSRF();
|
||||
|
||||
$requestBody = $request->getBodyAsString();
|
||||
|
||||
// If this request handler could not deal with this POST request, it
|
||||
// will return 'null' and other plugins get a chance to handle the
|
||||
// request.
|
||||
//
|
||||
// However, we already requested the full body. This is a problem,
|
||||
// because a body can only be read once. This is why we preemptively
|
||||
// re-populated the request body with the existing data.
|
||||
$request->setBody($requestBody);
|
||||
|
||||
$dom = XMLUtil::loadDOMDocument($requestBody);
|
||||
|
||||
$documentType = XMLUtil::toClarkNotation($dom->firstChild);
|
||||
|
||||
switch ($documentType) {
|
||||
|
||||
// Dealing with the 'share' document, which modified invitees on a
|
||||
// calendar.
|
||||
case '{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}share' :
|
||||
|
||||
// We can only deal with IShareableCalendar objects
|
||||
if (!$node instanceof IShareableAddressBook) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->server->transactionType = 'post-calendar-share';
|
||||
|
||||
// Getting ACL info
|
||||
$acl = $this->server->getPlugin('acl');
|
||||
|
||||
// If there's no ACL support, we allow everything
|
||||
if ($acl) {
|
||||
$acl->checkPrivileges($path, '{DAV:}write');
|
||||
}
|
||||
|
||||
$mutations = $this->parseShareRequest($dom);
|
||||
|
||||
$node->updateShares($mutations[0], $mutations[1]);
|
||||
|
||||
$response->setStatus(200);
|
||||
// Adding this because sending a response body may cause issues,
|
||||
// and I wanted some type of indicator the response was handled.
|
||||
$response->setHeader('X-Sabre-Status', 'everything-went-well');
|
||||
|
||||
// Breaking the event chain
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the 'share' POST request.
|
||||
*
|
||||
* This method returns an array, containing two arrays.
|
||||
* The first array is a list of new sharees. Every element is a struct
|
||||
* containing a:
|
||||
* * href element. (usually a mailto: address)
|
||||
* * commonName element (often a first and lastname, but can also be
|
||||
* false)
|
||||
* * readOnly (true or false)
|
||||
* * summary (A description of the share, can also be false)
|
||||
*
|
||||
* The second array is a list of sharees that are to be removed. This is
|
||||
* just a simple array with 'hrefs'.
|
||||
*
|
||||
* @param \DOMDocument $dom
|
||||
* @return array
|
||||
*/
|
||||
function parseShareRequest(\DOMDocument $dom) {
|
||||
|
||||
$xpath = new \DOMXPath($dom);
|
||||
$xpath->registerNamespace('cs', \Sabre\CardDAV\Plugin::NS_CARDDAV);
|
||||
$xpath->registerNamespace('d', 'urn:DAV');
|
||||
|
||||
$set = [];
|
||||
$elems = $xpath->query('cs:set');
|
||||
|
||||
for ($i = 0; $i < $elems->length; $i++) {
|
||||
|
||||
$xset = $elems->item($i);
|
||||
$set[] = [
|
||||
'href' => $xpath->evaluate('string(d:href)', $xset),
|
||||
'commonName' => $xpath->evaluate('string(cs:common-name)', $xset),
|
||||
'summary' => $xpath->evaluate('string(cs:summary)', $xset),
|
||||
'readOnly' => $xpath->evaluate('boolean(cs:read)', $xset) !== false
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
$remove = [];
|
||||
$elems = $xpath->query('cs:remove');
|
||||
|
||||
for ($i = 0; $i < $elems->length; $i++) {
|
||||
|
||||
$xremove = $elems->item($i);
|
||||
$remove[] = $xpath->evaluate('string(d:href)', $xremove);
|
||||
|
||||
}
|
||||
|
||||
return [$set, $remove];
|
||||
|
||||
}
|
||||
|
||||
private function protectAgainstCSRF() {
|
||||
$user = $this->auth->getCurrentUser();
|
||||
if ($this->auth->isDavAuthenticated($user)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->request->passesCSRFCheck()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace OCA\DAV\CardDAV;
|
||||
|
||||
class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome {
|
||||
|
||||
/**
|
||||
* Returns a list of addressbooks
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getChildren() {
|
||||
|
||||
$addressBooks = $this->carddavBackend->getAddressBooksForUser($this->principalUri);
|
||||
$objects = [];
|
||||
foreach($addressBooks as $addressBook) {
|
||||
$objects[] = new AddressBook($this->carddavBackend, $addressBook);
|
||||
}
|
||||
return $objects;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of ACE's for this node.
|
||||
*
|
||||
* Each ACE has the following properties:
|
||||
* * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
|
||||
* currently the only supported privileges
|
||||
* * 'principal', a url to the principal who owns the node
|
||||
* * 'protected' (optional), indicating that this ACE is not allowed to
|
||||
* be updated.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getACL() {
|
||||
|
||||
$acl = parent::getACL();
|
||||
if ($this->principalUri === 'principals/system/system') {
|
||||
$acl[] = [
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => '{DAV:}authenticated',
|
||||
'protected' => true,
|
||||
];
|
||||
}
|
||||
|
||||
return $acl;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Joas Schilling <nickvergessen@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Connector\Sabre\Exception;
|
||||
|
||||
class Forbidden extends \Sabre\DAV\Exception\Forbidden {
|
||||
|
||||
const NS_OWNCLOUD = 'http://owncloud.org/ns';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $retry;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param bool $retry
|
||||
* @param \Exception $previous
|
||||
*/
|
||||
public function __construct($message, $retry = false, \Exception $previous = null) {
|
||||
parent::__construct($message, 0, $previous);
|
||||
$this->retry = $retry;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows the exception to include additional information
|
||||
* into the WebDAV error response
|
||||
*
|
||||
* @param \Sabre\DAV\Server $server
|
||||
* @param \DOMElement $errorNode
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(\Sabre\DAV\Server $server,\DOMElement $errorNode) {
|
||||
|
||||
// set ownCloud namespace
|
||||
$errorNode->setAttribute('xmlns:o', self::NS_OWNCLOUD);
|
||||
|
||||
// adding the retry node
|
||||
$error = $errorNode->ownerDocument->createElementNS('o:','o:retry', var_export($this->retry, true));
|
||||
$errorNode->appendChild($error);
|
||||
|
||||
// adding the message node
|
||||
$error = $errorNode->ownerDocument->createElementNS('o:','o:reason', $this->getMessage());
|
||||
$errorNode->appendChild($error);
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Lukas Reschke <lukas@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Connector\Sabre;
|
||||
|
||||
use Sabre\DAV\Locks\LockInfo;
|
||||
use Sabre\DAV\ServerPlugin;
|
||||
use Sabre\DAV\Xml\Property\LockDiscovery;
|
||||
use Sabre\DAV\Xml\Property\SupportedLock;
|
||||
use Sabre\HTTP\RequestInterface;
|
||||
use Sabre\HTTP\ResponseInterface;
|
||||
use Sabre\DAV\PropFind;
|
||||
use Sabre\DAV\INode;
|
||||
|
||||
/**
|
||||
* Class FakeLockerPlugin is a plugin only used when connections come in from
|
||||
* OS X via Finder. The fake locking plugin does emulate Class 2 WebDAV support
|
||||
* (locking of files) which allows Finder to access the storage in write mode as
|
||||
* well.
|
||||
*
|
||||
* No real locking is performed, instead the plugin just returns always positive
|
||||
* responses.
|
||||
*
|
||||
* @see https://github.com/owncloud/core/issues/17732
|
||||
* @package OCA\DAV\Connector\Sabre
|
||||
*/
|
||||
class FakeLockerPlugin extends ServerPlugin {
|
||||
/** @var \Sabre\DAV\Server */
|
||||
private $server;
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function initialize(\Sabre\DAV\Server $server) {
|
||||
$this->server = $server;
|
||||
$this->server->on('method:LOCK', [$this, 'fakeLockProvider'], 1);
|
||||
$this->server->on('method:UNLOCK', [$this, 'fakeUnlockProvider'], 1);
|
||||
$server->on('propFind', [$this, 'propFind']);
|
||||
$server->on('validateTokens', [$this, 'validateTokens']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that we support LOCK and UNLOCK
|
||||
*
|
||||
* @param string $path
|
||||
* @return string[]
|
||||
*/
|
||||
public function getHTTPMethods($path) {
|
||||
return [
|
||||
'LOCK',
|
||||
'UNLOCK',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that we support locking
|
||||
*
|
||||
* @return integer[]
|
||||
*/
|
||||
function getFeatures() {
|
||||
return [2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return some dummy response for PROPFIND requests with regard to locking
|
||||
*
|
||||
* @param PropFind $propFind
|
||||
* @param INode $node
|
||||
* @return void
|
||||
*/
|
||||
function propFind(PropFind $propFind, INode $node) {
|
||||
$propFind->handle('{DAV:}supportedlock', function() {
|
||||
return new SupportedLock(true);
|
||||
});
|
||||
$propFind->handle('{DAV:}lockdiscovery', function() use ($propFind) {
|
||||
return new LockDiscovery([]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a locking token always as valid
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param array $conditions
|
||||
*/
|
||||
public function validateTokens(RequestInterface $request, &$conditions) {
|
||||
foreach($conditions as &$fileCondition) {
|
||||
if(isset($fileCondition['tokens'])) {
|
||||
foreach($fileCondition['tokens'] as &$token) {
|
||||
if(isset($token['token'])) {
|
||||
if(substr($token['token'], 0, 16) === 'opaquelocktoken:') {
|
||||
$token['validToken'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fakes a successful LOCK
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return bool
|
||||
*/
|
||||
public function fakeLockProvider(RequestInterface $request,
|
||||
ResponseInterface $response) {
|
||||
|
||||
$lockInfo = new LockInfo();
|
||||
$lockInfo->token = md5($request->getPath());
|
||||
$lockInfo->uri = $request->getPath();
|
||||
$lockInfo->depth = \Sabre\DAV\Server::DEPTH_INFINITY;
|
||||
$lockInfo->timeout = 1800;
|
||||
|
||||
$body = $this->server->xml->write('{DAV:}prop', [
|
||||
'{DAV:}lockdiscovery' =>
|
||||
new LockDiscovery([$lockInfo])
|
||||
]);
|
||||
|
||||
$response->setBody($body);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fakes a successful LOCK
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return bool
|
||||
*/
|
||||
public function fakeUnlockProvider(RequestInterface $request,
|
||||
ResponseInterface $response) {
|
||||
$response->setStatus(204);
|
||||
$response->setHeader('Content-Length', '0');
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\DAV;
|
||||
|
||||
use Sabre\DAVACL\PrincipalBackend\AbstractBackend;
|
||||
use Sabre\HTTP\URLUtil;
|
||||
|
||||
class SystemPrincipalBackend extends AbstractBackend {
|
||||
|
||||
/**
|
||||
* Returns a list of principals based on a prefix.
|
||||
*
|
||||
* This prefix will often contain something like 'principals'. You are only
|
||||
* expected to return principals that are in this base path.
|
||||
*
|
||||
* You are expected to return at least a 'uri' for every user, you can
|
||||
* return any additional properties if you wish so. Common properties are:
|
||||
* {DAV:}displayname
|
||||
* {http://sabredav.org/ns}email-address - This is a custom SabreDAV
|
||||
* field that's actually injected in a number of other properties. If
|
||||
* you have an email address, use this property.
|
||||
*
|
||||
* @param string $prefixPath
|
||||
* @return array
|
||||
*/
|
||||
function getPrincipalsByPrefix($prefixPath) {
|
||||
$principals = [];
|
||||
|
||||
if ($prefixPath === 'principals/system') {
|
||||
$principals[] = [
|
||||
'uri' => 'principals/system/system',
|
||||
'{DAV:}displayname' => 'system',
|
||||
];
|
||||
}
|
||||
|
||||
return $principals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific principal, specified by it's path.
|
||||
* The returned structure should be the exact same as from
|
||||
* getPrincipalsByPrefix.
|
||||
*
|
||||
* @param string $path
|
||||
* @return array
|
||||
*/
|
||||
function getPrincipalByPath($path) {
|
||||
|
||||
$elements = explode('/', $path);
|
||||
if ($elements[0] !== 'principals') {
|
||||
return null;
|
||||
}
|
||||
if ($elements[1] === 'system') {
|
||||
$principal = [
|
||||
'uri' => 'principals/system/system',
|
||||
'{DAV:}displayname' => 'system',
|
||||
];
|
||||
return $principal;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates one ore more webdav properties on a principal.
|
||||
*
|
||||
* The list of mutations is stored in a Sabre\DAV\PropPatch object.
|
||||
* To do the actual updates, you must tell this object which properties
|
||||
* you're going to process with the handle() method.
|
||||
*
|
||||
* Calling the handle method is like telling the PropPatch object "I
|
||||
* promise I can handle updating this property".
|
||||
*
|
||||
* Read the PropPatch documentation for more info and examples.
|
||||
*
|
||||
* @param string $path
|
||||
* @param \Sabre\DAV\PropPatch $propPatch
|
||||
* @return void
|
||||
*/
|
||||
function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to search for principals matching a set of
|
||||
* properties.
|
||||
*
|
||||
* This search is specifically used by RFC3744's principal-property-search
|
||||
* REPORT.
|
||||
*
|
||||
* The actual search should be a unicode-non-case-sensitive search. The
|
||||
* keys in searchProperties are the WebDAV property names, while the values
|
||||
* are the property values to search on.
|
||||
*
|
||||
* By default, if multiple properties are submitted to this method, the
|
||||
* various properties should be combined with 'AND'. If $test is set to
|
||||
* 'anyof', it should be combined using 'OR'.
|
||||
*
|
||||
* This method should simply return an array with full principal uri's.
|
||||
*
|
||||
* If somebody attempted to search on a property the backend does not
|
||||
* support, you should simply return 0 results.
|
||||
*
|
||||
* You can also just return 0 results if you choose to not support
|
||||
* searching at all, but keep in mind that this may stop certain features
|
||||
* from working.
|
||||
*
|
||||
* @param string $prefixPath
|
||||
* @param array $searchProperties
|
||||
* @param string $test
|
||||
* @return array
|
||||
*/
|
||||
function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of members for a group-principal
|
||||
*
|
||||
* @param string $principal
|
||||
* @return array
|
||||
*/
|
||||
function getGroupMemberSet($principal) {
|
||||
// TODO: for now the group principal has only one member, the user itself
|
||||
$principal = $this->getPrincipalByPath($principal);
|
||||
if (!$principal) {
|
||||
throw new \Sabre\DAV\Exception('Principal not found');
|
||||
}
|
||||
|
||||
return [$principal['uri']];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of groups a principal is a member of
|
||||
*
|
||||
* @param string $principal
|
||||
* @return array
|
||||
*/
|
||||
function getGroupMembership($principal) {
|
||||
list($prefix, $name) = URLUtil::splitPath($principal);
|
||||
|
||||
if ($prefix === 'principals/system') {
|
||||
$principal = $this->getPrincipalByPath($principal);
|
||||
if (!$principal) {
|
||||
throw new \Sabre\DAV\Exception('Principal not found');
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the list of group members for a group principal.
|
||||
*
|
||||
* The principals should be passed as a list of uri's.
|
||||
*
|
||||
* @param string $principal
|
||||
* @param array $members
|
||||
* @return void
|
||||
*/
|
||||
function setGroupMemberSet($principal, array $members) {
|
||||
throw new \Sabre\DAV\Exception('Setting members of the group is not supported yet');
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<CS:share xmlns:D="DAV:" xmlns:CS="urn:ietf:params:xml:ns:carddav">
|
||||
<CS:set>
|
||||
<D:href>principal:principals/admin</D:href>
|
||||
<CS:read-write />
|
||||
</CS:set>
|
||||
</CS:share>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,348 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Lukas Reschke <lukas@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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 Tests\Connector\Sabre;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use OCA\DAV\CalDAV\CalDavBackend;
|
||||
use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
|
||||
use Sabre\DAV\PropPatch;
|
||||
use Sabre\DAV\Xml\Property\Href;
|
||||
use Test\TestCase;
|
||||
|
||||
/**
|
||||
* Class CalDavBackendTest
|
||||
*
|
||||
* @group DB
|
||||
*
|
||||
* @package Tests\Connector\Sabre
|
||||
*/
|
||||
class CalDavBackendTest extends TestCase {
|
||||
|
||||
/** @var CalDavBackend */
|
||||
private $backend;
|
||||
|
||||
const UNIT_TEST_USER = 'caldav-unit-test';
|
||||
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$db = \OC::$server->getDatabaseConnection();
|
||||
$this->backend = new CalDavBackend($db);
|
||||
|
||||
$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']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCalendarOperations() {
|
||||
|
||||
$calendarId = $this->createTestCalendar();
|
||||
|
||||
// update it's display name
|
||||
$patch = new PropPatch([
|
||||
'{DAV:}displayname' => 'Unit test',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar used for unit testing'
|
||||
]);
|
||||
$this->backend->updateCalendar($calendarId, $patch);
|
||||
$patch->commit();
|
||||
$books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
|
||||
$this->assertEquals(1, count($books));
|
||||
$this->assertEquals('Unit test', $books[0]['{DAV:}displayname']);
|
||||
$this->assertEquals('Calendar used for unit testing', $books[0]['{urn:ietf:params:xml:ns:caldav}calendar-description']);
|
||||
|
||||
// delete the address book
|
||||
$this->backend->deleteCalendar($books[0]['id']);
|
||||
$books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER);
|
||||
$this->assertEquals(0, count($books));
|
||||
}
|
||||
|
||||
public function testCalendarObjectsOperations() {
|
||||
|
||||
$calendarId = $this->createTestCalendar();
|
||||
|
||||
// create a card
|
||||
$uri = $this->getUniqueID('calobj');
|
||||
$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:20130912T130000Z
|
||||
DTEND;VALUE=DATE-TIME:20130912T140000Z
|
||||
CLASS:PUBLIC
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
EOD;
|
||||
|
||||
$this->backend->createCalendarObject($calendarId, $uri, $calData);
|
||||
|
||||
// get all the cards
|
||||
$calendarObjects = $this->backend->getCalendarObjects($calendarId);
|
||||
$this->assertEquals(1, count($calendarObjects));
|
||||
$this->assertEquals($calendarId, $calendarObjects[0]['calendarid']);
|
||||
|
||||
// get the cards
|
||||
$calendarObject = $this->backend->getCalendarObject($calendarId, $uri);
|
||||
$this->assertNotNull($calendarObject);
|
||||
$this->assertArrayHasKey('id', $calendarObject);
|
||||
$this->assertArrayHasKey('uri', $calendarObject);
|
||||
$this->assertArrayHasKey('lastmodified', $calendarObject);
|
||||
$this->assertArrayHasKey('etag', $calendarObject);
|
||||
$this->assertArrayHasKey('size', $calendarObject);
|
||||
$this->assertEquals($calData, $calendarObject['calendardata']);
|
||||
|
||||
// update the card
|
||||
$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:20130912T130000Z
|
||||
DTEND;VALUE=DATE-TIME:20130912T140000Z
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
EOD;
|
||||
$this->backend->updateCalendarObject($calendarId, $uri, $calData);
|
||||
$calendarObject = $this->backend->getCalendarObject($calendarId, $uri);
|
||||
$this->assertEquals($calData, $calendarObject['calendardata']);
|
||||
|
||||
// delete the card
|
||||
$this->backend->deleteCalendarObject($calendarId, $uri);
|
||||
$calendarObjects = $this->backend->getCalendarObjects($calendarId);
|
||||
$this->assertEquals(0, count($calendarObjects));
|
||||
}
|
||||
|
||||
public function testMultiCalendarObjects() {
|
||||
|
||||
$calendarId = $this->createTestCalendar();
|
||||
|
||||
// create an event
|
||||
$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:20130912T130000Z
|
||||
DTEND;VALUE=DATE-TIME:20130912T140000Z
|
||||
CLASS:PUBLIC
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
EOD;
|
||||
$uri0 = $this->getUniqueID('card');
|
||||
$this->backend->createCalendarObject($calendarId, $uri0, $calData);
|
||||
$uri1 = $this->getUniqueID('card');
|
||||
$this->backend->createCalendarObject($calendarId, $uri1, $calData);
|
||||
$uri2 = $this->getUniqueID('card');
|
||||
$this->backend->createCalendarObject($calendarId, $uri2, $calData);
|
||||
|
||||
// get all the cards
|
||||
$calendarObjects = $this->backend->getCalendarObjects($calendarId);
|
||||
$this->assertEquals(3, count($calendarObjects));
|
||||
|
||||
// get the cards
|
||||
$calendarObjects = $this->backend->getMultipleCalendarObjects($calendarId, [$uri1, $uri2]);
|
||||
$this->assertEquals(2, count($calendarObjects));
|
||||
foreach($calendarObjects as $card) {
|
||||
$this->assertArrayHasKey('id', $card);
|
||||
$this->assertArrayHasKey('uri', $card);
|
||||
$this->assertArrayHasKey('lastmodified', $card);
|
||||
$this->assertArrayHasKey('etag', $card);
|
||||
$this->assertArrayHasKey('size', $card);
|
||||
$this->assertEquals($calData, $card['calendardata']);
|
||||
}
|
||||
|
||||
// delete the card
|
||||
$this->backend->deleteCalendarObject($calendarId, $uri0);
|
||||
$this->backend->deleteCalendarObject($calendarId, $uri1);
|
||||
$this->backend->deleteCalendarObject($calendarId, $uri2);
|
||||
$calendarObjects = $this->backend->getCalendarObjects($calendarId);
|
||||
$this->assertEquals(0, count($calendarObjects));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providesCalendarQueryParameters
|
||||
*/
|
||||
public function testCalendarQuery($expectedEventsInResult, $propFilters, $compFilter) {
|
||||
$calendarId = $this->createTestCalendar();
|
||||
$events = [];
|
||||
$events[0] = $this->createEvent($calendarId, '20130912T130000Z', '20130912T140000Z');
|
||||
$events[1] = $this->createEvent($calendarId, '20130912T150000Z', '20130912T170000Z');
|
||||
$events[2] = $this->createEvent($calendarId, '20130912T173000Z', '20130912T220000Z');
|
||||
|
||||
$result = $this->backend->calendarQuery($calendarId, [
|
||||
'name' => '',
|
||||
'prop-filters' => $propFilters,
|
||||
'comp-filters' => $compFilter
|
||||
]);
|
||||
|
||||
$expectedEventsInResult = array_map(function($index) use($events) {
|
||||
return $events[$index];
|
||||
}, $expectedEventsInResult);
|
||||
$this->assertEquals($expectedEventsInResult, $result, '', 0.0, 10, true);
|
||||
}
|
||||
|
||||
public function testGetCalendarObjectByUID() {
|
||||
$calendarId = $this->createTestCalendar();
|
||||
$this->createEvent($calendarId, '20130912T130000Z', '20130912T140000Z');
|
||||
|
||||
$co = $this->backend->getCalendarObjectByUID(self::UNIT_TEST_USER, '47d15e3ec8');
|
||||
$this->assertNotNull($co);
|
||||
}
|
||||
|
||||
public function providesCalendarQueryParameters() {
|
||||
return [
|
||||
'all' => [[0, 1, 2], [], []],
|
||||
'only-todos' => [[], ['name' => 'VTODO'], []],
|
||||
'only-events' => [[0, 1, 2], [], [['name' => 'VEVENT', 'is-not-defined' => false, 'comp-filters' => [], 'time-range' => ['start' => null, 'end' => null], 'prop-filters' => []]],],
|
||||
'start' => [[1, 2], [], [['name' => 'VEVENT', 'is-not-defined' => false, 'comp-filters' => [], 'time-range' => ['start' => new DateTime('2013-09-12 14:00:00', new DateTimeZone('UTC')), 'end' => null], 'prop-filters' => []]],],
|
||||
'end' => [[0], [], [['name' => 'VEVENT', 'is-not-defined' => false, 'comp-filters' => [], 'time-range' => ['start' => null, 'end' => new DateTime('2013-09-12 14:00:00', new DateTimeZone('UTC'))], 'prop-filters' => []]],],
|
||||
];
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// fist call without synctoken
|
||||
$changes = $this->backend->getChangesForCalendar($calendarId, '', 1);
|
||||
$syncToken = $changes['syncToken'];
|
||||
|
||||
// add a change
|
||||
$event = $this->createEvent($calendarId, '20130912T130000Z', '20130912T140000Z');
|
||||
|
||||
// look for changes
|
||||
$changes = $this->backend->getChangesForCalendar($calendarId, $syncToken, 1);
|
||||
$this->assertEquals($event, $changes['added'][0]);
|
||||
}
|
||||
|
||||
public function testSubscriptions() {
|
||||
$id = $this->backend->createSubscription(self::UNIT_TEST_USER, 'Subscription', [
|
||||
'{http://calendarserver.org/ns/}source' => new Href('test-source')
|
||||
]);
|
||||
|
||||
$subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER);
|
||||
$this->assertEquals(1, count($subscriptions));
|
||||
$this->assertEquals($id, $subscriptions[0]['id']);
|
||||
|
||||
$patch = new PropPatch([
|
||||
'{DAV:}displayname' => 'Unit test',
|
||||
]);
|
||||
$this->backend->updateSubscription($id, $patch);
|
||||
$patch->commit();
|
||||
|
||||
$subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER);
|
||||
$this->assertEquals(1, count($subscriptions));
|
||||
$this->assertEquals($id, $subscriptions[0]['id']);
|
||||
$this->assertEquals('Unit test', $subscriptions[0]['{DAV:}displayname']);
|
||||
|
||||
$this->backend->deleteSubscription($id);
|
||||
$subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER);
|
||||
$this->assertEquals(0, count($subscriptions));
|
||||
}
|
||||
|
||||
public function testScheduling() {
|
||||
$this->backend->createSchedulingObject(self::UNIT_TEST_USER, 'Sample Schedule', '');
|
||||
|
||||
$sos = $this->backend->getSchedulingObjects(self::UNIT_TEST_USER);
|
||||
$this->assertEquals(1, count($sos));
|
||||
|
||||
$so = $this->backend->getSchedulingObject(self::UNIT_TEST_USER, 'Sample Schedule');
|
||||
$this->assertNotNull($so);
|
||||
|
||||
$this->backend->deleteSchedulingObject(self::UNIT_TEST_USER, 'Sample Schedule');
|
||||
|
||||
$sos = $this->backend->getSchedulingObjects(self::UNIT_TEST_USER);
|
||||
$this->assertEquals(0, count($sos));
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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;
|
||||
|
||||
use OCA\DAV\CardDAV\Converter;
|
||||
use Test\TestCase;
|
||||
|
||||
class ConverterTests extends TestCase {
|
||||
|
||||
/**
|
||||
* @dataProvider providesNewUsers
|
||||
*/
|
||||
public function testCreation($expectedVCard, $displayName = null, $eMailAddress = null, $cloudId = null) {
|
||||
$user = $this->getUserMock($displayName, $eMailAddress, $cloudId);
|
||||
|
||||
$converter = new Converter();
|
||||
$vCard = $converter->createCardFromUser($user);
|
||||
$cardData = $vCard->serialize();
|
||||
|
||||
$this->assertEquals($expectedVCard, $cardData);
|
||||
}
|
||||
|
||||
public function providesNewUsers() {
|
||||
return [
|
||||
["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.4.7//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nPHOTO;ENCODING=b;TYPE=JPEG:MTIzNDU2Nzg5\r\nEND:VCARD\r\n"],
|
||||
["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.4.7//EN\r\nUID:12345\r\nFN:Dr. Foo Bar\r\nN:Bar;Dr.;Foo;;\r\nPHOTO;ENCODING=b;TYPE=JPEG:MTIzNDU2Nzg5\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
|
||||
["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.4.7//EN\r\nUID:12345\r\nFN:Dr. Foo Bar\r\nN:Bar;Dr.;Foo;;\r\nEMAIL;TYPE=OTHER:foo@bar.net\r\nPHOTO;ENCODING=b;TYPE=JPEG:MTIzNDU2Nzg5\r\nEND:VCARD\r\n", "Dr. Foo Bar", "foo@bar.net"],
|
||||
["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.4.7//EN\r\nUID:12345\r\nFN:Dr. Foo Bar\r\nN:Bar;Dr.;Foo;;\r\nCLOUD:foo@bar.net\r\nPHOTO;ENCODING=b;TYPE=JPEG:MTIzNDU2Nzg5\r\nEND:VCARD\r\n", "Dr. Foo Bar", null, "foo@bar.net"],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providesNewUsers
|
||||
*/
|
||||
public function testUpdateOfUnchangedUser($expectedVCard, $displayName = null, $eMailAddress = null, $cloudId = null) {
|
||||
$user = $this->getUserMock($displayName, $eMailAddress, $cloudId);
|
||||
|
||||
$converter = new Converter();
|
||||
$vCard = $converter->createCardFromUser($user);
|
||||
$updated = $converter->updateCard($vCard, $user);
|
||||
$this->assertFalse($updated);
|
||||
$cardData = $vCard->serialize();
|
||||
|
||||
$this->assertEquals($expectedVCard, $cardData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providesUsersForUpdateOfRemovedElement
|
||||
*/
|
||||
public function testUpdateOfRemovedElement($expectedVCard, $displayName = null, $eMailAddress = null, $cloudId = null) {
|
||||
$user = $this->getUserMock($displayName, $eMailAddress, $cloudId);
|
||||
|
||||
$converter = new Converter();
|
||||
$vCard = $converter->createCardFromUser($user);
|
||||
|
||||
$user1 = $this->getMockBuilder('OCP\IUser')->disableOriginalConstructor()->getMock();
|
||||
$user1->method('getUID')->willReturn('12345');
|
||||
$user1->method('getDisplayName')->willReturn(null);
|
||||
$user1->method('getEMailAddress')->willReturn(null);
|
||||
$user1->method('getCloudId')->willReturn(null);
|
||||
$user1->method('getAvatarImage')->willReturn(null);
|
||||
|
||||
$updated = $converter->updateCard($vCard, $user1);
|
||||
$this->assertTrue($updated);
|
||||
$cardData = $vCard->serialize();
|
||||
|
||||
$this->assertEquals($expectedVCard, $cardData);
|
||||
}
|
||||
|
||||
public function providesUsersForUpdateOfRemovedElement() {
|
||||
return [
|
||||
["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.4.7//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
|
||||
["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.4.7//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nEND:VCARD\r\n", "Dr. Foo Bar", "foo@bar.net"],
|
||||
["BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.4.7//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nEND:VCARD\r\n", "Dr. Foo Bar", null, "foo@bar.net"],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providesNames
|
||||
* @param $expected
|
||||
* @param $fullName
|
||||
*/
|
||||
public function testNameSplitter($expected, $fullName) {
|
||||
|
||||
$converter = new Converter();
|
||||
$r = $converter->splitFullName($fullName);
|
||||
$r = implode(';', $r);
|
||||
$this->assertEquals($expected, $r);
|
||||
}
|
||||
|
||||
public function providesNames() {
|
||||
return [
|
||||
['Sauron;;;;', 'Sauron'],
|
||||
['Baggins;Bilbo;;;', 'Bilbo Baggins'],
|
||||
['Tolkien;John;Ronald Reuel;;', 'John Ronald Reuel Tolkien'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $displayName
|
||||
* @param $eMailAddress
|
||||
* @param $cloudId
|
||||
* @return \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected function getUserMock($displayName, $eMailAddress, $cloudId) {
|
||||
$image0 = $this->getMockBuilder('OCP\IImage')->disableOriginalConstructor()->getMock();
|
||||
$image0->method('mimeType')->willReturn('JPEG');
|
||||
$image0->method('data')->willReturn('123456789');
|
||||
$user = $this->getMockBuilder('OCP\IUser')->disableOriginalConstructor()->getMock();
|
||||
$user->method('getUID')->willReturn('12345');
|
||||
$user->method('getDisplayName')->willReturn($displayName);
|
||||
$user->method('getEMailAddress')->willReturn($eMailAddress);
|
||||
$user->method('getCloudId')->willReturn($cloudId);
|
||||
$user->method('getAvatarImage')->willReturn($image0);
|
||||
return $user;
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Lukas Reschke <lukas@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Connector\Sabre;
|
||||
|
||||
use OCA\DAV\Connector\Sabre\FakeLockerPlugin;
|
||||
use Sabre\HTTP\Response;
|
||||
use Test\TestCase;
|
||||
|
||||
/**
|
||||
* Class FakeLockerPluginTest
|
||||
*
|
||||
* @package OCA\DAV\Tests\Unit\Connector\Sabre
|
||||
*/
|
||||
class FakeLockerPluginTest extends TestCase {
|
||||
/** @var FakeLockerPlugin */
|
||||
private $fakeLockerPlugin;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->fakeLockerPlugin = new FakeLockerPlugin();
|
||||
}
|
||||
|
||||
public function testInitialize() {
|
||||
/** @var \Sabre\DAV\Server $server */
|
||||
$server = $this->getMock('\Sabre\DAV\Server');
|
||||
$server
|
||||
->expects($this->at(0))
|
||||
->method('on')
|
||||
->with('method:LOCK', [$this->fakeLockerPlugin, 'fakeLockProvider'], 1);
|
||||
$server
|
||||
->expects($this->at(1))
|
||||
->method('on')
|
||||
->with('method:UNLOCK', [$this->fakeLockerPlugin, 'fakeUnlockProvider'], 1);
|
||||
$server
|
||||
->expects($this->at(2))
|
||||
->method('on')
|
||||
->with('propFind', [$this->fakeLockerPlugin, 'propFind']);
|
||||
$server
|
||||
->expects($this->at(3))
|
||||
->method('on')
|
||||
->with('validateTokens', [$this->fakeLockerPlugin, 'validateTokens']);
|
||||
|
||||
$this->fakeLockerPlugin->initialize($server);
|
||||
}
|
||||
|
||||
public function testGetHTTPMethods() {
|
||||
$expected = [
|
||||
'LOCK',
|
||||
'UNLOCK',
|
||||
];
|
||||
$this->assertSame($expected, $this->fakeLockerPlugin->getHTTPMethods('Test'));
|
||||
}
|
||||
|
||||
public function testGetFeatures() {
|
||||
$expected = [
|
||||
2,
|
||||
];
|
||||
$this->assertSame($expected, $this->fakeLockerPlugin->getFeatures());
|
||||
}
|
||||
|
||||
public function testPropFind() {
|
||||
$propFind = $this->getMockBuilder('\Sabre\DAV\PropFind')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$node = $this->getMock('\Sabre\DAV\INode');
|
||||
|
||||
$propFind->expects($this->at(0))
|
||||
->method('handle')
|
||||
->with('{DAV:}supportedlock');
|
||||
$propFind->expects($this->at(1))
|
||||
->method('handle')
|
||||
->with('{DAV:}lockdiscovery');
|
||||
|
||||
$this->fakeLockerPlugin->propFind($propFind, $node);
|
||||
}
|
||||
|
||||
public function tokenDataProvider() {
|
||||
return [
|
||||
[
|
||||
[
|
||||
[
|
||||
'tokens' => [
|
||||
[
|
||||
'token' => 'aToken',
|
||||
'validToken' => false,
|
||||
],
|
||||
[],
|
||||
[
|
||||
'token' => 'opaquelocktoken:asdf',
|
||||
'validToken' => false,
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
'tokens' => [
|
||||
[
|
||||
'token' => 'aToken',
|
||||
'validToken' => false,
|
||||
],
|
||||
[],
|
||||
[
|
||||
'token' => 'opaquelocktoken:asdf',
|
||||
'validToken' => true,
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider tokenDataProvider
|
||||
* @param array $input
|
||||
* @param array $expected
|
||||
*/
|
||||
public function testValidateTokens(array $input, array $expected) {
|
||||
$request = $this->getMock('\Sabre\HTTP\RequestInterface');
|
||||
$this->fakeLockerPlugin->validateTokens($request, $input);
|
||||
$this->assertSame($expected, $input);
|
||||
}
|
||||
|
||||
public function testFakeLockProvider() {
|
||||
$request = $this->getMock('\Sabre\HTTP\RequestInterface');
|
||||
$response = new Response();
|
||||
$server = $this->getMock('\Sabre\DAV\Server');
|
||||
$this->fakeLockerPlugin->initialize($server);
|
||||
|
||||
$request->expects($this->exactly(2))
|
||||
->method('getPath')
|
||||
->will($this->returnValue('MyPath'));
|
||||
|
||||
$this->assertSame(false, $this->fakeLockerPlugin->fakeLockProvider($request, $response));
|
||||
|
||||
$expectedXml = '<?xml version="1.0" encoding="utf-8"?><d:prop xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"><d:lockdiscovery><d:activelock><d:lockscope><d:exclusive/></d:lockscope><d:locktype><d:write/></d:locktype><d:lockroot><d:href>MyPath</d:href></d:lockroot><d:depth>infinity</d:depth><d:timeout>Second-1800</d:timeout><d:locktoken><d:href>opaquelocktoken:fe4f7f2437b151fbcb4e9f5c8118c6b1</d:href></d:locktoken><d:owner/></d:activelock></d:lockdiscovery></d:prop>';
|
||||
|
||||
$this->assertXmlStringEqualsXmlString($expectedXml, $response->getBody());
|
||||
}
|
||||
|
||||
public function testFakeUnlockProvider() {
|
||||
$request = $this->getMock('\Sabre\HTTP\RequestInterface');
|
||||
$response = $this->getMock('\Sabre\HTTP\ResponseInterface');
|
||||
|
||||
$response->expects($this->once())
|
||||
->method('setStatus')
|
||||
->with('204');
|
||||
$response->expects($this->once())
|
||||
->method('setHeader')
|
||||
->with('Content-Length', '0');
|
||||
|
||||
$this->assertSame(false, $this->fakeLockerPlugin->fakeUnlockProvider($request, $response));
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2015 Thomas Müller <deepdiver@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\Tests\Unit\Connector\Sabre\Exception;
|
||||
|
||||
use OCA\DAV\Connector\Sabre\Exception\Forbidden;
|
||||
|
||||
class ForbiddenTest extends \Test\TestCase {
|
||||
|
||||
public function testSerialization() {
|
||||
|
||||
// create xml doc
|
||||
$DOM = new \DOMDocument('1.0','utf-8');
|
||||
$DOM->formatOutput = true;
|
||||
$error = $DOM->createElementNS('DAV:','d:error');
|
||||
$error->setAttribute('xmlns:s', \Sabre\DAV\Server::NS_SABREDAV);
|
||||
$DOM->appendChild($error);
|
||||
|
||||
// serialize the exception
|
||||
$message = "1234567890";
|
||||
$retry = false;
|
||||
$expectedXml = <<<EOD
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:o="http://owncloud.org/ns">
|
||||
<o:retry xmlns:o="o:">false</o:retry>
|
||||
<o:reason xmlns:o="o:">1234567890</o:reason>
|
||||
</d:error>
|
||||
|
||||
EOD;
|
||||
|
||||
$ex = new Forbidden($message, $retry);
|
||||
$server = $this->getMock('Sabre\DAV\Server');
|
||||
$ex->serialize($server, $error);
|
||||
|
||||
// assert
|
||||
$xml = $DOM->saveXML();
|
||||
$this->assertEquals($expectedXml, $xml);
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\API;
|
||||
|
||||
use OCA\Federation\DbHandler;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\BackgroundJob\IJobList;
|
||||
use OCP\IRequest;
|
||||
use OCP\Security\ISecureRandom;
|
||||
use OCP\Security\StringUtils;
|
||||
|
||||
/**
|
||||
* Class OCSAuthAPI
|
||||
*
|
||||
* OCS API end-points to exchange shared secret between two connected ownClouds
|
||||
*
|
||||
* @package OCA\Federation\API
|
||||
*/
|
||||
class OCSAuthAPI {
|
||||
|
||||
/** @var IRequest */
|
||||
private $request;
|
||||
|
||||
/** @var ISecureRandom */
|
||||
private $secureRandom;
|
||||
|
||||
/** @var IJobList */
|
||||
private $jobList;
|
||||
|
||||
/** @var TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
/** @var DbHandler */
|
||||
private $dbHandler;
|
||||
|
||||
/**
|
||||
* OCSAuthAPI constructor.
|
||||
*
|
||||
* @param IRequest $request
|
||||
* @param ISecureRandom $secureRandom
|
||||
* @param IJobList $jobList
|
||||
* @param TrustedServers $trustedServers
|
||||
* @param DbHandler $dbHandler
|
||||
*/
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
ISecureRandom $secureRandom,
|
||||
IJobList $jobList,
|
||||
TrustedServers $trustedServers,
|
||||
DbHandler $dbHandler
|
||||
) {
|
||||
$this->request = $request;
|
||||
$this->secureRandom = $secureRandom;
|
||||
$this->jobList = $jobList;
|
||||
$this->trustedServers = $trustedServers;
|
||||
$this->dbHandler = $dbHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* request received to ask remote server for a shared secret
|
||||
*
|
||||
* @return \OC_OCS_Result
|
||||
*/
|
||||
public function requestSharedSecret() {
|
||||
|
||||
$url = $this->request->getParam('url');
|
||||
$token = $this->request->getParam('token');
|
||||
|
||||
if ($this->trustedServers->isTrustedServer($url) === false) {
|
||||
return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
// if both server initiated the exchange of the shared secret the greater
|
||||
// token wins
|
||||
$localToken = $this->dbHandler->getToken($url);
|
||||
if (strcmp($localToken, $token) > 0) {
|
||||
return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
$this->jobList->add(
|
||||
'OCA\Federation\BackgroundJob\GetSharedSecret',
|
||||
[
|
||||
'url' => $url,
|
||||
'token' => $token,
|
||||
]
|
||||
);
|
||||
|
||||
return new \OC_OCS_Result(null, Http::STATUS_OK);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* create shared secret and return it
|
||||
*
|
||||
* @return \OC_OCS_Result
|
||||
*/
|
||||
public function getSharedSecret() {
|
||||
|
||||
$url = $this->request->getParam('url');
|
||||
$token = $this->request->getParam('token');
|
||||
|
||||
if (
|
||||
$this->trustedServers->isTrustedServer($url) === false
|
||||
|| $this->isValidToken($url, $token) === false
|
||||
) {
|
||||
return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
$sharedSecret = $this->secureRandom->getMediumStrengthGenerator()->generate(32);
|
||||
|
||||
$this->trustedServers->addSharedSecret($url, $sharedSecret);
|
||||
// reset token after the exchange of the shared secret was successful
|
||||
$this->dbHandler->addToken($url, '');
|
||||
|
||||
return new \OC_OCS_Result(['sharedSecret' => $sharedSecret], Http::STATUS_OK);
|
||||
|
||||
}
|
||||
|
||||
protected function isValidToken($url, $token) {
|
||||
$storedToken = $this->dbHandler->getToken($url);
|
||||
return StringUtils::equals($storedToken, $token);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\AppInfo;
|
||||
|
||||
$app = new Application();
|
||||
$app->registerSettings();
|
||||
$app->registerHooks();
|
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\AppInfo;
|
||||
|
||||
use OCA\Federation\API\OCSAuthAPI;
|
||||
use OCA\Federation\Controller\SettingsController;
|
||||
use OCA\Federation\DbHandler;
|
||||
use OCA\Federation\Hooks;
|
||||
use OCA\Federation\Middleware\AddServerMiddleware;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\API;
|
||||
use OCP\App;
|
||||
use OCP\AppFramework\IAppContainer;
|
||||
use OCP\Util;
|
||||
|
||||
class Application extends \OCP\AppFramework\App {
|
||||
|
||||
/**
|
||||
* @param array $urlParams
|
||||
*/
|
||||
public function __construct($urlParams = array()) {
|
||||
parent::__construct('federation', $urlParams);
|
||||
$this->registerService();
|
||||
$this->registerMiddleware();
|
||||
}
|
||||
|
||||
/**
|
||||
* register setting scripts
|
||||
*/
|
||||
public function registerSettings() {
|
||||
App::registerAdmin('federation', 'settings/settings-admin');
|
||||
}
|
||||
|
||||
private function registerService() {
|
||||
$container = $this->getContainer();
|
||||
|
||||
$container->registerService('addServerMiddleware', function(IAppContainer $c) {
|
||||
return new AddServerMiddleware(
|
||||
$c->getAppName(),
|
||||
\OC::$server->getL10N($c->getAppName()),
|
||||
\OC::$server->getLogger()
|
||||
);
|
||||
});
|
||||
|
||||
$container->registerService('DbHandler', function(IAppContainer $c) {
|
||||
return new DbHandler(
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
\OC::$server->getL10N($c->getAppName())
|
||||
);
|
||||
});
|
||||
|
||||
$container->registerService('TrustedServers', function(IAppContainer $c) {
|
||||
return new TrustedServers(
|
||||
$c->query('DbHandler'),
|
||||
\OC::$server->getHTTPClientService(),
|
||||
\OC::$server->getLogger(),
|
||||
\OC::$server->getJobList(),
|
||||
\OC::$server->getSecureRandom(),
|
||||
\OC::$server->getConfig()
|
||||
);
|
||||
});
|
||||
|
||||
$container->registerService('SettingsController', function (IAppContainer $c) {
|
||||
$server = $c->getServer();
|
||||
return new SettingsController(
|
||||
$c->getAppName(),
|
||||
$server->getRequest(),
|
||||
$server->getL10N($c->getAppName()),
|
||||
$c->query('TrustedServers')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private function registerMiddleware() {
|
||||
$container = $this->getContainer();
|
||||
$container->registerMiddleware('addServerMiddleware');
|
||||
}
|
||||
|
||||
/**
|
||||
* register OCS API Calls
|
||||
*/
|
||||
public function registerOCSApi() {
|
||||
|
||||
$container = $this->getContainer();
|
||||
$server = $container->getServer();
|
||||
|
||||
$auth = new OCSAuthAPI(
|
||||
$server->getRequest(),
|
||||
$server->getSecureRandom(),
|
||||
$server->getJobList(),
|
||||
$container->query('TrustedServers'),
|
||||
$container->query('DbHandler')
|
||||
|
||||
);
|
||||
|
||||
API::register('get',
|
||||
'/apps/federation/api/v1/shared-secret',
|
||||
array($auth, 'getSharedSecret'),
|
||||
'federation',
|
||||
API::GUEST_AUTH
|
||||
);
|
||||
|
||||
API::register('post',
|
||||
'/apps/federation/api/v1/request-shared-secret',
|
||||
array($auth, 'requestSharedSecret'),
|
||||
'federation',
|
||||
API::GUEST_AUTH
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* listen to federated_share_added hooks to auto-add new servers to the
|
||||
* list of trusted servers.
|
||||
*/
|
||||
public function registerHooks() {
|
||||
|
||||
$container = $this->getContainer();
|
||||
$hooksManager = new Hooks($container->query('TrustedServers'));
|
||||
|
||||
Util::connectHook(
|
||||
'OCP\Share',
|
||||
'federated_share_added',
|
||||
$hooksManager,
|
||||
'addServerHook'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<database>
|
||||
<name>*dbname*</name>
|
||||
<create>true</create>
|
||||
<overwrite>false</overwrite>
|
||||
<charset>utf8</charset>
|
||||
<table>
|
||||
<name>*dbprefix*trusted_servers</name>
|
||||
<declaration>
|
||||
<field>
|
||||
<name>id</name>
|
||||
<type>integer</type>
|
||||
<default>0</default>
|
||||
<notnull>true</notnull>
|
||||
<autoincrement>1</autoincrement>
|
||||
<length>4</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>url</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>512</length>
|
||||
<comments>Url of trusted server</comments>
|
||||
</field>
|
||||
<field>
|
||||
<name>url_hash</name>
|
||||
<type>text</type>
|
||||
<default></default>
|
||||
<notnull>true</notnull>
|
||||
<length>32</length>
|
||||
<comments>md5 hash of the url without the protocol</comments>
|
||||
</field>
|
||||
<field>
|
||||
<name>token</name>
|
||||
<type>text</type>
|
||||
<length>128</length>
|
||||
<comments>toke used to exchange the shared secret</comments>
|
||||
</field>
|
||||
<field>
|
||||
<name>shared_secret</name>
|
||||
<type>text</type>
|
||||
<length>256</length>
|
||||
<comments>shared secret used to authenticate</comments>
|
||||
</field>
|
||||
<field>
|
||||
<name>status</name>
|
||||
<type>integer</type>
|
||||
<length>4</length>
|
||||
<notnull>true</notnull>
|
||||
<default>2</default>
|
||||
<comments>current status of the connection</comments>
|
||||
</field>
|
||||
<index>
|
||||
<name>url_hash</name>
|
||||
<unique>true</unique>
|
||||
<field>
|
||||
<name>url_hash</name>
|
||||
<sorting>ascending</sorting>
|
||||
</field>
|
||||
</index>
|
||||
</declaration>
|
||||
</table>
|
||||
</database>
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0"?>
|
||||
<info>
|
||||
<id>federation</id>
|
||||
<name>Federation</name>
|
||||
<description>ownCloud Federation allows you to connect with other trusted ownClouds to exchange the user directory. For example this will be used to auto-complete external users for federated sharing.</description>
|
||||
<licence>AGPL</licence>
|
||||
<author>Bjoern Schiessle</author>
|
||||
<version>0.0.1</version>
|
||||
<namespace>Federation</namespace>
|
||||
<category>other</category>
|
||||
<dependencies>
|
||||
<owncloud min-version="9.0" />
|
||||
</dependencies>
|
||||
</info>
|
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
$application = new \OCA\Federation\AppInfo\Application();
|
||||
|
||||
$application->registerRoutes(
|
||||
$this,
|
||||
[
|
||||
'routes' => [
|
||||
[
|
||||
'name' => 'Settings#addServer',
|
||||
'url' => '/trusted-servers',
|
||||
'verb' => 'POST'
|
||||
],
|
||||
[
|
||||
'name' => 'Settings#removeServer',
|
||||
'url' => '/trusted-servers/{id}',
|
||||
'verb' => 'DELETE'
|
||||
],
|
||||
[
|
||||
'name' => 'Settings#autoAddServers',
|
||||
'url' => '/auto-add-servers',
|
||||
'verb' => 'POST'
|
||||
],
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
$application->registerOCSApi();
|
@ -0,0 +1,185 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\BackgroundJob;
|
||||
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use OC\BackgroundJob\JobList;
|
||||
use OC\BackgroundJob\QueuedJob;
|
||||
use OCA\Federation\DbHandler;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\BackgroundJob\IJobList;
|
||||
use OCP\Http\Client\IClient;
|
||||
use OCP\ILogger;
|
||||
use OCP\IURLGenerator;
|
||||
|
||||
/**
|
||||
* Class GetSharedSecret
|
||||
*
|
||||
* request shared secret from remote ownCloud
|
||||
*
|
||||
* @package OCA\Federation\Backgroundjob
|
||||
*/
|
||||
class GetSharedSecret extends QueuedJob{
|
||||
|
||||
/** @var IClient */
|
||||
private $httpClient;
|
||||
|
||||
/** @var IJobList */
|
||||
private $jobList;
|
||||
|
||||
/** @var IURLGenerator */
|
||||
private $urlGenerator;
|
||||
|
||||
/** @var TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
/** @var DbHandler */
|
||||
private $dbHandler;
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
private $endPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret?format=json';
|
||||
|
||||
/**
|
||||
* RequestSharedSecret constructor.
|
||||
*
|
||||
* @param IClient $httpClient
|
||||
* @param IURLGenerator $urlGenerator
|
||||
* @param IJobList $jobList
|
||||
* @param TrustedServers $trustedServers
|
||||
* @param ILogger $logger
|
||||
* @param DbHandler $dbHandler
|
||||
*/
|
||||
public function __construct(
|
||||
IClient $httpClient = null,
|
||||
IURLGenerator $urlGenerator = null,
|
||||
IJobList $jobList = null,
|
||||
TrustedServers $trustedServers = null,
|
||||
ILogger $logger = null,
|
||||
dbHandler $dbHandler = null
|
||||
) {
|
||||
$this->logger = $logger ? $logger : \OC::$server->getLogger();
|
||||
$this->httpClient = $httpClient ? $httpClient : \OC::$server->getHTTPClientService()->newClient();
|
||||
$this->jobList = $jobList ? $jobList : \OC::$server->getJobList();
|
||||
$this->urlGenerator = $urlGenerator ? $urlGenerator : \OC::$server->getURLGenerator();
|
||||
$this->dbHandler = $dbHandler ? $dbHandler : new DbHandler(\OC::$server->getDatabaseConnection(), \OC::$server->getL10N('federation'));
|
||||
if ($trustedServers) {
|
||||
$this->trustedServers = $trustedServers;
|
||||
} else {
|
||||
$this->trustedServers = new TrustedServers(
|
||||
$this->dbHandler,
|
||||
\OC::$server->getHTTPClientService(),
|
||||
\OC::$server->getLogger(),
|
||||
$this->jobList,
|
||||
\OC::$server->getSecureRandom(),
|
||||
\OC::$server->getConfig()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* run the job, then remove it from the joblist
|
||||
*
|
||||
* @param JobList $jobList
|
||||
* @param ILogger $logger
|
||||
*/
|
||||
public function execute($jobList, ILogger $logger = null) {
|
||||
$jobList->remove($this, $this->argument);
|
||||
$target = $this->argument['url'];
|
||||
// only execute if target is still in the list of trusted domains
|
||||
if ($this->trustedServers->isTrustedServer($target)) {
|
||||
$this->parentExecute($jobList, $logger);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* call execute() method of parent
|
||||
*
|
||||
* @param JobList $jobList
|
||||
* @param ILogger $logger
|
||||
*/
|
||||
protected function parentExecute($jobList, $logger) {
|
||||
parent::execute($jobList, $logger);
|
||||
}
|
||||
|
||||
protected function run($argument) {
|
||||
$target = $argument['url'];
|
||||
$source = $this->urlGenerator->getAbsoluteURL('/');
|
||||
$source = rtrim($source, '/');
|
||||
$token = $argument['token'];
|
||||
|
||||
try {
|
||||
$result = $this->httpClient->get(
|
||||
$target . $this->endPoint,
|
||||
[
|
||||
'query' =>
|
||||
[
|
||||
'url' => $source,
|
||||
'token' => $token
|
||||
],
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
]
|
||||
);
|
||||
|
||||
$status = $result->getStatusCode();
|
||||
|
||||
} catch (ClientException $e) {
|
||||
$status = $e->getCode();
|
||||
}
|
||||
|
||||
// if we received a unexpected response we try again later
|
||||
if (
|
||||
$status !== Http::STATUS_OK
|
||||
&& $status !== Http::STATUS_FORBIDDEN
|
||||
) {
|
||||
$this->jobList->add(
|
||||
'OCA\Federation\BackgroundJob\GetSharedSecret',
|
||||
$argument
|
||||
);
|
||||
} else {
|
||||
// reset token if we received a valid response
|
||||
$this->dbHandler->addToken($target, '');
|
||||
}
|
||||
|
||||
if ($status === Http::STATUS_OK) {
|
||||
$body = $result->getBody();
|
||||
$result = json_decode($body, true);
|
||||
if (isset($result['ocs']['data']['sharedSecret'])) {
|
||||
$this->trustedServers->addSharedSecret(
|
||||
$target,
|
||||
$result['ocs']['data']['sharedSecret']
|
||||
);
|
||||
} else {
|
||||
$this->logger->error(
|
||||
'remote server "' . $target . '"" does not return a valid shared secret',
|
||||
['app' => 'federation']
|
||||
);
|
||||
$this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\BackgroundJob;
|
||||
|
||||
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use OC\BackgroundJob\JobList;
|
||||
use OC\BackgroundJob\QueuedJob;
|
||||
use OCA\Federation\DbHandler;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\BackgroundJob\IJobList;
|
||||
use OCP\Http\Client\IClient;
|
||||
use OCP\ILogger;
|
||||
use OCP\IURLGenerator;
|
||||
|
||||
/**
|
||||
* Class RequestSharedSecret
|
||||
*
|
||||
* Ask remote ownCloud to request a sharedSecret from this server
|
||||
*
|
||||
* @package OCA\Federation\Backgroundjob
|
||||
*/
|
||||
class RequestSharedSecret extends QueuedJob {
|
||||
|
||||
/** @var IClient */
|
||||
private $httpClient;
|
||||
|
||||
/** @var IJobList */
|
||||
private $jobList;
|
||||
|
||||
/** @var IURLGenerator */
|
||||
private $urlGenerator;
|
||||
|
||||
/** @var DbHandler */
|
||||
private $dbHandler;
|
||||
|
||||
/** @var TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
private $endPoint = '/ocs/v2.php/apps/federation/api/v1/request-shared-secret?format=json';
|
||||
|
||||
/**
|
||||
* RequestSharedSecret constructor.
|
||||
*
|
||||
* @param IClient $httpClient
|
||||
* @param IURLGenerator $urlGenerator
|
||||
* @param IJobList $jobList
|
||||
* @param TrustedServers $trustedServers
|
||||
* @param DbHandler $dbHandler
|
||||
*/
|
||||
public function __construct(
|
||||
IClient $httpClient = null,
|
||||
IURLGenerator $urlGenerator = null,
|
||||
IJobList $jobList = null,
|
||||
TrustedServers $trustedServers = null,
|
||||
dbHandler $dbHandler = null
|
||||
) {
|
||||
$this->httpClient = $httpClient ? $httpClient : \OC::$server->getHTTPClientService()->newClient();
|
||||
$this->jobList = $jobList ? $jobList : \OC::$server->getJobList();
|
||||
$this->urlGenerator = $urlGenerator ? $urlGenerator : \OC::$server->getURLGenerator();
|
||||
$this->dbHandler = $dbHandler ? $dbHandler : new DbHandler(\OC::$server->getDatabaseConnection(), \OC::$server->getL10N('federation'));
|
||||
if ($trustedServers) {
|
||||
$this->trustedServers = $trustedServers;
|
||||
} else {
|
||||
$this->trustedServers = new TrustedServers(
|
||||
$this->dbHandler,
|
||||
\OC::$server->getHTTPClientService(),
|
||||
\OC::$server->getLogger(),
|
||||
$this->jobList,
|
||||
\OC::$server->getSecureRandom(),
|
||||
\OC::$server->getConfig()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* run the job, then remove it from the joblist
|
||||
*
|
||||
* @param JobList $jobList
|
||||
* @param ILogger $logger
|
||||
*/
|
||||
public function execute($jobList, ILogger $logger = null) {
|
||||
$jobList->remove($this, $this->argument);
|
||||
$target = $this->argument['url'];
|
||||
// only execute if target is still in the list of trusted domains
|
||||
if ($this->trustedServers->isTrustedServer($target)) {
|
||||
$this->parentExecute($jobList, $logger);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param JobList $jobList
|
||||
* @param ILogger $logger
|
||||
*/
|
||||
protected function parentExecute($jobList, $logger) {
|
||||
parent::execute($jobList, $logger);
|
||||
}
|
||||
|
||||
protected function run($argument) {
|
||||
|
||||
$target = $argument['url'];
|
||||
$source = $this->urlGenerator->getAbsoluteURL('/');
|
||||
$source = rtrim($source, '/');
|
||||
$token = $argument['token'];
|
||||
|
||||
try {
|
||||
$result = $this->httpClient->post(
|
||||
$target . $this->endPoint,
|
||||
[
|
||||
'body' => [
|
||||
'url' => $source,
|
||||
'token' => $token,
|
||||
],
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
]
|
||||
);
|
||||
|
||||
$status = $result->getStatusCode();
|
||||
|
||||
} catch (ClientException $e) {
|
||||
$status = $e->getCode();
|
||||
}
|
||||
|
||||
// if we received a unexpected response we try again later
|
||||
if (
|
||||
$status !== Http::STATUS_OK
|
||||
&& $status !== Http::STATUS_FORBIDDEN
|
||||
) {
|
||||
$this->jobList->add(
|
||||
'OCA\Federation\BackgroundJob\RequestSharedSecret',
|
||||
$argument
|
||||
);
|
||||
}
|
||||
|
||||
if ($status === Http::STATUS_FORBIDDEN) {
|
||||
// clear token if remote server refuses to ask for shared secret
|
||||
$this->dbHandler->addToken($target, '');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\Controller;
|
||||
|
||||
use OC\HintException;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\IConfig;
|
||||
use OCP\IL10N;
|
||||
use OCP\IRequest;
|
||||
|
||||
|
||||
class SettingsController extends Controller {
|
||||
|
||||
/** @var IL10N */
|
||||
private $l;
|
||||
|
||||
/** @var TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
/**
|
||||
* @param string $AppName
|
||||
* @param IRequest $request
|
||||
* @param IL10N $l10n
|
||||
* @param TrustedServers $trustedServers
|
||||
*/
|
||||
public function __construct($AppName,
|
||||
IRequest $request,
|
||||
IL10N $l10n,
|
||||
TrustedServers $trustedServers
|
||||
) {
|
||||
parent::__construct($AppName, $request);
|
||||
$this->l = $l10n;
|
||||
$this->trustedServers = $trustedServers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* add server to the list of trusted ownClouds
|
||||
*
|
||||
* @param string $url
|
||||
* @return DataResponse
|
||||
* @throws HintException
|
||||
*/
|
||||
public function addServer($url) {
|
||||
$this->checkServer($url);
|
||||
$id = $this->trustedServers->addServer($url);
|
||||
|
||||
return new DataResponse(
|
||||
[
|
||||
'url' => $url,
|
||||
'id' => $id,
|
||||
'message' => (string) $this->l->t('Server added to the list of trusted ownClouds')
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* add server to the list of trusted ownClouds
|
||||
*
|
||||
* @param int $id
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function removeServer($id) {
|
||||
$this->trustedServers->removeServer($id);
|
||||
return new DataResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* enable/disable to automatically add servers to the list of trusted servers
|
||||
* once a federated share was created and accepted successfully
|
||||
*
|
||||
* @param bool $autoAddServers
|
||||
*/
|
||||
public function autoAddServers($autoAddServers) {
|
||||
$this->trustedServers->setAutoAddServers($autoAddServers);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the server should be added to the list of trusted servers or not
|
||||
*
|
||||
* @param string $url
|
||||
* @return bool
|
||||
* @throws HintException
|
||||
*/
|
||||
protected function checkServer($url) {
|
||||
if ($this->trustedServers->isTrustedServer($url) === true) {
|
||||
$message = 'Server is already in the list of trusted servers.';
|
||||
$hint = $this->l->t('Server is already in the list of trusted servers.');
|
||||
throw new HintException($message, $hint);
|
||||
}
|
||||
|
||||
if ($this->trustedServers->isOwnCloudServer($url) === false) {
|
||||
$message = 'No ownCloud server found';
|
||||
$hint = $this->l->t('No ownCloud server found');
|
||||
throw new HintException($message, $hint);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
#ocFederationSettings p {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
#listOfTrustedServers li {
|
||||
padding-top: 10px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.removeTrustedServer {
|
||||
display: none;
|
||||
vertical-align:middle;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
#ocFederationAddServerButton {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#listOfTrustedServers li:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#listOfTrustedServers .status {
|
||||
margin-right: 10px;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1.0" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<path d="m13.733 0.00064c-0.52991 0-0.93331 0.40337-0.93331 0.93333v2.6666c-1.182 0.3034-2.243 0.7934-3.2668 1.4001l-1.9334-1.9334c-0.3747-0.3747-0.9586-0.3747-1.3333 0l-3.1999 3.2c-0.37473 0.37474-0.37473 0.95859 0 1.3333l1.9334 1.9335c-0.6067 1.0239-1.0967 2.0849-1.4001 3.2669h-2.6666c-0.52994 0-0.9333 0.403-0.9333 0.933v4.5333c2e-8 0.52996 0.40336 0.93333 0.93331 0.93333h2.6666c0.30335 1.1817 0.79332 2.2426 1.4 3.2666l-1.9334 1.9349c-0.37473 0.37474-0.37473 0.95859 0 1.3333l3.1999 3.2c0.37473 0.37474 0.95857 0.37474 1.3333 0l1.9334-1.9349c1.024 0.608 2.0849 1.0965 3.2665 1.3995v2.6667c0 0.53 0.403 0.933 0.933 0.933h4.5332c0.52991 0 0.93331-0.4032 0.93331-0.9344v-2.6667c1.1816-0.30336 2.2425-0.79335 3.2665-1.4l1.9333 1.9333c0.37473 0.37474 0.95857 0.37474 1.3333 0l3.1999-3.2c0.37473-0.37474 0.37473-0.95859 0-1.3333l-1.9327-1.9328c0.60798-1.024 1.0965-2.0845 1.3994-3.2661h2.6666c0.532 0 0.935-0.403 0.935-0.933v-4.534c0-0.53-0.403-0.933-0.934-0.933h-2.667c-0.303-1.182-0.791-2.243-1.399-3.2666l1.932-1.9334c0.37473-0.37474 0.37473-0.95859 0-1.3333l-3.2-3.2c-0.37473-0.37474-0.95857-0.37474-1.3333 0l-1.9327 1.9334c-1.024-0.6067-2.084-1.0967-3.266-1.4001v-2.6667c0-0.52993-0.403-0.9333-0.933-0.9333zm2.2666 8.8689c3.9361 0 7.1309 3.1947 7.1309 7.1311 0 3.9362-3.1946 7.1311-7.1309 7.1311-3.9361 0-7.1309-3.1955-7.1309-7.1317s3.1948-7.1311 7.1309-7.1311z" display="block" fill="#fff"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
// show input field to add a new trusted server
|
||||
$("#ocFederationAddServer").on('click', function() {
|
||||
$('#ocFederationAddServerButton').addClass('hidden');
|
||||
$("#serverUrl").removeClass('hidden');
|
||||
$("#serverUrl").focus();
|
||||
});
|
||||
|
||||
// add new trusted server
|
||||
$("#serverUrl").keyup(function (e) {
|
||||
if (e.keyCode === 13) { // add server on "enter"
|
||||
var url = $('#serverUrl').val();
|
||||
OC.msg.startSaving('#ocFederationAddServer .msg');
|
||||
$.post(
|
||||
OC.generateUrl('/apps/federation/trusted-servers'),
|
||||
{
|
||||
url: url
|
||||
}
|
||||
).done(function (data) {
|
||||
$('#serverUrl').attr('value', '');
|
||||
$('ul#listOfTrustedServers').prepend(
|
||||
$('<li>')
|
||||
.attr('id', data.id)
|
||||
.attr('class', 'icon-delete')
|
||||
.html('<span class="status indeterminate"></span>' + data.url)
|
||||
);
|
||||
OC.msg.finishedSuccess('#ocFederationAddServer .msg', data.message);
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
OC.msg.finishedError('#ocFederationAddServer .msg', JSON.parse(jqXHR.responseText).message);
|
||||
});
|
||||
} else if (e.keyCode === 27) { // hide input filed again in ESC
|
||||
$('#ocFederationAddServerButton').toggleClass('hidden');
|
||||
$("#serverUrl").toggleClass('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
// remove trusted server from list
|
||||
$( "#listOfTrustedServers" ).on('click', 'li', function() {
|
||||
var id = $(this).attr('id');
|
||||
var $this = $(this);
|
||||
$.ajax({
|
||||
url: OC.generateUrl('/apps/federation/trusted-servers/' + id),
|
||||
type: 'DELETE',
|
||||
success: function(response) {
|
||||
$this.remove();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$("#ocFederationSettings #autoAddServers").change(function() {
|
||||
$.post(
|
||||
OC.generateUrl('/apps/federation/auto-add-servers'),
|
||||
{
|
||||
autoAddServers: $(this).is(":checked")
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,270 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation;
|
||||
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
use OC\HintException;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IL10N;
|
||||
|
||||
/**
|
||||
* Class DbHandler
|
||||
*
|
||||
* handles all database calls for the federation app
|
||||
*
|
||||
* @group DB
|
||||
* @package OCA\Federation
|
||||
*/
|
||||
class DbHandler {
|
||||
|
||||
/** @var IDBConnection */
|
||||
private $connection;
|
||||
|
||||
/** @var IL10N */
|
||||
private $l;
|
||||
|
||||
/** @var string */
|
||||
private $dbTable = 'trusted_servers';
|
||||
|
||||
/**
|
||||
* @param IDBConnection $connection
|
||||
* @param IL10N $il10n
|
||||
*/
|
||||
public function __construct(
|
||||
IDBConnection $connection,
|
||||
IL10N $il10n
|
||||
) {
|
||||
$this->connection = $connection;
|
||||
$this->IL10N = $il10n;
|
||||
}
|
||||
|
||||
/**
|
||||
* add server to the list of trusted ownCloud servers
|
||||
*
|
||||
* @param string $url
|
||||
* @return int
|
||||
* @throws HintException
|
||||
*/
|
||||
public function addServer($url) {
|
||||
$hash = $this->hash($url);
|
||||
$url = rtrim($url, '/');
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->insert($this->dbTable)
|
||||
->values(
|
||||
[
|
||||
'url' => $query->createParameter('url'),
|
||||
'url_hash' => $query->createParameter('url_hash'),
|
||||
]
|
||||
)
|
||||
->setParameter('url', $url)
|
||||
->setParameter('url_hash', $hash);
|
||||
|
||||
$result = $query->execute();
|
||||
|
||||
if ($result) {
|
||||
return (int)$this->connection->lastInsertId('*PREFIX*'.$this->dbTable);
|
||||
} else {
|
||||
$message = 'Internal failure, Could not add ownCloud as trusted server: ' . $url;
|
||||
$message_t = $this->l->t('Could not add server');
|
||||
throw new HintException($message, $message_t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove server from the list of trusted ownCloud servers
|
||||
*
|
||||
* @param int $id
|
||||
*/
|
||||
public function removeServer($id) {
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->delete($this->dbTable)
|
||||
->where($query->expr()->eq('id', $query->createParameter('id')))
|
||||
->setParameter('id', $id);
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* get all trusted servers
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAllServer() {
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->select(['url', 'id', 'status'])->from($this->dbTable);
|
||||
$result = $query->execute()->fetchAll();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if server already exists in the database table
|
||||
*
|
||||
* @param string $url
|
||||
* @return bool
|
||||
*/
|
||||
public function serverExists($url) {
|
||||
$hash = $this->hash($url);
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->select('url')->from($this->dbTable)
|
||||
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
|
||||
->setParameter('url_hash', $hash);
|
||||
$result = $query->execute()->fetchAll();
|
||||
|
||||
return !empty($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* write token to database. Token is used to exchange the secret
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $token
|
||||
*/
|
||||
public function addToken($url, $token) {
|
||||
$hash = $this->hash($url);
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->update($this->dbTable)
|
||||
->set('token', $query->createParameter('token'))
|
||||
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
|
||||
->setParameter('url_hash', $hash)
|
||||
->setParameter('token', $token);
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* get token stored in database
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
public function getToken($url) {
|
||||
$hash = $this->hash($url);
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->select('token')->from($this->dbTable)
|
||||
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
|
||||
->setParameter('url_hash', $hash);
|
||||
|
||||
$result = $query->execute()->fetch();
|
||||
return $result['token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* add shared Secret to database
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $sharedSecret
|
||||
*/
|
||||
public function addSharedSecret($url, $sharedSecret) {
|
||||
$hash = $this->hash($url);
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->update($this->dbTable)
|
||||
->set('shared_secret', $query->createParameter('sharedSecret'))
|
||||
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
|
||||
->setParameter('url_hash', $hash)
|
||||
->setParameter('sharedSecret', $sharedSecret);
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* get shared secret from database
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
public function getSharedSecret($url) {
|
||||
$hash = $this->hash($url);
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->select('shared_secret')->from($this->dbTable)
|
||||
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
|
||||
->setParameter('url_hash', $hash);
|
||||
|
||||
$result = $query->execute()->fetch();
|
||||
return $result['shared_secret'];
|
||||
}
|
||||
|
||||
/**
|
||||
* set server status
|
||||
*
|
||||
* @param string $url
|
||||
* @param int $status
|
||||
*/
|
||||
public function setServerStatus($url, $status) {
|
||||
$hash = $this->hash($url);
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->update($this->dbTable)
|
||||
->set('status', $query->createParameter('status'))
|
||||
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
|
||||
->setParameter('url_hash', $hash)
|
||||
->setParameter('status', $status);
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* get server status
|
||||
*
|
||||
* @param string $url
|
||||
* @return int
|
||||
*/
|
||||
public function getServerStatus($url) {
|
||||
$hash = $this->hash($url);
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->select('status')->from($this->dbTable)
|
||||
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
|
||||
->setParameter('url_hash', $hash);
|
||||
|
||||
$result = $query->execute()->fetch();
|
||||
return (int)$result['status'];
|
||||
}
|
||||
|
||||
/**
|
||||
* create hash from URL
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
protected function hash($url) {
|
||||
$normalized = $this->normalizeUrl($url);
|
||||
return md5($normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* normalize URL, used to create the md5 hash
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
protected function normalizeUrl($url) {
|
||||
$normalized = $url;
|
||||
|
||||
if (strpos($url, 'https://') === 0) {
|
||||
$normalized = substr($url, strlen('https://'));
|
||||
} else if (strpos($url, 'http://') === 0) {
|
||||
$normalized = substr($url, strlen('http://'));
|
||||
}
|
||||
|
||||
$normalized = Filesystem::normalizePath($normalized);
|
||||
$normalized = trim($normalized, '/');
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation;
|
||||
|
||||
|
||||
|
||||
class Hooks {
|
||||
|
||||
/** @var TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
public function __construct(TrustedServers $trustedServers) {
|
||||
$this->trustedServers = $trustedServers;
|
||||
}
|
||||
|
||||
/**
|
||||
* add servers to the list of trusted servers once a federated share was established
|
||||
*
|
||||
* @param array $params
|
||||
*/
|
||||
public function addServerHook($params) {
|
||||
if (
|
||||
$this->trustedServers->getAutoAddServers() === true &&
|
||||
$this->trustedServers->isTrustedServer($params['server']) === false
|
||||
) {
|
||||
$this->trustedServers->addServer($params['server']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,254 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation;
|
||||
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\BackgroundJob\IJobList;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\IConfig;
|
||||
use OCP\ILogger;
|
||||
use OCP\Security\ISecureRandom;
|
||||
|
||||
class TrustedServers {
|
||||
|
||||
/** after a user list was exchanged at least once successfully */
|
||||
const STATUS_OK = 1;
|
||||
/** waiting for shared secret or initial user list exchange */
|
||||
const STATUS_PENDING = 2;
|
||||
/** something went wrong, misconfigured server, software bug,... user interaction needed */
|
||||
const STATUS_FAILURE = 3;
|
||||
|
||||
/** @var dbHandler */
|
||||
private $dbHandler;
|
||||
|
||||
/** @var IClientService */
|
||||
private $httpClientService;
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
/** @var IJobList */
|
||||
private $jobList;
|
||||
|
||||
/** @var ISecureRandom */
|
||||
private $secureRandom;
|
||||
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @param DbHandler $dbHandler
|
||||
* @param IClientService $httpClientService
|
||||
* @param ILogger $logger
|
||||
* @param IJobList $jobList
|
||||
* @param ISecureRandom $secureRandom
|
||||
* @param IConfig $config
|
||||
*/
|
||||
public function __construct(
|
||||
DbHandler $dbHandler,
|
||||
IClientService $httpClientService,
|
||||
ILogger $logger,
|
||||
IJobList $jobList,
|
||||
ISecureRandom $secureRandom,
|
||||
IConfig $config
|
||||
) {
|
||||
$this->dbHandler = $dbHandler;
|
||||
$this->httpClientService = $httpClientService;
|
||||
$this->logger = $logger;
|
||||
$this->jobList = $jobList;
|
||||
$this->secureRandom = $secureRandom;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* add server to the list of trusted ownCloud servers
|
||||
*
|
||||
* @param $url
|
||||
* @return int server id
|
||||
*/
|
||||
public function addServer($url) {
|
||||
$url = $this->updateProtocol($url);
|
||||
$result = $this->dbHandler->addServer($url);
|
||||
if ($result) {
|
||||
$token = $this->secureRandom->getMediumStrengthGenerator()->generate(16);
|
||||
$this->dbHandler->addToken($url, $token);
|
||||
$this->jobList->add(
|
||||
'OCA\Federation\BackgroundJob\RequestSharedSecret',
|
||||
[
|
||||
'url' => $url,
|
||||
'token' => $token
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* enable/disable to automatically add servers to the list of trusted servers
|
||||
* once a federated share was created and accepted successfully
|
||||
*
|
||||
* @param bool $status
|
||||
*/
|
||||
public function setAutoAddServers($status) {
|
||||
$value = $status ? '1' : '0';
|
||||
$this->config->setAppValue('federation', 'autoAddServers', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* return if we automatically add servers to the list of trusted servers
|
||||
* once a federated share was created and accepted successfully
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getAutoAddServers() {
|
||||
$value = $this->config->getAppValue('federation', 'autoAddServers', '1');
|
||||
return $value === '1';
|
||||
}
|
||||
|
||||
/**
|
||||
* get shared secret for the given server
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
public function getSharedSecret($url) {
|
||||
return $this->dbHandler->getSharedSecret($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* add shared secret for the given server
|
||||
*
|
||||
* @param string $url
|
||||
* @param $sharedSecret
|
||||
*/
|
||||
public function addSharedSecret($url, $sharedSecret) {
|
||||
$this->dbHandler->addSharedSecret($url, $sharedSecret);
|
||||
}
|
||||
|
||||
/**
|
||||
* remove server from the list of trusted ownCloud servers
|
||||
*
|
||||
* @param int $id
|
||||
*/
|
||||
public function removeServer($id) {
|
||||
$this->dbHandler->removeServer($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* get all trusted servers
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getServers() {
|
||||
return $this->dbHandler->getAllServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* check if given server is a trusted ownCloud server
|
||||
*
|
||||
* @param string $url
|
||||
* @return bool
|
||||
*/
|
||||
public function isTrustedServer($url) {
|
||||
return $this->dbHandler->serverExists($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* set server status
|
||||
*
|
||||
* @param string $url
|
||||
* @param int $status
|
||||
*/
|
||||
public function setServerStatus($url, $status) {
|
||||
$this->dbHandler->setServerStatus($url, $status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return int
|
||||
*/
|
||||
public function getServerStatus($url) {
|
||||
return $this->dbHandler->getServerStatus($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if URL point to a ownCloud server
|
||||
*
|
||||
* @param string $url
|
||||
* @return bool
|
||||
*/
|
||||
public function isOwnCloudServer($url) {
|
||||
$isValidOwnCloud = false;
|
||||
$client = $this->httpClientService->newClient();
|
||||
try {
|
||||
$result = $client->get(
|
||||
$url . '/status.php',
|
||||
[
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
]
|
||||
);
|
||||
if ($result->getStatusCode() === Http::STATUS_OK) {
|
||||
$isValidOwnCloud = $this->checkOwnCloudVersion($result->getBody());
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error($e->getMessage(), ['app' => 'federation']);
|
||||
return false;
|
||||
}
|
||||
return $isValidOwnCloud;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if ownCloud version is >= 9.0
|
||||
*
|
||||
* @param $statusphp
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkOwnCloudVersion($statusphp) {
|
||||
$decoded = json_decode($statusphp, true);
|
||||
if (!empty($decoded) && isset($decoded['version'])) {
|
||||
return version_compare($decoded['version'], '9.0.0', '>=');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the URL contain a protocol, if not add https
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
protected function updateProtocol($url) {
|
||||
if (
|
||||
strpos($url, 'https://') === 0
|
||||
|| strpos($url, 'http://') === 0
|
||||
) {
|
||||
|
||||
return $url;
|
||||
|
||||
}
|
||||
|
||||
return 'https://' . $url;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\Middleware ;
|
||||
|
||||
use OC\HintException;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\AppFramework\Middleware;
|
||||
use OCP\IL10N;
|
||||
use OCP\ILogger;
|
||||
|
||||
class AddServerMiddleware extends Middleware {
|
||||
|
||||
/** @var string */
|
||||
protected $appName;
|
||||
|
||||
/** @var IL10N */
|
||||
protected $l;
|
||||
|
||||
/** @var ILogger */
|
||||
protected $logger;
|
||||
|
||||
public function __construct($appName, IL10N $l, ILogger $logger) {
|
||||
$this->appName = $appName;
|
||||
$this->l = $l;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log error message and return a response which can be displayed to the user
|
||||
*
|
||||
* @param \OCP\AppFramework\Controller $controller
|
||||
* @param string $methodName
|
||||
* @param \Exception $exception
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function afterException($controller, $methodName, \Exception $exception) {
|
||||
$this->logger->error($exception->getMessage(), ['app' => $this->appName]);
|
||||
if ($exception instanceof HintException) {
|
||||
$message = $exception->getHint();
|
||||
} else {
|
||||
$message = $this->l->t('Unknown error');
|
||||
}
|
||||
|
||||
return new JSONResponse(
|
||||
['message' => $message],
|
||||
Http::STATUS_BAD_REQUEST
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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/>
|
||||
*
|
||||
*/
|
||||
|
||||
\OC_Util::checkAdminUser();
|
||||
|
||||
$template = new OCP\Template('federation', 'settings-admin');
|
||||
|
||||
$dbHandler = new \OCA\Federation\DbHandler(
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
\OC::$server->getL10N('federation')
|
||||
);
|
||||
|
||||
$trustedServers = new \OCA\Federation\TrustedServers(
|
||||
$dbHandler,
|
||||
\OC::$server->getHTTPClientService(),
|
||||
\OC::$server->getLogger(),
|
||||
\OC::$server->getJobList(),
|
||||
\OC::$server->getSecureRandom(),
|
||||
\OC::$server->getConfig()
|
||||
);
|
||||
|
||||
$template->assign('trustedServers', $trustedServers->getServers());
|
||||
$template->assign('autoAddServers', $trustedServers->getAutoAddServers());
|
||||
|
||||
return $template->fetchPage();
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/** @var array $_ */
|
||||
use OCA\Federation\TrustedServers;
|
||||
|
||||
/** @var OC_L10N $l */
|
||||
script('federation', 'settings-admin');
|
||||
style('federation', 'settings-admin')
|
||||
?>
|
||||
<div id="ocFederationSettings" class="section">
|
||||
<h2><?php p($l->t('Federation')); ?></h2>
|
||||
<em><?php p($l->t('ownCloud Federation allows you to connect with other trusted ownClouds to exchange the user directory. For example this will be used to auto-complete external users for federated sharing.')); ?></em>
|
||||
|
||||
<p>
|
||||
<input id="autoAddServers" type="checkbox" class="checkbox" <?php if($_['autoAddServers']) p('checked'); ?> />
|
||||
<label for="autoAddServers">Add server automatically once a federated share was created successfully</label>
|
||||
</p>
|
||||
|
||||
<h3>Trusted ownCloud Servers</h3>
|
||||
<p id="ocFederationAddServer">
|
||||
<button id="ocFederationAddServerButton" class="">+ Add ownCloud server</button>
|
||||
<input id="serverUrl" class="hidden" type="text" value="" placeholder="ownCloud Server" name="server_url"/>
|
||||
<span class="msg"></span>
|
||||
</p>
|
||||
<ul id="listOfTrustedServers">
|
||||
<?php foreach($_['trustedServers'] as $trustedServer) { ?>
|
||||
<li id="<?php p($trustedServer['id']); ?>" class="icon-delete">
|
||||
<?php if((int)$trustedServer['status'] === TrustedServers::STATUS_OK) { ?>
|
||||
<span class="status success"></span>
|
||||
<?php } elseif((int)$trustedServer['status'] === TrustedServers::STATUS_PENDING) { ?>
|
||||
<span class="status indeterminate"></span>
|
||||
<?php } else {?>
|
||||
<span class="status error"></span>
|
||||
<?php } ?>
|
||||
<?php p($trustedServer['url']); ?>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
@ -0,0 +1,184 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\Tests\API;
|
||||
|
||||
|
||||
use OC\BackgroundJob\JobList;
|
||||
use OCA\Federation\API\OCSAuthAPI;
|
||||
use OCA\Federation\DbHandler;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\IRequest;
|
||||
use OCP\Security\ISecureRandom;
|
||||
use Test\TestCase;
|
||||
|
||||
class OCSAuthAPITest extends TestCase {
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IRequest */
|
||||
private $request;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | ISecureRandom */
|
||||
private $secureRandom;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | JobList */
|
||||
private $jobList;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
|
||||
private $dbHandler;
|
||||
|
||||
/** @var OCSAuthApi */
|
||||
private $ocsAuthApi;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->request = $this->getMock('OCP\IRequest');
|
||||
$this->secureRandom = $this->getMock('OCP\Security\ISecureRandom');
|
||||
$this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->jobList = $this->getMockBuilder('OC\BackgroundJob\JobList')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->ocsAuthApi = new OCSAuthAPI(
|
||||
$this->request,
|
||||
$this->secureRandom,
|
||||
$this->jobList,
|
||||
$this->trustedServers,
|
||||
$this->dbHandler
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestRequestSharedSecret
|
||||
*
|
||||
* @param string $token
|
||||
* @param string $localToken
|
||||
* @param bool $isTrustedServer
|
||||
* @param int $expected
|
||||
*/
|
||||
public function testRequestSharedSecret($token, $localToken, $isTrustedServer, $expected) {
|
||||
|
||||
$url = 'url';
|
||||
|
||||
$this->request->expects($this->at(0))->method('getParam')->with('url')->willReturn($url);
|
||||
$this->request->expects($this->at(1))->method('getParam')->with('token')->willReturn($token);
|
||||
$this->trustedServers
|
||||
->expects($this->once())
|
||||
->method('isTrustedServer')->with($url)->willReturn($isTrustedServer);
|
||||
$this->dbHandler->expects($this->any())
|
||||
->method('getToken')->with($url)->willReturn($localToken);
|
||||
|
||||
if ($expected === Http::STATUS_OK) {
|
||||
$this->jobList->expects($this->once())->method('add')
|
||||
->with('OCA\Federation\BackgroundJob\GetSharedSecret', ['url' => $url, 'token' => $token]);
|
||||
} else {
|
||||
$this->jobList->expects($this->never())->method('add');
|
||||
}
|
||||
|
||||
$result = $this->ocsAuthApi->requestSharedSecret();
|
||||
$this->assertSame($expected, $result->getStatusCode());
|
||||
}
|
||||
|
||||
public function dataTestRequestSharedSecret() {
|
||||
return [
|
||||
['token2', 'token1', true, Http::STATUS_OK],
|
||||
['token1', 'token2', false, Http::STATUS_FORBIDDEN],
|
||||
['token1', 'token2', true, Http::STATUS_FORBIDDEN],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestGetSharedSecret
|
||||
*
|
||||
* @param bool $isTrustedServer
|
||||
* @param bool $isValidToken
|
||||
* @param int $expected
|
||||
*/
|
||||
public function testGetSharedSecret($isTrustedServer, $isValidToken, $expected) {
|
||||
|
||||
$url = 'url';
|
||||
$token = 'token';
|
||||
|
||||
$this->request->expects($this->at(0))->method('getParam')->with('url')->willReturn($url);
|
||||
$this->request->expects($this->at(1))->method('getParam')->with('token')->willReturn($token);
|
||||
|
||||
/** @var OCSAuthAPI | \PHPUnit_Framework_MockObject_MockObject $ocsAuthApi */
|
||||
$ocsAuthApi = $this->getMockBuilder('OCA\Federation\API\OCSAuthAPI')
|
||||
->setConstructorArgs(
|
||||
[
|
||||
$this->request,
|
||||
$this->secureRandom,
|
||||
$this->jobList,
|
||||
$this->trustedServers,
|
||||
$this->dbHandler
|
||||
]
|
||||
)->setMethods(['isValidToken'])->getMock();
|
||||
|
||||
$this->trustedServers
|
||||
->expects($this->any())
|
||||
->method('isTrustedServer')->with($url)->willReturn($isTrustedServer);
|
||||
$ocsAuthApi->expects($this->any())
|
||||
->method('isValidToken')->with($url, $token)->willReturn($isValidToken);
|
||||
|
||||
if($expected === Http::STATUS_OK) {
|
||||
$this->secureRandom->expects($this->once())->method('getMediumStrengthGenerator')
|
||||
->willReturn($this->secureRandom);
|
||||
$this->secureRandom->expects($this->once())->method('generate')->with(32)
|
||||
->willReturn('secret');
|
||||
$this->trustedServers->expects($this->once())
|
||||
->method('addSharedSecret')->willReturn($url, 'secret');
|
||||
$this->dbHandler->expects($this->once())
|
||||
->method('addToken')->with($url, '');
|
||||
} else {
|
||||
$this->secureRandom->expects($this->never())->method('getMediumStrengthGenerator');
|
||||
$this->secureRandom->expects($this->never())->method('generate');
|
||||
$this->trustedServers->expects($this->never())->method('addSharedSecret');
|
||||
$this->dbHandler->expects($this->never())->method('addToken');
|
||||
}
|
||||
|
||||
$result = $ocsAuthApi->getSharedSecret();
|
||||
|
||||
$this->assertSame($expected, $result->getStatusCode());
|
||||
|
||||
if ($expected === Http::STATUS_OK) {
|
||||
$data = $result->getData();
|
||||
$this->assertSame('secret', $data['sharedSecret']);
|
||||
}
|
||||
}
|
||||
|
||||
public function dataTestGetSharedSecret() {
|
||||
return [
|
||||
[true, true, Http::STATUS_OK],
|
||||
[false, true, Http::STATUS_FORBIDDEN],
|
||||
[true, false, Http::STATUS_FORBIDDEN],
|
||||
[false, false, Http::STATUS_FORBIDDEN],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\Tests\BackgroundJob;
|
||||
|
||||
|
||||
use OCA\Federation\BackgroundJob\GetSharedSecret;
|
||||
use OCA\Files_Sharing\Tests\TestCase;
|
||||
use OCA\Federation\DbHandler;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\BackgroundJob\IJobList;
|
||||
use OCP\Http\Client\IClient;
|
||||
use OCP\Http\Client\IResponse;
|
||||
use OCP\ILogger;
|
||||
use OCP\IURLGenerator;
|
||||
|
||||
/**
|
||||
* Class GetSharedSecretTest
|
||||
*
|
||||
* @group DB
|
||||
*
|
||||
* @package OCA\Federation\Tests\BackgroundJob
|
||||
*/
|
||||
class GetSharedSecretTest extends TestCase {
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IClient */
|
||||
private $httpClient;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IJobList */
|
||||
private $jobList;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IURLGenerator */
|
||||
private $urlGenerator;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
|
||||
private $dbHandler;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
|
||||
private $logger;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */
|
||||
private $response;
|
||||
|
||||
/** @var GetSharedSecret */
|
||||
private $getSharedSecret;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->httpClient = $this->getMock('OCP\Http\Client\IClient');
|
||||
$this->jobList = $this->getMock('OCP\BackgroundJob\IJobList');
|
||||
$this->urlGenerator = $this->getMock('OCP\IURLGenerator');
|
||||
$this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->logger = $this->getMock('OCP\ILogger');
|
||||
$this->response = $this->getMock('OCP\Http\Client\IResponse');
|
||||
|
||||
$this->getSharedSecret = new GetSharedSecret(
|
||||
$this->httpClient,
|
||||
$this->urlGenerator,
|
||||
$this->jobList,
|
||||
$this->trustedServers,
|
||||
$this->logger,
|
||||
$this->dbHandler
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestExecute
|
||||
*
|
||||
* @param bool $isTrustedServer
|
||||
*/
|
||||
public function testExecute($isTrustedServer) {
|
||||
/** @var GetSharedSecret |\PHPUnit_Framework_MockObject_MockObject $getSharedSecret */
|
||||
$getSharedSecret = $this->getMockBuilder('OCA\Federation\BackgroundJob\GetSharedSecret')
|
||||
->setConstructorArgs(
|
||||
[
|
||||
$this->httpClient,
|
||||
$this->urlGenerator,
|
||||
$this->jobList,
|
||||
$this->trustedServers,
|
||||
$this->logger,
|
||||
$this->dbHandler
|
||||
]
|
||||
)->setMethods(['parentExecute'])->getMock();
|
||||
$this->invokePrivate($getSharedSecret, 'argument', [['url' => 'url']]);
|
||||
|
||||
$this->jobList->expects($this->once())->method('remove');
|
||||
$this->trustedServers->expects($this->once())->method('isTrustedServer')
|
||||
->with('url')->willReturn($isTrustedServer);
|
||||
if ($isTrustedServer) {
|
||||
$getSharedSecret->expects($this->once())->method('parentExecute');
|
||||
} else {
|
||||
$getSharedSecret->expects($this->never())->method('parentExecute');
|
||||
}
|
||||
|
||||
$getSharedSecret->execute($this->jobList);
|
||||
|
||||
}
|
||||
|
||||
public function dataTestExecute() {
|
||||
return [
|
||||
[true],
|
||||
[false]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestRun
|
||||
*
|
||||
* @param int $statusCode
|
||||
*/
|
||||
public function testRun($statusCode) {
|
||||
|
||||
$target = 'targetURL';
|
||||
$source = 'sourceURL';
|
||||
$token = 'token';
|
||||
|
||||
$argument = ['url' => $target, 'token' => $token];
|
||||
|
||||
$this->urlGenerator->expects($this->once())->method('getAbsoluteURL')->with('/')
|
||||
->willReturn($source);
|
||||
$this->httpClient->expects($this->once())->method('get')
|
||||
->with(
|
||||
$target . '/ocs/v2.php/apps/federation/api/v1/shared-secret?format=json',
|
||||
[
|
||||
'query' =>
|
||||
[
|
||||
'url' => $source,
|
||||
'token' => $token
|
||||
],
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
]
|
||||
)->willReturn($this->response);
|
||||
|
||||
$this->response->expects($this->once())->method('getStatusCode')
|
||||
->willReturn($statusCode);
|
||||
|
||||
if (
|
||||
$statusCode !== Http::STATUS_OK
|
||||
&& $statusCode !== Http::STATUS_FORBIDDEN
|
||||
) {
|
||||
$this->jobList->expects($this->once())->method('add')
|
||||
->with('OCA\Federation\BackgroundJob\GetSharedSecret', $argument);
|
||||
$this->dbHandler->expects($this->never())->method('addToken');
|
||||
} else {
|
||||
$this->dbHandler->expects($this->once())->method('addToken')->with($target, '');
|
||||
$this->jobList->expects($this->never())->method('add');
|
||||
}
|
||||
|
||||
if ($statusCode === Http::STATUS_OK) {
|
||||
$this->response->expects($this->once())->method('getBody')
|
||||
->willReturn('{"ocs":{"data":{"sharedSecret":"secret"}}}');
|
||||
$this->trustedServers->expects($this->once())->method('addSharedSecret')
|
||||
->with($target, 'secret');
|
||||
} else {
|
||||
$this->trustedServers->expects($this->never())->method('addSharedSecret');
|
||||
}
|
||||
|
||||
$this->invokePrivate($this->getSharedSecret, 'run', [$argument]);
|
||||
}
|
||||
|
||||
public function dataTestRun() {
|
||||
return [
|
||||
[Http::STATUS_OK],
|
||||
[Http::STATUS_FORBIDDEN],
|
||||
[Http::STATUS_CONFLICT],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\Tests\BackgroundJob;
|
||||
|
||||
|
||||
use OCA\Federation\BackgroundJob\RequestSharedSecret;
|
||||
use OCP\AppFramework\Http;
|
||||
use Test\TestCase;
|
||||
|
||||
class RequestSharedSecretTest extends TestCase {
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IClient */
|
||||
private $httpClient;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IJobList */
|
||||
private $jobList;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IURLGenerator */
|
||||
private $urlGenerator;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
|
||||
private $dbHandler;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */
|
||||
private $response;
|
||||
|
||||
/** @var RequestSharedSecret */
|
||||
private $requestSharedSecret;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->httpClient = $this->getMock('OCP\Http\Client\IClient');
|
||||
$this->jobList = $this->getMock('OCP\BackgroundJob\IJobList');
|
||||
$this->urlGenerator = $this->getMock('OCP\IURLGenerator');
|
||||
$this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->response = $this->getMock('OCP\Http\Client\IResponse');
|
||||
|
||||
$this->requestSharedSecret = new RequestSharedSecret(
|
||||
$this->httpClient,
|
||||
$this->urlGenerator,
|
||||
$this->jobList,
|
||||
$this->trustedServers,
|
||||
$this->dbHandler
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestExecute
|
||||
*
|
||||
* @param bool $isTrustedServer
|
||||
*/
|
||||
public function testExecute($isTrustedServer) {
|
||||
/** @var RequestSharedSecret |\PHPUnit_Framework_MockObject_MockObject $requestSharedSecret */
|
||||
$requestSharedSecret = $this->getMockBuilder('OCA\Federation\BackgroundJob\RequestSharedSecret')
|
||||
->setConstructorArgs(
|
||||
[
|
||||
$this->httpClient,
|
||||
$this->urlGenerator,
|
||||
$this->jobList,
|
||||
$this->trustedServers,
|
||||
$this->dbHandler
|
||||
]
|
||||
)->setMethods(['parentExecute'])->getMock();
|
||||
$this->invokePrivate($requestSharedSecret, 'argument', [['url' => 'url']]);
|
||||
|
||||
$this->jobList->expects($this->once())->method('remove');
|
||||
$this->trustedServers->expects($this->once())->method('isTrustedServer')
|
||||
->with('url')->willReturn($isTrustedServer);
|
||||
if ($isTrustedServer) {
|
||||
$requestSharedSecret->expects($this->once())->method('parentExecute');
|
||||
} else {
|
||||
$requestSharedSecret->expects($this->never())->method('parentExecute');
|
||||
}
|
||||
|
||||
$requestSharedSecret->execute($this->jobList);
|
||||
|
||||
}
|
||||
|
||||
public function dataTestExecute() {
|
||||
return [
|
||||
[true],
|
||||
[false]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestRun
|
||||
*
|
||||
* @param int $statusCode
|
||||
*/
|
||||
public function testRun($statusCode) {
|
||||
|
||||
$target = 'targetURL';
|
||||
$source = 'sourceURL';
|
||||
$token = 'token';
|
||||
|
||||
$argument = ['url' => $target, 'token' => $token];
|
||||
|
||||
$this->urlGenerator->expects($this->once())->method('getAbsoluteURL')->with('/')
|
||||
->willReturn($source);
|
||||
$this->httpClient->expects($this->once())->method('post')
|
||||
->with(
|
||||
$target . '/ocs/v2.php/apps/federation/api/v1/request-shared-secret?format=json',
|
||||
[
|
||||
'body' =>
|
||||
[
|
||||
'url' => $source,
|
||||
'token' => $token
|
||||
],
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
]
|
||||
)->willReturn($this->response);
|
||||
|
||||
$this->response->expects($this->once())->method('getStatusCode')
|
||||
->willReturn($statusCode);
|
||||
|
||||
if (
|
||||
$statusCode !== Http::STATUS_OK
|
||||
&& $statusCode !== Http::STATUS_FORBIDDEN
|
||||
) {
|
||||
$this->jobList->expects($this->once())->method('add')
|
||||
->with('OCA\Federation\BackgroundJob\RequestSharedSecret', $argument);
|
||||
$this->dbHandler->expects($this->never())->method('addToken');
|
||||
}
|
||||
|
||||
if ($statusCode === Http::STATUS_FORBIDDEN) {
|
||||
$this->jobList->expects($this->never())->method('add');
|
||||
$this->dbHandler->expects($this->once())->method('addToken')->with($target, '');
|
||||
}
|
||||
|
||||
$this->invokePrivate($this->requestSharedSecret, 'run', [$argument]);
|
||||
}
|
||||
|
||||
public function dataTestRun() {
|
||||
return [
|
||||
[Http::STATUS_OK],
|
||||
[Http::STATUS_FORBIDDEN],
|
||||
[Http::STATUS_CONFLICT],
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\Tests\Controller;
|
||||
|
||||
|
||||
use OCA\Federation\Controller\SettingsController;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use Test\TestCase;
|
||||
|
||||
class SettingsControllerTest extends TestCase {
|
||||
|
||||
/** @var SettingsController */
|
||||
private $controller;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IRequest */
|
||||
private $request;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IL10N */
|
||||
private $l10n;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | \OCA\Federation\TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->request = $this->getMock('OCP\IRequest');
|
||||
$this->l10n = $this->getMock('OCP\IL10N');
|
||||
$this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->controller = new SettingsController(
|
||||
'SettingsControllerTest',
|
||||
$this->request,
|
||||
$this->l10n,
|
||||
$this->trustedServers
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddServer() {
|
||||
$this->trustedServers
|
||||
->expects($this->once())
|
||||
->method('isTrustedServer')
|
||||
->with('url')
|
||||
->willReturn(false);
|
||||
$this->trustedServers
|
||||
->expects($this->once())
|
||||
->method('isOwnCloudServer')
|
||||
->with('url')
|
||||
->willReturn(true);
|
||||
|
||||
$result = $this->controller->addServer('url');
|
||||
$this->assertTrue($result instanceof DataResponse);
|
||||
|
||||
$data = $result->getData();
|
||||
$this->assertSame(200, $result->getStatus());
|
||||
$this->assertSame('url', $data['url']);
|
||||
$this->assertArrayHasKey('id', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider checkServerFails
|
||||
* @expectedException \OC\HintException
|
||||
*
|
||||
* @param bool $isTrustedServer
|
||||
* @param bool $isOwnCloud
|
||||
*/
|
||||
public function testAddServerFail($isTrustedServer, $isOwnCloud) {
|
||||
$this->trustedServers
|
||||
->expects($this->any())
|
||||
->method('isTrustedServer')
|
||||
->with('url')
|
||||
->willReturn($isTrustedServer);
|
||||
$this->trustedServers
|
||||
->expects($this->any())
|
||||
->method('isOwnCloudServer')
|
||||
->with('url')
|
||||
->willReturn($isOwnCloud);
|
||||
|
||||
$this->controller->addServer('url');
|
||||
}
|
||||
|
||||
public function testRemoveServer() {
|
||||
$this->trustedServers->expects($this->once())->method('removeServer')
|
||||
->with('url');
|
||||
$result = $this->controller->removeServer('url');
|
||||
$this->assertTrue($result instanceof DataResponse);
|
||||
$this->assertSame(200, $result->getStatus());
|
||||
}
|
||||
|
||||
public function testCheckServer() {
|
||||
$this->trustedServers
|
||||
->expects($this->once())
|
||||
->method('isTrustedServer')
|
||||
->with('url')
|
||||
->willReturn(false);
|
||||
$this->trustedServers
|
||||
->expects($this->once())
|
||||
->method('isOwnCloudServer')
|
||||
->with('url')
|
||||
->willReturn(true);
|
||||
|
||||
$this->assertTrue(
|
||||
$this->invokePrivate($this->controller, 'checkServer', ['url'])
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider checkServerFails
|
||||
* @expectedException \OC\HintException
|
||||
*
|
||||
* @param bool $isTrustedServer
|
||||
* @param bool $isOwnCloud
|
||||
*/
|
||||
public function testCheckServerFail($isTrustedServer, $isOwnCloud) {
|
||||
$this->trustedServers
|
||||
->expects($this->any())
|
||||
->method('isTrustedServer')
|
||||
->with('url')
|
||||
->willReturn($isTrustedServer);
|
||||
$this->trustedServers
|
||||
->expects($this->any())
|
||||
->method('isOwnCloudServer')
|
||||
->with('url')
|
||||
->willReturn($isOwnCloud);
|
||||
|
||||
$this->assertTrue(
|
||||
$this->invokePrivate($this->controller, 'checkServer', ['url'])
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* data to simulate checkServer fails
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function checkServerFails() {
|
||||
return [
|
||||
[true, true],
|
||||
[false, false]
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,259 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\Tests\lib;
|
||||
|
||||
|
||||
use OCA\Federation\DbHandler;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\IDBConnection;
|
||||
use Test\TestCase;
|
||||
|
||||
/**
|
||||
* @group DB
|
||||
*/
|
||||
class DbHandlerTest extends TestCase {
|
||||
|
||||
/** @var DbHandler */
|
||||
private $dbHandler;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $il10n;
|
||||
|
||||
/** @var IDBConnection */
|
||||
private $connection;
|
||||
|
||||
/** @var string */
|
||||
private $dbTable = 'trusted_servers';
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->connection = \OC::$server->getDatabaseConnection();
|
||||
$this->il10n = $this->getMock('OCP\IL10N');
|
||||
|
||||
$this->dbHandler = new DbHandler(
|
||||
$this->connection,
|
||||
$this->il10n
|
||||
);
|
||||
|
||||
$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
|
||||
$result = $query->execute()->fetchAll();
|
||||
$this->assertEmpty($result, 'we need to start with a empty trusted_servers table');
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
parent::tearDown();
|
||||
$query = $this->connection->getQueryBuilder()->delete($this->dbTable);
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestAddServer
|
||||
*
|
||||
* @param string $url passed to the method
|
||||
* @param string $expectedUrl the url we expect to be written to the db
|
||||
* @param string $expectedHash the hash value we expect to be written to the db
|
||||
*/
|
||||
public function testAddServer($url, $expectedUrl, $expectedHash) {
|
||||
$id = $this->dbHandler->addServer($url);
|
||||
|
||||
$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
|
||||
$result = $query->execute()->fetchAll();
|
||||
$this->assertSame(1, count($result));
|
||||
$this->assertSame($expectedUrl, $result[0]['url']);
|
||||
$this->assertSame($id, (int)$result[0]['id']);
|
||||
$this->assertSame($expectedHash, $result[0]['url_hash']);
|
||||
$this->assertSame(TrustedServers::STATUS_PENDING, (int)$result[0]['status']);
|
||||
}
|
||||
|
||||
public function dataTestAddServer() {
|
||||
return [
|
||||
['http://owncloud.org', 'http://owncloud.org', md5('owncloud.org')],
|
||||
['https://owncloud.org', 'https://owncloud.org', md5('owncloud.org')],
|
||||
['http://owncloud.org/', 'http://owncloud.org', md5('owncloud.org')],
|
||||
];
|
||||
}
|
||||
|
||||
public function testRemove() {
|
||||
$id1 = $this->dbHandler->addServer('server1');
|
||||
$id2 = $this->dbHandler->addServer('server2');
|
||||
|
||||
$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
|
||||
$result = $query->execute()->fetchAll();
|
||||
$this->assertSame(2, count($result));
|
||||
$this->assertSame('server1', $result[0]['url']);
|
||||
$this->assertSame('server2', $result[1]['url']);
|
||||
$this->assertSame($id1, (int)$result[0]['id']);
|
||||
$this->assertSame($id2, (int)$result[1]['id']);
|
||||
|
||||
$this->dbHandler->removeServer($id2);
|
||||
$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
|
||||
$result = $query->execute()->fetchAll();
|
||||
$this->assertSame(1, count($result));
|
||||
$this->assertSame('server1', $result[0]['url']);
|
||||
$this->assertSame($id1, (int)$result[0]['id']);
|
||||
}
|
||||
|
||||
public function testGetAll() {
|
||||
$id1 = $this->dbHandler->addServer('server1');
|
||||
$id2 = $this->dbHandler->addServer('server2');
|
||||
|
||||
$result = $this->dbHandler->getAllServer();
|
||||
$this->assertSame(2, count($result));
|
||||
$this->assertSame('server1', $result[0]['url']);
|
||||
$this->assertSame('server2', $result[1]['url']);
|
||||
$this->assertSame($id1, (int)$result[0]['id']);
|
||||
$this->assertSame($id2, (int)$result[1]['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestServerExists
|
||||
*
|
||||
* @param string $serverInTable
|
||||
* @param string $checkForServer
|
||||
* @param bool $expected
|
||||
*/
|
||||
public function testServerExists($serverInTable, $checkForServer, $expected) {
|
||||
$this->dbHandler->addServer($serverInTable);
|
||||
$this->assertSame($expected,
|
||||
$this->dbHandler->serverExists($checkForServer)
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestServerExists() {
|
||||
return [
|
||||
['server1', 'server1', true],
|
||||
['server1', 'http://server1', true],
|
||||
['server1', 'server2', false]
|
||||
];
|
||||
}
|
||||
|
||||
public function testAddToken() {
|
||||
$this->dbHandler->addServer('server1');
|
||||
$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
|
||||
$result = $query->execute()->fetchAll();
|
||||
$this->assertSame(1, count($result));
|
||||
$this->assertSame(null, $result[0]['token']);
|
||||
$this->dbHandler->addToken('http://server1', 'token');
|
||||
$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
|
||||
$result = $query->execute()->fetchAll();
|
||||
$this->assertSame(1, count($result));
|
||||
$this->assertSame('token', $result[0]['token']);
|
||||
}
|
||||
|
||||
public function testGetToken() {
|
||||
$this->dbHandler->addServer('server1');
|
||||
$this->dbHandler->addToken('http://server1', 'token');
|
||||
$this->assertSame('token',
|
||||
$this->dbHandler->getToken('https://server1')
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddSharedSecret() {
|
||||
$this->dbHandler->addServer('server1');
|
||||
$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
|
||||
$result = $query->execute()->fetchAll();
|
||||
$this->assertSame(1, count($result));
|
||||
$this->assertSame(null, $result[0]['shared_secret']);
|
||||
$this->dbHandler->addSharedSecret('http://server1', 'secret');
|
||||
$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
|
||||
$result = $query->execute()->fetchAll();
|
||||
$this->assertSame(1, count($result));
|
||||
$this->assertSame('secret', $result[0]['shared_secret']);
|
||||
}
|
||||
|
||||
public function testGetSharedSecret() {
|
||||
$this->dbHandler->addServer('server1');
|
||||
$this->dbHandler->addSharedSecret('http://server1', 'secret');
|
||||
$this->assertSame('secret',
|
||||
$this->dbHandler->getSharedSecret('https://server1')
|
||||
);
|
||||
}
|
||||
|
||||
public function testSetServerStatus() {
|
||||
$this->dbHandler->addServer('server1');
|
||||
$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
|
||||
$result = $query->execute()->fetchAll();
|
||||
$this->assertSame(1, count($result));
|
||||
$this->assertSame(TrustedServers::STATUS_PENDING, (int)$result[0]['status']);
|
||||
$this->dbHandler->setServerStatus('http://server1', TrustedServers::STATUS_OK);
|
||||
$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
|
||||
$result = $query->execute()->fetchAll();
|
||||
$this->assertSame(1, count($result));
|
||||
$this->assertSame(TrustedServers::STATUS_OK, (int)$result[0]['status']);
|
||||
}
|
||||
|
||||
public function testGetServerStatus() {
|
||||
$this->dbHandler->addServer('server1');
|
||||
$this->dbHandler->setServerStatus('http://server1', TrustedServers::STATUS_OK);
|
||||
$this->assertSame(TrustedServers::STATUS_OK,
|
||||
$this->dbHandler->getServerStatus('https://server1')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash should always be computed with the normalized URL
|
||||
*
|
||||
* @dataProvider dataTestHash
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $expected
|
||||
*/
|
||||
public function testHash($url, $expected) {
|
||||
$this->assertSame($expected,
|
||||
$this->invokePrivate($this->dbHandler, 'hash', [$url])
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestHash() {
|
||||
return [
|
||||
['server1', md5('server1')],
|
||||
['http://server1', md5('server1')],
|
||||
['https://server1', md5('server1')],
|
||||
['http://server1/', md5('server1')],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestNormalizeUrl
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $expected
|
||||
*/
|
||||
public function testNormalizeUrl($url, $expected) {
|
||||
$this->assertSame($expected,
|
||||
$this->invokePrivate($this->dbHandler, 'normalizeUrl', [$url])
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestNormalizeUrl() {
|
||||
return [
|
||||
['owncloud.org', 'owncloud.org'],
|
||||
['http://owncloud.org', 'owncloud.org'],
|
||||
['https://owncloud.org', 'owncloud.org'],
|
||||
['https://owncloud.org//mycloud', 'owncloud.org/mycloud'],
|
||||
['https://owncloud.org/mycloud/', 'owncloud.org/mycloud'],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\Tests\lib;
|
||||
|
||||
|
||||
use OCA\Federation\Hooks;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use Test\TestCase;
|
||||
|
||||
class HooksTest extends TestCase {
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
/** @var Hooks */
|
||||
private $hooks;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->hooks = new Hooks($this->trustedServers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestAddServerHook
|
||||
*
|
||||
* @param bool $autoAddEnabled is auto-add enabled
|
||||
* @param bool $isTrustedServer is the server already in the list of trusted servers
|
||||
* @param bool $addServer should the server be added
|
||||
*/
|
||||
public function testAddServerHook($autoAddEnabled, $isTrustedServer, $addServer) {
|
||||
$this->trustedServers->expects($this->any())->method('getAutoAddServers')
|
||||
->willReturn($autoAddEnabled);
|
||||
$this->trustedServers->expects($this->any())->method('isTrustedServer')
|
||||
->with('url')->willReturn($isTrustedServer);
|
||||
|
||||
if ($addServer) {
|
||||
$this->trustedServers->expects($this->once())->method('addServer')
|
||||
->with('url');
|
||||
} else {
|
||||
$this->trustedServers->expects($this->never())->method('addServer');
|
||||
}
|
||||
|
||||
$this->hooks->addServerHook(['server' => 'url']);
|
||||
|
||||
}
|
||||
|
||||
public function dataTestAddServerHook() {
|
||||
return [
|
||||
[true, true, false],
|
||||
[false, true, false],
|
||||
[true, false, true],
|
||||
[false, false, false],
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,344 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\Tests\lib;
|
||||
|
||||
|
||||
use OCA\Federation\DbHandler;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\BackgroundJob\IJobList;
|
||||
use OCP\Http\Client\IClient;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\Http\Client\IResponse;
|
||||
use OCP\IConfig;
|
||||
use OCP\ILogger;
|
||||
use OCP\Security\ISecureRandom;
|
||||
use Test\TestCase;
|
||||
|
||||
class TrustedServersTest extends TestCase {
|
||||
|
||||
/** @var TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
|
||||
private $dbHandler;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IClientService */
|
||||
private $httpClientService;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IClient */
|
||||
private $httpClient;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */
|
||||
private $response;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
|
||||
private $logger;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IJobList */
|
||||
private $jobList;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | ISecureRandom */
|
||||
private $secureRandom;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | IConfig */
|
||||
private $config;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->dbHandler = $this->getMockBuilder('\OCA\Federation\DbHandler')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->httpClientService = $this->getMock('OCP\Http\Client\IClientService');
|
||||
$this->httpClient = $this->getMock('OCP\Http\Client\IClient');
|
||||
$this->response = $this->getMock('OCP\Http\Client\IResponse');
|
||||
$this->logger = $this->getMock('OCP\ILogger');
|
||||
$this->jobList = $this->getMock('OCP\BackgroundJob\IJobList');
|
||||
$this->secureRandom = $this->getMock('OCP\Security\ISecureRandom');
|
||||
$this->config = $this->getMock('OCP\IConfig');
|
||||
|
||||
$this->trustedServers = new TrustedServers(
|
||||
$this->dbHandler,
|
||||
$this->httpClientService,
|
||||
$this->logger,
|
||||
$this->jobList,
|
||||
$this->secureRandom,
|
||||
$this->config
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTrueFalse
|
||||
*
|
||||
* @param bool $success
|
||||
*/
|
||||
public function testAddServer($success) {
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */
|
||||
$trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
|
||||
->setConstructorArgs(
|
||||
[
|
||||
$this->dbHandler,
|
||||
$this->httpClientService,
|
||||
$this->logger,
|
||||
$this->jobList,
|
||||
$this->secureRandom,
|
||||
$this->config
|
||||
]
|
||||
)
|
||||
->setMethods(['normalizeUrl', 'updateProtocol'])
|
||||
->getMock();
|
||||
$trustedServers->expects($this->once())->method('updateProtocol')
|
||||
->with('url')->willReturn('https://url');
|
||||
$this->dbHandler->expects($this->once())->method('addServer')->with('https://url')
|
||||
->willReturn($success);
|
||||
|
||||
if ($success) {
|
||||
$this->secureRandom->expects($this->once())->method('getMediumStrengthGenerator')
|
||||
->willReturn($this->secureRandom);
|
||||
$this->secureRandom->expects($this->once())->method('generate')
|
||||
->willReturn('token');
|
||||
$this->dbHandler->expects($this->once())->method('addToken')->with('https://url', 'token');
|
||||
$this->jobList->expects($this->once())->method('add')
|
||||
->with('OCA\Federation\BackgroundJob\RequestSharedSecret',
|
||||
['url' => 'https://url', 'token' => 'token']);
|
||||
} else {
|
||||
$this->jobList->expects($this->never())->method('add');
|
||||
}
|
||||
|
||||
$this->assertSame($success,
|
||||
$trustedServers->addServer('url')
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTrueFalse() {
|
||||
return [
|
||||
[true],
|
||||
[false]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTrueFalse
|
||||
*
|
||||
* @param bool $status
|
||||
*/
|
||||
public function testSetAutoAddServers($status) {
|
||||
if ($status) {
|
||||
$this->config->expects($this->once())->method('setAppValue')
|
||||
->with('federation', 'autoAddServers', '1');
|
||||
} else {
|
||||
$this->config->expects($this->once())->method('setAppValue')
|
||||
->with('federation', 'autoAddServers', '0');
|
||||
}
|
||||
|
||||
$this->trustedServers->setAutoAddServers($status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestGetAutoAddServers
|
||||
*
|
||||
* @param string $status
|
||||
* @param bool $expected
|
||||
*/
|
||||
public function testGetAutoAddServers($status, $expected) {
|
||||
$this->config->expects($this->once())->method('getAppValue')
|
||||
->with('federation', 'autoAddServers', '1')->willReturn($status);
|
||||
|
||||
$this->assertSame($expected,
|
||||
$this->trustedServers->getAutoAddServers($status)
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestGetAutoAddServers() {
|
||||
return [
|
||||
['1', true],
|
||||
['0', false]
|
||||
];
|
||||
}
|
||||
|
||||
public function testAddSharedSecret() {
|
||||
$this->dbHandler->expects($this->once())->method('addSharedSecret')
|
||||
->with('url', 'secret');
|
||||
$this->trustedServers->addSharedSecret('url', 'secret');
|
||||
}
|
||||
|
||||
public function testGetSharedSecret() {
|
||||
$this->dbHandler->expects($this->once())->method('getSharedSecret')
|
||||
->with('url')->willReturn(true);
|
||||
$this->assertTrue(
|
||||
$this->trustedServers->getSharedSecret('url')
|
||||
);
|
||||
}
|
||||
|
||||
public function testRemoveServer() {
|
||||
$id = 42;
|
||||
$this->dbHandler->expects($this->once())->method('removeServer')->with($id);
|
||||
$this->trustedServers->removeServer($id);
|
||||
}
|
||||
|
||||
public function testGetServers() {
|
||||
$this->dbHandler->expects($this->once())->method('getAllServer')->willReturn(true);
|
||||
|
||||
$this->assertTrue(
|
||||
$this->trustedServers->getServers()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testIsTrustedServer() {
|
||||
$this->dbHandler->expects($this->once())->method('serverExists')->with('url')
|
||||
->willReturn(true);
|
||||
|
||||
$this->assertTrue(
|
||||
$this->trustedServers->isTrustedServer('url')
|
||||
);
|
||||
}
|
||||
|
||||
public function testSetServerStatus() {
|
||||
$this->dbHandler->expects($this->once())->method('setServerStatus')
|
||||
->with('url', 'status');
|
||||
$this->trustedServers->setServerStatus('url', 'status');
|
||||
}
|
||||
|
||||
public function testGetServerStatus() {
|
||||
$this->dbHandler->expects($this->once())->method('getServerStatus')
|
||||
->with('url')->willReturn(true);
|
||||
$this->assertTrue(
|
||||
$this->trustedServers->getServerStatus('url')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestIsOwnCloudServer
|
||||
*
|
||||
* @param int $statusCode
|
||||
* @param bool $isValidOwnCloudVersion
|
||||
* @param bool $expected
|
||||
*/
|
||||
public function testIsOwnCloudServer($statusCode, $isValidOwnCloudVersion, $expected) {
|
||||
|
||||
$server = 'server1';
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */
|
||||
$trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
|
||||
->setConstructorArgs(
|
||||
[
|
||||
$this->dbHandler,
|
||||
$this->httpClientService,
|
||||
$this->logger,
|
||||
$this->jobList,
|
||||
$this->secureRandom,
|
||||
$this->config
|
||||
]
|
||||
)
|
||||
->setMethods(['checkOwnCloudVersion'])
|
||||
->getMock();
|
||||
|
||||
$this->httpClientService->expects($this->once())->method('newClient')
|
||||
->willReturn($this->httpClient);
|
||||
|
||||
$this->httpClient->expects($this->once())->method('get')->with($server . '/status.php')
|
||||
->willReturn($this->response);
|
||||
|
||||
$this->response->expects($this->once())->method('getStatusCode')
|
||||
->willReturn($statusCode);
|
||||
|
||||
if ($statusCode === 200) {
|
||||
$trustedServers->expects($this->once())->method('checkOwnCloudVersion')
|
||||
->willReturn($isValidOwnCloudVersion);
|
||||
} else {
|
||||
$trustedServers->expects($this->never())->method('checkOwnCloudVersion');
|
||||
}
|
||||
|
||||
$this->assertSame($expected,
|
||||
$trustedServers->isOwnCloudServer($server)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function dataTestIsOwnCloudServer() {
|
||||
return [
|
||||
[200, true, true],
|
||||
[200, false, false],
|
||||
[404, true, false],
|
||||
];
|
||||
}
|
||||
|
||||
public function testIsOwnCloudServerFail() {
|
||||
$server = 'server1';
|
||||
|
||||
$this->httpClientService->expects($this->once())->method('newClient')
|
||||
->willReturn($this->httpClient);
|
||||
|
||||
$this->logger->expects($this->once())->method('error')
|
||||
->with('simulated exception', ['app' => 'federation']);
|
||||
|
||||
$this->httpClient->expects($this->once())->method('get')->with($server . '/status.php')
|
||||
->willReturnCallback(function () {
|
||||
throw new \Exception('simulated exception');
|
||||
});
|
||||
|
||||
$this->assertFalse($this->trustedServers->isOwnCloudServer($server));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestCheckOwnCloudVersion
|
||||
*
|
||||
* @param $statusphp
|
||||
* @param $expected
|
||||
*/
|
||||
public function testCheckOwnCloudVersion($statusphp, $expected) {
|
||||
$this->assertSame($expected,
|
||||
$this->invokePrivate($this->trustedServers, 'checkOwnCloudVersion', [$statusphp])
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestCheckOwnCloudVersion() {
|
||||
return [
|
||||
['{"version":"8.4.0"}', false],
|
||||
['{"version":"9.0.0"}', true],
|
||||
['{"version":"9.1.0"}', true]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestUpdateProtocol
|
||||
* @param string $url
|
||||
* @param string $expected
|
||||
*/
|
||||
public function testUpdateProtocol($url, $expected) {
|
||||
$this->assertSame($expected,
|
||||
$this->invokePrivate($this->trustedServers, 'updateProtocol', [$url])
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestUpdateProtocol() {
|
||||
return [
|
||||
['http://owncloud.org', 'http://owncloud.org'],
|
||||
['https://owncloud.org', 'https://owncloud.org'],
|
||||
['owncloud.org', 'https://owncloud.org'],
|
||||
['httpserver', 'https://httpserver'],
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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\Federation\Tests\Middleware;
|
||||
|
||||
|
||||
use OC\HintException;
|
||||
use OCA\Federation\Middleware\AddServerMiddleware;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http;
|
||||
use Test\TestCase;
|
||||
|
||||
class AddServerMiddlewareTest extends TestCase {
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
|
||||
private $logger;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IL10N */
|
||||
private $l10n;
|
||||
|
||||
/** @var AddServerMiddleware */
|
||||
private $middleware;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | Controller */
|
||||
private $controller;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->logger = $this->getMock('OCP\ILogger');
|
||||
$this->l10n = $this->getMock('OCP\IL10N');
|
||||
$this->controller = $this->getMockBuilder('OCP\AppFramework\Controller')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->middleware = new AddServerMiddleware(
|
||||
'AddServerMiddlewareTest',
|
||||
$this->l10n,
|
||||
$this->logger
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestAfterException
|
||||
*
|
||||
* @param \Exception $exception
|
||||
* @param string $message
|
||||
* @param string $hint
|
||||
*/
|
||||
public function testAfterException($exception, $message, $hint) {
|
||||
|
||||
$this->logger->expects($this->once())->method('error')
|
||||
->with($message, ['app' => 'AddServerMiddlewareTest']);
|
||||
|
||||
$this->l10n->expects($this->any())->method('t')
|
||||
->willReturnCallback(
|
||||
function($message) {
|
||||
return $message;
|
||||
}
|
||||
);
|
||||
|
||||
$result = $this->middleware->afterException($this->controller, 'method', $exception);
|
||||
|
||||
$this->assertSame(Http::STATUS_BAD_REQUEST,
|
||||
$result->getStatus()
|
||||
);
|
||||
|
||||
$data = $result->getData();
|
||||
|
||||
$this->assertSame($hint,
|
||||
$data['message']
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestAfterException() {
|
||||
return [
|
||||
[new HintException('message', 'hint'), 'message', 'hint'],
|
||||
[new \Exception('message'), 'message', 'Unknown error'],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Arthur Schiwon <blizzz@owncloud.com>
|
||||
* @author Frank Karlitschek <frank@owncloud.org>
|
||||
* @author Jakob Sack <mail@jakobsack.de>
|
||||
* @author Joas Schilling <nickvergessen@owncloud.com>
|
||||
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
|
||||
* @author Lukas Reschke <lukas@owncloud.com>
|
||||
* @author Robin Appelman <icewind@owncloud.com>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, 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/>
|
||||
*
|
||||
*/
|
||||
OCP\JSON::checkLoggedIn();
|
||||
OCP\JSON::callCheck();
|
||||
\OC::$server->getSession()->close();
|
||||
|
||||
|
||||
// Get data
|
||||
$dir = isset($_POST['dir']) ? (string)$_POST['dir'] : '';
|
||||
$allFiles = isset($_POST["allfiles"]) ? (string)$_POST["allfiles"] : false;
|
||||
|
||||
// delete all files in dir ?
|
||||
if ($allFiles === 'true') {
|
||||
$files = array();
|
||||
$fileList = \OC\Files\Filesystem::getDirectoryContent($dir);
|
||||
foreach ($fileList as $fileInfo) {
|
||||
$files[] = $fileInfo['name'];
|
||||
}
|
||||
} else {
|
||||
$files = isset($_POST["file"]) ? (string)$_POST["file"] : (string)$_POST["files"];
|
||||
$files = json_decode($files);
|
||||
}
|
||||
$filesWithError = '';
|
||||
|
||||
$success = true;
|
||||
|
||||
//Now delete
|
||||
foreach ($files as $file) {
|
||||
try {
|
||||
if (\OC\Files\Filesystem::file_exists($dir . '/' . $file) &&
|
||||
!(\OC\Files\Filesystem::isDeletable($dir . '/' . $file) &&
|
||||
\OC\Files\Filesystem::unlink($dir . '/' . $file))
|
||||
) {
|
||||
$filesWithError .= $file . "\n";
|
||||
$success = false;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$filesWithError .= $file . "\n";
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// get array with updated storage stats (e.g. max file size) after upload
|
||||
try {
|
||||
$storageStats = \OCA\Files\Helper::buildFileStorageStatistics($dir);
|
||||
} catch(\OCP\Files\NotFoundException $e) {
|
||||
OCP\JSON::error(['data' => ['message' => 'File not found']]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
OCP\JSON::success(array("data" => array_merge(array("dir" => $dir, "files" => $files), $storageStats)));
|
||||
} else {
|
||||
OCP\JSON::error(array("data" => array_merge(array("message" => "Could not delete:\n" . $filesWithError), $storageStats)));
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue