Skip to content

Commit 04931cf

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 a99bfa2 commit 04931cf

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
@@ -24,6 +24,9 @@ When defining the script, you can specify one of the following placeholders that
2424

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

27+
### Security
28+
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.
29+
2730
### Hints
2831

2932
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
@@ -25,6 +25,7 @@
2525
namespace OCA\WorkflowScript\BackgroundJobs;
2626

2727
use Exception;
28+
use InvalidArgumentException;
2829
use OC\Files\View;
2930
use OCA\WorkflowScript\AppInfo\Application;
3031
use OCP\AppFramework\Utility\ITimeFactory;
@@ -48,16 +49,14 @@ protected function run($argument): void {
4849
if (strpos($command, '%f')) {
4950
$path = isset($argument['path']) ? (string)$argument['path'] : '';
5051
try {
51-
$view = new View(dirname($path));
52-
$tmpFile = $view->toTmpFile(basename($path));
52+
$command = str_replace('%f', escapeshellarg($this->resolveLocalPath($path)), $command);
5353
} catch (Exception $e) {
5454
$this->logger->warning($e->getMessage(), [
5555
'app' => Application::APPID,
5656
'exception' => $e
5757
]);
5858
return;
5959
}
60-
$command = str_replace('%f', escapeshellarg($tmpFile), $command);
6160
}
6261

6362
// with wrapping sh around the command, we leave any redirects intact,
@@ -69,4 +68,24 @@ protected function run($argument): void {
6968
);
7069
shell_exec($wrapper);
7170
}
71+
72+
/**
73+
* @throws InvalidArgumentException
74+
*/
75+
private function resolveLocalPath(string $path): string {
76+
try {
77+
$view = new View();
78+
$localFile = $view->getLocalFile($path);
79+
if ($localFile !== false && file_exists($localFile)) {
80+
return $localFile;
81+
}
82+
$tmpFile = $view->toTmpFile($path);
83+
if ($tmpFile === false) {
84+
throw new InvalidArgumentException();
85+
}
86+
return $tmpFile;
87+
} catch (Exception) {
88+
throw new InvalidArgumentException('Could not resolve local path for: ' . $path);
89+
}
90+
}
7291
}

‎lib/Operation.php‎

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

2525
namespace OCA\WorkflowScript;
2626

27-
use Exception;
28-
use InvalidArgumentException;
29-
use OC\Files\View;
3027
use OC\User\NoUserException;
3128
use OCA\Files_Sharing\SharedStorage;
3229
use OCA\GroupFolders\Mount\GroupFolderStorage;
@@ -151,6 +148,21 @@ public function onEvent(string $eventName, Event $event, IRuleMatcher $ruleMatch
151148
}
152149

153150
$matches = $ruleMatcher->getFlows(false);
151+
if (empty($matches)) {
152+
return;
153+
}
154+
155+
if (preg_match('/\$\(|`/', $node->getName())) {
156+
$this->logger->warning(
157+
'Potentially dangerous characters in filename, skipping workflow',
158+
[
159+
'app' => Application::APPID,
160+
'file' => $node->getPath(),
161+
]
162+
);
163+
return;
164+
}
165+
154166
foreach ($matches as $match) {
155167
try {
156168
$command = $this->buildCommand($match['operation'], $node, $eventName, $extra);
@@ -194,21 +206,6 @@ protected function buildCommand(string $template, Node $node, string $event, arr
194206
unset($ncRelPath);
195207
}
196208

197-
if (strpos($command, '%f')) {
198-
try {
199-
$view = new View();
200-
if ($node instanceof FileNode) {
201-
$fullPath = $view->getLocalFile($node->getPath());
202-
}
203-
if (!isset($fullPath) || $fullPath === false) {
204-
throw new InvalidArgumentException();
205-
}
206-
$command = str_replace('%f', escapeshellarg($fullPath), $command);
207-
} catch (Exception) {
208-
throw new InvalidArgumentException('Could not determine full path');
209-
}
210-
}
211-
212209
if (strpos($command, '%i')) {
213210
$nodeID = -1;
214211
try {

0 commit comments

Comments
 (0)