summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorJohn Molakvoæ <skjnldsv@users.noreply.github.com>2021-09-10 08:34:20 +0200
committerGitHub <noreply@github.com>2021-09-10 08:34:20 +0200
commit78d62063ff0617ca594bd1a45c5be3ff592b206c (patch)
treef862af71ee9c4becc4fdc8124ea59c2124b2186b /apps
parent347b59f2fd43c3299c1cddbb17ec5d49a12ede4a (diff)
parent763136ab48cc54fda27fa137392020fda900e114 (diff)
downloadnextcloud-server-78d62063ff0617ca594bd1a45c5be3ff592b206c.tar.gz
nextcloud-server-78d62063ff0617ca594bd1a45c5be3ff592b206c.zip
Merge pull request #28422 from nextcloud/enh/27465/notification-email
Diffstat (limited to 'apps')
-rw-r--r--apps/dav/lib/Connector/Sabre/Principal.php7
-rw-r--r--apps/dav/lib/DAV/GroupPrincipalBackend.php2
-rw-r--r--apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php34
-rw-r--r--apps/files_sharing/lib/Controller/ShareAPIController.php2
-rw-r--r--apps/files_sharing/tests/Controller/ShareAPIControllerTest.php8
-rw-r--r--apps/provisioning_api/appinfo/routes.php5
-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/AUserData.php20
-rw-r--r--apps/provisioning_api/lib/Controller/UsersController.php83
-rw-r--r--apps/provisioning_api/lib/Controller/VerificationController.php143
-rw-r--r--apps/provisioning_api/tests/Controller/UsersControllerTest.php13
-rw-r--r--apps/settings/lib/Controller/UsersController.php4
-rw-r--r--apps/settings/tests/Controller/UsersControllerTest.php9
-rw-r--r--apps/user_ldap/lib/User/User.php2
16 files changed, 262 insertions, 76 deletions
diff --git a/apps/dav/lib/Connector/Sabre/Principal.php b/apps/dav/lib/Connector/Sabre/Principal.php
index 4a422fa9628..8002f963798 100644
--- a/apps/dav/lib/Connector/Sabre/Principal.php
+++ b/apps/dav/lib/Connector/Sabre/Principal.php
@@ -300,16 +300,13 @@ class Principal implements BackendInterface {
if (!$allowEnumeration) {
if ($allowEnumerationFullMatch) {
$users = $this->userManager->getByEmail($value);
- $users = \array_filter($users, static function (IUser $user) use ($value) {
- return $user->getEMailAddress() === $value;
- });
} else {
$users = [];
}
} else {
$users = $this->userManager->getByEmail($value);
$users = \array_filter($users, function (IUser $user) use ($currentUser, $value, $limitEnumerationPhone, $limitEnumerationGroup, $allowEnumerationFullMatch, $currentUserGroups) {
- if ($allowEnumerationFullMatch && $user->getEMailAddress() === $value) {
+ if ($allowEnumerationFullMatch && $user->getSystemEMailAddress() === $value) {
return true;
}
@@ -516,7 +513,7 @@ class Principal implements BackendInterface {
'{http://nextcloud.com/ns}language' => $this->languageFactory->getUserLanguage($user),
];
- $email = $user->getEMailAddress();
+ $email = $user->getSystemEMailAddress();
if (!empty($email)) {
$principal['{http://sabredav.org/ns}email-address'] = $email;
}
diff --git a/apps/dav/lib/DAV/GroupPrincipalBackend.php b/apps/dav/lib/DAV/GroupPrincipalBackend.php
index 34ac26d7d97..6317fc59cc2 100644
--- a/apps/dav/lib/DAV/GroupPrincipalBackend.php
+++ b/apps/dav/lib/DAV/GroupPrincipalBackend.php
@@ -331,7 +331,7 @@ class GroupPrincipalBackend implements BackendInterface {
'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
];
- $email = $user->getEMailAddress();
+ $email = $user->getSystemEMailAddress();
if (!empty($email)) {
$principal['{http://sabredav.org/ns}email-address'] = $email;
}
diff --git a/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php b/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php
index ba65edf2dd1..d7c074c9e3b 100644
--- a/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php
+++ b/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php
@@ -120,7 +120,7 @@ class PrincipalTest extends TestCase {
->willReturn('Dr. Foo-Bar');
$fooUser
->expects($this->once())
- ->method('getEMailAddress')
+ ->method('getSystemEMailAddress')
->willReturn('');
$barUser = $this->createMock(User::class);
$barUser
@@ -129,7 +129,7 @@ class PrincipalTest extends TestCase {
->willReturn('bar');
$barUser
->expects($this->once())
- ->method('getEMailAddress')
+ ->method('getSystemEMailAddress')
->willReturn('bar@nextcloud.com');
$this->userManager
->expects($this->once())
@@ -205,7 +205,7 @@ class PrincipalTest extends TestCase {
$fooUser = $this->createMock(User::class);
$fooUser
->expects($this->once())
- ->method('getEMailAddress')
+ ->method('getSystemEMailAddress')
->willReturn('foo@nextcloud.com');
$fooUser
->expects($this->once())
@@ -605,15 +605,15 @@ class PrincipalTest extends TestCase {
$user2 = $this->createMock(IUser::class);
$user2->method('getUID')->willReturn('user2');
$user2->method('getDisplayName')->willReturn('User 2');
- $user2->method('getEMailAddress')->willReturn('user2@foo.bar');
+ $user2->method('getSystemEMailAddress')->willReturn('user2@foo.bar');
$user3 = $this->createMock(IUser::class);
$user3->method('getUID')->willReturn('user3');
$user2->method('getDisplayName')->willReturn('User 22');
- $user2->method('getEMailAddress')->willReturn('user2@foo.bar123');
+ $user2->method('getSystemEMailAddress')->willReturn('user2@foo.bar123');
$user4 = $this->createMock(IUser::class);
$user4->method('getUID')->willReturn('user4');
$user2->method('getDisplayName')->willReturn('User 222');
- $user2->method('getEMailAddress')->willReturn('user2@foo.bar456');
+ $user2->method('getSystemEMailAddress')->willReturn('user2@foo.bar456');
$this->userManager->expects($this->at(0))
->method('searchDisplayName')
@@ -665,20 +665,20 @@ class PrincipalTest extends TestCase {
$user2 = $this->createMock(IUser::class);
$user2->method('getUID')->willReturn('user2');
$user2->method('getDisplayName')->willReturn('User 2');
- $user2->method('getEMailAddress')->willReturn('user2@foo.bar');
+ $user2->method('getSystemEMailAddress')->willReturn('user2@foo.bar');
$user3 = $this->createMock(IUser::class);
$user3->method('getUID')->willReturn('user3');
$user2->method('getDisplayName')->willReturn('User 22');
- $user2->method('getEMailAddress')->willReturn('user2@foo.bar123');
+ $user2->method('getSystemEMailAddress')->willReturn('user2@foo.bar123');
$user4 = $this->createMock(IUser::class);
$user4->method('getUID')->willReturn('user4');
$user2->method('getDisplayName')->willReturn('User 222');
- $user2->method('getEMailAddress')->willReturn('user2@foo.bar456');
+ $user2->method('getSystemEMailAddress')->willReturn('user2@foo.bar456');
- $this->userManager->expects($this->at(0))
+ $this->userManager->expects($this->once())
->method('getByEmail')
->with('user2@foo.bar')
- ->willReturn([$user2, $user3, $user4]);
+ ->willReturn([$user2]);
$this->assertEquals(['principals/users/user2'], $this->connector->searchPrincipals('principals/users',
['{http://sabredav.org/ns}email-address' => 'user2@foo.bar']));
@@ -726,15 +726,15 @@ class PrincipalTest extends TestCase {
$user2 = $this->createMock(IUser::class);
$user2->method('getUID')->willReturn('user2');
$user2->method('getDisplayName')->willReturn('User 2');
- $user2->method('getEMailAddress')->willReturn('user2@foo.bar');
+ $user2->method('getSystemEMailAddress')->willReturn('user2@foo.bar');
$user3 = $this->createMock(IUser::class);
$user3->method('getUID')->willReturn('user3');
$user3->method('getDisplayName')->willReturn('User 22');
- $user3->method('getEMailAddress')->willReturn('user2@foo.bar123');
+ $user3->method('getSystemEMailAddress')->willReturn('user2@foo.bar123');
$user4 = $this->createMock(IUser::class);
$user4->method('getUID')->willReturn('user4');
$user4->method('getDisplayName')->willReturn('User 222');
- $user4->method('getEMailAddress')->willReturn('user2@foo.bar456');
+ $user4->method('getSystemEMailAddress')->willReturn('user2@foo.bar456');
$this->userSession->expects($this->at(0))
@@ -787,15 +787,15 @@ class PrincipalTest extends TestCase {
$user2 = $this->createMock(IUser::class);
$user2->method('getUID')->willReturn('user2');
$user2->method('getDisplayName')->willReturn('User 2');
- $user2->method('getEMailAddress')->willReturn('user2@foo.bar');
+ $user2->method('getSystemEMailAddress')->willReturn('user2@foo.bar');
$user3 = $this->createMock(IUser::class);
$user3->method('getUID')->willReturn('user3');
$user3->method('getDisplayName')->willReturn('User 22');
- $user3->method('getEMailAddress')->willReturn('user2@foo.bar123');
+ $user3->method('getSystemEMailAddress')->willReturn('user2@foo.bar123');
$user4 = $this->createMock(IUser::class);
$user4->method('getUID')->willReturn('user4');
$user4->method('getDisplayName')->willReturn('User 222');
- $user4->method('getEMailAddress')->willReturn('user2@foo.bar456');
+ $user4->method('getSystemEMailAddress')->willReturn('user2@foo.bar456');
$this->userSession->expects($this->at(0))
diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php
index 668bbb7cca8..c9853f1e12c 100644
--- a/apps/files_sharing/lib/Controller/ShareAPIController.php
+++ b/apps/files_sharing/lib/Controller/ShareAPIController.php
@@ -238,7 +238,7 @@ class ShareAPIController extends OCSController {
$result['share_with'] = $share->getSharedWith();
$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
$result['share_with_displayname_unique'] = $sharedWith !== null ? (
- $sharedWith->getEMailAddress() !== '' ? $sharedWith->getEMailAddress() : $sharedWith->getUID()
+ !empty($sharedWith->getSystemEMailAddress()) ? $sharedWith->getSystemEMailAddress() : $sharedWith->getUID()
) : $share->getSharedWith();
$result['status'] = [];
diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php
index 411496f7a27..86a7d479899 100644
--- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php
+++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php
@@ -47,6 +47,7 @@ use OCP\Files\Mount\IMountPoint;
use OCP\Files\NotFoundException;
use OCP\Files\Storage;
use OCP\IConfig;
+use OCP\IGroup;
use OCP\IGroupManager;
use OCP\IL10N;
use OCP\IPreview;
@@ -785,7 +786,7 @@ class ShareAPIControllerTest extends TestCase {
$user = $this->getMockBuilder(IUser::class)->getMock();
$user->method('getUID')->willReturn('userId');
$user->method('getDisplayName')->willReturn('userDisplay');
- $user->method('getEMailAddress')->willReturn('userId@example.com');
+ $user->method('getSystemEMailAddress')->willReturn('userId@example.com');
$group = $this->getMockBuilder('OCP\IGroup')->getMock();
$group->method('getGID')->willReturn('groupId');
@@ -3586,7 +3587,7 @@ class ShareAPIControllerTest extends TestCase {
$initiator->method('getDisplayName')->willReturn('initiatorDN');
$recipient = $this->getMockBuilder(IUser::class)->getMock();
$recipient->method('getDisplayName')->willReturn('recipientDN');
- $recipient->method('getEmailAddress')->willReturn('recipient');
+ $recipient->method('getSystemEMailAddress')->willReturn('recipient');
$result = [];
@@ -4387,7 +4388,7 @@ class ShareAPIControllerTest extends TestCase {
public function testFormatShare(array $expects, \OCP\Share\IShare $share, array $users, $exception) {
$this->userManager->method('get')->willReturnMap($users);
- $recipientGroup = $this->createMock('\OCP\IGroup');
+ $recipientGroup = $this->createMock(IGroup::class);
$recipientGroup->method('getDisplayName')->willReturn('recipientGroupDisplayName');
$this->groupManager->method('get')->willReturnMap([
['recipientGroup', $recipientGroup],
@@ -4397,7 +4398,6 @@ class ShareAPIControllerTest extends TestCase {
->with('files_sharing.sharecontroller.showShare', ['token' => 'myToken'])
->willReturn('myLink');
-
$this->rootFolder->method('getUserFolder')
->with($this->currentUser)
->willReturnSelf();
diff --git a/apps/provisioning_api/appinfo/routes.php b/apps/provisioning_api/appinfo/routes.php
index 2f981e0c924..54d550260b8 100644
--- a/apps/provisioning_api/appinfo/routes.php
+++ b/apps/provisioning_api/appinfo/routes.php
@@ -74,4 +74,9 @@ 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#showVerifyMail', 'url' => '/mailVerification/{key}/{token}/{userId}', 'verb' => 'GET'],
+ ['name' => 'Verification#verifyMail', 'url' => '/mailVerification/{key}/{token}/{userId}', 'verb' => 'POST'],
+ ]
];
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 b99ca67ef3a..561b3105cde 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' => 'fa56c13484afa1baf908b93ed5b6990c6a0e9ad6',
+ 'reference' => '2e49000abb5acb09de041369a2239db23fa63ec7',
'name' => '__root__',
'dev' => false,
),
@@ -16,7 +16,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
- 'reference' => 'fa56c13484afa1baf908b93ed5b6990c6a0e9ad6',
+ 'reference' => '2e49000abb5acb09de041369a2239db23fa63ec7',
'dev_requirement' => false,
),
),
diff --git a/apps/provisioning_api/lib/Controller/AUserData.php b/apps/provisioning_api/lib/Controller/AUserData.php
index e358d282061..5bb62f2b7dc 100644
--- a/apps/provisioning_api/lib/Controller/AUserData.php
+++ b/apps/provisioning_api/lib/Controller/AUserData.php
@@ -54,6 +54,13 @@ use OCP\User\Backend\ISetPasswordBackend;
abstract class AUserData extends OCSController {
public const SCOPE_SUFFIX = 'Scope';
+ public const USER_FIELD_DISPLAYNAME = 'display';
+ public const USER_FIELD_LANGUAGE = 'language';
+ public const USER_FIELD_LOCALE = 'locale';
+ public const USER_FIELD_PASSWORD = 'password';
+ public const USER_FIELD_QUOTA = 'quota';
+ public const USER_FIELD_NOTIFICATION_EMAIL = 'notify_email';
+
/** @var IUserManager */
protected $userManager;
/** @var IConfig */
@@ -139,14 +146,14 @@ abstract class AUserData extends OCSController {
$data['lastLogin'] = $targetUserObject->getLastLogin() * 1000;
$data['backend'] = $targetUserObject->getBackendClassName();
$data['subadmin'] = $this->getUserSubAdminGroupsData($targetUserObject->getUID());
- $data['quota'] = $this->fillStorageInfo($targetUserObject->getUID());
+ $data[self::USER_FIELD_QUOTA] = $this->fillStorageInfo($targetUserObject->getUID());
try {
if ($includeScopes) {
$data[IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_AVATAR)->getScope();
}
- $data[IAccountManager::PROPERTY_EMAIL] = $targetUserObject->getEMailAddress();
+ $data[IAccountManager::PROPERTY_EMAIL] = $targetUserObject->getSystemEMailAddress();
if ($includeScopes) {
$data[IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope();
}
@@ -187,8 +194,9 @@ abstract class AUserData extends OCSController {
}
$data['groups'] = $gids;
- $data['language'] = $this->l10nFactory->getUserLanguage($targetUserObject);
- $data['locale'] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'locale');
+ $data[self::USER_FIELD_LANGUAGE] = $this->l10nFactory->getUserLanguage($targetUserObject);
+ $data[self::USER_FIELD_LOCALE] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'locale');
+ $data[self::USER_FIELD_NOTIFICATION_EMAIL] = $targetUserObject->getPrimaryEMailAddress();
$backend = $targetUserObject->getBackend();
$data['backendCapabilities'] = [
@@ -238,7 +246,7 @@ abstract class AUserData extends OCSController {
'used' => $storage['used'],
'total' => $storage['total'],
'relative' => $storage['relative'],
- 'quota' => $storage['quota'],
+ self::USER_FIELD_QUOTA => $storage['quota'],
];
} catch (NotFoundException $ex) {
// User fs is not setup yet
@@ -251,7 +259,7 @@ abstract class AUserData extends OCSController {
$quota = OC_Helper::computerFileSize($quota);
}
$data = [
- 'quota' => $quota !== false ? $quota : 'none',
+ self::USER_FIELD_QUOTA => $quota !== false ? $quota : 'none',
'used' => 0
];
}
diff --git a/apps/provisioning_api/lib/Controller/UsersController.php b/apps/provisioning_api/lib/Controller/UsersController.php
index a0eda5848ec..dd8397a8a89 100644
--- a/apps/provisioning_api/lib/Controller/UsersController.php
+++ b/apps/provisioning_api/lib/Controller/UsersController.php
@@ -42,6 +42,7 @@ declare(strict_types=1);
*/
namespace OCA\Provisioning_API\Controller;
+use InvalidArgumentException;
use libphonenumber\NumberParseException;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberFormat;
@@ -418,15 +419,15 @@ class UsersController extends AUserData {
}
if ($displayName !== '') {
- $this->editUser($userid, 'display', $displayName);
+ $this->editUser($userid, self::USER_FIELD_DISPLAYNAME, $displayName);
}
if ($quota !== '') {
- $this->editUser($userid, 'quota', $quota);
+ $this->editUser($userid, self::USER_FIELD_QUOTA, $quota);
}
if ($language !== '') {
- $this->editUser($userid, 'language', $language);
+ $this->editUser($userid, self::USER_FIELD_LANGUAGE, $language);
}
// Send new user mail only if a mail is set
@@ -466,7 +467,7 @@ class UsersController extends AUserData {
]
);
throw $e;
- } catch (\InvalidArgumentException $e) {
+ } catch (InvalidArgumentException $e) {
$this->logger->error('Failed addUser attempt with invalid argument exeption.',
[
'app' => 'ocs_api',
@@ -621,6 +622,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 +633,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 +654,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;
@@ -670,7 +677,7 @@ class UsersController extends AUserData {
try {
$targetProperty->setScope($value);
$this->accountManager->updateAccount($userAccount);
- } catch (\InvalidArgumentException $e) {
+ } catch (InvalidArgumentException $e) {
throw new OCSException('', 102);
}
} else {
@@ -711,7 +718,7 @@ class UsersController extends AUserData {
if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
if ($targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)) {
- $permittedFields[] = 'display';
+ $permittedFields[] = self::USER_FIELD_DISPLAYNAME;
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
}
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
@@ -722,15 +729,16 @@ class UsersController extends AUserData {
$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
- $permittedFields[] = 'password';
+ $permittedFields[] = self::USER_FIELD_PASSWORD;
+ $permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
if ($this->config->getSystemValue('force_language', false) === false ||
$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
- $permittedFields[] = 'language';
+ $permittedFields[] = self::USER_FIELD_LANGUAGE;
}
if ($this->config->getSystemValue('force_locale', false) === false ||
$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
- $permittedFields[] = 'locale';
+ $permittedFields[] = self::USER_FIELD_LOCALE;
}
$permittedFields[] = IAccountManager::PROPERTY_PHONE;
@@ -746,7 +754,7 @@ class UsersController extends AUserData {
// If admin they can edit their own quota
if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
- $permittedFields[] = 'quota';
+ $permittedFields[] = self::USER_FIELD_QUOTA;
}
} else {
// Check if admin / subadmin
@@ -756,19 +764,20 @@ class UsersController extends AUserData {
// They have permissions over the user
if ($targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)) {
- $permittedFields[] = 'display';
+ $permittedFields[] = self::USER_FIELD_DISPLAYNAME;
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
}
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
- $permittedFields[] = 'password';
- $permittedFields[] = 'language';
- $permittedFields[] = 'locale';
+ $permittedFields[] = self::USER_FIELD_PASSWORD;
+ $permittedFields[] = self::USER_FIELD_LANGUAGE;
+ $permittedFields[] = self::USER_FIELD_LOCALE;
$permittedFields[] = IAccountManager::PROPERTY_PHONE;
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
- $permittedFields[] = 'quota';
+ $permittedFields[] = self::USER_FIELD_QUOTA;
+ $permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
} else {
// No rights
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
@@ -780,11 +789,11 @@ class UsersController extends AUserData {
}
// Process the edit
switch ($key) {
- case 'display':
+ case self::USER_FIELD_DISPLAYNAME:
case IAccountManager::PROPERTY_DISPLAYNAME:
$targetUser->setDisplayName($value);
break;
- case 'quota':
+ case self::USER_FIELD_QUOTA:
$quota = $value;
if ($quota !== 'none' && $quota !== 'default') {
if (is_numeric($quota)) {
@@ -814,7 +823,7 @@ class UsersController extends AUserData {
}
$targetUser->setQuota($quota);
break;
- case 'password':
+ case self::USER_FIELD_PASSWORD:
try {
if (!$targetUser->canChangePassword()) {
throw new OCSException('Setting the password is not supported by the users backend', 103);
@@ -824,19 +833,39 @@ class UsersController extends AUserData {
throw new OCSException($e->getMessage(), 103);
}
break;
- case 'language':
+ case self::USER_FIELD_LANGUAGE:
$languagesCodes = $this->l10nFactory->findAvailableLanguages();
if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
throw new OCSException('Invalid language', 102);
}
$this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
break;
- case 'locale':
+ case self::USER_FIELD_LOCALE:
if (!$this->l10nFactory->localeExists($value)) {
throw new OCSException('Invalid locale', 102);
}
$this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
break;
+ case self::USER_FIELD_NOTIFICATION_EMAIL:
+ $success = false;
+ if ($value === '' || filter_var($value, FILTER_VALIDATE_EMAIL)) {
+ try {
+ $targetUser->setPrimaryEMailAddress($value);
+ $success = true;
+ } catch (InvalidArgumentException $e) {
+ $this->logger->info(
+ 'Cannot set primary email, because provided address is not verified',
+ [
+ 'app' => 'provisioning_api',
+ 'exception' => $e,
+ ]
+ );
+ }
+ }
+ if (!$success) {
+ throw new OCSException('', 102);
+ }
+ break;
case IAccountManager::PROPERTY_EMAIL:
if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
$targetUser->setEMailAddress($value);
@@ -845,7 +874,7 @@ class UsersController extends AUserData {
}
break;
case IAccountManager::COLLECTION_EMAIL:
- if (filter_var($value, FILTER_VALIDATE_EMAIL) && $value !== $targetUser->getEMailAddress()) {
+ if (filter_var($value, FILTER_VALIDATE_EMAIL) && $value !== $targetUser->getSystemEMailAddress()) {
$userAccount = $this->accountManager->getAccount($targetUser);
$mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
foreach ($mailCollection->getProperties() as $property) {
@@ -872,7 +901,7 @@ class UsersController extends AUserData {
if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) {
$this->knownUserService->deleteByContactUserId($targetUser->getUID());
}
- } catch (\InvalidArgumentException $e) {
+ } catch (InvalidArgumentException $e) {
throw new OCSException('Invalid ' . $e->getMessage(), 102);
}
}
@@ -895,7 +924,7 @@ class UsersController extends AUserData {
try {
$userProperty->setScope($value);
$this->accountManager->updateAccount($userAccount);
- } catch (\InvalidArgumentException $e) {
+ } catch (InvalidArgumentException $e) {
throw new OCSException('Invalid ' . $e->getMessage(), 102);
}
}
diff --git a/apps/provisioning_api/lib/Controller/VerificationController.php b/apps/provisioning_api/lib/Controller/VerificationController.php
new file mode 100644
index 00000000000..c4ddd1e644d
--- /dev/null
+++ b/apps/provisioning_api/lib/Controller/VerificationController.php
@@ -0,0 +1,143 @@
+<?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
+ * @NoAdminRequired
+ * @NoSubAdminRequired
+ */
+ public function showVerifyMail(string $token, string $userId, string $key) {
+ if ($this->userSession->getUser()->getUID() !== $userId) {
+ // not a public page, hence getUser() must return an IUser
+ throw new InvalidArgumentException('Logged in user is not mail address owner');
+ }
+ $email = $this->crypto->decrypt($key);
+
+ return new TemplateResponse(
+ 'core', 'confirmation', [
+ 'title' => $this->l10n->t('Email confirmation'),
+ 'message' => $this->l10n->t('To enable the email address %s please click the button below.', [$email]),
+ 'action' => $this->l10n->t('Confirm'),
+ ], TemplateResponse::RENDER_AS_GUEST);
+ }
+
+ /**
+ * @NoAdminRequired
+ * @NoSubAdminRequired
+ */
+ 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);
+ $this->verificationToken->delete($token, $user, 'verifyMail' . $ref);
+ } 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]]
+ ], TemplateResponse::RENDER_AS_GUEST);
+ }
+
+ return new TemplateResponse(
+ 'core', 'success', [
+ 'title' => $this->l10n->t('Email confirmation successful'),
+ 'message' => $this->l10n->t('Email confirmation successful'),
+ ], TemplateResponse::RENDER_AS_GUEST);
+ }
+}
diff --git a/apps/provisioning_api/tests/Controller/UsersControllerTest.php b/apps/provisioning_api/tests/Controller/UsersControllerTest.php
index cc638c89a63..7ae5d0c245f 100644
--- a/apps/provisioning_api/tests/Controller/UsersControllerTest.php
+++ b/apps/provisioning_api/tests/Controller/UsersControllerTest.php
@@ -952,7 +952,7 @@ class UsersControllerTest extends TestCase {
->disableOriginalConstructor()
->getMock();
$targetUser->expects($this->once())
- ->method('getEMailAddress')
+ ->method('getSystemEMailAddress')
->willReturn('demo@nextcloud.com');
$this->userSession
->expects($this->once())
@@ -1067,6 +1067,7 @@ class UsersControllerTest extends TestCase {
'setPassword' => true,
],
'additional_mail' => [],
+ 'notify_email' => null,
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
@@ -1083,9 +1084,9 @@ class UsersControllerTest extends TestCase {
->disableOriginalConstructor()
->getMock();
$targetUser
- ->expects($this->once())
- ->method('getEMailAddress')
- ->willReturn('demo@nextcloud.com');
+ ->expects($this->once())
+ ->method('getSystemEMailAddress')
+ ->willReturn('demo@nextcloud.com');
$this->userSession
->expects($this->once())
->method('getUser')
@@ -1195,6 +1196,7 @@ class UsersControllerTest extends TestCase {
'setPassword' => true,
],
'additional_mail' => [],
+ 'notify_email' => null,
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
@@ -1306,7 +1308,7 @@ class UsersControllerTest extends TestCase {
->willReturn('Subadmin User');
$targetUser
->expects($this->once())
- ->method('getEMailAddress')
+ ->method('getSystemEMailAddress')
->willReturn('subadmin@nextcloud.com');
$targetUser
->method('getUID')
@@ -1361,6 +1363,7 @@ class UsersControllerTest extends TestCase {
'setPassword' => false,
],
'additional_mail' => [],
+ 'notify_email' => null,
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
diff --git a/apps/settings/lib/Controller/UsersController.php b/apps/settings/lib/Controller/UsersController.php
index f78fa7dd9b8..6be93d6a3a0 100644
--- a/apps/settings/lib/Controller/UsersController.php
+++ b/apps/settings/lib/Controller/UsersController.php
@@ -482,7 +482,7 @@ class UsersController extends Controller {
}
}
- $oldEmailAddress = $userAccount->getUser()->getEMailAddress();
+ $oldEmailAddress = $userAccount->getUser()->getSystemEMailAddress();
$oldEmailAddress = strtolower((string)$oldEmailAddress);
if ($oldEmailAddress !== $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue()) {
// this is the only permission a backend provides and is also used
@@ -490,7 +490,7 @@ class UsersController extends Controller {
if (!$userAccount->getUser()->canChangeDisplayName()) {
throw new ForbiddenException($this->l10n->t('Unable to change email address'));
}
- $userAccount->getUser()->setEMailAddress($userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue());
+ $userAccount->getUser()->setSystemEMailAddress($userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue());
}
try {
diff --git a/apps/settings/tests/Controller/UsersControllerTest.php b/apps/settings/tests/Controller/UsersControllerTest.php
index 7faca378cdf..797fa1621fa 100644
--- a/apps/settings/tests/Controller/UsersControllerTest.php
+++ b/apps/settings/tests/Controller/UsersControllerTest.php
@@ -621,16 +621,15 @@ class UsersControllerTest extends \Test\TestCase {
$user = $this->createMock(IUser::class);
$user->method('getDisplayName')->willReturn($oldDisplayName);
- $user->method('getEMailAddress')->willReturn($oldEmailAddress);
+ $user->method('getSystemEMailAddress')->willReturn($oldEmailAddress);
$user->method('canChangeDisplayName')->willReturn(true);
if ($data[IAccountManager::PROPERTY_EMAIL]['value'] === $oldEmailAddress ||
($oldEmailAddress === null && $data[IAccountManager::PROPERTY_EMAIL]['value'] === '')) {
- $user->expects($this->never())->method('setEMailAddress');
+ $user->expects($this->never())->method('setSystemEMailAddress');
} else {
- $user->expects($this->once())->method('setEMailAddress')
- ->with($data[IAccountManager::PROPERTY_EMAIL]['value'])
- ->willReturn(true);
+ $user->expects($this->once())->method('setSystemEMailAddress')
+ ->with($data[IAccountManager::PROPERTY_EMAIL]['value']);
}
if ($data[IAccountManager::PROPERTY_DISPLAYNAME]['value'] === $oldDisplayName ||
diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php
index 7d57fcbb275..b09fbd18327 100644
--- a/apps/user_ldap/lib/User/User.php
+++ b/apps/user_ldap/lib/User/User.php
@@ -448,7 +448,7 @@ class User {
if ($email !== '') {
$user = $this->userManager->get($this->uid);
if (!is_null($user)) {
- $currentEmail = (string)$user->getEMailAddress();
+ $currentEmail = (string)$user->getSystemEMailAddress();
if ($currentEmail !== $email) {
$user->setEMailAddress($email);
}