Skip to content

Commit 24bdc8d

Browse files
committed
refactor(workflowengine): Check if class is correct
Signed-off-by: Carl Schwan <[email protected]>
1 parent 4fbfeb6 commit 24bdc8d

File tree

2 files changed

+57
-31
lines changed

2 files changed

+57
-31
lines changed

apps/workflowengine/lib/Manager.php

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -424,10 +424,6 @@ protected function validateEvents(string $entity, array $events, IOperation $ope
424424
throw new \UnexpectedValueException($this->l->t('Entity %s does not exist', [$entity]));
425425
}
426426

427-
if (!$instance instanceof IEntity) {
428-
throw new \UnexpectedValueException($this->l->t('Entity %s is invalid', [$entity]));
429-
}
430-
431427
if (empty($events)) {
432428
if (!$operation instanceof IComplexOperation) {
433429
throw new \UnexpectedValueException($this->l->t('No events are chosen.'));
@@ -458,17 +454,23 @@ protected function validateEvents(string $entity, array $events, IOperation $ope
458454
* @throws \UnexpectedValueException
459455
*/
460456
public function validateOperation($class, $name, array $checks, $operation, ScopeContext $scope, string $entity, array $events) {
457+
if (strlen($operation) > IManager::MAX_OPERATION_VALUE_BYTES) {
458+
throw new \UnexpectedValueException($this->l->t('The provided operation data is too long'));
459+
}
460+
461+
/** @psalm-suppress TaintedCallable newInstance is not called */
462+
$reflection = new \ReflectionClass($class);
463+
if ($class !== IOperation::class && !in_array(IOperation::class, $reflection->getInterfaceNames())) {
464+
throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]) . join(', ', $reflection->getInterfaceNames()));
465+
}
466+
461467
try {
462468
/** @var IOperation $instance */
463469
$instance = $this->container->query($class);
464-
} catch (QueryException $e) {
470+
} catch (QueryException) {
465471
throw new \UnexpectedValueException($this->l->t('Operation %s does not exist', [$class]));
466472
}
467473

468-
if (!($instance instanceof IOperation)) {
469-
throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
470-
}
471-
472474
if (!$instance->isAvailableForScope($scope->getScope())) {
473475
throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
474476
}
@@ -479,38 +481,35 @@ public function validateOperation($class, $name, array $checks, $operation, Scop
479481
throw new \UnexpectedValueException($this->l->t('At least one check needs to be provided'));
480482
}
481483

482-
if (strlen((string)$operation) > IManager::MAX_OPERATION_VALUE_BYTES) {
483-
throw new \UnexpectedValueException($this->l->t('The provided operation data is too long'));
484-
}
485-
486484
$instance->validateOperation($name, $checks, $operation);
487485

488486
foreach ($checks as $check) {
489487
if (!is_string($check['class'])) {
490488
throw new \UnexpectedValueException($this->l->t('Invalid check provided'));
491489
}
492490

491+
if (strlen((string)$check['value']) > IManager::MAX_CHECK_VALUE_BYTES) {
492+
throw new \UnexpectedValueException($this->l->t('The provided check value is too long'));
493+
}
494+
495+
$reflection = new \ReflectionClass($check['class']);
496+
if ($check['class'] !== ICheck::class && !in_array(ICheck::class, $reflection->getInterfaceNames())) {
497+
throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class]));
498+
}
499+
493500
try {
494501
/** @var ICheck $instance */
495502
$instance = $this->container->query($check['class']);
496503
} catch (QueryException $e) {
497504
throw new \UnexpectedValueException($this->l->t('Check %s does not exist', [$class]));
498505
}
499506

500-
if (!($instance instanceof ICheck)) {
501-
throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class]));
502-
}
503-
504507
if (!empty($instance->supportedEntities())
505508
&& !in_array($entity, $instance->supportedEntities())
506509
) {
507510
throw new \UnexpectedValueException($this->l->t('Check %s is not allowed with this entity', [$class]));
508511
}
509512

510-
if (strlen((string)$check['value']) > IManager::MAX_CHECK_VALUE_BYTES) {
511-
throw new \UnexpectedValueException($this->l->t('The provided check value is too long'));
512-
}
513-
514513
$instance->validateCheck($check['operator'], $check['value']);
515514
}
516515
}

