Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build/integration/features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,7 @@ protected function resetAppConfigs(): void {
$this->deleteServerConfig('bruteForce', 'whitelist_0');
$this->deleteServerConfig('bruteForce', 'whitelist_1');
$this->deleteServerConfig('bruteforcesettings', 'apply_allowlist_to_ratelimit');
$this->deleteServerConfig('core', 'shareapi_exclude_groups');
$this->deleteServerConfig('core', 'shareapi_exclude_groups_list');
}
}
2 changes: 2 additions & 0 deletions build/integration/features/bootstrap/ShareesContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@ protected function resetAppConfigs() {
$this->deleteServerConfig('core', 'shareapi_only_share_with_group_members');
$this->deleteServerConfig('core', 'shareapi_allow_share_dialog_user_enumeration');
$this->deleteServerConfig('core', 'shareapi_allow_group_sharing');
$this->deleteServerConfig('core', 'shareapi_exclude_groups');
$this->deleteServerConfig('core', 'shareapi_exclude_groups_list');
}
}
134 changes: 134 additions & 0 deletions build/integration/features/contacts-menu.feature
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,140 @@ Feature: contacts-menu
And searched contact "1" is named "Test name"
And searched contact "2" is named "user2"



Scenario: users can not be searched by display name when searcher belongs to a group excluded from sharing
Given user "user0" exists
And group "ExcludedGroup" exists
And user "user0" belongs to group "ExcludedGroup"
And parameter "shareapi_exclude_groups" of app "core" is set to "yes"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "ExcludedGroup"
And user "user1" exists
And As an "admin"
And sending "PUT" to "/cloud/users/user1" with
| key | displayname |
| value | Test name |
When Logging in using web as "user0"
And searching for contacts matching with "test"
Then the list of searched contacts has "0" contacts

Scenario: users can not be searched by email when searcher belongs to a group excluded from sharing
Given user "user0" exists
And group "ExcludedGroup" exists
And user "user0" belongs to group "ExcludedGroup"
And parameter "shareapi_exclude_groups" of app "core" is set to "yes"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "ExcludedGroup"
And user "user1" exists
And As an "admin"
And sending "PUT" to "/cloud/users/user1" with
| key | email |
| value | [email protected] |
When Logging in using web as "user0"
And searching for contacts matching with "test"
Then the list of searched contacts has "0" contacts

Scenario: users can be searched by display name when searcher belongs to both a group excluded from sharing and another group
Given user "user0" exists
And group "ExcludedGroup" exists
And user "user0" belongs to group "ExcludedGroup"
And group "AnotherGroup" exists
And user "user0" belongs to group "AnotherGroup"
And parameter "shareapi_exclude_groups" of app "core" is set to "yes"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "ExcludedGroup"
And user "user1" exists
And As an "admin"
And sending "PUT" to "/cloud/users/user1" with
| key | displayname |
| value | Test name |
When Logging in using web as "user0"
And searching for contacts matching with "test"
Then the list of searched contacts has "1" contacts
And searched contact "0" is named "Test name"

Scenario: users can be searched by email when searcher belongs to both a group excluded from sharing and another group
Given user "user0" exists
And group "ExcludedGroup" exists
And user "user0" belongs to group "ExcludedGroup"
And group "AnotherGroup" exists
And user "user0" belongs to group "AnotherGroup"
And parameter "shareapi_exclude_groups" of app "core" is set to "yes"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "ExcludedGroup"
And user "user1" exists
And As an "admin"
And sending "PUT" to "/cloud/users/user1" with
| key | email |
| value | [email protected] |
When Logging in using web as "user0"
And searching for contacts matching with "test"
Then the list of searched contacts has "1" contacts
And searched contact "0" is named "user1"

Scenario: users can not be searched by display name when searcher does not belong to a group allowed to share
Given user "user0" exists
And group "AllowedGroup" exists
And parameter "shareapi_exclude_groups" of app "core" is set to "allow"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "AllowedGroup"
And user "user1" exists
And As an "admin"
And sending "PUT" to "/cloud/users/user1" with
| key | displayname |
| value | Test name |
When Logging in using web as "user0"
And searching for contacts matching with "test"
Then the list of searched contacts has "0" contacts

