Skip to content

Commit a9a839c

Browse files
Merge pull request #51194 from nextcloud/refactor/tempmanager
refactor(TempManager): Simplify and unify implementations and remove legacy behavior
2 parents 705d730 + 8acfc0f commit a9a839c

File tree

4 files changed

+34
-87
lines changed

4 files changed

+34
-87
lines changed

build/psalm-baseline.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2517,12 +2517,6 @@
25172517
<code><![CDATA[$tag]]></code>
25182518
</MoreSpecificImplementedParamType>
25192519
</file>
2520-
<file src="lib/private/TempManager.php">
2521-
<FalsableReturnStatement>
2522-
<code><![CDATA[false]]></code>
2523-
<code><![CDATA[false]]></code>
2524-
</FalsableReturnStatement>
2525-
</file>
25262520
<file src="lib/private/Template/CSSResourceLocator.php">
25272521
<ParamNameMismatch>
25282522
<code><![CDATA[$style]]></code>

lib/private/TempManager.php

Lines changed: 21 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use bantu\IniGetWrapper\IniGetWrapper;
1111
use OCP\IConfig;
1212
use OCP\ITempManager;
13+
use OCP\Security\ISecureRandom;
1314
use Psr\Log\LoggerInterface;
1415

1516
class TempManager implements ITempManager {
@@ -34,51 +35,25 @@ public function __construct(LoggerInterface $logger, IConfig $config, IniGetWrap
3435
$this->tmpBaseDir = $this->getTempBaseDir();
3536
}
3637

37-
/**
38-
* Builds the filename with suffix and removes potential dangerous characters
39-
* such as directory separators.
40-
*
41-
* @param string $absolutePath Absolute path to the file / folder
42-
* @param string $postFix Postfix appended to the temporary file name, may be user controlled
43-
* @return string
44-
*/
45-
private function buildFileNameWithSuffix($absolutePath, $postFix = '') {
38+
private function generateTemporaryPath(string $postFix): string {
39+
$secureRandom = \OCP\Server::get(ISecureRandom::class);
40+
$absolutePath = $this->tmpBaseDir . '/' . self::TMP_PREFIX . $secureRandom->generate(32, ISecureRandom::CHAR_ALPHANUMERIC);
41+
4642
if ($postFix !== '') {
4743
$postFix = '.' . ltrim($postFix, '.');
4844
$postFix = str_replace(['\\', '/'], '', $postFix);
49-
$absolutePath .= '-';
5045
}
5146

5247
return $absolutePath . $postFix;
5348
}
5449

55-
/**
56-
* Create a temporary file and return the path
57-
*
58-
* @param string $postFix Postfix appended to the temporary file name
59-
* @return string
60-
*/
61-
public function getTemporaryFile($postFix = '') {
62-
if (is_writable($this->tmpBaseDir)) {
63-
// To create an unique file and prevent the risk of race conditions
64-
// or duplicated temporary files by other means such as collisions
65-
// we need to create the file using `tempnam` and append a possible
66-
// postfix to it later
67-
$file = tempnam($this->tmpBaseDir, self::TMP_PREFIX);
68-
$this->current[] = $file;
50+
public function getTemporaryFile($postFix = ''): string|false {
51+
$path = $this->generateTemporaryPath($postFix);
6952

70-
// If a postfix got specified sanitize it and create a postfixed
71-
// temporary file
72-
if ($postFix !== '') {
73-
$fileNameWithPostfix = $this->buildFileNameWithSuffix($file, $postFix);
74-
touch($fileNameWithPostfix);
75-
chmod($fileNameWithPostfix, 0600);
76-
$this->current[] = $fileNameWithPostfix;
77-
return $fileNameWithPostfix;
78-
}
79-
80-
return $file;
81-
} else {
53+
$old_umask = umask(0077);
54+
$fp = fopen($path, 'x');
55+
umask($old_umask);
56+
if ($fp === false) {
8257
$this->log->warning(
8358
'Can not create a temporary file in directory {dir}. Check it exists and has correct permissions',
8459
[
@@ -87,30 +62,16 @@ public function getTemporaryFile($postFix = '') {
8762
);
8863
return false;
8964
}
90-
}
9165

92-
/**
93-
* Create a temporary folder and return the path
94-
*
95-
* @param string $postFix Postfix appended to the temporary folder name
96-
* @return string
97-
*/
98-
public function getTemporaryFolder($postFix = '') {
99-
if (is_writable($this->tmpBaseDir)) {
100-
// To create an unique directory and prevent the risk of race conditions
101-
// or duplicated temporary files by other means such as collisions
102-
// we need to create the file using `tempnam` and append a possible
103-
// postfix to it later
104-
$uniqueFileName = tempnam($this->tmpBaseDir, self::TMP_PREFIX);
105-
$this->current[] = $uniqueFileName;
66+
fclose($fp);
67+
$this->current[] = $path;
68+
return $path;
69+
}
10670

107-
// Build a name without postfix
108-
$path = $this->buildFileNameWithSuffix($uniqueFileName . '-folder', $postFix);
109-
mkdir($path, 0700);
110-
$this->current[] = $path;
71+
public function getTemporaryFolder($postFix = ''): string|false {
72+
$path = $this->generateTemporaryPath($postFix) . '/';
11173

112-
return $path . '/';
113-
} else {
74+
if (mkdir($path, 0700) === false) {
11475
$this->log->warning(
11576
'Can not create a temporary folder in directory {dir}. Check it exists and has correct permissions',
11677
[
@@ -119,6 +80,9 @@ public function getTemporaryFolder($postFix = '') {
11980
);
12081
return false;
12182
}
83+
84+
$this->current[] = $path;
85+
return $path;
12286
}
12387

12488
/**

lib/public/ITempManager.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@ interface ITempManager {
1616
/**
1717
* Create a temporary file and return the path
1818
*
19-
* @param string $postFix
20-
* @return string
19+
* @param string $postFix Postfix appended to the temporary file name
20+
*
2121
* @since 8.0.0
2222
*/
23-
public function getTemporaryFile($postFix = '');
23+
public function getTemporaryFile(string $postFix = ''): string|false;
2424

2525
/**
2626
* Create a temporary folder and return the path
2727
*
28-
* @param string $postFix
29-
* @return string
28+
* @param string $postFix Postfix appended to the temporary folder name
29+
*
3030
* @since 8.0.0
3131
*/
32-
public function getTemporaryFolder($postFix = '');
32+
public function getTemporaryFolder(string $postFix = ''): string|false;
3333

3434
/**
3535
* Remove the temporary files and folders generated during this request

tests/lib/TempManagerTest.php

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -154,34 +154,23 @@ public function testLogCantCreateFolder(): void {
154154
$this->assertFalse($manager->getTemporaryFolder());
155155
}
156156

157-
public function testBuildFileNameWithPostfix(): void {
157+
public function testGenerateTemporaryPathWithPostfix(): void {
158158
$logger = $this->createMock(LoggerInterface::class);
159159
$tmpManager = self::invokePrivate(
160160
$this->getManager($logger),
161-
'buildFileNameWithSuffix',
162-
['/tmp/myTemporaryFile', 'postfix']
161+
'generateTemporaryPath',
162+
['postfix']
163163
);
164164

165-
$this->assertEquals('/tmp/myTemporaryFile-.postfix', $tmpManager);
165+
$this->assertStringEndsWith('.postfix', $tmpManager);
166166
}
167167

168-
public function testBuildFileNameWithoutPostfix(): void {
168+
public function testGenerateTemporaryPathTraversal(): void {
169169
$logger = $this->createMock(LoggerInterface::class);
170170
$tmpManager = self::invokePrivate(
171171
$this->getManager($logger),
172-
'buildFileNameWithSuffix',
173-
['/tmp/myTemporaryFile', '']
174-
);
175-
176-
$this->assertEquals('/tmp/myTemporaryFile', $tmpManager);
177-
}
178-
179-
public function testBuildFileNameWithSuffixPathTraversal(): void {
180-
$logger = $this->createMock(LoggerInterface::class);
181-
$tmpManager = self::invokePrivate(
182-
$this->getManager($logger),
183-
'buildFileNameWithSuffix',
184-
['foo', '../Traversal\\../FileName']
172+
'generateTemporaryPath',
173+
['../Traversal\\../FileName']
185174
);
186175

187176
$this->assertStringEndsNotWith('./Traversal\\../FileName', $tmpManager);

0 commit comments

Comments
 (0)