UsersControllerTest.php 32 KB

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