Merge pull request #59802 from nextcloud/backport/59792/stable26
Some checks are pending
Cypress / init (push) Waiting to run
Cypress / runner 1 (push) Blocked by required conditions
Cypress / runner 2 (push) Blocked by required conditions
Cypress / runner component (push) Blocked by required conditions
Cypress / cypress-summary (push) Blocked by required conditions
Lint eslint / eslint (push) Waiting to run
Lint php / php-lint (push) Waiting to run
Lint php / php-lint-summary (push) Blocked by required conditions
Node / versions (push) Waiting to run
Node / test (push) Blocked by required conditions
Node / jsunit (push) Blocked by required conditions
Node / handlebars (push) Blocked by required conditions
Node / node (push) Waiting to run
S3 primary storage integration tests / php8.0-objectstore-minio (push) Waiting to run
S3 primary storage integration tests / php8.0-objectstore_multibucket-minio (push) Waiting to run
S3 primary storage integration tests / s3-primary-integration-summary (push) Blocked by required conditions
S3 primary storage / php8.0-objectstore-minio (push) Waiting to run
S3 primary storage / php8.0-objectstore_multibucket-minio (push) Waiting to run
S3 primary storage / s3-primary-summary (push) Blocked by required conditions
Psalm static code analysis / static-code-analysis (push) Waiting to run
Psalm static code analysis / static-code-analysis-security (push) Waiting to run
Psalm static code analysis / static-code-analysis-ocp (push) Waiting to run

[stable26] hide share token if share has more permissions than the current user
This commit is contained in:
Stephan Orbaugh 2026-04-22 16:54:48 +02:00 committed by GitHub
commit 0294edad80
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 41 additions and 5 deletions

View file

@ -227,6 +227,10 @@ class ShareAPIController extends OCSController {
$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
}
$currentUserPermissions = $recipientNode?->getPermissions() ?? Constants::PERMISSION_ALL;
$userHasEnoughPermissions = ($currentUserPermissions & $share->getPermissions()) === $share->getPermissions();
$token = $userHasEnoughPermissions ? $share->getToken() : null;
if ($share->getShareType() === IShare::TYPE_USER) {
$sharedWith = $this->userManager->get($share->getSharedWith());
$result['share_with'] = $share->getSharedWith();
@ -253,6 +257,8 @@ class ShareAPIController extends OCSController {
$result['share_with'] = $share->getSharedWith();
$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
} elseif ($share->getShareType() === IShare::TYPE_LINK) {
$url = $token ? $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $token]) : null;
// "share_with" and "share_with_displayname" for passwords of link
// shares was deprecated in Nextcloud 15, use "password" instead.
$result['share_with'] = $share->getPassword();
@ -262,23 +268,23 @@ class ShareAPIController extends OCSController {
$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
$result['token'] = $share->getToken();
$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
$result['token'] = $token;
$result['url'] = $url;
} elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
$result['share_with'] = $share->getSharedWith();
$result['share_with_displayname'] = $this->getCachedFederatedDisplayName($share->getSharedWith());
$result['token'] = $share->getToken();
$result['token'] = $token;
} elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
$result['share_with'] = $share->getSharedWith();
$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
$result['token'] = $share->getToken();
$result['token'] = $token;
} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
$result['share_with'] = $share->getSharedWith();
$result['password'] = $share->getPassword();
$result['password_expiration_time'] = $share->getPasswordExpirationTime() !== null ? $share->getPasswordExpirationTime()->format(\DateTime::ATOM) : null;
$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
$result['token'] = $share->getToken();
$result['token'] = $token;
} elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
// getSharedWith() returns either "name (type, owner)" or
// "name (type, owner) [id]", depending on the Circles app version.

View file

@ -21,6 +21,36 @@ Feature: sharing
And User "user2" should be included in the response
And User "user3" should not be included in the response
Scenario: getting all shares of a file with reshares with link share with less permissions
Given user "user0" exists
And user "user1" exists
When as "user0" creating a share with
| path | textfile0.txt |
| shareType | 0 |
| shareWith | user1 |
| permissions | 17 |
Then the OCS status code should be "100"
And the HTTP status code should be "200"
When as "user0" creating a share with
| path | textfile0.txt |
| shareType | 3 |
| permissions | 19 |
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And last link share can be downloaded
When As an "user1"
And sending "GET" to "/apps/files_sharing/api/v1/shares?reshares=true&path=textfile0 (2).txt"
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And User "user1" should not be included in the response
Then the list of returned shares has 1 shares
And share 0 is returned with
| share_type | 3 |
| uid_owner | user0 |
| token | |
| url | |
| permissions | 19 |
Scenario: getting all shares of a file with a received share after revoking the resharing rights
Given user "user0" exists
And user "user1" exists