Skip to content

Commit 4cc140d

Browse files
Merge pull request #56187 from nextcloud/backport/55748/stable31
[stable31] fix(jobs): Limit command jobs to known cases
2 parents a206c1a + 4fe190a commit 4cc140d

File tree

12 files changed

+62
-214
lines changed

12 files changed

+62
-214
lines changed

build/psalm-baseline.xml

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,15 +1550,19 @@
15501550
}, $context->getCalendarProviders())]]></code>
15511551
</NamedArgumentNotAllowed>
15521552
</file>
1553-
<file src="lib/private/Command/CallableJob.php">
1554-
<ParamNameMismatch>
1555-
<code><![CDATA[$serializedCallable]]></code>
1556-
</ParamNameMismatch>
1553+
<file src="lib/private/Command/CommandJob.php">
1554+
<UndefinedClass>
1555+
<code><![CDATA[\Test\Command\FilesystemCommand]]></code>
1556+
<code><![CDATA[\Test\Command\SimpleCommand]]></code>
1557+
<code><![CDATA[\Test\Command\StateFullCommand]]></code>
1558+
</UndefinedClass>
15571559
</file>
1558-
<file src="lib/private/Command/ClosureJob.php">
1559-
<InvalidArgument>
1560-
<code><![CDATA[[LaravelClosure::class]]]></code>
1561-
</InvalidArgument>
1560+
<file src="lib/private/Command/QueueBus.php">
1561+
<UndefinedClass>
1562+
<code><![CDATA[\Test\Command\FilesystemCommand]]></code>
1563+
<code><![CDATA[\Test\Command\SimpleCommand]]></code>
1564+
<code><![CDATA[\Test\Command\StateFullCommand]]></code>
1565+
</UndefinedClass>
15621566
</file>
15631567
<file src="lib/private/Comments/Manager.php">
15641568
<RedundantCast>

lib/composer/composer/autoload_classmap.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,8 +1172,6 @@
11721172
'OC\\Collaboration\\Resources\\Resource' => $baseDir . '/lib/private/Collaboration/Resources/Resource.php',
11731173
'OC\\Color' => $baseDir . '/lib/private/Color.php',
11741174
'OC\\Command\\AsyncBus' => $baseDir . '/lib/private/Command/AsyncBus.php',
1175-
'OC\\Command\\CallableJob' => $baseDir . '/lib/private/Command/CallableJob.php',
1176-
'OC\\Command\\ClosureJob' => $baseDir . '/lib/private/Command/ClosureJob.php',
11771175
'OC\\Command\\CommandJob' => $baseDir . '/lib/private/Command/CommandJob.php',
11781176
'OC\\Command\\CronBus' => $baseDir . '/lib/private/Command/CronBus.php',
11791177
'OC\\Command\\FileAccess' => $baseDir . '/lib/private/Command/FileAccess.php',

lib/composer/composer/autoload_static.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,8 +1221,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
12211221
'OC\\Collaboration\\Resources\\Resource' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Resources/Resource.php',
12221222
'OC\\Color' => __DIR__ . '/../../..' . '/lib/private/Color.php',
12231223
'OC\\Command\\AsyncBus' => __DIR__ . '/../../..' . '/lib/private/Command/AsyncBus.php',
1224-
'OC\\Command\\CallableJob' => __DIR__ . '/../../..' . '/lib/private/Command/CallableJob.php',
1225-
'OC\\Command\\ClosureJob' => __DIR__ . '/../../..' . '/lib/private/Command/ClosureJob.php',
12261224
'OC\\Command\\CommandJob' => __DIR__ . '/../../..' . '/lib/private/Command/CommandJob.php',
12271225
'OC\\Command\\CronBus' => __DIR__ . '/../../..' . '/lib/private/Command/CronBus.php',
12281226
'OC\\Command\\FileAccess' => __DIR__ . '/../../..' . '/lib/private/Command/FileAccess.php',

lib/private/Command/AsyncBus.php

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
/**
46
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
57
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
@@ -19,14 +21,12 @@ abstract class AsyncBus implements IBus {
1921
*
2022
* @var string[]
2123
*/
22-
private $syncTraits = [];
24+
private array $syncTraits = [];
2325

