diff options
-rw-r--r-- | apps/lookup_server_connector/appinfo/app.php | 1 | ||||
-rw-r--r-- | core/css/styles.css | 5 | ||||
-rw-r--r-- | core/shipped.json | 1 | ||||
-rw-r--r-- | lib/base.php | 6 | ||||
-rw-r--r-- | lib/private/Accounts/AccountManager.php | 16 | ||||
-rw-r--r-- | lib/private/Accounts/Hooks.php | 98 | ||||
-rw-r--r-- | lib/private/Security/IdentityProof/Signer.php | 27 | ||||
-rw-r--r-- | lib/private/Updater.php | 131 | ||||
-rw-r--r-- | settings/Controller/UsersController.php | 115 | ||||
-rw-r--r-- | settings/routes.php | 1 | ||||
-rw-r--r-- | tests/Settings/Controller/UsersControllerTest.php | 323 | ||||
-rw-r--r-- | tests/lib/Accounts/AccountsManagerTest.php | 39 | ||||
-rw-r--r-- | tests/lib/Accounts/HooksTest.php | 157 | ||||
-rw-r--r-- | tests/lib/Security/IdentityProof/KeyTest.php | 45 | ||||
-rw-r--r-- | tests/lib/Security/IdentityProof/ManagerTest.php | 2 | ||||
-rw-r--r-- | tests/lib/Security/IdentityProof/SignerTest.php | 204 | ||||
-rw-r--r-- | version.php | 2 |
17 files changed, 1092 insertions, 81 deletions
diff --git a/apps/lookup_server_connector/appinfo/app.php b/apps/lookup_server_connector/appinfo/app.php index 6c63e9a0400..639eeafcf3f 100644 --- a/apps/lookup_server_connector/appinfo/app.php +++ b/apps/lookup_server_connector/appinfo/app.php @@ -37,7 +37,6 @@ $dispatcher->addListener('OC\AccountManager::userUpdated', function(\Symfony\Com new \OC\Security\IdentityProof\Signer( $keyManager, new \OC\AppFramework\Utility\TimeFactory(), - \OC::$server->getURLGenerator(), \OC::$server->getUserManager() ), \OC::$server->getJobList() diff --git a/core/css/styles.css b/core/css/styles.css index f0c4c4f33ff..21583d6198c 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -272,7 +272,6 @@ body { text-align: center; } #body-login p.info { - width: 22em; margin: 0 auto; padding-top: 20px; -webkit-user-select: none; @@ -426,10 +425,6 @@ label.infield { opacity: .6; } -#body-login footer .info { - white-space: nowrap; -} - /* Show password toggle */ #show, #dbpassword { position: absolute; diff --git a/core/shipped.json b/core/shipped.json index 7fb87b7f17d..d325117c67e 100644 --- a/core/shipped.json +++ b/core/shipped.json @@ -23,6 +23,7 @@ "gallery", "logreader", "lookup_server_connector", + "nextcloud_announcements", "notifications", "password_policy", "provisioning_api", diff --git a/lib/base.php b/lib/base.php index 7f5afd9a66c..7bd14de56b6 100644 --- a/lib/base.php +++ b/lib/base.php @@ -757,6 +757,7 @@ class OC { self::registerLogRotate(); self::registerEncryptionWrapper(); self::registerEncryptionHooks(); + self::registerAccountHooks(); self::registerSettingsHooks(); //make sure temporary files are cleaned up @@ -867,6 +868,11 @@ class OC { } } + private static function registerAccountHooks() { + $hookHandler = new \OC\Accounts\Hooks(\OC::$server->getLogger()); + \OCP\Util::connectHook('OC_User', 'changeUser', $hookHandler, 'changeUserHook'); + } + /** * register hooks for the cache */ diff --git a/lib/private/Accounts/AccountManager.php b/lib/private/Accounts/AccountManager.php index 6496a521326..3701421a20f 100644 --- a/lib/private/Accounts/AccountManager.php +++ b/lib/private/Accounts/AccountManager.php @@ -81,16 +81,22 @@ class AccountManager { */ public function updateUser(IUser $user, $data) { $userData = $this->getUser($user); + $updated = true; if (empty($userData)) { $this->insertNewUser($user, $data); - } else { + } elseif ($userData !== $data) { $this->updateExistingUser($user, $data); + } else { + // nothing needs to be done if new and old data set are the same + $updated = false; } - $this->eventDispatcher->dispatch( - 'OC\AccountManager::userUpdated', - new GenericEvent($user) - ); + if ($updated) { + $this->eventDispatcher->dispatch( + 'OC\AccountManager::userUpdated', + new GenericEvent($user) + ); + } } /** diff --git a/lib/private/Accounts/Hooks.php b/lib/private/Accounts/Hooks.php new file mode 100644 index 00000000000..38e7e20485b --- /dev/null +++ b/lib/private/Accounts/Hooks.php @@ -0,0 +1,98 @@ +<?php +/** + * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +namespace OC\Accounts; + +use OCP\ILogger; +use OCP\IUser; + +class Hooks { + + /** @var AccountManager */ + private $accountManager = null; + + /** @var ILogger */ + private $logger; + + /** + * Hooks constructor. + * + * @param ILogger $logger + */ + public function __construct(ILogger $logger) { + $this->logger = $logger; + } + + /** + * update accounts table if email address or display name was changed from outside + * + * @param array $params + */ + public function changeUserHook($params) { + + $accountManager = $this->getAccountManager(); + + /** @var IUser $user */ + $user = isset($params['user']) ? $params['user'] : null; + $feature = isset($params['feature']) ? $params['feature'] : null; + $newValue = isset($params['value']) ? $params['value'] : null; + + if (is_null($user) || is_null($feature) || is_null($newValue)) { + $this->logger->warning('Missing expected parameters in change user hook'); + return; + } + + $accountData = $accountManager->getUser($user); + + switch ($feature) { + case 'eMailAddress': + if ($accountData[AccountManager::PROPERTY_EMAIL]['value'] !== $newValue) { + $accountData[AccountManager::PROPERTY_EMAIL]['value'] = $newValue; + $accountManager->updateUser($user, $accountData); + } + break; + case 'displayName': + if ($accountData[AccountManager::PROPERTY_DISPLAYNAME]['value'] !== $newValue) { + $accountData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $newValue; + $accountManager->updateUser($user, $accountData); + } + break; + } + + } + + /** + * return instance of accountManager + * + * @return AccountManager + */ + protected function getAccountManager() { + if (is_null($this->accountManager)) { + $this->accountManager = new AccountManager( + \OC::$server->getDatabaseConnection(), + \OC::$server->getEventDispatcher() + ); + } + return $this->accountManager; + } + +} diff --git a/lib/private/Security/IdentityProof/Signer.php b/lib/private/Security/IdentityProof/Signer.php index 50c36b26966..169f284fe9d 100644 --- a/lib/private/Security/IdentityProof/Signer.php +++ b/lib/private/Security/IdentityProof/Signer.php @@ -22,7 +22,6 @@ namespace OC\Security\IdentityProof; use OCP\AppFramework\Utility\ITimeFactory; -use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserManager; @@ -31,20 +30,16 @@ class Signer { private $keyManager; /** @var ITimeFactory */ private $timeFactory; - /** @var IURLGenerator */ - private $urlGenerator; /** @var IUserManager */ private $userManager; /** * @param Manager $keyManager * @param ITimeFactory $timeFactory - * @param IURLGenerator $urlGenerator * @param IUserManager $userManager */ public function __construct(Manager $keyManager, ITimeFactory $timeFactory, - IURLGenerator $urlGenerator, IUserManager $userManager) { $this->keyManager = $keyManager; $this->timeFactory = $timeFactory; @@ -76,20 +71,6 @@ class Signer { } /** - * @param string $url - * @return string - */ - private function removeProtocolFromUrl($url) { - if (strpos($url, 'https://') === 0) { - return substr($url, strlen('https://')); - } else if (strpos($url, 'http://') === 0) { - return substr($url, strlen('http://')); - } - - return $url; - } - - /** * Whether the data is signed properly * * @param array $data @@ -100,9 +81,8 @@ class Signer { && isset($data['signature']) && isset($data['message']['signer']) ) { - $server = $this->urlGenerator->getAbsoluteURL('/'); - $postfix = strlen('@' . rtrim($this->removeProtocolFromUrl($server), '/')); - $userId = substr($data['message']['signer'], -$postfix); + $location = strrpos($data['message']['signer'], '@'); + $userId = substr($data['message']['signer'], 0, $location); $user = $this->userManager->get($userId); if($user !== null) { @@ -110,7 +90,8 @@ class Signer { return (bool)openssl_verify( json_encode($data['message']), base64_decode($data['signature']), - $key->getPublic() + $key->getPublic(), + OPENSSL_ALGO_SHA512 ); } } diff --git a/lib/private/Updater.php b/lib/private/Updater.php index c3d8ef9fea3..e30777227cc 100644 --- a/lib/private/Updater.php +++ b/lib/private/Updater.php @@ -102,6 +102,7 @@ class Updater extends BasicEmitter { */ public function upgrade() { $this->emitRepairEvents(); + $this->logAllEvents(); $logLevel = $this->config->getSystemValue('loglevel', Util::WARN); $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); @@ -477,5 +478,135 @@ class Updater extends BasicEmitter { }); } + private function logAllEvents() { + $log = $this->log; + + $dispatcher = \OC::$server->getEventDispatcher(); + $dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) { + if (!$event instanceof GenericEvent) { + return; + } + $log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']); + }); + $dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) { + if (!$event instanceof GenericEvent) { + return; + } + $log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']); + }); + + $repairListener = function($event) use ($log) { + if (!$event instanceof GenericEvent) { + return; + } + switch ($event->getSubject()) { + case '\OC\Repair::startProgress': + $log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']); + break; + case '\OC\Repair::advance': + $desc = $event->getArgument(1); + if (empty($desc)) { + $desc = ''; + } + $log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']); + + break; + case '\OC\Repair::finishProgress': + $log->info('\OC\Repair::finishProgress', ['app' => 'updater']); + break; + case '\OC\Repair::step': + $log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']); + break; + case '\OC\Repair::info': + $log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']); + break; + case '\OC\Repair::warning': + $log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']); + break; + case '\OC\Repair::error': + $log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']); + break; + } + }; + + $dispatcher->addListener('\OC\Repair::startProgress', $repairListener); + $dispatcher->addListener('\OC\Repair::advance', $repairListener); + $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener); + $dispatcher->addListener('\OC\Repair::step', $repairListener); + $dispatcher->addListener('\OC\Repair::info', $repairListener); + $dispatcher->addListener('\OC\Repair::warning', $repairListener); + $dispatcher->addListener('\OC\Repair::error', $repairListener); + + + $this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) { + $log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) { + $log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'maintenanceActive', function () use($log) { + $log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) { + if ($success) { + $log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']); + } else { + $log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']); + } + }); + $this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) { + $log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'dbUpgrade', function () use($log) { + $log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) { + $log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) { + $log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) { + $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use ($log) { + $log->info('\OC\Updater::thirdPartyAppDisabled: Disabled 3rd-party app: ' . $app, ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) { + $log->info('\OC\Updater::upgradeAppStoreApp: Update 3rd-party app: ' . $app, ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) { + $log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) { + $log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) { + $log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) { + $log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) { + $log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'failure', function ($message) use($log) { + $log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) { + $log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) { + $log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) { + $log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']); + }); + $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) { + $log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']); + }); + + } + } diff --git a/settings/Controller/UsersController.php b/settings/Controller/UsersController.php index 206f1872542..20440e6d395 100644 --- a/settings/Controller/UsersController.php +++ b/settings/Controller/UsersController.php @@ -536,7 +536,6 @@ class UsersController extends Controller { $twitterScope ) { - if(!empty($email) && !$this->mailer->validateMailAddress($email)) { return new DataResponse( array( @@ -549,8 +548,6 @@ class UsersController extends Controller { ); } - $user = $this->userSession->getUser(); - $data = [ AccountManager::PROPERTY_AVATAR => ['scope' => $avatarScope], AccountManager::PROPERTY_DISPLAYNAME => ['value' => $displayname, 'scope' => $displaynameScope], @@ -561,7 +558,7 @@ class UsersController extends Controller { AccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope] ]; - $this->accountManager->updateUser($user, $data); + $user = $this->userSession->getUser(); try { $this->saveUserSettings($user, $data); @@ -603,23 +600,30 @@ class UsersController extends Controller { * @param array $data * @throws ForbiddenException */ - private function saveUserSettings(IUser $user, $data) { + protected function saveUserSettings(IUser $user, $data) { // keep the user back-end up-to-date with the latest display name and email // address $oldDisplayName = $user->getDisplayName(); - if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value']) && $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']) { + if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value']) + && $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value'] + ) { $result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']); if ($result === false) { throw new ForbiddenException($this->l10n->t('Unable to change full name')); } } - if (isset($data['email'][0]['value']) && $user->getEMailAddress() !== $data['email'][0]['value']) { - $result = $user->setEMailAddress($data['email'][0]['value']); - if ($result === false) { - throw new ForbiddenException($this->l10n->t('Unable to change mail address')); + $oldEmailAddress = $user->getEMailAddress(); + if (isset($data[AccountManager::PROPERTY_EMAIL]['value']) + && $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value'] + ) { + // this is the only permission a backend provides and is also used + // for the permission of setting a email address + if (!$user->canChangeDisplayName()) { + throw new ForbiddenException($this->l10n->t('Unable to change email address')); } + $user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']); } $this->accountManager->updateUser($user, $data); @@ -720,4 +724,95 @@ class UsersController extends Controller { ]); } } + + /** + * Set the mail address of a user + * + * @NoAdminRequired + * @NoSubadminRequired + * @PasswordConfirmationRequired + * + * @param string $id + * @param string $mailAddress + * @return DataResponse + */ + public function setEMailAddress($id, $mailAddress) { + $user = $this->userManager->get($id); + if (!$this->isAdmin + && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user) + ) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Forbidden') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Invalid mail address') + ) + ), + Http::STATUS_UNPROCESSABLE_ENTITY + ); + } + + if (!$user) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Invalid user') + ) + ), + Http::STATUS_UNPROCESSABLE_ENTITY + ); + } + // this is the only permission a backend provides and is also used + // for the permission of setting a email address + if (!$user->canChangeDisplayName()) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Unable to change mail address') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + $userData = $this->accountManager->getUser($user); + $userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress; + + try { + $this->saveUserSettings($user, $userData); + return new DataResponse( + array( + 'status' => 'success', + 'data' => array( + 'username' => $id, + 'mailAddress' => $mailAddress, + 'message' => (string)$this->l10n->t('Email saved') + ) + ), + Http::STATUS_OK + ); + } catch (ForbiddenException $e) { + return new DataResponse([ + 'status' => 'error', + 'data' => [ + 'message' => $e->getMessage() + ], + ]); + } + } + } diff --git a/settings/routes.php b/settings/routes.php index 62cfc398fdc..3f034d363e2 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -51,6 +51,7 @@ $application->registerRoutes($this, [ ['name' => 'AppSettings#listApps', 'url' => '/settings/apps/list', 'verb' => 'GET'], ['name' => 'SecuritySettings#trustedDomains', 'url' => '/settings/admin/security/trustedDomains', 'verb' => 'POST'], ['name' => 'Users#setDisplayName', 'url' => '/settings/users/{username}/displayName', 'verb' => 'POST'], + ['name' => 'Users#setEMailAddress', 'url' => '/settings/users/{id}/mailAddress', 'verb' => 'PUT'], ['name' => 'Users#setUserSettings', 'url' => '/settings/users/{username}/settings', 'verb' => 'PUT'], ['name' => 'Users#stats', 'url' => '/settings/users/stats', 'verb' => 'GET'], ['name' => 'LogSettings#setLogLevel', 'url' => '/settings/admin/log/level', 'verb' => 'POST'], diff --git a/tests/Settings/Controller/UsersControllerTest.php b/tests/Settings/Controller/UsersControllerTest.php index ec92479b40e..69082a7929c 100644 --- a/tests/Settings/Controller/UsersControllerTest.php +++ b/tests/Settings/Controller/UsersControllerTest.php @@ -103,27 +103,51 @@ class UsersControllerTest extends \Test\TestCase { /** * @param bool $isAdmin - * @return UsersController + * @return UsersController | \PHPUnit_Framework_MockObject_MockObject */ - protected function getController($isAdmin) { - return new UsersController( - 'settings', - $this->createMock(IRequest::class), - $this->userManager, - $this->groupManager, - $this->userSession, - $this->config, - $isAdmin, - $this->l, - $this->logger, - $this->defaults, - $this->mailer, - 'no-reply@owncloud.com', - $this->urlGenerator, - $this->appManager, - $this->avatarManager, - $this->accountManager - ); + protected function getController($isAdmin = false, $mockedMethods = []) { + if (empty($mockedMethods)) { + return new UsersController( + 'settings', + $this->createMock(IRequest::class), + $this->userManager, + $this->groupManager, + $this->userSession, + $this->config, + $isAdmin, + $this->l, + $this->logger, + $this->defaults, + $this->mailer, + 'no-reply@owncloud.com', + $this->urlGenerator, + $this->appManager, + $this->avatarManager, + $this->accountManager + ); + } else { + return $this->getMockBuilder(UsersController::class) + ->setConstructorArgs( + [ + 'settings', + $this->createMock(IRequest::class), + $this->userManager, + $this->groupManager, + $this->userSession, + $this->config, + $isAdmin, + $this->l, + $this->logger, + $this->defaults, + $this->mailer, + 'no-reply@owncloud.com', + $this->urlGenerator, + $this->appManager, + $this->avatarManager, + $this->accountManager + ] + )->setMethods($mockedMethods)->getMock(); + } } public function testIndexAdmin() { @@ -2010,4 +2034,263 @@ class UsersControllerTest extends \Test\TestCase { $response = $controller->setDisplayName($user->getUID(), 'newDisplayName'); $this->assertEquals($expectedResponse, $response); } + + /** + * @dataProvider dataTestSetUserSettings + * + * @param string $email + * @param bool $validEmail + * @param $expectedStatus + */ + public function testSetUserSettings($email, $validEmail, $expectedStatus) { + $controller = $this->getController(false, ['saveUserSettings']); + $user = $this->createMock(IUser::class); + + $this->userSession->method('getUser')->willReturn($user); + + if (!empty($email) && $validEmail) { + $this->mailer->expects($this->once())->method('validateMailAddress') + ->willReturn($validEmail); + } + + $saveData = (!empty($email) && $validEmail) || empty($email); + + if ($saveData) { + $controller->expects($this->once())->method('saveUserSettings'); + } else { + $controller->expects($this->never())->method('saveUserSettings'); + } + + $result = $controller->setUserSettings( + AccountManager::VISIBILITY_CONTACTS_ONLY, + 'displayName', + AccountManager::VISIBILITY_CONTACTS_ONLY, + '47658468', + AccountManager::VISIBILITY_CONTACTS_ONLY, + $email, + AccountManager::VISIBILITY_CONTACTS_ONLY, + 'nextcloud.com', + AccountManager::VISIBILITY_CONTACTS_ONLY, + 'street and city', + AccountManager::VISIBILITY_CONTACTS_ONLY, + '@nextclouders', + AccountManager::VISIBILITY_CONTACTS_ONLY + ); + + $this->assertSame($expectedStatus, $result->getStatus()); + } + + public function dataTestSetUserSettings() { + return [ + ['', true, Http::STATUS_OK], + ['', false, Http::STATUS_OK], + ['example.com', false, Http::STATUS_UNPROCESSABLE_ENTITY], + ['john@example.com', true, Http::STATUS_OK], + ]; + } + + /** + * @dataProvider dataTestSaveUserSettings + * + * @param array $data + * @param string $oldEmailAddress + * @param string $oldDisplayName + */ + public function testSaveUserSettings($data, + $oldEmailAddress, + $oldDisplayName + ) { + $controller = $this->getController(); + $user = $this->createMock(IUser::class); + + $user->method('getDisplayName')->willReturn($oldDisplayName); + $user->method('getEMailAddress')->willReturn($oldEmailAddress); + $user->method('canChangeDisplayName')->willReturn(true); + + if ($data[AccountManager::PROPERTY_EMAIL]['value'] !== $oldEmailAddress) { + $user->expects($this->once())->method('setEMailAddress') + ->with($data[AccountManager::PROPERTY_EMAIL]['value']) + ->willReturn(true); + } else { + $user->expects($this->never())->method('setEMailAddress'); + } + + if ($data[AccountManager::PROPERTY_DISPLAYNAME]['value'] !== $oldDisplayName) { + $user->expects($this->once())->method('setDisplayName') + ->with($data[AccountManager::PROPERTY_DISPLAYNAME]['value']) + ->willReturn(true); + } else { + $user->expects($this->never())->method('setDisplayName'); + } + + $this->accountManager->expects($this->once())->method('updateUser') + ->with($user, $data); + + $this->invokePrivate($controller, 'saveUserSettings', [$user, $data]); + } + + public function dataTestSaveUserSettings() { + return [ + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'john@example.com', + 'john doe' + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'johnNew@example.com', + 'john New doe' + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'johnNew@example.com', + 'john doe' + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'john@example.com', + 'john New doe' + ] + + ]; + } + + /** + * @dataProvider dataTestSaveUserSettingsException + * + * @param array $data + * @param string $oldEmailAddress + * @param string $oldDisplayName + * @param bool $setDisplayNameResult + * @param bool $canChangeEmail + * + * @expectedException \OC\ForbiddenException + */ + public function testSaveUserSettingsException($data, + $oldEmailAddress, + $oldDisplayName, + $setDisplayNameResult, + $canChangeEmail + ) { + $controller = $this->getController(); + $user = $this->createMock(IUser::class); + + $user->method('getDisplayName')->willReturn($oldDisplayName); + $user->method('getEMailAddress')->willReturn($oldEmailAddress); + + if ($data[AccountManager::PROPERTY_EMAIL]['value'] !== $oldEmailAddress) { + $user->method('canChangeDisplayName') + ->willReturn($canChangeEmail); + } + + if ($data[AccountManager::PROPERTY_DISPLAYNAME]['value'] !== $oldDisplayName) { + $user->method('setDisplayName') + ->with($data[AccountManager::PROPERTY_DISPLAYNAME]['value']) + ->willReturn($setDisplayNameResult); + } + + $this->invokePrivate($controller, 'saveUserSettings', [$user, $data]); + } + + + public function dataTestSaveUserSettingsException() { + return [ + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'johnNew@example.com', + 'john New doe', + true, + false + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'johnNew@example.com', + 'john New doe', + false, + true + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'johnNew@example.com', + 'john New doe', + false, + false + ], + + ]; + } + + /** + * @return array + */ + public function setEmailAddressData() { + return [ + /* mailAddress, isValid, expectsUpdate, canChangeDisplayName, responseCode */ + [ '', true, true, true, Http::STATUS_OK ], + [ 'foo@local', true, true, true, Http::STATUS_OK], + [ 'foo@bar@local', false, false, true, Http::STATUS_UNPROCESSABLE_ENTITY], + [ 'foo@local', true, false, false, Http::STATUS_FORBIDDEN], + ]; + } + /** + * @dataProvider setEmailAddressData + * + */ + public function testSetEMailAddress($mailAddress, $isValid, $expectsUpdate, $canChangeDisplayName, $responseCode) { + $user = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor()->getMock(); + $user + ->expects($this->any()) + ->method('getUID') + ->will($this->returnValue('foo')); + $user + ->expects($this->any()) + ->method('canChangeDisplayName') + ->will($this->returnValue($canChangeDisplayName)); + $user + ->expects($expectsUpdate ? $this->once() : $this->never()) + ->method('setEMailAddress') + ->with( + $this->equalTo($mailAddress) + ); + $this->mailer + ->expects($this->any()) + ->method('validateMailAddress') + ->with($mailAddress) + ->willReturn($isValid); + if ($isValid) { + $user->expects($this->atLeastOnce()) + ->method('canChangeDisplayName') + ->willReturn(true); + $this->userManager + ->expects($this->atLeastOnce()) + ->method('get') + ->with('foo') + ->will($this->returnValue($user)); + } + $controller = $this->getController(true); + $response = $controller->setEMailAddress($user->getUID(), $mailAddress); + $this->assertSame($responseCode, $response->getStatus()); + } } diff --git a/tests/lib/Accounts/AccountsManagerTest.php b/tests/lib/Accounts/AccountsManagerTest.php index de88fbcab97..60811140e72 100644 --- a/tests/lib/Accounts/AccountsManagerTest.php +++ b/tests/lib/Accounts/AccountsManagerTest.php @@ -78,36 +78,45 @@ class AccountsManagerTest extends TestCase { * * @param bool $userAlreadyExists */ - public function testUpdateUser($userAlreadyExists) { + public function testUpdateUser($newData, $oldData, $insertNew, $updateExisitng) { $accountManager = $this->getInstance(['getUser', 'insertNewUser', 'updateExistingUser']); $user = $this->getMockBuilder('OCP\IUser')->getMock(); - $accountManager->expects($this->once())->method('getUser')->with($user)->willReturn($userAlreadyExists); + $accountManager->expects($this->once())->method('getUser')->with($user)->willReturn($oldData); - if ($userAlreadyExists) { + if ($updateExisitng) { $accountManager->expects($this->once())->method('updateExistingUser') - ->with($user, 'data'); + ->with($user, $newData); $accountManager->expects($this->never())->method('insertNewUser'); - } else { + } + if ($insertNew) { $accountManager->expects($this->once())->method('insertNewUser') - ->with($user, 'data'); + ->with($user, $newData); $accountManager->expects($this->never())->method('updateExistingUser'); } - $this->eventDispatcher->expects($this->once())->method('dispatch') - ->willReturnCallback(function($eventName, $event) use ($user) { - $this->assertSame('OC\AccountManager::userUpdated', $eventName); - $this->assertInstanceOf('Symfony\Component\EventDispatcher\GenericEvent', $event); - } - ); + if (!$insertNew && !$updateExisitng) { + $accountManager->expects($this->never())->method('updateExistingUser'); + $accountManager->expects($this->never())->method('insertNewUser'); + $this->eventDispatcher->expects($this->never())->method('dispatch'); + } else { + $this->eventDispatcher->expects($this->once())->method('dispatch') + ->willReturnCallback( + function ($eventName, $event) use ($user) { + $this->assertSame('OC\AccountManager::userUpdated', $eventName); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\GenericEvent', $event); + } + ); + } - $accountManager->updateUser($user, 'data'); + $accountManager->updateUser($user, $newData); } public function dataTrueFalse() { return [ - [true], - [false] + [['newData'], ['oldData'], false, true], + [['newData'], [], true, false], + [['oldData'], ['oldData'], false, false] ]; } diff --git a/tests/lib/Accounts/HooksTest.php b/tests/lib/Accounts/HooksTest.php new file mode 100644 index 00000000000..071e78146ea --- /dev/null +++ b/tests/lib/Accounts/HooksTest.php @@ -0,0 +1,157 @@ +<?php +/** + * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +namespace Test\Accounts; + + +use OC\Accounts\AccountManager; +use OC\Accounts\Hooks; +use OCP\ILogger; +use OCP\IUser; +use Test\TestCase; + +/** + * Class HooksTest + * + * @package Test\Accounts + * @group DB + */ +class HooksTest extends TestCase { + + /** @var ILogger | \PHPUnit_Framework_MockObject_MockObject */ + private $logger; + + /** @var AccountManager | \PHPUnit_Framework_MockObject_MockObject */ + private $accountManager; + + /** @var Hooks | \PHPUnit_Framework_MockObject_MockObject */ + private $hooks; + + public function setUp() { + parent::setUp(); + + $this->logger = $this->createMock(ILogger::class); + $this->accountManager = $this->getMockBuilder(AccountManager::class) + ->disableOriginalConstructor()->getMock(); + + $this->hooks = $this->getMockBuilder(Hooks::class) + ->setConstructorArgs([$this->logger]) + ->setMethods(['getAccountManager']) + ->getMock(); + + $this->hooks->method('getAccountManager')->willReturn($this->accountManager); + } + + /** + * @dataProvider dataTestChangeUserHook + * + * @param $params + * @param $data + * @param $setEmail + * @param $setDisplayName + * @param $error + */ + public function testChangeUserHook($params, $data, $setEmail, $setDisplayName, $error) { + if ($error) { + $this->accountManager->expects($this->never())->method('getUser'); + $this->accountManager->expects($this->never())->method('updateUser'); + } else { + $this->accountManager->expects($this->once())->method('getUser')->willReturn($data); + $newData = $data; + if ($setEmail) { + $newData[AccountManager::PROPERTY_EMAIL]['value'] = $params['value']; + $this->accountManager->expects($this->once())->method('updateUser') + ->with($params['user'], $newData); + } elseif ($setDisplayName) { + $newData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $params['value']; + $this->accountManager->expects($this->once())->method('updateUser') + ->with($params['user'], $newData); + } else { + $this->accountManager->expects($this->never())->method('updateUser'); + } + } + + $this->hooks->changeUserHook($params); + + } + + public function dataTestChangeUserHook() { + $user = $this->createMock(IUser::class); + return [ + [ + ['feature' => '', 'value' => ''], + [ + AccountManager::PROPERTY_EMAIL => ['value' => ''], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => ''] + ], + false, false, true + ], + [ + ['user' => $user, 'value' => ''], + [ + AccountManager::PROPERTY_EMAIL => ['value' => ''], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => ''] + ], + false, false, true + ], + [ + ['user' => $user, 'feature' => ''], + [ + AccountManager::PROPERTY_EMAIL => ['value' => ''], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => ''] + ], + false, false, true + ], + [ + ['user' => $user, 'feature' => 'foo', 'value' => 'bar'], + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'oldMail@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName'] + ], + false, false, false + ], + [ + ['user' => $user, 'feature' => 'eMailAddress', 'value' => 'newMail@example.com'], + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'oldMail@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName'] + ], + true, false, false + ], + [ + ['user' => $user, 'feature' => 'displayName', 'value' => 'newDisplayName'], + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'oldMail@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName'] + ], + false, true, false + ], + ]; + } + + public function testGetAccountManager() { + $hooks = new Hooks($this->logger); + $result = $this->invokePrivate($hooks, 'getAccountManager'); + $this->assertInstanceOf(AccountManager::class, $result); + } + +} diff --git a/tests/lib/Security/IdentityProof/KeyTest.php b/tests/lib/Security/IdentityProof/KeyTest.php new file mode 100644 index 00000000000..0468afe633a --- /dev/null +++ b/tests/lib/Security/IdentityProof/KeyTest.php @@ -0,0 +1,45 @@ +<?php +/** + * @copyright 2016, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace Test\Security\IdentityProof; + +use OC\Security\IdentityProof\Key; +use Test\TestCase; + +class KeyTest extends TestCase { + /** @var Key */ + private $key; + + public function setUp() { + parent::setUp(); + + $this->key = new Key('public', 'private'); + } + + public function testGetPrivate() { + $this->assertSame('private', $this->key->getPrivate()); + } + + public function testGetPublic() { + $this->assertSame('public', $this->key->getPublic()); + } +} diff --git a/tests/lib/Security/IdentityProof/ManagerTest.php b/tests/lib/Security/IdentityProof/ManagerTest.php index d93f675825b..2925dea5ec5 100644 --- a/tests/lib/Security/IdentityProof/ManagerTest.php +++ b/tests/lib/Security/IdentityProof/ManagerTest.php @@ -19,7 +19,7 @@ * */ -namespace Test\Security; +namespace Test\Security\IdentityProof; use OC\Security\IdentityProof\Key; use OC\Security\IdentityProof\Manager; diff --git a/tests/lib/Security/IdentityProof/SignerTest.php b/tests/lib/Security/IdentityProof/SignerTest.php new file mode 100644 index 00000000000..f12e6d94be3 --- /dev/null +++ b/tests/lib/Security/IdentityProof/SignerTest.php @@ -0,0 +1,204 @@ +<?php +/** + * @copyright 2016, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace Test\Security\IdentityProof; + +use OC\Security\IdentityProof\Key; +use OC\Security\IdentityProof\Manager; +use OC\Security\IdentityProof\Signer; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\IUser; +use OCP\IUserManager; +use Test\TestCase; + +class SignerTest extends TestCase { + + /** @var string */ + private $private = '-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDImc6QvHBjBIoo +w9nnywiPNESleUuFJ2yQ3Gd/3w2BkblojlUAJAsUd/bQokjOH9d+7nqyzgSiXjRl +iwKagY6NjcNEEq0X5KOMNwx6uEbtq3+7pA7H2JefNrnAuD+Fhp3Hyo3h1cse6hAq +6Zr8haCiSdFBfelLnx/X3gPgCzgl6GnvSmiqPEPFGng822dlW2RW+IIUv4y2LoIH +2PKZpxottxtFGIpcKSSHGUfNWya7Ih4E6RBgOrpyu4hrkikl4Xdh4RVgAf/GH54F +gQi/AFeRS6llXJhep3lZOtLnFdYNPKFz1i/UvBoyUv8lrsvNa76HIgSMmGQKON4i +QO0P/OaBAgMBAAECggEAdrtCnjxKsPDQ7Yvuf9mWeVxQfTir0GYjRiKOSAs3rUcZ +XJ9SBEFRJY5T0e0b9pS2MfTpPsfdylTD4o5CvjyMqZAM0U/Uj93OR4GVq1VC9g2a +Du/tp6+1HpF/pGfpgRjKbqSfEdo+3U9gvmWCTJCzIRtb9c2WtiG68UQBOyyo0RYQ +F2b4az2BEOa7mATgwwGfdhV4VTQ18+iQKtfVoguw0bi1khDA0t+o8phhhmBHlOOi +lpV5uSnJB7H3s6B01xf1dA44y57bcFNKL4THQv9dlazL2R2DhgxmADWXGPyJs0YM +mhRSB25pEcFvLu//e0fHpO+kmZ+MPsey5blH3D92+QKBgQDzmlYIWSvNWXejKMdH +QGVQmrG9nExld3LhNERONhh4FaxoXOqVZgLqAAUaSMHawYzfYjRaLuW16UTYh0XC +hs2ISE5Oc4abDc6obNs2Xalrxp9stmD/Ti+/aSQifm2SoIeIH2lcPYob5yh/bfqh +AP/Uk9ZdDSnHcsGm6wzhCmS1UwKBgQDSzz0ogjtsmPa14jIHrHZluzbfbqOgaeQi +5WZPPbuEqdS37kaDznt4goDLOywqWUGrmBtBPi2hOqGF0K7qzUvlM0mlvedvjH1l +4JByb6gXwGoZPnnzTCfDx86gKB1+rWzVbo236dHi1oirZ52voKu57TqC8My5MTzW +YFgi872GWwKBgQCkxLd8XhQqiWFKksJ3hy8AHiIqxhVGbEzf1qJ85EoYr1A2JuLk +umMuM2VAKgY1GMVYMuyGM0JckLNoYdblhJhwnbeZiLp7FhO6CCcd1qxJoccjmRhy +l0fkiBFQ44Lpsnr5r4VsRpOr2+agipsDW9Guz3Am8EhaB1zEsie773O+0QKBgFb/ +W3fqNufcQIRTMt5j2ACnwD95A2HiEVotXYl6KnbXN4god0VR4zaadNhqNRHNAAL2 +pNjJ9j7BWYNF2cngq1+NSOlzc51fVyjCAhqX5cDXkXGVjPJRDWAIh0clBvcOTwnN +tAKgJhP9AS3rdvHR1szGEA2VnocWwMqfu//AowhdAoGACYwuBjfUWc21jcT5yeLZ +ahLp+ImQsKDE0swhmk4uesbLLPRfyvpLca98XbBMuS1iLrVUY3mEfIV7ltaBajE0 +l3eB7suqch3WUzH1RMWzwpuUMWV/A8qjPbIrd2QYUFYxJsU88lBqRg92rPnri6Ec +kC6HCb+CXsMRD7yp8KrrYnw= +-----END PRIVATE KEY-----'; + + /** @var string */ + private $public = '-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyJnOkLxwYwSKKMPZ58sI +jzREpXlLhSdskNxnf98NgZG5aI5VACQLFHf20KJIzh/Xfu56ss4Eol40ZYsCmoGO +jY3DRBKtF+SjjDcMerhG7at/u6QOx9iXnza5wLg/hYadx8qN4dXLHuoQKuma/IWg +oknRQX3pS58f194D4As4Jehp70poqjxDxRp4PNtnZVtkVviCFL+Mti6CB9jymaca +LbcbRRiKXCkkhxlHzVsmuyIeBOkQYDq6cruIa5IpJeF3YeEVYAH/xh+eBYEIvwBX +kUupZVyYXqd5WTrS5xXWDTyhc9Yv1LwaMlL/Ja7LzWu+hyIEjJhkCjjeIkDtD/zm +gQIDAQAB +-----END PUBLIC KEY-----'; + + /** @var Key */ + private $key; + + /** @var Manager|\PHPUnit_Framework_MockObject_MockObject */ + private $keyManager; + + /** @var ITimeFactory|\PHPUnit_Framework_MockObject_MockObject */ + private $timeFactory; + + /** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */ + private $userManager; + + /** @var Signer */ + private $signer; + + public function setUp() { + parent::setUp(); + + $this->key = new Key($this->public, $this->private); + + $this->keyManager = $this->createMock(Manager::class); + $this->timeFactory = $this->createMock(ITimeFactory::class); + $this->userManager = $this->createMock(IUserManager::class); + + $this->signer = new Signer( + $this->keyManager, + $this->timeFactory, + $this->userManager + ); + } + + public function testSign() { + $user = $this->createMock(IUser::class); + $user->method('getCloudId') + ->willReturn('foo@example.com'); + + $this->timeFactory->method('getTime') + ->willReturn(42); + + $this->keyManager->method('getKey') + ->with($this->equalTo($user)) + ->willReturn($this->key); + + $data = [ + 'foo' => 'bar', + 'abc' => 'def', + 'xyz' => 123, + ]; + + $expects = [ + 'message' => [ + 'data' => $data, + 'type' => 'myType', + 'signer' => 'foo@example.com', + 'timestamp' => 42, + ], + 'signature' => 'E1fNdoWMX1QmSyKv+S3FtOgLe9niYGQFWOKGaMLxc2h7s3V++EIqJvw/NCLBfrUowzWkTzhkjfbHaf88Hz34WAn4sAwXYAO8cnboQs6SClKRzQ/nvbtLgd2wm9RQ8UTOM7wR6C7HpIn4qqJ4BTQ1bAwYAiJ2GoK+W8wC0o0Gpub2906j3JJ4cbc9lufd5ohWKCev8Ubem/EEKaRIZA7qHh+Q1MKXTaJQJlCjTMe5PyGy0fsmtVxsPls3/Fkd9sVeHEHSYHzOiF6ttlxWou4TdRbq3WSEVpt1DOOvkKI9w2+zBJ7IPH8CnVpXcdIzWDctUygZKzNMUQnweDOOziEdUw==' + ]; + + $result = $this->signer->sign('myType', $data, $user); + + $this->assertEquals($expects, $result); + } + + public function testVerifyValid() { + $data = [ + 'message' => [ + 'data' => [ + 'foo' => 'bar', + 'abc' => 'def', + 'xyz' => 123, + ], + 'type' => 'myType', + 'signer' => 'foo@example.com', + 'timestamp' => 42, + ], + 'signature' => 'E1fNdoWMX1QmSyKv+S3FtOgLe9niYGQFWOKGaMLxc2h7s3V++EIqJvw/NCLBfrUowzWkTzhkjfbHaf88Hz34WAn4sAwXYAO8cnboQs6SClKRzQ/nvbtLgd2wm9RQ8UTOM7wR6C7HpIn4qqJ4BTQ1bAwYAiJ2GoK+W8wC0o0Gpub2906j3JJ4cbc9lufd5ohWKCev8Ubem/EEKaRIZA7qHh+Q1MKXTaJQJlCjTMe5PyGy0fsmtVxsPls3/Fkd9sVeHEHSYHzOiF6ttlxWou4TdRbq3WSEVpt1DOOvkKI9w2+zBJ7IPH8CnVpXcdIzWDctUygZKzNMUQnweDOOziEdUw==' + ]; + + $user = $this->createMock(IUser::class); + + $this->keyManager->method('getKey') + ->with($this->equalTo($user)) + ->willReturn($this->key); + + $this->userManager->method('get') + ->with('foo') + ->willReturn($user); + + $this->assertTrue($this->signer->verify($data)); + } + + public function testVerifyInvalid() { + $data = [ + 'message' => [ + 'data' => [ + 'foo' => 'bar', + 'abc' => 'def', + 'xyz' => 123, + ], + 'type' => 'myType', + 'signer' => 'foo@example.com', + 'timestamp' => 42, + ], + 'signature' => 'Invalid sig' + ]; + + $user = $this->createMock(IUser::class); + + $this->keyManager->method('getKey') + ->with($this->equalTo($user)) + ->willReturn($this->key); + + $this->userManager->method('get') + ->with('foo') + ->willReturn($user); + + $this->assertFalse($this->signer->verify($data)); + } + + public function testVerifyInvalidData() { + $data = [ + ]; + + $this->assertFalse($this->signer->verify($data)); + } + + +} diff --git a/version.php b/version.php index 4aef5b12d77..47c3ca4f236 100644 --- a/version.php +++ b/version.php @@ -26,7 +26,7 @@ // between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel // when updating major/minor version number. -$OC_Version = array(11, 0, 0, 2); +$OC_Version = array(11, 0, 0, 4); // The human readable string $OC_VersionString = '11.0 beta'; |