From 6d93d39b314d586f55fdb4bc8952e76599f356b1 Mon Sep 17 00:00:00 2001 From: Vasili Sviridov Date: Tue, 27 Dec 2022 17:42:04 -0800 Subject: [PATCH] TURN REST API Credentials Problem ======= * If I want to use my own TURN/STUN server, this requires generating ephemeral credentials, to avoid compromising long-term credentials, as those would be exposed in the source code. Solution ======== * Generate an ephemeral credential server-side, and provide it to each client via socket.io connection Notes ===== Tested against a local `coturn` server --- README.md | 17 +++++++++++++++++ server/signalling-server.js | 25 ++++++++++++++++++++++++- www/script.js | 7 ++++++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a9b61a1..f028c2b 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,23 @@ npm start to start the tlk server on port 3000. Your tlk instance will be running on http://localhost:3000. Alternatively you can run the application using docker with `docker-compose up`. +### How to self host it + +In order to self-host it on your dedicated server, Tlk must be exposed on `https` following [this documentation](./docs/self-hosting.md). + +You can also expose it quickly on `https` from your local PC or any host using [ngrok](https://ngrok.com/). + +### Using TURN REST API Authentication + +If you're using `coturn` - set up `use-auth-secret` and provision a secret either via `static-auth-secret` or via `turnadmin -s` + +Set up following environment variables: + +* `SHARED_SECRET`: This should match the parameter provided to coturn +* `CUSTOM_STUN_SERVER`: `stun:stun.your.domain.name` +* `CUSTOM_TURN_SERVER`: `turn:stun.your.domain.name` +* `CREDENTIAL_LIFETIME`: How long should the credential be valid for (in seconds) + ### LICENSE MIT License diff --git a/server/signalling-server.js b/server/signalling-server.js index 26c9c47..6c01927 100755 --- a/server/signalling-server.js +++ b/server/signalling-server.js @@ -1,8 +1,24 @@ /* -Note: This socket connection is used a signalling server as WebRTC does not support discovery of other peers. +Note: This socket connection is used a signalling server as WebRTC does not support discovery of other peers. Your audio, video & chat messages does not use this socket. */ const util = require("util"); +const { createHmac } = require("crypto"); + +const { SHARED_SECRET, CUSTOM_STUN_SERVER, CUSTOM_TURN_SERVER } = process.env +const CREDENTIAL_LIFETIME = parseInt(process.env.CREDENTIAL_LIFETIME, 10) || 3600; + +function getTurnCredentials(name, secret = SHARED_SECRET, duration = CREDENTIAL_LIFETIME) { + const timestamp = parseInt(Date.now() / 1000) + duration; + const username = `${timestamp}:${name}`; + const hmac = createHmac("sha1", secret); + hmac.setEncoding('base64') + hmac.write(username); + hmac.end(); + + const credential = hmac.read(); + return { username, credential }; +} const channels = {}; const sockets = {}; @@ -29,6 +45,13 @@ const signallingServer = (socket) => { console.log("[" + socket.id + "] join ", config); const channel = socketHostName + config.channel; + if(SHARED_SECRET && CUSTOM_STUN_SERVER && CUSTOM_TURN_SERVER) { + socket.emit('ice_servers', [ + { urls: CUSTOM_STUN_SERVER }, + { urls: CUSTOM_TURN_SERVER, ...getTurnCredentials(config.channel) } + ]); + } + // Already Joined if (channel in socket.channels) return; diff --git a/www/script.js b/www/script.js index 0060057..49e92fd 100755 --- a/www/script.js +++ b/www/script.js @@ -73,6 +73,11 @@ function init() { }); }); + signalingSocket.on("ice_servers", function(data) { + console.log('Received ICE Servers', data); + App.ice_servers = data; + }); + signalingSocket.on("disconnect", function () { for (let peer_id in peerMediaElements) { document.getElementById("videos").removeChild(peerMediaElements[peer_id].parentNode); @@ -99,7 +104,7 @@ function init() { channel = config.channel; //console.log('[Join] - connected peers in the channel', JSON.stringify(channel, null, 2)); - const peerConnection = new RTCPeerConnection({ iceServers: ICE_SERVERS }); + const peerConnection = new RTCPeerConnection({ iceServers: App.ice_servers || ICE_SERVERS }); peers[peer_id] = peerConnection; peerConnection.onicecandidate = function (event) {