@@ -358,7 +358,7 @@ public function updateShareRecipientSecret(string $id, ShareRecipient $recipient
358358 }
359359
360360 #[\Override]
361- public function createShareProperty (string $ id , ShareProperty $ property ): void {
361+ public function createShareProperty (string $ id , ShareProperty $ property ): ? string {
362362 $ value = $ property ->value ;
363363
364364 $ propertyType = $ this ->registry ->getPropertyTypes ()[$ property ->class ];
@@ -377,6 +377,8 @@ public function createShareProperty(string $id, ShareProperty $property): void {
377377 'property_value ' => $ qb ->createNamedParameter ($ value ),
378378 ])
379379 ->executeStatement ();
380+
381+ return $ value ;
380382 } catch (\OCP \DB \Exception $ exception ) {
381383 if ($ exception ->getReason () === \OCP \DB \Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION ) {
382384 throw new RuntimeException ('The property already exists: ' . $ property ->class , $ exception ->getCode (), $ exception );
@@ -387,7 +389,7 @@ public function createShareProperty(string $id, ShareProperty $property): void {
387389 }
388390
389391 #[\Override]
390- public function updateShareProperty (string $ id , ShareProperty $ property ): void {
392+ public function updateShareProperty (string $ id , ShareProperty $ property ): ? string {
391393 $ value = $ property ->value ;
392394
393395 $ propertyType = $ this ->registry ->getPropertyTypes ()[$ property ->class ];
@@ -425,6 +427,8 @@ public function updateShareProperty(string $id, ShareProperty $property): void {
425427 if ($ rowCount === 0 ) {
426428 throw new ShareNotFoundException ();
427429 }
430+
431+ return $ value ;
428432 }
429433
430434 #[\Override]
@@ -588,9 +592,22 @@ private function hideDisabledUserShares(): bool {
588592 * @return list<Share>
589593 */
590594 private function list (
591- ShareAccessContext $ accessContext , ?string $ filterShareID , ?string $ filterSourceTypeClass , ?string $ filterSourceTypeValue , ?string $ lastShareID ,
595+ ShareAccessContext $ accessContext ,
596+ ?string $ filterShareID ,
597+ ?string $ filterSourceTypeClass ,
598+ ?string $ filterSourceTypeValue ,
599+ ?string $ lastShareID ,
592600 ?int $ limit ,
593601 ): array {
602+ if ($ filterSourceTypeClass ) {
603+ $ filterSourceType = $ this ->registry ->getSourceTypes ()[$ filterSourceTypeClass ] ?? null ;
604+ if ($ filterSourceType === null ) {
605+ throw new RuntimeException ('The source type is not registered: ' . $ filterSourceTypeClass );
606+ }
607+ } else {
608+ $ filterSourceType = null ;
609+ }
610+
594611 /** @var array<class-string<IShareRecipientType>, list<string>> $recipientTypeValues */
595612 $ recipientTypeValues = [];
596613
@@ -601,7 +618,11 @@ private function list(
601618 } else {
602619 if ($ accessContext ->currentUser instanceof IUser) {
603620 $ qb = $ this ->connection ->getQueryBuilder ();
604- $ qb ->where ($ qb ->expr ()->eq ('s.owner_user_id ' , $ qb ->createNamedParameter ($ accessContext ->currentUser ->getUID ())));
621+ // if we're filtering by source or id, we need to also check for non-owned shares
622+ if ($ filterSourceTypeValue === null && $ filterShareID === null ) {
623+ $ qb ->where ($ qb ->expr ()->eq ('s.owner_user_id ' , $ qb ->createNamedParameter ($ accessContext ->currentUser ->getUID ())));
624+ }
625+
605626 $ queries [] = $ qb ;
606627 }
607628
@@ -613,6 +634,7 @@ private function list(
613634 }
614635
615636 // Do not add a query if no recipients matched, otherwise all shares will be returned.
637+ // If the user has "direct" access, we already get all the shares, so no need to run an extra query for recipients
616638 if ($ recipientTypeValues !== []) {
617639 $ qb = $ this ->connection ->getQueryBuilder ();
618640 $ qb ->innerJoin (
@@ -672,7 +694,7 @@ private function list(
672694 $ qb ->andWhere ($ qb ->expr ()->eq ('s.id ' , $ qb ->createNamedParameter ($ filterShareID )));
673695 }
674696
675- if ($ filterSourceTypeClass !== null ) {
697+ if ($ filterSourceType !== null && $ filterSourceTypeClass !== null ) {
676698 $ sourceTypeFilters = [
677699 $ qb ->expr ()->eq ('s.id ' , 'ss.share_id ' ),
678700 $ qb ->expr ()->eq (
@@ -867,8 +889,10 @@ private function list(
867889
868890 // Some recipients might have been removed if the initiator was disabled, so check again if this share can be accessed by the current user as a recipient.
869891 // This logic is a bit duplicated with the SQL logic that selects shares based on the secret and the recipient type values, but neither can be removed.
892+ /** @var array<string, bool> $hasRecipientAccess */
893+ $ hasRecipientAccess = [];
870894 if (!$ accessContext ->overrideChecks ) {
871- foreach ($ shares as $ id => &$ share ) {
895+ foreach ($ shares as &$ share ) {
872896 if ($ share ['owner ' ]->isCurrentUser ($ accessContext )) {
873897 continue ;
874898 }
@@ -904,9 +928,7 @@ private function list(
904928
905929 unset($ recipient );
906930
907- if (!$ isAnyMatchingRecipient ) {
908- unset($ shares [$ id ]);
909- }
931+ $ hasRecipientAccess [$ share ['id ' ]] = $ isAnyMatchingRecipient && $ share ['state ' ] === ShareState::Active;
910932 }
911933
912934 unset($ share );
@@ -1016,6 +1038,41 @@ private function list(
10161038 $ share ['permissions ' ],
10171039 ), $ shares );
10181040
1041+ // when listing shares for a source, we also return any non-owned share if the user has "direct" access to the source
1042+ // but we do need to validate that the user has "direct" access to *all* of the sources in the share, not just one
1043+ $ hasSourceAccess = [];
1044+ if (!$ accessContext ->overrideChecks && $ accessContext ->currentUser instanceof IUser) {
1045+ foreach ($ shares as $ share ) {
1046+ if ($ share ->owner ->isCurrentUser ($ accessContext )) {
1047+ continue ;
1048+ }
1049+
1050+ if ($ hasRecipientAccess [$ share ->id ]) {
1051+ continue ;
1052+ }
1053+
1054+ if ($ share ->sources === []) {
1055+ $ hasSourceAccess [$ share ->id ] = false ;
1056+ continue ;
1057+ }
1058+
1059+ $ hasSourceAccess [$ share ->id ] = true ;
1060+ foreach ($ share ->sources as $ source ) {
1061+ $ sourceType = $ this ->registry ->getSourceTypes ()[$ source ->class ];
1062+ if (!$ sourceType ->userHasDirectSharingAccessToSource ($ accessContext ->currentUser , $ source ->value )) {
1063+ $ hasSourceAccess [$ share ->id ] = false ;
1064+ }
1065+ }
1066+ }
1067+ }
1068+
1069+ if (!$ accessContext ->overrideChecks ) {
1070+ $ shares = array_filter (
1071+ $ shares ,
1072+ fn (Share $ share ): bool => $ share ->owner ->isCurrentUser ($ accessContext ) || $ hasRecipientAccess [$ share ->id ] || $ hasSourceAccess [$ share ->id ]
1073+ );
1074+ }
1075+
10191076 if (!$ accessContext ->overrideChecks ) {
10201077 $ filterPropertyTypes = array_filter (
10211078 $ registryPropertyTypes , static fn (ISharePropertyType $ propertyType ): bool => $ propertyType instanceof ISharePropertyTypeFilter
@@ -1102,7 +1159,15 @@ public function createSharePropertyDefaultValue(Share $share, string $propertyTy
11021159
11031160 $ property = new ShareProperty ($ propertyTypeClass , $ propertyType ->getDefaultValue ($ share ));
11041161
1105- $ this ->createShareProperty ($ share ->id , $ property );
1162+ $ value = $ this ->createShareProperty ($ share ->id , $ property );
1163+ if ($ propertyType instanceof ISharePropertyTypeModifyValue) {
1164+ $ value = $ propertyType ->modifyValueOnLoad ($ value );
1165+ }
1166+
1167+ $ property = new ShareProperty (
1168+ $ property ->class ,
1169+ $ value ,
1170+ );
11061171
11071172 $ properties = $ share ->properties ;
11081173 $ properties [$ propertyTypeClass ] = $ property ;
0 commit comments