Scenario: users can not be searched by email when searcher does not belong to a group allowed to share
Given user "user0" exists
And group "AllowedGroup" exists
And parameter "shareapi_exclude_groups" of app "core" is set to "allow"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "AllowedGroup"
And user "user1" exists
And As an "admin"
And sending "PUT" to "/cloud/users/user1" with
| key | email |
| value | [email protected] |
When Logging in using web as "user0"
And searching for contacts matching with "test"
Then the list of searched contacts has "0" contacts

Scenario: users can be searched by display name when searcher belongs to both a group allowed to share and another group
Given user "user0" exists
And group "AllowedGroup" exists
And user "user0" belongs to group "AllowedGroup"
And group "AnotherGroup" exists
And user "user0" belongs to group "AnotherGroup"
And parameter "shareapi_exclude_groups" of app "core" is set to "allow"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "AllowedGroup"
And user "user1" exists
And As an "admin"
And sending "PUT" to "/cloud/users/user1" with
| key | displayname |
| value | Test name |
When Logging in using web as "user0"
And searching for contacts matching with "test"
Then the list of searched contacts has "1" contacts
And searched contact "0" is named "Test name"

Scenario: users can be searched by email when searcher belongs to both a group allowed to share and another group
Given user "user0" exists
And group "AllowedGroup" exists
And user "user0" belongs to group "AllowedGroup"
And group "AnotherGroup" exists
And user "user0" belongs to group "AnotherGroup"
And parameter "shareapi_exclude_groups" of app "core" is set to "allow"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "AllowedGroup"
And user "user1" exists
And As an "admin"
And sending "PUT" to "/cloud/users/user1" with
| key | email |
| value | [email protected] |
When Logging in using web as "user0"
And searching for contacts matching with "test"
Then the list of searched contacts has "1" contacts
And searched contact "0" is named "user1"



Scenario: users can not be found by display name if visibility is private
Given user "user0" exists
And user "user1" exists
Expand Down
75 changes: 75 additions & 0 deletions build/integration/sharees_features/sharees.feature
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,81 @@ Feature: sharees
And "exact remotes" sharees returned is empty
And "remotes" sharees returned is empty

Scenario: Search when belonging to a group excluded from sharing
Given As an "test"
And parameter "shareapi_exclude_groups" of app "core" is set to "yes"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "ShareeGroup"
When getting sharees for
| search | sharee |
| itemType | file |
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And "exact users" sharees returned is empty
And "users" sharees returned is empty
And "exact groups" sharees returned is empty
And "groups" sharees returned is empty
And "exact remotes" sharees returned is empty
And "remotes" sharees returned is empty

Scenario: Search when belonging to both a group excluded from sharing and another group
Given As an "test"
And group "AnotherGroup" exists
And user "test" belongs to group "AnotherGroup"
And parameter "shareapi_exclude_groups" of app "core" is set to "yes"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "ShareeGroup"
When getting sharees for
| search | sharee |
| itemType | file |
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And "exact users" sharees returned is empty
And "users" sharees returned are
| Sharee1 | 0 | Sharee1 | Sharee1 |
| Sharee2 | 0 | Sharee2 | [email protected] |
And "exact groups" sharees returned is empty
And "groups" sharees returned are
| ShareeGroup | 1 | ShareeGroup |
And "exact remotes" sharees returned is empty
And "remotes" sharees returned is empty

Scenario: Search when not belonging to a group allowed to share
Given As an "test"
And group "AnotherGroup" exists
And parameter "shareapi_exclude_groups" of app "core" is set to "allow"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "AnotherGroup"
When getting sharees for
| search | sharee |
| itemType | file |
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And "exact users" sharees returned is empty
And "users" sharees returned is empty
And "exact groups" sharees returned is empty
And "groups" sharees returned is empty
And "exact remotes" sharees returned is empty
And "remotes" sharees returned is empty

Scenario: Search when belonging to both a group allowed to share and another group
Given As an "test"
And group "AnotherGroup" exists
And user "test" belongs to group "AnotherGroup"
And parameter "shareapi_exclude_groups" of app "core" is set to "allow"
And parameter "shareapi_exclude_groups_list" of app "core" is set to "AnotherGroup"
When getting sharees for
| search | sharee |
| itemType | file |
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And "exact users" sharees returned is empty
And "users" sharees returned are
| Sharee1 | 0 | Sharee1 | Sharee1 |
| Sharee2 | 0 | Sharee2 | [email protected] |
And "exact groups" sharees returned is empty
And "groups" sharees returned are
| ShareeGroup | 1 | ShareeGroup |
And "exact remotes" sharees returned is empty
And "remotes" sharees returned is empty

