From 543e556cfec6514adc5127abbdd947bb96abe7a6 Mon Sep 17 00:00:00 2001 From: Amit Mishra Date: Sat, 27 Jun 2026 21:02:44 +0530 Subject: [PATCH] fix(files_sharing): reject custom share tokens longer than the database column validateToken() only checked for an empty string and an invalid character set, not length. A custom share token longer than 32 characters passes validation, then fails at the database layer (oc_share.token is varchar(32)) with a raw SQL exception instead of a clear validation error. Add a max-length check matching the column size, and mention the limit in the existing error message. Assisted-by: ClaudeCode:claude-sonnet-4-6 Signed-off-by: Amit Mishra --- .../lib/Controller/ShareAPIController.php | 7 +++++-- .../tests/Controller/ShareAPIControllerTest.php | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index ec7b0c51515c0..b19da4d96a443 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -77,6 +77,9 @@ */ class ShareAPIController extends OCSController { + /** Maximum length of a custom share token, matching the oc_share.token database column. */ + private const TOKEN_MAX_LENGTH = 32; + private ?Node $lockedNode = null; /** @var array $trustedServerCache */ private array $trustedServerCache = []; @@ -1363,7 +1366,7 @@ public function updateShare( throw new OCSForbiddenException($this->l->t('Custom share link tokens have been disabled by the administrator')); } if (!$this->validateToken($token)) { - throw new OCSBadRequestException($this->l->t('Tokens must contain at least 1 character and may only contain letters, numbers, or a hyphen')); + throw new OCSBadRequestException($this->l->t('Tokens must be between 1 and %s characters long and may only contain letters, numbers, or a hyphen', [self::TOKEN_MAX_LENGTH])); } $share->setToken($token); } @@ -1402,7 +1405,7 @@ public function updateShare( } private function validateToken(string $token): bool { - if (mb_strlen($token) === 0) { + if (mb_strlen($token) === 0 || mb_strlen($token) > self::TOKEN_MAX_LENGTH) { return false; } if (!preg_match('/^[a-z0-9-]+$/i', $token)) { diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php index 55cf24d79d788..8a88d66fc190a 100644 --- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -5604,6 +5604,22 @@ public function testWrapperStorageUnwrapped(): void { $this->invokePrivate($ocs, 'checkInheritedAttributes', [$share]); } + public static function dataValidateToken(): array { + return [ + 'empty token' => ['', false], + 'single character' => ['a', true], + 'letters numbers and hyphen' => ['abc-123', true], + 'invalid character' => ['abc_123', false], + '32 characters (oc_share.token column limit)' => [str_repeat('a', 32), true], + '33 characters (exceeds oc_share.token column limit)' => [str_repeat('a', 33), false], + ]; + } + + #[DataProvider('dataValidateToken')] + public function testValidateToken(string $token, bool $expected): void { + $this->assertSame($expected, $this->invokePrivate($this->ocs, 'validateToken', [$token])); + } + /** * Helper to allow testing Talk integration even if Talk * is not available during tests.