refactor(TempManager): Simplify and unify implementations and remove legacy behavior

Signed-off-by: provokateurin <kate@provokateurin.de>
pull/51194/head
provokateurin 2 months ago
parent afae742a2b
commit 8acfc0f0f2
No known key found for this signature in database
  1. 6
      build/psalm-baseline.xml
  2. 78
      lib/private/TempManager.php
  3. 12
      lib/public/ITempManager.php
  4. 25
      tests/lib/TempManagerTest.php

@ -2517,12 +2517,6 @@
<code><![CDATA[$tag]]></code> <code><![CDATA[$tag]]></code>
</MoreSpecificImplementedParamType> </MoreSpecificImplementedParamType>
</file> </file>
<file src="lib/private/TempManager.php">
<FalsableReturnStatement>
<code><![CDATA[false]]></code>
<code><![CDATA[false]]></code>
</FalsableReturnStatement>
</file>
<file src="lib/private/Template/CSSResourceLocator.php"> <file src="lib/private/Template/CSSResourceLocator.php">
<ParamNameMismatch> <ParamNameMismatch>
<code><![CDATA[$style]]></code> <code><![CDATA[$style]]></code>

@ -10,6 +10,7 @@ namespace OC;
use bantu\IniGetWrapper\IniGetWrapper; use bantu\IniGetWrapper\IniGetWrapper;
use OCP\IConfig; use OCP\IConfig;
use OCP\ITempManager; use OCP\ITempManager;
use OCP\Security\ISecureRandom;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class TempManager implements ITempManager { class TempManager implements ITempManager {
@ -34,51 +35,25 @@ class TempManager implements ITempManager {
$this->tmpBaseDir = $this->getTempBaseDir(); $this->tmpBaseDir = $this->getTempBaseDir();
} }
/** private function generateTemporaryPath(string $postFix): string {
* Builds the filename with suffix and removes potential dangerous characters $secureRandom = \OCP\Server::get(ISecureRandom::class);
* such as directory separators. $absolutePath = $this->tmpBaseDir . '/' . self::TMP_PREFIX . $secureRandom->generate(32, ISecureRandom::CHAR_ALPHANUMERIC);
*
* @param string $absolutePath Absolute path to the file / folder
* @param string $postFix Postfix appended to the temporary file name, may be user controlled
* @return string
*/
private function buildFileNameWithSuffix($absolutePath, $postFix = '') {
if ($postFix !== '') { if ($postFix !== '') {
$postFix = '.' . ltrim($postFix, '.'); $postFix = '.' . ltrim($postFix, '.');
$postFix = str_replace(['\\', '/'], '', $postFix); $postFix = str_replace(['\\', '/'], '', $postFix);
$absolutePath .= '-';
} }
return $absolutePath . $postFix; return $absolutePath . $postFix;
} }
/** public function getTemporaryFile($postFix = ''): string|false {
* Create a temporary file and return the path $path = $this->generateTemporaryPath($postFix);
*
* @param string $postFix Postfix appended to the temporary file name
* @return string
*/
public function getTemporaryFile($postFix = '') {
if (is_writable($this->tmpBaseDir)) {
// To create an unique file and prevent the risk of race conditions
// or duplicated temporary files by other means such as collisions
// we need to create the file using `tempnam` and append a possible
// postfix to it later
$file = tempnam($this->tmpBaseDir, self::TMP_PREFIX);
$this->current[] = $file;
// If a postfix got specified sanitize it and create a postfixed $old_umask = umask(0077);
// temporary file $fp = fopen($path, 'x');
if ($postFix !== '') { umask($old_umask);
$fileNameWithPostfix = $this->buildFileNameWithSuffix($file, $postFix); if ($fp === false) {
touch($fileNameWithPostfix);
chmod($fileNameWithPostfix, 0600);
$this->current[] = $fileNameWithPostfix;
return $fileNameWithPostfix;
}
return $file;
} else {
$this->log->warning( $this->log->warning(
'Can not create a temporary file in directory {dir}. Check it exists and has correct permissions', 'Can not create a temporary file in directory {dir}. Check it exists and has correct permissions',
[ [
@ -87,30 +62,16 @@ class TempManager implements ITempManager {
); );
return false; return false;
} }
}
/** fclose($fp);
* Create a temporary folder and return the path $this->current[] = $path;
* return $path;
* @param string $postFix Postfix appended to the temporary folder name }
* @return string
*/
public function getTemporaryFolder($postFix = '') {
if (is_writable($this->tmpBaseDir)) {
// To create an unique directory and prevent the risk of race conditions
// or duplicated temporary files by other means such as collisions
// we need to create the file using `tempnam` and append a possible
// postfix to it later
$uniqueFileName = tempnam($this->tmpBaseDir, self::TMP_PREFIX);
$this->current[] = $uniqueFileName;
// Build a name without postfix public function getTemporaryFolder($postFix = ''): string|false {
$path = $this->buildFileNameWithSuffix($uniqueFileName . '-folder', $postFix); $path = $this->generateTemporaryPath($postFix) . '/';
mkdir($path, 0700);
$this->current[] = $path;
return $path . '/'; if (mkdir($path, 0700) === false) {
} else {
$this->log->warning( $this->log->warning(
'Can not create a temporary folder in directory {dir}. Check it exists and has correct permissions', 'Can not create a temporary folder in directory {dir}. Check it exists and has correct permissions',
[ [
@ -119,6 +80,9 @@ class TempManager implements ITempManager {
); );
return false; return false;
} }
$this->current[] = $path;
return $path;
} }
/** /**

@ -16,20 +16,20 @@ interface ITempManager {
/** /**
* Create a temporary file and return the path * Create a temporary file and return the path
* *
* @param string $postFix * @param string $postFix Postfix appended to the temporary file name
* @return string *
* @since 8.0.0 * @since 8.0.0
*/ */
public function getTemporaryFile($postFix = ''); public function getTemporaryFile(string $postFix = ''): string|false;
/** /**
* Create a temporary folder and return the path * Create a temporary folder and return the path
* *
* @param string $postFix * @param string $postFix Postfix appended to the temporary folder name
* @return string *
* @since 8.0.0 * @since 8.0.0
*/ */
public function getTemporaryFolder($postFix = ''); public function getTemporaryFolder(string $postFix = ''): string|false;
/** /**
* Remove the temporary files and folders generated during this request * Remove the temporary files and folders generated during this request

@ -154,34 +154,23 @@ class TempManagerTest extends \Test\TestCase {
$this->assertFalse($manager->getTemporaryFolder()); $this->assertFalse($manager->getTemporaryFolder());
} }
public function testBuildFileNameWithPostfix(): void { public function testGenerateTemporaryPathWithPostfix(): void {
$logger = $this->createMock(LoggerInterface::class); $logger = $this->createMock(LoggerInterface::class);
$tmpManager = self::invokePrivate( $tmpManager = self::invokePrivate(
$this->getManager($logger), $this->getManager($logger),
'buildFileNameWithSuffix', 'generateTemporaryPath',
['/tmp/myTemporaryFile', 'postfix'] ['postfix']
); );
$this->assertEquals('/tmp/myTemporaryFile-.postfix', $tmpManager); $this->assertStringEndsWith('.postfix', $tmpManager);
} }
public function testBuildFileNameWithoutPostfix(): void { public function testGenerateTemporaryPathTraversal(): void {
$logger = $this->createMock(LoggerInterface::class); $logger = $this->createMock(LoggerInterface::class);
$tmpManager = self::invokePrivate( $tmpManager = self::invokePrivate(
$this->getManager($logger), $this->getManager($logger),
'buildFileNameWithSuffix', 'generateTemporaryPath',
['/tmp/myTemporaryFile', ''] ['../Traversal\\../FileName']
);
$this->assertEquals('/tmp/myTemporaryFile', $tmpManager);
}
public function testBuildFileNameWithSuffixPathTraversal(): void {
$logger = $this->createMock(LoggerInterface::class);
$tmpManager = self::invokePrivate(
$this->getManager($logger),
'buildFileNameWithSuffix',
['foo', '../Traversal\\../FileName']
); );
$this->assertStringEndsNotWith('./Traversal\\../FileName', $tmpManager); $this->assertStringEndsNotWith('./Traversal\\../FileName', $tmpManager);

Loading…
Cancel
Save