UsersControllerTest.php 31 KB

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