Scenario: Search without exact match no iteration allowed
Given As an "test"
And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no"
Expand Down
6 changes: 3 additions & 3 deletions lib/private/Contacts/ContactsMenu/ContactsStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public function getContacts(IUser $user, ?string $filter, ?int $limit = null, ?i
* 1. if the `shareapi_allow_share_dialog_user_enumeration` config option is
* enabled it will filter all local users
* 2. if the `shareapi_exclude_groups` config option is enabled and the
* current user is in an excluded group it will filter all local users.
* current user is only in excluded groups it will filter all local users.
* 3. if the `shareapi_only_share_with_group_members` config option is
* enabled it will filter all users which doesn't have a common group
* with the current user.
Expand Down Expand Up @@ -184,8 +184,8 @@ private function filterContacts(
$excludeGroupsList = $decodedExcludeGroups ?? [];

if ($excludeGroups != 'allow') {
if (count(array_intersect($excludeGroupsList, $selfGroups)) !== 0) {
// a group of the current user is excluded -> filter all local users
if (count($selfGroups) > 0 && count(array_diff($selfGroups, $excludeGroupsList)) === 0) {
// all the groups of the current user are excluded -> filter all local users
$skipLocal = true;
}
} else {
Expand Down
89 changes: 88 additions & 1 deletion tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,94 @@ public function testGetContactsWithoutAvatarURI(): void {
$this->assertEquals('https://photo', $entries[1]->getAvatar());
}

public function testGetContactsWhenUserIsInExcludeGroups(): void {
public static function dataGetContactsWhenUserIsInExcludeGroups(): array {
return [
['yes', '[]', [], ['user123', 'user12345']],
['yes', '["excludedGroup1"]', [], ['user123', 'user12345']],
['yes', '["excludedGroup1"]', ['anotherGroup1'], ['user123', 'user12345']],
['yes', '["excludedGroup1"]', ['anotherGroup1', 'anotherGroup2', 'anotherGroup3'], ['user123', 'user12345']],
['yes', '["excludedGroup1"]', ['excludedGroup1'], []],
['yes', '["excludedGroup1"]', ['anotherGroup1', 'excludedGroup1'], ['user123', 'user12345']],
['yes', '["excludedGroup1"]', ['excludedGroup1', 'anotherGroup1', 'anotherGroup2', 'anotherGroup3'], ['user123', 'user12345']],
['yes', '["excludedGroup1", "excludedGroup2", "excludedGroup3"]', [], ['user123', 'user12345']],
['yes', '["excludedGroup1", "excludedGroup2", "excludedGroup3"]', ['anotherGroup1'], ['user123', 'user12345']],
['yes', '["excludedGroup1", "excludedGroup2", "excludedGroup3"]', ['anotherGroup1', 'anotherGroup2', 'anotherGroup3'], ['user123', 'user12345']],
['yes', '["excludedGroup1", "excludedGroup2", "excludedGroup3"]', ['excludedGroup1'], []],
['yes', '["excludedGroup1", "excludedGroup2", "excludedGroup3"]', ['excludedGroup2'], []],
['yes', '["excludedGroup1", "excludedGroup2", "excludedGroup3"]', ['excludedGroup3'], []],
['yes', '["excludedGroup1", "excludedGroup2", "excludedGroup3"]', ['excludedGroup1', 'excludedGroup2', 'excludedGroup3'], []],
['yes', '["excludedGroup1", "excludedGroup2", "excludedGroup3"]', ['anotherGroup1', 'excludedGroup1'], ['user123', 'user12345']],
['yes', '["excludedGroup1", "excludedGroup2", "excludedGroup3"]', ['anotherGroup1', 'excludedGroup2', 'anotherGroup2', 'anotherGroup3'], ['user123', 'user12345']],
['yes', '["excludedGroup1", "excludedGroup2", "excludedGroup3"]', ['excludedGroup3', 'anotherGroup1', 'anotherGroup2', 'anotherGroup3'], ['user123', 'user12345']],
['allow', '[]', [], []],
['allow', '["allowedGroup1"]', [], []],
['allow', '["allowedGroup1"]', ['anotherGroup1'], []],
['allow', '["allowedGroup1"]', ['anotherGroup1', 'anotherGroup2', 'anotherGroup3'], []],
['allow', '["allowedGroup1"]', ['allowedGroup1'], ['user123', 'user12345']],
['allow', '["allowedGroup1"]', ['anotherGroup1', 'allowedGroup1'], ['user123', 'user12345']],
['allow', '["allowedGroup1"]', ['allowedGroup1', 'anotherGroup1', 'anotherGroup2', 'anotherGroup3'], ['user123', 'user12345']],
['allow', '["allowedGroup1", "allowedGroup2", "allowedGroup3"]', [], []],
['allow', '["allowedGroup1", "allowedGroup2", "allowedGroup3"]', ['anotherGroup1'], []],
['allow', '["allowedGroup1", "allowedGroup2", "allowedGroup3"]', ['anotherGroup1', 'anotherGroup2', 'anotherGroup3'], []],
['allow', '["allowedGroup1", "allowedGroup2", "allowedGroup3"]', ['allowedGroup1'], ['user123', 'user12345']],
['allow', '["allowedGroup1", "allowedGroup2", "allowedGroup3"]', ['allowedGroup2'], ['user123', 'user12345']],
['allow', '["allowedGroup1", "allowedGroup2", "allowedGroup3"]', ['allowedGroup3'], ['user123', 'user12345']],
['allow', '["allowedGroup1", "allowedGroup2", "allowedGroup3"]', ['allowedGroup1', 'allowedGroup2', 'allowedGroup3'], ['user123', 'user12345']],
['allow', '["allowedGroup1", "allowedGroup2", "allowedGroup3"]', ['anotherGroup1', 'allowedGroup1'], ['user123', 'user12345']],
['allow', '["allowedGroup1", "allowedGroup2", "allowedGroup3"]', ['anotherGroup1', 'allowedGroup2', 'anotherGroup2', 'anotherGroup3'], ['user123', 'user12345']],
['allow', '["allowedGroup1", "allowedGroup2", "allowedGroup3"]', ['allowedGroup3', 'anotherGroup1', 'anotherGroup2', 'anotherGroup3'], ['user123', 'user12345']],
];
}

#[\PHPUnit\Framework\Attributes\DataProvider('dataGetContactsWhenUserIsInExcludeGroups')]
public function testGetContactsWhenUserIsInExcludeGroups(string $excludeGroups, string $excludeGroupsList, array $currentUserGroupIds, array $expectedUids): void {
$this->config
->method('getAppValue')
->willReturnMap([
['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'yes'],
['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'no'],
['core', 'shareapi_restrict_user_enumeration_to_phone', 'no', 'no'],
['core', 'shareapi_exclude_groups', 'no', $excludeGroups],
['core', 'shareapi_only_share_with_group_members', 'no', 'no'],
['core', 'shareapi_exclude_groups_list', '', $excludeGroupsList],
['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
]);

/** @var IUser|MockObject $currentUser */
$currentUser = $this->createMock(IUser::class);
$currentUser->expects($this->exactly(2))
->method('getUID')
->willReturn('user001');

$this->groupManager->expects($this->once())
->method('getUserGroupIds')
->with($this->equalTo($currentUser))
->willReturn($currentUserGroupIds);

$this->contactsManager->expects($this->once())
->method('search')
->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
->willReturn([
[
'UID' => 'user123',
'isLocalSystemBook' => true
],
[
'UID' => 'user12345',
'isLocalSystemBook' => true
],
]);


$entries = $this->contactsStore->getContacts($currentUser, '');

$this->assertCount(count($expectedUids), $entries);
for ($i = 0; $i < count($expectedUids); $i++) {
$this->assertEquals($expectedUids[$i], $entries[$i]->getProperty('UID'));
}
}

public function testGetContactsOnlyShareIfInTheSameGroupWhenUserIsInExcludeGroups(): void {
$this->config
->method('getAppValue')
->willReturnMap([
Expand Down
Loading