UsersControllerTest.php 32 KB

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