apps/workflowengine/tests/ManagerTest.php

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use OCA\WorkflowEngine\Helper\ScopeContext;
1313
use OCA\WorkflowEngine\Manager;
1414
use OCP\AppFramework\QueryException;
15+
use OCP\EventDispatcher\Event;
1516
use OCP\EventDispatcher\IEventDispatcher;
1617
use OCP\Files\Events\Node\NodeCreatedEvent;
1718
use OCP\Files\IRootFolder;
@@ -33,10 +34,41 @@
3334
use OCP\WorkflowEngine\IEntityEvent;
3435
use OCP\WorkflowEngine\IManager;
3536
use OCP\WorkflowEngine\IOperation;
37+
use OCP\WorkflowEngine\IRuleMatcher;
3638
use PHPUnit\Framework\MockObject\MockObject;
3739
use Psr\Log\LoggerInterface;
3840
use Test\TestCase;
3941

42+
class TestAdminOp implements IOperation {
43+
public function getDisplayName(): string {
44+
return 'Admin';
45+
}
46+
47+
public function getDescription(): string {
48+
return '';
49+
}
50+
51+
public function getIcon(): string {
52+
return '';
53+
}
54+
55+
public function isAvailableForScope(int $scope): bool {
56+
return true;
57+
}
58+
59+
public function validateOperation(string $name, array $checks, string $operation): void {
60+
}
61+
62+
public function onEvent(string $eventName, Event $event, IRuleMatcher $ruleMatcher): void {
63+
}
64+
}
65+
66+
class TestUserOp extends TestAdminOp {
67+
public function getDisplayName(): string {
68+
return 'User';
69+
}
70+
}
71+
4072
/**
4173
* Class ManagerTest
4274
*
@@ -407,19 +439,19 @@ public function testUpdateOperation(): void {
407439
$opId1 = $this->invokePrivate(
408440
$this->manager,
409441
'insertOperation',
410-
['OCA\WFE\TestAdminOp', 'Test01', [11, 22], 'foo', $entity, []]
442+
[TestAdminOp::class, 'Test01', [11, 22], 'foo', $entity, []]
411443
);
412444
$this->invokePrivate($this->manager, 'addScope', [$opId1, $adminScope]);
413445

414446
$opId2 = $this->invokePrivate(
415447
$this->manager,
416448
'insertOperation',
417-
['OCA\WFE\TestUserOp', 'Test02', [33, 22], 'bar', $entity, []]
449+
[TestUserOp::class, 'Test02', [33, 22], 'bar', $entity, []]
418450
);
419451
$this->invokePrivate($this->manager, 'addScope', [$opId2, $userScope]);
420452

421-
$check1 = ['class' => 'OCA\WFE\C22', 'operator' => 'eq', 'value' => 'asdf'];
422-
$check2 = ['class' => 'OCA\WFE\C33', 'operator' => 'eq', 'value' => 23456];
453+
$check1 = ['class' => ICheck::class, 'operator' => 'eq', 'value' => 'asdf'];
454+
$check2 = ['class' => ICheck::class, 'operator' => 'eq', 'value' => 23456];
423455

424456
/** @noinspection PhpUnhandledExceptionInspection */
425457
$op = $this->manager->updateOperation($opId1, 'Test01a', [$check1, $check2], 'foohur', $adminScope, $entity, ['\OCP\Files::postDelete']);
@@ -682,11 +714,6 @@ public function testValidateOperationDataLengthError(): void {
682714
->method('getScope')
683715
->willReturn(IManager::SCOPE_ADMIN);
684716

685-
$operationMock->expects($this->once())
686-
->method('isAvailableForScope')
687-
->with(IManager::SCOPE_ADMIN)
688-
->willReturn(true);
689-
690717
$operationMock->expects($this->never())
691718
->method('validateOperation');
692719

@@ -734,7 +761,7 @@ public function testValidateOperationScopeNotAvailable(): void {
734761
'operator' => 'is',
735762
'value' => 'barfoo',
736763
];
737-
$operationData = str_pad('', IManager::MAX_OPERATION_VALUE_BYTES + 1, 'FooBar');
764+
$operationData = str_pad('', IManager::MAX_OPERATION_VALUE_BYTES - 1, 'FooBar');
738765

739766
$operationMock = $this->createMock(IOperation::class);
740767
$entityMock = $this->createMock(IEntity::class);

0 commit comments

Comments
 (0)