Skip to content

Commit

Permalink
feat(share): make sharelink token length configurable
Browse files Browse the repository at this point in the history
- ensure unique share token with dynamic length adjustment

Signed-off-by: ernolf <raphael.gradenwitz@googlemail.com>
  • Loading branch information
ernolf authored and nickvergessen committed Sep 28, 2024
1 parent e202b6c commit b4ea146
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 8 deletions.
5 changes: 4 additions & 1 deletion lib/private/Share/Constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions lib/private/Share/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,13 @@ public static function isSameUserOnSameServer($user1, $server1, $user2, $server2

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));
}
}
44 changes: 37 additions & 7 deletions lib/private/Share20/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -656,13 +656,43 @@ public function createShare(IShare $share) {
$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);
Expand Down

0 comments on commit b4ea146

Please sign in to comment.