summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/lookup_server_connector/appinfo/app.php1
-rw-r--r--core/css/styles.css5
-rw-r--r--core/shipped.json1
-rw-r--r--lib/base.php6
-rw-r--r--lib/private/Accounts/AccountManager.php16
-rw-r--r--lib/private/Accounts/Hooks.php98
-rw-r--r--lib/private/Security/IdentityProof/Signer.php27
-rw-r--r--lib/private/Updater.php131
-rw-r--r--settings/Controller/UsersController.php115
-rw-r--r--settings/routes.php1
-rw-r--r--tests/Settings/Controller/UsersControllerTest.php323
-rw-r--r--tests/lib/Accounts/AccountsManagerTest.php39
-rw-r--r--tests/lib/Accounts/HooksTest.php157
-rw-r--r--tests/lib/Security/IdentityProof/KeyTest.php45
-rw-r--r--tests/lib/Security/IdentityProof/ManagerTest.php2
-rw-r--r--tests/lib/Security/IdentityProof/SignerTest.php204
-rw-r--r--version.php2
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';