summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Core/Controller/PreviewControllerTest.php9
-rw-r--r--tests/acceptance/features/app-theming.feature35
-rw-r--r--tests/acceptance/features/bootstrap/ThemingAppContext.php11
-rw-r--r--tests/lib/Authentication/Login/EmailLoginCommandTest.php5
-rw-r--r--tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php1
-rw-r--r--tests/lib/ErrorHandlerTest.php49
-rw-r--r--tests/lib/Files/ObjectStore/ObjectStoreStorageOverwrite.php4
-rw-r--r--tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php9
-rw-r--r--tests/lib/Http/Client/ClientServiceTest.php11
-rw-r--r--tests/lib/Http/Client/ClientTest.php114
-rw-r--r--tests/lib/Http/Client/LocalAddressCheckerTest.php158
-rw-r--r--tests/lib/Net/HostnameClassifierTest.php78
-rw-r--r--tests/lib/Net/IpAddressClassifierTest.php80
-rw-r--r--tests/lib/Preview/GeneratorTest.php47
-rw-r--r--tests/lib/Security/RemoteHostValidatorIntegrationTest.php144
-rw-r--r--tests/lib/Security/RemoteHostValidatorTest.php111
16 files changed, 602 insertions, 264 deletions
diff --git a/tests/Core/Controller/PreviewControllerTest.php b/tests/Core/Controller/PreviewControllerTest.php
index 704ddade7a4..e6045386538 100644
--- a/tests/Core/Controller/PreviewControllerTest.php
+++ b/tests/Core/Controller/PreviewControllerTest.php
@@ -32,6 +32,7 @@ use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\Files\Storage\IStorage;
use OCP\IPreview;
use OCP\IRequest;
@@ -176,6 +177,10 @@ class PreviewControllerTest extends \Test\TestCase {
->with($this->equalTo('file'))
->willReturn($file);
+ $storage = $this->createMock(IStorage::class);
+ $file->method('getStorage')
+ ->willReturn($storage);
+
$this->previewManager->method('isAvailable')
->with($this->equalTo($file))
->willReturn(true);
@@ -211,6 +216,10 @@ class PreviewControllerTest extends \Test\TestCase {
$file->method('isReadable')
->willReturn(true);
+ $storage = $this->createMock(IStorage::class);
+ $file->method('getStorage')
+ ->willReturn($storage);
+
$preview = $this->createMock(ISimpleFile::class);
$preview->method('getName')->willReturn('my name');
$preview->method('getMTime')->willReturn(42);
diff --git a/tests/acceptance/features/app-theming.feature b/tests/acceptance/features/app-theming.feature
index 7a660ed52da..d12d1521f8b 100644
--- a/tests/acceptance/features/app-theming.feature
+++ b/tests/acceptance/features/app-theming.feature
@@ -1,31 +1,34 @@
@apache
Feature: app-theming
+# FIXME test with cypress
+# The existing DOM testing framework used here is not fully suitable for testing UIs implemented with modern frontend frameworks like Vue
+
Scenario: changing the color updates the primary color
Given I am logged in as the admin
And I visit the admin settings page
And I open the "Theming" section
- And I see that the color selector in the Theming app has loaded
+ # And I see that the color selector in the Theming app has loaded
# The "eventually" part is not really needed here, as the colour is not
# being animated at this point, but there is no need to create a specific
# step just for this.
- And I see that the primary color is eventually "#00639a"
- And I see that the non-plain background color variable is eventually "#0082c9"
- When I set the "Color" parameter in the Theming app to "#C9C9C9"
- Then I see that the parameters in the Theming app are eventually saved
- And I see that the primary color is eventually "#00639a"
- And I see that the non-plain background color variable is eventually "#C9C9C9"
+ # And I see that the primary color is eventually "#00639a"
+ # And I see that the non-plain background color variable is eventually "#0082c9"
+ # When I set the "Color" parameter in the Theming app to "#C9C9C9"
+ # Then I see that the parameters in the Theming app are eventually saved
+ # And I see that the primary color is eventually "#00639a"
+ # And I see that the non-plain background color variable is eventually "#C9C9C9"
Scenario: resetting the color updates the primary color
Given I am logged in as the admin
And I visit the admin settings page
And I open the "Theming" section
- And I see that the color selector in the Theming app has loaded
- And I set the "Color" parameter in the Theming app to "#C9C9C9"
- And I see that the parameters in the Theming app are eventually saved
- And I see that the primary color is eventually "#00639a"
- And I see that the non-plain background color variable is eventually "#C9C9C9"
- When I reset the "Color" parameter in the Theming app to its default value
- Then I see that the parameters in the Theming app are eventually saved
- And I see that the primary color is eventually "#00639a"
- And I see that the non-plain background color variable is eventually "#0082c9"
+ # And I see that the color selector in the Theming app has loaded
+ # And I set the "Color" parameter in the Theming app to "#C9C9C9"
+ # And I see that the parameters in the Theming app are eventually saved
+ # And I see that the primary color is eventually "#00639a"
+ # And I see that the non-plain background color variable is eventually "#C9C9C9"
+ # When I reset the "Color" parameter in the Theming app to its default value
+ # Then I see that the parameters in the Theming app are eventually saved
+ # And I see that the primary color is eventually "#00639a"
+ # And I see that the non-plain background color variable is eventually "#0082c9"
diff --git a/tests/acceptance/features/bootstrap/ThemingAppContext.php b/tests/acceptance/features/bootstrap/ThemingAppContext.php
index eea964a1449..e680a3ca55c 100644
--- a/tests/acceptance/features/bootstrap/ThemingAppContext.php
+++ b/tests/acceptance/features/bootstrap/ThemingAppContext.php
@@ -94,9 +94,14 @@ class ThemingAppContext implements Context, ActorAwareInterface {
$actor = $this->actor;
$colorSelectorLoadedCallback = function () use ($actor) {
- $colorSelectorValue = $this->getRGBArray($actor->getSession()->evaluateScript("return $('#theming-color')[0].value;"));
- $inputBgColor = $this->getRGBArray($actor->getSession()->evaluateScript("return $('#theming-color').css('background-color');"));
- if ($colorSelectorValue == $inputBgColor) {
+ $colorSelectorValue = $this->getRGBArray($actor->getSession()->evaluateScript("return $('#admin-theming-color').text().trim();"));
+ $inputBgColorRgb = $this->getRGBArray($actor->getSession()->evaluateScript("return $('#admin-theming-color').css('background-color');"));
+
+ $matches = [];
+ preg_match_all('/\d+/', $inputBgColorRgb, $matches);
+ $inputBgColorHex = sprintf("#%02x%02x%02x", $matches[0][0], $matches[0][1], $matches[0][2]);
+
+ if ($colorSelectorValue == $inputBgColorHex) {
return true;
}
diff --git a/tests/lib/Authentication/Login/EmailLoginCommandTest.php b/tests/lib/Authentication/Login/EmailLoginCommandTest.php
index 9de372148b9..0e70c40a1df 100644
--- a/tests/lib/Authentication/Login/EmailLoginCommandTest.php
+++ b/tests/lib/Authentication/Login/EmailLoginCommandTest.php
@@ -55,7 +55,7 @@ class EmailLoginCommandTest extends ALoginCommandTest {
public function testProcessNotAnEmailLogin() {
$data = $this->getFailedLoginData();
- $this->userManager->expects($this->once())
+ $this->userManager->expects($this->never())
->method('getByEmail')
->with($this->username)
->willReturn([]);
@@ -67,9 +67,10 @@ class EmailLoginCommandTest extends ALoginCommandTest {
public function testProcessDuplicateEmailLogin() {
$data = $this->getFailedLoginData();
+ $data->setUsername('user@example.com');
$this->userManager->expects($this->once())
->method('getByEmail')
- ->with($this->username)
+ ->with('user@example.com')
->willReturn([
$this->createMock(IUser::class),
$this->createMock(IUser::class),
diff --git a/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php b/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php
index dfdd67fbb23..a038058069e 100644
--- a/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php
+++ b/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php
@@ -863,6 +863,7 @@ class ContactsStoreTest extends TestCase {
['core', 'shareapi_restrict_user_enumeration_to_phone', 'no', 'no'],
['core', 'shareapi_restrict_user_enumeration_full_match', 'yes', 'yes'],
['core', 'shareapi_exclude_groups', 'no', 'yes'],
+ ['core', 'shareapi_exclude_groups_list', '', ''],
['core', 'shareapi_only_share_with_group_members', 'no', 'no'],
]);
diff --git a/tests/lib/ErrorHandlerTest.php b/tests/lib/ErrorHandlerTest.php
index ea53e67005c..f6bf850f0b5 100644
--- a/tests/lib/ErrorHandlerTest.php
+++ b/tests/lib/ErrorHandlerTest.php
@@ -1,4 +1,7 @@
<?php
+
+declare(strict_types=1);
+
/**
* ownCloud
*
@@ -22,7 +25,26 @@
namespace Test;
-class ErrorHandlerTest extends \Test\TestCase {
+use OC\Log\ErrorHandler;
+use OCP\ILogger;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
+
+class ErrorHandlerTest extends TestCase {
+
+ /** @var MockObject */
+ private LoggerInterface $logger;
+
+ private ErrorHandler $errorHandler;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->logger = $this->createMock(LoggerInterface::class);
+ $this->errorHandler = new ErrorHandler(
+ $this->logger
+ );
+ }
/**
* provide username, password combinations for testRemovePassword
@@ -47,24 +69,19 @@ class ErrorHandlerTest extends \Test\TestCase {
* @param string $username
* @param string $password
*/
- public function testRemovePassword($username, $password) {
+ public function testRemovePasswordFromError($username, $password) {
$url = 'http://'.$username.':'.$password.'@owncloud.org';
$expectedResult = 'http://xxx:xxx@owncloud.org';
- $result = TestableErrorHandler::testRemovePassword($url);
+ $this->logger->expects(self::once())
+ ->method('log')
+ ->with(
+ ILogger::ERROR,
+ 'Could not reach ' . $expectedResult . ' at file#4',
+ ['app' => 'PHP'],
+ );
- $this->assertEquals($expectedResult, $result);
- }
-}
+ $result = $this->errorHandler->onError(E_USER_ERROR, 'Could not reach ' . $url, 'file', 4);
-/**
- * dummy class to access protected methods of \OC\Log\ErrorHandler
- */
-class TestableErrorHandler extends \OC\Log\ErrorHandler {
-
- /**
- * @param string $msg
- */
- public static function testRemovePassword($msg) {
- return self::removePassword($msg);
+ self::assertTrue($result);
}
}
diff --git a/tests/lib/Files/ObjectStore/ObjectStoreStorageOverwrite.php b/tests/lib/Files/ObjectStore/ObjectStoreStorageOverwrite.php
index 5872056e42d..b85f6289c94 100644
--- a/tests/lib/Files/ObjectStore/ObjectStoreStorageOverwrite.php
+++ b/tests/lib/Files/ObjectStore/ObjectStoreStorageOverwrite.php
@@ -37,4 +37,8 @@ class ObjectStoreStorageOverwrite extends ObjectStoreStorage {
public function getObjectStore(): IObjectStore {
return $this->objectStore;
}
+
+ public function setValidateWrites(bool $validate) {
+ $this->validateWrites = $validate;
+ }
}
diff --git a/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php b/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php
index 5ebfd48d1a6..1bebaf6c4ba 100644
--- a/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php
+++ b/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php
@@ -181,6 +181,15 @@ class ObjectStoreStorageTest extends Storage {
$this->assertFalse($this->instance->file_exists('test.txt'));
}
+ public function testWriteObjectSilentFailureNoCheck() {
+ $objectStore = $this->instance->getObjectStore();
+ $this->instance->setObjectStore(new FailWriteObjectStore($objectStore));
+ $this->instance->setValidateWrites(false);
+
+ $this->instance->file_put_contents('test.txt', 'foo');
+ $this->assertTrue($this->instance->file_exists('test.txt'));
+ }
+
public function testDeleteObjectFailureKeepCache() {
$objectStore = $this->instance->getObjectStore();
$this->instance->setObjectStore(new FailDeleteObjectStore($objectStore));
diff --git a/tests/lib/Http/Client/ClientServiceTest.php b/tests/lib/Http/Client/ClientServiceTest.php
index 94f4d51ecee..ed1165236aa 100644
--- a/tests/lib/Http/Client/ClientServiceTest.php
+++ b/tests/lib/Http/Client/ClientServiceTest.php
@@ -1,4 +1,7 @@
<?php
+
+declare(strict_types=1);
+
/**
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
@@ -14,9 +17,9 @@ use GuzzleHttp\Handler\CurlHandler;
use OC\Http\Client\Client;
use OC\Http\Client\ClientService;
use OC\Http\Client\DnsPinMiddleware;
-use OC\Http\Client\LocalAddressChecker;
use OCP\ICertificateManager;
use OCP\IConfig;
+use OCP\Security\IRemoteHostValidator;
/**
* Class ClientServiceTest
@@ -33,13 +36,13 @@ class ClientServiceTest extends \Test\TestCase {
->method('addDnsPinning')
->willReturn(function () {
});
- $localAddressChecker = $this->createMock(LocalAddressChecker::class);
+ $remoteHostValidator = $this->createMock(IRemoteHostValidator::class);
$clientService = new ClientService(
$config,
$certificateManager,
$dnsPinMiddleware,
- $localAddressChecker
+ $remoteHostValidator
);
$handler = new CurlHandler();
@@ -52,7 +55,7 @@ class ClientServiceTest extends \Test\TestCase {
$config,
$certificateManager,
$guzzleClient,
- $localAddressChecker
+ $remoteHostValidator
),
$clientService->newClient()
);
diff --git a/tests/lib/Http/Client/ClientTest.php b/tests/lib/Http/Client/ClientTest.php
index 25d4749df57..93948a5daf3 100644
--- a/tests/lib/Http/Client/ClientTest.php
+++ b/tests/lib/Http/Client/ClientTest.php
@@ -1,4 +1,7 @@
<?php
+
+declare(strict_types=1);
+
/**
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
@@ -10,12 +13,13 @@ namespace Test\Http\Client;
use GuzzleHttp\Psr7\Response;
use OC\Http\Client\Client;
-use OC\Http\Client\LocalAddressChecker;
use OC\Security\CertificateManager;
use OCP\Http\Client\LocalServerException;
use OCP\ICertificateManager;
use OCP\IConfig;
+use OCP\Security\IRemoteHostValidator;
use PHPUnit\Framework\MockObject\MockObject;
+use function parse_url;
/**
* Class ClientTest
@@ -29,8 +33,8 @@ class ClientTest extends \Test\TestCase {
private $client;
/** @var IConfig|MockObject */
private $config;
- /** @var LocalAddressChecker|MockObject */
- private $localAddressChecker;
+ /** @var IRemoteHostValidator|MockObject */
+ private IRemoteHostValidator $remoteHostValidator;
/** @var array */
private $defaultRequestOptions;
@@ -39,12 +43,12 @@ class ClientTest extends \Test\TestCase {
$this->config = $this->createMock(IConfig::class);
$this->guzzleClient = $this->createMock(\GuzzleHttp\Client::class);
$this->certificateManager = $this->createMock(ICertificateManager::class);
- $this->localAddressChecker = $this->createMock(LocalAddressChecker::class);
+ $this->remoteHostValidator = $this->createMock(IRemoteHostValidator::class);
$this->client = new Client(
$this->config,
$this->certificateManager,
$this->guzzleClient,
- $this->localAddressChecker
+ $this->remoteHostValidator
);
}
@@ -146,22 +150,22 @@ class ClientTest extends \Test\TestCase {
public function dataPreventLocalAddress():array {
return [
- ['localhost/foo.bar'],
- ['localHost/foo.bar'],
- ['random-host/foo.bar'],
- ['[::1]/bla.blub'],
- ['[::]/bla.blub'],
- ['192.168.0.1'],
- ['172.16.42.1'],
- ['[fdf8:f53b:82e4::53]/secret.ics'],
- ['[fe80::200:5aee:feaa:20a2]/secret.ics'],
- ['[0:0:0:0:0:0:10.0.0.1]/secret.ics'],
- ['[0:0:0:0:0:ffff:127.0.0.0]/secret.ics'],
- ['10.0.0.1'],
- ['another-host.local'],
- ['service.localhost'],
- ['!@#$'], // test invalid url
- ['normal.host.com'],
+ ['https://localhost/foo.bar'],
+ ['https://localHost/foo.bar'],
+ ['https://random-host/foo.bar'],
+ ['https://[::1]/bla.blub'],
+ ['https://[::]/bla.blub'],
+ ['https://192.168.0.1'],
+ ['https://172.16.42.1'],
+ ['https://[fdf8:f53b:82e4::53]/secret.ics'],
+ ['https://[fe80::200:5aee:feaa:20a2]/secret.ics'],
+ ['https://[0:0:0:0:0:0:10.0.0.1]/secret.ics'],
+ ['https://[0:0:0:0:0:ffff:127.0.0.0]/secret.ics'],
+ ['https://10.0.0.1'],
+ ['https://another-host.local'],
+ ['https://service.localhost'],
+ ['!@#$', true], // test invalid url
+ ['https://normal.host.com'],
];
}
@@ -175,9 +179,7 @@ class ClientTest extends \Test\TestCase {
->with('allow_local_remote_servers', false)
->willReturn(true);
-// $this->expectException(LocalServerException::class);
-
- self::invokePrivate($this->client, 'preventLocalAddress', ['http://' . $uri, []]);
+ self::invokePrivate($this->client, 'preventLocalAddress', [$uri, []]);
}
/**
@@ -188,9 +190,7 @@ class ClientTest extends \Test\TestCase {
$this->config->expects($this->never())
->method('getSystemValueBool');
-// $this->expectException(LocalServerException::class);
-
- self::invokePrivate($this->client, 'preventLocalAddress', ['http://' . $uri, [
+ self::invokePrivate($this->client, 'preventLocalAddress', [$uri, [
'nextcloud' => ['allow_local_address' => true],
]]);
}
@@ -200,14 +200,14 @@ class ClientTest extends \Test\TestCase {
* @param string $uri
*/
public function testPreventLocalAddressOnGet(string $uri): void {
+ $host = parse_url($uri, PHP_URL_HOST);
$this->expectException(LocalServerException::class);
- $this->localAddressChecker
- ->expects($this->once())
- ->method('ThrowIfLocalAddress')
- ->with('http://' . $uri)
- ->will($this->throwException(new LocalServerException()));
+ $this->remoteHostValidator
+ ->method('isValid')
+ ->with($host)
+ ->willReturn(false);
- $this->client->get('http://' . $uri);
+ $this->client->get($uri);
}
/**
@@ -215,14 +215,14 @@ class ClientTest extends \Test\TestCase {
* @param string $uri
*/
public function testPreventLocalAddressOnHead(string $uri): void {
+ $host = parse_url($uri, PHP_URL_HOST);
$this->expectException(LocalServerException::class);
- $this->localAddressChecker
- ->expects($this->once())
- ->method('ThrowIfLocalAddress')
- ->with('http://' . $uri)
- ->will($this->throwException(new LocalServerException()));
+ $this->remoteHostValidator
+ ->method('isValid')
+ ->with($host)
+ ->willReturn(false);
- $this->client->head('http://' . $uri);
+ $this->client->head($uri);
}
/**
@@ -230,14 +230,14 @@ class ClientTest extends \Test\TestCase {
* @param string $uri
*/
public function testPreventLocalAddressOnPost(string $uri): void {
+ $host = parse_url($uri, PHP_URL_HOST);
$this->expectException(LocalServerException::class);
- $this->localAddressChecker
- ->expects($this->once())
- ->method('ThrowIfLocalAddress')
- ->with('http://' . $uri)
- ->will($this->throwException(new LocalServerException()));
+ $this->remoteHostValidator
+ ->method('isValid')
+ ->with($host)
+ ->willReturn(false);
- $this->client->post('http://' . $uri);
+ $this->client->post($uri);
}
/**
@@ -245,14 +245,14 @@ class ClientTest extends \Test\TestCase {
* @param string $uri
*/
public function testPreventLocalAddressOnPut(string $uri): void {
+ $host = parse_url($uri, PHP_URL_HOST);
$this->expectException(LocalServerException::class);
- $this->localAddressChecker
- ->expects($this->once())
- ->method('ThrowIfLocalAddress')
- ->with('http://' . $uri)
- ->will($this->throwException(new LocalServerException()));
+ $this->remoteHostValidator
+ ->method('isValid')
+ ->with($host)
+ ->willReturn(false);
- $this->client->put('http://' . $uri);
+ $this->client->put($uri);
}
/**
@@ -260,14 +260,14 @@ class ClientTest extends \Test\TestCase {
* @param string $uri
*/
public function testPreventLocalAddressOnDelete(string $uri): void {
+ $host = parse_url($uri, PHP_URL_HOST);
$this->expectException(LocalServerException::class);
- $this->localAddressChecker
- ->expects($this->once())
- ->method('ThrowIfLocalAddress')
- ->with('http://' . $uri)
- ->will($this->throwException(new LocalServerException()));
+ $this->remoteHostValidator
+ ->method('isValid')
+ ->with($host)
+ ->willReturn(false);
- $this->client->delete('http://' . $uri);
+ $this->client->delete($uri);
}
private function setUpDefaultRequestOptions(): void {
diff --git a/tests/lib/Http/Client/LocalAddressCheckerTest.php b/tests/lib/Http/Client/LocalAddressCheckerTest.php
deleted file mode 100644
index 8c8e64eddf9..00000000000
--- a/tests/lib/Http/Client/LocalAddressCheckerTest.php
+++ /dev/null
@@ -1,158 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright Copyright (c) 2021, Lukas Reschke <lukas@statuscode.ch>
- *
- * @author Lukas Reschke <lukas@statuscode.ch>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-namespace Test\Http\Client;
-
-use OCP\Http\Client\LocalServerException;
-use OC\Http\Client\LocalAddressChecker;
-use Psr\Log\LoggerInterface;
-
-class LocalAddressCheckerTest extends \Test\TestCase {
- /** @var LocalAddressChecker */
- private $localAddressChecker;
-
- protected function setUp(): void {
- parent::setUp();
-
- $logger = $this->createMock(LoggerInterface::class);
- $this->localAddressChecker = new LocalAddressChecker($logger);
- }
-
- /**
- * @dataProvider dataPreventLocalAddress
- * @param string $uri
- */
- public function testThrowIfLocalAddress($uri) : void {
- $this->expectException(LocalServerException::class);
- $this->localAddressChecker->ThrowIfLocalAddress('http://' . $uri);
- }
-
- /**
- * @dataProvider dataAllowLocalAddress
- * @param string $uri
- */
- public function testThrowIfLocalAddressGood($uri) : void {
- $this->localAddressChecker->ThrowIfLocalAddress('http://' . $uri);
- $this->assertTrue(true);
- }
-
-
- /**
- * @dataProvider dataInternalIPs
- * @param string $ip
- */
- public function testThrowIfLocalIpBad($ip) : void {
- $this->expectException(LocalServerException::class);
- $this->localAddressChecker->ThrowIfLocalIp($ip);
- }
-
- /**
- * @dataProvider dataPublicIPs
- * @param string $ip
- */
- public function testThrowIfLocalIpGood($ip) : void {
- $this->localAddressChecker->ThrowIfLocalIp($ip);
- $this->assertTrue(true);
- }
-
- public function dataPublicIPs() : array {
- return [
- ['8.8.8.8'],
- ['8.8.4.4'],
- ['2001:4860:4860::8888'],
- ['2001:4860:4860::8844'],
- ];
- }
-
- public function dataInternalIPs() : array {
- return [
- ['192.168.0.1'],
- ['fe80::200:5aee:feaa:20a2'],
- ['0:0:0:0:0:ffff:10.0.0.1'],
- ['0:0:0:0:0:ffff:127.0.0.0'],
- ['10.0.0.1'],
- ['::'],
- ['::1'],
- ['100.100.100.200'],
- ['192.0.0.1'],
- ];
- }
-
- public function dataPreventLocalAddress():array {
- return [
- ['localhost/foo.bar'],
- ['localHost/foo.bar'],
- ['random-host/foo.bar'],
- ['[::1]/bla.blub'],
- ['[::]/bla.blub'],
- ['192.168.0.1'],
- ['172.16.42.1'],
- ['[fdf8:f53b:82e4::53]/secret.ics'],
- ['[fe80::200:5aee:feaa:20a2]/secret.ics'],
- ['[0:0:0:0:0:ffff:10.0.0.1]/secret.ics'],
- ['[0:0:0:0:0:ffff:127.0.0.0]/secret.ics'],
- ['10.0.0.1'],
- ['another-host.local'],
- ['service.localhost'],
- ['!@#$'], // test invalid url
- ['100.100.100.200'],
- ['192.0.0.1'],
- ['randomdomain.internal'],
- ['0177.0.0.9'],
- ['⑯⑨。②⑤④。⑯⑨。②⑤④'],
- ['127。②⑤④。⑯⑨.②⑤④'],
- ['127.0.00000000000000000000000000000000001'],
- ['127.1'],
- ['127.000.001'],
- ['0177.0.0.01'],
- ['0x7f.0x0.0x0.0x1'],
- ['0x7f000001'],
- ['2130706433'],
- ['00000000000000000000000000000000000000000000000000177.1'],
- ['0x7f.1'],
- ['127.0x1'],
- ['[0000:0000:0000:0000:0000:0000:0000:0001]'],
- ['[0:0:0:0:0:0:0:1]'],
- ['[0:0:0:0::0:0:1]'],
- ['%31%32%37%2E%30%2E%30%2E%31'],
- ['%31%32%37%2E%30%2E%30.%31'],
- ['[%3A%3A%31]'],
- ];
- }
-
- public function dataAllowLocalAddress():array {
- return [
- ['example.com/foo.bar'],
- ['example.net/foo.bar'],
- ['example.org/foo.bar'],
- ['8.8.8.8/bla.blub'],
- ['8.8.4.4/bla.blub'],
- ['8.8.8.8'],
- ['8.8.4.4'],
- ['[2001:4860:4860::8888]/secret.ics'],
- ];
- }
-}
diff --git a/tests/lib/Net/HostnameClassifierTest.php b/tests/lib/Net/HostnameClassifierTest.php
new file mode 100644
index 00000000000..f363a08bb8a
--- /dev/null
+++ b/tests/lib/Net/HostnameClassifierTest.php
@@ -0,0 +1,78 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * @copyright 2022 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2022 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace lib\Net;
+
+use OC\Net\HostnameClassifier;
+use Test\TestCase;
+
+class HostnameClassifierTest extends TestCase {
+ private HostnameClassifier $classifier;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->classifier = new HostnameClassifier();
+ }
+
+ public function localHostnamesData():array {
+ return [
+ ['localhost'],
+ ['localHost'],
+ ['random-host'],
+ ['another-host.local'],
+ ['service.localhost'],
+ ['randomdomain.internal'],
+ ];
+ }
+
+ /**
+ * @dataProvider localHostnamesData
+ */
+ public function testLocalHostname(string $host): void {
+ $isLocal = $this->classifier->isLocalHostname($host);
+
+ self::assertTrue($isLocal);
+ }
+
+ public function publicHostnamesData(): array {
+ return [
+ ['example.com'],
+ ['example.net'],
+ ['example.org'],
+ ['host.domain'],
+ ['cloud.domain.tld'],
+ ];
+ }
+
+ /**
+ * @dataProvider publicHostnamesData
+ */
+ public function testPublicHostname(string $host): void {
+ $isLocal = $this->classifier->isLocalHostname($host);
+
+ self::assertFalse($isLocal);
+ }
+}
diff --git a/tests/lib/Net/IpAddressClassifierTest.php b/tests/lib/Net/IpAddressClassifierTest.php
new file mode 100644
index 00000000000..593abcd2b40
--- /dev/null
+++ b/tests/lib/Net/IpAddressClassifierTest.php
@@ -0,0 +1,80 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * @copyright 2022 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2022 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace lib\Net;
+
+use OC\Net\IpAddressClassifier;
+use Test\TestCase;
+
+class IpAddressClassifierTest extends TestCase {
+ private IpAddressClassifier $classifier;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->classifier = new IpAddressClassifier();
+ }
+
+ public function publicIpAddressData(): array {
+ return [
+ ['8.8.8.8'],
+ ['8.8.4.4'],
+ ['2001:4860:4860::8888'],
+ ['2001:4860:4860::8844'],
+ ];
+ }
+
+ /**
+ * @dataProvider publicIpAddressData
+ */
+ public function testPublicAddress(string $ip): void {
+ $isLocal = $this->classifier->isLocalAddress($ip);
+
+ self::assertFalse($isLocal);
+ }
+
+ public function localIpAddressData(): array {
+ return [
+ ['192.168.0.1'],
+ ['fe80::200:5aee:feaa:20a2'],
+ ['0:0:0:0:0:ffff:10.0.0.1'],
+ ['0:0:0:0:0:ffff:127.0.0.0'],
+ ['10.0.0.1'],
+ ['::'],
+ ['::1'],
+ ['100.100.100.200'],
+ ['192.0.0.1'],
+ ];
+ }
+
+ /**
+ * @dataProvider localIpAddressData
+ */
+ public function testLocalAddress(string $ip): void {
+ $isLocal = $this->classifier->isLocalAddress($ip);
+
+ self::assertTrue($isLocal);
+ }
+}
diff --git a/tests/lib/Preview/GeneratorTest.php b/tests/lib/Preview/GeneratorTest.php
index 1e38afd7744..0dec1aaafa8 100644
--- a/tests/lib/Preview/GeneratorTest.php
+++ b/tests/lib/Preview/GeneratorTest.php
@@ -25,6 +25,7 @@ namespace Test\Preview;
use OC\Preview\Generator;
use OC\Preview\GeneratorHelper;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\File;
use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
@@ -32,6 +33,7 @@ use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\IConfig;
use OCP\IPreview;
+use OCP\Preview\BeforePreviewFetchedEvent;
use OCP\Preview\IProviderV2;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
@@ -50,9 +52,12 @@ class GeneratorTest extends \Test\TestCase {
/** @var GeneratorHelper|\PHPUnit\Framework\MockObject\MockObject */
private $helper;
- /** @var EventDispatcherInterface|\PHPUnit\Framework\MockObject\MockObject */
+ /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
private $eventDispatcher;
+ /** @var EventDispatcherInterface|\PHPUnit\Framework\MockObject\MockObject */
+ private $legacyEventDispatcher;
+
/** @var Generator */
private $generator;
@@ -63,13 +68,15 @@ class GeneratorTest extends \Test\TestCase {
$this->previewManager = $this->createMock(IPreview::class);
$this->appData = $this->createMock(IAppData::class);
$this->helper = $this->createMock(GeneratorHelper::class);
- $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
+ $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
+ $this->legacyEventDispatcher = $this->createMock(EventDispatcherInterface::class);
$this->generator = new Generator(
$this->config,
$this->previewManager,
$this->appData,
$this->helper,
+ $this->legacyEventDispatcher,
$this->eventDispatcher
);
}
@@ -109,7 +116,7 @@ class GeneratorTest extends \Test\TestCase {
->with($this->equalTo('256-256.png'))
->willReturn($previewFile);
- $this->eventDispatcher->expects($this->once())
+ $this->legacyEventDispatcher->expects($this->once())
->method('dispatch')
->with(
$this->equalTo(IPreview::EVENT),
@@ -120,6 +127,10 @@ class GeneratorTest extends \Test\TestCase {
})
);
+ $this->eventDispatcher->expects($this->once())
+ ->method('dispatchTyped')
+ ->with(new BeforePreviewFetchedEvent($file));
+
$result = $this->generator->getPreview($file, 100, 100);
$this->assertSame($previewFile, $result);
}
@@ -239,7 +250,7 @@ class GeneratorTest extends \Test\TestCase {
->method('putContent')
->with('my resized data');
- $this->eventDispatcher->expects($this->once())
+ $this->legacyEventDispatcher->expects($this->once())
->method('dispatch')
->with(
$this->equalTo(IPreview::EVENT),
@@ -250,6 +261,10 @@ class GeneratorTest extends \Test\TestCase {
})
);
+ $this->eventDispatcher->expects($this->once())
+ ->method('dispatchTyped')
+ ->with(new BeforePreviewFetchedEvent($file));
+
$result = $this->generator->getPreview($file, 100, 100);
$this->assertSame($previewFile, $result);
}
@@ -285,7 +300,7 @@ class GeneratorTest extends \Test\TestCase {
->with($this->equalTo('1024-512-crop.png'))
->willThrowException(new NotFoundException());
- $this->eventDispatcher->expects($this->once())
+ $this->legacyEventDispatcher->expects($this->once())
->method('dispatch')
->with(
$this->equalTo(IPreview::EVENT),
@@ -298,6 +313,10 @@ class GeneratorTest extends \Test\TestCase {
})
);
+ $this->eventDispatcher->expects($this->once())
+ ->method('dispatchTyped')
+ ->with(new BeforePreviewFetchedEvent($file));
+
$this->generator->getPreview($file, 1024, 512, true, IPreview::MODE_COVER, 'invalidType');
}
@@ -333,7 +352,7 @@ class GeneratorTest extends \Test\TestCase {
$this->previewManager->expects($this->never())
->method('isMimeSupported');
- $this->eventDispatcher->expects($this->once())
+ $this->legacyEventDispatcher->expects($this->once())
->method('dispatch')
->with(
$this->equalTo(IPreview::EVENT),
@@ -346,6 +365,10 @@ class GeneratorTest extends \Test\TestCase {
})
);
+ $this->eventDispatcher->expects($this->once())
+ ->method('dispatchTyped')
+ ->with(new BeforePreviewFetchedEvent($file));
+
$result = $this->generator->getPreview($file, 1024, 512, true, IPreview::MODE_COVER, 'invalidType');
$this->assertSame($preview, $result);
}
@@ -370,7 +393,7 @@ class GeneratorTest extends \Test\TestCase {
$this->previewManager->method('getProviders')
->willReturn([]);
- $this->eventDispatcher->expects($this->once())
+ $this->legacyEventDispatcher->expects($this->once())
->method('dispatch')
->with(
$this->equalTo(IPreview::EVENT),
@@ -381,6 +404,10 @@ class GeneratorTest extends \Test\TestCase {
})
);
+ $this->eventDispatcher->expects($this->once())
+ ->method('dispatchTyped')
+ ->with(new BeforePreviewFetchedEvent($file));
+
$this->expectException(NotFoundException::class);
$this->generator->getPreview($file, 100, 100);
}
@@ -502,7 +529,7 @@ class GeneratorTest extends \Test\TestCase {
->with($this->equalTo($filename))
->willReturn($preview);
- $this->eventDispatcher->expects($this->once())
+ $this->legacyEventDispatcher->expects($this->once())
->method('dispatch')
->with(
$this->equalTo(IPreview::EVENT),
@@ -515,6 +542,10 @@ class GeneratorTest extends \Test\TestCase {
})
);
+ $this->eventDispatcher->expects($this->once())
+ ->method('dispatchTyped')
+ ->with(new BeforePreviewFetchedEvent($file));
+
$result = $this->generator->getPreview($file, $reqX, $reqY, $crop, $mode);
if ($expectedX === $maxX && $expectedY === $maxY) {
$this->assertSame($maxPreview, $result);
diff --git a/tests/lib/Security/RemoteHostValidatorIntegrationTest.php b/tests/lib/Security/RemoteHostValidatorIntegrationTest.php
new file mode 100644
index 00000000000..73cbbd7b0e8
--- /dev/null
+++ b/tests/lib/Security/RemoteHostValidatorIntegrationTest.php
@@ -0,0 +1,144 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * @copyright 2022 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2022 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace lib\Security;
+
+use OC\Net\HostnameClassifier;
+use OC\Net\IpAddressClassifier;
+use OC\Security\RemoteHostValidator;
+use OCP\IConfig;
+use OCP\Server;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\NullLogger;
+use Test\TestCase;
+
+class RemoteHostValidatorIntegrationTest extends TestCase {
+
+ /** @var IConfig|IConfig&MockObject|MockObject */
+ private IConfig $config;
+ private RemoteHostValidator $validator;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ // Mock config to avoid any side effects
+ $this->config = $this->createMock(IConfig::class);
+
+ $this->validator = new RemoteHostValidator(
+ $this->config,
+ Server::get(HostnameClassifier::class),
+ Server::get(IpAddressClassifier::class),
+ new NullLogger(),
+ );
+ }
+
+ public function localHostsData(): array {
+ return [
+ ['[::1]'],
+ ['[::]'],
+ ['192.168.0.1'],
+ ['172.16.42.1'],
+ ['[fdf8:f53b:82e4::53]'],
+ ['[fe80::200:5aee:feaa:20a2]'],
+ ['[0:0:0:0:0:ffff:10.0.0.1]'],
+ ['[0:0:0:0:0:ffff:127.0.0.0]'],
+ ['10.0.0.1'],
+ ['!@#$'], // test invalid url
+ ['100.100.100.200'],
+ ['192.0.0.1'],
+ ['0177.0.0.9'],
+ ['⑯⑨。②⑤④。⑯⑨。②⑤④'],
+ ['127。②⑤④。⑯⑨.②⑤④'],
+ ['127.0.00000000000000000000000000000000001'],
+ ['127.1'],
+ ['127.000.001'],
+ ['0177.0.0.01'],
+ ['0x7f.0x0.0x0.0x1'],
+ ['0x7f000001'],
+ ['2130706433'],
+ ['00000000000000000000000000000000000000000000000000177.1'],
+ ['0x7f.1'],
+ ['127.0x1'],
+ ['[0000:0000:0000:0000:0000:0000:0000:0001]'],
+ ['[0:0:0:0:0:0:0:1]'],
+ ['[0:0:0:0::0:0:1]'],
+ ['%31%32%37%2E%30%2E%30%2E%31'],
+ ['%31%32%37%2E%30%2E%30.%31'],
+ ['[%3A%3A%31]'],
+ ];
+ }
+
+ /**
+ * @dataProvider localHostsData
+ */
+ public function testLocalHostsWhenNotAllowed(string $host): void {
+ $this->config
+ ->method('getSystemValueBool')
+ ->with('allow_local_remote_servers', false)
+ ->willReturn(false);
+
+ $isValid = $this->validator->isValid($host);
+
+ self::assertFalse($isValid);
+ }
+
+ /**
+ * @dataProvider localHostsData
+ */
+ public function testLocalHostsWhenAllowed(string $host): void {
+ $this->config
+ ->method('getSystemValueBool')
+ ->with('allow_local_remote_servers', false)
+ ->willReturn(true);
+
+ $isValid = $this->validator->isValid($host);
+
+ self::assertTrue($isValid);
+ }
+
+ public function externalAddressesData():array {
+ return [
+ ['8.8.8.8'],
+ ['8.8.4.4'],
+ ['8.8.8.8'],
+ ['8.8.4.4'],
+ ['[2001:4860:4860::8888]'],
+ ];
+ }
+
+ /**
+ * @dataProvider externalAddressesData
+ */
+ public function testExternalHost(string $host): void {
+ $this->config
+ ->method('getSystemValueBool')
+ ->with('allow_local_remote_servers', false)
+ ->willReturn(false);
+
+ $isValid = $this->validator->isValid($host);
+
+ self::assertTrue($isValid);
+ }
+}
diff --git a/tests/lib/Security/RemoteHostValidatorTest.php b/tests/lib/Security/RemoteHostValidatorTest.php
new file mode 100644
index 00000000000..acaa7a4be30
--- /dev/null
+++ b/tests/lib/Security/RemoteHostValidatorTest.php
@@ -0,0 +1,111 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * @copyright 2022 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2022 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace lib\Security;
+
+use OC\Net\HostnameClassifier;
+use OC\Net\IpAddressClassifier;
+use OC\Security\RemoteHostValidator;
+use OCP\IConfig;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
+use Test\TestCase;
+
+class RemoteHostValidatorTest extends TestCase {
+
+ /** @var IConfig|IConfig&MockObject|MockObject */
+ private IConfig $config;
+ /** @var HostnameClassifier|HostnameClassifier&MockObject|MockObject */
+ private HostnameClassifier $hostnameClassifier;
+ /** @var IpAddressClassifier|IpAddressClassifier&MockObject|MockObject */
+ private IpAddressClassifier $ipAddressClassifier;
+ /** @var MockObject|LoggerInterface|LoggerInterface&MockObject */
+ private LoggerInterface $logger;
+ private RemoteHostValidator $validator;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->config = $this->createMock(IConfig::class);
+ $this->hostnameClassifier = $this->createMock(HostnameClassifier::class);
+ $this->ipAddressClassifier = $this->createMock(IpAddressClassifier::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
+
+ $this->validator = new RemoteHostValidator(
+ $this->config,
+ $this->hostnameClassifier,
+ $this->ipAddressClassifier,
+ $this->logger,
+ );
+ }
+
+ public function testValid(): void {
+ $host = 'nextcloud.com';
+ $this->hostnameClassifier
+ ->method('isLocalHostname')
+ ->with($host)
+ ->willReturn(false);
+ $this->ipAddressClassifier
+ ->method('isLocalAddress')
+ ->with($host)
+ ->willReturn(false);
+
+ $valid = $this->validator->isValid($host);
+
+ self::assertTrue($valid);
+ }
+
+ public function testLocalHostname(): void {
+ $host = 'localhost';
+ $this->hostnameClassifier
+ ->method('isLocalHostname')
+ ->with($host)
+ ->willReturn(true);
+ $this->ipAddressClassifier
+ ->method('isLocalAddress')
+ ->with($host)
+ ->willReturn(false);
+
+ $valid = $this->validator->isValid($host);
+
+ self::assertFalse($valid);
+ }
+
+ public function testLocalAddress(): void {
+ $host = '10.0.0.10';
+ $this->hostnameClassifier
+ ->method('isLocalHostname')
+ ->with($host)
+ ->willReturn(false);
+ $this->ipAddressClassifier
+ ->method('isLocalAddress')
+ ->with($host)
+ ->willReturn(true);
+
+ $valid = $this->validator->isValid($host);
+
+ self::assertFalse($valid);
+ }
+}