From 9ff15ad4f4e7922c0f4bffa9018488cb21010a5c Mon Sep 17 00:00:00 2001 From: Daniel Kesselberg Date: Thu, 25 Sep 2025 14:05:56 +0200 Subject: [PATCH] fix: validate filename when creating file from template Signed-off-by: Daniel Kesselberg --- .../Files/Template/TemplateManager.php | 8 +- .../Files/Template/TemplateManagerTest.php | 104 ++++++++++++++++++ 2 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 tests/lib/Files/Template/TemplateManagerTest.php diff --git a/lib/private/Files/Template/TemplateManager.php b/lib/private/Files/Template/TemplateManager.php index 7c1636338ef5e..0f29a8ab1a2c0 100644 --- a/lib/private/Files/Template/TemplateManager.php +++ b/lib/private/Files/Template/TemplateManager.php @@ -15,6 +15,7 @@ use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\GenericFileException; +use OCP\Files\IFilenameValidator; use OCP\Files\IRootFolder; use OCP\Files\Node; use OCP\Files\NotFoundException; @@ -63,7 +64,8 @@ public function __construct( IPreview $previewManager, IConfig $config, IFactory $l10nFactory, - LoggerInterface $logger + LoggerInterface $logger, + private IFilenameValidator $filenameValidator, ) { $this->serverContainer = $serverContainer; $this->eventDispatcher = $eventDispatcher; @@ -157,7 +159,9 @@ public function createFromTemplate(string $filePath, string $templateId = '', st } } - $targetFile = $folder->newFile(basename($filePath), ($template instanceof File ? $template->fopen('rb') : null)); + $filename = basename($filePath); + $this->filenameValidator->validateFilename($filename); + $targetFile = $folder->newFile($filename, ($template instanceof File ? $template->fopen('rb') : null)); $this->eventDispatcher->dispatchTyped(new FileCreatedFromTemplateEvent($template, $targetFile, $templateFields)); return $this->formatFile($userFolder->get($filePath)); diff --git a/tests/lib/Files/Template/TemplateManagerTest.php b/tests/lib/Files/Template/TemplateManagerTest.php new file mode 100644 index 0000000000000..fcd7ca1aa92a8 --- /dev/null +++ b/tests/lib/Files/Template/TemplateManagerTest.php @@ -0,0 +1,104 @@ +createMock(IL10N::class); + $l10n->method('t') + ->willReturnCallback(fn ($string, $params) => sprintf($string, ...$params)); + $l10nFactory = $this->createMock(IFactory::class); + $l10nFactory->method('get') + ->willReturn($l10n); + $database = $this->createMock(IDBConnection::class); + $database->method('supports4ByteText')->willReturn(true); + $config = $this->createMock(IConfig::class); + $logger = new NullLogger(); + + $filenameValidator = new FilenameValidator( + $l10nFactory, + $database, + $config, + $logger, + ); + + $serverContainer = $this->createMock(\OCP\IServerContainer::class); + $eventDispatcher = $this->createMock(\OCP\EventDispatcher\IEventDispatcher::class); + $this->bootstrapCoordinator = $this->createMock(Coordinator::class); + $this->bootstrapCoordinator->method('getRegistrationContext') + ->willReturn(new RegistrationContext($logger)); + $this->rootFolder = $this->createMock(IRootFolder::class); + $userSession = $this->createMock(\OCP\IUserSession::class); + $userManager = $this->createMock(\OCP\IUserManager::class); + $previewManager = $this->createMock(IPreview::class); + + $this->templateManager = new TemplateManager( + $serverContainer, + $eventDispatcher, + $this->bootstrapCoordinator, + $this->rootFolder, + $userSession, + $userManager, + $previewManager, + $config, + $l10nFactory, + $logger, + $filenameValidator + ); + } + + public function testCreateFromTemplateShoudValidateFilename(): void { + $this->expectException(GenericFileException::class); + + $fileDirectory = '/'; + $filePath = $fileDirectory . str_repeat('a', 251); + + $userFolder = $this->createMock(Folder::class); + $userFolder->method('get') + ->willReturnCallback(function ($path) use ($filePath, $fileDirectory) { + if ($path === $filePath) { + throw new NotFoundException(); + } + return $this->createMock(Folder::class); + }); + $userFolder->method('nodeExists') + ->willReturnCallback(function ($path) use ($filePath, $fileDirectory) { + return $path === $fileDirectory; + }); + $this->rootFolder->method('getUserFolder') + ->willReturn($userFolder); + + $this->templateManager->createFromTemplate($filePath); + } +}