Skip to content

Commit d06e165

Browse files
CarlSchwanbackportbot[bot]
authored andcommitted
refactor(workflowengine): Check if class is correct
Signed-off-by: Carl Schwan <[email protected]>
1 parent ff6f591 commit d06e165

File tree

2 files changed

+57
-26
lines changed

2 files changed

+57
-26
lines changed

apps/workflowengine/lib/Manager.php

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
23
/**
34
* @copyright Copyright (c) 2016 Morris Jobke <[email protected]>
45
*
@@ -447,10 +448,6 @@ protected function validateEvents(string $entity, array $events, IOperation $ope
447448
throw new \UnexpectedValueException($this->l->t('Entity %s does not exist', [$entity]));
448449
}
449450

450-
if (!$instance instanceof IEntity) {
451-
throw new \UnexpectedValueException($this->l->t('Entity %s is invalid', [$entity]));
452-
}
453-
454451
if (empty($events)) {
455452
if (!$operation instanceof IComplexOperation) {
456453
throw new \UnexpectedValueException($this->l->t('No events are chosen.'));
@@ -481,17 +478,23 @@ protected function validateEvents(string $entity, array $events, IOperation $ope
481478
* @throws \UnexpectedValueException
482479
*/
483480
public function validateOperation($class, $name, array $checks, $operation, ScopeContext $scope, string $entity, array $events) {
481+
if (strlen($operation) > IManager::MAX_OPERATION_VALUE_BYTES) {
482+
throw new \UnexpectedValueException($this->l->t('The provided operation data is too long'));
483+
}
484+
485+
/** @psalm-suppress TaintedCallable newInstance is not called */
486+
$reflection = new \ReflectionClass($class);
487+
if ($class !== IOperation::class && !in_array(IOperation::class, $reflection->getInterfaceNames())) {
488+
throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]) . join(', ', $reflection->getInterfaceNames()));
489+
}
490+
484491
try {
485492
/** @var IOperation $instance */
486493
$instance = $this->container->query($class);
487494
} catch (QueryException $e) {
488495
throw new \UnexpectedValueException($this->l->t('Operation %s does not exist', [$class]));
489496
}
490497

491-
if (!($instance instanceof IOperation)) {
492-
throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
493-
}
494-
495498
if (!$instance->isAvailableForScope($scope->getScope())) {
496499
throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
497500
}
@@ -513,27 +516,28 @@ public function validateOperation($class, $name, array $checks, $operation, Scop
513516
throw new \UnexpectedValueException($this->l->t('Invalid check provided'));
514517
}
515518

519+
if (strlen((string)$check['value']) > IManager::MAX_CHECK_VALUE_BYTES) {
520+
throw new \UnexpectedValueException($this->l->t('The provided check value is too long'));
521+
}
522+
523+
$reflection = new \ReflectionClass($check['class']);
524+
if ($check['class'] !== ICheck::class && !in_array(ICheck::class, $reflection->getInterfaceNames())) {
525+
throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class]));
526+
}
527+
516528
try {
517529
/** @var ICheck $instance */
518530
$instance = $this->container->query($check['class']);
519531
} catch (QueryException $e) {
520532
throw new \UnexpectedValueException($this->l->t('Check %s does not exist', [$class]));
521533
}
522534

523-
if (!($instance instanceof ICheck)) {
524-
throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class]));
525-
}
526-
527535
if (!empty($instance->supportedEntities())
528536
&& !in_array($entity, $instance->supportedEntities())
529537
) {
530538
throw new \UnexpectedValueException($this->l->t('Check %s is not allowed with this entity', [$class]));
531539
}
532540

533-
if (strlen((string)$check['value']) > IManager::MAX_CHECK_VALUE_BYTES) {
534-
throw new \UnexpectedValueException($this->l->t('The provided check value is too long'));
535-
}
536-
537541
$instance->validateCheck($check['operator'], $check['value']);
538542
}
539543
}

