1
0

UsersControllerTest.php 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  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. IAccountManager::PROPERTY_PRONOUNS => $this->buildPropertyMock(
  217. IAccountManager::PROPERTY_PRONOUNS,
  218. 'Default pronouns',
  219. IAccountManager::SCOPE_LOCAL,
  220. ),
  221. ];
  222. $account = $this->createMock(IAccount::class);
  223. $account->expects($this->any())
  224. ->method('getProperty')
  225. ->willReturnCallback(function (string $propertyName) use ($propertyMocks) {
  226. if (isset($propertyMocks[$propertyName])) {
  227. return $propertyMocks[$propertyName];
  228. }
  229. throw new PropertyDoesNotExistException($propertyName);
  230. });
  231. $account->expects($this->any())
  232. ->method('getProperties')
  233. ->willReturn($propertyMocks);
  234. return $account;
  235. }
  236. /**
  237. * @dataProvider dataTestSetUserSettings
  238. *
  239. * @param string $email
  240. * @param bool $validEmail
  241. * @param $expectedStatus
  242. */
  243. public function testSetUserSettings($email, $validEmail, $expectedStatus): void {
  244. $controller = $this->getController(false, ['saveUserSettings']);
  245. $user = $this->createMock(IUser::class);
  246. $user->method('getUID')->willReturn('johndoe');
  247. $this->userSession->method('getUser')->willReturn($user);
  248. if (!empty($email) && $validEmail) {
  249. $this->mailer->expects($this->once())->method('validateMailAddress')
  250. ->willReturn($validEmail);
  251. }
  252. $saveData = (!empty($email) && $validEmail) || empty($email);
  253. if ($saveData) {
  254. $this->accountManager->expects($this->once())
  255. ->method('getAccount')
  256. ->with($user)
  257. ->willReturn($this->getDefaultAccountMock());
  258. $controller->expects($this->once())
  259. ->method('saveUserSettings');
  260. } else {
  261. $controller->expects($this->never())->method('saveUserSettings');
  262. }
  263. $result = $controller->setUserSettings(
  264. AccountManager::SCOPE_FEDERATED,
  265. 'displayName',
  266. AccountManager::SCOPE_FEDERATED,
  267. '47658468',
  268. AccountManager::SCOPE_FEDERATED,
  269. $email,
  270. AccountManager::SCOPE_FEDERATED,
  271. 'nextcloud.com',
  272. AccountManager::SCOPE_FEDERATED,
  273. 'street and city',
  274. AccountManager::SCOPE_FEDERATED,
  275. '@nextclouders',
  276. AccountManager::SCOPE_FEDERATED,
  277. '@nextclouders',
  278. AccountManager::SCOPE_FEDERATED,
  279. '2020-01-01',
  280. AccountManager::SCOPE_FEDERATED,
  281. 'they/them',
  282. AccountManager::SCOPE_FEDERATED,
  283. );
  284. $this->assertSame($expectedStatus, $result->getStatus());
  285. }
  286. public function dataTestSetUserSettings() {
  287. return [
  288. ['', true, Http::STATUS_OK],
  289. ['', false, Http::STATUS_OK],
  290. ['example.com', false, Http::STATUS_UNPROCESSABLE_ENTITY],
  291. ['john@example.com', true, Http::STATUS_OK],
  292. ];
  293. }
  294. public function testSetUserSettingsWhenUserDisplayNameChangeNotAllowed(): void {
  295. $controller = $this->getController(false, ['saveUserSettings']);
  296. $avatarScope = IAccountManager::SCOPE_PUBLISHED;
  297. $displayName = 'Display name';
  298. $displayNameScope = IAccountManager::SCOPE_PUBLISHED;
  299. $phone = '47658468';
  300. $phoneScope = IAccountManager::SCOPE_PUBLISHED;
  301. $email = 'john@example.com';
  302. $emailScope = IAccountManager::SCOPE_PUBLISHED;
  303. $website = 'nextcloud.com';
  304. $websiteScope = IAccountManager::SCOPE_PUBLISHED;
  305. $address = 'street and city';
  306. $addressScope = IAccountManager::SCOPE_PUBLISHED;
  307. $twitter = '@nextclouders';
  308. $twitterScope = IAccountManager::SCOPE_PUBLISHED;
  309. $fediverse = '@nextclouders@floss.social';
  310. $fediverseScope = IAccountManager::SCOPE_PUBLISHED;
  311. $birtdate = '2020-01-01';
  312. $birthdateScope = IAccountManager::SCOPE_PUBLISHED;
  313. $pronouns = 'she/her';
  314. $pronounsScope = IAccountManager::SCOPE_PUBLISHED;
  315. $user = $this->createMock(IUser::class);
  316. $user->method('getUID')->willReturn('johndoe');
  317. $this->userSession->method('getUser')->willReturn($user);
  318. /** @var MockObject|IAccount $userAccount */
  319. $userAccount = $this->getDefaultAccountMock();
  320. $this->accountManager->expects($this->once())
  321. ->method('getAccount')
  322. ->with($user)
  323. ->willReturn($userAccount);
  324. /** @var MockObject|IAccountProperty $avatarProperty */
  325. $avatarProperty = $userAccount->getProperty(IAccountManager::PROPERTY_AVATAR);
  326. $avatarProperty->expects($this->atLeastOnce())
  327. ->method('setScope')
  328. ->with($avatarScope)
  329. ->willReturnSelf();
  330. /** @var MockObject|IAccountProperty $avatarProperty */
  331. $avatarProperty = $userAccount->getProperty(IAccountManager::PROPERTY_ADDRESS);
  332. $avatarProperty->expects($this->atLeastOnce())
  333. ->method('setScope')
  334. ->with($addressScope)
  335. ->willReturnSelf();
  336. $avatarProperty->expects($this->atLeastOnce())
  337. ->method('setValue')
  338. ->with($address)
  339. ->willReturnSelf();
  340. /** @var MockObject|IAccountProperty $emailProperty */
  341. $emailProperty = $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL);
  342. $emailProperty->expects($this->never())
  343. ->method('setValue');
  344. $emailProperty->expects($this->never())
  345. ->method('setScope');
  346. /** @var MockObject|IAccountProperty $emailProperty */
  347. $emailProperty = $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME);
  348. $emailProperty->expects($this->never())
  349. ->method('setValue');
  350. $emailProperty->expects($this->never())
  351. ->method('setScope');
  352. $this->config->expects($this->once())
  353. ->method('getSystemValueBool')
  354. ->with('allow_user_to_change_display_name')
  355. ->willReturn(false);
  356. $this->appManager->expects($this->any())
  357. ->method('isEnabledForUser')
  358. ->with('federatedfilesharing')
  359. ->willReturn(true);
  360. $this->mailer->expects($this->once())->method('validateMailAddress')
  361. ->willReturn(true);
  362. $controller->expects($this->once())
  363. ->method('saveUserSettings');
  364. $controller->setUserSettings(
  365. $avatarScope,
  366. $displayName,
  367. $displayNameScope,
  368. $phone,
  369. $phoneScope,
  370. $email,
  371. $emailScope,
  372. $website,
  373. $websiteScope,
  374. $address,
  375. $addressScope,
  376. $twitter,
  377. $twitterScope,
  378. $fediverse,
  379. $fediverseScope,
  380. $birtdate,
  381. $birthdateScope,
  382. $pronouns,
  383. $pronounsScope,
  384. );
  385. }
  386. public function testSetUserSettingsWhenFederatedFilesharingNotEnabled(): void {
  387. $controller = $this->getController(false, ['saveUserSettings']);
  388. $user = $this->createMock(IUser::class);
  389. $user->method('getUID')->willReturn('johndoe');
  390. $this->userSession->method('getUser')->willReturn($user);
  391. $defaultProperties = []; //$this->getDefaultAccountMock();
  392. $userAccount = $this->getDefaultAccountMock();
  393. $this->accountManager->expects($this->once())
  394. ->method('getAccount')
  395. ->with($user)
  396. ->willReturn($userAccount);
  397. $this->appManager->expects($this->any())
  398. ->method('isEnabledForUser')
  399. ->with('federatedfilesharing')
  400. ->willReturn(false);
  401. $avatarScope = IAccountManager::SCOPE_PUBLISHED;
  402. $displayName = 'Display name';
  403. $displayNameScope = IAccountManager::SCOPE_PUBLISHED;
  404. $phone = '47658468';
  405. $phoneScope = IAccountManager::SCOPE_PUBLISHED;
  406. $email = 'john@example.com';
  407. $emailScope = IAccountManager::SCOPE_PUBLISHED;
  408. $website = 'nextcloud.com';
  409. $websiteScope = IAccountManager::SCOPE_PUBLISHED;
  410. $address = 'street and city';
  411. $addressScope = IAccountManager::SCOPE_PUBLISHED;
  412. $twitter = '@nextclouders';
  413. $twitterScope = IAccountManager::SCOPE_PUBLISHED;
  414. $fediverse = '@nextclouders@floss.social';
  415. $fediverseScope = IAccountManager::SCOPE_PUBLISHED;
  416. $birthdate = '2020-01-01';
  417. $birthdateScope = IAccountManager::SCOPE_PUBLISHED;
  418. $pronouns = 'she/her';
  419. $pronounsScope = IAccountManager::SCOPE_PUBLISHED;
  420. // All settings are changed (in the past phone, website, address and
  421. // twitter were not changed).
  422. $expectedProperties = $defaultProperties;
  423. $expectedProperties[IAccountManager::PROPERTY_AVATAR]['scope'] = $avatarScope;
  424. $expectedProperties[IAccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
  425. $expectedProperties[IAccountManager::PROPERTY_DISPLAYNAME]['scope'] = $displayNameScope;
  426. $expectedProperties[IAccountManager::PROPERTY_EMAIL]['value'] = $email;
  427. $expectedProperties[IAccountManager::PROPERTY_EMAIL]['scope'] = $emailScope;
  428. $expectedProperties[IAccountManager::PROPERTY_PHONE]['value'] = $phone;
  429. $expectedProperties[IAccountManager::PROPERTY_PHONE]['scope'] = $phoneScope;
  430. $expectedProperties[IAccountManager::PROPERTY_WEBSITE]['value'] = $website;
  431. $expectedProperties[IAccountManager::PROPERTY_WEBSITE]['scope'] = $websiteScope;
  432. $expectedProperties[IAccountManager::PROPERTY_ADDRESS]['value'] = $address;
  433. $expectedProperties[IAccountManager::PROPERTY_ADDRESS]['scope'] = $addressScope;
  434. $expectedProperties[IAccountManager::PROPERTY_TWITTER]['value'] = $twitter;
  435. $expectedProperties[IAccountManager::PROPERTY_TWITTER]['scope'] = $twitterScope;
  436. $expectedProperties[IAccountManager::PROPERTY_FEDIVERSE]['value'] = $fediverse;
  437. $expectedProperties[IAccountManager::PROPERTY_FEDIVERSE]['scope'] = $fediverseScope;
  438. $expectedProperties[IAccountManager::PROPERTY_BIRTHDATE]['value'] = $birthdate;
  439. $expectedProperties[IAccountManager::PROPERTY_BIRTHDATE]['scope'] = $birthdateScope;
  440. $expectedProperties[IAccountManager::PROPERTY_PRONOUNS]['value'] = $pronouns;
  441. $expectedProperties[IAccountManager::PROPERTY_PRONOUNS]['scope'] = $pronounsScope;
  442. $this->mailer->expects($this->once())->method('validateMailAddress')
  443. ->willReturn(true);
  444. $controller->expects($this->once())
  445. ->method('saveUserSettings')
  446. ->with($userAccount);
  447. $controller->setUserSettings(
  448. $avatarScope,
  449. $displayName,
  450. $displayNameScope,
  451. $phone,
  452. $phoneScope,
  453. $email,
  454. $emailScope,
  455. $website,
  456. $websiteScope,
  457. $address,
  458. $addressScope,
  459. $twitter,
  460. $twitterScope,
  461. $fediverse,
  462. $fediverseScope,
  463. $birthdate,
  464. $birthdateScope,
  465. $pronouns,
  466. $pronounsScope,
  467. );
  468. }
  469. /**
  470. * @dataProvider dataTestSetUserSettingsSubset
  471. *
  472. * @param string $property
  473. * @param string $propertyValue
  474. */
  475. public function testSetUserSettingsSubset($property, $propertyValue): void {
  476. $controller = $this->getController(false, ['saveUserSettings']);
  477. $user = $this->createMock(IUser::class);
  478. $user->method('getUID')->willReturn('johndoe');
  479. $this->userSession->method('getUser')->willReturn($user);
  480. /** @var IAccount|MockObject $userAccount */
  481. $userAccount = $this->getDefaultAccountMock();
  482. $this->accountManager->expects($this->once())
  483. ->method('getAccount')
  484. ->with($user)
  485. ->willReturn($userAccount);
  486. $avatarScope = ($property === 'avatarScope') ? $propertyValue : null;
  487. $displayName = ($property === 'displayName') ? $propertyValue : null;
  488. $displayNameScope = ($property === 'displayNameScope') ? $propertyValue : null;
  489. $phone = ($property === 'phone') ? $propertyValue : null;
  490. $phoneScope = ($property === 'phoneScope') ? $propertyValue : null;
  491. $email = ($property === 'email') ? $propertyValue : null;
  492. $emailScope = ($property === 'emailScope') ? $propertyValue : null;
  493. $website = ($property === 'website') ? $propertyValue : null;
  494. $websiteScope = ($property === 'websiteScope') ? $propertyValue : null;
  495. $address = ($property === 'address') ? $propertyValue : null;
  496. $addressScope = ($property === 'addressScope') ? $propertyValue : null;
  497. $twitter = ($property === 'twitter') ? $propertyValue : null;
  498. $twitterScope = ($property === 'twitterScope') ? $propertyValue : null;
  499. $fediverse = ($property === 'fediverse') ? $propertyValue : null;
  500. $fediverseScope = ($property === 'fediverseScope') ? $propertyValue : null;
  501. $birthdate = ($property === 'birthdate') ? $propertyValue : null;
  502. $birthdateScope = ($property === 'birthdateScope') ? $propertyValue : null;
  503. $pronouns = ($property === 'pronouns') ? $propertyValue : null;
  504. $pronounsScope = ($property === 'pronounsScope') ? $propertyValue : null;
  505. /** @var IAccountProperty[]|MockObject[] $expectedProperties */
  506. $expectedProperties = $userAccount->getProperties();
  507. $isScope = strrpos($property, 'Scope') === strlen($property) - strlen(5);
  508. switch ($property) {
  509. case 'avatarScope':
  510. $propertyId = IAccountManager::PROPERTY_AVATAR;
  511. break;
  512. case 'displayName':
  513. case 'displayNameScope':
  514. $propertyId = IAccountManager::PROPERTY_DISPLAYNAME;
  515. break;
  516. case 'phone':
  517. case 'phoneScope':
  518. $propertyId = IAccountManager::PROPERTY_PHONE;
  519. break;
  520. case 'email':
  521. case 'emailScope':
  522. $propertyId = IAccountManager::PROPERTY_EMAIL;
  523. break;
  524. case 'website':
  525. case 'websiteScope':
  526. $propertyId = IAccountManager::PROPERTY_WEBSITE;
  527. break;
  528. case 'address':
  529. case 'addressScope':
  530. $propertyId = IAccountManager::PROPERTY_ADDRESS;
  531. break;
  532. case 'twitter':
  533. case 'twitterScope':
  534. $propertyId = IAccountManager::PROPERTY_TWITTER;
  535. break;
  536. case 'fediverse':
  537. case 'fediverseScope':
  538. $propertyId = IAccountManager::PROPERTY_FEDIVERSE;
  539. break;
  540. case 'birthdate':
  541. case 'birthdateScope':
  542. $propertyId = IAccountManager::PROPERTY_BIRTHDATE;
  543. break;
  544. case 'pronouns':
  545. case 'pronounsScope':
  546. $propertyId = IAccountManager::PROPERTY_PRONOUNS;
  547. break;
  548. default:
  549. $propertyId = '404';
  550. }
  551. $expectedProperties[$propertyId]->expects($this->any())
  552. ->method($isScope ? 'getScope' : 'getValue')
  553. ->willReturn($propertyValue);
  554. if (!empty($email)) {
  555. $this->mailer->expects($this->once())->method('validateMailAddress')
  556. ->willReturn(true);
  557. }
  558. $controller->expects($this->once())
  559. ->method('saveUserSettings')
  560. ->with($userAccount);
  561. $controller->setUserSettings(
  562. $avatarScope,
  563. $displayName,
  564. $displayNameScope,
  565. $phone,
  566. $phoneScope,
  567. $email,
  568. $emailScope,
  569. $website,
  570. $websiteScope,
  571. $address,
  572. $addressScope,
  573. $twitter,
  574. $twitterScope,
  575. $fediverse,
  576. $fediverseScope,
  577. $birthdate,
  578. $birthdateScope,
  579. $pronouns,
  580. $pronounsScope,
  581. );
  582. }
  583. public function dataTestSetUserSettingsSubset() {
  584. return [
  585. ['avatarScope', IAccountManager::SCOPE_PUBLISHED],
  586. ['displayName', 'Display name'],
  587. ['displayNameScope', IAccountManager::SCOPE_PUBLISHED],
  588. ['phone', '47658468'],
  589. ['phoneScope', IAccountManager::SCOPE_PUBLISHED],
  590. ['email', 'john@example.com'],
  591. ['emailScope', IAccountManager::SCOPE_PUBLISHED],
  592. ['website', 'nextcloud.com'],
  593. ['websiteScope', IAccountManager::SCOPE_PUBLISHED],
  594. ['address', 'street and city'],
  595. ['addressScope', IAccountManager::SCOPE_PUBLISHED],
  596. ['twitter', '@nextclouders'],
  597. ['twitterScope', IAccountManager::SCOPE_PUBLISHED],
  598. ['fediverse', '@nextclouders@floss.social'],
  599. ['fediverseScope', IAccountManager::SCOPE_PUBLISHED],
  600. ['birthdate', '2020-01-01'],
  601. ['birthdateScope', IAccountManager::SCOPE_PUBLISHED],
  602. ['pronouns', 'he/him'],
  603. ['pronounsScope', IAccountManager::SCOPE_PUBLISHED],
  604. ];
  605. }
  606. /**
  607. * @dataProvider dataTestSaveUserSettings
  608. *
  609. * @param array $data
  610. * @param ?string $oldEmailAddress
  611. * @param ?string $oldDisplayName
  612. */
  613. public function testSaveUserSettings($data,
  614. $oldEmailAddress,
  615. $oldDisplayName,
  616. ): void {
  617. $controller = $this->getController();
  618. $user = $this->createMock(IUser::class);
  619. $user->method('getDisplayName')->willReturn($oldDisplayName);
  620. $user->method('getSystemEMailAddress')->willReturn($oldEmailAddress);
  621. $user->method('canChangeDisplayName')->willReturn(true);
  622. if (strtolower($data[IAccountManager::PROPERTY_EMAIL]['value']) === strtolower($oldEmailAddress ?? '')) {
  623. $user->expects($this->never())->method('setSystemEMailAddress');
  624. } else {
  625. $user->expects($this->once())->method('setSystemEMailAddress')
  626. ->with($data[IAccountManager::PROPERTY_EMAIL]['value']);
  627. }
  628. if ($data[IAccountManager::PROPERTY_DISPLAYNAME]['value'] === $oldDisplayName ?? '') {
  629. $user->expects($this->never())->method('setDisplayName');
  630. } else {
  631. $user->expects($this->once())->method('setDisplayName')
  632. ->with($data[IAccountManager::PROPERTY_DISPLAYNAME]['value'])
  633. ->willReturn(true);
  634. }
  635. $properties = [];
  636. foreach ($data as $propertyName => $propertyData) {
  637. $properties[$propertyName] = $this->createMock(IAccountProperty::class);
  638. $properties[$propertyName]->expects($this->any())
  639. ->method('getValue')
  640. ->willReturn($propertyData['value']);
  641. }
  642. $account = $this->createMock(IAccount::class);
  643. $account->expects($this->any())
  644. ->method('getUser')
  645. ->willReturn($user);
  646. $account->expects($this->any())
  647. ->method('getProperty')
  648. ->willReturnCallback(function (string $propertyName) use ($properties) {
  649. return $properties[$propertyName];
  650. });
  651. $this->accountManager->expects($this->any())
  652. ->method('getAccount')
  653. ->willReturn($account);
  654. $this->accountManager->expects($this->once())
  655. ->method('updateAccount')
  656. ->with($account);
  657. $this->invokePrivate($controller, 'saveUserSettings', [$account]);
  658. }
  659. public function dataTestSaveUserSettings() {
  660. return [
  661. [
  662. [
  663. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  664. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  665. ],
  666. 'john@example.com',
  667. 'john doe'
  668. ],
  669. [
  670. [
  671. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  672. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  673. ],
  674. 'johnNew@example.com',
  675. 'john New doe'
  676. ],
  677. [
  678. [
  679. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  680. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  681. ],
  682. 'johnNew@example.com',
  683. 'john doe'
  684. ],
  685. [
  686. [
  687. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  688. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  689. ],
  690. 'john@example.com',
  691. 'john New doe'
  692. ],
  693. [
  694. [
  695. IAccountManager::PROPERTY_EMAIL => ['value' => ''],
  696. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  697. ],
  698. null,
  699. 'john New doe'
  700. ],
  701. [
  702. [
  703. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  704. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  705. ],
  706. 'john@example.com',
  707. null
  708. ],
  709. [
  710. [
  711. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  712. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  713. ],
  714. 'JOHN@example.com',
  715. null
  716. ],
  717. ];
  718. }
  719. /**
  720. * @dataProvider dataTestSaveUserSettingsException
  721. */
  722. public function testSaveUserSettingsException(
  723. array $data,
  724. string $oldEmailAddress,
  725. string $oldDisplayName,
  726. bool $setDisplayNameResult,
  727. bool $canChangeEmail,
  728. ): void {
  729. $this->expectException(ForbiddenException::class);
  730. $controller = $this->getController();
  731. $user = $this->createMock(IUser::class);
  732. $user->method('getDisplayName')->willReturn($oldDisplayName);
  733. $user->method('getEMailAddress')->willReturn($oldEmailAddress);
  734. /** @var MockObject|IAccount $userAccount */
  735. $userAccount = $this->createMock(IAccount::class);
  736. $userAccount->expects($this->any())
  737. ->method('getUser')
  738. ->willReturn($user);
  739. $propertyMocks = [];
  740. foreach ($data as $propertyName => $propertyData) {
  741. /** @var MockObject|IAccountProperty $property */
  742. $propertyMocks[$propertyName] = $this->buildPropertyMock($propertyName, $propertyData['value'], '');
  743. }
  744. $userAccount->expects($this->any())
  745. ->method('getProperty')
  746. ->willReturnCallback(function (string $propertyName) use ($propertyMocks) {
  747. return $propertyMocks[$propertyName];
  748. });
  749. if ($data[IAccountManager::PROPERTY_EMAIL]['value'] !== $oldEmailAddress) {
  750. $user->method('canChangeDisplayName')
  751. ->willReturn($canChangeEmail);
  752. }
  753. if ($data[IAccountManager::PROPERTY_DISPLAYNAME]['value'] !== $oldDisplayName) {
  754. $user->method('setDisplayName')
  755. ->with($data[IAccountManager::PROPERTY_DISPLAYNAME]['value'])
  756. ->willReturn($setDisplayNameResult);
  757. }
  758. $this->invokePrivate($controller, 'saveUserSettings', [$userAccount]);
  759. }
  760. public function dataTestSaveUserSettingsException() {
  761. return [
  762. [
  763. [
  764. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  765. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  766. ],
  767. 'johnNew@example.com',
  768. 'john New doe',
  769. true,
  770. false
  771. ],
  772. [
  773. [
  774. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  775. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  776. ],
  777. 'johnNew@example.com',
  778. 'john New doe',
  779. false,
  780. true
  781. ],
  782. [
  783. [
  784. IAccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'],
  785. IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'],
  786. ],
  787. 'johnNew@example.com',
  788. 'john New doe',
  789. false,
  790. false
  791. ],
  792. ];
  793. }
  794. /**
  795. * @param string $account
  796. * @param string $type
  797. * @param array $dataBefore
  798. * @param array $expectedData
  799. *
  800. * @dataProvider dataTestGetVerificationCode
  801. */
  802. public function testGetVerificationCode($account, $type, $dataBefore, $expectedData, $onlyVerificationCode): void {
  803. $message = 'Use my Federated Cloud ID to share with me: user@nextcloud.com';
  804. $signature = 'theSignature';
  805. $code = $message . ' ' . $signature;
  806. if ($type === IAccountManager::PROPERTY_TWITTER || $type === IAccountManager::PROPERTY_FEDIVERSE) {
  807. $code = $message . ' ' . md5($signature);
  808. }
  809. $controller = $this->getController(false, ['signMessage', 'getCurrentTime']);
  810. $user = $this->createMock(IUser::class);
  811. $property = $this->buildPropertyMock($type, $dataBefore[$type]['value'], '', IAccountManager::NOT_VERIFIED);
  812. $property->expects($this->atLeastOnce())
  813. ->method('setVerified')
  814. ->with(IAccountManager::VERIFICATION_IN_PROGRESS)
  815. ->willReturnSelf();
  816. $property->expects($this->atLeastOnce())
  817. ->method('setVerificationData')
  818. ->with($signature)
  819. ->willReturnSelf();
  820. $userAccount = $this->createMock(IAccount::class);
  821. $userAccount->expects($this->any())
  822. ->method('getUser')
  823. ->willReturn($user);
  824. $userAccount->expects($this->any())
  825. ->method('getProperty')
  826. ->willReturn($property);
  827. $this->userSession->expects($this->once())->method('getUser')->willReturn($user);
  828. $this->accountManager->expects($this->once())->method('getAccount')->with($user)->willReturn($userAccount);
  829. $user->expects($this->any())->method('getCloudId')->willReturn('user@nextcloud.com');
  830. $user->expects($this->any())->method('getUID')->willReturn('uid');
  831. $controller->expects($this->once())->method('signMessage')->with($user, $message)->willReturn($signature);
  832. $controller->expects($this->any())->method('getCurrentTime')->willReturn(1234567);
  833. if ($onlyVerificationCode === false) {
  834. $this->accountManager->expects($this->once())->method('updateAccount')->with($userAccount)->willReturnArgument(1);
  835. $this->jobList->expects($this->once())->method('add')
  836. ->with('OCA\Settings\BackgroundJobs\VerifyUserData',
  837. [
  838. 'verificationCode' => $code,
  839. 'data' => $dataBefore[$type]['value'],
  840. 'type' => $type,
  841. 'uid' => 'uid',
  842. 'try' => 0,
  843. 'lastRun' => 1234567
  844. ]);
  845. }
  846. $result = $controller->getVerificationCode($account, $onlyVerificationCode);
  847. $data = $result->getData();
  848. $this->assertSame(Http::STATUS_OK, $result->getStatus());
  849. $this->assertSame($code, $data['code']);
  850. }
  851. public function dataTestGetVerificationCode() {
  852. $accountDataBefore = [
  853. IAccountManager::PROPERTY_WEBSITE => ['value' => 'https://nextcloud.com', 'verified' => IAccountManager::NOT_VERIFIED],
  854. IAccountManager::PROPERTY_TWITTER => ['value' => '@nextclouders', 'verified' => IAccountManager::NOT_VERIFIED, 'signature' => 'theSignature'],
  855. ];
  856. $accountDataAfterWebsite = [
  857. IAccountManager::PROPERTY_WEBSITE => ['value' => 'https://nextcloud.com', 'verified' => IAccountManager::VERIFICATION_IN_PROGRESS, 'signature' => 'theSignature'],
  858. IAccountManager::PROPERTY_TWITTER => ['value' => '@nextclouders', 'verified' => IAccountManager::NOT_VERIFIED, 'signature' => 'theSignature'],
  859. ];
  860. $accountDataAfterTwitter = [
  861. IAccountManager::PROPERTY_WEBSITE => ['value' => 'https://nextcloud.com', 'verified' => IAccountManager::NOT_VERIFIED],
  862. IAccountManager::PROPERTY_TWITTER => ['value' => '@nextclouders', 'verified' => IAccountManager::VERIFICATION_IN_PROGRESS, 'signature' => 'theSignature'],
  863. ];
  864. return [
  865. ['verify-twitter', IAccountManager::PROPERTY_TWITTER, $accountDataBefore, $accountDataAfterTwitter, false],
  866. ['verify-website', IAccountManager::PROPERTY_WEBSITE, $accountDataBefore, $accountDataAfterWebsite, false],
  867. ['verify-twitter', IAccountManager::PROPERTY_TWITTER, $accountDataBefore, $accountDataAfterTwitter, true],
  868. ['verify-website', IAccountManager::PROPERTY_WEBSITE, $accountDataBefore, $accountDataAfterWebsite, true],
  869. ];
  870. }
  871. /**
  872. * test get verification code in case no valid user was given
  873. */
  874. public function testGetVerificationCodeInvalidUser(): void {
  875. $controller = $this->getController();
  876. $this->userSession->expects($this->once())->method('getUser')->willReturn(null);
  877. $result = $controller->getVerificationCode('account', false);
  878. $this->assertSame(Http::STATUS_BAD_REQUEST, $result->getStatus());
  879. }
  880. /**
  881. * @dataProvider dataTestCanAdminChangeUserPasswords
  882. *
  883. * @param bool $encryptionEnabled
  884. * @param bool $encryptionModuleLoaded
  885. * @param bool $masterKeyEnabled
  886. * @param bool $expected
  887. */
  888. public function testCanAdminChangeUserPasswords($encryptionEnabled,
  889. $encryptionModuleLoaded,
  890. $masterKeyEnabled,
  891. $expected): void {
  892. $controller = $this->getController();
  893. $this->encryptionManager->expects($this->any())
  894. ->method('isEnabled')
  895. ->willReturn($encryptionEnabled);
  896. $this->encryptionManager->expects($this->any())
  897. ->method('getEncryptionModule')
  898. ->willReturnCallback(function () use ($encryptionModuleLoaded) {
  899. if ($encryptionModuleLoaded) {
  900. return $this->encryptionModule;
  901. } else {
  902. throw new ModuleDoesNotExistsException();
  903. }
  904. });
  905. $this->encryptionModule->expects($this->any())
  906. ->method('needDetailedAccessList')
  907. ->willReturn(!$masterKeyEnabled);
  908. $result = $this->invokePrivate($controller, 'canAdminChangeUserPasswords', []);
  909. $this->assertSame($expected, $result);
  910. }
  911. public function dataTestCanAdminChangeUserPasswords() {
  912. return [
  913. // encryptionEnabled, encryptionModuleLoaded, masterKeyEnabled, expectedResult
  914. [true, true, true, true],
  915. [false, true, true, true],
  916. [true, false, true, false],
  917. [false, false, true, true],
  918. [true, true, false, false],
  919. [false, true, false, false],
  920. [true, false, false, false],
  921. [false, false, false, true],
  922. ];
  923. }
  924. }