зеркало из https://github.com/nextcloud/spreed.git
458 строки
17 KiB
PHP
458 строки
17 KiB
PHP
<?php
|
|
/**
|
|
* @copyright Copyright (c) 2016 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 OCA\Talk\Tests\php;
|
|
|
|
use OCA\Talk\Config;
|
|
use OCA\Talk\Events\GetTurnServersEvent;
|
|
use OCA\Talk\Tests\php\Mocks\GetTurnServerListener;
|
|
use OCA\Talk\Vendor\Firebase\JWT\JWT;
|
|
use OCA\Talk\Vendor\Firebase\JWT\Key;
|
|
use OCP\AppFramework\Utility\ITimeFactory;
|
|
use OCP\EventDispatcher\IEventDispatcher;
|
|
use OCP\IConfig;
|
|
use OCP\IGroupManager;
|
|
use OCP\IURLGenerator;
|
|
use OCP\IUser;
|
|
use OCP\IUserManager;
|
|
use OCP\Security\ISecureRandom;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use Test\TestCase;
|
|
|
|
class ConfigTest extends TestCase {
|
|
private function createConfig(IConfig $config) {
|
|
/** @var MockObject|ITimeFactory $timeFactory */
|
|
$timeFactory = $this->createMock(ITimeFactory::class);
|
|
/** @var MockObject|ISecureRandom $secureRandom */
|
|
$secureRandom = $this->createMock(ISecureRandom::class);
|
|
/** @var MockObject|IGroupManager $groupManager */
|
|
$groupManager = $this->createMock(IGroupManager::class);
|
|
/** @var MockObject|IUserManager $userManager */
|
|
$userManager = $this->createMock(IUserManager::class);
|
|
/** @var MockObject|IURLGenerator $urlGenerator */
|
|
$urlGenerator = $this->createMock(IURLGenerator::class);
|
|
/** @var MockObject|IEventDispatcher $dispatcher */
|
|
$dispatcher = $this->createMock(IEventDispatcher::class);
|
|
|
|
$helper = new Config($config, $secureRandom, $groupManager, $userManager, $urlGenerator, $timeFactory, $dispatcher);
|
|
return $helper;
|
|
}
|
|
|
|
public function testGetStunServers() {
|
|
$servers = [
|
|
'stun1.example.com:443',
|
|
'stun2.example.com:129',
|
|
];
|
|
|
|
/** @var MockObject|IConfig $config */
|
|
$config = $this->createMock(IConfig::class);
|
|
$config
|
|
->expects($this->once())
|
|
->method('getAppValue')
|
|
->with('spreed', 'stun_servers', json_encode(['stun.nextcloud.com:443']))
|
|
->willReturn(json_encode($servers));
|
|
$config
|
|
->expects($this->once())
|
|
->method('getSystemValueBool')
|
|
->with('has_internet_connection', true)
|
|
->willReturn(true);
|
|
|
|
$helper = $this->createConfig($config);
|
|
$this->assertSame($helper->getStunServers(), $servers);
|
|
}
|
|
|
|
public function testGetDefaultStunServer() {
|
|
/** @var MockObject|IConfig $config */
|
|
$config = $this->createMock(IConfig::class);
|
|
$config
|
|
->expects($this->once())
|
|
->method('getAppValue')
|
|
->with('spreed', 'stun_servers', json_encode(['stun.nextcloud.com:443']))
|
|
->willReturn(json_encode([]));
|
|
$config
|
|
->expects($this->once())
|
|
->method('getSystemValueBool')
|
|
->with('has_internet_connection', true)
|
|
->willReturn(true);
|
|
|
|
$helper = $this->createConfig($config);
|
|
$this->assertSame(['stun.nextcloud.com:443'], $helper->getStunServers());
|
|
}
|
|
|
|
public function testGetDefaultStunServerNoInternet() {
|
|
/** @var MockObject|IConfig $config */
|
|
$config = $this->createMock(IConfig::class);
|
|
$config
|
|
->expects($this->once())
|
|
->method('getAppValue')
|
|
->with('spreed', 'stun_servers', json_encode(['stun.nextcloud.com:443']))
|
|
->willReturn(json_encode([]));
|
|
$config
|
|
->expects($this->once())
|
|
->method('getSystemValueBool')
|
|
->with('has_internet_connection', true)
|
|
->willReturn(false);
|
|
|
|
$helper = $this->createConfig($config);
|
|
$this->assertSame([], $helper->getStunServers());
|
|
}
|
|
|
|
public function testGenerateTurnSettings() {
|
|
/** @var MockObject|IConfig $config */
|
|
$config = $this->createMock(IConfig::class);
|
|
$config
|
|
->expects($this->once())
|
|
->method('getAppValue')
|
|
->with('spreed', 'turn_servers', '')
|
|
->willReturn(json_encode([
|
|
[
|
|
// No scheme explicitly given
|
|
'server' => 'turn.example.org:3478',
|
|
'secret' => 'thisisasupersecretsecret',
|
|
'protocols' => 'udp,tcp',
|
|
],
|
|
[
|
|
'schemes' => 'turn,turns',
|
|
'server' => 'turn2.example.com:5349',
|
|
'secret' => 'ThisIsAlsoSuperSecret',
|
|
'protocols' => 'udp',
|
|
],
|
|
[
|
|
'schemes' => 'turns',
|
|
'server' => 'turn-tls.example.com:443',
|
|
'secret' => 'ThisIsAlsoSuperSecret',
|
|
'protocols' => 'tcp',
|
|
],
|
|
]));
|
|
|
|
/** @var MockObject|ITimeFactory $timeFactory */
|
|
$timeFactory = $this->createMock(ITimeFactory::class);
|
|
$timeFactory
|
|
->expects($this->once())
|
|
->method('getTime')
|
|
->willReturn(1479743025);
|
|
|
|
/** @var MockObject|IGroupManager $groupManager */
|
|
$groupManager = $this->createMock(IGroupManager::class);
|
|
/** @var MockObject|IUserManager $userManager */
|
|
$userManager = $this->createMock(IUserManager::class);
|
|
/** @var MockObject|IURLGenerator $urlGenerator */
|
|
$urlGenerator = $this->createMock(IURLGenerator::class);
|
|
/** @var MockObject|IEventDispatcher $dispatcher */
|
|
$dispatcher = $this->createMock(IEventDispatcher::class);
|
|
|
|
/** @var MockObject|ISecureRandom $secureRandom */
|
|
$secureRandom = $this->createMock(ISecureRandom::class);
|
|
$secureRandom
|
|
->expects($this->once())
|
|
->method('generate')
|
|
->with(16)
|
|
->willReturn('abcdefghijklmnop');
|
|
$helper = new Config($config, $secureRandom, $groupManager, $userManager, $urlGenerator, $timeFactory, $dispatcher);
|
|
|
|
//
|
|
$settings = $helper->getTurnSettings();
|
|
$this->assertEquals(3, count($settings));
|
|
$this->assertSame([
|
|
'schemes' => 'turn',
|
|
'server' => 'turn.example.org:3478',
|
|
'username' => '1479829425:abcdefghijklmnop',
|
|
'password' => '4VJLVbihLzuxgMfDrm5C3zy8kLQ=',
|
|
'protocols' => 'udp,tcp',
|
|
], $settings[0]);
|
|
$this->assertSame([
|
|
'schemes' => 'turn,turns',
|
|
'server' => 'turn2.example.com:5349',
|
|
'username' => '1479829425:abcdefghijklmnop',
|
|
'password' => 'Ol9DEqnvyN4g+IAM+vFnqhfWUTE=',
|
|
'protocols' => 'udp',
|
|
], $settings[1]);
|
|
$this->assertSame([
|
|
'schemes' => 'turns',
|
|
'server' => 'turn-tls.example.com:443',
|
|
'username' => '1479829425:abcdefghijklmnop',
|
|
'password' => 'Ol9DEqnvyN4g+IAM+vFnqhfWUTE=',
|
|
'protocols' => 'tcp',
|
|
], $settings[2]);
|
|
}
|
|
|
|
public function testGenerateTurnSettingsEmpty() {
|
|
/** @var MockObject|IConfig $config */
|
|
$config = $this->createMock(IConfig::class);
|
|
$config
|
|
->expects($this->once())
|
|
->method('getAppValue')
|
|
->with('spreed', 'turn_servers', '')
|
|
->willReturn(json_encode([]));
|
|
|
|
$helper = $this->createConfig($config);
|
|
|
|
$settings = $helper->getTurnSettings();
|
|
$this->assertEquals(0, count($settings));
|
|
}
|
|
|
|
public function testGenerateTurnSettingsEvent() {
|
|
/** @var MockObject|IConfig $config */
|
|
$config = $this->createMock(IConfig::class);
|
|
$config
|
|
->expects($this->once())
|
|
->method('getAppValue')
|
|
->with('spreed', 'turn_servers', '')
|
|
->willReturn(json_encode([]));
|
|
|
|
/** @var MockObject|ITimeFactory $timeFactory */
|
|
$timeFactory = $this->createMock(ITimeFactory::class);
|
|
|
|
/** @var MockObject|IGroupManager $groupManager */
|
|
$groupManager = $this->createMock(IGroupManager::class);
|
|
|
|
/** @var MockObject|IUserManager $userManager */
|
|
$userManager = $this->createMock(IUserManager::class);
|
|
|
|
/** @var MockObject|IURLGenerator $urlGenerator */
|
|
$urlGenerator = $this->createMock(IURLGenerator::class);
|
|
|
|
/** @var MockObject|ISecureRandom $secureRandom */
|
|
$secureRandom = $this->createMock(ISecureRandom::class);
|
|
|
|
/** @var IEventDispatcher $dispatcher */
|
|
$dispatcher = \OC::$server->get(IEventDispatcher::class);
|
|
|
|
$servers = [
|
|
[
|
|
'schemes' => 'turn',
|
|
'server' => 'turn.domain.invalid',
|
|
'username' => 'john',
|
|
'password' => 'abcde',
|
|
'protocols' => 'udp,tcp',
|
|
],
|
|
[
|
|
'schemes' => 'turns',
|
|
'server' => 'turns.domain.invalid',
|
|
'username' => 'jane',
|
|
'password' => 'ABCDE',
|
|
'protocols' => 'tcp',
|
|
],
|
|
];
|
|
|
|
$dispatcher->addServiceListener(GetTurnServersEvent::class, GetTurnServerListener::class);
|
|
|
|
$helper = new Config($config, $secureRandom, $groupManager, $userManager, $urlGenerator, $timeFactory, $dispatcher);
|
|
|
|
$settings = $helper->getTurnSettings();
|
|
$this->assertSame($servers, $settings);
|
|
}
|
|
|
|
public function dataGetWebSocketDomainForSignalingServer() {
|
|
return [
|
|
['http://blabla.nextcloud.com', 'ws://blabla.nextcloud.com'],
|
|
['http://blabla.nextcloud.com/', 'ws://blabla.nextcloud.com'],
|
|
['http://blabla.nextcloud.com/signaling', 'ws://blabla.nextcloud.com'],
|
|
['http://blabla.nextcloud.com/signaling/', 'ws://blabla.nextcloud.com'],
|
|
['http://blabla.nextcloud.com:80', 'ws://blabla.nextcloud.com:80'],
|
|
['http://blabla.nextcloud.com:80/', 'ws://blabla.nextcloud.com:80'],
|
|
['http://blabla.nextcloud.com:80/signaling', 'ws://blabla.nextcloud.com:80'],
|
|
['http://blabla.nextcloud.com:80/signaling/', 'ws://blabla.nextcloud.com:80'],
|
|
['http://blabla.nextcloud.com:8000', 'ws://blabla.nextcloud.com:8000'],
|
|
['http://blabla.nextcloud.com:8000/', 'ws://blabla.nextcloud.com:8000'],
|
|
['http://blabla.nextcloud.com:8000/signaling', 'ws://blabla.nextcloud.com:8000'],
|
|
['http://blabla.nextcloud.com:8000/signaling/', 'ws://blabla.nextcloud.com:8000'],
|
|
|
|
['https://blabla.nextcloud.com', 'wss://blabla.nextcloud.com'],
|
|
['https://blabla.nextcloud.com/', 'wss://blabla.nextcloud.com'],
|
|
['https://blabla.nextcloud.com/signaling', 'wss://blabla.nextcloud.com'],
|
|
['https://blabla.nextcloud.com/signaling/', 'wss://blabla.nextcloud.com'],
|
|
['https://blabla.nextcloud.com:443', 'wss://blabla.nextcloud.com:443'],
|
|
['https://blabla.nextcloud.com:443/', 'wss://blabla.nextcloud.com:443'],
|
|
['https://blabla.nextcloud.com:443/signaling', 'wss://blabla.nextcloud.com:443'],
|
|
['https://blabla.nextcloud.com:443/signaling/', 'wss://blabla.nextcloud.com:443'],
|
|
['https://blabla.nextcloud.com:8443', 'wss://blabla.nextcloud.com:8443'],
|
|
['https://blabla.nextcloud.com:8443/', 'wss://blabla.nextcloud.com:8443'],
|
|
['https://blabla.nextcloud.com:8443/signaling', 'wss://blabla.nextcloud.com:8443'],
|
|
['https://blabla.nextcloud.com:8443/signaling/', 'wss://blabla.nextcloud.com:8443'],
|
|
|
|
['ws://blabla.nextcloud.com', 'ws://blabla.nextcloud.com'],
|
|
['ws://blabla.nextcloud.com/', 'ws://blabla.nextcloud.com'],
|
|
['ws://blabla.nextcloud.com/signaling', 'ws://blabla.nextcloud.com'],
|
|
['ws://blabla.nextcloud.com/signaling/', 'ws://blabla.nextcloud.com'],
|
|
['ws://blabla.nextcloud.com:80', 'ws://blabla.nextcloud.com:80'],
|
|
['ws://blabla.nextcloud.com:80/', 'ws://blabla.nextcloud.com:80'],
|
|
['ws://blabla.nextcloud.com:80/signaling', 'ws://blabla.nextcloud.com:80'],
|
|
['ws://blabla.nextcloud.com:80/signaling/', 'ws://blabla.nextcloud.com:80'],
|
|
['ws://blabla.nextcloud.com:8000', 'ws://blabla.nextcloud.com:8000'],
|
|
['ws://blabla.nextcloud.com:8000/', 'ws://blabla.nextcloud.com:8000'],
|
|
['ws://blabla.nextcloud.com:8000/signaling', 'ws://blabla.nextcloud.com:8000'],
|
|
['ws://blabla.nextcloud.com:8000/signaling/', 'ws://blabla.nextcloud.com:8000'],
|
|
|
|
['wss://blabla.nextcloud.com', 'wss://blabla.nextcloud.com'],
|
|
['wss://blabla.nextcloud.com/', 'wss://blabla.nextcloud.com'],
|
|
['wss://blabla.nextcloud.com/signaling', 'wss://blabla.nextcloud.com'],
|
|
['wss://blabla.nextcloud.com/signaling/', 'wss://blabla.nextcloud.com'],
|
|
['wss://blabla.nextcloud.com:443', 'wss://blabla.nextcloud.com:443'],
|
|
['wss://blabla.nextcloud.com:443/', 'wss://blabla.nextcloud.com:443'],
|
|
['wss://blabla.nextcloud.com:443/signaling', 'wss://blabla.nextcloud.com:443'],
|
|
['wss://blabla.nextcloud.com:443/signaling/', 'wss://blabla.nextcloud.com:443'],
|
|
['wss://blabla.nextcloud.com:8443', 'wss://blabla.nextcloud.com:8443'],
|
|
['wss://blabla.nextcloud.com:8443/', 'wss://blabla.nextcloud.com:8443'],
|
|
['wss://blabla.nextcloud.com:8443/signaling', 'wss://blabla.nextcloud.com:8443'],
|
|
['wss://blabla.nextcloud.com:8443/signaling/', 'wss://blabla.nextcloud.com:8443'],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider dataGetWebSocketDomainForSignalingServer
|
|
* @param string $url
|
|
* @param string $expectedWebSocketDomain
|
|
*/
|
|
public function testGetWebSocketDomainForSignalingServer($url, $expectedWebSocketDomain) {
|
|
/** @var MockObject|IConfig $config */
|
|
$config = $this->createMock(IConfig::class);
|
|
|
|
$helper = $this->createConfig($config);
|
|
|
|
$this->assertEquals(
|
|
$expectedWebSocketDomain,
|
|
self::invokePrivate($helper, 'getWebSocketDomainForSignalingServer', [$url])
|
|
);
|
|
}
|
|
|
|
public function dataTicketV2Algorithm() {
|
|
return [
|
|
['ES384'],
|
|
['ES256'],
|
|
['RS256'],
|
|
['RS384'],
|
|
['RS512'],
|
|
['EdDSA'],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider dataTicketV2Algorithm
|
|
* @param string $algo
|
|
*/
|
|
public function testSignalingTicketV2User(string $algo): void {
|
|
/** @var IConfig $config */
|
|
$config = \OC::$server->getConfig();
|
|
/** @var MockObject|ITimeFactory $timeFactory */
|
|
$timeFactory = $this->createMock(ITimeFactory::class);
|
|
/** @var MockObject|ISecureRandom $secureRandom */
|
|
$secureRandom = $this->createMock(ISecureRandom::class);
|
|
/** @var MockObject|IGroupManager $groupManager */
|
|
$groupManager = $this->createMock(IGroupManager::class);
|
|
/** @var MockObject|IUserManager $userManager */
|
|
$userManager = $this->createMock(IUserManager::class);
|
|
/** @var MockObject|IURLGenerator $urlGenerator */
|
|
$urlGenerator = $this->createMock(IURLGenerator::class);
|
|
/** @var MockObject|IEventDispatcher $dispatcher */
|
|
$dispatcher = $this->createMock(IEventDispatcher::class);
|
|
/** @var MockObject|IUser $user */
|
|
$user = $this->createMock(IUser::class);
|
|
|
|
$now = time();
|
|
$timeFactory
|
|
->expects($this->once())
|
|
->method('getTime')
|
|
->willReturn($now);
|
|
$urlGenerator
|
|
->expects($this->once())
|
|
->method('getAbsoluteURL')
|
|
->with('')
|
|
->willReturn('https://domain.invalid/nextcloud');
|
|
$userManager
|
|
->expects($this->once())
|
|
->method('get')
|
|
->with('user1')
|
|
->willReturn($user);
|
|
$user
|
|
->expects($this->once())
|
|
->method('getUID')
|
|
->willReturn('user1');
|
|
$user
|
|
->expects($this->once())
|
|
->method('getDisplayName')
|
|
->willReturn('Jane Doe');
|
|
|
|
$helper = new Config($config, $secureRandom, $groupManager, $userManager, $urlGenerator, $timeFactory, $dispatcher);
|
|
|
|
$config->setAppValue('spreed', 'signaling_token_alg', $algo);
|
|
// Make sure new keys are generated.
|
|
$config->deleteAppValue('spreed', 'signaling_token_privkey_' . strtolower($algo));
|
|
$config->deleteAppValue('spreed', 'signaling_token_pubkey_' . strtolower($algo));
|
|
$ticket = $helper->getSignalingTicket(Config::SIGNALING_TICKET_V2, 'user1');
|
|
$this->assertNotNull($ticket);
|
|
|
|
$key = new Key($config->getAppValue('spreed', 'signaling_token_pubkey_' . strtolower($algo)), $algo);
|
|
$decoded = JWT::decode($ticket, $key);
|
|
|
|
$this->assertEquals($now, $decoded->iat);
|
|
$this->assertEquals('https://domain.invalid/nextcloud', $decoded->iss);
|
|
$this->assertEquals('user1', $decoded->sub);
|
|
$this->assertSame(['displayname' => 'Jane Doe'], (array) $decoded->userdata);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider dataTicketV2Algorithm
|
|
* @param string $algo
|
|
*/
|
|
public function testSignalingTicketV2Anonymous(string $algo): void {
|
|
/** @var IConfig $config */
|
|
$config = \OC::$server->getConfig();
|
|
/** @var MockObject|ITimeFactory $timeFactory */
|
|
$timeFactory = $this->createMock(ITimeFactory::class);
|
|
/** @var MockObject|ISecureRandom $secureRandom */
|
|
$secureRandom = $this->createMock(ISecureRandom::class);
|
|
/** @var MockObject|IGroupManager $groupManager */
|
|
$groupManager = $this->createMock(IGroupManager::class);
|
|
/** @var MockObject|IUserManager $userManager */
|
|
$userManager = $this->createMock(IUserManager::class);
|
|
/** @var MockObject|IURLGenerator $urlGenerator */
|
|
$urlGenerator = $this->createMock(IURLGenerator::class);
|
|
/** @var MockObject|IEventDispatcher $dispatcher */
|
|
$dispatcher = $this->createMock(IEventDispatcher::class);
|
|
|
|
$now = time();
|
|
$timeFactory
|
|
->expects($this->once())
|
|
->method('getTime')
|
|
->willReturn($now);
|
|
$urlGenerator
|
|
->expects($this->once())
|
|
->method('getAbsoluteURL')
|
|
->with('')
|
|
->willReturn('https://domain.invalid/nextcloud');
|
|
|
|
$helper = new Config($config, $secureRandom, $groupManager, $userManager, $urlGenerator, $timeFactory, $dispatcher);
|
|
|
|
$config->setAppValue('spreed', 'signaling_token_alg', $algo);
|
|
// Make sure new keys are generated.
|
|
$config->deleteAppValue('spreed', 'signaling_token_privkey_' . strtolower($algo));
|
|
$config->deleteAppValue('spreed', 'signaling_token_pubkey_' . strtolower($algo));
|
|
$ticket = $helper->getSignalingTicket(Config::SIGNALING_TICKET_V2, null);
|
|
$this->assertNotNull($ticket);
|
|
|
|
$key = new Key($config->getAppValue('spreed', 'signaling_token_pubkey_' . strtolower($algo)), $algo);
|
|
$decoded = JWT::decode($ticket, $key);
|
|
|
|
$this->assertEquals($now, $decoded->iat);
|
|
$this->assertEquals('https://domain.invalid/nextcloud', $decoded->iss);
|
|
}
|
|
}
|