UsersControllerTest.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. <?php
  2. /**
  3. * @copyright 2014-2015 Lukas Reschke lukas@owncloud.com
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Bjoern Schiessle <bjoern@schiessle.org>
  7. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  8. * @author Daniel Calviño Sánchez <danxuliu@gmail.com>
  9. * @author Joas Schilling <coding@schilljs.com>
  10. * @author John Molakvoæ <skjnldsv@protonmail.com>
  11. * @author Morris Jobke <hey@morrisjobke.de>
  12. * @author Roeland Jago Douma <roeland@famdouma.nl>
  13. * @author Vincent Petry <vincent@nextcloud.com>
  14. *
  15. * @license GNU AGPL version 3 or any later version
  16. *
  17. * This program is free software: you can redistribute it and/or modify
  18. * it under the terms of the GNU Affero General Public License as
  19. * published by the Free Software Foundation, either version 3 of the
  20. * License, or (at your option) any later version.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU Affero General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU Affero General Public License
  28. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  29. *
  30. */
  31. namespace OCA\Settings\Tests\Controller;
  32. use OC\Accounts\AccountManager;
  33. use OC\Encryption\Exceptions\ModuleDoesNotExistsException;
  34. use OC\ForbiddenException;
  35. use OC\Group\Manager;
  36. use OC\KnownUser\KnownUserService;
  37. use OCA\Settings\Controller\UsersController;
  38. use OCP\Accounts\IAccount;
  39. use OCP\Accounts\IAccountManager;
  40. use OCP\Accounts\IAccountProperty;
  41. use OCP\Accounts\PropertyDoesNotExistException;
  42. use OCP\App\IAppManager;
  43. use OCP\AppFramework\Http;
  44. use OCP\BackgroundJob\IJobList;
  45. use OCP\Encryption\IEncryptionModule;
  46. use OCP\Encryption\IManager;
  47. use OCP\EventDispatcher\IEventDispatcher;
  48. use OCP\IAvatarManager;
  49. use OCP\IConfig;
  50. use OCP\IGroupManager;
  51. use OCP\IL10N;
  52. use OCP\ILogger;
  53. use OCP\IRequest;
  54. use OCP\IUser;
  55. use OCP\IUserManager;
  56. use OCP\IUserSession;
  57. use OCP\L10N\IFactory;
  58. use OCP\Mail\IMailer;
  59. use OCP\Security\ISecureRandom;
  60. use PHPUnit\Framework\MockObject\MockObject;
  61. /**
  62. * @group DB
  63. *
  64. * @package Tests\Settings\Controller
  65. */
  66. class UsersControllerTest extends \Test\TestCase {
  67. /** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject */
  68. private $groupManager;
  69. /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */
  70. private $userManager;
  71. /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
  72. private $userSession;
  73. /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
  74. private $config;
  75. /** @var ILogger|\PHPUnit\Framework\MockObject\MockObject */
  76. private $logger;
  77. /** @var IMailer|\PHPUnit\Framework\MockObject\MockObject */
  78. private $mailer;
  79. /** @var IFactory|\PHPUnit\Framework\MockObject\MockObject */
  80. private $l10nFactory;
  81. /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */
  82. private $appManager;
  83. /** @var IAvatarManager|\PHPUnit\Framework\MockObject\MockObject */
  84. private $avatarManager;
  85. /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */
  86. private $l;
  87. /** @var AccountManager | \PHPUnit\Framework\MockObject\MockObject */
  88. private $accountManager;
  89. /** @var ISecureRandom | \PHPUnit\Framework\MockObject\MockObject */
  90. private $secureRandom;
  91. /** @var \OCA\Settings\Mailer\NewUserMailHelper|\PHPUnit\Framework\MockObject\MockObject */
  92. private $newUserMailHelper;
  93. /** @var IJobList | \PHPUnit\Framework\MockObject\MockObject */
  94. private $jobList;
  95. /** @var \OC\Security\IdentityProof\Manager |\PHPUnit\Framework\MockObject\MockObject */
  96. private $securityManager;
  97. /** @var IManager | \PHPUnit\Framework\MockObject\MockObject */
  98. private $encryptionManager;
  99. /** @var KnownUserService|\PHPUnit\Framework\MockObject\MockObject */
  100. private $knownUserService;
  101. /** @var IEncryptionModule | \PHPUnit\Framework\MockObject\MockObject */
  102. private $encryptionModule;
  103. /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
  104. private $dispatcher;
  105. protected function setUp(): void {
  106. parent::setUp();
  107. $this->userManager = $this->createMock(IUserManager::class);
  108. $this->groupManager = $this->createMock(Manager::class);
  109. $this->userSession = $this->createMock(IUserSession::class);
  110. $this->config = $this->createMock(IConfig::class);
  111. $this->l = $this->createMock(IL10N::class);
  112. $this->mailer = $this->createMock(IMailer::class);
  113. $this->l10nFactory = $this->createMock(IFactory::class);
  114. $this->appManager = $this->createMock(IAppManager::class);
  115. $this->accountManager = $this->createMock(AccountManager::class);
  116. $this->securityManager = $this->getMockBuilder(\OC\Security\IdentityProof\Manager::class)->disableOriginalConstructor()->getMock();
  117. $this->jobList = $this->createMock(IJobList::class);
  118. $this->encryptionManager = $this->createMock(IManager::class);
  119. $this->knownUserService = $this->createMock(KnownUserService::class);
  120. $this->dispatcher = $this->createMock(IEventDispatcher::class);
  121. $this->l->method('t')
  122. ->willReturnCallback(function ($text, $parameters = []) {
  123. return vsprintf($text, $parameters);
  124. });
  125. $this->encryptionModule = $this->createMock(IEncryptionModule::class);
  126. $this->encryptionManager->expects($this->any())->method('getEncryptionModules')
  127. ->willReturn(['encryptionModule' => ['callback' => function () {
  128. return $this->encryptionModule;
  129. }]]);
  130. }
  131. /**
  132. * @param bool $isAdmin
  133. * @return UsersController | \PHPUnit\Framework\MockObject\MockObject
  134. */
  135. protected function getController($isAdmin = false, $mockedMethods = []) {
  136. if (empty($mockedMethods)) {
  137. return new UsersController(
  138. 'settings',
  139. $this->createMock(IRequest::class),
  140. $this->userManager,
  141. $this->groupManager,
  142. $this->userSession,
  143. $this->config,
  144. $isAdmin,
  145. $this->l,
  146. $this->mailer,
  147. $this->l10nFactory,
  148. $this->appManager,
  149. $this->accountManager,
  150. $this->securityManager,
  151. $this->jobList,
  152. $this->encryptionManager,
  153. $this->knownUserService,
  154. $this->dispatcher
  155. );
  156. } else {
  157. return $this->getMockBuilder(UsersController::class)
  158. ->setConstructorArgs(
  159. [
  160. 'settings',
  161. $this->createMock(IRequest::class),
  162. $this->userManager,
  163. $this->groupManager,
  164. $this->userSession,
  165. $this->config,
  166. $isAdmin,
  167. $this->l,
  168. $this->mailer,
  169. $this->l10nFactory,
  170. $this->appManager,
  171. $this->accountManager,
  172. $this->securityManager,
  173. $this->jobList,
  174. $this->encryptionManager,
  175. $this->knownUserService,
  176. $this->dispatcher
  177. ]
  178. )->setMethods($mockedMethods)->getMock();
  179. }
  180. }
  181. protected function buildPropertyMock(string $name, string $value, string $scope, string $verified = IAccountManager::VERIFIED): MockObject {
  182. $property = $this->createMock(IAccountProperty::class);
  183. $property->expects($this->any())
  184. ->method('getName')
  185. ->willReturn($name);
  186. $property->expects($this->any())
  187. ->method('getValue')
  188. ->willReturn($value);
  189. $property->expects($this->any())
  190. ->method('getScope')
  191. ->willReturn($scope);
  192. $property->expects($this->any())
  193. ->method('getVerified')
  194. ->willReturn($verified);
  195. return $property;
  196. }
  197. protected function getDefaultAccountMock(bool $useDefaultValues = true): MockObject {
  198. $propertyMocks = [
  199. IAccountManager::PROPERTY_DISPLAYNAME => $this->buildPropertyMock(
  200. IAccountManager::PROPERTY_DISPLAYNAME,
  201. 'Default display name',
  202. IAccountManager::SCOPE_FEDERATED,
  203. ),
  204. IAccountManager::PROPERTY_ADDRESS => $this->buildPropertyMock(
  205. IAccountManager::PROPERTY_ADDRESS,
  206. 'Default address',
  207. IAccountManager::SCOPE_LOCAL,
  208. ),
  209. IAccountManager::PROPERTY_WEBSITE => $this->buildPropertyMock(
  210. IAccountManager::PROPERTY_WEBSITE,
  211. 'Default website',
  212. IAccountManager::SCOPE_LOCAL,
  213. ),
  214. IAccountManager::PROPERTY_EMAIL => $this->buildPropertyMock(
  215. IAccountManager::PROPERTY_EMAIL,
  216. 'Default email',
  217. IAccountManager::SCOPE_FEDERATED,
  218. ),
  219. IAccountManager::PROPERTY_AVATAR => $this->buildPropertyMock(
  220. IAccountManager::PROPERTY_AVATAR,
  221. '',
  222. IAccountManager::SCOPE_FEDERATED,
  223. ),
  224. IAccountManager::PROPERTY_PHONE => $this->buildPropertyMock(
  225. IAccountManager::PROPERTY_PHONE,
  226. 'Default phone',
  227. IAccountManager::SCOPE_LOCAL,
  228. ),
  229. IAccountManager::PROPERTY_TWITTER => $this->buildPropertyMock(
  230. IAccountManager::PROPERTY_TWITTER,
  231. 'Default twitter',
  232. IAccountManager::SCOPE_LOCAL,
  233. ),
  234. ];
  235. $account = $this->createMock(IAccount::class);
  236. $account->expects($this->any())
  237. ->method('getProperty')
  238. ->willReturnCallback(function (string $propertyName) use ($propertyMocks) {
  239. if (isset($propertyMocks[$propertyName])) {
  240. return $propertyMocks[$propertyName];
  241. }
  242. throw new PropertyDoesNotExistException($propertyName);
  243. });
  244. $account->expects($this->any())
  245. ->method('getProperties')
  246. ->willReturn($propertyMocks);
  247. return $account;
  248. }
  249. /**
  250. * @dataProvider dataTestSetUserSettings
  251. *
  252. * @param string $email
  253. * @param bool $validEmail
  254. * @param $expectedStatus
  255. */
  256. public function testSetUserSettings($email, $validEmail, $expectedStatus) {
  257. $controller = $this->getController(false, ['saveUserSettings']);
  258. $user = $this->createMock(IUser::class);
  259. $user->method('getUID')->willReturn('johndoe');
  260. $this->userSession->method('getUser')->willReturn($user);
  261. if (!empty($email) && $validEmail) {
  262. $this->mailer->expects($this->once())->method('validateMailAddress')
  263. ->willReturn($validEmail);
  264. }
  265. $saveData = (!empty($email) && $validEmail) || empty($email);
  266. if ($saveData) {
  267. $this->accountManager->expects($this->once())
  268. ->method('getAccount')
  269. ->with($user)
  270. ->willReturn($this->getDefaultAccountMock());
  271. $controller->expects($this->once())
  272. ->method('saveUserSettings');
  273. } else {
  274. $controller->expects($this->never())->method('saveUserSettings');
  275. }
  276. $result = $controller->setUserSettings(//
  277. AccountManager::SCOPE_FEDERATED,
  278. 'displayName',
  279. AccountManager::SCOPE_FEDERATED,
  280. '47658468',
  281. AccountManager::SCOPE_FEDERATED,
  282. $email,
  283. AccountManager::SCOPE_FEDERATED,
  284. 'nextcloud.com',
  285. AccountManager::SCOPE_FEDERATED,
  286. 'street and city',
  287. AccountManager::SCOPE_FEDERATED,
  288. '@nextclouders',
  289. AccountManager::SCOPE_FEDERATED
  290. );
  291. $this->assertSame($expectedStatus, $result->getStatus());
  292. }
  293. public function dataTestSetUserSettings() {
  294. return [
  295. ['', true, Http::STATUS_OK],
  296. ['', false, Http::STATUS_OK],
  297. ['example.com', false, Http::STATUS_UNPROCESSABLE_ENTITY],
  298. ['john@example.com', true, Http::STATUS_OK],
  299. ];
  300. }
  301. public function testSetUserSettingsWhenUserDisplayNameChangeNotAllowed() {
  302. $controller = $this->getController(false, ['saveUserSettings']);
  303. $avatarScope = IAccountManager::SCOPE_PUBLISHED;
  304. $displayName = 'Display name';
  305. $displayNameScope = IAccountManager::SCOPE_PUBLISHED;
  306. $phone = '47658468';
  307. $phoneScope = IAccountManager::SCOPE_PUBLISHED;
  308. $email = 'john@example.com';
  309. $emailScope = IAccountManager::SCOPE_PUBLISHED;
  310. $website = 'nextcloud.com';
  311. $websiteScope = IAccountManager::SCOPE_PUBLISHED;
  312. $address = 'street and city';
  313. $addressScope = IAccountManager::SCOPE_PUBLISHED;
  314. $twitter = '@nextclouders';
  315. $twitterScope = IAccountManager::SCOPE_PUBLISHED;
  316. $user = $this->createMock(IUser::class);
  317. $user->method('getUID')->willReturn('johndoe');
  318. $this->userSession->method('getUser')->willReturn($user);
  319. /** @var MockObject|IAccount $userAccount */
  320. $userAccount = $this->getDefaultAccountMock();
  321. $this->accountManager->expects($this->once())
  322. ->method('getAccount')
  323. ->with($user)
  324. ->willReturn($userAccount);
  325. /** @var MockObject|IAccountProperty $avatarProperty */
  326. $avatarProperty = $userAccount->getProperty(IAccountManager::PROPERTY_AVATAR);
  327. $avatarProperty->expects($this->atLeastOnce())
  328. ->method('setScope')
  329. ->with($avatarScope)
  330. ->willReturnSelf();
  331. /** @var MockObject|IAccountProperty $avatarProperty */
  332. $avatarProperty = $userAccount->getProperty(IAccountManager::PROPERTY_ADDRESS);
  333. $avatarProperty->expects($this->atLeastOnce())
  334. ->method('setScope')
  335. ->with($addressScope)
  336. ->willReturnSelf();
  337. $avatarProperty->expects($this->atLeastOnce())
  338. ->method('setValue')
  339. ->with($address)
  340. ->willReturnSelf();
  341. /** @var MockObject|IAccountProperty $emailProperty */
  342. $emailProperty = $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL);
  343. $emailProperty->expects($this->never())
  344. ->method('setValue');
  345. $emailProperty->expects($this->never())
  346. ->method('setScope');
  347. /** @var MockObject|IAccountProperty $emailProperty */
  348. $emailProperty = $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME);
  349. $emailProperty->expects($this->never())
  350. ->method('setValue');
  351. $emailProperty->expects($this->never())
  352. ->method('setScope');
  353. $this->config->expects($this->once())
  354. ->method('getSystemValueBool')
  355. ->with('allow_user_to_change_display_name')
  356. ->willReturn(false);
  357. $this->appManager->expects($this->any())
  358. ->method('isEnabledForUser')
  359. ->with('federatedfilesharing')
  360. ->willReturn(true);
  361. $this->mailer->expects($this->once())->method('validateMailAddress')
  362. ->willReturn(true);
  363. $controller->expects($this->once())
  364. ->method('saveUserSettings');
  365. $controller->setUserSettings(
  366. $avatarScope,
  367. $displayName,
  368. $displayNameScope,
  369. $phone,
  370. $phoneScope,
  371. $email,
  372. $emailScope,
  373. $website,
  374. $websiteScope,
  375. $address,
  376. $addressScope,
  377. $twitter,
  378. $twitterScope
  379. );
  380. }
  381. public function testSetUserSettingsWhenFederatedFilesharingNotEnabled() {
  382. $controller = $this->getController(false, ['saveUserSettings']);
  383. $user = $this->createMock(IUser::class);
  384. $user->method('getUID')->willReturn('johndoe');
  385. $this->userSession->method('getUser')->willReturn($user);
  386. $defaultProperties = []; //$this->getDefaultAccountMock();
  387. $userAccount = $this->getDefaultAccountMock();
  388. $this->accountManager->expects($this->once())
  389. ->method('getAccount')
  390. ->with($user)
  391. ->willReturn($userAccount);
  392. $this->appManager->expects($this->any())
  393. ->method('isEnabledForUser')
  394. ->with('federatedfilesharing')
  395. ->willReturn(false);
  396. $avatarScope = IAccountManager::SCOPE_PUBLISHED;
  397. $displayName = 'Display name';
  398. $displayNameScope = IAccountManager::SCOPE_PUBLISHED;
  399. $phone = '47658468';
  400. $phoneScope = IAccountManager::SCOPE_PUBLISHED;
  401. $email = 'john@example.com';
  402. $emailScope = IAccountManager::SCOPE_PUBLISHED;
  403. $website = 'nextcloud.com';
  404. $websiteScope = IAccountManager::SCOPE_PUBLISHED;
  405. $address = 'street and city';
  406. $addressScope = IAccountManager::SCOPE_PUBLISHED;
  407. $twitter = '@nextclouders';
  408. $twitterScope = IAccountManager::SCOPE_PUBLISHED;
  409. // All settings are changed (in the past phone, website, address and
  410. // twitter were not changed).
  411. $expectedProperties = $defaultProperties;
  412. $expectedProperties[IAccountManager::PROPERTY_AVATAR]['scope'] = $avatarScope;
  413. $expectedProperties[IAccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
  414. $expectedProperties[IAccountManager::PROPERTY_DISPLAYNAME]['scope'] = $displayNameScope;
  415. $expectedProperties[IAccountManager::PROPERTY_EMAIL]['value'] = $email;
  416. $expectedProperties[IAccountManager::PROPERTY_EMAIL]['scope'] = $emailScope;
  417. $expectedProperties[IAccountManager::PROPERTY_PHONE]['value'] = $phone;
  418. $expectedProperties[IAccountManager::PROPERTY_PHONE]['scope'] = $phoneScope;
  419. $expectedProperties[IAccountManager::PROPERTY_WEBSITE]['value'] = $website;
  420. $expectedProperties[IAccountManager::PROPERTY_WEBSITE]['scope'] = $websiteScope;
  421. $expectedProperties[IAccountManager::PROPERTY_ADDRESS]['value'] = $address;
  422. $expectedProperties[IAccountManager::PROPERTY_ADDRESS]['scope'] = $addressScope;
  423. $expectedProperties[IAccountManager::PROPERTY_TWITTER]['value'] = $twitter;
  424. $expectedProperties[IAccountManager::PROPERTY_TWITTER]['scope'] = $twitterScope;
  425. $this->mailer->expects($this->once())->method('validateMailAddress')
  426. ->willReturn(true);
  427. $controller->expects($this->once())
  428. ->method('saveUserSettings')
  429. ->with($userAccount);
  430. $controller->setUserSettings(
  431. $avatarScope,
  432. $displayName,
  433. $displayNameScope,
  434. $phone,
  435. $phoneScope,
  436. $email,
  437. $emailScope,
  438. $website,
  439. $websiteScope,
  440. $address,
  441. $addressScope,
  442. $twitter,
  443. $twitterScope
  444. );
  445. }
  446. /**
  447. * @dataProvider dataTestSetUserSettingsSubset
  448. *
  449. * @param string $property
  450. * @param string $propertyValue
  451. */
  452. public function testSetUserSettingsSubset($property, $propertyValue) {
  453. $controller = $this->getController(false, ['saveUserSettings']);
  454. $user = $this->createMock(IUser::class);
  455. $user->method('getUID')->willReturn('johndoe');
  456. $this->userSession->method('getUser')->willReturn($user);
  457. /** @var IAccount|MockObject $userAccount */
  458. $userAccount = $this->getDefaultAccountMock();
  459. $this->accountManager->expects($this->once())
  460. ->method('getAccount')
  461. ->with($user)
  462. ->willReturn($userAccount);
  463. $avatarScope = ($property === 'avatarScope') ? $propertyValue : null;
  464. $displayName = ($property === 'displayName') ? $propertyValue : null;
  465. $displayNameScope = ($property === 'displayNameScope') ? $propertyValue : null;
  466. $phone = ($property === 'phone') ? $propertyValue : null;
  467. $phoneScope = ($property === 'phoneScope') ? $propertyValue : null;
  468. $email = ($property === 'email') ? $propertyValue : null;
  469. $emailScope = ($property === 'emailScope') ? $propertyValue : null;
  470. $website = ($property === 'website') ? $propertyValue : null;
  471. $websiteScope = ($property === 'websiteScope') ? $propertyValue : null;
  472. $address = ($property === 'address') ? $propertyValue : null;
  473. $addressScope = ($property === 'addressScope') ? $propertyValue : null;
  474. $twitter = ($property === 'twitter') ? $propertyValue : null;
  475. $twitterScope = ($property === 'twitterScope') ? $propertyValue : null;
  476. /** @var IAccountProperty[]|MockObject[] $expectedProperties */
  477. $expectedProperties = $userAccount->getProperties();
  478. $isScope = strrpos($property, 'Scope') === strlen($property) - strlen(5);
  479. switch ($property) {
  480. case 'avatarScope':
  481. $propertyId = IAccountManager::PROPERTY_AVATAR;
  482. break;
  483. case 'displayName':
  484. case 'displayNameScope':
  485. $propertyId = IAccountManager::PROPERTY_DISPLAYNAME;
  486. break;
  487. case 'phone':
  488. case 'phoneScope':
  489. $propertyId = IAccountManager::PROPERTY_PHONE;
  490. break;
  491. case 'email':
  492. case 'emailScope':
  493. $propertyId = IAccountManager::PROPERTY_EMAIL;
  494. break;
  495. case 'website':
  496. case 'websiteScope':
  497. $propertyId = IAccountManager::PROPERTY_WEBSITE;
  498. break;
  499. case 'address':
  500. case 'addressScope':
  501. $propertyId = IAccountManager::PROPERTY_ADDRESS;
  502. break;
  503. case 'twitter':
  504. case 'twitterScope':
  505. $propertyId = IAccountManager::PROPERTY_TWITTER;
  506. break;
  507. default:
  508. $propertyId = '404';
  509. }
  510. $expectedProperties[$propertyId]->expects($this->any())
  511. ->method($isScope ? 'getScope' : 'getValue')
  512. ->willReturn($propertyValue);
  513. if (!empty($email)) {
  514. $this->mailer->expects($this->once())->method('validateMailAddress')
  515. ->willReturn(true);
  516. }
  517. $controller->expects($this->once())
  518. ->method('saveUserSettings')
  519. ->with($userAccount);
  520. $controller->setUserSettings(
  521. $avatarScope,
  522. $displayName,
  523. $displayNameScope,
  524. $phone,
  525. $phoneScope,
  526. $email,
  527. $emailScope,
  528. $website,
  529. $websiteScope,
  530. $address,
  531. $addressScope,
  532. $twitter,
  533. $twitterScope
  534. );
  535. }
  536. public function dataTestSetUserSettingsSubset() {
  537. return [
  538. ['avatarScope', IAccountManager::SCOPE_PUBLISHED],
  539. ['displayName', 'Display name'],
  540. ['displayNameScope', IAccountManager::SCOPE_PUBLISHED],
  541. ['phone', '47658468'],
  542. ['phoneScope', IAccountManager::SCOPE_PUBLISHED],
  543. ['email', 'john@example.com'],
  544. ['emailScope', IAccountManager::SCOPE_PUBLISHED],
  545. ['website', 'nextcloud.com'],
  546. ['websiteScope', IAccountManager::SCOPE_PUBLISHED],
  547. ['address', 'street and city'],
  548. ['addressScope', IAccountManager::SCOPE_PUBLISHED],
  549. ['twitter', '@nextclouders'],
  550. ['twitterScope', IAccountManager::SCOPE_PUBLISHED],
  551. ];
  552. }
  553. /**
  554. * @dataProvider dataTestSaveUserSettings
  555. *
  556. * @param array $data
  557. * @param string $oldEmailAddress
  558. * @param string $oldDisplayName
  559. */
  560. public function testSaveUserSettings($data,
  561. $oldEmailAddress,
  562. $oldDisplayName
  563. ) {
  564. $controller = $this->getController();
  565. $user = $this->createMock(IUser::class);
  566. $user->method('getDisplayName')->willReturn($oldDisplayName);
  567. $user->method('getSystemEMailAddress')->willReturn($oldEmailAddress);
  568. $user->method('canChangeDisplayName')->willReturn(true);
  569. if ($data[IAccountManager::PROPERTY_EMAIL]['value'] === $oldEmailAddress ||
  570. ($oldEmailAddress === null && $data[IAccountManager::PROPERTY_EMAIL]['value'] === '')) {
  571. $user->expects($this->never())->method('setSystemEMailAddress');
  572. } else {
  573. $user->expects($this->once())->method('setSystemEMailAddress')
  574. ->with($data[IAccountManager::PROPERTY_EMAIL]['value']);
  575. }
  576. if ($data[IAccountManager::PROPERTY_DISPLAYNAME]['value'] === $oldDisplayName ||
  577. ($oldDisplayName === null && $data[IAccountManager::PROPERTY_DISPLAYNAME]['value'] === '')) {
  578. $user->expects($this->never())->method('setDisplayName');
  579. } else {
  580. $user->expects($this->once())->method('setDisplayName')
  581. ->with($data[IAccountManager::PROPERTY_DISPLAYNAME]['value'])
  582. ->willReturn(true);
  583. }
  584. $properties = [];
  585. foreach ($data as $propertyName => $propertyData) {
  586. $properties[$propertyName] = $this->createMock(IAccountProperty::class);
  587. $properties[$propertyName]->expects($this->any())
  588. ->method('getValue')
  589. ->willReturn($propertyData['value']);
  590. }
  591. $account = $this->createMock(IAccount::class);
  592. $account->expects($this->any())
  593. ->method('getUser')
  594. ->willReturn($user);
  595. $account->expects($this->any())
  596. ->method('getProperty')
  597. ->willReturnCallback(function (string $propertyName) use ($properties) {
  598. return $properties[$propertyName];
  599. });
  600. $this->accountManager->expects($this->any())
  601. ->method('getAccount')
  602. ->willReturn($account);
  603. $this->accountManager->expects($this->once())
  604. ->method('updateAccount')
  605. ->with($account);
  606. $this->invokePrivate($controller, 'saveUserSettings', [$account]);
  607. }
  608. public function dataTestSaveUserSettings() {
  609. return [
  610. [
  611. [
  612. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  613. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  614. ],
  615. 'john@example.com',
  616. 'john doe'
  617. ],
  618. [
  619. [
  620. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  621. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  622. ],
  623. 'johnNew@example.com',
  624. 'john New doe'
  625. ],
  626. [
  627. [
  628. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  629. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  630. ],
  631. 'johnNew@example.com',
  632. 'john doe'
  633. ],
  634. [
  635. [
  636. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  637. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  638. ],
  639. 'john@example.com',
  640. 'john New doe'
  641. ],
  642. [
  643. [
  644. IAccountManager::PROPERTY_EMAIL => ['value' => ''],
  645. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  646. ],
  647. null,
  648. 'john New doe'
  649. ],
  650. [
  651. [
  652. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  653. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  654. ],
  655. 'john@example.com',
  656. null
  657. ],
  658. ];
  659. }
  660. /**
  661. * @dataProvider dataTestSaveUserSettingsException
  662. */
  663. public function testSaveUserSettingsException(
  664. array $data,
  665. string $oldEmailAddress,
  666. string $oldDisplayName,
  667. bool $setDisplayNameResult,
  668. bool $canChangeEmail
  669. ) {
  670. $this->expectException(ForbiddenException::class);
  671. $controller = $this->getController();
  672. $user = $this->createMock(IUser::class);
  673. $user->method('getDisplayName')->willReturn($oldDisplayName);
  674. $user->method('getEMailAddress')->willReturn($oldEmailAddress);
  675. /** @var MockObject|IAccount $userAccount */
  676. $userAccount = $this->createMock(IAccount::class);
  677. $userAccount->expects($this->any())
  678. ->method('getUser')
  679. ->willReturn($user);
  680. $propertyMocks = [];
  681. foreach ($data as $propertyName => $propertyData) {
  682. /** @var MockObject|IAccountProperty $property */
  683. $propertyMocks[$propertyName] = $this->buildPropertyMock($propertyName, $propertyData['value'], '');
  684. }
  685. $userAccount->expects($this->any())
  686. ->method('getProperty')
  687. ->willReturnCallback(function (string $propertyName) use ($propertyMocks) {
  688. return $propertyMocks[$propertyName];
  689. });
  690. if ($data[IAccountManager::PROPERTY_EMAIL]['value'] !== $oldEmailAddress) {
  691. $user->method('canChangeDisplayName')
  692. ->willReturn($canChangeEmail);
  693. }
  694. if ($data[IAccountManager::PROPERTY_DISPLAYNAME]['value'] !== $oldDisplayName) {
  695. $user->method('setDisplayName')
  696. ->with($data[IAccountManager::PROPERTY_DISPLAYNAME]['value'])
  697. ->willReturn($setDisplayNameResult);
  698. }
  699. $this->invokePrivate($controller, 'saveUserSettings', [$userAccount]);
  700. }
  701. public function dataTestSaveUserSettingsException() {
  702. return [
  703. [
  704. [
  705. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  706. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  707. ],
  708. 'johnNew@example.com',
  709. 'john New doe',
  710. true,
  711. false
  712. ],
  713. [
  714. [
  715. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  716. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  717. ],
  718. 'johnNew@example.com',
  719. 'john New doe',
  720. false,
  721. true
  722. ],
  723. [
  724. [
  725. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  726. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  727. ],
  728. 'johnNew@example.com',
  729. 'john New doe',
  730. false,
  731. false
  732. ],
  733. ];
  734. }
  735. /**
  736. * @param string $account
  737. * @param string $type
  738. * @param array $dataBefore
  739. * @param array $expectedData
  740. *
  741. * @dataProvider dataTestGetVerificationCode
  742. */
  743. public function testGetVerificationCode($account, $type, $dataBefore, $expectedData, $onlyVerificationCode) {
  744. $message = 'Use my Federated Cloud ID to share with me: user@nextcloud.com';
  745. $signature = 'theSignature';
  746. $code = $message . ' ' . $signature;
  747. if ($type === IAccountManager::PROPERTY_TWITTER) {
  748. $code = $message . ' ' . md5($signature);
  749. }
  750. $controller = $this->getController(false, ['signMessage', 'getCurrentTime']);
  751. $user = $this->createMock(IUser::class);
  752. $property = $this->buildPropertyMock($type, $dataBefore[$type]['value'], '', IAccountManager::NOT_VERIFIED);
  753. $property->expects($this->atLeastOnce())
  754. ->method('setVerified')
  755. ->with(IAccountManager::VERIFICATION_IN_PROGRESS)
  756. ->willReturnSelf();
  757. $property->expects($this->atLeastOnce())
  758. ->method('setVerificationData')
  759. ->with($signature)
  760. ->willReturnSelf();
  761. $userAccount = $this->createMock(IAccount::class);
  762. $userAccount->expects($this->any())
  763. ->method('getUser')
  764. ->willReturn($user);
  765. $userAccount->expects($this->any())
  766. ->method('getProperty')
  767. ->willReturn($property);
  768. $this->userSession->expects($this->once())->method('getUser')->willReturn($user);
  769. $this->accountManager->expects($this->once())->method('getAccount')->with($user)->willReturn($userAccount);
  770. $user->expects($this->any())->method('getCloudId')->willReturn('user@nextcloud.com');
  771. $user->expects($this->any())->method('getUID')->willReturn('uid');
  772. $controller->expects($this->once())->method('signMessage')->with($user, $message)->willReturn($signature);
  773. $controller->expects($this->any())->method('getCurrentTime')->willReturn(1234567);
  774. if ($onlyVerificationCode === false) {
  775. $this->accountManager->expects($this->once())->method('updateAccount')->with($userAccount)->willReturnArgument(1);
  776. $this->jobList->expects($this->once())->method('add')
  777. ->with('OCA\Settings\BackgroundJobs\VerifyUserData',
  778. [
  779. 'verificationCode' => $code,
  780. 'data' => $dataBefore[$type]['value'],
  781. 'type' => $type,
  782. 'uid' => 'uid',
  783. 'try' => 0,
  784. 'lastRun' => 1234567
  785. ]);
  786. }
  787. $result = $controller->getVerificationCode($account, $onlyVerificationCode);
  788. $data = $result->getData();
  789. $this->assertSame(Http::STATUS_OK, $result->getStatus());
  790. $this->assertSame($code, $data['code']);
  791. }
  792. public function dataTestGetVerificationCode() {
  793. $accountDataBefore = [
  794. IAccountManager::PROPERTY_WEBSITE => ['value' => 'https://nextcloud.com', 'verified' => IAccountManager::NOT_VERIFIED],
  795. IAccountManager::PROPERTY_TWITTER => ['value' => '@nextclouders', 'verified' => IAccountManager::NOT_VERIFIED, 'signature' => 'theSignature'],
  796. ];
  797. $accountDataAfterWebsite = [
  798. IAccountManager::PROPERTY_WEBSITE => ['value' => 'https://nextcloud.com', 'verified' => IAccountManager::VERIFICATION_IN_PROGRESS, 'signature' => 'theSignature'],
  799. IAccountManager::PROPERTY_TWITTER => ['value' => '@nextclouders', 'verified' => IAccountManager::NOT_VERIFIED, 'signature' => 'theSignature'],
  800. ];
  801. $accountDataAfterTwitter = [
  802. IAccountManager::PROPERTY_WEBSITE => ['value' => 'https://nextcloud.com', 'verified' => IAccountManager::NOT_VERIFIED],
  803. IAccountManager::PROPERTY_TWITTER => ['value' => '@nextclouders', 'verified' => IAccountManager::VERIFICATION_IN_PROGRESS, 'signature' => 'theSignature'],
  804. ];
  805. return [
  806. ['verify-twitter', IAccountManager::PROPERTY_TWITTER, $accountDataBefore, $accountDataAfterTwitter, false],
  807. ['verify-website', IAccountManager::PROPERTY_WEBSITE, $accountDataBefore, $accountDataAfterWebsite, false],
  808. ['verify-twitter', IAccountManager::PROPERTY_TWITTER, $accountDataBefore, $accountDataAfterTwitter, true],
  809. ['verify-website', IAccountManager::PROPERTY_WEBSITE, $accountDataBefore, $accountDataAfterWebsite, true],
  810. ];
  811. }
  812. /**
  813. * test get verification code in case no valid user was given
  814. */
  815. public function testGetVerificationCodeInvalidUser() {
  816. $controller = $this->getController();
  817. $this->userSession->expects($this->once())->method('getUser')->willReturn(null);
  818. $result = $controller->getVerificationCode('account', false);
  819. $this->assertSame(Http::STATUS_BAD_REQUEST, $result->getStatus());
  820. }
  821. /**
  822. * @dataProvider dataTestCanAdminChangeUserPasswords
  823. *
  824. * @param bool $encryptionEnabled
  825. * @param bool $encryptionModuleLoaded
  826. * @param bool $masterKeyEnabled
  827. * @param bool $expected
  828. */
  829. public function testCanAdminChangeUserPasswords($encryptionEnabled,
  830. $encryptionModuleLoaded,
  831. $masterKeyEnabled,
  832. $expected) {
  833. $controller = $this->getController();
  834. $this->encryptionManager->expects($this->any())
  835. ->method('isEnabled')
  836. ->willReturn($encryptionEnabled);
  837. $this->encryptionManager->expects($this->any())
  838. ->method('getEncryptionModule')
  839. ->willReturnCallback(function () use ($encryptionModuleLoaded) {
  840. if ($encryptionModuleLoaded) {
  841. return $this->encryptionModule;
  842. } else {
  843. throw new ModuleDoesNotExistsException();
  844. }
  845. });
  846. $this->encryptionModule->expects($this->any())
  847. ->method('needDetailedAccessList')
  848. ->willReturn(!$masterKeyEnabled);
  849. $result = $this->invokePrivate($controller, 'canAdminChangeUserPasswords', []);
  850. $this->assertSame($expected, $result);
  851. }
  852. public function dataTestCanAdminChangeUserPasswords() {
  853. return [
  854. // encryptionEnabled, encryptionModuleLoaded, masterKeyEnabled, expectedResult
  855. [true, true, true, true],
  856. [false, true, true, true],
  857. [true, false, true, false],
  858. [false, false, true, true],
  859. [true, true, false, false],
  860. [false, true, false, false],
  861. [true, false, false, false],
  862. [false, false, false, true],
  863. ];
  864. }
  865. }