Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/provisioning_api/appinfo/routes.php4
-rw-r--r--apps/provisioning_api/composer/composer/autoload_classmap.php1
-rw-r--r--apps/provisioning_api/composer/composer/autoload_static.php1
-rw-r--r--apps/provisioning_api/composer/composer/installed.php4
-rw-r--r--apps/provisioning_api/lib/Controller/UsersController.php14
-rw-r--r--apps/provisioning_api/lib/Controller/VerificationController.php121
-rw-r--r--core/templates/success.php13
-rw-r--r--lib/private/Accounts/AccountManager.php131
-rw-r--r--lib/private/Accounts/AccountProperty.php21
-rw-r--r--lib/private/Accounts/AccountPropertyCollection.php9
-rw-r--r--lib/private/Server.php4
-rw-r--r--lib/public/Accounts/IAccountProperty.php20
-rw-r--r--lib/public/Accounts/IAccountPropertyCollection.php9
-rw-r--r--tests/lib/Accounts/AccountManagerTest.php36
14 files changed, 371 insertions, 17 deletions
diff --git a/apps/provisioning_api/appinfo/routes.php b/apps/provisioning_api/appinfo/routes.php
index 2f981e0c924..81a5bb94e02 100644
--- a/apps/provisioning_api/appinfo/routes.php
+++ b/apps/provisioning_api/appinfo/routes.php
@@ -74,4 +74,8 @@ return [
['name' => 'AppConfig#setValue', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'POST'],
['name' => 'AppConfig#deleteKey', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'DELETE'],
],
+ 'routes' => [
+ // Verification
+ ['name' => 'Verification#verifyMail', 'url' => '/mailVerification/{key}/{token}/{userId}', 'verb' => 'GET'],
+ ]
];
diff --git a/apps/provisioning_api/composer/composer/autoload_classmap.php b/apps/provisioning_api/composer/composer/autoload_classmap.php
index 22927806e65..447f92afc8d 100644
--- a/apps/provisioning_api/composer/composer/autoload_classmap.php
+++ b/apps/provisioning_api/composer/composer/autoload_classmap.php
@@ -14,6 +14,7 @@ return array(
'OCA\\Provisioning_API\\Controller\\AppsController' => $baseDir . '/../lib/Controller/AppsController.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\\VerificationController' => $baseDir . '/../lib/Controller/VerificationController.php',
'OCA\\Provisioning_API\\FederatedShareProviderFactory' => $baseDir . '/../lib/FederatedShareProviderFactory.php',
'OCA\\Provisioning_API\\Listener\\UserDeletedListener' => $baseDir . '/../lib/Listener/UserDeletedListener.php',
'OCA\\Provisioning_API\\Middleware\\Exceptions\\NotSubAdminException' => $baseDir . '/../lib/Middleware/Exceptions/NotSubAdminException.php',
diff --git a/apps/provisioning_api/composer/composer/autoload_static.php b/apps/provisioning_api/composer/composer/autoload_static.php
index f5a4b73f4f8..6dbf6b45c79 100644
--- a/apps/provisioning_api/composer/composer/autoload_static.php
+++ b/apps/provisioning_api/composer/composer/autoload_static.php
@@ -29,6 +29,7 @@ class ComposerStaticInitProvisioning_API
'OCA\\Provisioning_API\\Controller\\AppsController' => __DIR__ . '/..' . '/../lib/Controller/AppsController.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\\VerificationController' => __DIR__ . '/..' . '/../lib/Controller/VerificationController.php',
'OCA\\Provisioning_API\\FederatedShareProviderFactory' => __DIR__ . '/..' . '/../lib/FederatedShareProviderFactory.php',
'OCA\\Provisioning_API\\Listener\\UserDeletedListener' => __DIR__ . '/..' . '/../lib/Listener/UserDeletedListener.php',
'OCA\\Provisioning_API\\Middleware\\Exceptions\\NotSubAdminException' => __DIR__ . '/..' . '/../lib/Middleware/Exceptions/NotSubAdminException.php',
diff --git a/apps/provisioning_api/composer/composer/installed.php b/apps/provisioning_api/composer/composer/installed.php
index 244245bc0cf..9f53826650b 100644
--- a/apps/provisioning_api/composer/composer/installed.php
+++ b/apps/provisioning_api/composer/composer/installed.php
@@ -5,7 +5,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
- 'reference' => 'fb5ee6087bfd1f4cc2f37cda7a7cab7072aaae86',
+ 'reference' => '13a9cd28a5a5d92e285df040d084d5d608e2f768',
'name' => '__root__',
'dev' => false,
),
@@ -16,7 +16,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
- 'reference' => 'fb5ee6087bfd1f4cc2f37cda7a7cab7072aaae86',
+ 'reference' => '13a9cd28a5a5d92e285df040d084d5d608e2f768',
'dev_requirement' => false,
),
),
diff --git a/apps/provisioning_api/lib/Controller/UsersController.php b/apps/provisioning_api/lib/Controller/UsersController.php
index 20472bebace..114dfcb074a 100644
--- a/apps/provisioning_api/lib/Controller/UsersController.php
+++ b/apps/provisioning_api/lib/Controller/UsersController.php
@@ -621,6 +621,10 @@ class UsersController extends AUserData {
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
+ $subAdminManager = $this->groupManager->getSubAdmin();
+ $isAdminOrSubadmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID())
+ || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser);
+
$permittedFields = [];
if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
// Editing self (display, email)
@@ -628,11 +632,8 @@ class UsersController extends AUserData {
$permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX;
} else {
// 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
-
$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
} else {
// No rights
@@ -652,6 +653,11 @@ class UsersController extends AUserData {
$mailCollection->removePropertyByValue($key);
if ($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);
break;
diff --git a/apps/provisioning_api/lib/Controller/VerificationController.php b/apps/provisioning_api/lib/Controller/VerificationController.php
new file mode 100644
index 00000000000..b248d3e8285
--- /dev/null
+++ b/apps/provisioning_api/lib/Controller/VerificationController.php
@@ -0,0 +1,121 @@
+<?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');
+ }
+}
diff --git a/core/templates/success.php b/core/templates/success.php
new file mode 100644
index 00000000000..5ce8ff4f045
--- /dev/null
+++ b/core/templates/success.php
@@ -0,0 +1,13 @@
+<?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>
diff --git a/lib/private/Accounts/AccountManager.php b/lib/private/Accounts/AccountManager.php
index 9fc5accfa08..a3f971df6a1 100644
--- a/lib/private/Accounts/AccountManager.php
+++ b/lib/private/Accounts/AccountManager.php
@@ -32,6 +32,7 @@
*/
namespace OC\Accounts;
+use Exception;
use InvalidArgumentException;
use libphonenumber\NumberParseException;
use libphonenumber\PhoneNumber;
@@ -45,9 +46,17 @@ use OCP\Accounts\IAccountPropertyCollection;
use OCP\Accounts\PropertyDoesNotExistException;
use OCP\BackgroundJob\IJobList;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\Defaults;
use OCP\IConfig;
use OCP\IDBConnection;
+use OCP\IL10N;
+use OCP\IURLGenerator;
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 Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
@@ -88,17 +97,46 @@ class AccountManager implements IAccountManager {
/** @var LoggerInterface */
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->config = $config;
$this->eventDispatcher = $eventDispatcher;
$this->jobList = $jobList;
$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;
}
/**
@@ -337,7 +375,6 @@ class AccountManager implements IAccountManager {
/**
* 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 {
try {
@@ -358,11 +395,73 @@ class AccountManager implements IAccountManager {
]
);
+ $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;
}
/**
@@ -406,7 +505,6 @@ class AccountManager implements IAccountManager {
}
}
-
/**
* add new user to accounts table
*
@@ -435,6 +533,12 @@ class AccountManager implements IAccountManager {
foreach ($data as $dataRow) {
$propertyName = $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)) {
$preparedData[$propertyName] = $dataRow;
continue;
@@ -511,7 +615,6 @@ class AccountManager implements IAccountManager {
continue;
}
-
$query->setParameter('name', $property['name'])
->setParameter('value', $property['value'] ?? '');
$query->executeStatement();
@@ -587,6 +690,7 @@ class AccountManager implements IAccountManager {
$data['verified'] ?? self::NOT_VERIFIED,
''
);
+ $p->setLocallyVerified($data['locallyVerified'] ?? self::NOT_VERIFIED);
$collection->addProperty($p);
return $collection;
@@ -599,6 +703,10 @@ class AccountManager implements IAccountManager {
$account->setPropertyCollection($this->arrayDataToCollection($account, $accountData));
} else {
$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;
@@ -640,14 +748,17 @@ class AccountManager implements IAccountManager {
$oldData = $this->getUser($account->getUser(), false);
$this->updateVerificationStatus($account, $oldData);
$this->checkEmailVerification($account, $oldData);
+ $this->checkLocalEmailVerification($account, $oldData);
$data = [];
foreach ($account->getAllProperties() as $property) {
+ /** @var IAccountProperty $property */
$data[] = [
'name' => $property->getName(),
'value' => $property->getValue(),
'scope' => $property->getScope(),
'verified' => $property->getVerified(),
+ 'locallyVerified' => $property->getLocallyVerified(),
];
}
diff --git a/lib/private/Accounts/AccountProperty.php b/lib/private/Accounts/AccountProperty.php
index 1a21baf9698..0e6356e9e92 100644
--- a/lib/private/Accounts/AccountProperty.php
+++ b/lib/private/Accounts/AccountProperty.php
@@ -27,6 +27,7 @@ declare(strict_types=1);
*/
namespace OC\Accounts;
+use InvalidArgumentException;
use OCP\Accounts\IAccountManager;
use OCP\Accounts\IAccountProperty;
@@ -42,6 +43,8 @@ class AccountProperty implements IAccountProperty {
private $verified;
/** @var string */
private $verificationData;
+ /** @var string */
+ private $locallyVerified = IAccountManager::NOT_VERIFIED;
public function __construct(string $name, string $value, string $scope, string $verified, string $verificationData) {
$this->name = $name;
@@ -90,7 +93,7 @@ class AccountProperty implements IAccountProperty {
IAccountManager::SCOPE_PRIVATE,
IAccountManager::SCOPE_PUBLISHED
])) {
- throw new \InvalidArgumentException('Invalid scope');
+ throw new InvalidArgumentException('Invalid scope');
}
$this->scope = $newScope;
return $this;
@@ -178,4 +181,20 @@ class AccountProperty implements IAccountProperty {
public function getVerificationData(): string {
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;
+ }
}
diff --git a/lib/private/Accounts/AccountPropertyCollection.php b/lib/private/Accounts/AccountPropertyCollection.php
index eb92536a6a0..3aed76d8746 100644
--- a/lib/private/Accounts/AccountPropertyCollection.php
+++ b/lib/private/Accounts/AccountPropertyCollection.php
@@ -84,6 +84,15 @@ class AccountPropertyCollection implements IAccountPropertyCollection {
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 {
foreach ($this->properties as $i => $property) {
if ($property->getValue() === $value) {
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 03d6a4146ed..883bf3f5c24 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -135,6 +135,7 @@ use OC\Security\CSRF\TokenStorage\SessionStorage;
use OC\Security\Hasher;
use OC\Security\SecureRandom;
use OC\Security\TrustedDomainHelper;
+use OC\Security\VerificationToken\VerificationToken;
use OC\Session\CryptoWrapper;
use OC\Share20\ProviderFactory;
use OC\Share20\ShareHelper;
@@ -224,6 +225,7 @@ use OCP\Security\ICredentialsManager;
use OCP\Security\ICrypto;
use OCP\Security\IHasher;
use OCP\Security\ISecureRandom;
+use OCP\Security\VerificationToken\IVerificationToken;
use OCP\Share\IShareHelper;
use OCP\SystemTag\ISystemTagManager;
use OCP\SystemTag\ISystemTagObjectMapper;
@@ -795,6 +797,8 @@ class Server extends ServerContainer implements IServerContainer {
/** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('SecureRandom', \OCP\Security\ISecureRandom::class);
+ $this->registerAlias(IVerificationToken::class, VerificationToken::class);
+
$this->registerAlias(ICrypto::class, Crypto::class);
/** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Crypto', ICrypto::class);
diff --git a/lib/public/Accounts/IAccountProperty.php b/lib/public/Accounts/IAccountProperty.php
index 20505f299dd..94712e50f7d 100644
--- a/lib/public/Accounts/IAccountProperty.php
+++ b/lib/public/Accounts/IAccountProperty.php
@@ -115,4 +115,24 @@ interface IAccountProperty extends \JsonSerializable {
* @since 22.0.0
*/
public function getVerificationData(): string;
+
+ /**
+ * Set the instance-based verification status of a property
+ *
+ * @since 22.2.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 22.2.0
+ *
+ * @return string
+ */
+ public function getLocallyVerified(): string;
}
diff --git a/lib/public/Accounts/IAccountPropertyCollection.php b/lib/public/Accounts/IAccountPropertyCollection.php
index 779fb1299b4..6ee3fed0acb 100644
--- a/lib/public/Accounts/IAccountPropertyCollection.php
+++ b/lib/public/Accounts/IAccountPropertyCollection.php
@@ -89,4 +89,13 @@ interface IAccountPropertyCollection extends JsonSerializable {
* @since 22.0.0
*/
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 22.2.0
+ */
+ public function getPropertyByValue(string $value): ?IAccountProperty;
}
diff --git a/tests/lib/Accounts/AccountManagerTest.php b/tests/lib/Accounts/AccountManagerTest.php
index 8ed0e29d7ce..bf79d233131 100644
--- a/tests/lib/Accounts/AccountManagerTest.php
+++ b/tests/lib/Accounts/AccountManagerTest.php
@@ -25,9 +25,15 @@ use OC\Accounts\Account;
use OC\Accounts\AccountManager;
use OCP\Accounts\IAccountManager;
use OCP\BackgroundJob\IJobList;
+use OCP\Defaults;
use OCP\IConfig;
use OCP\IDBConnection;
+use OCP\IURLGenerator;
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 Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -41,6 +47,18 @@ use Test\TestCase;
* @package Test\Accounts
*/
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 */
private $connection;
@@ -70,6 +88,12 @@ class AccountManagerTest extends TestCase {
$this->config = $this->createMock(IConfig::class);
$this->jobList = $this->createMock(IJobList::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->connection,
@@ -77,6 +101,12 @@ class AccountManagerTest extends TestCase {
$this->eventDispatcher,
$this->jobList,
$this->logger,
+ $this->verificationToken,
+ $this->mailer,
+ $this->defaults,
+ $this->l10nFactory,
+ $this->urlGenerator,
+ $this->crypto
);
}
@@ -310,6 +340,12 @@ class AccountManagerTest extends TestCase {
$this->eventDispatcher,
$this->jobList,
$this->logger,
+ $this->verificationToken,
+ $this->mailer,
+ $this->defaults,
+ $this->l10nFactory,
+ $this->urlGenerator,
+ $this->crypto
])
->setMethods($mockedMethods)
->getMock();