- mails added by (sub)admins are automatically verified - provisioning_api controller as verification endpoint - IAccountProperty gets a locallyVerified property - IPropertyCollection gets a method to fetch an IAccountProperty by value - an remove equivalent was already present - AccountManager always initiates mail verification on update if necessary - add core success template for arbitrary title and message Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>tags/v23.0.0beta1
['name' => 'AppConfig#setValue', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'POST'], | ['name' => 'AppConfig#setValue', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'POST'], | ||||
['name' => 'AppConfig#deleteKey', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'DELETE'], | ['name' => 'AppConfig#deleteKey', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'DELETE'], | ||||
], | ], | ||||
'routes' => [ | |||||
// Verification | |||||
['name' => 'Verification#verifyMail', 'url' => '/mailVerification/{key}/{token}/{userId}', 'verb' => 'GET'], | |||||
] | |||||
]; | ]; |
'OCA\\Provisioning_API\\Controller\\AppsController' => $baseDir . '/../lib/Controller/AppsController.php', | 'OCA\\Provisioning_API\\Controller\\AppsController' => $baseDir . '/../lib/Controller/AppsController.php', | ||||
'OCA\\Provisioning_API\\Controller\\GroupsController' => $baseDir . '/../lib/Controller/GroupsController.php', | 'OCA\\Provisioning_API\\Controller\\GroupsController' => $baseDir . '/../lib/Controller/GroupsController.php', | ||||
'OCA\\Provisioning_API\\Controller\\UsersController' => $baseDir . '/../lib/Controller/UsersController.php', | 'OCA\\Provisioning_API\\Controller\\UsersController' => $baseDir . '/../lib/Controller/UsersController.php', | ||||
'OCA\\Provisioning_API\\Controller\\VerificationController' => $baseDir . '/../lib/Controller/VerificationController.php', | |||||
'OCA\\Provisioning_API\\FederatedShareProviderFactory' => $baseDir . '/../lib/FederatedShareProviderFactory.php', | 'OCA\\Provisioning_API\\FederatedShareProviderFactory' => $baseDir . '/../lib/FederatedShareProviderFactory.php', | ||||
'OCA\\Provisioning_API\\Listener\\UserDeletedListener' => $baseDir . '/../lib/Listener/UserDeletedListener.php', | 'OCA\\Provisioning_API\\Listener\\UserDeletedListener' => $baseDir . '/../lib/Listener/UserDeletedListener.php', | ||||
'OCA\\Provisioning_API\\Middleware\\Exceptions\\NotSubAdminException' => $baseDir . '/../lib/Middleware/Exceptions/NotSubAdminException.php', | 'OCA\\Provisioning_API\\Middleware\\Exceptions\\NotSubAdminException' => $baseDir . '/../lib/Middleware/Exceptions/NotSubAdminException.php', |
'OCA\\Provisioning_API\\Controller\\AppsController' => __DIR__ . '/..' . '/../lib/Controller/AppsController.php', | 'OCA\\Provisioning_API\\Controller\\AppsController' => __DIR__ . '/..' . '/../lib/Controller/AppsController.php', | ||||
'OCA\\Provisioning_API\\Controller\\GroupsController' => __DIR__ . '/..' . '/../lib/Controller/GroupsController.php', | 'OCA\\Provisioning_API\\Controller\\GroupsController' => __DIR__ . '/..' . '/../lib/Controller/GroupsController.php', | ||||
'OCA\\Provisioning_API\\Controller\\UsersController' => __DIR__ . '/..' . '/../lib/Controller/UsersController.php', | 'OCA\\Provisioning_API\\Controller\\UsersController' => __DIR__ . '/..' . '/../lib/Controller/UsersController.php', | ||||
'OCA\\Provisioning_API\\Controller\\VerificationController' => __DIR__ . '/..' . '/../lib/Controller/VerificationController.php', | |||||
'OCA\\Provisioning_API\\FederatedShareProviderFactory' => __DIR__ . '/..' . '/../lib/FederatedShareProviderFactory.php', | 'OCA\\Provisioning_API\\FederatedShareProviderFactory' => __DIR__ . '/..' . '/../lib/FederatedShareProviderFactory.php', | ||||
'OCA\\Provisioning_API\\Listener\\UserDeletedListener' => __DIR__ . '/..' . '/../lib/Listener/UserDeletedListener.php', | 'OCA\\Provisioning_API\\Listener\\UserDeletedListener' => __DIR__ . '/..' . '/../lib/Listener/UserDeletedListener.php', | ||||
'OCA\\Provisioning_API\\Middleware\\Exceptions\\NotSubAdminException' => __DIR__ . '/..' . '/../lib/Middleware/Exceptions/NotSubAdminException.php', | 'OCA\\Provisioning_API\\Middleware\\Exceptions\\NotSubAdminException' => __DIR__ . '/..' . '/../lib/Middleware/Exceptions/NotSubAdminException.php', |
'type' => 'library', | 'type' => 'library', | ||||
'install_path' => __DIR__ . '/../', | 'install_path' => __DIR__ . '/../', | ||||
'aliases' => array(), | 'aliases' => array(), | ||||
'reference' => 'fa56c13484afa1baf908b93ed5b6990c6a0e9ad6', | |||||
'reference' => '2e49000abb5acb09de041369a2239db23fa63ec7', | |||||
'name' => '__root__', | 'name' => '__root__', | ||||
'dev' => false, | 'dev' => false, | ||||
), | ), | ||||
'type' => 'library', | 'type' => 'library', | ||||
'install_path' => __DIR__ . '/../', | 'install_path' => __DIR__ . '/../', | ||||
'aliases' => array(), | 'aliases' => array(), | ||||
'reference' => 'fa56c13484afa1baf908b93ed5b6990c6a0e9ad6', | |||||
'reference' => '2e49000abb5acb09de041369a2239db23fa63ec7', | |||||
'dev_requirement' => false, | 'dev_requirement' => false, | ||||
), | ), | ||||
), | ), |
throw new OCSException('', OCSController::RESPOND_NOT_FOUND); | throw new OCSException('', OCSController::RESPOND_NOT_FOUND); | ||||
} | } | ||||
$subAdminManager = $this->groupManager->getSubAdmin(); | |||||
$isAdminOrSubadmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID()) | |||||
|| $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser); | |||||
$permittedFields = []; | $permittedFields = []; | ||||
if ($targetUser->getUID() === $currentLoggedInUser->getUID()) { | if ($targetUser->getUID() === $currentLoggedInUser->getUID()) { | ||||
// Editing self (display, email) | // Editing self (display, email) | ||||
$permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX; | $permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX; | ||||
} else { | } else { | ||||
// Check if admin / subadmin | // Check if admin / subadmin | ||||
$subAdminManager = $this->groupManager->getSubAdmin(); | |||||
if ($this->groupManager->isAdmin($currentLoggedInUser->getUID()) | |||||
|| $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) { | |||||
if ($isAdminOrSubadmin) { | |||||
// They have permissions over the user | // They have permissions over the user | ||||
$permittedFields[] = IAccountManager::COLLECTION_EMAIL; | $permittedFields[] = IAccountManager::COLLECTION_EMAIL; | ||||
} else { | } else { | ||||
// No rights | // No rights | ||||
$mailCollection->removePropertyByValue($key); | $mailCollection->removePropertyByValue($key); | ||||
if ($value !== '') { | if ($value !== '') { | ||||
$mailCollection->addPropertyWithDefaults($value); | $mailCollection->addPropertyWithDefaults($value); | ||||
$property = $mailCollection->getPropertyByValue($key); | |||||
if ($isAdminOrSubadmin && $property) { | |||||
// admin set mails are auto-verified | |||||
$property->setLocallyVerified(IAccountManager::VERIFIED); | |||||
} | |||||
} | } | ||||
$this->accountManager->updateAccount($userAccount); | $this->accountManager->updateAccount($userAccount); | ||||
break; | break; |
<?php | |||||
declare(strict_types=1); | |||||
/** | |||||
* @copyright Copyright (c) 2021 Arthur Schiwon <blizzz@arthur-schiwon.de> | |||||
* | |||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de> | |||||
* | |||||
* @license GNU AGPL version 3 or any later version | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License as | |||||
* published by the Free Software Foundation, either version 3 of the | |||||
* License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Affero General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public License | |||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
namespace OCA\Provisioning_API\Controller; | |||||
use InvalidArgumentException; | |||||
use OC\Security\Crypto; | |||||
use OCP\Accounts\IAccountManager; | |||||
use OCP\AppFramework\Controller; | |||||
use OCP\AppFramework\Http\TemplateResponse; | |||||
use OCP\IL10N; | |||||
use OCP\IRequest; | |||||
use OCP\IUserManager; | |||||
use OCP\IUserSession; | |||||
use OCP\Security\VerificationToken\InvalidTokenException; | |||||
use OCP\Security\VerificationToken\IVerificationToken; | |||||
class VerificationController extends Controller { | |||||
/** @var IVerificationToken */ | |||||
private $verificationToken; | |||||
/** @var IUserManager */ | |||||
private $userManager; | |||||
/** @var IL10N */ | |||||
private $l10n; | |||||
/** @var IUserSession */ | |||||
private $userSession; | |||||
/** @var IAccountManager */ | |||||
private $accountManager; | |||||
/** @var Crypto */ | |||||
private $crypto; | |||||
public function __construct( | |||||
string $appName, | |||||
IRequest $request, | |||||
IVerificationToken $verificationToken, | |||||
IUserManager $userManager, | |||||
IL10N $l10n, | |||||
IUserSession $userSession, | |||||
IAccountManager $accountManager, | |||||
Crypto $crypto | |||||
) { | |||||
parent::__construct($appName, $request); | |||||
$this->verificationToken = $verificationToken; | |||||
$this->userManager = $userManager; | |||||
$this->l10n = $l10n; | |||||
$this->userSession = $userSession; | |||||
$this->accountManager = $accountManager; | |||||
$this->crypto = $crypto; | |||||
} | |||||
/** | |||||
* @NoCSRFRequired | |||||
*/ | |||||
public function verifyMail(string $token, string $userId, string $key) { | |||||
try { | |||||
if ($this->userSession->getUser()->getUID() !== $userId) { | |||||
throw new InvalidArgumentException('Logged in user is not mail address owner'); | |||||
} | |||||
$email = $this->crypto->decrypt($key); | |||||
$ref = \substr(hash('sha256', $email), 0, 8); | |||||
$user = $this->userManager->get($userId); | |||||
$this->verificationToken->check($token, $user, 'verifyMail' . $ref, $email); | |||||
$userAccount = $this->accountManager->getAccount($user); | |||||
$emailProperty = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL) | |||||
->getPropertyByValue($email); | |||||
if ($emailProperty === null) { | |||||
throw new InvalidArgumentException($this->l10n->t('Email was already removed from account and cannot be confirmed anymore.')); | |||||
} | |||||
$emailProperty->setLocallyVerified(IAccountManager::VERIFIED); | |||||
$this->accountManager->updateAccount($userAccount); | |||||
} catch (InvalidTokenException $e) { | |||||
$error = $e->getCode() === InvalidTokenException::TOKEN_EXPIRED | |||||
? $this->l10n->t('Could not verify mail because the token is expired.') | |||||
: $this->l10n->t('Could not verify mail because the token is invalid.'); | |||||
} catch (InvalidArgumentException $e) { | |||||
$error = $e->getMessage(); | |||||
} catch (\Exception $e) { | |||||
$error = $this->l10n->t('An unexpected error occurred. Please consult your sysadmin.'); | |||||
} | |||||
if (isset($error)) { | |||||
return new TemplateResponse( | |||||
'core', 'error', [ | |||||
'errors' => [['error' => $error]] | |||||
], 'guest'); | |||||
} | |||||
return new TemplateResponse( | |||||
'core', 'success', [ | |||||
'title' => $this->l10n->t('Email confirmation successful'), | |||||
'message' => $this->l10n->t('Email confirmation successful'), | |||||
], 'guest'); | |||||
} | |||||
} |
<?php | |||||
/** @var array $_ */ | |||||
/** @var \OCP\IL10N $l */ | |||||
/** @var \OCP\Defaults $theme */ | |||||
?> | |||||
<div class="update"> | |||||
<h2><?php p($_['title']) ?></h2> | |||||
<p><?php p($_['message']) ?></p> | |||||
<p><a class="button primary" href="<?php p(\OC::$server->get(\OCP\IURLGenerator::class)->linkTo('', 'index.php')) ?>"> | |||||
<?php p($l->t('Go to %s', [$theme->getName()])); ?> | |||||
</a></p> | |||||
</div> |
*/ | */ | ||||
namespace OC\Accounts; | namespace OC\Accounts; | ||||
use Exception; | |||||
use InvalidArgumentException; | use InvalidArgumentException; | ||||
use libphonenumber\NumberParseException; | use libphonenumber\NumberParseException; | ||||
use libphonenumber\PhoneNumber; | use libphonenumber\PhoneNumber; | ||||
use OCP\Accounts\PropertyDoesNotExistException; | use OCP\Accounts\PropertyDoesNotExistException; | ||||
use OCP\BackgroundJob\IJobList; | use OCP\BackgroundJob\IJobList; | ||||
use OCP\DB\QueryBuilder\IQueryBuilder; | use OCP\DB\QueryBuilder\IQueryBuilder; | ||||
use OCP\Defaults; | |||||
use OCP\IConfig; | use OCP\IConfig; | ||||
use OCP\IDBConnection; | use OCP\IDBConnection; | ||||
use OCP\IL10N; | |||||
use OCP\IURLGenerator; | |||||
use OCP\IUser; | use OCP\IUser; | ||||
use OCP\L10N\IFactory; | |||||
use OCP\Mail\IMailer; | |||||
use OCP\Security\ICrypto; | |||||
use OCP\Security\VerificationToken\IVerificationToken; | |||||
use OCP\Util; | |||||
use Psr\Log\LoggerInterface; | use Psr\Log\LoggerInterface; | ||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||||
use Symfony\Component\EventDispatcher\GenericEvent; | use Symfony\Component\EventDispatcher\GenericEvent; | ||||
/** @var LoggerInterface */ | /** @var LoggerInterface */ | ||||
private $logger; | private $logger; | ||||
public function __construct(IDBConnection $connection, | |||||
IConfig $config, | |||||
EventDispatcherInterface $eventDispatcher, | |||||
IJobList $jobList, | |||||
LoggerInterface $logger) { | |||||
/** @var IVerificationToken */ | |||||
private $verificationToken; | |||||
/** @var IMailer */ | |||||
private $mailer; | |||||
/** @var Defaults */ | |||||
private $defaults; | |||||
/** @var IL10N */ | |||||
private $l10n; | |||||
/** @var IURLGenerator */ | |||||
private $urlGenerator; | |||||
/** @var ICrypto */ | |||||
private $crypto; | |||||
/** @var IFactory */ | |||||
private $l10nfactory; | |||||
public function __construct( | |||||
IDBConnection $connection, | |||||
IConfig $config, | |||||
EventDispatcherInterface $eventDispatcher, | |||||
IJobList $jobList, | |||||
LoggerInterface $logger, | |||||
IVerificationToken $verificationToken, | |||||
IMailer $mailer, | |||||
Defaults $defaults, | |||||
IFactory $factory, | |||||
IURLGenerator $urlGenerator, | |||||
ICrypto $crypto | |||||
) { | |||||
$this->connection = $connection; | $this->connection = $connection; | ||||
$this->config = $config; | $this->config = $config; | ||||
$this->eventDispatcher = $eventDispatcher; | $this->eventDispatcher = $eventDispatcher; | ||||
$this->jobList = $jobList; | $this->jobList = $jobList; | ||||
$this->logger = $logger; | $this->logger = $logger; | ||||
$this->verificationToken = $verificationToken; | |||||
$this->mailer = $mailer; | |||||
$this->defaults = $defaults; | |||||
$this->urlGenerator = $urlGenerator; | |||||
$this->crypto = $crypto; | |||||
// DIing IL10N results in a dependency loop | |||||
$this->l10nfactory = $factory; | |||||
} | } | ||||
/** | /** | ||||
/** | /** | ||||
* check if we need to ask the server for email verification, if yes we create a cronjob | * check if we need to ask the server for email verification, if yes we create a cronjob | ||||
* | |||||
*/ | */ | ||||
protected function checkEmailVerification(IAccount $updatedAccount, array $oldData): void { | protected function checkEmailVerification(IAccount $updatedAccount, array $oldData): void { | ||||
try { | try { | ||||
] | ] | ||||
); | ); | ||||
$property->setVerified(self::VERIFICATION_IN_PROGRESS); | |||||
} | |||||
} | |||||
protected function checkLocalEmailVerification(IAccount $updatedAccount, array $oldData): void { | |||||
$mailCollection = $updatedAccount->getPropertyCollection(self::COLLECTION_EMAIL); | |||||
foreach ($mailCollection->getProperties() as $property) { | |||||
if ($property->getLocallyVerified() !== self::NOT_VERIFIED) { | |||||
continue; | |||||
} | |||||
if ($this->sendEmailVerificationEmail($updatedAccount->getUser(), $property->getValue())) { | |||||
$property->setLocallyVerified(self::VERIFICATION_IN_PROGRESS); | |||||
} | |||||
} | |||||
} | |||||
protected function sendEmailVerificationEmail(IUser $user, string $email): bool { | |||||
$ref = \substr(hash('sha256', $email), 0, 8); | |||||
$key = $this->crypto->encrypt($email); | |||||
$token = $this->verificationToken->create($user, 'verifyMail' . $ref, $email); | |||||
$link = $this->urlGenerator->linkToRouteAbsolute('provisioning_api.Verification.verifyMail', | |||||
[ | |||||
'userId' => $user->getUID(), | |||||
'token' => $token, | |||||
'key' => $key | |||||
]); | |||||
$emailTemplate = $this->mailer->createEMailTemplate('core.EmailVerification', [ | |||||
'link' => $link, | |||||
]); | |||||
$property->setVerified(self::VERIFICATION_IN_PROGRESS); | |||||
if (!$this->l10n) { | |||||
$this->l10n = $this->l10nfactory->get('core'); | |||||
} | } | ||||
$emailTemplate->setSubject($this->l10n->t('%s email verification', [$this->defaults->getName()])); | |||||
$emailTemplate->addHeader(); | |||||
$emailTemplate->addHeading($this->l10n->t('Email verification')); | |||||
$emailTemplate->addBodyText( | |||||
htmlspecialchars($this->l10n->t('Click the following button to confirm your email.')), | |||||
$this->l10n->t('Click the following link to confirm your email.') | |||||
); | |||||
$emailTemplate->addBodyButton( | |||||
htmlspecialchars($this->l10n->t('Confirm your email')), | |||||
$link, | |||||
false | |||||
); | |||||
$emailTemplate->addFooter(); | |||||
try { | |||||
$message = $this->mailer->createMessage(); | |||||
$message->setTo([$email => $user->getDisplayName()]); | |||||
$message->setFrom([Util::getDefaultEmailAddress('verification-noreply') => $this->defaults->getName()]); | |||||
$message->useTemplate($emailTemplate); | |||||
$this->mailer->send($message); | |||||
} catch (Exception $e) { | |||||
// Log the exception and continue | |||||
$this->logger->info('Failed to send verification mail', [ | |||||
'app' => 'core', | |||||
'exception' => $e | |||||
]); | |||||
return false; | |||||
} | |||||
return true; | |||||
} | } | ||||
/** | /** | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* add new user to accounts table | * add new user to accounts table | ||||
* | * | ||||
foreach ($data as $dataRow) { | foreach ($data as $dataRow) { | ||||
$propertyName = $dataRow['name']; | $propertyName = $dataRow['name']; | ||||
unset($dataRow['name']); | unset($dataRow['name']); | ||||
if (isset($dataRow['locallyVerified']) && $dataRow['locallyVerified'] === self::NOT_VERIFIED) { | |||||
// do not write default value, save DB space | |||||
unset($dataRow['locallyVerified']); | |||||
} | |||||
if (!$this->isCollection($propertyName)) { | if (!$this->isCollection($propertyName)) { | ||||
$preparedData[$propertyName] = $dataRow; | $preparedData[$propertyName] = $dataRow; | ||||
continue; | continue; | ||||
continue; | continue; | ||||
} | } | ||||
$query->setParameter('name', $property['name']) | $query->setParameter('name', $property['name']) | ||||
->setParameter('value', $property['value'] ?? ''); | ->setParameter('value', $property['value'] ?? ''); | ||||
$query->executeStatement(); | $query->executeStatement(); | ||||
$data['verified'] ?? self::NOT_VERIFIED, | $data['verified'] ?? self::NOT_VERIFIED, | ||||
'' | '' | ||||
); | ); | ||||
$p->setLocallyVerified($data['locallyVerified'] ?? self::NOT_VERIFIED); | |||||
$collection->addProperty($p); | $collection->addProperty($p); | ||||
return $collection; | return $collection; | ||||
$account->setPropertyCollection($this->arrayDataToCollection($account, $accountData)); | $account->setPropertyCollection($this->arrayDataToCollection($account, $accountData)); | ||||
} else { | } else { | ||||
$account->setProperty($accountData['name'], $accountData['value'] ?? '', $accountData['scope'] ?? self::SCOPE_LOCAL, $accountData['verified'] ?? self::NOT_VERIFIED); | $account->setProperty($accountData['name'], $accountData['value'] ?? '', $accountData['scope'] ?? self::SCOPE_LOCAL, $accountData['verified'] ?? self::NOT_VERIFIED); | ||||
if (isset($accountData['locallyVerified'])) { | |||||
$property = $account->getProperty($accountData['name']); | |||||
$property->setLocallyVerified($accountData['locallyVerified']); | |||||
} | |||||
} | } | ||||
} | } | ||||
return $account; | return $account; | ||||
$oldData = $this->getUser($account->getUser(), false); | $oldData = $this->getUser($account->getUser(), false); | ||||
$this->updateVerificationStatus($account, $oldData); | $this->updateVerificationStatus($account, $oldData); | ||||
$this->checkEmailVerification($account, $oldData); | $this->checkEmailVerification($account, $oldData); | ||||
$this->checkLocalEmailVerification($account, $oldData); | |||||
$data = []; | $data = []; | ||||
foreach ($account->getAllProperties() as $property) { | foreach ($account->getAllProperties() as $property) { | ||||
/** @var IAccountProperty $property */ | |||||
$data[] = [ | $data[] = [ | ||||
'name' => $property->getName(), | 'name' => $property->getName(), | ||||
'value' => $property->getValue(), | 'value' => $property->getValue(), | ||||
'scope' => $property->getScope(), | 'scope' => $property->getScope(), | ||||
'verified' => $property->getVerified(), | 'verified' => $property->getVerified(), | ||||
'locallyVerified' => $property->getLocallyVerified(), | |||||
]; | ]; | ||||
} | } | ||||
*/ | */ | ||||
namespace OC\Accounts; | namespace OC\Accounts; | ||||
use InvalidArgumentException; | |||||
use OCP\Accounts\IAccountManager; | use OCP\Accounts\IAccountManager; | ||||
use OCP\Accounts\IAccountProperty; | use OCP\Accounts\IAccountProperty; | ||||
private $verified; | private $verified; | ||||
/** @var string */ | /** @var string */ | ||||
private $verificationData; | private $verificationData; | ||||
/** @var string */ | |||||
private $locallyVerified = IAccountManager::NOT_VERIFIED; | |||||
public function __construct(string $name, string $value, string $scope, string $verified, string $verificationData) { | public function __construct(string $name, string $value, string $scope, string $verified, string $verificationData) { | ||||
$this->name = $name; | $this->name = $name; | ||||
IAccountManager::SCOPE_PRIVATE, | IAccountManager::SCOPE_PRIVATE, | ||||
IAccountManager::SCOPE_PUBLISHED | IAccountManager::SCOPE_PUBLISHED | ||||
])) { | ])) { | ||||
throw new \InvalidArgumentException('Invalid scope'); | |||||
throw new InvalidArgumentException('Invalid scope'); | |||||
} | } | ||||
$this->scope = $newScope; | $this->scope = $newScope; | ||||
return $this; | return $this; | ||||
public function getVerificationData(): string { | public function getVerificationData(): string { | ||||
return $this->verificationData; | return $this->verificationData; | ||||
} | } | ||||
public function setLocallyVerified(string $verified): IAccountProperty { | |||||
if (!in_array($verified, [ | |||||
IAccountManager::NOT_VERIFIED, | |||||
IAccountManager::VERIFICATION_IN_PROGRESS, | |||||
IAccountManager::VERIFIED, | |||||
])) { | |||||
throw new InvalidArgumentException('Provided verification value is invalid'); | |||||
} | |||||
$this->locallyVerified = $verified; | |||||
return $this; | |||||
} | |||||
public function getLocallyVerified(): string { | |||||
return $this->locallyVerified; | |||||
} | |||||
} | } |
return $this; | return $this; | ||||
} | } | ||||
public function getPropertyByValue(string $value): ?IAccountProperty { | |||||
foreach ($this->properties as $i => $property) { | |||||
if ($property->getValue() === $value) { | |||||
return $property; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
public function removePropertyByValue(string $value): IAccountPropertyCollection { | public function removePropertyByValue(string $value): IAccountPropertyCollection { | ||||
foreach ($this->properties as $i => $property) { | foreach ($this->properties as $i => $property) { | ||||
if ($property->getValue() === $value) { | if ($property->getValue() === $value) { |
use OC\Security\Hasher; | use OC\Security\Hasher; | ||||
use OC\Security\SecureRandom; | use OC\Security\SecureRandom; | ||||
use OC\Security\TrustedDomainHelper; | use OC\Security\TrustedDomainHelper; | ||||
use OC\Security\VerificationToken\VerificationToken; | |||||
use OC\Session\CryptoWrapper; | use OC\Session\CryptoWrapper; | ||||
use OC\Share20\ProviderFactory; | use OC\Share20\ProviderFactory; | ||||
use OC\Share20\ShareHelper; | use OC\Share20\ShareHelper; | ||||
use OCP\Security\ICrypto; | use OCP\Security\ICrypto; | ||||
use OCP\Security\IHasher; | use OCP\Security\IHasher; | ||||
use OCP\Security\ISecureRandom; | use OCP\Security\ISecureRandom; | ||||
use OCP\Security\VerificationToken\IVerificationToken; | |||||
use OCP\Share\IShareHelper; | use OCP\Share\IShareHelper; | ||||
use OCP\SystemTag\ISystemTagManager; | use OCP\SystemTag\ISystemTagManager; | ||||
use OCP\SystemTag\ISystemTagObjectMapper; | use OCP\SystemTag\ISystemTagObjectMapper; | ||||
/** @deprecated 19.0.0 */ | /** @deprecated 19.0.0 */ | ||||
$this->registerDeprecatedAlias('SecureRandom', \OCP\Security\ISecureRandom::class); | $this->registerDeprecatedAlias('SecureRandom', \OCP\Security\ISecureRandom::class); | ||||
$this->registerAlias(IVerificationToken::class, VerificationToken::class); | |||||
$this->registerAlias(ICrypto::class, Crypto::class); | $this->registerAlias(ICrypto::class, Crypto::class); | ||||
/** @deprecated 19.0.0 */ | /** @deprecated 19.0.0 */ | ||||
$this->registerDeprecatedAlias('Crypto', ICrypto::class); | $this->registerDeprecatedAlias('Crypto', ICrypto::class); |
* @since 22.0.0 | * @since 22.0.0 | ||||
*/ | */ | ||||
public function getVerificationData(): string; | public function getVerificationData(): string; | ||||
/** | |||||
* Set the instance-based verification status of a property | |||||
* | |||||
* @since 23.0.0 | |||||
* | |||||
* @param string $verified must be one of the verification constants of IAccountManager | |||||
* @return IAccountProperty | |||||
* @throws InvalidArgumentException | |||||
*/ | |||||
public function setLocallyVerified(string $verified): IAccountProperty; | |||||
/** | |||||
* Get the instance-based verification status of a property | |||||
* | |||||
* @since 23.0.0 | |||||
* | |||||
* @return string | |||||
*/ | |||||
public function getLocallyVerified(): string; | |||||
} | } |
* @since 22.0.0 | * @since 22.0.0 | ||||
*/ | */ | ||||
public function removePropertyByValue(string $value): IAccountPropertyCollection; | public function removePropertyByValue(string $value): IAccountPropertyCollection; | ||||
/** | |||||
* retrieves a property identified by its value. null, if none was found. | |||||
* | |||||
* Returns only the first property if there are more with the same value. | |||||
* | |||||
* @since 23.0.0 | |||||
*/ | |||||
public function getPropertyByValue(string $value): ?IAccountProperty; | |||||
} | } |
use OC\Accounts\AccountManager; | use OC\Accounts\AccountManager; | ||||
use OCP\Accounts\IAccountManager; | use OCP\Accounts\IAccountManager; | ||||
use OCP\BackgroundJob\IJobList; | use OCP\BackgroundJob\IJobList; | ||||
use OCP\Defaults; | |||||
use OCP\IConfig; | use OCP\IConfig; | ||||
use OCP\IDBConnection; | use OCP\IDBConnection; | ||||
use OCP\IURLGenerator; | |||||
use OCP\IUser; | use OCP\IUser; | ||||
use OCP\L10N\IFactory; | |||||
use OCP\Mail\IMailer; | |||||
use OCP\Security\ICrypto; | |||||
use OCP\Security\VerificationToken\IVerificationToken; | |||||
use PHPUnit\Framework\MockObject\MockObject; | use PHPUnit\Framework\MockObject\MockObject; | ||||
use Psr\Log\LoggerInterface; | use Psr\Log\LoggerInterface; | ||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||||
* @package Test\Accounts | * @package Test\Accounts | ||||
*/ | */ | ||||
class AccountManagerTest extends TestCase { | class AccountManagerTest extends TestCase { | ||||
/** @var IVerificationToken|MockObject */ | |||||
protected $verificationToken; | |||||
/** @var IMailer|MockObject */ | |||||
protected $mailer; | |||||
/** @var ICrypto|MockObject */ | |||||
protected $crypto; | |||||
/** @var IURLGenerator|MockObject */ | |||||
protected $urlGenerator; | |||||
/** @var Defaults|MockObject */ | |||||
protected $defaults; | |||||
/** @var IFactory|MockObject */ | |||||
protected $l10nFactory; | |||||
/** @var \OCP\IDBConnection */ | /** @var \OCP\IDBConnection */ | ||||
private $connection; | private $connection; | ||||
$this->config = $this->createMock(IConfig::class); | $this->config = $this->createMock(IConfig::class); | ||||
$this->jobList = $this->createMock(IJobList::class); | $this->jobList = $this->createMock(IJobList::class); | ||||
$this->logger = $this->createMock(LoggerInterface::class); | $this->logger = $this->createMock(LoggerInterface::class); | ||||
$this->verificationToken = $this->createMock(IVerificationToken::class); | |||||
$this->mailer = $this->createMock(IMailer::class); | |||||
$this->defaults = $this->createMock(Defaults::class); | |||||
$this->l10nFactory = $this->createMock(IFactory::class); | |||||
$this->urlGenerator = $this->createMock(IURLGenerator::class); | |||||
$this->crypto = $this->createMock(ICrypto::class); | |||||
$this->accountManager = new AccountManager( | $this->accountManager = new AccountManager( | ||||
$this->connection, | $this->connection, | ||||
$this->eventDispatcher, | $this->eventDispatcher, | ||||
$this->jobList, | $this->jobList, | ||||
$this->logger, | $this->logger, | ||||
$this->verificationToken, | |||||
$this->mailer, | |||||
$this->defaults, | |||||
$this->l10nFactory, | |||||
$this->urlGenerator, | |||||
$this->crypto | |||||
); | ); | ||||
} | } | ||||
$this->eventDispatcher, | $this->eventDispatcher, | ||||
$this->jobList, | $this->jobList, | ||||
$this->logger, | $this->logger, | ||||
$this->verificationToken, | |||||
$this->mailer, | |||||
$this->defaults, | |||||
$this->l10nFactory, | |||||
$this->urlGenerator, | |||||
$this->crypto | |||||
]) | ]) | ||||
->setMethods($mockedMethods) | ->setMethods($mockedMethods) | ||||
->getMock(); | ->getMock(); |