Browse Source
fix(federation): remove background jobs when removing trusted servers
fix(federation): remove background jobs when removing trusted servers
Add event listener to remove matching background jobs for trusted server url. Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>pull/53760/head
No known key found for this signature in database
GPG Key ID: 4A81C29F63464E8F
8 changed files with 149 additions and 7 deletions
-
1apps/federation/composer/composer/autoload_classmap.php
-
1apps/federation/composer/composer/autoload_static.php
-
3apps/federation/lib/AppInfo/Application.php
-
57apps/federation/lib/Listener/TrustedServerRemovedListener.php
-
2apps/federation/lib/TrustedServers.php
-
71apps/federation/tests/Listener/TrustedServerRemovedListenerTest.php
-
6apps/federation/tests/TrustedServersTest.php
-
15lib/public/Federation/Events/TrustedServerRemovedEvent.php
@ -0,0 +1,57 @@ |
|||
<?php |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
/** |
|||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors |
|||
* SPDX-License-Identifier: AGPL-3.0-or-later |
|||
*/ |
|||
|
|||
namespace OCA\Federation\Listener; |
|||
|
|||
use OCA\Federation\BackgroundJob\GetSharedSecret; |
|||
use OCA\Federation\BackgroundJob\RequestSharedSecret; |
|||
use OCP\BackgroundJob\IJobList; |
|||
use OCP\EventDispatcher\Event; |
|||
use OCP\EventDispatcher\IEventListener; |
|||
use OCP\Federation\Events\TrustedServerRemovedEvent; |
|||
|
|||
/** @template-implements IEventListener<TrustedServerRemovedEvent> */ |
|||
class TrustedServerRemovedListener implements IEventListener { |
|||
public function __construct( |
|||
private readonly IJobList $jobList, |
|||
) { |
|||
} |
|||
|
|||
public function handle(Event $event): void { |
|||
if (!$event instanceof TrustedServerRemovedEvent) { |
|||
return; |
|||
} |
|||
|
|||
if ($event->getUrl() === null) { |
|||
return; // safe guard
|
|||
} |
|||
|
|||
$this->removeJobsByUrl(RequestSharedSecret::class, $event->getUrl()); |
|||
$this->removeJobsByUrl(GetSharedSecret::class, $event->getUrl()); |
|||
} |
|||
|
|||
/** |
|||
* Remove RequestSharedSecret or GetSharedSecret jobs from the job list by their URL. |
|||
* The jobs are scheduled with url, token, and created as arguments. |
|||
* Thus, we have to loop over the jobs here and cannot use IJobList.remove. |
|||
*/ |
|||
private function removeJobsByUrl(string $class, string $url): void { |
|||
foreach ($this->jobList->getJobsIterator($class, null, 0) as $job) { |
|||
$arguments = $job->getArgument(); |
|||
if (isset($arguments['url']) && $arguments['url'] === $url) { |
|||
try { |
|||
$this->jobList->removeById($job->getId()); |
|||
} catch (\Exception) { |
|||
// Removing the background jobs is optional because they will expire sometime.
|
|||
// Therefore, we are using catch and ignore.
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,71 @@ |
|||
<?php |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
/** |
|||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors |
|||
* SPDX-License-Identifier: AGPL-3.0-or-later |
|||
*/ |
|||
|
|||
namespace OCA\Federation\Tests\Listener; |
|||
|
|||
use OC\AppFramework\Utility\TimeFactory; |
|||
use OCA\Federation\BackgroundJob\GetSharedSecret; |
|||
use OCA\Federation\Listener\TrustedServerRemovedListener; |
|||
use OCA\Federation\TrustedServers; |
|||
use OCP\BackgroundJob\IJobList; |
|||
use OCP\Federation\Events\TrustedServerRemovedEvent; |
|||
use OCP\Http\Client\IClientService; |
|||
use OCP\IConfig; |
|||
use OCP\IURLGenerator; |
|||
use OCP\OCS\IDiscoveryService; |
|||
use Psr\Log\NullLogger; |
|||
use Test\BackgroundJob\DummyJobList; |
|||
use Test\TestCase; |
|||
|
|||
class TrustedServerRemovedListenerTest extends TestCase { |
|||
|
|||
private IJobList $jobList; |
|||
private TrustedServerRemovedListener $listener; |
|||
|
|||
protected function setUp(): void { |
|||
parent::setUp(); |
|||
|
|||
$this->jobList = new DummyJobList(); |
|||
$this->listener = new TrustedServerRemovedListener($this->jobList); |
|||
} |
|||
|
|||
public function testHandle(): void { |
|||
// Arrange
|
|||
$url = 'https://example.com'; |
|||
$event = new TrustedServerRemovedEvent(md5($url), $url); // we are using a different hashing in the tests.
|
|||
$job1 = $this->createGetSharedSecretMock(); |
|||
$job2 = $this->createGetSharedSecretMock(); |
|||
$job3 = $this->createGetSharedSecretMock(); |
|||
$job4 = $this->createGetSharedSecretMock(); |
|||
$this->jobList->add($job1, ['url' => 'https://example.org', 'token' => 'nei0dooX', 'created' => 0]); |
|||
$this->jobList->add($job2, ['url' => 'https://example.net', 'token' => 'ci6Shah7', 'created' => 0]); |
|||
$this->jobList->add($job3, ['url' => $url, 'token' => 'ieXie6Me', 'created' => 0]); |
|||
$this->jobList->add($job4, ['url' => $url, 'token' => 'thoQu8th', 'created' => 0]); |
|||
|
|||
// Act
|
|||
$this->listener->handle($event); |
|||
$jobs = iterator_to_array($this->jobList->getJobsIterator(GetSharedSecret::class, null, 0), false); |
|||
|
|||
// Assert
|
|||
$this->assertCount(2, $jobs); |
|||
} |
|||
|
|||
private function createGetSharedSecretMock(): GetSharedSecret { |
|||
return new GetSharedSecret( |
|||
$this->createMock(IClientService::class), |
|||
$this->createMock(IURLGenerator::class), |
|||
$this->jobList, |
|||
$this->createMock(TrustedServers::class), |
|||
new NullLogger(), |
|||
$this->createMock(IDiscoveryService::class), |
|||
new TimeFactory(), |
|||
$this->createMock(IConfig::class), |
|||
); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue