1
0

UsersController.php 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Clark Tomlinson <fallen013@gmail.com>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author Lukas Reschke <lukas@statuscode.ch>
  9. * @author Morris Jobke <hey@morrisjobke.de>
  10. * @author Robin Appelman <robin@icewind.nl>
  11. * @author Roeland Jago Douma <roeland@famdouma.nl>
  12. * @author Thomas Müller <thomas.mueller@tmit.eu>
  13. * @author Vincent Petry <pvince81@owncloud.com>
  14. *
  15. * @license AGPL-3.0
  16. *
  17. * This code is free software: you can redistribute it and/or modify
  18. * it under the terms of the GNU Affero General Public License, version 3,
  19. * as published by the Free Software Foundation.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU Affero General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU Affero General Public License, version 3,
  27. * along with this program. If not, see <http://www.gnu.org/licenses/>
  28. *
  29. */
  30. namespace OC\Settings\Controller;
  31. use OC\Accounts\AccountManager;
  32. use OC\AppFramework\Http;
  33. use OC\ForbiddenException;
  34. use OC\HintException;
  35. use OC\Settings\Mailer\NewUserMailHelper;
  36. use OC\Security\IdentityProof\Manager;
  37. use OCP\App\IAppManager;
  38. use OCP\AppFramework\Controller;
  39. use OCP\AppFramework\Http\DataResponse;
  40. use OCP\AppFramework\Utility\ITimeFactory;
  41. use OCP\BackgroundJob\IJobList;
  42. use OCP\IConfig;
  43. use OCP\IGroupManager;
  44. use OCP\IL10N;
  45. use OCP\ILogger;
  46. use OCP\IRequest;
  47. use OCP\IURLGenerator;
  48. use OCP\IUser;
  49. use OCP\IUserManager;
  50. use OCP\IUserSession;
  51. use OCP\Mail\IMailer;
  52. use OCP\IAvatarManager;
  53. use OCP\Security\ICrypto;
  54. use OCP\Security\ISecureRandom;
  55. /**
  56. * @package OC\Settings\Controller
  57. */
  58. class UsersController extends Controller {
  59. /** @var IL10N */
  60. private $l10n;
  61. /** @var IUserSession */
  62. private $userSession;
  63. /** @var bool */
  64. private $isAdmin;
  65. /** @var IUserManager */
  66. private $userManager;
  67. /** @var IGroupManager */
  68. private $groupManager;
  69. /** @var IConfig */
  70. private $config;
  71. /** @var ILogger */
  72. private $log;
  73. /** @var IMailer */
  74. private $mailer;
  75. /** @var bool contains the state of the encryption app */
  76. private $isEncryptionAppEnabled;
  77. /** @var bool contains the state of the admin recovery setting */
  78. private $isRestoreEnabled = false;
  79. /** @var IAppManager */
  80. private $appManager;
  81. /** @var IAvatarManager */
  82. private $avatarManager;
  83. /** @var AccountManager */
  84. private $accountManager;
  85. /** @var ISecureRandom */
  86. private $secureRandom;
  87. /** @var NewUserMailHelper */
  88. private $newUserMailHelper;
  89. /** @var ITimeFactory */
  90. private $timeFactory;
  91. /** @var ICrypto */
  92. private $crypto;
  93. /** @var Manager */
  94. private $keyManager;
  95. /** @var IJobList */
  96. private $jobList;
  97. /**
  98. * @param string $appName
  99. * @param IRequest $request
  100. * @param IUserManager $userManager
  101. * @param IGroupManager $groupManager
  102. * @param IUserSession $userSession
  103. * @param IConfig $config
  104. * @param bool $isAdmin
  105. * @param IL10N $l10n
  106. * @param ILogger $log
  107. * @param IMailer $mailer
  108. * @param IURLGenerator $urlGenerator
  109. * @param IAppManager $appManager
  110. * @param IAvatarManager $avatarManager
  111. * @param AccountManager $accountManager
  112. * @param ISecureRandom $secureRandom
  113. * @param NewUserMailHelper $newUserMailHelper
  114. * @param ITimeFactory $timeFactory
  115. * @param ICrypto $crypto
  116. * @param Manager $keyManager
  117. * @param IJobList $jobList
  118. */
  119. public function __construct($appName,
  120. IRequest $request,
  121. IUserManager $userManager,
  122. IGroupManager $groupManager,
  123. IUserSession $userSession,
  124. IConfig $config,
  125. $isAdmin,
  126. IL10N $l10n,
  127. ILogger $log,
  128. IMailer $mailer,
  129. IURLGenerator $urlGenerator,
  130. IAppManager $appManager,
  131. IAvatarManager $avatarManager,
  132. AccountManager $accountManager,
  133. ISecureRandom $secureRandom,
  134. NewUserMailHelper $newUserMailHelper,
  135. ITimeFactory $timeFactory,
  136. ICrypto $crypto,
  137. Manager $keyManager,
  138. IJobList $jobList) {
  139. parent::__construct($appName, $request);
  140. $this->userManager = $userManager;
  141. $this->groupManager = $groupManager;
  142. $this->userSession = $userSession;
  143. $this->config = $config;
  144. $this->isAdmin = $isAdmin;
  145. $this->l10n = $l10n;
  146. $this->log = $log;
  147. $this->mailer = $mailer;
  148. $this->appManager = $appManager;
  149. $this->avatarManager = $avatarManager;
  150. $this->accountManager = $accountManager;
  151. $this->secureRandom = $secureRandom;
  152. $this->newUserMailHelper = $newUserMailHelper;
  153. $this->timeFactory = $timeFactory;
  154. $this->crypto = $crypto;
  155. $this->keyManager = $keyManager;
  156. $this->jobList = $jobList;
  157. // check for encryption state - TODO see formatUserForIndex
  158. $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
  159. if($this->isEncryptionAppEnabled) {
  160. // putting this directly in empty is possible in PHP 5.5+
  161. $result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
  162. $this->isRestoreEnabled = !empty($result);
  163. }
  164. }
  165. /**
  166. * @param IUser $user
  167. * @param array $userGroups
  168. * @return array
  169. */
  170. private function formatUserForIndex(IUser $user, array $userGroups = null) {
  171. // TODO: eliminate this encryption specific code below and somehow
  172. // hook in additional user info from other apps
  173. // recovery isn't possible if admin or user has it disabled and encryption
  174. // is enabled - so we eliminate the else paths in the conditional tree
  175. // below
  176. $restorePossible = false;
  177. if ($this->isEncryptionAppEnabled) {
  178. if ($this->isRestoreEnabled) {
  179. // check for the users recovery setting
  180. $recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
  181. // method call inside empty is possible with PHP 5.5+
  182. $recoveryModeEnabled = !empty($recoveryMode);
  183. if ($recoveryModeEnabled) {
  184. // user also has recovery mode enabled
  185. $restorePossible = true;
  186. }
  187. }
  188. } else {
  189. // recovery is possible if encryption is disabled (plain files are
  190. // available)
  191. $restorePossible = true;
  192. }
  193. $subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
  194. foreach($subAdminGroups as $key => $subAdminGroup) {
  195. $subAdminGroups[$key] = $subAdminGroup->getGID();
  196. }
  197. $displayName = $user->getEMailAddress();
  198. if (is_null($displayName)) {
  199. $displayName = '';
  200. }
  201. $avatarAvailable = false;
  202. try {
  203. $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
  204. } catch (\Exception $e) {
  205. //No avatar yet
  206. }
  207. return [
  208. 'name' => $user->getUID(),
  209. 'displayname' => $user->getDisplayName(),
  210. 'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
  211. 'subadmin' => $subAdminGroups,
  212. 'quota' => $user->getQuota(),
  213. 'storageLocation' => $user->getHome(),
  214. 'lastLogin' => $user->getLastLogin() * 1000,
  215. 'backend' => $user->getBackendClassName(),
  216. 'email' => $displayName,
  217. 'isRestoreDisabled' => !$restorePossible,
  218. 'isAvatarAvailable' => $avatarAvailable,
  219. 'isEnabled' => $user->isEnabled(),
  220. ];
  221. }
  222. /**
  223. * @param array $userIDs Array with schema [$uid => $displayName]
  224. * @return IUser[]
  225. */
  226. private function getUsersForUID(array $userIDs) {
  227. $users = [];
  228. foreach ($userIDs as $uid => $displayName) {
  229. $users[$uid] = $this->userManager->get($uid);
  230. }
  231. return $users;
  232. }
  233. /**
  234. * @NoAdminRequired
  235. *
  236. * @param int $offset
  237. * @param int $limit
  238. * @param string $gid GID to filter for
  239. * @param string $pattern Pattern to search for in the username
  240. * @param string $backend Backend to filter for (class-name)
  241. * @return DataResponse
  242. *
  243. * TODO: Tidy up and write unit tests - code is mainly static method calls
  244. */
  245. public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
  246. // Remove backends
  247. if(!empty($backend)) {
  248. $activeBackends = $this->userManager->getBackends();
  249. $this->userManager->clearBackends();
  250. foreach($activeBackends as $singleActiveBackend) {
  251. if($backend === get_class($singleActiveBackend)) {
  252. $this->userManager->registerBackend($singleActiveBackend);
  253. break;
  254. }
  255. }
  256. }
  257. $users = [];
  258. if ($this->isAdmin) {
  259. if($gid !== '' && $gid !== '_disabledUsers') {
  260. $batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
  261. } else {
  262. $batch = $this->userManager->search($pattern, $limit, $offset);
  263. }
  264. foreach ($batch as $user) {
  265. if( ($gid !== '_disabledUsers' && $user->isEnabled()) ||
  266. ($gid === '_disabledUsers' && !$user->isEnabled())
  267. ) {
  268. $users[] = $this->formatUserForIndex($user);
  269. }
  270. }
  271. } else {
  272. $subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
  273. // New class returns IGroup[] so convert back
  274. $gids = [];
  275. foreach ($subAdminOfGroups as $group) {
  276. $gids[] = $group->getGID();
  277. }
  278. $subAdminOfGroups = $gids;
  279. // Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
  280. if($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
  281. $gid = '';
  282. }
  283. // Batch all groups the user is subadmin of when a group is specified
  284. $batch = [];
  285. if ($gid !== '' && $gid !== '_disabledUsers' && $gid !== '_everyone') {
  286. $batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
  287. } else {
  288. foreach($subAdminOfGroups as $group) {
  289. $groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
  290. foreach($groupUsers as $uid => $displayName) {
  291. $batch[$uid] = $displayName;
  292. }
  293. }
  294. }
  295. $batch = $this->getUsersForUID($batch);
  296. foreach ($batch as $user) {
  297. // Only add the groups, this user is a subadmin of
  298. $userGroups = array_values(array_intersect(
  299. $this->groupManager->getUserGroupIds($user),
  300. $subAdminOfGroups
  301. ));
  302. if( ($gid !== '_disabledUsers' && $user->isEnabled()) ||
  303. ($gid === '_disabledUsers' && !$user->isEnabled())
  304. ) {
  305. $users[] = $this->formatUserForIndex($user, $userGroups);
  306. }
  307. }
  308. }
  309. return new DataResponse($users);
  310. }
  311. /**
  312. * @NoAdminRequired
  313. * @PasswordConfirmationRequired
  314. *
  315. * @param string $username
  316. * @param string $password
  317. * @param array $groups
  318. * @param string $email
  319. * @return DataResponse
  320. */
  321. public function create($username, $password, array $groups=[], $email='') {
  322. if($email !== '' && !$this->mailer->validateMailAddress($email)) {
  323. return new DataResponse(
  324. [
  325. 'message' => (string)$this->l10n->t('Invalid mail address')
  326. ],
  327. Http::STATUS_UNPROCESSABLE_ENTITY
  328. );
  329. }
  330. $currentUser = $this->userSession->getUser();
  331. if (!$this->isAdmin) {
  332. if (!empty($groups)) {
  333. foreach ($groups as $key => $group) {
  334. $groupObject = $this->groupManager->get($group);
  335. if($groupObject === null) {
  336. unset($groups[$key]);
  337. continue;
  338. }
  339. if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
  340. unset($groups[$key]);
  341. }
  342. }
  343. }
  344. if (empty($groups)) {
  345. return new DataResponse(
  346. [
  347. 'message' => $this->l10n->t('No valid group selected'),
  348. ],
  349. Http::STATUS_FORBIDDEN
  350. );
  351. }
  352. }
  353. if ($this->userManager->userExists($username)) {
  354. return new DataResponse(
  355. [
  356. 'message' => (string)$this->l10n->t('A user with that name already exists.')
  357. ],
  358. Http::STATUS_CONFLICT
  359. );
  360. }
  361. $generatePasswordResetToken = false;
  362. if ($password === '') {
  363. if ($email === '') {
  364. return new DataResponse(
  365. [
  366. 'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
  367. ],
  368. Http::STATUS_UNPROCESSABLE_ENTITY
  369. );
  370. }
  371. $password = $this->secureRandom->generate(32);
  372. $generatePasswordResetToken = true;
  373. }
  374. try {
  375. $user = $this->userManager->createUser($username, $password);
  376. } catch (\Exception $exception) {
  377. $message = $exception->getMessage();
  378. if ($exception instanceof HintException && $exception->getHint()) {
  379. $message = $exception->getHint();
  380. }
  381. if (!$message) {
  382. $message = $this->l10n->t('Unable to create user.');
  383. }
  384. return new DataResponse(
  385. [
  386. 'message' => (string) $message,
  387. ],
  388. Http::STATUS_FORBIDDEN
  389. );
  390. }
  391. if($user instanceof IUser) {
  392. if($groups !== null) {
  393. foreach($groups as $groupName) {
  394. $group = $this->groupManager->get($groupName);
  395. if(empty($group)) {
  396. $group = $this->groupManager->createGroup($groupName);
  397. }
  398. $group->addUser($user);
  399. }
  400. }
  401. /**
  402. * Send new user mail only if a mail is set
  403. */
  404. if($email !== '') {
  405. $user->setEMailAddress($email);
  406. try {
  407. $emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
  408. $this->newUserMailHelper->sendMail($user, $emailTemplate);
  409. } catch(\Exception $e) {
  410. $this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
  411. }
  412. }
  413. // fetch users groups
  414. $userGroups = $this->groupManager->getUserGroupIds($user);
  415. return new DataResponse(
  416. $this->formatUserForIndex($user, $userGroups),
  417. Http::STATUS_CREATED
  418. );
  419. }
  420. return new DataResponse(
  421. [
  422. 'message' => (string) $this->l10n->t('Unable to create user.')
  423. ],
  424. Http::STATUS_FORBIDDEN
  425. );
  426. }
  427. /**
  428. * @NoAdminRequired
  429. * @PasswordConfirmationRequired
  430. *
  431. * @param string $id
  432. * @return DataResponse
  433. */
  434. public function destroy($id) {
  435. $userId = $this->userSession->getUser()->getUID();
  436. $user = $this->userManager->get($id);
  437. if($userId === $id) {
  438. return new DataResponse(
  439. [
  440. 'status' => 'error',
  441. 'data' => [
  442. 'message' => (string) $this->l10n->t('Unable to delete user.')
  443. ]
  444. ],
  445. Http::STATUS_FORBIDDEN
  446. );
  447. }
  448. if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
  449. return new DataResponse(
  450. [
  451. 'status' => 'error',
  452. 'data' => [
  453. 'message' => (string)$this->l10n->t('Authentication error')
  454. ]
  455. ],
  456. Http::STATUS_FORBIDDEN
  457. );
  458. }
  459. if($user) {
  460. if($user->delete()) {
  461. return new DataResponse(
  462. [
  463. 'status' => 'success',
  464. 'data' => [
  465. 'username' => $id
  466. ]
  467. ],
  468. Http::STATUS_NO_CONTENT
  469. );
  470. }
  471. }
  472. return new DataResponse(
  473. [
  474. 'status' => 'error',
  475. 'data' => [
  476. 'message' => (string)$this->l10n->t('Unable to delete user.')
  477. ]
  478. ],
  479. Http::STATUS_FORBIDDEN
  480. );
  481. }
  482. /**
  483. * @NoAdminRequired
  484. *
  485. * @param string $id
  486. * @param int $enabled
  487. * @return DataResponse
  488. */
  489. public function setEnabled($id, $enabled) {
  490. $enabled = (bool)$enabled;
  491. if($enabled) {
  492. $errorMsgGeneral = (string) $this->l10n->t('Error while enabling user.');
  493. } else {
  494. $errorMsgGeneral = (string) $this->l10n->t('Error while disabling user.');
  495. }
  496. $userId = $this->userSession->getUser()->getUID();
  497. $user = $this->userManager->get($id);
  498. if ($userId === $id) {
  499. return new DataResponse(
  500. [
  501. 'status' => 'error',
  502. 'data' => [
  503. 'message' => $errorMsgGeneral
  504. ]
  505. ], Http::STATUS_FORBIDDEN
  506. );
  507. }
  508. if($user) {
  509. if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
  510. return new DataResponse(
  511. [
  512. 'status' => 'error',
  513. 'data' => [
  514. 'message' => (string) $this->l10n->t('Authentication error')
  515. ]
  516. ],
  517. Http::STATUS_FORBIDDEN
  518. );
  519. }
  520. $user->setEnabled($enabled);
  521. return new DataResponse(
  522. [
  523. 'status' => 'success',
  524. 'data' => [
  525. 'username' => $id,
  526. 'enabled' => $enabled
  527. ]
  528. ]
  529. );
  530. } else {
  531. return new DataResponse(
  532. [
  533. 'status' => 'error',
  534. 'data' => [
  535. 'message' => $errorMsgGeneral
  536. ]
  537. ],
  538. Http::STATUS_FORBIDDEN
  539. );
  540. }
  541. }
  542. /**
  543. * Set the mail address of a user
  544. *
  545. * @NoAdminRequired
  546. * @NoSubadminRequired
  547. * @PasswordConfirmationRequired
  548. *
  549. * @param string $account
  550. * @param bool $onlyVerificationCode only return verification code without updating the data
  551. * @return DataResponse
  552. */
  553. public function getVerificationCode($account, $onlyVerificationCode) {
  554. $user = $this->userSession->getUser();
  555. if ($user === null) {
  556. return new DataResponse([], Http::STATUS_BAD_REQUEST);
  557. }
  558. $accountData = $this->accountManager->getUser($user);
  559. $cloudId = $user->getCloudId();
  560. $message = "Use my Federated Cloud ID to share with me: " . $cloudId;
  561. $signature = $this->signMessage($user, $message);
  562. $code = $message . ' ' . $signature;
  563. $codeMd5 = $message . ' ' . md5($signature);
  564. switch ($account) {
  565. case 'verify-twitter':
  566. $accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
  567. $msg = $this->l10n->t('In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):');
  568. $code = $codeMd5;
  569. $type = AccountManager::PROPERTY_TWITTER;
  570. $data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
  571. $accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
  572. break;
  573. case 'verify-website':
  574. $accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
  575. $msg = $this->l10n->t('In order to verify your Website, store the following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
  576. $type = AccountManager::PROPERTY_WEBSITE;
  577. $data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
  578. $accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
  579. break;
  580. default:
  581. return new DataResponse([], Http::STATUS_BAD_REQUEST);
  582. }
  583. if ($onlyVerificationCode === false) {
  584. $this->accountManager->updateUser($user, $accountData);
  585. $this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
  586. [
  587. 'verificationCode' => $code,
  588. 'data' => $data,
  589. 'type' => $type,
  590. 'uid' => $user->getUID(),
  591. 'try' => 0,
  592. 'lastRun' => $this->getCurrentTime()
  593. ]
  594. );
  595. }
  596. return new DataResponse(['msg' => $msg, 'code' => $code]);
  597. }
  598. /**
  599. * get current timestamp
  600. *
  601. * @return int
  602. */
  603. protected function getCurrentTime() {
  604. return time();
  605. }
  606. /**
  607. * sign message with users private key
  608. *
  609. * @param IUser $user
  610. * @param string $message
  611. *
  612. * @return string base64 encoded signature
  613. */
  614. protected function signMessage(IUser $user, $message) {
  615. $privateKey = $this->keyManager->getKey($user)->getPrivate();
  616. openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
  617. $signatureBase64 = base64_encode($signature);
  618. return $signatureBase64;
  619. }
  620. /**
  621. * @NoAdminRequired
  622. * @NoSubadminRequired
  623. * @PasswordConfirmationRequired
  624. *
  625. * @param string $avatarScope
  626. * @param string $displayname
  627. * @param string $displaynameScope
  628. * @param string $phone
  629. * @param string $phoneScope
  630. * @param string $email
  631. * @param string $emailScope
  632. * @param string $website
  633. * @param string $websiteScope
  634. * @param string $address
  635. * @param string $addressScope
  636. * @param string $twitter
  637. * @param string $twitterScope
  638. * @return DataResponse
  639. */
  640. public function setUserSettings($avatarScope,
  641. $displayname,
  642. $displaynameScope,
  643. $phone,
  644. $phoneScope,
  645. $email,
  646. $emailScope,
  647. $website,
  648. $websiteScope,
  649. $address,
  650. $addressScope,
  651. $twitter,
  652. $twitterScope
  653. ) {
  654. if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
  655. return new DataResponse(
  656. [
  657. 'status' => 'error',
  658. 'data' => [
  659. 'message' => (string) $this->l10n->t('Invalid mail address')
  660. ]
  661. ],
  662. Http::STATUS_UNPROCESSABLE_ENTITY
  663. );
  664. }
  665. $user = $this->userSession->getUser();
  666. $data = $this->accountManager->getUser($user);
  667. $data[AccountManager::PROPERTY_AVATAR] = ['scope' => $avatarScope];
  668. if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
  669. $data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
  670. $data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
  671. }
  672. if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
  673. $federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
  674. $shareProvider = $federatedFileSharing->getFederatedShareProvider();
  675. if ($shareProvider->isLookupServerUploadEnabled()) {
  676. $data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
  677. $data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
  678. $data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
  679. $data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
  680. }
  681. }
  682. try {
  683. $this->saveUserSettings($user, $data);
  684. return new DataResponse(
  685. [
  686. 'status' => 'success',
  687. 'data' => [
  688. 'userId' => $user->getUID(),
  689. 'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
  690. 'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
  691. 'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
  692. 'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
  693. 'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
  694. 'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
  695. 'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
  696. 'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
  697. 'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
  698. 'message' => (string) $this->l10n->t('Settings saved')
  699. ]
  700. ],
  701. Http::STATUS_OK
  702. );
  703. } catch (ForbiddenException $e) {
  704. return new DataResponse([
  705. 'status' => 'error',
  706. 'data' => [
  707. 'message' => $e->getMessage()
  708. ],
  709. ]);
  710. }
  711. }
  712. /**
  713. * update account manager with new user data
  714. *
  715. * @param IUser $user
  716. * @param array $data
  717. * @throws ForbiddenException
  718. */
  719. protected function saveUserSettings(IUser $user, $data) {
  720. // keep the user back-end up-to-date with the latest display name and email
  721. // address
  722. $oldDisplayName = $user->getDisplayName();
  723. $oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
  724. if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
  725. && $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
  726. ) {
  727. $result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
  728. if ($result === false) {
  729. throw new ForbiddenException($this->l10n->t('Unable to change full name'));
  730. }
  731. }
  732. $oldEmailAddress = $user->getEMailAddress();
  733. $oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
  734. if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
  735. && $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
  736. ) {
  737. // this is the only permission a backend provides and is also used
  738. // for the permission of setting a email address
  739. if (!$user->canChangeDisplayName()) {
  740. throw new ForbiddenException($this->l10n->t('Unable to change email address'));
  741. }
  742. $user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
  743. }
  744. $this->accountManager->updateUser($user, $data);
  745. }
  746. /**
  747. * Count all unique users visible for the current admin/subadmin.
  748. *
  749. * @NoAdminRequired
  750. *
  751. * @return DataResponse
  752. */
  753. public function stats() {
  754. $userCount = 0;
  755. if ($this->isAdmin) {
  756. $countByBackend = $this->userManager->countUsers();
  757. if (!empty($countByBackend)) {
  758. foreach ($countByBackend as $count) {
  759. $userCount += $count;
  760. }
  761. }
  762. } else {
  763. $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
  764. $uniqueUsers = [];
  765. foreach ($groups as $group) {
  766. foreach($group->getUsers() as $uid => $displayName) {
  767. $uniqueUsers[$uid] = true;
  768. }
  769. }
  770. $userCount = count($uniqueUsers);
  771. }
  772. return new DataResponse(
  773. [
  774. 'totalUsers' => $userCount
  775. ]
  776. );
  777. }
  778. /**
  779. * Set the displayName of a user
  780. *
  781. * @NoAdminRequired
  782. * @NoSubadminRequired
  783. * @PasswordConfirmationRequired
  784. * @todo merge into saveUserSettings
  785. *
  786. * @param string $username
  787. * @param string $displayName
  788. * @return DataResponse
  789. */
  790. public function setDisplayName($username, $displayName) {
  791. $currentUser = $this->userSession->getUser();
  792. $user = $this->userManager->get($username);
  793. if ($user === null ||
  794. !$user->canChangeDisplayName() ||
  795. (
  796. !$this->groupManager->isAdmin($currentUser->getUID()) &&
  797. !$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
  798. $currentUser->getUID() !== $username
  799. )
  800. ) {
  801. return new DataResponse([
  802. 'status' => 'error',
  803. 'data' => [
  804. 'message' => $this->l10n->t('Authentication error'),
  805. ],
  806. ]);
  807. }
  808. $userData = $this->accountManager->getUser($user);
  809. $userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
  810. try {
  811. $this->saveUserSettings($user, $userData);
  812. return new DataResponse([
  813. 'status' => 'success',
  814. 'data' => [
  815. 'message' => $this->l10n->t('Your full name has been changed.'),
  816. 'username' => $username,
  817. 'displayName' => $displayName,
  818. ],
  819. ]);
  820. } catch (ForbiddenException $e) {
  821. return new DataResponse([
  822. 'status' => 'error',
  823. 'data' => [
  824. 'message' => $e->getMessage(),
  825. 'displayName' => $user->getDisplayName(),
  826. ],
  827. ]);
  828. }
  829. }
  830. /**
  831. * Set the mail address of a user
  832. *
  833. * @NoAdminRequired
  834. * @NoSubadminRequired
  835. * @PasswordConfirmationRequired
  836. *
  837. * @param string $id
  838. * @param string $mailAddress
  839. * @return DataResponse
  840. */
  841. public function setEMailAddress($id, $mailAddress) {
  842. $user = $this->userManager->get($id);
  843. if (!$this->isAdmin
  844. && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
  845. ) {
  846. return new DataResponse(
  847. [
  848. 'status' => 'error',
  849. 'data' => [
  850. 'message' => (string) $this->l10n->t('Forbidden')
  851. ]
  852. ],
  853. Http::STATUS_FORBIDDEN
  854. );
  855. }
  856. if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
  857. return new DataResponse(
  858. [
  859. 'status' => 'error',
  860. 'data' => [
  861. 'message' => (string) $this->l10n->t('Invalid mail address')
  862. ]
  863. ],
  864. Http::STATUS_UNPROCESSABLE_ENTITY
  865. );
  866. }
  867. if (!$user) {
  868. return new DataResponse(
  869. [
  870. 'status' => 'error',
  871. 'data' => [
  872. 'message' => (string) $this->l10n->t('Invalid user')
  873. ]
  874. ],
  875. Http::STATUS_UNPROCESSABLE_ENTITY
  876. );
  877. }
  878. // this is the only permission a backend provides and is also used
  879. // for the permission of setting a email address
  880. if (!$user->canChangeDisplayName()) {
  881. return new DataResponse(
  882. [
  883. 'status' => 'error',
  884. 'data' => [
  885. 'message' => (string) $this->l10n->t('Unable to change mail address')
  886. ]
  887. ],
  888. Http::STATUS_FORBIDDEN
  889. );
  890. }
  891. $userData = $this->accountManager->getUser($user);
  892. $userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
  893. try {
  894. $this->saveUserSettings($user, $userData);
  895. return new DataResponse(
  896. [
  897. 'status' => 'success',
  898. 'data' => [
  899. 'username' => $id,
  900. 'mailAddress' => $mailAddress,
  901. 'message' => (string) $this->l10n->t('Email saved')
  902. ]
  903. ],
  904. Http::STATUS_OK
  905. );
  906. } catch (ForbiddenException $e) {
  907. return new DataResponse([
  908. 'status' => 'error',
  909. 'data' => [
  910. 'message' => $e->getMessage()
  911. ],
  912. ]);
  913. }
  914. }
  915. }