apps/workflowengine/tests/ManagerTest.php

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
use OCA\WorkflowEngine\Helper\ScopeContext;
3333
use OCA\WorkflowEngine\Manager;
3434
use OCP\AppFramework\QueryException;
35+
use OCP\EventDispatcher\Event;
3536
use OCP\EventDispatcher\IEventDispatcher;
3637
use OCP\Files\Events\Node\NodeCreatedEvent;
3738
use OCP\Files\IRootFolder;
@@ -52,10 +53,41 @@
5253
use OCP\WorkflowEngine\IEntityEvent;
5354
use OCP\WorkflowEngine\IManager;
5455
use OCP\WorkflowEngine\IOperation;
56+
use OCP\WorkflowEngine\IRuleMatcher;
5557
use PHPUnit\Framework\MockObject\MockObject;
5658
use Psr\Log\LoggerInterface;
5759
use Test\TestCase;
5860

61+
class TestAdminOp implements IOperation {
62+
public function getDisplayName(): string {
63+
return 'Admin';
64+
}
65+
66+
public function getDescription(): string {
67+
return '';
68+
}
69+
70+
public function getIcon(): string {
71+
return '';
72+
}
73+
74+
public function isAvailableForScope(int $scope): bool {
75+
return true;
76+
}
77+
78+
public function validateOperation(string $name, array $checks, string $operation): void {
79+
}
80+
81+
public function onEvent(string $eventName, Event $event, IRuleMatcher $ruleMatcher): void {
82+
}
83+
}
84+
85+
class TestUserOp extends TestAdminOp {
86+
public function getDisplayName(): string {
87+
return 'User';
88+
}
89+
}
90+
5991
/**
6092
* Class ManagerTest
6193
*
@@ -420,19 +452,19 @@ public function testUpdateOperation() {
420452
$opId1 = $this->invokePrivate(
421453
$this->manager,
422454
'insertOperation',
423-
['OCA\WFE\TestAdminOp', 'Test01', [11, 22], 'foo', $entity, []]
455+
[TestAdminOp::class, 'Test01', [11, 22], 'foo', $entity, []]
424456
);
425457
$this->invokePrivate($this->manager, 'addScope', [$opId1, $adminScope]);
426458

427459
$opId2 = $this->invokePrivate(
428460
$this->manager,
429461
'insertOperation',
430-
['OCA\WFE\TestUserOp', 'Test02', [33, 22], 'bar', $entity, []]
462+
[TestUserOp::class, 'Test02', [33, 22], 'bar', $entity, []]
431463
);
432464
$this->invokePrivate($this->manager, 'addScope', [$opId2, $userScope]);
433465

434-
$check1 = ['class' => 'OCA\WFE\C22', 'operator' => 'eq', 'value' => 'asdf'];
435-
$check2 = ['class' => 'OCA\WFE\C33', 'operator' => 'eq', 'value' => 23456];
466+
$check1 = ['class' => ICheck::class, 'operator' => 'eq', 'value' => 'asdf'];
467+
$check2 = ['class' => ICheck::class, 'operator' => 'eq', 'value' => 23456];
436468

437469
/** @noinspection PhpUnhandledExceptionInspection */
438470
$op = $this->manager->updateOperation($opId1, 'Test01a', [$check1, $check2], 'foohur', $adminScope, $entity, ['\OCP\Files::postDelete']);
@@ -695,11 +727,6 @@ public function testValidateOperationDataLengthError() {
695727
->method('getScope')
696728
->willReturn(IManager::SCOPE_ADMIN);
697729

698-
$operationMock->expects($this->once())
699-
->method('isAvailableForScope')
700-
->with(IManager::SCOPE_ADMIN)
701-
->willReturn(true);
702-
703730
$operationMock->expects($this->never())
704731
->method('validateOperation');
705732

@@ -747,7 +774,7 @@ public function testValidateOperationScopeNotAvailable() {
747774
'operator' => 'is',
748775
'value' => 'barfoo',
749776
];
750-
$operationData = str_pad('', IManager::MAX_OPERATION_VALUE_BYTES + 1, 'FooBar');
777+
$operationData = str_pad('', IManager::MAX_OPERATION_VALUE_BYTES - 1, 'FooBar');
751778

752779
$operationMock = $this->createMock(IOperation::class);
753780
$entityMock = $this->createMock(IEntity::class);

0 commit comments

Comments
 (0)