Merge pull request #59795 from nextcloud/backport/59792/stable31
Some checks are pending
Integration sqlite / changes (push) Waiting to run
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, --tags ~@large files_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, capabilities_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, collaboration_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, comments_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, dav_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, federation_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, file_conversions) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, files_reminders) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, filesdrop_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, ldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, openldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, openldap_numerical_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, remoteapi_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, setup_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, sharees_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, sharing_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, theming_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable31, 8.1, stable31, videoverification_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite-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
Psalm static code analysis / static-code-analysis-ncu (push) Waiting to run

[stable31] hide share token if share has more permissions than the current user
This commit is contained in:
Stephan Orbaugh 2026-04-22 16:53:09 +02:00 committed by GitHub
commit 54252ca04b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 44 additions and 7 deletions

View file

@ -74,6 +74,7 @@ use Psr\Log\LoggerInterface;
class ShareAPIController extends OCSController {
private ?Node $lockedNode = null;
/** @var array<bool> $trustedServerCache */
private array $trustedServerCache = [];
/**
@ -233,6 +234,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();
@ -258,6 +263,7 @@ 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.
@ -268,23 +274,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 Teams app version.

View file

@ -54,7 +54,7 @@ namespace OCA\Files_Sharing;
* token: ?string,
* uid_file_owner: string,
* uid_owner: string,
* url?: string,
* url?: string|null,
* }
*
* @psalm-type Files_SharingDeletedShare = array{

View file

@ -700,7 +700,8 @@
"type": "string"
},
"url": {
"type": "string"
"type": "string",
"nullable": true
}
}
},

View file

@ -23,6 +23,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