Surcouche Jitsi prenant en charge notamment l'authentification OIDC
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Jitsi-overlay/app.js

339 lines
11 KiB

3 years ago
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var i18n = require('./i18n');
var jwt = require('jsonwebtoken');
const expressSesssion = require('express-session');
const passport = require('passport');
const { Issuer, Strategy } = require('openid-client');
require('dotenv').config();
var app = express();
app.locals.metricsCache = {};
var indexRouter = require('./routes/index');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(i18n);
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// Proxy HTTP
const {bootstrap} = require('global-agent');
bootstrap();
//
const homepage = process.env.HOME_PATH ? process.env.HOME_PATH + '/index' : 'Home/index';
if (process.env.OID_USE !== undefined && process.env.OID_USE == "true") { // if using openid connect
Issuer.discover(process.env.OID_URL) // oid provider address
.then(criiptoIssuer => {
var client = new criiptoIssuer.Client({
//authorization_signed_response_alg: 'RS512',
id_token_signed_response_alg: process.env.OID_ALG, // openid provider supported algorithm
client_id: process.env.OID_APP_ID, // openid provider app id
client_secret: process.env.OID_SECRET, // openid provider secret
redirect_uris: [process.env.OID_REDIRECT_URI], // redirect url after auth
post_logout_redirect_uris: [process.env.OID_LOGOUT_URI], // redirect after logout
response_type: "code" // response type, "code" is what works the best
});
app.use( // tell the app to use a server side session to store the user infos and other usefull stuff
expressSesssion({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
})
);
app.use(passport.initialize()); // initialize the passport (auth middleware)
app.use(passport.session()); // tell passport to use our session to store it's infos
passport.use( // define the oidc strategy
'oidc',
new Strategy({
client,
params: {
scope: "openid email profile userinfo" // scope we'll be able to access
}
}, (tokenSet, userinfo, done) => {
//return done(null, tokenSet.claims());
done(null, { ...tokenSet.claims(), token: tokenSet.access_token, ...userinfo });
})
);
// handles serialization and deserialization of authenticated user
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
// start authentication request
// app.get('/auth', (req, res, next) => { // default path where we redirect user to when we want to begin the auth flow
// passport.authenticate('oidc')(req, res, next);
// });
// start authentication request
//app.get('/auth/*', (req, res, next) => { // default path where we redirect user to when we want to begin the auth flow
//let roomname = req.url.split("?").shift()
//roomname = roomname.split("/")[2];
//console.log(roomname);
//req.session.room = roomname;
//passport.authenticate('oidc')(req, res, next);
//});
app.get('/', function(req, res, next) { // root path, just a check in the session to see if we need to show a login/logout button based on if we're authenticated or not
req.session.room = '';
if (req.user) {
res.render(homepage, {
from_electron: req.query.from_electron,
authentified: true
});
} else {
res.render(homepage, {
from_electron: req.query.from_electron,
authentified: false
});
}
});
// authentication callback, where the oidc provider hand us the user back after login
app.get('/auth/callback', (req, res, next) => {
passport.authenticate('oidc', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.redirect('/');
}
req.logIn(user, function(err) {
if (err) {
return next(err);
}
if (typeof req.session.room !== 'undefined' && req.session.room) { // check were really in a room
req.session.room_jwt = req.session.room; // keep the room the jwt token was generated for
let firstnameClaim = process.env.OID_FIRSTNAME_CLAIM || 'given_name';
let lastnameClaim = process.env.OID_LASTNAME_CLAIM || 'family_name';
let emailClaim = process.env.OID_EMAIL_CLAIM || 'email';
let name = (user[firstnameClaim] + ' ' + user[lastnameClaim]).trim();
let email = user[emailClaim];
var token = jwt.sign({ // generate the jwt based on the info in the session
"context": {
"user": {
"name": name,
"email": email,
},
},
"aud": "jitsi",
"iss": process.env.JWT_APP_ID,
"sub": process.env.JITSI_DOMAIN, // jitsi domain
"room": "*"
}, process.env.JWT_SECRET);
req.session.jitsi_jwt = token;
return res.redirect("https:" + "//" + req.headers.host + "/" + req.session.room); // redirect to the room
} else {
return res.redirect("https:" + "//" + req.headers.host + "/"); // redirect to root path
}
});
})(req, res, next);
});
// start authentication request
// app.get('/auth/*', (req, res, next) => { // default path where we redirect user to when we want to begin the auth flow
// let roomname = req.url.split("?").shift()
// roomname = roomname.split("/")[2];
// console.log(roomname);
// req.session.room = roomname;
// passport.authenticate('oidc')(req, res, next);
// });
app.get('/auth/:room', (req, res, next) => { // default path where we redirect user to when we want to begin the auth flow
var stringHelper = require('./lib/Shared/StringHelper');
var room = stringHelper.customEncodeURIComponent(req.params['room']);
// let roomname = req.url.split("?").shift()
// roomname = roomname.split("/")[2];
console.log(room);
req.session.room = room;
passport.authenticate('oidc')(req, res, next);
});
// start logout request
app.get('/logout', (req, res) => {
req.session.room = '';
req.session.jitsi_jwt = '';
req.session.room_jwt = '';
res.redirect(client.endSessionUrl());
});
// logout callback, where the oidc provider hand us the user back after logout
app.get('/logout/callback', (req, res) => {
// clears the persisted user from the local storage
req.logout();
// redirects the user to a public route
res.redirect('/');
});
const api = require('./lib/Api/index');
app.get('/Api/metrics', api.metrics)
const room = require('./lib/Room/index');
app.post('/Room/Rate', room.rate);
app.get('/:room', (req, res, next) => {
var stringHelper = require('./lib/Shared/StringHelper');
var room = stringHelper.customEncodeURIComponent(req.params['room']);
req.session.room = room;
if (req.query.embedded == '1' || req.query.embedded == '1/') {
res.sendFile('/usr/share/jitsi-meet/index.html');
} else {
if (req.query.guest == '1' || req.query.guest == '1/') {
res.render('Room/index', {
room: room,
from_electron: req.query.from_electron,
jwt: req.query.jwt,
enable_auth_modal: false,
authentified: false
});
} else {
if (req.user) {
if (req.query.jwt) {
res.render('Room/index', {
room: room,
from_electron: req.query.from_electron,
jwt: req.query.jwt,
enable_auth_modal: false,
authentified: true
});
} else {
if (req.session.room_jwt != room || req.session.jitsi_jwt == '') {
res.redirect("https:" + "//" + req.headers.host + "/auth/" + room);
} else {
res.render('Room/index', {
room: room,
from_electron: req.query.from_electron,
jwt: req.session.jitsi_jwt,
enable_auth_modal: false,
authentified: true
});
}
}
} else {
if (req.query.jwt) {
res.render('Room/index', {
room: room,
from_electron: req.query.from_electron,
jwt: req.query.jwt,
enable_auth_modal: false,
authentified: false
});
} else {
res.render('Room/index', {
room: room,
from_electron: req.query.from_electron,
jwt: req.query.jwt,
enable_auth_modal: true,
authentified: false
});
}
}
}
}
});
});
} else { // if not using openid connect, we dont bother with aditional paths
/* GET welcome page. */
app.get('/', function(req, res, next) {
res.render(homepage, {
from_electron: req.query.from_electron,
enable_auth_modal: false,
authentified: false
});
});
const api = require('./lib/Api/index');
app.get('/Api/metrics', api.metrics)
const room = require('./lib/Room/index');
app.post('/Room/Rate', room.rate);
app.get('/:room', (req, res, next) => {
var stringHelper = require('./lib/Shared/StringHelper');
var room = stringHelper.customEncodeURIComponent(req.params['room']);
if (req.query.embedded == '1' || req.query.embedded == '1/') {
res.sendFile('/usr/share/jitsi-meet/index.html');
} else {
res.render('Room/index', {
room: room,
from_electron: req.query.from_electron,
jwt: req.query.jwt,
enable_auth_modal: false,
authentified: false
});
}
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('Shared/error', {
from_electron: req.query.from_electron
});
});
}
module.exports = app;