From 03f9bbf8023c41d889b38eab2109f26658666213 Mon Sep 17 00:00:00 2001 From: Luka Trovic Date: Mon, 6 Apr 2026 16:17:17 +0200 Subject: [PATCH] fix: update URL validation for text-link column Signed-off-by: Luka Trovic --- lib/Service/ColumnTypes/TextLinkBusiness.php | 25 +++++++++++++++++++ .../ColumnTypes/TextLinkBusinessTest.php | 25 ++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/Service/ColumnTypes/TextLinkBusiness.php b/lib/Service/ColumnTypes/TextLinkBusiness.php index c5cfd86578..1110533606 100644 --- a/lib/Service/ColumnTypes/TextLinkBusiness.php +++ b/lib/Service/ColumnTypes/TextLinkBusiness.php @@ -8,9 +8,19 @@ namespace OCA\Tables\Service\ColumnTypes; use OCA\Tables\Db\Column; +use OCA\Tables\Errors\BadRequestError; +use OCP\IL10N; +use Psr\Log\LoggerInterface; class TextLinkBusiness extends SuperBusiness { + public function __construct( + LoggerInterface $logger, + private IL10N $n, + ) { + parent::__construct($logger); + } + /** * @param mixed $value (string|null) * @param Column $column @@ -96,4 +106,19 @@ public function canBeParsed($value, Column $column): bool { preg_match('/(http|https)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/', $value, $matches); return !empty($matches); } + + public function validateValue(mixed $value, Column $column, string $userId, int $tableId, ?int $rowId): void { + $data = json_decode($value, true); + + // Only allow URLs that start with http or https + if (isset($data['value']) && !preg_match('/(http|https)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/', $data['value'])) { + throw new BadRequestError( + 'Column "' . $column->getTitle() . '" contains an invalid protocol. Only http and https are allowed.', + translatedMessage: $this->n->t( + 'Column "%s" contains an invalid protocol. Only http and https are allowed.', + [$column->getTitle()] + ), + ); + } + } } diff --git a/tests/unit/Service/ColumnTypes/TextLinkBusinessTest.php b/tests/unit/Service/ColumnTypes/TextLinkBusinessTest.php index 7762d91dc1..7938388d92 100644 --- a/tests/unit/Service/ColumnTypes/TextLinkBusinessTest.php +++ b/tests/unit/Service/ColumnTypes/TextLinkBusinessTest.php @@ -8,6 +8,7 @@ namespace OCA\Tables\Service\ColumnTypes; use OCA\Tables\Db\Column; +use OCP\IL10N; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; @@ -18,7 +19,8 @@ class TextLinkBusinessTest extends TestCase { public function setUp(): void { $this->textLinkBusiness = new TextLinkBusiness( - $this->createMock(LoggerInterface::class) + $this->createMock(LoggerInterface::class), + $this->createMock(IL10N::class) ); $this->column = $this->createMock(Column::class); @@ -90,4 +92,25 @@ public function testParseValue() { 'providerId' => 'url', ]), $column)); } + + public function testValidateValue() { + // Assert that no exception is thrown for valid values + try { + $this->textLinkBusiness->validateValue(json_encode([ + 'title' => 'Test link', + 'value' => 'https://nextcloud.com', + 'providerId' => 'url', + ]), $this->column, 'userId', 1, null); + } catch (\Exception $e) { + $this->fail('validateValue threw an exception for valid input: ' . $e->getMessage()); + } + + // Assert that exception is thrown for invalid values + $this->expectException(\OCA\Tables\Errors\BadRequestError::class); + $this->textLinkBusiness->validateValue(json_encode([ + 'title' => 'Test link', + 'value' => 'invalidurl', + 'providerId' => 'url', + ]), $this->column, 'userId', 1, null); + } }