@@ -204,17 +204,21 @@ public function newShare(int $formId, int $shareType, string $shareWith = '', ar
204204 }
205205
206206 /**
207- * Update permissions of a share
207+ * Update properties of a share
208208 *
209209 * @param int $formId of the form
210210 * @param int $shareId of the share to update
211211 * @param array<string, mixed> $keyValuePairs Array of key=>value pairs to update.
212212 * @return DataResponse<Http::STATUS_OK, int, array{}>
213213 * @throws OCSBadRequestException Share doesn't belong to given Form
214214 * @throws OCSBadRequestException Invalid permission given
215+ * @throws OCSBadRequestException Invalid share token
216+ * @throws OCSBadRequestException Share hash exists, please retry
217+ * @throws OCSForbiddenException Custom public share tokens are not allowed
215218 * @throws OCSForbiddenException This form is not owned by the current user
216219 * @throws OCSForbiddenException Empty keyValuePairs, will not update
217- * @throws OCSForbiddenException Not allowed to update other properties than permissions
220+ * @throws OCSForbiddenException Not allowed to update token on non-link share
221+ * @throws OCSForbiddenException Not allowed to update unknown properties
218222 * @throws OCSNotFoundException Could not find share
219223 *
220224 * 200: the id of the updated share
@@ -223,7 +227,7 @@ public function newShare(int $formId, int $shareType, string $shareWith = '', ar
223227 #[NoAdminRequired()]
224228 #[ApiRoute(verb: 'PATCH ' , url: '/api/v3/forms/{formId}/shares/{shareId} ' )]
225229 public function updateShare (int $ formId , int $ shareId , array $ keyValuePairs ): DataResponse {
226- $ this ->logger ->debug ('Updating share: {shareId} of form {formId}, permissions : {permissions } ' , [
230+ $ this ->logger ->debug ('Updating share: {shareId} of form {formId}, values : {keyValuePairs } ' , [
227231 'formId ' => $ formId ,
228232 'shareId ' => $ shareId ,
229233 'keyValuePairs ' => $ keyValuePairs
@@ -253,22 +257,64 @@ public function updateShare(int $formId, int $shareId, array $keyValuePairs): Da
253257 throw new OCSForbiddenException ('Empty keyValuePairs, will not update ' );
254258 }
255259
256- //Don't allow to change other properties than permissions
257- if (count ($ keyValuePairs ) > 1 || !array_key_exists ('permissions ' , $ keyValuePairs )) {
258- $ this ->logger ->debug ('Not allowed to update other properties than permissions ' );
259- throw new OCSForbiddenException ('Not allowed to update other properties than permissions ' );
260+ $ allowedKeys = ['permissions ' , 'token ' ];
261+ foreach (array_keys ($ keyValuePairs ) as $ key ) {
262+ if (!in_array ($ key , $ allowedKeys , true )) {
263+ $ this ->logger ->debug ('Not allowed to update other properties than permissions or token ' );
264+ throw new OCSForbiddenException ('Not allowed to update other properties than permissions or token ' );
265+ }
260266 }
261267
262- if (!$ this ->validatePermissions ($ keyValuePairs ['permissions ' ], $ formShare ->getShareType ())) {
268+ if (array_key_exists ( ' permissions ' , $ keyValuePairs ) && !$ this ->validatePermissions ($ keyValuePairs ['permissions ' ], $ formShare ->getShareType ())) {
263269 throw new OCSBadRequestException ('Invalid permission given ' );
264270 }
265271
272+ if (array_key_exists ('token ' , $ keyValuePairs )) {
273+ if (!$ this ->configService ->getAllowCustomPublicToken ()) {
274+ $ this ->logger ->debug ('Custom public share tokens are not allowed. ' );
275+ throw new OCSForbiddenException ('Custom public share tokens are not allowed. ' );
276+ }
277+
278+ if ($ formShare ->getShareType () !== IShare::TYPE_LINK ) {
279+ $ this ->logger ->debug ('Not allowed to update token on non-link share ' );
280+ throw new OCSForbiddenException ('Not allowed to update token on non-link share ' );
281+ }
282+
283+ if (!is_string ($ keyValuePairs ['token ' ])) {
284+ throw new OCSBadRequestException ('Invalid share token ' );
285+ }
286+
287+ $ token = $ keyValuePairs ['token ' ];
288+ if (!array_key_exists ('permissions ' , $ keyValuePairs ) && $ token === $ formShare ->getShareWith ()) {
289+ return new DataResponse ($ formShare ->getId ());
290+ }
291+
292+ if ($ token !== $ formShare ->getShareWith ()) {
293+ $ this ->validatePublicShareToken ($ token );
294+
295+ try {
296+ $ existingShare = $ this ->shareMapper ->findPublicShareByHash ($ token );
297+ if ($ existingShare ->getId () !== $ formShare ->getId ()) {
298+ $ this ->logger ->debug ('Share hash already exists. ' );
299+ throw new OCSBadRequestException ('Share hash exists, please retry. ' );
300+ }
301+ } catch (DoesNotExistException $ e ) {
302+ // Just continue, this is what we expect to happen (share hash not existing yet).
303+ }
304+
305+ $ formShare ->setShareWith ($ token );
306+ }
307+ }
308+
266309 $ this ->formsService ->obtainFormLock ($ form );
267310
268- $ formShare ->setPermissions ($ keyValuePairs ['permissions ' ]);
311+ if (array_key_exists ('permissions ' , $ keyValuePairs )) {
312+ $ formShare ->setPermissions ($ keyValuePairs ['permissions ' ]);
313+ }
269314 $ formShare = $ this ->shareMapper ->update ($ formShare );
270315
271- if (in_array ($ formShare ->getShareType (), [IShare::TYPE_USER , IShare::TYPE_GROUP , IShare::TYPE_USERGROUP , IShare::TYPE_CIRCLE ], true )) {
316+ if (array_key_exists ('permissions ' , $ keyValuePairs )
317+ && in_array ($ formShare ->getShareType (), [IShare::TYPE_USER , IShare::TYPE_GROUP , IShare::TYPE_USERGROUP , IShare::TYPE_CIRCLE ], true )) {
272318 if (in_array (Constants::PERMISSION_RESULTS , $ keyValuePairs ['permissions ' ], true )) {
273319 $ userFolder = $ this ->rootFolder ->getUserFolder ($ form ->getOwnerId ());
274320 $ uploadedFilesFolderPath = $ this ->filePathHelper ->getFormUploadedFilesFolderPath ($ form );
@@ -418,4 +464,22 @@ private function validatePermissions(array $permissions, int $shareType): bool {
418464 }
419465 return true ;
420466 }
467+
468+ /**
469+ * @throws OCSBadRequestException If token does not satisfy basic safety checks
470+ */
471+ private function validatePublicShareToken (string $ token ): void {
472+ if ($ token !== trim ($ token )) {
473+ throw new OCSBadRequestException ('Invalid share token ' );
474+ }
475+
476+ $ tokenLength = strlen ($ token );
477+ if ($ tokenLength < Constants::PUBLIC_SHARE_TOKEN_MIN_LENGTH || $ tokenLength > Constants::PUBLIC_SHARE_TOKEN_MAX_LENGTH ) {
478+ throw new OCSBadRequestException ('Invalid share token ' );
479+ }
480+
481+ if (preg_match ('/^[a-zA-Z0-9]+$/ ' , $ token ) !== 1 ) {
482+ throw new OCSBadRequestException ('Invalid share token ' );
483+ }
484+ }
421485}
0 commit comments