2426
/**
2527
* Schedule a command to be fired
26-
*
27-
* @param \OCP\Command\ICommand | callable $command
2828
*/
29-
public function push($command) {
29+
public function push(ICommand $command): void {
3030
if ($this->canRunAsync($command)) {
3131
$this->queueCommand($command);
3232
} else {
@@ -36,54 +36,39 @@ public function push($command) {
3636

3737
/**
3838
* Queue a command in the bus
39-
*
40-
* @param \OCP\Command\ICommand | callable $command
4139
*/
42-
abstract protected function queueCommand($command);
40+
abstract protected function queueCommand(ICommand $command);
4341

4442
/**
4543
* Require all commands using a trait to be run synchronous
4644
*
4745
* @param string $trait
4846
*/
49-
public function requireSync($trait) {
47+
public function requireSync(string $trait): void {
5048
$this->syncTraits[] = trim($trait, '\\');
5149
}
5250

53-
/**
54-
* @param \OCP\Command\ICommand | callable $command
55-
*/
56-
private function runCommand($command) {
57-
if ($command instanceof ICommand) {
58-
$command->handle();
59-
} else {
60-
$command();
61-
}
51+
private function runCommand(ICommand $command): void {
52+
$command->handle();
6253
}
6354

6455
/**
65-
* @param \OCP\Command\ICommand | callable $command
6656
* @return bool
6757
*/
68-
private function canRunAsync($command) {
58+
private function canRunAsync(ICommand $command): bool {
6959
$traits = $this->getTraits($command);
7060
foreach ($traits as $trait) {
71-
if (in_array($trait, $this->syncTraits)) {
61+
if (in_array($trait, $this->syncTraits, true)) {
7262
return false;
7363
}
7464
}
7565
return true;
7666
}
7767

7868
/**
79-
* @param \OCP\Command\ICommand | callable $command
8069
* @return string[]
8170
*/
82-
private function getTraits($command) {
83-
if ($command instanceof ICommand) {
84-
return class_uses($command);
85-
} else {
86-
return [];
87-
}
71+
private function getTraits(ICommand $command): array {
72+
return class_uses($command);
8873
}
8974
}

lib/private/Command/CallableJob.php

Lines changed: 0 additions & 21 deletions
This file was deleted.

lib/private/Command/ClosureJob.php

Lines changed: 0 additions & 23 deletions
This file was deleted.

lib/private/Command/CommandJob.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515
*/
1616
class CommandJob extends QueuedJob {
1717
protected function run($argument) {
18-
$command = unserialize($argument);
18+
$command = unserialize($argument, ['allowed_classes' => [
19+
\Test\Command\SimpleCommand::class,
20+
\Test\Command\StateFullCommand::class,
21+
\Test\Command\FilesystemCommand::class,
22+
\OCA\Files_Trashbin\Command\Expire::class,
23+
\OCA\Files_Versions\Command\Expire::class,
24+
]]);
1925
if ($command instanceof ICommand) {
2026
$command->handle();
2127
} else {

lib/private/Command/CronBus.php

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<?php
2+
3+
declare(strict_types=1);
4+
25
/**
36
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
47
* SPDX-License-Identifier: AGPL-3.0-or-later
58
*/
69
namespace OC\Command;
710

8-
use Laravel\SerializableClosure\SerializableClosure;
9-
use OCP\BackgroundJob\IJob;
1011
use OCP\BackgroundJob\IJobList;
1112
use OCP\Command\ICommand;
1213

@@ -16,37 +17,7 @@ public function __construct(
1617
) {
1718
}
1819

19-
protected function queueCommand($command): void {
20-
$this->jobList->add($this->getJobClass($command), $this->serializeCommand($command));
21-
}
22-
23-
/**
24-
* @param ICommand|callable $command
25-
* @return class-string<IJob>
26-
*/
27-
private function getJobClass($command): string {
28-
if ($command instanceof \Closure) {
29-
return ClosureJob::class;
30-
} elseif (is_callable($command)) {
31-
return CallableJob::class;
32-
} elseif ($command instanceof ICommand) {
33-
return CommandJob::class;
34-
} else {
35-
throw new \InvalidArgumentException('Invalid command');
36-
}
37-
}
38-
39-
/**
40-
* @param ICommand|callable $command
41-
* @return string
42-
*/
43-
private function serializeCommand($command): string {
44-
if ($command instanceof \Closure) {
45-
return serialize(new SerializableClosure($command));
46-
} elseif (is_callable($command) or $command instanceof ICommand) {
47-
return serialize($command);
48-
} else {
49-
throw new \InvalidArgumentException('Invalid command');
50-
}
20+
protected function queueCommand(ICommand $command): void {
21+
$this->jobList->add(CommandJob::class, serialize($command));
5122
}
5223
}

lib/private/Command/QueueBus.php

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
/**
46
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
57
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
@@ -12,45 +14,40 @@
1214

1315
class QueueBus implements IBus {
1416
/**
15-
* @var ICommand[]|callable[]
17+
* @var ICommand[]
1618
*/
17-
private $queue = [];
19+
private array $queue = [];
1820

1921
/**
2022
* Schedule a command to be fired
21-
*
22-
* @param \OCP\Command\ICommand | callable $command
2323
*/
24-
public function push($command) {
24+
public function push(ICommand $command): void {
2525
$this->queue[] = $command;
2626
}
2727

2828
/**
2929
* Require all commands using a trait to be run synchronous
30-
*
31-
* @param string $trait
3230
*/
33-
public function requireSync($trait) {
31+
public function requireSync(string $trait): void {
3432
}
3533

36-
/**
37-
* @param \OCP\Command\ICommand | callable $command
38-
*/
39-
private function runCommand($command) {
40-
if ($command instanceof ICommand) {
41-
// ensure the command can be serialized
42-
$serialized = serialize($command);
43-
if (strlen($serialized) > 4000) {
44-
throw new \InvalidArgumentException('Trying to push a command which serialized form can not be stored in the database (>4000 character)');
45-
}
46-
$unserialized = unserialize($serialized);
47-
$unserialized->handle();
48-
} else {
49-
$command();
34+
private function runCommand(ICommand $command): void {
35+
// ensure the command can be serialized
36+
$serialized = serialize($command);
37+
if (strlen($serialized) > 4000) {
38+
throw new \InvalidArgumentException('Trying to push a command which serialized form can not be stored in the database (>4000 character)');
5039
}
40+
$unserialized = unserialize($serialized, ['allowed_classes' => [
41+
\Test\Command\SimpleCommand::class,
42+
\Test\Command\StateFullCommand::class,
43+
\Test\Command\FilesystemCommand::class,
44+
\OCA\Files_Trashbin\Command\Expire::class,
45+
\OCA\Files_Versions\Command\Expire::class,
46+
]]);
47+
$unserialized->handle();
5148
}
5249

53-
public function run() {
50+
public function run(): void {
5451
while ($command = array_shift($this->queue)) {
5552
$this->runCommand($command);
5653
}

lib/public/Command/IBus.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,24 @@
1010
/**
1111
* Interface IBus
1212
*
13+
* @deprecated 33.0.0 The interface is considered internal going forward and should not be implemented by apps anymore
1314
* @since 8.1.0
1415
*/
1516
interface IBus {
1617
/**
1718
* Schedule a command to be fired
1819
*
19-
* @param \OCP\Command\ICommand | callable $command
20+
* @param \OCP\Command\ICommand $command
21+
* @since 33.0.0 Only allowed for {@see \OCA\Files_Trashbin\Command\Expire} and {@see \OCA\Files_Versions\Command\Expire}
2022
* @since 8.1.0
2123
*/
22-
public function push($command);
24+
public function push(ICommand $command): void;
2325

2426
/**
2527
* Require all commands using a trait to be run synchronous
2628
*
2729
* @param string $trait
2830
* @since 8.1.0
2931
*/
30-
public function requireSync($trait);
32+
public function requireSync(string $trait): void;
3133
}

0 commit comments

Comments
 (0)