Skip to content

Commit b4ea146

Browse files
ernolfnickvergessen
authored andcommitted
feat(share): make sharelink token length configurable
- ensure unique share token with dynamic length adjustment Signed-off-by: ernolf <raphael.gradenwitz@googlemail.com>
1 parent e202b6c commit b4ea146

3 files changed

Lines changed: 50 additions & 8 deletions

File tree

lib/private/Share/Constants.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ class Constants {
6363

6464
public const RESPONSE_FORMAT = 'json'; // default response format for ocs calls
6565

66-
public const TOKEN_LENGTH = 15; // old (oc7) length is 32, keep token length in db at least that for compatibility
66+
public const MIN_TOKEN_LENGTH = 6; // 19,770,609,664 different possible variations
67+
public const DEFAULT_TOKEN_LENGTH = 15; // 54,960,434,128,018,667,122,720,768 different possible variations
68+
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
69+
public const TOKEN_LENGTH = self::DEFAULT_TOKEN_LENGTH; // old (oc7) length is 32, keep token length in db at least that for compatibility
6770

6871
protected static $shareTypeUserAndGroups = -1;
6972
protected static $shareTypeGroupUserUnique = 2;

lib/private/Share/Helper.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,13 @@ public static function isSameUserOnSameServer($user1, $server1, $user2, $server2
126126

127127
return false;
128128
}
129+
130+
public static function getTokenLength(): int {
131+
$config = \OCP\Server::get(\OCP\IAppConfig::class);
132+
$tokenLength = $config->getValueInt('core', 'shareapi_token_length', self::DEFAULT_TOKEN_LENGTH);
133+
$tokenLength = $tokenLength ?: self::DEFAULT_TOKEN_LENGTH;
134+
135+
// Token length should be within the defined min and max limits
136+
return max(self::MIN_TOKEN_LENGTH, min($tokenLength, self::MAX_TOKEN_LENGTH));
137+
}
129138
}

lib/private/Share20/Manager.php

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -656,13 +656,43 @@ public function createShare(IShare $share) {
656656
$this->linkCreateChecks($share);
657657
$this->setLinkParent($share);
658658

659-
// For now ignore a set token.
660-
$share->setToken(
661-
$this->secureRandom->generate(
662-
\OC\Share\Constants::TOKEN_LENGTH,
663-
\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
664-
)
665-
);
659+
// Initial token length
660+
$tokenLength = \OC\Share\Helper::getTokenLength();
661+
662+
do {
663+
$tokenExists = false;
664+
665+
for ($i = 0; $i <= 2; $i++) {
666+
// Generate a new token
667+
$token = $this->secureRandom->generate(
668+
$tokenLength,
669+
\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
670+
);
671+
672+
try {
673+
// Try to fetch a share with the generated token
674+
$this->getShareByToken($token);
675+
$tokenExists = true; // Token exists, we need to try again
676+
} catch (\OCP\Share\Exceptions\ShareNotFound $e) {
677+
// Token is unique, exit the loop
678+
$tokenExists = false;
679+
break;
680+
}
681+
}
682+
683+
// If we've reached the maximum attempts and the token still exists, increase the token length
684+
if ($tokenExists) {
685+
$tokenLength++;
686+
687+
// Check if the token length exceeds the maximum allowed length
688+
if ($tokenLength > \OC\Share\Constants::MAX_TOKEN_LENGTH) {
689+
throw new \Exception('Unable to generate a unique share token. Maximum token length exceeded.');
690+
}
691+
}
692+
} while ($tokenExists);
693+
694+
// Set the unique token
695+
$share->setToken($token);
666696

667697
// Verify the expiration date
668698
$share = $this->validateExpirationDateLink($share);

0 commit comments

Comments
 (0)