Add support for coturn authentication
This commit is contained in:
parent
aa2f3f47d8
commit
ddb54a28e2
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ dist/
|
|||||||
node_modules/
|
node_modules/
|
||||||
config.js
|
config.js
|
||||||
coverage/
|
coverage/
|
||||||
|
config/local.json
|
||||||
|
|||||||
6
config/default.json
Normal file
6
config/default.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"iceServers": [{
|
||||||
|
"url": "stun:23.21.150.121",
|
||||||
|
"urls": "stun:23.21.150.121"
|
||||||
|
}]
|
||||||
|
}
|
||||||
@ -14,6 +14,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bluebird": "^3.3.4",
|
"bluebird": "^3.3.4",
|
||||||
|
"config": "^1.26.1",
|
||||||
"express": "^4.13.3",
|
"express": "^4.13.3",
|
||||||
"flux": "^2.1.1",
|
"flux": "^2.1.1",
|
||||||
"jade": "^1.11.0",
|
"jade": "^1.11.0",
|
||||||
|
|||||||
1
src/client/__mocks__/iceServers.js
Normal file
1
src/client/__mocks__/iceServers.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = [];
|
||||||
3
src/client/iceServers.js
Normal file
3
src/client/iceServers.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = JSON.parse(
|
||||||
|
window.document.getElementById('iceServers').value
|
||||||
|
);
|
||||||
@ -2,6 +2,7 @@ const _ = require('underscore');
|
|||||||
const Peer = require('./Peer.js');
|
const Peer = require('./Peer.js');
|
||||||
const debug = require('debug')('peer-calls:peer');
|
const debug = require('debug')('peer-calls:peer');
|
||||||
const dispatcher = require('../dispatcher/dispatcher.js');
|
const dispatcher = require('../dispatcher/dispatcher.js');
|
||||||
|
const iceServers = require('../iceServers.js');
|
||||||
const notify = require('../action/notify.js');
|
const notify = require('../action/notify.js');
|
||||||
|
|
||||||
let peers = {};
|
let peers = {};
|
||||||
@ -25,17 +26,7 @@ function create({ socket, user, initiator, stream }) {
|
|||||||
let peer = peers[user.id] = Peer.init({
|
let peer = peers[user.id] = Peer.init({
|
||||||
initiator: socket.id === initiator,
|
initiator: socket.id === initiator,
|
||||||
stream,
|
stream,
|
||||||
config: {
|
config: { iceServers }
|
||||||
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'
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
peer.once('error', err => {
|
peer.once('error', err => {
|
||||||
|
|||||||
53
src/server/__tests__/turn-test.js
Normal file
53
src/server/__tests__/turn-test.js
Normal 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/);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
@ -1,8 +1,12 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
'use strict';
|
'use strict';
|
||||||
|
const config = require('config');
|
||||||
|
const turn = require('../turn.js');
|
||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
const uuid = require('uuid');
|
const uuid = require('uuid');
|
||||||
|
|
||||||
|
const cfgIceServers = config.get('iceServers');
|
||||||
|
|
||||||
router.get('/', (req, res) => {
|
router.get('/', (req, res) => {
|
||||||
let prefix = 'call/';
|
let prefix = 'call/';
|
||||||
if (req.originalUrl.charAt(req.originalUrl.length - 1) === '/') prefix = '';
|
if (req.originalUrl.charAt(req.originalUrl.length - 1) === '/') prefix = '';
|
||||||
@ -10,8 +14,10 @@ router.get('/', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/:callId', (req, res) => {
|
router.get('/:callId', (req, res) => {
|
||||||
|
const iceServers = turn.processServers(cfgIceServers);
|
||||||
res.render('call', {
|
res.render('call', {
|
||||||
callId: encodeURIComponent(req.params.callId)
|
callId: encodeURIComponent(req.params.callId),
|
||||||
|
iceServers
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
35
src/server/turn.js
Normal file
35
src/server/turn.js
Normal 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 };
|
||||||
@ -12,6 +12,7 @@ html
|
|||||||
|
|
||||||
body.call
|
body.call
|
||||||
input#callId(type="hidden" value="#{callId}")
|
input#callId(type="hidden" value="#{callId}")
|
||||||
|
input#iceServers(type="hidden" value="#{JSON.stringify(iceServers)}")
|
||||||
|
|
||||||
div#container
|
div#container
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user