diff --git a/lib/private/Share/Constants.php b/lib/private/Share/Constants.php index 8cfa83f9ea2..baff04fbc4a 100644 --- a/lib/private/Share/Constants.php +++ b/lib/private/Share/Constants.php @@ -63,7 +63,10 @@ class Constants { public const RESPONSE_FORMAT = 'json'; // default response format for ocs calls - public const TOKEN_LENGTH = 15; // old (oc7) length is 32, keep token length in db at least that for compatibility + public const MIN_TOKEN_LENGTH = 6; // 19,770,609,664 different possible variations + public const DEFAULT_TOKEN_LENGTH = 15; // 54,960,434,128,018,667,122,720,768 different possible variations + public const MAX_TOKEN_LENGTH = 32; // 8,167,835,760,036,914,488,254,418,108,462,708,901,695,678,621,570,564,096 different possible variations + public const TOKEN_LENGTH = self::DEFAULT_TOKEN_LENGTH; // old (oc7) length is 32, keep token length in db at least that for compatibility protected static $shareTypeUserAndGroups = -1; protected static $shareTypeGroupUserUnique = 2; diff --git a/lib/private/Share/Helper.php b/lib/private/Share/Helper.php index 76e7daeb9e5..d53f9d6ed94 100644 --- a/lib/private/Share/Helper.php +++ b/lib/private/Share/Helper.php @@ -126,4 +126,13 @@ class Helper extends \OC\Share\Constants { return false; } + + public static function getTokenLength(): int { + $config = \OCP\Server::get(\OCP\IAppConfig::class); + $tokenLength = $config->getValueInt('core', 'shareapi_token_length', self::DEFAULT_TOKEN_LENGTH); + $tokenLength = $tokenLength ?: self::DEFAULT_TOKEN_LENGTH; + + // Token length should be within the defined min and max limits + return max(self::MIN_TOKEN_LENGTH, min($tokenLength, self::MAX_TOKEN_LENGTH)); + } } diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 1477560c6fd..f46d163e58a 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -656,13 +656,43 @@ class Manager implements IManager { $this->linkCreateChecks($share); $this->setLinkParent($share); - // For now ignore a set token. - $share->setToken( - $this->secureRandom->generate( - \OC\Share\Constants::TOKEN_LENGTH, - \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE - ) - ); + // 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); + + // Set the unique token + $share->setToken($token); // Verify the expiration date $share = $this->validateExpirationDateLink($share);