Merge pull request #95 from havfo/feat/spdy

http2
master
Stefan Otto 2019-05-15 15:41:14 +02:00 committed by GitHub
commit e9b946ba93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 282 additions and 124 deletions

View File

@ -253,14 +253,14 @@ export default class RoomClient
login()
{
const url = `/login?roomId=${this._room.roomId}&peerName=${this._peerName}`;
const url = `/auth/login?roomId=${this._room.roomId}&peerName=${this._peerName}`;
this._loginWindow = window.open(url, 'loginWindow');
}
logout()
{
window.location = '/logout';
window.location = '/auth/logout';
}
closeLoginWindow()

View File

@ -1,12 +1,26 @@
module.exports =
{
// oAuth2 conf
oauth2 :
auth :
{
clientID : '',
clientSecret : '',
callbackURL : 'https://mYDomainName:port/auth-callback'
/*
The issuer URL for OpenID Connect discovery
The OpenID Provider Configuration Document
could be discovered on:
issuerURL + '/.well-known/openid-configuration'
*/
issuerURL : 'https://example.com'
clientOptions :
{
client_id : '',
client_secret : '',
scope : 'openid email profile'
// where client.example.com is your multiparty meeting server
redirect_uri : 'https://client.example.com/auth/callback'
}
},
// session cookie secret
cookieSecret : 'T0P-S3cR3t_cook!e',
// Listening hostname for `gulp live|open`.
domain : 'localhost',
tls :

View File

@ -12,9 +12,12 @@
"compression": "^1.7.3",
"debug": "^4.1.0",
"express": "^4.16.3",
"express-session": "^1.16.1",
"mediasoup": "^2.6.11",
"passport-dataporten": "^1.3.0",
"socket.io": "^2.1.1"
"openid-client": "^2.5.0",
"passport": "^0.4.0",
"socket.io": "^2.1.1",
"spdy": "^4.0.0"
},
"devDependencies": {
"gulp": "^4.0.0",

View File

@ -6,15 +6,18 @@ process.title = 'multiparty-meeting-server';
const config = require('./config/config');
const fs = require('fs');
const https = require('https');
const http = require('http');
const spdy = require('spdy');
const express = require('express');
const compression = require('compression');
const Logger = require('./lib/Logger');
const Room = require('./lib/Room');
const Dataporten = require('passport-dataporten');
const utils = require('./util');
const base64 = require('base-64');
// auth
const passport = require('passport');
const { Issuer, Strategy } = require('openid-client');
const session = require('express-session')
/* eslint-disable no-console */
console.log('- process.env.DEBUG:', process.env.DEBUG);
@ -37,148 +40,286 @@ const tls =
key : fs.readFileSync(config.tls.key)
};
const app = express();
let app = express();
let httpsServer;
let oidcClient;
let oidcStrategy;
app.use(compression());
const dataporten = new Dataporten.Setup(config.oauth2);
app.all('*', (req, res, next) =>
passport.serializeUser(function(user, done)
{
if (req.secure)
done(null, user);
});
passport.deserializeUser(function(user, done)
{
done(null, user);
});
const auth=config.auth;
function setupAuth(oidcIssuer)
{
oidcClient = new oidcIssuer.Client(auth.clientOptions);
const params =
{
return next();
}
...auth.clientOptions
// ... any authorization request parameters go here
// client_id defaults to client.client_id
// redirect_uri defaults to client.redirect_uris[0]
// response type defaults to client.response_types[0], then 'code'
// scope defaults to 'openid'
};
res.redirect(`https://${req.hostname}${req.url}`);
});
// optional, defaults to false, when true req is passed as a first
// argument to verify fn
const passReqToCallback = false;
app.use(dataporten.passport.initialize());
app.use(dataporten.passport.session());
// optional, defaults to false, when true the code_challenge_method will be
// resolved from the issuer configuration, instead of true you may provide
// any of the supported values directly, i.e. "S256" (recommended) or "plain"
const usePKCE = false;
const client=oidcClient;
app.get('/login', (req, res, next) =>
{
dataporten.passport.authenticate('dataporten', {
state : base64.encode(JSON.stringify({
roomId : req.query.roomId,
peerName : req.query.peerName,
code : utils.random(10)
}))
})(req, res, next);
});
dataporten.setupLogout(app, '/logout');
app.get('/', (req, res) =>
{
res.sendFile(`${__dirname}/public/chooseRoom.html`);
});
app.get(
'/auth-callback',
dataporten.passport.authenticate('dataporten', { failureRedirect: '/login' }),
(req, res) =>
{
const state = JSON.parse(base64.decode(req.query.state));
if (rooms.has(state.roomId))
oidcStrategy = new Strategy(
{ client, params, passReqToCallback, usePKCE },
(tokenset, userinfo, done) =>
{
const data =
{
peerName : state.peerName,
name : req.user.data.displayName,
picture : req.user.data.photos[0]
let user = {
id : tokenset.claims.sub,
provider : tokenset.claims.iss,
_userinfo : userinfo,
_claims : tokenset.claims,
};
const room = rooms.get(state.roomId);
room.authCallback(data);
if ( typeof(userinfo.picture) !== 'undefined' ){
if ( ! userinfo.picture.match(/^http/g) ) {
user.Photos = [ { value: `data:image/jpeg;base64, ${userinfo.picture}` } ];
} else {
user.Photos= [ { value: userinfo.picture } ];
}
}
if ( typeof(userinfo.nickname) !== 'undefined' ){
user.displayName=userinfo.nickname;
}
if ( typeof(userinfo.name) !== 'undefined' ){
user.displayName=userinfo.name;
}
if ( typeof(userinfo.email) !== 'undefined' ){
user.emails=[{value: userinfo.email}];
}
if ( typeof(userinfo.given_name) !== 'undefined' ){
user.name={givenName: userinfo.given_name};
}
if ( typeof(userinfo.family_name) !== 'undefined' ){
user.name={familyName: userinfo.family_name};
}
if ( typeof(userinfo.middle_name) !== 'undefined' ){
user.name={middleName: userinfo.middle_name};
}
return done(null, user);
}
);
passport.use('oidc', oidcStrategy);
app.use(session({
secret: config.cookieSecret,
resave: true,
saveUninitialized: true,
cookie: { secure: true }
}));
app.use(passport.initialize());
app.use(passport.session());
// login
app.get('/auth/login', (req, res, next) =>
{
passport.authenticate('oidc', {
state : base64.encode(JSON.stringify({
roomId : req.query.roomId,
peerName : req.query.peerName,
code : utils.random(10)
}))
})(req, res, next);
});
// logout
app.get('/auth/logout', function(req, res)
{
req.logout();
res.redirect('/');
}
);
// callback
app.get(
'/auth/callback',
passport.authenticate('oidc', { failureRedirect: '/auth/login' }),
(req, res) =>
{
const state = JSON.parse(base64.decode(req.query.state));
if (rooms.has(state.roomId))
{
let displayName,photo
if (typeof(req.user) !== 'undefined'){
if (typeof(req.user.displayName) !== 'undefined') displayName=req.user.displayName;
else displayName="";
if (
typeof(req.user.Photos) !== 'undefined' &&
typeof(req.user.Photos[0]) !== 'undefined' &&
typeof(req.user.Photos[0].value) !== 'undefined'
) photo=req.user.Photos[0].value;
else photo="/static/media/buddy.403cb9f6.svg";
}
const data =
{
peerName : state.peerName,
name : displayName,
picture : photo
};
const room = rooms.get(state.roomId);
room.authCallback(data);
}
res.send('');
}
);
}
function setupWebServer() {
app.use(compression());
app.all('*', (req, res, next) =>
{
if (req.secure)
{
return next();
}
res.send('');
}
);
res.redirect(`https://${req.hostname}${req.url}`);
});
// Serve all files in the public folder as static files.
app.use(express.static('public'));
app.use((req, res) => res.sendFile(`${__dirname}/public/index.html`));
const httpsServer = https.createServer(tls, app);
httpsServer.listen(config.listeningPort, '0.0.0.0', () =>
{
logger.info('Server running on port: ', config.listeningPort);
});
const httpServer = http.createServer(app);
httpServer.listen(config.listeningRedirectPort, '0.0.0.0', () =>
{
logger.info('Server redirecting port: ', config.listeningRedirectPort);
});
const io = require('socket.io')(httpsServer);
// Handle connections from clients.
io.on('connection', (socket) =>
{
const { roomId, peerName } = socket.handshake.query;
if (!roomId || !peerName)
app.get('/', (req, res) =>
{
logger.warn('connection request without roomId and/or peerName');
res.sendFile(`${__dirname}/public/chooseRoom.html`);
});
socket.disconnect(true);
// Serve all files in the public folder as static files.
app.use(express.static('public'));
return;
}
app.use((req, res) => res.sendFile(`${__dirname}/public/index.html`));
logger.info(
'connection request [roomId:"%s", peerName:"%s"]', roomId, peerName);
httpsServer = spdy.createServer(tls, app);
let room;
// If an unknown roomId, create a new Room.
if (!rooms.has(roomId))
httpsServer.listen(config.listeningPort, '0.0.0.0', () =>
{
logger.info('creating a new Room [roomId:"%s"]', roomId);
logger.info('Server running on port: ', config.listeningPort);
});
try
{
room = new Room(roomId, mediaServer, io);
const httpServer = http.createServer(app);
global.APP_ROOM = room;
}
catch (error)
httpServer.listen(config.listeningRedirectPort, '0.0.0.0', () =>
{
logger.info('Server redirecting port: ', config.listeningRedirectPort);
});
};
function setupSocketIO(){
const io = require('socket.io')(httpsServer);
// Handle connections from clients.
io.on('connection', (socket) =>
{
const { roomId, peerName } = socket.handshake.query;
if (!roomId || !peerName)
{
logger.error('error creating a new Room: %s', error);
logger.warn('connection request without roomId and/or peerName');
socket.disconnect(true);
return;
}
const logStatusTimer = setInterval(() =>
{
room.logStatus();
}, 30000);
logger.info(
'connection request [roomId:"%s", peerName:"%s"]', roomId, peerName);
rooms.set(roomId, room);
let room;
room.on('close', () =>
// If an unknown roomId, create a new Room.
if (!rooms.has(roomId))
{
rooms.delete(roomId);
clearInterval(logStatusTimer);
});
}
else
logger.info('creating a new Room [roomId:"%s"]', roomId);
try
{
room = new Room(roomId, mediaServer, io);
global.APP_ROOM = room;
}
catch (error)
{
logger.error('error creating a new Room: %s', error);
socket.disconnect(true);
return;
}
const logStatusTimer = setInterval(() =>
{
room.logStatus();
}, 30000);
rooms.set(roomId, room);
room.on('close', () =>
{
rooms.delete(roomId);
clearInterval(logStatusTimer);
});
}
else
{
room = rooms.get(roomId);
}
socket.room = roomId;
room.handleConnection(peerName, socket);
});
}
if (
typeof(auth) !== 'undefined' &&
typeof(auth.issuerURL) !== 'undefined' &&
typeof(auth.clientOptions) !== 'undefined'
)
{
Issuer.discover(auth.issuerURL).then((oidcIssuer) =>
{
room = rooms.get(roomId);
setupAuth(oidcIssuer);
setupWebServer();
setupSocketIO();
}).catch((err) => {
logger.error(err);
}
);
} else
{
logger.error('Auth is not configure properly!');
setupWebServer();
setupSocketIO();
}
socket.room = roomId;
room.handleConnection(peerName, socket);
});