diff options
author | Joachim Bauch <bauch@struktur.de> | 2017-07-20 14:40:49 +0300 |
---|---|---|
committer | Joachim Bauch <bauch@struktur.de> | 2017-11-02 13:23:09 +0300 |
commit | be33ec8d9c30b1acd0336976fd64cc0dfff96c27 (patch) | |
tree | ce9b5d73e3e3b34a5dcf44c004f4963c37edb6e2 | |
parent | d7ef5ef868060f497e6e69617f088c69dfbb6cc3 (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.xml | 1 | ||||
-rw-r--r-- | appinfo/routes.php | 8 | ||||
-rw-r--r-- | js/admin/signaling-server.js | 43 | ||||
-rw-r--r-- | lib/Config.php | 82 | ||||
-rw-r--r-- | lib/Controller/BackendController.php | 183 | ||||
-rw-r--r-- | lib/Controller/PageController.php | 12 | ||||
-rw-r--r-- | lib/Controller/RoomController.php | 23 | ||||
-rw-r--r-- | lib/Controller/SignalingController.php | 154 | ||||
-rw-r--r-- | lib/Settings/Admin/SignalingServer.php | 68 | ||||
-rw-r--r-- | templates/settings/admin/signaling-server.php | 24 |
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> |