Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/spreed.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoachim Bauch <bauch@struktur.de>2017-07-20 14:40:49 +0300
committerJoachim Bauch <bauch@struktur.de>2017-11-02 13:23:09 +0300
commitbe33ec8d9c30b1acd0336976fd64cc0dfff96c27 (patch)
treece9b5d73e3e3b34a5dcf44c004f4963c37edb6e2
parentd7ef5ef868060f497e6e69617f088c69dfbb6cc3 (diff)
Implement backend APIs to be used by standalone signaling server.
A standalone signaling server can be configured in the admin UI and is notified through the BackendController on changes that should be sent to connected clients. See #339 for a description of the backend API. Signed-off-by: Joachim Bauch <bauch@struktur.de>
-rw-r--r--appinfo/info.xml1
-rw-r--r--appinfo/routes.php8
-rw-r--r--js/admin/signaling-server.js43
-rw-r--r--lib/Config.php82
-rw-r--r--lib/Controller/BackendController.php183
-rw-r--r--lib/Controller/PageController.php12
-rw-r--r--lib/Controller/RoomController.php23
-rw-r--r--lib/Controller/SignalingController.php154
-rw-r--r--lib/Settings/Admin/SignalingServer.php68
-rw-r--r--templates/settings/admin/signaling-server.php24
10 files changed, 595 insertions, 3 deletions
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 1795b53b3..fdf9cd018 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -59,6 +59,7 @@ And in the works for the [coming versions](https://github.com/nextcloud/spreed/m
<settings>
<admin>OCA\Spreed\Settings\Admin\TurnServer</admin>
<admin>OCA\Spreed\Settings\Admin\StunServer</admin>
+ <admin>OCA\Spreed\Settings\Admin\SignalingServer</admin>
<admin-section>OCA\Spreed\Settings\Admin\Section</admin-section>
</settings>
diff --git a/appinfo/routes.php b/appinfo/routes.php
index d6bab70cc..c0aed8a5c 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -47,6 +47,14 @@ return [
],
],
[
+ 'name' => 'Signaling#backend',
+ 'url' => '/api/{apiVersion}/signaling/backend',
+ 'verb' => 'POST',
+ 'requirements' => [
+ 'apiVersion' => 'v1',
+ ],
+ ],
+ [
'name' => 'Call#getPeersForCall',
'url' => '/api/{apiVersion}/call/{token}',
'verb' => 'GET',
diff --git a/js/admin/signaling-server.js b/js/admin/signaling-server.js
new file mode 100644
index 000000000..d3e67a3ae
--- /dev/null
+++ b/js/admin/signaling-server.js
@@ -0,0 +1,43 @@
+/* global OC, OCP, OCA, $, _, Handlebars */
+
+(function(OC, OCP, OCA, $) {
+ 'use strict';
+
+ OCA.VideoCalls = OCA.VideoCalls || {};
+ OCA.VideoCalls.Admin = OCA.VideoCalls.Admin || {};
+ OCA.VideoCalls.Admin.SignalingServer = {
+
+ $signaling: undefined,
+
+ init: function() {
+ this.$signaling = $('div.signaling-server');
+ this.$signaling.find('input').on('change', this.saveServer);
+ },
+
+ saveServer: function() {
+ // this.$signaling.find('input').removeClass('error');
+ // this.$signaling.find('.icon-checkmark-color').addClass('hidden');
+
+ // OCP.AppConfig.setValue('spreed', $(this).attr('name'), $(this).value, {
+ // success: function() {
+ // self.temporaryShowSuccess($server);
+ // }
+ // });
+ },
+
+ temporaryShowSuccess: function($server) {
+ var $icon = $server.find('.icon-checkmark-color');
+ $icon.removeClass('hidden');
+ setTimeout(function() {
+ $icon.addClass('hidden');
+ }, 2000);
+ }
+
+ };
+
+
+})(OC, OCP, OCA, $);
+
+$(document).ready(function(){
+ OCA.VideoCalls.Admin.SignalingServer.init();
+});
diff --git a/lib/Config.php b/lib/Config.php
index c3bf358c5..5b9019854 100644
--- a/lib/Config.php
+++ b/lib/Config.php
@@ -23,6 +23,8 @@ namespace OCA\Spreed;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
+use OCP\IUser;
+use OCP\Security\ISecureRandom;
class Config {
@@ -32,14 +34,21 @@ class Config {
/** @var ITimeFactory */
protected $timeFactory;
+ /** @var ISecureRandom */
+ private $secureRandom;
+
/**
* Config constructor.
*
* @param IConfig $config
+ * @param ISecureRandom $secureRandom
* @param ITimeFactory $timeFactory
*/
- public function __construct(IConfig $config, ITimeFactory $timeFactory) {
+ public function __construct(IConfig $config,
+ ISecureRandom $secureRandom,
+ ITimeFactory $timeFactory) {
$this->config = $config;
+ $this->secureRandom = $secureRandom;
$this->timeFactory = $timeFactory;
}
@@ -96,4 +105,75 @@ class Config {
);
}
+ /**
+ * @return string
+ */
+ public function getSignalingServer() {
+ return $this->config->getAppValue('spreed', 'signaling_server', '');
+ }
+
+ /**
+ * @return string
+ */
+ public function getSignalingSecret() {
+ return $this->config->getAppValue('spreed', 'signaling_secret', '');
+ }
+
+ /**
+ * @param string $userId
+ * @return string
+ */
+ public function getSignalingTicket($userId) {
+ if (empty($userId)) {
+ $secret = $this->config->getAppValue('spreed', 'signaling_ticket_secret', '');
+ } else {
+ $secret = $this->config->getUserValue($userId, 'spreed', 'signaling_ticket_secret', '');
+ }
+ if (empty($secret)) {
+ // Create secret lazily on first access.
+ // TODO(fancycode): Is there a possibility for a race condition?
+ $secret = $this->secureRandom->generate(255);
+ if (empty($userId)) {
+ $this->config->setAppValue('spreed', 'signaling_ticket_secret', $secret);
+ } else {
+ $this->config->setUserValue($userId, 'spreed', 'signaling_ticket_secret', $secret);
+ }
+ }
+
+ // Format is "random:timestamp:userid:checksum" and "checksum" is the
+ // SHA256-HMAC of "random:timestamp:userid" with the per-user secret.
+ $random = $this->secureRandom->generate(16);
+ $timestamp = $this->timeFactory->getTime();
+ $data = $random . ':' . $timestamp . ':' . $userId;
+ $hash = hash_hmac('sha256', $data, $secret);
+ return $data . ':' . $hash;
+ }
+
+ /**
+ * @param string $userId
+ * @param string $ticket
+ * @return bool
+ */
+ public function validateSignalingTicket($userId, $ticket) {
+ if (empty($userId)) {
+ $secret = $this->config->getAppValue('spreed', 'signaling_ticket_secret', '');
+ } else {
+ $secret = $this->config->getUserValue($userId, 'spreed', 'signaling_ticket_secret', '');
+ }
+ if (empty($secret)) {
+ return false;
+ }
+
+ $lastcolon = strrpos($ticket, ':');
+ if ($lastcolon === false) {
+ // Immediately reject invalid formats.
+ return false;
+ }
+
+ // TODO(fancycode): Should we reject tickets that are too old?
+ $data = substr($ticket, 0, $lastcolon);
+ $hash = hash_hmac('sha256', $data, $secret);
+ return hash_equals($hash, substr($ticket, $lastcolon + 1));
+ }
+
}
diff --git a/lib/Controller/BackendController.php b/lib/Controller/BackendController.php
new file mode 100644
index 000000000..f27b4fcd4
--- /dev/null
+++ b/lib/Controller/BackendController.php
@@ -0,0 +1,183 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Joachim Bauch <bauch@struktur.de>
+ *
+ * @author Joachim Bauch <bauch@struktur.de>
+ *
+ * @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\Spreed\Controller;
+
+use OCA\Spreed\Config;
+use OCA\Spreed\Room;
+use OCP\AppFramework\Controller;
+use OCP\Http\Client\IClientService;
+use OCP\ILogger;
+use OCP\IRequest;
+use OCP\Security\ISecureRandom;
+
+class BackendController extends Controller {
+ /** @var Config */
+ private $config;
+ /** @var ILogger */
+ private $logger;
+ /** @var IClientService */
+ private $clientService;
+ /** @var ISecureRandom */
+ private $secureRandom;
+
+ /**
+ * @param string $appName
+ * @param IRequest $request
+ * @param IConfig $config
+ * @param ILogger $logger
+ * @param IClientService $clientService
+ */
+ public function __construct($appName,
+ IRequest $request,
+ Config $config,
+ ILogger $logger,
+ IClientService $clientService,
+ ISecureRandom $secureRandom) {
+ parent::__construct($appName, $request);
+ $this->config = $config;
+ $this->logger = $logger;
+ $this->clientService = $clientService;
+ $this->secureRandom = $secureRandom;
+ }
+
+ /**
+ * Perform a request to the signaling backend.
+ *
+ * @param string $url
+ * @param array $data
+ */
+ private function backendRequest($url, $data) {
+ $signaling = $this->config->getSignalingServer();
+ if (empty($signaling)) {
+ return;
+ }
+
+ if (substr($signaling, -1) === '/') {
+ $signaling = substr($signaling, 0, strlen($signaling) - 1);
+ }
+ $url = $signaling . $url;
+ if (substr($url, 0, 6) === 'wss://') {
+ $url = 'https://' . substr($url, 6);
+ } else if (substr($url, 0, 5) === 'ws://') {
+ $url = 'http://' . substr($url, 5);
+ }
+ $client = $this->clientService->newClient();
+ $body = json_encode($data);
+ $headers = [
+ 'Content-Type' => 'application/json',
+ ];
+
+ $random = $this->secureRandom->generate(64);
+ $hash = hash_hmac('sha256', $random . $body, $this->config->getSignalingSecret());
+ $headers['Spreed-Signaling-Random'] = $random;
+ $headers['Spreed-Signaling-Checksum'] = $hash;
+
+ $response = $client->post($url, [
+ 'headers' => $headers,
+ 'body' => $body,
+ 'verify' => false,
+ ]);
+ }
+
+ /**
+ * The given users are now invited to a room.
+ *
+ * @param Room $room
+ * @param array $userIds
+ */
+ public function roomInvited($room, $userIds) {
+ $this->logger->info("Now invited to " . $room->getToken() . ": " + print_r($userIds, true));
+ $this->backendRequest('/api/v1/room/' . $room->getToken(), [
+ 'type' => 'invite',
+ 'invite' => [
+ 'userids' => $userIds,
+ 'properties' => [
+ 'name' => $room->getName(),
+ 'type' => $room->getType(),
+ ],
+ ],
+ ]);
+ }
+
+ /**
+ * The given users are no longer invited to a room.
+ *
+ * @param Room $room
+ * @param array $userIds
+ */
+ public function roomsDisinvited($room, $userIds) {
+ $this->logger->info("No longer invited to " . $room->getToken() . ": " + print_r($userIds, true));
+ $this->backendRequest('/api/v1/room/' . $room->getToken(), [
+ 'type' => 'disinvite',
+ 'disinvite' => [
+ 'userids' => $userIds,
+ ],
+ ]);
+ }
+
+ /**
+ * The given room has been modified.
+ *
+ * @param Room $room
+ */
+ public function roomModified($room) {
+ $this->logger->info("Room modified: " . $room->getToken());
+ $participants = $room->getParticipants();
+ $userIds = [];
+ foreach ($participants['users'] as $participant => $data) {
+ array_push($userIds, $participant);
+ }
+ $this->backendRequest('/api/v1/room/' . $room->getToken(), [
+ 'type' => 'update',
+ 'update' => [
+ 'userids' => $userIds,
+ 'properties' => [
+ 'name' => $room->getName(),
+ 'type' => $room->getType(),
+ ],
+ ],
+ ]);
+ }
+
+ /**
+ * The given room has been deleted.
+ *
+ * @param Room $room
+ */
+ public function roomDeleted($room) {
+ $this->logger->info("Room deleted: " . $room->getToken());
+ $participants = $room->getParticipants();
+ $userIds = [];
+ foreach ($participants['users'] as $participant => $data) {
+ array_push($userIds, $participant);
+ }
+ $this->backendRequest('/api/v1/room/' . $room->getToken(), [
+ 'type' => 'delete',
+ 'delete' => [
+ 'userids' => $userIds,
+ ],
+ ]);
+ }
+
+}
diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php
index b362f8dea..bcb972f64 100644
--- a/lib/Controller/PageController.php
+++ b/lib/Controller/PageController.php
@@ -26,6 +26,7 @@ namespace OCA\Spreed\Controller;
use OC\HintException;
use OCA\Spreed\Exceptions\ParticipantNotFoundException;
use OCA\Spreed\Exceptions\RoomNotFoundException;
+use OCA\Spreed\Config;
use OCA\Spreed\Manager;
use OCA\Spreed\Participant;
use OCA\Spreed\Room;
@@ -55,6 +56,8 @@ class PageController extends Controller {
private $url;
/** @var IManager */
private $notificationManager;
+ /** @var Config */
+ private $config;
/**
* @param string $appName
@@ -66,6 +69,7 @@ class PageController extends Controller {
* @param Manager $manager
* @param IURLGenerator $url
* @param IManager $notificationManager
+ * @param Config $config
*/
public function __construct($appName,
IRequest $request,
@@ -75,7 +79,8 @@ class PageController extends Controller {
ILogger $logger,
Manager $manager,
IURLGenerator $url,
- IManager $notificationManager) {
+ IManager $notificationManager,
+ Config $config) {
parent::__construct($appName, $request);
$this->api = $api;
$this->session = $session;
@@ -84,6 +89,7 @@ class PageController extends Controller {
$this->manager = $manager;
$this->url = $url;
$this->notificationManager = $notificationManager;
+ $this->config = $config;
}
/**
@@ -156,6 +162,8 @@ class PageController extends Controller {
$params = [
'token' => $token,
+ 'signaling-server' => $this->config->getSignalingServer(),
+ 'signaling-ticket' => $this->config->getSignalingTicket($this->userId),
];
$response = new TemplateResponse($this->appName, 'index', $params);
$csp = new ContentSecurityPolicy();
@@ -194,6 +202,8 @@ class PageController extends Controller {
$params = [
'token' => $token,
+ 'signaling-server' => $this->config->getSignalingServer(),
+ 'signaling-ticket' => $this->config->getSignalingTicket($this->userId),
];
$response = new TemplateResponse($this->appName, 'index-public', $params, 'base');
$csp = new ContentSecurityPolicy();
diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php
index 2065540d5..5669c1948 100644
--- a/lib/Controller/RoomController.php
+++ b/lib/Controller/RoomController.php
@@ -63,6 +63,8 @@ class RoomController extends OCSController {
private $activityManager;
/** @var IL10N */
private $l10n;
+ /** @var BackendController */
+ private $backend;
/**
* @param string $appName
@@ -76,6 +78,7 @@ class RoomController extends OCSController {
* @param INotificationManager $notificationManager
* @param IActivityManager $activityManager
* @param IL10N $l10n
+ * @param BackendController $backend
*/
public function __construct($appName,
$UserId,
@@ -87,7 +90,8 @@ class RoomController extends OCSController {
Manager $manager,
INotificationManager $notificationManager,
IActivityManager $activityManager,
- IL10N $l10n) {
+ IL10N $l10n,
+ BackendController $backend) {
parent::__construct($appName, $request);
$this->session = $session;
$this->userId = $UserId;
@@ -98,6 +102,7 @@ class RoomController extends OCSController {
$this->notificationManager = $notificationManager;
$this->activityManager = $activityManager;
$this->l10n = $l10n;
+ $this->backend = $backend;
}
/**
@@ -350,6 +355,11 @@ class RoomController extends OCSController {
$this->createNotification($currentUser, $targetUser, $room);
+ $this->backend->roomInvited($room, [
+ $currentUser->getUID(),
+ $targetUser->getUID(),
+ ]);
+
return new DataResponse(['token' => $room->getToken()], Http::STATUS_CREATED);
}
}
@@ -419,6 +429,8 @@ class RoomController extends OCSController {
'participantType' => Participant::OWNER,
]);
+ $this->backend->roomInvited($room, [$this->userId]);
+
return new DataResponse(['token' => $room->getToken()], Http::STATUS_CREATED);
}
@@ -450,6 +462,8 @@ class RoomController extends OCSController {
if (!$room->setName($roomName)) {
return new DataResponse([], Http::STATUS_METHOD_NOT_ALLOWED);
}
+
+ $this->backend->roomModified($room);
return new DataResponse([]);
}
@@ -473,6 +487,7 @@ class RoomController extends OCSController {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}
+ $this->backend->roomDeleted($room);
$room->deleteRoom();
return new DataResponse([]);
@@ -561,6 +576,7 @@ class RoomController extends OCSController {
'userId' => $newUser->getUID(),
]);
$this->createNotification($currentUser, $newUser, $room);
+ $this->backend->roomInvited($room, [$newUser->getUID()]);
return new DataResponse(['type' => $room->getType()]);
}
@@ -569,6 +585,7 @@ class RoomController extends OCSController {
'userId' => $newUser->getUID(),
]);
$this->createNotification($currentUser, $newUser, $room);
+ $this->backend->roomInvited($room, [$newUser->getUID()]);
return new DataResponse([]);
}
@@ -596,6 +613,7 @@ class RoomController extends OCSController {
if ($room->getType() === Room::ONE_TO_ONE_CALL) {
$room->deleteRoom();
+ $this->backend->roomDeleted($room);
return new DataResponse([]);
}
@@ -615,6 +633,7 @@ class RoomController extends OCSController {
}
$room->removeUser($targetUser);
+ $this->backend->roomsDisinvited($room, [$targetUser->getUID()]);
return new DataResponse([]);
}
@@ -636,6 +655,7 @@ class RoomController extends OCSController {
if ($room->getType() === Room::ONE_TO_ONE_CALL || $room->getNumberOfParticipants() === 1) {
$room->deleteRoom();
+ $this->backend->roomDeleted($room);
} else {
$currentUser = $this->userManager->get($this->userId);
if (!$currentUser instanceof IUser) {
@@ -643,6 +663,7 @@ class RoomController extends OCSController {
}
$room->removeUser($currentUser);
+ $this->backend->roomsDisinvited($room, [$currentUser->getUID()]);
}
return new DataResponse([]);
diff --git a/lib/Controller/SignalingController.php b/lib/Controller/SignalingController.php
index 5186c02ba..6713c6820 100644
--- a/lib/Controller/SignalingController.php
+++ b/lib/Controller/SignalingController.php
@@ -30,10 +30,13 @@ use OCA\Spreed\Room;
use OCA\Spreed\Signaling\Messages;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\OCSController;
use OCP\IDBConnection;
use OCP\IRequest;
use OCP\ISession;
+use OCP\IUser;
+use OCP\IUserManager;
class SignalingController extends OCSController {
/** @var Config */
@@ -48,6 +51,8 @@ class SignalingController extends OCSController {
private $messages;
/** @var string|null */
private $userId;
+ /** @var IUserManager */
+ private $userManager;
/**
* @param string $appName
@@ -66,6 +71,7 @@ class SignalingController extends OCSController {
Manager $manager,
IDBConnection $connection,
Messages $messages,
+ IUserManager $userManager,
$UserId) {
parent::__construct($appName, $request);
$this->config = $config;
@@ -73,6 +79,7 @@ class SignalingController extends OCSController {
$this->dbConnection = $connection;
$this->manager = $manager;
$this->messages = $messages;
+ $this->userManager = $userManager;
$this->userId = $UserId;
}
@@ -83,6 +90,10 @@ class SignalingController extends OCSController {
* @return DataResponse
*/
public function signaling($messages) {
+ if ($this->config->getSignalingServer() !== '') {
+ throw new \Exception('Internal signaling disabled.');
+ }
+
$response = [];
$messages = json_decode($messages, true);
foreach($messages as $message) {
@@ -137,6 +148,10 @@ class SignalingController extends OCSController {
* @return DataResponse
*/
public function pullMessages() {
+ if ($this->config->getSignalingServer() !== '') {
+ throw new \Exception('Internal signaling disabled.');
+ }
+
$data = [];
$seconds = 30;
$sessionId = '';
@@ -221,4 +236,143 @@ class SignalingController extends OCSController {
return $usersInRoom;
}
+
+ /*
+ * Check if the current request is coming from an allowed backend.
+ *
+ * The backends are sending the custom header "Spreed-Signaling-Random"
+ * containing at least 32 bytes random data, and the header
+ * "Spreed-Signaling-Checksum", which is the SHA256-HMAC of the random data
+ * and the body of the request, calculated with the shared secret from the
+ * configuration.
+ *
+ * @return bool
+ */
+ private function validateBackendRequest($data) {
+ $random = $_SERVER['HTTP_SPREED_SIGNALING_RANDOM'];
+ if (empty($random) || strlen($random) < 32) {
+ return false;
+ }
+ $checksum = $_SERVER['HTTP_SPREED_SIGNALING_CHECKSUM'];
+ if (empty($checksum)) {
+ return false;
+ }
+ $hash = hash_hmac('sha256', $random . $data, $this->config->getSignalingSecret());
+ return hash_equals($hash, strtolower($checksum));
+ }
+
+ /**
+ * Backend API to query information required for standalone signaling
+ * servers.
+ *
+ * See sections "Backend validation" in
+ * https://github.com/nextcloud/spreed/wiki/Spreed-Signaling-API
+ *
+ * @NoCSRFRequired
+ * @PublicPage
+ *
+ * @param string $message
+ * @return JSONResponse
+ */
+ public function backend() {
+ $json = file_get_contents('php://input');
+ if (!$this->validateBackendRequest($json)) {
+ return new JSONResponse([
+ 'type' => 'error',
+ 'error' => [
+ 'code' => 'invalid_request',
+ 'message' => 'The request could not be authenticated.',
+ ],
+ ]);
+ }
+
+ $message = json_decode($json, true);
+ switch ($message['type']) {
+ case 'auth':
+ // Query authentication information about a user.
+ return $this->backendAuth($message['auth']);
+ case 'room':
+ // Query information about a room.
+ return $this->backendRoom($message['room']);
+ default:
+ return new JSONResponse([
+ 'type' => 'error',
+ 'error' => [
+ 'code' => 'unknown_type',
+ 'message' => 'The given type ' . print_r($message, true) . ' is not supported.',
+ ],
+ ]);
+ }
+ }
+
+ private function backendAuth($auth) {
+ $params = $auth['params'];
+ $userId = $params['userid'];
+ if (!$this->config->validateSignalingTicket($userId, $params['ticket'])) {
+ return new JSONResponse([
+ 'type' => 'error',
+ 'error' => [
+ 'code' => 'invalid_ticket',
+ 'message' => 'The given ticket is not valid for this user.',
+ ],
+ ]);
+ }
+
+ if (!empty($userId)) {
+ $user = $this->userManager->get($userId);
+ if (!$user instanceof IUser) {
+ return new JSONResponse([
+ 'type' => 'error',
+ 'error' => [
+ 'code' => 'no_such_user',
+ 'message' => 'The given user does not exist.',
+ ],
+ ]);
+ }
+ }
+
+ $response = [
+ 'type' => 'auth',
+ 'auth' => [
+ 'version' => '1.0',
+ ],
+ ];
+ if (!empty($userId)) {
+ $response['auth']['userid'] = $user->getUID();
+ $response['auth']['user'] = [
+ 'displayname' => $user->getDisplayName(),
+ ];
+ }
+ return new JSONResponse($response);
+ }
+
+ private function backendRoom($room) {
+ $roomId = $room['roomid'];
+ $userId = $room['userid'];
+ try {
+ $room = $this->manager->getRoomForParticipantByToken($roomId, $userId);
+ } catch (RoomNotFoundException $e) {
+ return new JSONResponse([
+ 'type' => 'error',
+ 'error' => [
+ 'code' => 'no_such_room',
+ 'message' => 'The user is not invited to this room.',
+ ],
+ ]);
+ }
+
+ $response = [
+ 'type' => 'room',
+ 'room' => [
+ 'version' => '1.0',
+ 'roomid' => $room->getToken(),
+ 'properties' => [
+ 'name' => $room->getName(),
+ 'type' => $room->getType(),
+ ],
+ ],
+ ];
+ return new JSONResponse($response);
+ }
+
}
diff --git a/lib/Settings/Admin/SignalingServer.php b/lib/Settings/Admin/SignalingServer.php
new file mode 100644
index 000000000..d700d48ac
--- /dev/null
+++ b/lib/Settings/Admin/SignalingServer.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * @author Joachim Bauch <mail@joachim-bauch.de>
+ *
+ * @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\Spreed\Settings\Admin;
+
+
+use OCP\AppFramework\Http\TemplateResponse;
+use OCP\IConfig;
+use OCP\Settings\ISettings;
+
+class SignalingServer implements ISettings {
+
+ /** @var IConfig */
+ private $config;
+
+ public function __construct(IConfig $config) {
+ $this->config = $config;
+ }
+
+ /**
+ * @return TemplateResponse
+ */
+ public function getForm() {
+ $parameters = [
+ 'signalingServer' => $this->config->getAppValue('spreed', 'signaling_server'),
+ 'signalingSecret' => $this->config->getAppValue('spreed', 'signaling_secret'),
+ ];
+
+ return new TemplateResponse('spreed', 'settings/admin/signaling-server', $parameters, '');
+ }
+
+ /**
+ * @return string the section ID, e.g. 'sharing'
+ */
+ public function getSection() {
+ return 'videocalls';
+ }
+
+ /**
+ * @return int whether the form should be rather on the top or bottom of
+ * the admin section. The forms are arranged in ascending order of the
+ * priority values. It is required to return a value between 0 and 100.
+ *
+ * E.g.: 70
+ */
+ public function getPriority() {
+ return 75;
+ }
+
+}
diff --git a/templates/settings/admin/signaling-server.php b/templates/settings/admin/signaling-server.php
new file mode 100644
index 000000000..e960fdb41
--- /dev/null
+++ b/templates/settings/admin/signaling-server.php
@@ -0,0 +1,24 @@
+<?php
+/** @var array $_ */
+/** @var \OCP\IL10N $l */
+script('spreed', ['admin/signaling-server']);
+style('spreed', ['settings-admin']);
+?>
+
+<div class="videocalls section signaling-server">
+ <h3><?php p($l->t('Signaling server')) ?></h3>
+ <p class="settings-hint"><?php p($l->t('An external signaling server can optionally be used for larger installations. Leave empty to use the internal signaling server.')) ?></p>
+
+ <p>
+ <label for="signaling_server"><?php p($l->t('External signaling server')) ?></label>
+ <input type="text" id="signaling_server"
+ name="signaling_server" placeholder="wss://signaling.example.org"
+ value="<?php p($_['signalingServer']) ?>" />
+ </p>
+ <p>
+ <label for="signaling_secret"><?php p($l->t('Shared secret')) ?></label>
+ <input type="text" id="signaling_secret"
+ name="signaling_secret" placeholder="shared secret"
+ value="<?php p($_['signalingSecret']) ?>" />
+ </p>
+</div>