diff options
Diffstat (limited to 'lib/private/User')
-rw-r--r-- | lib/private/User/LoginException.php | 26 | ||||
-rw-r--r-- | lib/private/User/Manager.php | 371 | ||||
-rw-r--r-- | lib/private/User/NoUserException.php | 24 | ||||
-rw-r--r-- | lib/private/User/Session.php | 322 | ||||
-rw-r--r-- | lib/private/User/User.php | 420 |
5 files changed, 1163 insertions, 0 deletions
diff --git a/lib/private/User/LoginException.php b/lib/private/User/LoginException.php new file mode 100644 index 00000000000..84426f7f5da --- /dev/null +++ b/lib/private/User/LoginException.php @@ -0,0 +1,26 @@ +<?php +/** + * @author Morris Jobke <hey@morrisjobke.de> + * @author Robin Appelman <icewind@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\User; + +class LoginException extends \Exception { +} diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php new file mode 100644 index 00000000000..37a3e5ba134 --- /dev/null +++ b/lib/private/User/Manager.php @@ -0,0 +1,371 @@ +<?php +/** + * @author Arthur Schiwon <blizzz@owncloud.com> + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Jörn Friedrich Dreyer <jfd@butonic.de> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Michael U <mdusher@users.noreply.github.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author RealRancor <Fisch.666@gmx.de> + * @author Robin Appelman <icewind@owncloud.com> + * @author Robin McCorkell <robin@mccorkell.me.uk> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Vincent Chan <plus.vincchan@gmail.com> + * @author Volkan Gezer <volkangezer@gmail.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\User; + +use OC\Hooks\PublicEmitter; +use OCP\IUser; +use OCP\IUserBackend; +use OCP\IUserManager; +use OCP\IConfig; + +/** + * Class Manager + * + * Hooks available in scope \OC\User: + * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - preDelete(\OC\User\User $user) + * - postDelete(\OC\User\User $user) + * - preCreateUser(string $uid, string $password) + * - postCreateUser(\OC\User\User $user, string $password) + * - change(\OC\User\User $user) + * + * @package OC\User + */ +class Manager extends PublicEmitter implements IUserManager { + /** + * @var \OCP\UserInterface[] $backends + */ + private $backends = array(); + + /** + * @var \OC\User\User[] $cachedUsers + */ + private $cachedUsers = array(); + + /** + * @var \OCP\IConfig $config + */ + private $config; + + /** + * @param \OCP\IConfig $config + */ + public function __construct(IConfig $config = null) { + $this->config = $config; + $cachedUsers = &$this->cachedUsers; + $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) { + /** @var \OC\User\User $user */ + unset($cachedUsers[$user->getUID()]); + }); + $this->listen('\OC\User', 'postLogin', function ($user) { + /** @var \OC\User\User $user */ + $user->updateLastLoginTimestamp(); + }); + $this->listen('\OC\User', 'postRememberedLogin', function ($user) { + /** @var \OC\User\User $user */ + $user->updateLastLoginTimestamp(); + }); + } + + /** + * Get the active backends + * @return \OCP\UserInterface[] + */ + public function getBackends() { + return $this->backends; + } + + /** + * register a user backend + * + * @param \OCP\UserInterface $backend + */ + public function registerBackend($backend) { + $this->backends[] = $backend; + } + + /** + * remove a user backend + * + * @param \OCP\UserInterface $backend + */ + public function removeBackend($backend) { + $this->cachedUsers = array(); + if (($i = array_search($backend, $this->backends)) !== false) { + unset($this->backends[$i]); + } + } + + /** + * remove all user backends + */ + public function clearBackends() { + $this->cachedUsers = array(); + $this->backends = array(); + } + + /** + * get a user by user id + * + * @param string $uid + * @return \OC\User\User|null Either the user or null if the specified user does not exist + */ + public function get($uid) { + if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends + return $this->cachedUsers[$uid]; + } + foreach ($this->backends as $backend) { + if ($backend->userExists($uid)) { + return $this->getUserObject($uid, $backend); + } + } + return null; + } + + /** + * get or construct the user object + * + * @param string $uid + * @param \OCP\UserInterface $backend + * @param bool $cacheUser If false the newly created user object will not be cached + * @return \OC\User\User + */ + protected function getUserObject($uid, $backend, $cacheUser = true) { + if (isset($this->cachedUsers[$uid])) { + return $this->cachedUsers[$uid]; + } + + $user = new User($uid, $backend, $this, $this->config); + if ($cacheUser) { + $this->cachedUsers[$uid] = $user; + } + return $user; + } + + /** + * check if a user exists + * + * @param string $uid + * @return bool + */ + public function userExists($uid) { + $user = $this->get($uid); + return ($user !== null); + } + + /** + * Check if the password is valid for the user + * + * @param string $loginName + * @param string $password + * @return mixed the User object on success, false otherwise + */ + public function checkPassword($loginName, $password) { + $loginName = str_replace("\0", '', $loginName); + $password = str_replace("\0", '', $password); + + foreach ($this->backends as $backend) { + if ($backend->implementsActions(\OC_User_Backend::CHECK_PASSWORD)) { + $uid = $backend->checkPassword($loginName, $password); + if ($uid !== false) { + return $this->getUserObject($uid, $backend); + } + } + } + + \OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']); + return false; + } + + /** + * search by user id + * + * @param string $pattern + * @param int $limit + * @param int $offset + * @return \OC\User\User[] + */ + public function search($pattern, $limit = null, $offset = null) { + $users = array(); + foreach ($this->backends as $backend) { + $backendUsers = $backend->getUsers($pattern, $limit, $offset); + if (is_array($backendUsers)) { + foreach ($backendUsers as $uid) { + $users[$uid] = $this->getUserObject($uid, $backend); + } + } + } + + uasort($users, function ($a, $b) { + /** + * @var \OC\User\User $a + * @var \OC\User\User $b + */ + return strcmp($a->getUID(), $b->getUID()); + }); + return $users; + } + + /** + * search by displayName + * + * @param string $pattern + * @param int $limit + * @param int $offset + * @return \OC\User\User[] + */ + public function searchDisplayName($pattern, $limit = null, $offset = null) { + $users = array(); + foreach ($this->backends as $backend) { + $backendUsers = $backend->getDisplayNames($pattern, $limit, $offset); + if (is_array($backendUsers)) { + foreach ($backendUsers as $uid => $displayName) { + $users[] = $this->getUserObject($uid, $backend); + } + } + } + + usort($users, function ($a, $b) { + /** + * @var \OC\User\User $a + * @var \OC\User\User $b + */ + return strcmp($a->getDisplayName(), $b->getDisplayName()); + }); + return $users; + } + + /** + * @param string $uid + * @param string $password + * @throws \Exception + * @return bool|\OC\User\User the created user or false + */ + public function createUser($uid, $password) { + $l = \OC::$server->getL10N('lib'); + // Check the name for bad characters + // Allowed are: "a-z", "A-Z", "0-9" and "_.@-'" + if (preg_match('/[^a-zA-Z0-9 _\.@\-\']/', $uid)) { + throw new \Exception($l->t('Only the following characters are allowed in a username:' + . ' "a-z", "A-Z", "0-9", and "_.@-\'"')); + } + // No empty username + if (trim($uid) == '') { + throw new \Exception($l->t('A valid username must be provided')); + } + // No whitespace at the beginning or at the end + if (strlen(trim($uid, "\t\n\r\0\x0B\xe2\x80\x8b")) !== strlen(trim($uid))) { + throw new \Exception($l->t('Username contains whitespace at the beginning or at the end')); + } + // No empty password + if (trim($password) == '') { + throw new \Exception($l->t('A valid password must be provided')); + } + + // Check if user already exists + if ($this->userExists($uid)) { + throw new \Exception($l->t('The username is already being used')); + } + + $this->emit('\OC\User', 'preCreateUser', array($uid, $password)); + foreach ($this->backends as $backend) { + if ($backend->implementsActions(\OC_User_Backend::CREATE_USER)) { + $backend->createUser($uid, $password); + $user = $this->getUserObject($uid, $backend); + $this->emit('\OC\User', 'postCreateUser', array($user, $password)); + return $user; + } + } + return false; + } + + /** + * returns how many users per backend exist (if supported by backend) + * + * @return array an array of backend class as key and count number as value + */ + public function countUsers() { + $userCountStatistics = array(); + foreach ($this->backends as $backend) { + if ($backend->implementsActions(\OC_User_Backend::COUNT_USERS)) { + $backendUsers = $backend->countUsers(); + if($backendUsers !== false) { + if($backend instanceof IUserBackend) { + $name = $backend->getBackendName(); + } else { + $name = get_class($backend); + } + if(isset($userCountStatistics[$name])) { + $userCountStatistics[$name] += $backendUsers; + } else { + $userCountStatistics[$name] = $backendUsers; + } + } + } + } + return $userCountStatistics; + } + + /** + * The callback is executed for each user on each backend. + * If the callback returns false no further users will be retrieved. + * + * @param \Closure $callback + * @param string $search + * @since 9.0.0 + */ + public function callForAllUsers(\Closure $callback, $search = '') { + foreach($this->getBackends() as $backend) { + $limit = 500; + $offset = 0; + do { + $users = $backend->getUsers($search, $limit, $offset); + foreach ($users as $uid) { + if (!$backend->userExists($uid)) { + continue; + } + $user = $this->getUserObject($uid, $backend, false); + $return = $callback($user); + if ($return === false) { + break; + } + } + $offset += $limit; + } while (count($users) >= $limit); + } + } + + /** + * @param string $email + * @return IUser[] + * @since 9.1.0 + */ + public function getByEmail($email) { + $userIds = $this->config->getUsersForUserValue('settings', 'email', $email); + + return array_map(function($uid) { + return $this->get($uid); + }, $userIds); + } +} diff --git a/lib/private/User/NoUserException.php b/lib/private/User/NoUserException.php new file mode 100644 index 00000000000..afd5c729fcf --- /dev/null +++ b/lib/private/User/NoUserException.php @@ -0,0 +1,24 @@ +<?php +/** + * @author Jörn Friedrich Dreyer <jfd@butonic.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\User; + +class NoUserException extends \Exception {}
\ No newline at end of file diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php new file mode 100644 index 00000000000..c7f8a6920de --- /dev/null +++ b/lib/private/User/Session.php @@ -0,0 +1,322 @@ +<?php +/** + * @author Arthur Schiwon <blizzz@owncloud.com> + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Jörn Friedrich Dreyer <jfd@butonic.de> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Robin Appelman <icewind@owncloud.com> + * @author Robin McCorkell <robin@mccorkell.me.uk> + * @author Roeland Jago Douma <rullzer@owncloud.com> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Vincent Petry <pvince81@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\User; + +use OC\Hooks\Emitter; +use OCP\ISession; +use OCP\IUserManager; +use OCP\IUserSession; + +/** + * Class Session + * + * Hooks available in scope \OC\User: + * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - preDelete(\OC\User\User $user) + * - postDelete(\OC\User\User $user) + * - preCreateUser(string $uid, string $password) + * - postCreateUser(\OC\User\User $user) + * - preLogin(string $user, string $password) + * - postLogin(\OC\User\User $user, string $password) + * - preRememberedLogin(string $uid) + * - postRememberedLogin(\OC\User\User $user) + * - logout() + * + * @package OC\User + */ +class Session implements IUserSession, Emitter { + /** @var \OC\User\Manager $manager */ + private $manager; + + /** @var \OC\Session\Session $session */ + private $session; + + /** @var \OC\User\User $activeUser */ + protected $activeUser; + + /** + * @param IUserManager $manager + * @param ISession $session + */ + public function __construct(IUserManager $manager, ISession $session) { + $this->manager = $manager; + $this->session = $session; + } + + /** + * @param string $scope + * @param string $method + * @param callable $callback + */ + public function listen($scope, $method, callable $callback) { + $this->manager->listen($scope, $method, $callback); + } + + /** + * @param string $scope optional + * @param string $method optional + * @param callable $callback optional + */ + public function removeListener($scope = null, $method = null, callable $callback = null) { + $this->manager->removeListener($scope, $method, $callback); + } + + /** + * get the manager object + * + * @return \OC\User\Manager + */ + public function getManager() { + return $this->manager; + } + + /** + * get the session object + * + * @return ISession + */ + public function getSession() { + return $this->session; + } + + /** + * set the session object + * + * @param ISession $session + */ + public function setSession(ISession $session) { + if ($this->session instanceof ISession) { + $this->session->close(); + } + $this->session = $session; + $this->activeUser = null; + } + + /** + * set the currently active user + * + * @param \OC\User\User|null $user + */ + public function setUser($user) { + if (is_null($user)) { + $this->session->remove('user_id'); + } else { + $this->session->set('user_id', $user->getUID()); + } + $this->activeUser = $user; + } + + /** + * get the current active user + * + * @return \OCP\IUser|null Current user, otherwise null + */ + public function getUser() { + // FIXME: This is a quick'n dirty work-around for the incognito mode as + // described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155 + if (\OC_User::isIncognitoMode()) { + return null; + } + if ($this->activeUser) { + return $this->activeUser; + } else { + $uid = $this->session->get('user_id'); + if ($uid !== null) { + $this->activeUser = $this->manager->get($uid); + return $this->activeUser; + } else { + return null; + } + } + } + + /** + * Checks whether the user is logged in + * + * @return bool if logged in + */ + public function isLoggedIn() { + $user = $this->getUser(); + if (is_null($user)) { + return false; + } + + return $user->isEnabled(); + } + + /** + * set the login name + * + * @param string|null $loginName for the logged in user + */ + public function setLoginName($loginName) { + if (is_null($loginName)) { + $this->session->remove('loginname'); + } else { + $this->session->set('loginname', $loginName); + } + } + + /** + * get the login name of the current user + * + * @return string + */ + public function getLoginName() { + if ($this->activeUser) { + return $this->session->get('loginname'); + } else { + $uid = $this->session->get('user_id'); + if ($uid) { + $this->activeUser = $this->manager->get($uid); + return $this->session->get('loginname'); + } else { + return null; + } + } + } + + /** + * try to login with the provided credentials + * + * @param string $uid + * @param string $password + * @return boolean|null + * @throws LoginException + */ + public function login($uid, $password) { + $this->session->regenerateId(); + $this->manager->emit('\OC\User', 'preLogin', array($uid, $password)); + $user = $this->manager->checkPassword($uid, $password); + if ($user !== false) { + if (!is_null($user)) { + if ($user->isEnabled()) { + $this->setUser($user); + $this->setLoginName($uid); + $this->manager->emit('\OC\User', 'postLogin', array($user, $password)); + if ($this->isLoggedIn()) { + return true; + } else { + // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory + $message = \OC::$server->getL10N('lib')->t('Login canceled by app'); + throw new LoginException($message); + } + } else { + // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory + $message = \OC::$server->getL10N('lib')->t('User disabled'); + throw new LoginException($message); + } + } + } + return false; + } + + /** + * perform login using the magic cookie (remember login) + * + * @param string $uid the username + * @param string $currentToken + * @return bool + */ + public function loginWithCookie($uid, $currentToken) { + $this->session->regenerateId(); + $this->manager->emit('\OC\User', 'preRememberedLogin', array($uid)); + $user = $this->manager->get($uid); + if (is_null($user)) { + // user does not exist + return false; + } + + // get stored tokens + $tokens = \OC::$server->getConfig()->getUserKeys($uid, 'login_token'); + // test cookies token against stored tokens + if (!in_array($currentToken, $tokens, true)) { + return false; + } + // replace successfully used token with a new one + \OC::$server->getConfig()->deleteUserValue($uid, 'login_token', $currentToken); + $newToken = \OC::$server->getSecureRandom()->generate(32); + \OC::$server->getConfig()->setUserValue($uid, 'login_token', $newToken, time()); + $this->setMagicInCookie($user->getUID(), $newToken); + + //login + $this->setUser($user); + $this->manager->emit('\OC\User', 'postRememberedLogin', array($user)); + return true; + } + + /** + * logout the user from the session + */ + public function logout() { + $this->manager->emit('\OC\User', 'logout'); + $this->setUser(null); + $this->setLoginName(null); + $this->unsetMagicInCookie(); + $this->session->clear(); + } + + /** + * Set cookie value to use in next page load + * + * @param string $username username to be set + * @param string $token + */ + public function setMagicInCookie($username, $token) { + $secureCookie = \OC::$server->getRequest()->getServerProtocol() === 'https'; + $expires = time() + \OC::$server->getConfig()->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15); + setcookie("oc_username", $username, $expires, \OC::$WEBROOT, '', $secureCookie, true); + setcookie("oc_token", $token, $expires, \OC::$WEBROOT, '', $secureCookie, true); + setcookie("oc_remember_login", "1", $expires, \OC::$WEBROOT, '', $secureCookie, true); + } + + /** + * Remove cookie for "remember username" + */ + public function unsetMagicInCookie() { + //TODO: DI for cookies and IRequest + $secureCookie = \OC::$server->getRequest()->getServerProtocol() === 'https'; + + unset($_COOKIE["oc_username"]); //TODO: DI + unset($_COOKIE["oc_token"]); + unset($_COOKIE["oc_remember_login"]); + setcookie('oc_username', '', time() - 3600, \OC::$WEBROOT, '',$secureCookie, true); + setcookie('oc_token', '', time() - 3600, \OC::$WEBROOT, '', $secureCookie, true); + setcookie('oc_remember_login', '', time() - 3600, \OC::$WEBROOT, '', $secureCookie, true); + // old cookies might be stored under /webroot/ instead of /webroot + // and Firefox doesn't like it! + setcookie('oc_username', '', time() - 3600, \OC::$WEBROOT . '/', '', $secureCookie, true); + setcookie('oc_token', '', time() - 3600, \OC::$WEBROOT . '/', '', $secureCookie, true); + setcookie('oc_remember_login', '', time() - 3600, \OC::$WEBROOT . '/', '', $secureCookie, true); + } +} diff --git a/lib/private/User/User.php b/lib/private/User/User.php new file mode 100644 index 00000000000..36680436769 --- /dev/null +++ b/lib/private/User/User.php @@ -0,0 +1,420 @@ +<?php +/** + * @author Arthur Schiwon <blizzz@owncloud.com> + * @author Bart Visscher <bartv@thisnet.nl> + * @author Björn Schießle <schiessle@owncloud.com> + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Jörn Friedrich Dreyer <jfd@butonic.de> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Robin Appelman <icewind@owncloud.com> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\User; + +use OC\Hooks\Emitter; +use OC_Helper; +use OCP\IAvatarManager; +use OCP\IImage; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\IConfig; +use OCP\UserInterface; + +class User implements IUser { + /** @var string $uid */ + private $uid; + + /** @var string $displayName */ + private $displayName; + + /** @var UserInterface $backend */ + private $backend; + + /** @var bool $enabled */ + private $enabled; + + /** @var Emitter|Manager $emitter */ + private $emitter; + + /** @var string $home */ + private $home; + + /** @var int $lastLogin */ + private $lastLogin; + + /** @var \OCP\IConfig $config */ + private $config; + + /** @var IAvatarManager */ + private $avatarManager; + + /** @var IURLGenerator */ + private $urlGenerator; + + /** + * @param string $uid + * @param UserInterface $backend + * @param \OC\Hooks\Emitter $emitter + * @param IConfig|null $config + * @param IURLGenerator $urlGenerator + */ + public function __construct($uid, $backend, $emitter = null, IConfig $config = null, $urlGenerator = null) { + $this->uid = $uid; + $this->backend = $backend; + $this->emitter = $emitter; + if(is_null($config)) { + $config = \OC::$server->getConfig(); + } + $this->config = $config; + $this->urlGenerator = $urlGenerator; + $enabled = $this->config->getUserValue($uid, 'core', 'enabled', 'true'); + $this->enabled = ($enabled === 'true'); + $this->lastLogin = $this->config->getUserValue($uid, 'login', 'lastLogin', 0); + if (is_null($this->urlGenerator)) { + $this->urlGenerator = \OC::$server->getURLGenerator(); + } + } + + /** + * get the user id + * + * @return string + */ + public function getUID() { + return $this->uid; + } + + /** + * get the display name for the user, if no specific display name is set it will fallback to the user id + * + * @return string + */ + public function getDisplayName() { + if (!isset($this->displayName)) { + $displayName = ''; + if ($this->backend and $this->backend->implementsActions(\OC_User_Backend::GET_DISPLAYNAME)) { + // get display name and strip whitespace from the beginning and end of it + $backendDisplayName = $this->backend->getDisplayName($this->uid); + if (is_string($backendDisplayName)) { + $displayName = trim($backendDisplayName); + } + } + + if (!empty($displayName)) { + $this->displayName = $displayName; + } else { + $this->displayName = $this->uid; + } + } + return $this->displayName; + } + + /** + * set the displayname for the user + * + * @param string $displayName + * @return bool + */ + public function setDisplayName($displayName) { + $displayName = trim($displayName); + if ($this->backend->implementsActions(\OC_User_Backend::SET_DISPLAYNAME) && !empty($displayName)) { + $result = $this->backend->setDisplayName($this->uid, $displayName); + if ($result) { + $this->displayName = $displayName; + $this->triggerChange('displayName', $displayName); + } + return $result !== false; + } else { + return false; + } + } + + /** + * set the email address of the user + * + * @param string|null $mailAddress + * @return void + * @since 9.0.0 + */ + public function setEMailAddress($mailAddress) { + if($mailAddress === '') { + $this->config->deleteUserValue($this->uid, 'settings', 'email'); + } else { + $this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress); + } + $this->triggerChange('eMailAddress', $mailAddress); + } + + /** + * returns the timestamp of the user's last login or 0 if the user did never + * login + * + * @return int + */ + public function getLastLogin() { + return $this->lastLogin; + } + + /** + * updates the timestamp of the most recent login of this user + */ + public function updateLastLoginTimestamp() { + $this->lastLogin = time(); + \OC::$server->getConfig()->setUserValue( + $this->uid, 'login', 'lastLogin', $this->lastLogin); + } + + /** + * Delete the user + * + * @return bool + */ + public function delete() { + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'preDelete', array($this)); + } + $result = $this->backend->deleteUser($this->uid); + if ($result) { + + // FIXME: Feels like an hack - suggestions? + + // We have to delete the user from all groups + foreach (\OC_Group::getUserGroups($this->uid) as $i) { + \OC_Group::removeFromGroup($this->uid, $i); + } + // Delete the user's keys in preferences + \OC::$server->getConfig()->deleteAllUserValues($this->uid); + + // Delete user files in /data/ + \OC_Helper::rmdirr(\OC_User::getHome($this->uid)); + + // Delete the users entry in the storage table + \OC\Files\Cache\Storage::remove('home::' . $this->uid); + + \OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid); + \OC::$server->getCommentsManager()->deleteReadMarksFromUser($this); + } + + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'postDelete', array($this)); + } + return !($result === false); + } + + /** + * Set the password of the user + * + * @param string $password + * @param string $recoveryPassword for the encryption app to reset encryption keys + * @return bool + */ + public function setPassword($password, $recoveryPassword = null) { + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'preSetPassword', array($this, $password, $recoveryPassword)); + } + if ($this->backend->implementsActions(\OC_User_Backend::SET_PASSWORD)) { + $result = $this->backend->setPassword($this->uid, $password); + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'postSetPassword', array($this, $password, $recoveryPassword)); + } + return !($result === false); + } else { + return false; + } + } + + /** + * get the users home folder to mount + * + * @return string + */ + public function getHome() { + if (!$this->home) { + if ($this->backend->implementsActions(\OC_User_Backend::GET_HOME) and $home = $this->backend->getHome($this->uid)) { + $this->home = $home; + } elseif ($this->config) { + $this->home = $this->config->getSystemValue('datadirectory') . '/' . $this->uid; + } else { + $this->home = \OC::$SERVERROOT . '/data/' . $this->uid; + } + } + return $this->home; + } + + /** + * Get the name of the backend class the user is connected with + * + * @return string + */ + public function getBackendClassName() { + if($this->backend instanceof \OCP\IUserBackend) { + return $this->backend->getBackendName(); + } + return get_class($this->backend); + } + + /** + * check if the backend allows the user to change his avatar on Personal page + * + * @return bool + */ + public function canChangeAvatar() { + if ($this->backend->implementsActions(\OC_User_Backend::PROVIDE_AVATAR)) { + return $this->backend->canChangeAvatar($this->uid); + } + return true; + } + + /** + * check if the backend supports changing passwords + * + * @return bool + */ + public function canChangePassword() { + return $this->backend->implementsActions(\OC_User_Backend::SET_PASSWORD); + } + + /** + * check if the backend supports changing display names + * + * @return bool + */ + public function canChangeDisplayName() { + if ($this->config->getSystemValue('allow_user_to_change_display_name') === false) { + return false; + } + return $this->backend->implementsActions(\OC_User_Backend::SET_DISPLAYNAME); + } + + /** + * check if the user is enabled + * + * @return bool + */ + public function isEnabled() { + return $this->enabled; + } + + /** + * set the enabled status for the user + * + * @param bool $enabled + */ + public function setEnabled($enabled) { + $this->enabled = $enabled; + $enabled = ($enabled) ? 'true' : 'false'; + $this->config->setUserValue($this->uid, 'core', 'enabled', $enabled); + } + + /** + * get the users email address + * + * @return string|null + * @since 9.0.0 + */ + public function getEMailAddress() { + return $this->config->getUserValue($this->uid, 'settings', 'email', null); + } + + /** + * get the users' quota + * + * @return string + * @since 9.0.0 + */ + public function getQuota() { + $quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default'); + if($quota === 'default') { + $quota = $this->config->getAppValue('files', 'default_quota', 'none'); + } + return $quota; + } + + /** + * set the users' quota + * + * @param string $quota + * @return void + * @since 9.0.0 + */ + public function setQuota($quota) { + if($quota !== 'none' and $quota !== 'default') { + $quota = OC_Helper::computerFileSize($quota); + $quota = OC_Helper::humanFileSize($quota); + } + $this->config->setUserValue($this->uid, 'files', 'quota', $quota); + $this->triggerChange('quota', $quota); + } + + /** + * get the avatar image if it exists + * + * @param int $size + * @return IImage|null + * @since 9.0.0 + */ + public function getAvatarImage($size) { + // delay the initialization + if (is_null($this->avatarManager)) { + $this->avatarManager = \OC::$server->getAvatarManager(); + } + + $avatar = $this->avatarManager->getAvatar($this->uid); + $image = $avatar->get(-1); + if ($image) { + return $image; + } + + return null; + } + + /** + * get the federation cloud id + * + * @return string + * @since 9.0.0 + */ + public function getCloudId() { + $uid = $this->getUID(); + $server = $this->urlGenerator->getAbsoluteURL('/'); + return $uid . '@' . rtrim( $this->removeProtocolFromUrl($server), '/'); + } + + /** + * @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; + } + + public function triggerChange($feature, $value = null) { + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'changeUser', array($this, $feature, $value)); + } + } +} |