aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/files_sharing/lib/Controller/ShareAPIController.php24
-rw-r--r--lib/private/Share20/Manager.php76
-rw-r--r--lib/public/Share/Exceptions/ShareTokenException.php16
-rw-r--r--lib/public/Share/IManager.php9
4 files changed, 90 insertions, 35 deletions
diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php
index 57022f7ea1c..b00c97f0dd3 100644
--- a/apps/files_sharing/lib/Controller/ShareAPIController.php
+++ b/apps/files_sharing/lib/Controller/ShareAPIController.php
@@ -21,6 +21,7 @@ use OCA\Files_Sharing\SharedStorage;
use OCA\GlobalSiteSelector\Service\SlaveService;
use OCP\App\IAppManager;
use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\Attribute\ApiRoute;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\UserRateLimit;
use OCP\AppFramework\Http\DataResponse;
@@ -52,6 +53,7 @@ use OCP\Lock\LockedException;
use OCP\Mail\IMailer;
use OCP\Server;
use OCP\Share\Exceptions\ShareNotFound;
+use OCP\Share\Exceptions\ShareTokenException;
use OCP\Share\IManager;
use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
@@ -2172,4 +2174,26 @@ class ShareAPIController extends OCSController {
throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
}
}
+
+ /**
+ * Get a unique share token
+ *
+ * @throws OCSException Failed to generate a unique token
+ *
+ * @return DataResponse<Http::STATUS_OK, array{token: string}, array{}>
+ *
+ * 200: Token generated successfully
+ */
+ #[ApiRoute(verb: 'GET', url: '/api/v1/token')]
+ #[NoAdminRequired]
+ public function generateToken(): DataResponse {
+ try {
+ $token = $this->shareManager->generateToken();
+ return new DataResponse([
+ 'token' => $token,
+ ]);
+ } catch (ShareTokenException $e) {
+ throw new OCSException($this->l->t('Failed to generate a unique token'));
+ }
+ }
}
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index 219f3d86380..4138819f6b1 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -43,6 +43,7 @@ use OCP\Share\Events\ShareDeletedFromSelfEvent;
use OCP\Share\Exceptions\AlreadySharedException;
use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\Exceptions\ShareNotFound;
+use OCP\Share\Exceptions\ShareTokenException;
use OCP\Share\IManager;
use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
@@ -659,41 +660,7 @@ class Manager implements IManager {
$this->linkCreateChecks($share);
$this->setLinkParent($share);
- // Initial token length
- $tokenLength = \OC\Share\Helper::getTokenLength();
-
- do {
- $tokenExists = false;
-
- for ($i = 0; $i <= 2; $i++) {
- // Generate a new token
- $token = $this->secureRandom->generate(
- $tokenLength,
- \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
- );
-
- try {
- // Try to fetch a share with the generated token
- $this->getShareByToken($token);
- $tokenExists = true; // Token exists, we need to try again
- } catch (\OCP\Share\Exceptions\ShareNotFound $e) {
- // Token is unique, exit the loop
- $tokenExists = false;
- break;
- }
- }
-
- // If we've reached the maximum attempts and the token still exists, increase the token length
- if ($tokenExists) {
- $tokenLength++;
-
- // Check if the token length exceeds the maximum allowed length
- if ($tokenLength > \OC\Share\Constants::MAX_TOKEN_LENGTH) {
- throw new \Exception('Unable to generate a unique share token. Maximum token length exceeded.');
- }
- }
- } while ($tokenExists);
-
+ $token = $this->generateToken();
// Set the unique token
$share->setToken($token);
@@ -2025,4 +1992,43 @@ class Manager implements IManager {
yield from $provider->getAllShares();
}
}
+
+ public function generateToken(): string {
+ // Initial token length
+ $tokenLength = \OC\Share\Helper::getTokenLength();
+
+ do {
+ $tokenExists = false;
+
+ for ($i = 0; $i <= 2; $i++) {
+ // Generate a new token
+ $token = $this->secureRandom->generate(
+ $tokenLength,
+ ISecureRandom::CHAR_HUMAN_READABLE,
+ );
+
+ try {
+ // Try to fetch a share with the generated token
+ $this->getShareByToken($token);
+ $tokenExists = true; // Token exists, we need to try again
+ } catch (ShareNotFound $e) {
+ // Token is unique, exit the loop
+ $tokenExists = false;
+ break;
+ }
+ }
+
+ // If we've reached the maximum attempts and the token still exists, increase the token length
+ if ($tokenExists) {
+ $tokenLength++;
+
+ // Check if the token length exceeds the maximum allowed length
+ if ($tokenLength > \OC\Share\Constants::MAX_TOKEN_LENGTH) {
+ throw new ShareTokenException('Unable to generate a unique share token. Maximum token length exceeded.');
+ }
+ }
+ } while ($tokenExists);
+
+ return $token;
+ }
}
diff --git a/lib/public/Share/Exceptions/ShareTokenException.php b/lib/public/Share/Exceptions/ShareTokenException.php
new file mode 100644
index 00000000000..027d00640e9
--- /dev/null
+++ b/lib/public/Share/Exceptions/ShareTokenException.php
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCP\Share\Exceptions;
+
+use Exception;
+
+/**
+ * @since 31.0.0
+ */
+class ShareTokenException extends Exception {
+}
diff --git a/lib/public/Share/IManager.php b/lib/public/Share/IManager.php
index c3a8494a5ac..85b421c04f6 100644
--- a/lib/public/Share/IManager.php
+++ b/lib/public/Share/IManager.php
@@ -13,6 +13,7 @@ use OCP\Files\Node;
use OCP\IUser;
use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\Exceptions\ShareNotFound;
+use OCP\Share\Exceptions\ShareTokenException;
/**
* This interface allows to manage sharing files between users and groups.
@@ -522,4 +523,12 @@ interface IManager {
* @since 18.0.0
*/
public function getAllShares(): iterable;
+
+ /**
+ * Generate a unique share token
+ *
+ * @throws ShareTokenException Failed to generate a unique token
+ * @since 31.0.0
+ */
+ public function generateToken(): string;
}