47
47
namespace OCA \Files_Sharing \Controller ;
48
48
49
49
use Exception ;
50
- use OC \Files \FileInfo ;
51
50
use OC \Files \Storage \Wrapper \Wrapper ;
52
51
use OCA \Files \Helper ;
53
52
use OCA \Files_Sharing \Exceptions \SharingRightsException ;
64
63
use OCP \AppFramework \OCSController ;
65
64
use OCP \AppFramework \QueryException ;
66
65
use OCP \Constants ;
66
+ use OCP \Files \File ;
67
67
use OCP \Files \Folder ;
68
68
use OCP \Files \InvalidPathException ;
69
69
use OCP \Files \IRootFolder ;
@@ -566,8 +566,8 @@ public function deleteShare(string $id): DataResponse {
566
566
* @param string|null $path Path of the share
567
567
* @param int|null $permissions Permissions for the share
568
568
* @param int $shareType Type of the share
569
- * @param string|null $shareWith The entity this should be shared with
570
- * @param string $publicUpload If public uploading is allowed
569
+ * @param ? string $shareWith The entity this should be shared with
570
+ * @param 'true'|'false'|null $publicUpload If public uploading is allowed (deprecated)
571
571
* @param string $password Password for the share
572
572
* @param string|null $sendPasswordByTalk Send the password for the share over Talk
573
573
* @param ?string $expireDate The expiry date of the share in the user's timezone at 00:00.
@@ -590,7 +590,7 @@ public function createShare(
590
590
?int $ permissions = null ,
591
591
int $ shareType = -1 ,
592
592
?string $ shareWith = null ,
593
- string $ publicUpload = ' false ' ,
593
+ ? string $ publicUpload = null ,
594
594
string $ password = '' ,
595
595
?string $ sendPasswordByTalk = null ,
596
596
?string $ expireDate = null ,
@@ -599,17 +599,7 @@ public function createShare(
599
599
?string $ attributes = null
600
600
): DataResponse {
601
601
$ share = $ this ->shareManager ->newShare ();
602
-
603
- if ($ permissions === null ) {
604
- if ($ shareType === IShare::TYPE_LINK
605
- || $ shareType === IShare::TYPE_EMAIL ) {
606
-
607
- // to keep legacy default behaviour, we ignore the setting below for link shares
608
- $ permissions = Constants::PERMISSION_READ ;
609
- } else {
610
- $ permissions = (int )$ this ->config ->getAppValue ('core ' , 'shareapi_default_permissions ' , (string )Constants::PERMISSION_ALL );
611
- }
612
- }
602
+ $ hasPublicUpload = $ this ->getLegacyPublicUpload ($ publicUpload );
613
603
614
604
// Verify path
615
605
if ($ path === null ) {
@@ -628,7 +618,7 @@ public function createShare(
628
618
// combine all permissions to determine if the user can share this file
629
619
$ nodes = $ userFolder ->getById ($ node ->getId ());
630
620
foreach ($ nodes as $ nodeById ) {
631
- /** @var FileInfo $fileInfo */
621
+ /** @var \OC\Files\ FileInfo $fileInfo */
632
622
$ fileInfo = $ node ->getFileInfo ();
633
623
$ fileInfo ['permissions ' ] |= $ nodeById ->getPermissions ();
634
624
}
@@ -641,17 +631,23 @@ public function createShare(
641
631
throw new OCSNotFoundException ($ this ->l ->t ('Could not create share ' ));
642
632
}
643
633
644
- if ($ permissions < 0 || $ permissions > Constants::PERMISSION_ALL ) {
645
- throw new OCSNotFoundException ($ this ->l ->t ('Invalid permissions ' ));
634
+ // Set permissions
635
+ if ($ shareType === IShare::TYPE_LINK || $ shareType === IShare::TYPE_EMAIL ) {
636
+ $ permissions = $ this ->getLinkSharePermissions ($ permissions , $ hasPublicUpload );
637
+ $ this ->validateLinkSharePermissions ($ node , $ permissions , $ hasPublicUpload );
638
+ } else {
639
+ // Use default permissions only for non-link shares to keep legacy behavior
640
+ if ($ permissions === null ) {
641
+ $ permissions = (int )$ this ->config ->getAppValue ('core ' , 'shareapi_default_permissions ' , (string )Constants::PERMISSION_ALL );
642
+ }
643
+ // Non-link shares always require read permissions (link shares could be file drop)
644
+ $ permissions |= Constants::PERMISSION_READ ;
646
645
}
647
646
648
- // Shares always require read permissions
649
- $ permissions |= Constants::PERMISSION_READ ;
650
-
651
- if ($ node instanceof \OCP \Files \File) {
652
- // Single file shares should never have delete or create permissions
653
- $ permissions &= ~Constants::PERMISSION_DELETE ;
654
- $ permissions &= ~Constants::PERMISSION_CREATE ;
647
+ // For legacy reasons the API allows to pass PERMISSIONS_ALL even for single file shares (I look at you Talk)
648
+ if ($ node instanceof File) {
649
+ // if this is a single file share we remove the DELETE and CREATE permissions
650
+ $ permissions = $ permissions & ~(Constants::PERMISSION_DELETE | Constants::PERMISSION_CREATE );
655
651
}
656
652
657
653
/**
@@ -712,28 +708,7 @@ public function createShare(
712
708
throw new OCSNotFoundException ($ this ->l ->t ('Public link sharing is disabled by the administrator ' ));
713
709
}
714
710
715
- if ($ publicUpload === 'true ' ) {
716
- // Check if public upload is allowed
717
- if (!$ this ->shareManager ->shareApiLinkAllowPublicUpload ()) {
718
- throw new OCSForbiddenException ($ this ->l ->t ('Public upload disabled by the administrator ' ));
719
- }
720
-
721
- // Public upload can only be set for folders
722
- if ($ node instanceof \OCP \Files \File) {
723
- throw new OCSNotFoundException ($ this ->l ->t ('Public upload is only possible for publicly shared folders ' ));
724
- }
725
-
726
- $ permissions = Constants::PERMISSION_READ |
727
- Constants::PERMISSION_CREATE |
728
- Constants::PERMISSION_UPDATE |
729
- Constants::PERMISSION_DELETE ;
730
- }
731
-
732
- // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
733
- if ($ this ->shareManager ->outgoingServer2ServerSharesAllowed ()) {
734
- $ permissions |= Constants::PERMISSION_SHARE ;
735
- }
736
-
711
+ $ this ->validateLinkSharePermissions ($ node , $ permissions , $ hasPublicUpload );
737
712
$ share ->setPermissions ($ permissions );
738
713
739
714
// Set password
@@ -979,6 +954,71 @@ public function getShares(
979
954
return new DataResponse ($ shares );
980
955
}
981
956
957
+ private function getLinkSharePermissions (?int $ permissions , ?bool $ legacyPublicUpload ): int {
958
+ $ permissions = $ permissions ?? Constants::PERMISSION_READ ;
959
+
960
+ // Legacy option handling
961
+ if ($ legacyPublicUpload !== null ) {
962
+ $ permissions = $ legacyPublicUpload
963
+ ? (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE )
964
+ : Constants::PERMISSION_READ ;
965
+ }
966
+
967
+ // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
968
+ if ($ this ->hasPermission ($ permissions , Constants::PERMISSION_READ )
969
+ && $ this ->shareManager ->outgoingServer2ServerSharesAllowed ()) {
970
+ $ permissions |= Constants::PERMISSION_SHARE ;
971
+ }
972
+
973
+ return $ permissions ;
974
+ }
975
+
976
+ /**
977
+ * Helper to check for legacy "publicUpload" handling.
978
+ * If the value is set to `true` or `false` then true or false are returned.
979
+ * Otherwise null is returned to indicate that the option was not (or wrong) set.
980
+ *
981
+ * @param null|string $legacyPublicUpload The value of `publicUpload`
982
+ */
983
+ private function getLegacyPublicUpload (?string $ legacyPublicUpload ): ?bool {
984
+ if ($ legacyPublicUpload === 'true ' ) {
985
+ return true ;
986
+ } elseif ($ legacyPublicUpload === 'false ' ) {
987
+ return false ;
988
+ }
989
+ // Not set at all
990
+ return null ;
991
+ }
992
+
993
+ /**
994
+ * For link and email shares validate that only allowed combinations are set.
995
+ *
996
+ * @throw OCSBadRequestException If permission combination is invalid.
997
+ * @throw OCSForbiddenException If public upload was forbidden by the administrator.
998
+ */
999
+ private function validateLinkSharePermissions (Node $ node , int $ permissions , ?bool $ legacyPublicUpload ): void {
1000
+ if ($ legacyPublicUpload && ($ node instanceof File)) {
1001
+ throw new OCSBadRequestException ($ this ->l ->t ('Public upload is only possible for publicly shared folders ' ));
1002
+ }
1003
+
1004
+ // We need at least READ or CREATE (file drop)
1005
+ if (!$ this ->hasPermission ($ permissions , Constants::PERMISSION_READ )
1006
+ && !$ this ->hasPermission ($ permissions , Constants::PERMISSION_CREATE )) {
1007
+ throw new OCSBadRequestException ($ this ->l ->t ('Share must at least have READ or CREATE permissions ' ));
1008
+ }
1009
+
1010
+ // UPDATE and DELETE require a READ permission
1011
+ if (!$ this ->hasPermission ($ permissions , Constants::PERMISSION_READ )
1012
+ && ($ this ->hasPermission ($ permissions , Constants::PERMISSION_UPDATE ) || $ this ->hasPermission ($ permissions , Constants::PERMISSION_DELETE ))) {
1013
+ throw new OCSBadRequestException ($ this ->l ->t ('Share must have READ permission if UPDATE or DELETE permission is set ' ));
1014
+ }
1015
+
1016
+ // Check if public uploading was disabled
1017
+ if ($ this ->hasPermission ($ permissions , Constants::PERMISSION_CREATE )
1018
+ && !$ this ->shareManager ->shareApiLinkAllowPublicUpload ()) {
1019
+ throw new OCSForbiddenException ($ this ->l ->t ('Public upload disabled by the administrator ' ));
1020
+ }
1021
+ }
982
1022
983
1023
/**
984
1024
* @param string $viewer
@@ -1161,7 +1201,6 @@ private function hasPermission(int $permissionsSet, int $permissionsToCheck): bo
1161
1201
return ($ permissionsSet & $ permissionsToCheck ) === $ permissionsToCheck ;
1162
1202
}
1163
1203
1164
-
1165
1204
/**
1166
1205
* @NoAdminRequired
1167
1206
*
@@ -1236,7 +1275,7 @@ public function updateShare(
1236
1275
$ this ->checkInheritedAttributes ($ share );
1237
1276
1238
1277
/**
1239
- * expirationdate , password and publicUpload only make sense for link shares
1278
+ * expiration date , password and publicUpload only make sense for link shares
1240
1279
*/
1241
1280
if ($ share ->getShareType () === IShare::TYPE_LINK
1242
1281
|| $ share ->getShareType () === IShare::TYPE_EMAIL ) {
@@ -1260,58 +1299,13 @@ public function updateShare(
1260
1299
$ share ->setHideDownload (false );
1261
1300
}
1262
1301
1263
- $ newPermissions = null ;
1264
- if ($ publicUpload === 'true ' ) {
1265
- $ newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE ;
1266
- } elseif ($ publicUpload === 'false ' ) {
1267
- $ newPermissions = Constants::PERMISSION_READ ;
1268
- }
1269
-
1270
- if ($ permissions !== null ) {
1271
- $ newPermissions = $ permissions ;
1272
- $ newPermissions = $ newPermissions & ~Constants::PERMISSION_SHARE ;
1273
- }
1274
-
1275
- if ($ newPermissions !== null ) {
1276
- if (!$ this ->hasPermission ($ newPermissions , Constants::PERMISSION_READ ) && !$ this ->hasPermission ($ newPermissions , Constants::PERMISSION_CREATE )) {
1277
- throw new OCSBadRequestException ($ this ->l ->t ('Share must at least have READ or CREATE permissions ' ));
1278
- }
1279
-
1280
- if (!$ this ->hasPermission ($ newPermissions , Constants::PERMISSION_READ ) && (
1281
- $ this ->hasPermission ($ newPermissions , Constants::PERMISSION_UPDATE ) || $ this ->hasPermission ($ newPermissions , Constants::PERMISSION_DELETE )
1282
- )) {
1283
- throw new OCSBadRequestException ($ this ->l ->t ('Share must have READ permission if UPDATE or DELETE permission is set ' ));
1284
- }
1285
- }
1286
-
1287
- if (
1288
- // legacy
1289
- $ newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE ) ||
1290
- // correct
1291
- $ newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE )
1292
- ) {
1293
- if (!$ this ->shareManager ->shareApiLinkAllowPublicUpload ()) {
1294
- throw new OCSForbiddenException ($ this ->l ->t ('Public upload disabled by the administrator ' ));
1295
- }
1296
-
1297
- if (!($ share ->getNode () instanceof \OCP \Files \Folder)) {
1298
- throw new OCSBadRequestException ($ this ->l ->t ('Public upload is only possible for publicly shared folders ' ));
1299
- }
1300
-
1301
- // normalize to correct public upload permissions
1302
- if ($ publicUpload === 'true ' ) {
1303
- $ newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE ;
1304
- }
1305
- }
1306
-
1307
- if ($ newPermissions !== null ) {
1308
- // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
1309
- if (($ newPermissions & Constants::PERMISSION_READ ) && $ this ->shareManager ->outgoingServer2ServerSharesAllowed ()) {
1310
- $ newPermissions |= Constants::PERMISSION_SHARE ;
1311
- }
1312
-
1313
- $ share ->setPermissions ($ newPermissions );
1314
- $ permissions = $ newPermissions ;
1302
+ // If either manual permissions are specified or publicUpload
1303
+ // then we need to also update the permissions of the share
1304
+ if ($ permissions !== null || $ publicUpload !== null ) {
1305
+ $ hasPublicUpload = $ this ->getLegacyPublicUpload ($ publicUpload );
1306
+ $ permissions = $ this ->getLinkSharePermissions ($ permissions ?? Constants::PERMISSION_READ , $ hasPublicUpload );
1307
+ $ this ->validateLinkSharePermissions ($ share ->getNode (), $ permissions , $ hasPublicUpload );
1308
+ $ share ->setPermissions ($ permissions );
1315
1309
}
1316
1310
1317
1311
if ($ password === '' ) {
0 commit comments