77
88namespace OCA \Activity \Controller ;
99
10+ use DateTimeInterface ;
11+ use OC \Files \Storage \Wrapper \Wrapper ;
1012use OCA \Activity \Extension \Files ;
13+ use OCA \Files_Sharing \External \Storage as ExternalStorage ;
1114use OCP \Activity \IManager as IActivityManager ;
1215use OCP \App \IAppManager ;
1316use OCP \AppFramework \Http ;
17+ use OCP \AppFramework \Http \Attribute \BruteForceProtection ;
1418use OCP \AppFramework \Http \DataResponse ;
1519use OCP \AppFramework \OCSController ;
20+ use OCP \AppFramework \Utility \ITimeFactory ;
21+ use OCP \Federation \ICloudIdManager ;
22+ use OCP \Files \IFilenameValidator ;
1623use OCP \Files \InvalidPathException ;
1724use OCP \Files \IRootFolder ;
25+ use OCP \Files \ISetupManager ;
1826use OCP \Files \NotFoundException ;
1927use OCP \IDBConnection ;
2028use OCP \IRequest ;
@@ -30,6 +38,10 @@ public function __construct(
3038 protected IAppManager $ appManager ,
3139 protected IRootFolder $ rootFolder ,
3240 protected IActivityManager $ activityManager ,
41+ protected ICloudIdManager $ cloudIdManager ,
42+ protected IFilenameValidator $ filenameValidator ,
43+ protected ISetupManager $ setupManager ,
44+ protected ITimeFactory $ timeFactory ,
3345 ) {
3446 parent ::__construct ($ appName , $ request );
3547 }
@@ -48,20 +60,26 @@ public function __construct(
4860 * @param string[] $origin
4961 * @return DataResponse
5062 */
51- public function receiveActivity ($ token , array $ to , array $ actor , $ type , $ updated , array $ object = [], array $ target = [], array $ origin = []) {
52- $ date = \DateTime::createFromFormat (\DateTime::W3C , $ updated );
53- if ($ date === false ) {
63+ #[BruteForceProtection(action: 'receiveActivity ' )]
64+ public function receiveActivity ($ token , array $ to , array $ actor , $ type , $ updated , array $ object = [], array $ target = [], array $ origin = []): DataResponse {
65+ if (!$ this ->appManager ->isEnabledForAnyone ('federatedfilesharing ' )) {
66+ return new DataResponse ([], Http::STATUS_NOT_FOUND );
67+ }
68+
69+ $ date = \DateTime::createFromFormat (DateTimeInterface::W3C , $ updated );
70+ if ($ date === false || abs ($ date ->getTimestamp () - $ this ->timeFactory ->getTime ()) > 600 ) {
5471 return new DataResponse ([], Http::STATUS_BAD_REQUEST );
5572 }
56- $ time = $ date ->getTimestamp ();
5773
5874 if (!isset ($ to ['type ' ], $ to ['name ' ]) || $ to ['type ' ] !== 'Person ' ) {
5975 return new DataResponse ([], Http::STATUS_BAD_REQUEST );
6076 }
6177
6278 $ user = $ this ->userManager ->get ($ to ['name ' ]);
6379 if (!$ user instanceof IUser) {
64- return new DataResponse ([], Http::STATUS_NOT_FOUND );
80+ $ response = new DataResponse ([], Http::STATUS_NOT_FOUND );
81+ $ response ->throttle ();
82+ return $ response ;
6583 }
6684
6785 if (!isset ($ actor ['type ' ], $ actor ['name ' ]) || $ actor ['type ' ] !== 'Person ' ) {
@@ -72,27 +90,44 @@ public function receiveActivity($token, array $to, array $actor, $type, $updated
7290 return new DataResponse ([], Http::STATUS_BAD_REQUEST );
7391 }
7492
75- if (!$ this ->appManager ->isInstalled ('federatedfilesharing ' )) {
76- return new DataResponse ([], Http::STATUS_NOT_FOUND );
93+ if (isset ($ object ['name ' ]) && preg_match ('/(^|\/)\.\.(\/|$)/ ' , $ object ['name ' ])) {
94+ return new DataResponse ([], Http::STATUS_BAD_REQUEST );
95+ }
96+
97+ try {
98+ $ resolved = $ this ->cloudIdManager ->resolveCloudId ($ actor ['name ' ]);
99+ $ actorServer = $ resolved ->getRemote ();
100+ $ actorUser = $ resolved ->getUser ();
101+ } catch (\InvalidArgumentException ) {
102+ return new DataResponse ([], Http::STATUS_BAD_REQUEST );
103+ }
104+
105+ $ internalType = $ this ->translateType ($ type );
106+ if ($ internalType === '' ) {
107+ return new DataResponse ([], Http::STATUS_BAD_REQUEST );
77108 }
78109
79110 $ query = $ this ->db ->getQueryBuilder ();
80111 $ query ->select ('* ' )
81112 ->from ('share_external ' )
82113 ->where ($ query ->expr ()->eq ('share_token ' , $ query ->createNamedParameter ($ token )))
83- ->andWhere ($ query ->expr ()->eq ('user ' , $ query ->createNamedParameter ($ user ->getUID ())));
114+ ->andWhere ($ query ->expr ()->eq ('user ' , $ query ->createNamedParameter ($ user ->getUID ())))
115+ ->andWhere ($ query ->expr ()->eq ('owner ' , $ query ->createNamedParameter ($ actorUser )));
84116
85117 $ result = $ query ->executeQuery ();
86118 $ share = $ result ->fetch ();
87119 $ result ->closeCursor ();
88120
89- if (!is_array ($ share ) || strpos ($ share ['mountpoint ' ], '{{TemporaryMountPointName# ' ) === 0 ) {
90- return new DataResponse ([], Http::STATUS_NOT_FOUND );
121+ if (!is_array ($ share ) || str_starts_with ($ share ['mountpoint ' ], '{{TemporaryMountPointName# ' )) {
122+ $ response = new DataResponse ([], Http::STATUS_NOT_FOUND );
123+ $ response ->throttle ();
124+ return $ response ;
91125 }
92126
93- $ internalType = $ this ->translateType ($ type );
94- if ($ internalType === '' ) {
95- return new DataResponse ([], Http::STATUS_BAD_REQUEST );
127+ $ normalizedActorServer = rtrim (strtolower (preg_replace ('/^https?:\/\// ' , '' , $ actorServer )), '/ ' );
128+ $ normalizedShareRemote = rtrim (strtolower (preg_replace ('/^https?:\/\// ' , '' , $ share ['remote ' ])), '/ ' );
129+ if ($ normalizedActorServer !== $ normalizedShareRemote ) {
130+ return new DataResponse ([], Http::STATUS_FORBIDDEN );
96131 }
97132
98133 $ path2 = null ;
@@ -111,7 +146,6 @@ public function receiveActivity($token, array $to, array $actor, $type, $updated
111146 if (!isset ($ object ['type ' ], $ object ['name ' ]) || $ object ['type ' ] !== 'Document ' ) {
112147 return new DataResponse ([], Http::STATUS_BAD_REQUEST );
113148 }
114-
115149 $ path = $ share ['mountpoint ' ] . $ object ['name ' ];
116150 }
117151
@@ -124,10 +158,25 @@ public function receiveActivity($token, array $to, array $actor, $type, $updated
124158 try {
125159 $ node = $ userFolder ->get ($ path );
126160 $ fileId = $ node ->getId ();
127- } catch (NotFoundException $ e ) {
128- return new DataResponse ([], Http::STATUS_NOT_FOUND );
129- } catch (InvalidPathException $ e ) {
130- return new DataResponse ([], Http::STATUS_NOT_FOUND );
161+
162+ $ storage = $ node ->getStorage ();
163+ if (!$ storage ->instanceOfStorage (ExternalStorage::class)) {
164+ $ response = new DataResponse ([], Http::STATUS_FORBIDDEN );
165+ $ response ->throttle ();
166+ return $ response ;
167+ }
168+ while ($ storage instanceof Wrapper) {
169+ $ storage = $ storage ->getWrapperStorage ();
170+ }
171+ if (!($ storage instanceof ExternalStorage) || $ storage ->getToken () !== $ token ) {
172+ $ response = new DataResponse ([], Http::STATUS_FORBIDDEN );
173+ $ response ->throttle ();
174+ return $ response ;
175+ }
176+ } catch (NotFoundException |InvalidPathException ) {
177+ $ response = new DataResponse ([], Http::STATUS_NOT_FOUND );
178+ $ response ->throttle ();
179+ return $ response ;
131180 }
132181
133182 if ($ path2 !== null ) {
@@ -136,8 +185,7 @@ public function receiveActivity($token, array $to, array $actor, $type, $updated
136185 try {
137186 $ parent = $ node ->getParent ();
138187 $ secondPath = [$ parent ->getId () => dirname ($ path2 )];
139- } catch (NotFoundException $ e ) {
140- } catch (InvalidPathException $ e ) {
188+ } catch (NotFoundException |InvalidPathException ) {
141189 }
142190 }
143191 $ subjectParams = [$ secondPath , $ actor ['name ' ], [$ fileId => $ path ]];
@@ -153,11 +201,11 @@ public function receiveActivity($token, array $to, array $actor, $type, $updated
153201 ->setAuthor ($ actor ['name ' ])
154202 ->setObject ('files ' , $ fileId , $ path )
155203 ->setSubject ($ subject , $ subjectParams )
156- ->setTimestamp ($ time );
204+ ->setTimestamp ($ date -> getTimestamp () );
157205 $ this ->activityManager ->publish ($ event );
158- } catch (\InvalidArgumentException $ e ) {
206+ } catch (\InvalidArgumentException ) {
159207 return new DataResponse (['activity ' ], Http::STATUS_BAD_REQUEST );
160- } catch (\BadMethodCallException $ e ) {
208+ } catch (\BadMethodCallException ) {
161209 return new DataResponse (['sending ' ], Http::STATUS_BAD_REQUEST );
162210 }
163211
0 commit comments