Skip to content

Commit 3b6bcc7

Browse files
authored
Merge pull request #55329 from nextcloud/backport/55311/stable32
[stable32] fix: add missing sharing options to ui and add full-match results
2 parents bc02b6a + 9581641 commit 3b6bcc7

File tree

7 files changed

+94
-48
lines changed

7 files changed

+94
-48
lines changed

apps/settings/lib/Settings/Admin/Sharing.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ public function getForm() {
5353
'allowFederationOnPublicShares' => $this->appConfig->getValueBool('core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES),
5454
'restrictUserEnumerationToGroup' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_to_group'),
5555
'restrictUserEnumerationToPhone' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_to_phone'),
56-
'restrictUserEnumerationFullMatch' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_full_match', true),
57-
'restrictUserEnumerationFullMatchUserId' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_full_match_userid', true),
58-
'restrictUserEnumerationFullMatchEmail' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_full_match_email', true),
59-
'restrictUserEnumerationFullMatchIgnoreSecondDN' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_full_match_ignore_second_dn'),
56+
'restrictUserEnumerationFullMatch' => $this->shareManager->allowEnumerationFullMatch(),
57+
'restrictUserEnumerationFullMatchUserId' => $this->shareManager->matchUserId(),
58+
'restrictUserEnumerationFullMatchEmail' => $this->shareManager->matchEmail(),
59+
'restrictUserEnumerationFullMatchIgnoreSecondDN' => $this->shareManager->ignoreSecondDisplayName(),
6060
'enforceLinksPassword' => Util::isPublicLinkPasswordRequired(false),
6161
'enforceLinksPasswordExcludedGroups' => json_decode($excludedPasswordGroups) ?? [],
6262
'enforceLinksPasswordExcludedGroupsEnabled' => $this->config->getSystemValueBool('sharing.allow_disabled_password_enforcement_groups', false),

apps/settings/src/components/AdminSettingsSharingForm.vue

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
-->
55
<template>
66
<form class="sharing">
7-
<NcCheckboxRadioSwitch aria-controls="settings-sharing-api settings-sharing-api-settings settings-sharing-default-permissions settings-sharing-privary-related"
7+
<NcCheckboxRadioSwitch aria-controls="settings-sharing-api settings-sharing-api-settings settings-sharing-default-permissions settings-sharing-privacy-related"
88
type="switch"
99
:checked.sync="settings.enabled">
1010
{{ t('settings', 'Allow apps to use the Share API') }}
@@ -174,7 +174,7 @@
174174
</fieldset>
175175
</div>
176176

177-
<div v-show="settings.enabled" id="settings-sharing-privary-related" class="sharing__section">
177+
<div v-show="settings.enabled" id="settings-sharing-privacy-related" class="sharing__section">
178178
<h3>{{ t('settings', 'Privacy settings for sharing') }}</h3>
179179

180180
<NcCheckboxRadioSwitch type="switch"
@@ -183,33 +183,52 @@
183183
{{ t('settings', 'Allow account name autocompletion in share dialog and allow access to the system address book') }}
184184
</NcCheckboxRadioSwitch>
185185
<fieldset v-show="settings.allowShareDialogUserEnumeration" id="settings-sharing-privacy-user-enumeration" class="sharing__sub-section">
186+
<legend class="hidden-visually">
187+
{{ t('settings', 'Sharing autocompletion restrictions') }}
188+
</legend>
186189
<em>
187-
{{ t('settings', 'If autocompletion "same group" and "phone number integration" are enabled a match in either is enough to show the user.') }}
190+
{{ t('settings', 'If autocompletion restrictions for both "same group" and "phonebook integration" are enabled, a match in either is enough to show the user.') }}
188191
</em>
189192
<NcCheckboxRadioSwitch :checked.sync="settings.restrictUserEnumerationToGroup">
190193
{{ t('settings', 'Restrict account name autocompletion and system address book access to users within the same groups') }}
191194
</NcCheckboxRadioSwitch>
192195
<NcCheckboxRadioSwitch :checked.sync="settings.restrictUserEnumerationToPhone">
193-
{{ t('settings', 'Restrict account name autocompletion to users based on phone number integration') }}
196+
{{ t('settings', 'Restrict account name autocompletion to users based on their phonebook') }}
194197
</NcCheckboxRadioSwitch>
195198
</fieldset>
196199

197-
<NcCheckboxRadioSwitch type="switch" :checked.sync="settings.restrictUserEnumerationFullMatch">
198-
{{ t('settings', 'Allow autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)') }}
200+
<NcCheckboxRadioSwitch v-model="settings.restrictUserEnumerationFullMatch"
201+
type="switch"
202+
aria-controls="settings-sharing-privacy-autocomplete">
203+
{{ t('settings', 'Allow autocompletion to full match when entering the full name (ignoring restrictions like group membership or missing phonebook match)') }}
199204
</NcCheckboxRadioSwitch>
205+
<fieldset v-show="settings.restrictUserEnumerationFullMatch" id="settings-sharing-privacy-autocomplete" class="sharing__sub-section">
206+
<legend class="hidden-visually">
207+
{{ t('settings', 'Full match autocompletion restrictions') }}
208+
</legend>
209+
<NcCheckboxRadioSwitch :checked.sync="settings.restrictUserEnumerationFullMatchUserId">
210+
{{ t('settings', 'Also allow autocompletion on full match of the user id') }}
211+
</NcCheckboxRadioSwitch>
212+
<NcCheckboxRadioSwitch :checked.sync="settings.restrictUserEnumerationFullMatchEmail">
213+
{{ t('settings', 'Also allow autocompletion on full match of the user email') }}
214+
</NcCheckboxRadioSwitch>
215+
<NcCheckboxRadioSwitch :checked.sync="settings.restrictUserEnumerationFullMatchIgnoreSecondDN">
216+
{{ t('settings', 'Do not use second user displayname for full match') }}
217+
</NcCheckboxRadioSwitch>
218+
</fieldset>
200219

201220
<NcCheckboxRadioSwitch type="switch" :checked.sync="publicShareDisclaimerEnabled">
202221
{{ t('settings', 'Show disclaimer text on the public link upload page (only shown when the file list is hidden)') }}
203222
</NcCheckboxRadioSwitch>
204223
<div v-if="publicShareDisclaimerEnabled"
205-
aria-describedby="settings-sharing-privary-related-disclaimer-hint"
224+
aria-describedby="settings-sharing-privacy-related-disclaimer-hint"
206225
class="sharing__sub-section">
207226
<NcTextArea class="sharing__input"
208227
:label="t('settings', 'Disclaimer text')"
209-
aria-describedby="settings-sharing-privary-related-disclaimer-hint"
228+
aria-describedby="settings-sharing-privacy-related-disclaimer-hint"
210229
:value="settings.publicShareDisclaimerText"
211230
@update:value="onUpdateDisclaimer" />
212-
<em id="settings-sharing-privary-related-disclaimer-hint" class="sharing__input">
231+
<em id="settings-sharing-privacy-related-disclaimer-hint" class="sharing__input">
213232
{{ t('settings', 'This text will be shown on the public link upload page when the file list is hidden.') }}
214233
</em>
215234
</div>

dist/settings-vue-settings-admin-sharing.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/settings-vue-settings-admin-sharing.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/private/Collaboration/Collaborators/UserPlugin.php

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,10 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b
6363
$users = [];
6464
$hasMoreResults = false;
6565

66-
$currentUserId = $this->userSession->getUser()->getUID();
67-
$currentUserGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
66+
/** @var IUser */
67+
$currentUser = $this->userSession->getUser();
68+
$currentUserId = $currentUser->getUID();
69+
$currentUserGroups = $this->groupManager->getUserGroupIds($currentUser);
6870

6971
// ShareWithGroupOnly filtering
7072
$currentUserGroups = array_diff($currentUserGroups, $this->shareWithGroupOnlyExcludeGroupsList);
@@ -76,7 +78,7 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b
7678
foreach ($usersInGroup as $userId => $displayName) {
7779
$userId = (string)$userId;
7880
$user = $this->userManager->get($userId);
79-
if (!$user->isEnabled()) {
81+
if (!$user?->isEnabled()) {
8082
// Ignore disabled users
8183
continue;
8284
}
@@ -86,37 +88,43 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b
8688
$hasMoreResults = true;
8789
}
8890
}
91+
}
8992

90-
if (!$this->shareWithGroupOnly && $this->shareeEnumerationPhone) {
91-
$usersTmp = $this->userManager->searchKnownUsersByDisplayName($currentUserId, $search, $limit, $offset);
92-
if (!empty($usersTmp)) {
93+
// not limited to group only sharing
94+
if (!$this->shareWithGroupOnly) {
95+
if (!$this->shareeEnumerationPhone && !$this->shareeEnumerationInGroupOnly) {
96+
// no restrictions, add everything
97+
$usersTmp = $this->userManager->searchDisplayName($search, $limit, $offset);
98+
foreach ($usersTmp as $user) {
99+
if ($user->isEnabled()) { // Don't keep deactivated users
100+
$users[$user->getUID()] = $user;
101+
}
102+
}
103+
} else {
104+
// make sure to add phonebook matches if configured
105+
if ($this->shareeEnumerationPhone) {
106+
$usersTmp = $this->userManager->searchKnownUsersByDisplayName($currentUserId, $search, $limit, $offset);
93107
foreach ($usersTmp as $user) {
94108
if ($user->isEnabled()) { // Don't keep deactivated users
95109
$users[$user->getUID()] = $user;
96110
}
97111
}
98-
99-
uasort($users, function ($a, $b) {
100-
/**
101-
* @var \OC\User\User $a
102-
* @var \OC\User\User $b
103-
*/
104-
return strcasecmp($a->getDisplayName(), $b->getDisplayName());
105-
});
106112
}
107-
}
108-
} else {
109-
// Search in all users
110-
if ($this->shareeEnumerationPhone) {
111-
$usersTmp = $this->userManager->searchKnownUsersByDisplayName($currentUserId, $search, $limit, $offset);
112-
} else {
113-
$usersTmp = $this->userManager->searchDisplayName($search, $limit, $offset);
114-
}
115-
foreach ($usersTmp as $user) {
116-
if ($user->isEnabled()) { // Don't keep deactivated users
117-
$users[$user->getUID()] = $user;
113+
114+
// additionally we need to add full matches
115+
if ($this->shareeEnumerationFullMatch) {
116+
$usersTmp = $this->userManager->searchDisplayName($search, $limit, $offset);
117+
foreach ($usersTmp as $user) {
118+
if ($user->isEnabled() && mb_strtolower($user->getDisplayName()) === mb_strtolower($search)) {
119+
$users[$user->getUID()] = $user;
120+
}
121+
}
118122
}
119123
}
124+
125+
uasort($users, function (IUser $a, IUser $b) {
126+
return strcasecmp($a->getDisplayName(), $b->getDisplayName());
127+
});
120128
}
121129

122130
$this->takeOutCurrentUser($users);
@@ -149,10 +157,13 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b
149157

150158
if (
151159
$this->shareeEnumerationFullMatch
152-
&& $lowerSearch !== '' && (strtolower($uid) === $lowerSearch
153-
|| strtolower($userDisplayName) === $lowerSearch
154-
|| ($this->shareeEnumerationFullMatchIgnoreSecondDisplayName && trim(strtolower(preg_replace('/ \(.*\)$/', '', $userDisplayName))) === $lowerSearch)
155-
|| ($this->shareeEnumerationFullMatchEmail && strtolower($userEmail ?? '') === $lowerSearch))
160+
&& $lowerSearch !== ''
161+
&& (
162+
strtolower($uid) === $lowerSearch
163+
|| strtolower($userDisplayName) === $lowerSearch
164+
|| ($this->shareeEnumerationFullMatchIgnoreSecondDisplayName && trim(strtolower(preg_replace('/ \(.*\)$/', '', $userDisplayName))) === $lowerSearch)
165+
|| ($this->shareeEnumerationFullMatchEmail && strtolower($userEmail ?? '') === $lowerSearch)
166+
)
156167
) {
157168
if (strtolower($uid) === $lowerSearch) {
158169
$foundUserById = true;

lib/private/Share20/Manager.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,6 +1931,10 @@ public function matchEmail(): bool {
19311931
return $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_email', 'yes') === 'yes';
19321932
}
19331933

1934+
public function matchUserId(): bool {
1935+
return $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_userid', 'yes') === 'yes';
1936+
}
1937+
19341938
public function ignoreSecondDisplayName(): bool {
19351939
return $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_ignore_second_dn', 'no') === 'yes';
19361940
}

lib/public/Share/IManager.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -441,23 +441,35 @@ public function limitEnumerationToGroups(): bool;
441441
public function limitEnumerationToPhone(): bool;
442442

443443
/**
444-
* Check if user enumeration is allowed to return on full match
444+
* Check if user enumeration is allowed to return also on full match
445+
* and ignore limitations to phonebook or groups.
445446
*
446447
* @return bool
447448
* @since 21.0.1
448449
*/
449450
public function allowEnumerationFullMatch(): bool;
450451

451452
/**
452-
* Check if the search should match the email
453+
* When `allowEnumerationFullMatch` is enabled and `matchEmail` is set,
454+
* then also return results for full email matches.
453455
*
454456
* @return bool
455457
* @since 25.0.0
456458
*/
457459
public function matchEmail(): bool;
458460

459461
/**
460-
* Check if the search should ignore the second in parentheses display name if there is any
462+
* When `allowEnumerationFullMatch` is enabled and `matchUserId` is set,
463+
* then also return results for full user id matches.
464+
*
465+
* @return bool
466+
* @since 32.0.1
467+
*/
468+
public function matchUserId(): bool;
469+
470+
/**
471+
* When `allowEnumerationFullMatch` is enabled and `ignoreSecondDisplayName` is set,
472+
* then the search should ignore matches on the second displayname and only use the first.
461473
*
462474
* @return bool
463475
* @since 25.0.0

0 commit comments

Comments
 (0)