Add support for coturn authentication

This commit is contained in:
Jerko Steiner 2017-05-29 20:45:08 -04:00
parent aa2f3f47d8
commit ddb54a28e2
10 changed files with 110 additions and 12 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ dist/
node_modules/
config.js
coverage/
config/local.json

6
config/default.json Normal file
View File

@ -0,0 +1,6 @@
{
"iceServers": [{
"url": "stun:23.21.150.121",
"urls": "stun:23.21.150.121"
}]
}

View File

@ -14,6 +14,7 @@
"license": "MIT",
"dependencies": {
"bluebird": "^3.3.4",
"config": "^1.26.1",
"express": "^4.13.3",
"flux": "^2.1.1",
"jade": "^1.11.0",

View File

@ -0,0 +1 @@
module.exports = [];

3
src/client/iceServers.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = JSON.parse(
window.document.getElementById('iceServers').value
);

View File

@ -2,6 +2,7 @@ const _ = require('underscore');
const Peer = require('./Peer.js');
const debug = require('debug')('peer-calls:peer');
const dispatcher = require('../dispatcher/dispatcher.js');
const iceServers = require('../iceServers.js');
const notify = require('../action/notify.js');
let peers = {};
@ -25,17 +26,7 @@ function create({ socket, user, initiator, stream }) {
let peer = peers[user.id] = Peer.init({
initiator: socket.id === initiator,
stream,
config: {
iceServers: [{
url: 'stun:23.21.150.121',
urls: 'stun:23.21.150.121'
}, {
url: 'turn:numb.viagenie.ca',
urls: 'turn:numb.viagenie.ca',
credential: 'muazkh',
username: 'webrtc@live.com'
}]
}
config: { iceServers }
});
peer.once('error', err => {

View File

@ -0,0 +1,53 @@
jest.unmock('../turn.js');
const turn = require('../turn.js');
describe('turn', () => {
describe('getCredentials', () => {
it('returns username & credential', () => {
const auth = turn.getCredentials('a', 'b');
expect(auth).toEqual(jasmine.any(Object));
expect(auth.username).toEqual(jasmine.any(String));
expect(auth.credential).toEqual(jasmine.any(String));
});
});
describe('processServers', () => {
const servers = [{
url: 'server1',
urls: 'server1',
username: 'a',
credential: 'b'
}, {
url: 'server2',
urls: 'server2',
username: 'c',
secret: 'd',
auth: 'secret'
}]
it('does not expose secret', () => {
const s = turn.processServers(servers);
expect(s.length).toBe(2);
expect(s[0]).toBe(servers[0]);
expect(s[1]).toEqual({
url: 'server2',
urls: 'server2',
username: jasmine.any(String),
credential: jasmine.any(String)
});
expect(s[1].username).toMatch(/^[0-9]+:c$/);
})
it('throws error when unknown auth type', () => {
expect(() => turn.processServers([{ auth: 'bla' }]))
.toThrowError(/not implemented/);
});
});
});

View File

@ -1,8 +1,12 @@
#!/usr/bin/env node
'use strict';
const config = require('config');
const turn = require('../turn.js');
const router = require('express').Router();
const uuid = require('uuid');
const cfgIceServers = config.get('iceServers');
router.get('/', (req, res) => {
let prefix = 'call/';
if (req.originalUrl.charAt(req.originalUrl.length - 1) === '/') prefix = '';
@ -10,8 +14,10 @@ router.get('/', (req, res) => {
});
router.get('/:callId', (req, res) => {
const iceServers = turn.processServers(cfgIceServers);
res.render('call', {
callId: encodeURIComponent(req.params.callId)
callId: encodeURIComponent(req.params.callId),
iceServers
});
});

35
src/server/turn.js Normal file
View File

@ -0,0 +1,35 @@
'use strict';
const crypto = require('crypto');
function getCredentials(name, secret) {
// this credential would be valid for the next 24 hours
const timestamp = parseInt(Date.now() / 1000, 10) + 24 * 3600;
const username = [timestamp, name].join(':');
const hmac = crypto.createHmac('sha1', secret);
hmac.setEncoding('base64');
hmac.write(username);
hmac.end();
const credential = hmac.read();
return { username, credential };
}
function processServers(iceServers) {
return iceServers.map(server => {
switch (server.auth) {
case undefined:
return server;
case 'secret':
const cred = getCredentials(server.username, server.secret);
return {
url: server.url,
urls: server.urls,
username: cred.username,
credential: cred.credential
};
default:
throw new Error('Authentication type not implemented: ' + server.auth);
}
});
}
module.exports = { getCredentials, processServers };

View File

@ -12,6 +12,7 @@ html
body.call
input#callId(type="hidden" value="#{callId}")
input#iceServers(type="hidden" value="#{JSON.stringify(iceServers)}")
div#container