Skip to content

Commit 2d2bced

Browse files
committed
fix: don't fetch own remote collabora url
Signed-off-by: Elizabeth Danzberger <lizzy7128@tutanota.de>
1 parent 10685df commit 2d2bced

2 files changed

Lines changed: 98 additions & 1 deletion

File tree

lib/Service/FederationService.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use OCP\ICacheFactory;
2525
use OCP\IRequest;
2626
use OCP\IURLGenerator;
27+
use OCP\Security\ITrustedDomainHelper;
2728
use OCP\Share\IShare;
2829
use Psr\Container\ContainerExceptionInterface;
2930
use Psr\Container\NotFoundExceptionInterface;
@@ -46,15 +47,18 @@ class FederationService {
4647
private $request;
4748
/** @var IURLGenerator */
4849
private $urlGenerator;
50+
/** @var ITrustedDomainHelper */
51+
private $trustedDomainHelper;
4952

50-
public function __construct(ICacheFactory $cacheFactory, IClientService $clientService, LoggerInterface $logger, TokenManager $tokenManager, AppConfig $appConfig, IRequest $request, IURLGenerator $urlGenerator) {
53+
public function __construct(ICacheFactory $cacheFactory, IClientService $clientService, LoggerInterface $logger, TokenManager $tokenManager, AppConfig $appConfig, IRequest $request, IURLGenerator $urlGenerator, ITrustedDomainHelper $trustedDomainHelper) {
5154
$this->cache = $cacheFactory->createDistributed('richdocuments_remote/');
5255
$this->clientService = $clientService;
5356
$this->logger = $logger;
5457
$this->tokenManager = $tokenManager;
5558
$this->appConfig = $appConfig;
5659
$this->request = $request;
5760
$this->urlGenerator = $urlGenerator;
61+
$this->trustedDomainHelper = $trustedDomainHelper;
5862
try {
5963
$this->trustedServers = \OC::$server->get(\OCA\Federation\TrustedServers::class);
6064
} catch (NotFoundExceptionInterface $e) {
@@ -87,6 +91,11 @@ public function getRemoteCollaboraURL($remote) {
8791
if (!$this->isTrustedRemote($remote)) {
8892
throw new \Exception('Unable to determine collabora URL of remote server ' . $remote . ' - Remote is not a trusted server');
8993
}
94+
95+
if ($this->trustedDomainHelper->isTrustedUrl($remote)) {
96+
return $this->appConfig->getCollaboraUrlInternal();
97+
}
98+
9099
$remoteCollabora = $this->cache->get('richdocuments_remote/' . $remote);
91100
if ($remoteCollabora !== null) {
92101
return $remoteCollabora;
@@ -127,6 +136,10 @@ public function isTrustedRemote($domainWithPort) {
127136
if (!is_string($trusted)) {
128137
break;
129138
}
139+
140+
// This regular expression ensures that wildcards for trusted domains
141+
// are parsed properly in order to match subdomains:
142+
// *.example.com => /^[-\.a-zA-Z0-9]*\.example\.com$/i
130143
$regex = '/^' . implode('[-\.a-zA-Z0-9]*', array_map(function ($v) {
131144
return preg_quote($v, '/');
132145
}, explode('*', $trusted))) . '$/i';
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace Tests\Richdocuments;
11+
12+
use OCA\Federation\TrustedServers;
13+
use OCA\Richdocuments\AppConfig;
14+
use OCA\Richdocuments\Service\FederationService;
15+
use OCA\Richdocuments\TokenManager;
16+
use OCP\Http\Client\IClientService;
17+
use OCP\ICacheFactory;
18+
use OCP\IRequest;
19+
use OCP\IURLGenerator;
20+
use OCP\Security\ITrustedDomainHelper;
21+
use PHPUnit\Framework\TestCase;
22+
use Psr\Log\LoggerInterface;
23+
24+
class FederationServiceTest extends TestCase {
25+
public const NEXTCLOUD_ADDRESS = 'https://nextcloud.local';
26+
public const COLLABORA_ADDRESS = 'https://collabora.local';
27+
28+
public function setUp(): void {
29+
parent::setUp();
30+
31+
$this->cacheFactory = $this->createMock(ICacheFactory::class);
32+
$this->clientService = $this->createMock(IClientService::class);
33+
$this->logger = $this->createMock(LoggerInterface::class);
34+
$this->tokenManager = $this->createMock(TokenManager::class);
35+
$this->appConfig = $this->createStub(AppConfig::class);
36+
$this->request = $this->createMock(IRequest::class);
37+
$this->urlGenerator = $this->createMock(IURLGenerator::class);
38+
$this->trustedDomainHelper = $this->createStub(ITrustedDomainHelper::class);
39+
40+
$this->federationService = new FederationService(
41+
$this->cacheFactory,
42+
$this->clientService,
43+
$this->logger,
44+
$this->tokenManager,
45+
$this->appConfig,
46+
$this->request,
47+
$this->urlGenerator,
48+
$this->trustedDomainHelper
49+
);
50+
}
51+
52+
/**
53+
* @test
54+
* @testdox returns own instance's Collabora URL
55+
*/
56+
public function getRemoteCollaboraURLFromOwnInstance(): void {
57+
// Ensure that trusted domains can be used for federated editing
58+
$this->appConfig->method('isTrustedDomainAllowedForFederation')
59+
->willReturn(true);
60+
$this->appConfig->method('getCollaboraUrlInternal')
61+
->willReturn(self::COLLABORA_ADDRESS);
62+
63+
$this->trustedDomainHelper->method('isTrustedUrl')
64+
->with(self::NEXTCLOUD_ADDRESS)
65+
->willReturn(true);
66+
67+
// Create a stub TrustedServers class which always tells us
68+
// the server is trusted
69+
$trustedServers = $this->createStub(TrustedServers::class);
70+
$trustedServers->method('isTrustedServer')
71+
->with('nextcloud.local')
72+
->willReturn(true);
73+
74+
// Do some reflection property manipulation to set the TrustedServers object
75+
// It would be nice if the TrustedServers were passed into FederationService
76+
// instead of being set manually in the constructor to make testing easier
77+
$reflection = new \ReflectionClass($this->federationService);
78+
$reflectionProperty = $reflection->getProperty('trustedServers');
79+
$reflectionProperty->setAccessible(true);
80+
$reflectionProperty->setValue($this->federationService, $trustedServers);
81+
82+
$this->assertEquals(self::COLLABORA_ADDRESS, $this->federationService->getRemoteCollaboraURL(self::NEXTCLOUD_ADDRESS));
83+
}
84+
}

0 commit comments

Comments
 (0)