Install typescript, upgrade server to TypeScript
This commit is contained in:
parent
085fae4b22
commit
1eaca46a16
21
.eslintrc
21
.eslintrc
@ -1,21 +0,0 @@
|
||||
{
|
||||
"parser": "babel-eslint",
|
||||
"extends": ["standard", "standard-react"],
|
||||
"rules": {
|
||||
"max-len": [2, 80, 4],
|
||||
"jsx-quotes": ["error", "prefer-double"],
|
||||
"padded-blocks": 0,
|
||||
"import/first": 0,
|
||||
"no-return-assign": 0,
|
||||
"indent": ["error", 2, { "MemberExpression": 0, "SwitchCase": 1, "flatTernaryExpressions": true }],
|
||||
},
|
||||
"globals": {
|
||||
"expect": true,
|
||||
"jest": true,
|
||||
"jasmine": true,
|
||||
"it": true,
|
||||
"beforeEach": true,
|
||||
"afterEach": true,
|
||||
"describe": true
|
||||
}
|
||||
}
|
||||
66
.eslintrc.yaml
Normal file
66
.eslintrc.yaml
Normal file
@ -0,0 +1,66 @@
|
||||
extends:
|
||||
- eslint:recommended
|
||||
- plugin:react/recommended
|
||||
- plugin:@typescript-eslint/eslint-recommended
|
||||
- plugin:@typescript-eslint/recommended
|
||||
plugins:
|
||||
- import
|
||||
settings:
|
||||
react:
|
||||
version: 'detect'
|
||||
rules:
|
||||
max-len:
|
||||
- warn
|
||||
- code: 80
|
||||
ignorePattern: '^import .* from '
|
||||
comma-dangle:
|
||||
- warn
|
||||
- arrays: always-multiline
|
||||
objects: always-multiline
|
||||
imports: always-multiline
|
||||
exports: always-multiline
|
||||
functions: always-multiline
|
||||
|
||||
semi:
|
||||
- warn
|
||||
- never
|
||||
quotes:
|
||||
- warn
|
||||
- single
|
||||
- allowTemplateLiterals: true
|
||||
# interface-name-prefix:
|
||||
'import/no-extraneous-dependencies': off
|
||||
'@typescript-eslint/member-delimiter-style':
|
||||
- warn
|
||||
- multiline:
|
||||
delimiter: none
|
||||
singleline:
|
||||
delimiter: comma
|
||||
'@typescript-eslint/no-unused-vars':
|
||||
- warn
|
||||
- vars: all
|
||||
args: none
|
||||
ignoreRestSiblings: true
|
||||
'@typescript-eslint/explicit-function-return-type': off
|
||||
'@typescript-eslint/no-non-null-assertion': off
|
||||
'@typescript-eslint/no-use-before-define': off
|
||||
'@typescript-eslint/no-empty-interface': off
|
||||
'@typescript-eslint/no-explicit-any':
|
||||
- warn
|
||||
- ignoreRestArgs: true
|
||||
'@typescript-eslint/triple-slash-reference':
|
||||
- warn
|
||||
- path: always
|
||||
overrides:
|
||||
- files:
|
||||
- '*.test.ts'
|
||||
- '*.test.tsx'
|
||||
rules:
|
||||
'@typescript-eslint/no-explicit-any': off
|
||||
- files:
|
||||
- '*.js'
|
||||
rules:
|
||||
'@typescript-eslint/no-var-requires': off
|
||||
env:
|
||||
node: true
|
||||
es6: true
|
||||
16
jest.config.js
Normal file
16
jest.config.js
Normal file
@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
roots: [
|
||||
'<rootDir>/src'
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.tsx?$': 'ts-jest'
|
||||
},
|
||||
testRegex: '(/__tests__/.*|\\.(test|spec))\\.tsx?$',
|
||||
moduleFileExtensions: [
|
||||
'ts',
|
||||
'tsx',
|
||||
'js',
|
||||
'jsx'
|
||||
],
|
||||
setupFiles: ['<rootDir>/jest.setup.js']
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
import '@babel/polyfill'
|
||||
2074
package-lock.json
generated
2074
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
51
package.json
51
package.json
@ -3,27 +3,29 @@
|
||||
"version": "2.0.12",
|
||||
"description": "Group peer to peer video calls for anybody.",
|
||||
"repository": "https://github.com/jeremija/peer-calls",
|
||||
"main": "src/index.js",
|
||||
"main": "lib/index.js",
|
||||
"bin": {
|
||||
"peercalls": "./src/index.js"
|
||||
"peercalls": "./lib/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node src/index.js",
|
||||
"start:server": "nodemon src/index.js --ignore build/ --ignore src/client",
|
||||
"start:watch": "chastifol [ npm run js:watch ] [ npm run css:watch ] [ npm run start:server ]",
|
||||
"start": "node lib/index.js",
|
||||
"start:server": "nodemon -ignore build/ --ignore lib/client lib/index.js",
|
||||
"start:watch": "chastifol [ npm run ts:watch ] [ npm run js:watch ] [ npm run css:watch ] [ npm run start:server ]",
|
||||
"watch": "",
|
||||
"prepublishOnly": "npm run build",
|
||||
"build": "npm run css && npm run js",
|
||||
"test": "jest",
|
||||
"test:coverage": "jest --coverage",
|
||||
"test:watch": "jest --watch",
|
||||
"js": "browserify -t babelify ./src/client/index.js -o ./build/index.js",
|
||||
"js:watch": "watchify -d -v -t babelify ./src/client/index.js -o ./build/index.js",
|
||||
"js": "browserify -t babelify ./lib/client/index.js -o ./build/index.js",
|
||||
"js:watch": "watchify -d -v -t babelify ./lib/client/index.js -o ./build/index.js",
|
||||
"css": "node-sass ./src/scss/style.scss -o ./build/",
|
||||
"css:watch": "npm run css && node-sass --watch ./src/scss/style.scss -o ./build/",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"ci": "npm run lint && npm run test:coverage && npm run build"
|
||||
"ci": "npm run lint && npm run test:coverage && npm run build",
|
||||
"ts:watch": "tsc --build . --watch --preserveWatchOutput",
|
||||
"ts": "tsc --build ."
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
@ -78,36 +80,41 @@
|
||||
"@babel/polyfill": "^7.4.4",
|
||||
"@babel/preset-env": "^7.5.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@types/config": "0.0.36",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/express": "^4.17.2",
|
||||
"@types/jest": "^24.0.23",
|
||||
"@types/node": "^12.12.7",
|
||||
"@types/socket.io": "^2.1.4",
|
||||
"@types/socket.io-client": "^1.4.32",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"@types/underscore": "^1.9.3",
|
||||
"@types/uuid": "^3.4.6",
|
||||
"@typescript-eslint/eslint-plugin": "^2.7.0",
|
||||
"@typescript-eslint/parser": "^2.7.0",
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-jest": "^24.8.0",
|
||||
"babelify": "^10.0.0",
|
||||
"chastifol": "^4.1.0",
|
||||
"eslint": "^5.10.0",
|
||||
"eslint": "^6.6.0",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"eslint-config-standard-react": "^7.0.2",
|
||||
"eslint-plugin-import": "^2.3.0",
|
||||
"eslint-plugin-import": "^2.18.2",
|
||||
"eslint-plugin-node": "^8.0.0",
|
||||
"eslint-plugin-promise": "^4.0.1",
|
||||
"eslint-plugin-react": "^7.0.1",
|
||||
"eslint-plugin-react": "^7.16.0",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"jest": "^24.9.0",
|
||||
"jest-cli": "^24.8.0",
|
||||
"node-sass": "^4.13.0",
|
||||
"nodemon": "^1.18.8",
|
||||
"redux-mock-store": "^1.2.3",
|
||||
"supertest": "^3.0.0",
|
||||
"ts-jest": "^24.1.0",
|
||||
"ts-node": "^8.5.0",
|
||||
"typescript": "^3.6.4",
|
||||
"uglify-js": "^3.4.9",
|
||||
"watchify": "^3.11.1"
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
"^.+\\.[t|j]sx?$": "<rootDir>/node_modules/babel-jest"
|
||||
},
|
||||
"setupFiles": [
|
||||
"<rootDir>/jest.setup.js"
|
||||
],
|
||||
"modulePathIgnorePatterns": [
|
||||
"<rootDir>/node_modules/"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,8 +4,10 @@ if (!process.env.DEBUG) {
|
||||
process.env.DEBUG = 'peercalls'
|
||||
}
|
||||
|
||||
const app = require('./server/app.js')
|
||||
const debug = require('debug')('peercalls')
|
||||
import app from './server/app'
|
||||
import _debug from 'debug'
|
||||
|
||||
const debug = _debug('peercalls')
|
||||
|
||||
const port = process.env.PORT || 3000
|
||||
const server = app.listen(port, () => debug('Listening on: %s', port))
|
||||
|
||||
@ -1,16 +1,19 @@
|
||||
jest.mock('socket.io', () => {
|
||||
// eslint-disable-next-line
|
||||
const { EventEmitter } = require('events')
|
||||
return jest.fn().mockReturnValue(new EventEmitter())
|
||||
})
|
||||
jest.mock('./socket.js')
|
||||
jest.mock('./socket')
|
||||
|
||||
const app = require('./app.js')
|
||||
const config = require('config')
|
||||
const handleSocket = require('./socket.js')
|
||||
const io = require('socket.io')()
|
||||
const request = require('supertest')
|
||||
import app from './app'
|
||||
import { config } from './config'
|
||||
import handleSocket from './socket'
|
||||
import SocketIO from 'socket.io'
|
||||
import request from 'supertest'
|
||||
|
||||
const BASE_URL = config.get('baseUrl')
|
||||
const io = SocketIO()
|
||||
|
||||
const BASE_URL: string = config.get('baseUrl')
|
||||
|
||||
describe('server/app', () => {
|
||||
|
||||
@ -50,7 +53,7 @@ describe('server/app', () => {
|
||||
it('calls handleSocket with socket', () => {
|
||||
const socket = { hi: 'me socket' }
|
||||
io.emit('connection', socket)
|
||||
expect(handleSocket.mock.calls).toEqual([[ socket, io ]])
|
||||
expect((handleSocket as jest.Mock).mock.calls).toEqual([[ socket, io ]])
|
||||
})
|
||||
|
||||
})
|
||||
@ -1,20 +1,23 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict'
|
||||
const config = require('config')
|
||||
const debug = require('debug')('peercalls')
|
||||
const express = require('express')
|
||||
const handleSocket = require('./socket.js')
|
||||
const path = require('path')
|
||||
const { createServer } = require('./server.js')
|
||||
import { config } from './config'
|
||||
import _debug from 'debug'
|
||||
import express from 'express'
|
||||
import handleSocket from './socket'
|
||||
import path from 'path'
|
||||
import { createServer } from './server'
|
||||
import SocketIO from 'socket.io'
|
||||
import call from './routes/call'
|
||||
import index from './routes/index'
|
||||
|
||||
const BASE_URL = config.get('baseUrl')
|
||||
const debug = _debug('peercalls')
|
||||
|
||||
const BASE_URL: string = config.get('baseUrl')
|
||||
const SOCKET_URL = `${BASE_URL}/ws`
|
||||
|
||||
debug(`WebSocket URL: ${SOCKET_URL}`)
|
||||
|
||||
const app = express()
|
||||
const server = createServer(config, app)
|
||||
const io = require('socket.io')(server, { path: SOCKET_URL })
|
||||
const io = SocketIO(server, { path: SOCKET_URL })
|
||||
|
||||
app.locals.version = require('../../package.json').version
|
||||
app.locals.baseUrl = BASE_URL
|
||||
@ -25,10 +28,10 @@ app.set('views', path.join(__dirname, '../views'))
|
||||
const router = express.Router()
|
||||
router.use('/res', express.static(path.join(__dirname, '../res')))
|
||||
router.use('/static', express.static(path.join(__dirname, '../../build')))
|
||||
router.use('/call', require('./routes/call.js'))
|
||||
router.use('/', require('./routes/index.js'))
|
||||
router.use('/call', call)
|
||||
router.use('/', index)
|
||||
app.use(BASE_URL, router)
|
||||
|
||||
io.on('connection', socket => handleSocket(socket, io))
|
||||
|
||||
module.exports = server
|
||||
export default server
|
||||
26
src/server/config.ts
Normal file
26
src/server/config.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import cfg, { IConfig } from 'config'
|
||||
|
||||
export type ICEServer = {
|
||||
url: string
|
||||
urls: string[] | string
|
||||
auth: 'secret'
|
||||
username: string
|
||||
secret: string
|
||||
} | {
|
||||
url: string
|
||||
urls: string[] | string
|
||||
auth: undefined
|
||||
username: string
|
||||
credential: string
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
baseUrl: string
|
||||
iceServers: ICEServer[]
|
||||
ssl: {
|
||||
cert: string
|
||||
key: string
|
||||
}
|
||||
}
|
||||
|
||||
export const config = cfg as IConfig & Config
|
||||
@ -1,23 +0,0 @@
|
||||
#!/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 BASE_URL = config.get('baseUrl')
|
||||
const cfgIceServers = config.get('iceServers')
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
res.redirect(`${BASE_URL}/call/${uuid.v4()}`)
|
||||
})
|
||||
|
||||
router.get('/:callId', (req, res) => {
|
||||
const iceServers = turn.processServers(cfgIceServers)
|
||||
res.render('call', {
|
||||
callId: encodeURIComponent(req.params.callId),
|
||||
iceServers
|
||||
})
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
23
src/server/routes/call.ts
Normal file
23
src/server/routes/call.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { config, ICEServer } from '../config'
|
||||
import * as turn from '../turn'
|
||||
import { Router } from 'express'
|
||||
import { v4 } from 'uuid'
|
||||
|
||||
const router = Router()
|
||||
|
||||
const BASE_URL: string = config.get('baseUrl')
|
||||
const cfgIceServers = config.get('iceServers') as ICEServer[]
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
res.redirect(`${BASE_URL}/call/${v4()}`)
|
||||
})
|
||||
|
||||
router.get('/:callId', (req, res) => {
|
||||
const iceServers = turn.processServers(cfgIceServers)
|
||||
res.render('call', {
|
||||
callId: encodeURIComponent(req.params.callId),
|
||||
iceServers,
|
||||
})
|
||||
})
|
||||
|
||||
export default router
|
||||
@ -1,9 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict'
|
||||
const router = require('express').Router()
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
res.render('index')
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
9
src/server/routes/index.ts
Normal file
9
src/server/routes/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Router } from 'express'
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
res.render('index')
|
||||
})
|
||||
|
||||
export default router
|
||||
@ -1,17 +0,0 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const projectRoot = path.resolve(path.join(__dirname, '../..'))
|
||||
|
||||
const readFile = file => fs.readFileSync(path.resolve(projectRoot, file))
|
||||
|
||||
function createServer (config, app) {
|
||||
if (config.ssl) {
|
||||
const key = readFile(config.ssl.key)
|
||||
const cert = readFile(config.ssl.cert)
|
||||
return require('https').createServer({ key, cert }, app)
|
||||
}
|
||||
return require('http').createServer(app)
|
||||
}
|
||||
|
||||
module.exports = { createServer }
|
||||
@ -1,11 +1,11 @@
|
||||
const express = require('express')
|
||||
const http = require('http')
|
||||
const https = require('https')
|
||||
const { createServer } = require('./server.js')
|
||||
import express from 'express'
|
||||
import http from 'http'
|
||||
import https from 'https'
|
||||
import { createServer } from './server'
|
||||
|
||||
describe('server', () => {
|
||||
|
||||
let app, config
|
||||
let app: Express.Application, config: any
|
||||
beforeEach(() => {
|
||||
config = {}
|
||||
app = express()
|
||||
@ -15,7 +15,7 @@ describe('server', () => {
|
||||
it('creates https server when config.ssl', () => {
|
||||
config.ssl = {
|
||||
cert: 'config/cert.example.pem',
|
||||
key: 'config/cert.example.key'
|
||||
key: 'config/cert.example.key',
|
||||
}
|
||||
const s = createServer(config, app)
|
||||
expect(s).toEqual(jasmine.any(https.Server))
|
||||
16
src/server/server.ts
Normal file
16
src/server/server.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { readFileSync } from 'fs'
|
||||
import { resolve, join } from 'path'
|
||||
import { Config } from './config'
|
||||
|
||||
const projectRoot = resolve(join(__dirname, '../..'))
|
||||
|
||||
const readFile = (file: string) => readFileSync(resolve(projectRoot, file))
|
||||
|
||||
export function createServer (config: Config, app: Express.Application) {
|
||||
if (config.ssl) {
|
||||
const key = readFile(config.ssl.key)
|
||||
const cert = readFile(config.ssl.cert)
|
||||
return require('https').createServer({ key, cert }, app)
|
||||
}
|
||||
return require('http').createServer(app)
|
||||
}
|
||||
@ -1,21 +1,33 @@
|
||||
'use strict'
|
||||
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const handleSocket = require('./socket.js')
|
||||
import { EventEmitter } from 'events'
|
||||
import handleSocket from './socket'
|
||||
import { Socket, Server } from 'socket.io'
|
||||
|
||||
describe('server/socket', () => {
|
||||
let socket, io, rooms
|
||||
type SocketMock = Socket & {
|
||||
id: string
|
||||
room?: string
|
||||
join: jest.Mock
|
||||
leave: jest.Mock
|
||||
emit: jest.Mock
|
||||
}
|
||||
|
||||
let socket: SocketMock
|
||||
let io: Server & {
|
||||
in: jest.Mock<(room: string) => SocketMock>
|
||||
to: jest.Mock<(room: string) => SocketMock>
|
||||
}
|
||||
let rooms: Record<string, {emit: any}>
|
||||
beforeEach(() => {
|
||||
socket = new EventEmitter()
|
||||
socket = new EventEmitter() as SocketMock
|
||||
socket.id = 'socket0'
|
||||
socket.join = jest.fn()
|
||||
socket.leave = jest.fn()
|
||||
rooms = {}
|
||||
|
||||
io = {}
|
||||
io = {} as any
|
||||
io.in = io.to = jest.fn().mockImplementation(room => {
|
||||
return (rooms[room] = rooms[room] || {
|
||||
emit: jest.fn()
|
||||
emit: jest.fn(),
|
||||
})
|
||||
})
|
||||
|
||||
@ -23,21 +35,21 @@ describe('server/socket', () => {
|
||||
adapter: {
|
||||
rooms: {
|
||||
room1: {
|
||||
'socket0': true
|
||||
},
|
||||
socket0: true,
|
||||
} as any,
|
||||
room2: {
|
||||
'socket0': true
|
||||
},
|
||||
socket0: true,
|
||||
} as any,
|
||||
room3: {
|
||||
sockets: {
|
||||
'socket0': true,
|
||||
'socket1': true,
|
||||
'socket2': true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'socket2': true,
|
||||
},
|
||||
} as any,
|
||||
},
|
||||
} as any,
|
||||
} as any
|
||||
|
||||
socket.leave = jest.fn()
|
||||
socket.join = jest.fn()
|
||||
@ -52,16 +64,16 @@ describe('server/socket', () => {
|
||||
|
||||
describe('signal', () => {
|
||||
it('should broadcast signal to specific user', () => {
|
||||
let signal = { type: 'signal' }
|
||||
const signal = { type: 'signal' }
|
||||
|
||||
socket.emit('signal', { userId: 'a', signal })
|
||||
|
||||
expect(io.to.mock.calls).toEqual([[ 'a' ]])
|
||||
expect(io.to('a').emit.mock.calls).toEqual([[
|
||||
expect((io.to('a').emit as jest.Mock).mock.calls).toEqual([[
|
||||
'signal', {
|
||||
userId: 'socket0',
|
||||
signal
|
||||
}
|
||||
signal,
|
||||
},
|
||||
]])
|
||||
})
|
||||
})
|
||||
@ -84,19 +96,19 @@ describe('server/socket', () => {
|
||||
socket.emit('ready', 'room3')
|
||||
|
||||
expect(io.to.mock.calls).toEqual([[ 'room3' ]])
|
||||
expect(io.to('room3').emit.mock.calls).toEqual([
|
||||
expect((io.to('room3').emit as jest.Mock).mock.calls).toEqual([
|
||||
[
|
||||
'users', {
|
||||
initiator: 'socket0',
|
||||
users: [{
|
||||
id: 'socket0'
|
||||
id: 'socket0',
|
||||
}, {
|
||||
id: 'socket1'
|
||||
id: 'socket1',
|
||||
}, {
|
||||
id: 'socket2'
|
||||
}]
|
||||
}
|
||||
]
|
||||
id: 'socket2',
|
||||
}],
|
||||
},
|
||||
],
|
||||
])
|
||||
})
|
||||
})
|
||||
@ -1,13 +1,18 @@
|
||||
'use strict'
|
||||
const debug = require('debug')('peer-calls:socket')
|
||||
const _ = require('underscore')
|
||||
import _debug from 'debug'
|
||||
import _ from 'underscore'
|
||||
import { Socket, Server } from 'socket.io'
|
||||
|
||||
module.exports = function (socket, io) {
|
||||
const debug = _debug('peercalls:socket')
|
||||
|
||||
type SocketWithRoom = Socket & { room?: string }
|
||||
|
||||
export default function handleSocket(socket: SocketWithRoom, io: Server) {
|
||||
socket.on('signal', payload => {
|
||||
// debug('signal: %s, payload: %o', socket.id, payload)
|
||||
io.to(payload.userId).emit('signal', {
|
||||
userId: socket.id,
|
||||
signal: payload.signal
|
||||
signal: payload.signal,
|
||||
})
|
||||
})
|
||||
|
||||
@ -18,17 +23,17 @@ module.exports = function (socket, io) {
|
||||
socket.join(roomName)
|
||||
socket.room = roomName
|
||||
|
||||
let users = getUsers(roomName)
|
||||
const users = getUsers(roomName)
|
||||
|
||||
debug('ready: %s, room: %s, users: %o', socket.id, roomName, users)
|
||||
|
||||
io.to(roomName).emit('users', {
|
||||
initiator: socket.id,
|
||||
users
|
||||
users,
|
||||
})
|
||||
})
|
||||
|
||||
function getUsers (roomName) {
|
||||
function getUsers (roomName: string) {
|
||||
return _.map(io.sockets.adapter.rooms[roomName].sockets, (_, id) => {
|
||||
return { id }
|
||||
})
|
||||
@ -1,35 +0,0 @@
|
||||
'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 }
|
||||
@ -1,4 +1,5 @@
|
||||
const turn = require('./turn.js')
|
||||
import * as turn from './turn'
|
||||
import { ICEServer } from './config'
|
||||
|
||||
describe('server/turn', () => {
|
||||
describe('getCredentials', () => {
|
||||
@ -11,17 +12,18 @@ describe('server/turn', () => {
|
||||
})
|
||||
|
||||
describe('processServers', () => {
|
||||
const servers = [{
|
||||
const servers: ICEServer[] = [{
|
||||
url: 'server1',
|
||||
urls: 'server1',
|
||||
auth: undefined,
|
||||
username: 'a',
|
||||
credential: 'b'
|
||||
credential: 'b',
|
||||
}, {
|
||||
url: 'server2',
|
||||
urls: 'server2',
|
||||
username: 'c',
|
||||
secret: 'd',
|
||||
auth: 'secret'
|
||||
auth: 'secret',
|
||||
}]
|
||||
|
||||
it('does not expose secret', () => {
|
||||
@ -32,13 +34,13 @@ describe('server/turn', () => {
|
||||
url: 'server2',
|
||||
urls: 'server2',
|
||||
username: jasmine.any(String),
|
||||
credential: 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' }]))
|
||||
expect(() => turn.processServers([{ auth: 'bla' } as any]))
|
||||
.toThrowError(/not implemented/)
|
||||
})
|
||||
})
|
||||
45
src/server/turn.ts
Normal file
45
src/server/turn.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import crypto from 'crypto'
|
||||
import { ICEServer } from './config'
|
||||
|
||||
export interface Credentials {
|
||||
username: string
|
||||
credential: string
|
||||
}
|
||||
|
||||
export function getCredentials (name: string, secret: string): Credentials {
|
||||
// this credential would be valid for the next 24 hours
|
||||
const timestamp = Math.floor(Date.now() / 1000) + 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 getServerConfig(server: ICEServer, cred: Credentials) {
|
||||
return {
|
||||
url: server.url,
|
||||
urls: server.urls,
|
||||
username: cred.username,
|
||||
credential: cred.credential,
|
||||
}
|
||||
}
|
||||
|
||||
export function processServers (iceServers: ICEServer[]) {
|
||||
return iceServers.map(server => {
|
||||
switch (server.auth) {
|
||||
case undefined:
|
||||
return server
|
||||
case 'secret':
|
||||
return getServerConfig(
|
||||
server,
|
||||
getCredentials(server.username, server.secret),
|
||||
)
|
||||
default:
|
||||
throw new Error('Authentication type not implemented: ' +
|
||||
(server as {auth: string}).auth)
|
||||
}
|
||||
})
|
||||
}
|
||||
24
tsconfig.json
Normal file
24
tsconfig.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"lib": ["es2015", "dom"],
|
||||
"target": "es3",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react",
|
||||
"noImplicitAny": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noUnusedLocals": false,
|
||||
"esModuleInterop": true,
|
||||
"emitDecoratorMetadata": false,
|
||||
"experimentalDecorators": false,
|
||||
"allowJs": false,
|
||||
"checkJs": false,
|
||||
"outDir": "lib",
|
||||
"rootDir": "src"
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user