Skip to content

Commit

Permalink
New core setting : shareapi_only_share_with_group_members_exclude_gro…
Browse files Browse the repository at this point in the history
…up_list (issue 37677)

Signed-off-by: Sebastien Marinier <[email protected]>
  • Loading branch information
smarinier committed May 10, 2023
1 parent 74f31ba commit 4a8a75b
Show file tree
Hide file tree
Showing 13 changed files with 106 additions and 2 deletions.
1 change: 1 addition & 0 deletions apps/settings/l10n/en_GB.js
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ OC.L10N.register(
"Allow resharing" : "Allow resharing",
"Allow sharing with groups" : "Allow sharing with groups",
"Restrict users to only share with users in their groups" : "Restrict users to only share with users in their groups",
"Exclude some groups from sharing with users in their group" : "Exclude some groups from sharing with users in their group",
"Exclude groups from sharing" : "Exclude groups from sharing",
"These groups will still be able to receive shares, but not to initiate them." : "These groups will still be able to receive shares, but not to initiate them.",
"Allow username autocompletion in share dialog" : "Allow username autocompletion in share dialogue",
Expand Down
1 change: 1 addition & 0 deletions apps/settings/l10n/en_GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@
"Allow resharing" : "Allow resharing",
"Allow sharing with groups" : "Allow sharing with groups",
"Restrict users to only share with users in their groups" : "Restrict users to only share with users in their groups",
"Exclude some groups from sharing with users in their group" : "Exclude some groups from sharing with users in their group",
"Exclude groups from sharing" : "Exclude groups from sharing",
"These groups will still be able to receive shares, but not to initiate them." : "These groups will still be able to receive shares, but not to initiate them.",
"Allow username autocompletion in share dialog" : "Allow username autocompletion in share dialogue",
Expand Down
1 change: 1 addition & 0 deletions apps/settings/l10n/fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ OC.L10N.register(
"Allow resharing" : "Autoriser le repartage",
"Allow sharing with groups" : "Autoriser le partage avec les groupes",
"Restrict users to only share with users in their groups" : "N'autoriser les partages qu'entre membres de mêmes groupes",
"Exclude some groups from sharing with users in their group" : "Empêcher certains groupes de partager avec les utilisateurs de leur groupe",
"Exclude groups from sharing" : "Empêcher certains groupes de partager",
"These groups will still be able to receive shares, but not to initiate them." : "Ces groupes ne pourront plus initier de partage, mais ils pourront toujours rejoindre les partages faits par d'autres. ",
"Allow username autocompletion in share dialog" : "Autoriser l'autocomplétion du nom d'utilisateur dans la boite de dialogue de partage",
Expand Down
1 change: 1 addition & 0 deletions apps/settings/l10n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@
"Allow resharing" : "Autoriser le repartage",
"Allow sharing with groups" : "Autoriser le partage avec les groupes",
"Restrict users to only share with users in their groups" : "N'autoriser les partages qu'entre membres de mêmes groupes",
"Exclude some groups from sharing with users in their group" : "Empêcher certains groupes de partager avec les utilisateurs de leur groupe",
"Exclude groups from sharing" : "Empêcher certains groupes de partager",
"These groups will still be able to receive shares, but not to initiate them." : "Ces groupes ne pourront plus initier de partage, mais ils pourront toujours rejoindre les partages faits par d'autres. ",
"Allow username autocompletion in share dialog" : "Autoriser l'autocomplétion du nom d'utilisateur dans la boite de dialogue de partage",
Expand Down
4 changes: 4 additions & 0 deletions apps/settings/lib/Settings/Admin/Sharing.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ public function getForm() {
$excludedPasswordGroupsList = !is_null(json_decode($excludedPasswordGroups))
? implode('|', json_decode($excludedPasswordGroups, true)) : '';

$shareWithGroupMembersExcludeGroups = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', '');
$shareWithGroupMembersExcludeGroupsList = !is_null(json_decode($shareWithGroupMembersExcludeGroups))
? implode('|', json_decode($shareWithGroupMembersExcludeGroups, true)) : '';

$parameters = [
// Built-In Sharing
Expand All @@ -96,6 +99,7 @@ public function getForm() {
'passwordExcludedGroups' => $excludedPasswordGroupsList,
'passwordExcludedGroupsFeatureEnabled' => $this->config->getSystemValueBool('sharing.allow_disabled_password_enforcement_groups', false),
'onlyShareWithGroupMembers' => $this->shareManager->shareWithGroupMembersOnly(),
'shareWithGroupMembersExcludeGroupsList'=> $shareWithGroupMembersExcludeGroupsList,
'shareAPIEnabled' => $this->config->getAppValue('core', 'shareapi_enabled', 'yes'),
'shareDefaultExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no'),
'shareExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7'),
Expand Down
6 changes: 5 additions & 1 deletion apps/settings/src/admin.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
window.addEventListener('DOMContentLoaded', () => {
$('#excludedGroups,#linksExcludedGroups,#passwordsExcludedGroups').each(function(index, element) {
$('#excludedGroups,#shareGroupMembersExcludeGroups,#linksExcludedGroups,#passwordsExcludedGroups').each(function(index, element) {
OC.Settings.setupGroupsSelect($(element))
$(element).change(function(ev) {
let groups = ev.val || []
Expand Down Expand Up @@ -214,6 +214,10 @@ window.addEventListener('DOMContentLoaded', () => {
$('#selectExcludedGroups').toggleClass('hidden', !this.checked)
})

$('#onlyShareWithGroupMembers').change(function() {
$('#selectShareWithGroupMembersExcludeGroups').toggleClass('hidden', !this.checked)
})

const setupChecks = () => {
// run setup checks then gather error messages
$.when(
Expand Down
7 changes: 7 additions & 0 deletions apps/settings/templates/settings/admin/sharing.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@
} ?> />
<label for="onlyShareWithGroupMembers"><?php p($l->t('Restrict users to only share with users in their groups'));?></label><br/>
</p>
<p id="selectShareWithGroupMembersExcludeGroups" class="indent <?php if (!$_['onlyShareWithGroupMembers'] || $_['shareAPIEnabled'] === 'no') {
p('hidden');
} ?>">
<em><?php p($l->t('Exclude some groups from sharing with users in their group')); ?></em>
<br />
<input name="shareapi_only_share_with_group_members_exclude_group_list" type="hidden" id="shareGroupMembersExcludeGroups" value="<?php p($_['shareWithGroupMembersExcludeGroupsList']) ?>" style="width: 400px" class="noJSAutoUpdate"/>
</p>
<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
p('hidden');
}?>">
Expand Down
13 changes: 13 additions & 0 deletions lib/private/Collaboration/Collaborators/GroupPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class GroupPlugin implements ISearchPlugin {
protected $shareeEnumerationInGroupOnly;
/** @var bool */
protected $groupSharingDisabled;
/** @var array */
protected $shareWithGroupOnlyExcludeGroupsList;

/** @var IGroupManager */
private $groupManager;
Expand All @@ -62,6 +64,14 @@ public function __construct(IConfig $config, IGroupManager $groupManager, IUserS
$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
$this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
$this->groupSharingDisabled = $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'no';

if ($this->shareWithGroupOnly) {
$shareWithGroupOnlyExcludeGroups = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', '');
$decodedExcludeGroups = json_decode($shareWithGroupOnlyExcludeGroups, true);
$this->shareWithGroupOnlyExcludeGroupsList = $decodedExcludeGroups ?? [];
} else {
$this->shareWithGroupOnlyExcludeGroupsList = [];
}
}

public function search($search, $limit, $offset, ISearchResult $searchResult) {
Expand Down Expand Up @@ -89,6 +99,9 @@ public function search($search, $limit, $offset, ISearchResult $searchResult) {
return $group->getGID();
}, $userGroups);
$groupIds = array_intersect($groupIds, $userGroups);

// ShareWithGroupOnly filtering
$groupIds = array_diff( $groupIds, $this->shareWithGroupOnlyExcludeGroupsList);
}

$lowerSearch = strtolower($search);
Expand Down
14 changes: 14 additions & 0 deletions lib/private/Collaboration/Collaborators/MailPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class MailPlugin implements ISearchPlugin {
protected $shareeEnumerationFullMatch;
/* @var bool */
protected $shareeEnumerationFullMatchEmail;
/** @var array */
protected $shareWithGroupOnlyExcludeGroupsList;

/** @var IManager */
private $contactsManager;
Expand Down Expand Up @@ -91,6 +93,14 @@ public function __construct(IManager $contactsManager,
$this->shareeEnumerationPhone = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
$this->shareeEnumerationFullMatch = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes';
$this->shareeEnumerationFullMatchEmail = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_email', 'yes') === 'yes';

if ($this->shareWithGroupOnly) {
$shareWithGroupOnlyExcludeGroups = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', '');
$decodedExcludeGroups = json_decode($shareWithGroupOnlyExcludeGroups, true);
$this->shareWithGroupOnlyExcludeGroupsList = $decodedExcludeGroups ?? [];
} else {
$this->shareWithGroupOnlyExcludeGroupsList = [];
}
}

/**
Expand Down Expand Up @@ -150,6 +160,10 @@ public function search($search, $limit, $offset, ISearchResult $searchResult) {
* Check if the user may share with the user associated with the e-mail of the just found contact
*/
$userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());

// ShareWithGroupOnly filtering
$userGroups = array_diff( $userGroups, $this->shareWithGroupOnlyExcludeGroupsList);

$found = false;
foreach ($userGroups as $userGroup) {
if ($this->groupManager->isInGroup($contact['UID'], $userGroup)) {
Expand Down
14 changes: 14 additions & 0 deletions lib/private/Collaboration/Collaborators/UserPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class UserPlugin implements ISearchPlugin {
protected $shareeEnumerationFullMatchEmail;
/* @var bool */
protected $shareeEnumerationFullMatchIgnoreSecondDisplayName;
/** @var array */
protected $shareWithGroupOnlyExcludeGroupsList;

/** @var IConfig */
private $config;
Expand Down Expand Up @@ -96,6 +98,14 @@ public function __construct(IConfig $config,
$this->shareeEnumerationFullMatchUserId = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_userid', 'yes') === 'yes';
$this->shareeEnumerationFullMatchEmail = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_email', 'yes') === 'yes';
$this->shareeEnumerationFullMatchIgnoreSecondDisplayName = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_ignore_second_dn', 'no') === 'yes';

if ($this->shareWithGroupOnly) {
$shareWithGroupOnlyExcludeGroups = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', '');
$decodedExcludeGroups = json_decode($shareWithGroupOnlyExcludeGroups, true);
$this->shareWithGroupOnlyExcludeGroupsList = $decodedExcludeGroups ?? [];
} else {
$this->shareWithGroupOnlyExcludeGroupsList = [];
}
}

public function search($search, $limit, $offset, ISearchResult $searchResult) {
Expand All @@ -105,6 +115,10 @@ public function search($search, $limit, $offset, ISearchResult $searchResult) {

$currentUserId = $this->userSession->getUser()->getUID();
$currentUserGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());

// ShareWithGroupOnly filtering
$currentUserGroups = array_diff( $currentUserGroups, $this->shareWithGroupOnlyExcludeGroupsList);

if ($this->shareWithGroupOnly || $this->shareeEnumerationInGroupOnly) {
// Search in all the groups this user is part of
foreach ($currentUserGroups as $userGroupId) {
Expand Down
11 changes: 11 additions & 0 deletions lib/private/Contacts/ContactsMenu/ContactsStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ public function getContacts(IUser $user, ?string $filter, ?int $limit = null, ?i
* 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.
* If enabled, the 'shareapi_only_share_with_group_members_exclude_group_list'
* config option may specify some groups excluded from the principle of
* belonging to the same group.
*
* @param IUser $self
* @param Entry[] $entries
Expand Down Expand Up @@ -160,6 +163,14 @@ private function filterContacts(
}
}

// ownGroupsOnly : some groups may be excluded
if ($ownGroupsOnly) {
$excludeGroupsFromOwnGroups = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', '');
$decodedExcludeGroupsFromOwnGroups = json_decode($excludeGroupsFromOwnGroups, true);
$excludeGroupsFromOwnGroupsList = $decodedExcludeGroupsFromOwnGroups ?? [];
$selfGroups = array_diff( $selfGroups, $excludeGroupsFromOwnGroupsList);
}

$selfUID = $self->getUID();

return array_values(array_filter($entries, function (IEntry $entry) use ($skipLocal, $ownGroupsOnly, $selfGroups, $selfUID, $disallowEnumeration, $restrictEnumerationGroup, $restrictEnumerationPhone, $allowEnumerationFullMatch, $filter) {
Expand Down
26 changes: 25 additions & 1 deletion lib/private/Share20/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,11 @@ protected function userCreateChecks(IShare $share) {
$this->groupManager->getUserGroupIds($sharedBy),
$this->groupManager->getUserGroupIds($sharedWith)
);

// optional excluded groups
$excludedGroups = $this->shareWithGroupMembersOnlyExcludedGroupsList();
$groups = array_diff($groups, $excludedGroups);

if (empty($groups)) {
$message_t = $this->l->t('Sharing is only allowed with group members');
throw new \Exception($message_t);
Expand Down Expand Up @@ -610,7 +615,10 @@ protected function groupCreateChecks(IShare $share) {
if ($this->shareWithGroupMembersOnly()) {
$sharedBy = $this->userManager->get($share->getSharedBy());
$sharedWith = $this->groupManager->get($share->getSharedWith());
if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {

// optional excluded groups
$excludedGroups = $this->shareWithGroupMembersOnlyExcludedGroupsList();
if (is_null($sharedWith) || in_array($share->getSharedWith(), $excludedGroups) || !$sharedWith->inGroup($sharedBy)) {
throw new \Exception('Sharing is only allowed within your own groups');
}
}
Expand Down Expand Up @@ -1940,6 +1948,22 @@ public function shareWithGroupMembersOnly() {
return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
}

/**
* If shareWithGroupMembersOnly is enabled, return an optional
* list of groups that must be excluded from the principle of
* belonging to the same group.
*
* @return array
*/
public function shareWithGroupMembersOnlyExcludedGroupsList() {
if (!$this->shareWithGroupMembersOnly()) {
return [];
}
$excludeGroups = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', '');
$decodedExcludeGroups = json_decode($excludeGroups, true);
return $decodedExcludeGroups ?? [];
}

/**
* Check if users can share with groups
*
Expand Down
9 changes: 9 additions & 0 deletions lib/public/Share/IManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,15 @@ public function shareApiLinkAllowPublicUpload();
*/
public function shareWithGroupMembersOnly();

/**
* If shareWithGroupMembersOnly is enabled, return an optional
* list of groups that must be excluded from the principle of
* belonging to the same group.
* @return array
* @since 27.0.0
*/
public function shareWithGroupMembersOnlyExcludedGroupsList();

/**
* Check if users can share with groups
* @return bool
Expand Down

0 comments on commit 4a8a75b

Please sign in to comment.