Skip to content

Commit c47506c

Browse files
benjaminfruehbackportbot[bot]
authored andcommitted
chore: improve placeholder substitution
chore: improve placeholder substitution Signed-off-by: Benjamin Frueh <benjamin.frueh@gmail.com> [skip ci]
1 parent a212cc0 commit c47506c

3 files changed

Lines changed: 40 additions & 21 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ When defining the script, you can specify one of the following placeholders that
3030

3131
When no placeholder was specified, then the exact command as given is being executed.
3232

33+
### Security
34+
Do not wrap placeholders in quotes, as they are already quoted by the app. Wrapping them in quotes can neutralize this and may allow command execution via filenames. Files containing `$(` or `` ` `` in their filename will be skipped.
35+
3336
### Hints
3437

3538
Events for files and folders are triggered by file system operations. An operation like

lib/BackgroundJobs/Launcher.php

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace OCA\WorkflowScript\BackgroundJobs;
99

1010
use Exception;
11+
use InvalidArgumentException;
1112
use OC\Files\View;
1213
use OCA\WorkflowScript\AppInfo\Application;
1314
use OCP\AppFramework\Utility\ITimeFactory;
@@ -31,16 +32,14 @@ protected function run($argument): void {
3132
if (strpos($command, '%f')) {
3233
$path = isset($argument['path']) ? (string)$argument['path'] : '';
3334
try {
34-
$view = new View(dirname($path));
35-
$tmpFile = $view->toTmpFile(basename($path));
35+
$command = str_replace('%f', escapeshellarg($this->resolveLocalPath($path)), $command);
3636
} catch (Exception $e) {
3737
$this->logger->warning($e->getMessage(), [
3838
'app' => Application::APPID,
3939
'exception' => $e
4040
]);
4141
return;
4242
}
43-
$command = str_replace('%f', escapeshellarg($tmpFile), $command);
4443
}
4544

4645
// with wrapping sh around the command, we leave any redirects intact,
@@ -52,4 +51,24 @@ protected function run($argument): void {
5251
);
5352
shell_exec($wrapper);
5453
}
54+
55+
/**
56+
* @throws InvalidArgumentException
57+
*/
58+
private function resolveLocalPath(string $path): string {
59+
try {
60+
$view = new View();
61+
$localFile = $view->getLocalFile($path);
62+
if ($localFile !== false && file_exists($localFile)) {
63+
return $localFile;
64+
}
65+
$tmpFile = $view->toTmpFile($path);
66+
if ($tmpFile === false) {
67+
throw new InvalidArgumentException();
68+
}
69+
return $tmpFile;
70+
} catch (Exception) {
71+
throw new InvalidArgumentException('Could not resolve local path for: ' . $path);
72+
}
73+
}
5574
}

lib/Operation.php

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77

88
namespace OCA\WorkflowScript;
99

10-
use Exception;
11-
use InvalidArgumentException;
12-
use OC\Files\View;
1310
use OC\User\NoUserException;
1411
use OCA\Files_Sharing\SharedStorage;
1512
use OCA\GroupFolders\Mount\GroupFolderStorage;
@@ -134,6 +131,21 @@ public function onEvent(string $eventName, Event $event, IRuleMatcher $ruleMatch
134131
}
135132

136133
$matches = $ruleMatcher->getFlows(false);
134+
if (empty($matches)) {
135+
return;
136+
}
137+
138+
if (preg_match('/\$\(|`/', $node->getName())) {
139+
$this->logger->warning(
140+
'Potentially dangerous characters in filename, skipping workflow',
141+
[
142+
'app' => Application::APPID,
143+
'file' => $node->getPath(),
144+
]
145+
);
146+
return;
147+
}
148+
137149
foreach ($matches as $match) {
138150
try {
139151
$command = $this->buildCommand($match['operation'], $node, $eventName, $extra);
@@ -177,21 +189,6 @@ protected function buildCommand(string $template, Node $node, string $event, arr
177189
unset($ncRelPath);
178190
}
179191

180-
if (strpos($command, '%f')) {
181-
try {
182-
$view = new View();
183-
if ($node instanceof FileNode) {
184-
$fullPath = $view->getLocalFile($node->getPath());
185-
}
186-
if (!isset($fullPath) || $fullPath === false) {
187-
throw new InvalidArgumentException();
188-
}
189-
$command = str_replace('%f', escapeshellarg($fullPath), $command);
190-
} catch (Exception) {
191-
throw new InvalidArgumentException('Could not determine full path');
192-
}
193-
}
194-
195192
if (strpos($command, '%i')) {
196193
$nodeID = -1;
197194
try {

0 commit comments

Comments
 (0)