[mirotalk] - enable OIDC authentication in conjunction with Host protected
This commit is contained in:
+4
-2
@@ -43,11 +43,13 @@ OIDC_ISSUER_BASE_URL='https://server.example.com'
|
||||
OIDC_BASE_URL='http://localhost:3000' # https://p2p.mirotalk.com
|
||||
OIDC_CLIENT_ID='ClientID'
|
||||
OIDC_CLIENT_SECRET='ClientSecret'
|
||||
OIDC_AUTH_REUIRED=false # set to true if authentication is required for all routes
|
||||
SESSION_SECRET='mirotalk-p2p-oidc-secret'
|
||||
|
||||
# Host protection
|
||||
# HOST_PROTECTED: When set to true, it requires a valid username and password from the HOST_USERS list to initialize or join a room.
|
||||
# HOST_USER_AUTH: When set to true, it also requires a valid username and password for joining the room.
|
||||
# HOST_PROTECTED:
|
||||
# - When set to true, it requires a valid username and password from the HOST_USERS list to initialize or join a room.
|
||||
# - When OIDC_ENABLED is utilized alongside host protection, the authenticated user will be recognized as valid.# HOST_USER_AUTH: When set to true, it also requires a valid username and password for joining the room.
|
||||
# HOST_USERS: This is the list of valid users along with their credentials.
|
||||
|
||||
HOST_PROTECTED=false # true or false
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
module.exports = class Host {
|
||||
constructor() {
|
||||
this.authorizedIPs = new Map();
|
||||
this.roomActive = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IP from req
|
||||
* @param {object} req
|
||||
* @returns string IP
|
||||
*/
|
||||
getIP(req) {
|
||||
return req.headers['x-forwarded-for'] || req.headers['X-Forwarded-For'] || req.socket.remoteAddress || req.ip;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -20,6 +30,7 @@ module.exports = class Host {
|
||||
*/
|
||||
setAuthorizedIP(ip, authorized) {
|
||||
this.authorizedIPs.set(ip, authorized);
|
||||
this.setRoomActive();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,12 +42,37 @@ module.exports = class Host {
|
||||
return this.authorizedIPs.has(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Host room status
|
||||
* @returns boolean
|
||||
*/
|
||||
isRoomActive() {
|
||||
return this.roomActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set host room activate
|
||||
*/
|
||||
setRoomActive() {
|
||||
this.roomActive = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set host room deactivate
|
||||
*/
|
||||
setRoomDeactivate() {
|
||||
this.roomActive = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete ip from authorized IPs
|
||||
* @param {string} ip
|
||||
* @returns boolean
|
||||
*/
|
||||
deleteIP(ip) {
|
||||
if (this.isAuthorizedIP(ip)) {
|
||||
this.setRoomDeactivate();
|
||||
}
|
||||
return this.authorizedIPs.delete(ip);
|
||||
}
|
||||
};
|
||||
|
||||
+74
-14
@@ -40,7 +40,7 @@ dependencies: {
|
||||
* @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.3.28
|
||||
* @version 1.3.29
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -295,7 +295,7 @@ const OIDC = {
|
||||
response_type: 'code',
|
||||
scope: 'openid profile email',
|
||||
},
|
||||
authRequired: false, // Set to true if authentication is required for all routes
|
||||
authRequired: process.env.OIDC_AUTH_REQUIRED ? getEnvBoolean(process.env.OIDC_AUTH_REQUIRED) : false, // Set to true if authentication is required for all routes
|
||||
auth0Logout: true, // Set to true to enable logout with Auth0
|
||||
routes: {
|
||||
callback: '/auth/callback', // Indicating the endpoint where your application will handle the callback from the authentication provider after a user has been authenticated.
|
||||
@@ -306,13 +306,36 @@ const OIDC = {
|
||||
};
|
||||
|
||||
// Custom middleware function for OIDC authentication
|
||||
const OIDCAuth = function (req, res, next) {
|
||||
function OIDCAuth(req, res, next) {
|
||||
if (OIDC.enabled) {
|
||||
requiresAuth()(req, res, next); // Apply requiresAuth() middleware conditionally
|
||||
// Apply requiresAuth() middleware conditionally
|
||||
requiresAuth()(req, res, function () {
|
||||
log.debug('[OIDC] ------> requiresAuth');
|
||||
// Check if user is authenticated
|
||||
if (req.oidc.isAuthenticated()) {
|
||||
log.debug('[OIDC] ------> User isAuthenticated');
|
||||
// User is authenticated
|
||||
if (hostCfg.protected) {
|
||||
const ip = authHost.getIP(req);
|
||||
hostCfg.authenticated = true;
|
||||
authHost.setAuthorizedIP(ip, true);
|
||||
// Check...
|
||||
log.debug('[OIDC] ------> Host protected', {
|
||||
authenticated: hostCfg.authenticated,
|
||||
authorizedIPs: authHost.getAuthorizedIPs(),
|
||||
activeRoom: authHost.isRoomActive(),
|
||||
});
|
||||
}
|
||||
next();
|
||||
} else {
|
||||
// User is not authenticated
|
||||
res.status(401).send('Unauthorized');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// stats configuration
|
||||
const statsData = {
|
||||
@@ -426,16 +449,33 @@ app.get('/auth/callback', (req, res, next) => {
|
||||
|
||||
// Logout Route
|
||||
app.get('/logout', (req, res) => {
|
||||
if (OIDC.enabled) req.logout();
|
||||
if (OIDC.enabled) {
|
||||
//
|
||||
if (hostCfg.protected) {
|
||||
const ip = authHost.getIP(req);
|
||||
if (authHost.isAuthorizedIP(ip)) {
|
||||
authHost.deleteIP(ip);
|
||||
}
|
||||
hostCfg.authenticated = false;
|
||||
//
|
||||
log.debug('[OIDC] ------> Logout', {
|
||||
authenticated: hostCfg.authenticated,
|
||||
authorizedIPs: authHost.getAuthorizedIPs(),
|
||||
activeRoom: authHost.isRoomActive(),
|
||||
});
|
||||
}
|
||||
req.logout(); // Logout user
|
||||
}
|
||||
res.redirect('/'); // Redirect to the home page after logout
|
||||
});
|
||||
|
||||
// main page
|
||||
app.get(['/'], OIDCAuth, (req, res) => {
|
||||
if (hostCfg.protected && !hostCfg.authenticated) {
|
||||
if ((!OIDC.enabled && hostCfg.protected && !hostCfg.authenticated) || authHost.isRoomActive()) {
|
||||
const ip = getIP(req);
|
||||
if (allowedIP(ip)) {
|
||||
res.sendFile(views.landing);
|
||||
hostCfg.authenticated = true;
|
||||
} else {
|
||||
hostCfg.authenticated = false;
|
||||
res.sendFile(views.login);
|
||||
@@ -447,10 +487,11 @@ app.get(['/'], OIDCAuth, (req, res) => {
|
||||
|
||||
// set new room name and join
|
||||
app.get(['/newcall'], OIDCAuth, (req, res) => {
|
||||
if (hostCfg.protected && !hostCfg.authenticated) {
|
||||
if ((!OIDC.enabled && hostCfg.protected && !hostCfg.authenticated) || authHost.isRoomActive()) {
|
||||
const ip = getIP(req);
|
||||
if (allowedIP(ip)) {
|
||||
res.sendFile(views.newCall);
|
||||
hostCfg.authenticated = true;
|
||||
} else {
|
||||
hostCfg.authenticated = false;
|
||||
res.sendFile(views.login);
|
||||
@@ -485,7 +526,7 @@ app.get(['/test'], (req, res) => {
|
||||
});
|
||||
|
||||
// Handle Direct join room with params
|
||||
app.get('/join/', OIDCAuth, async (req, res) => {
|
||||
app.get('/join/', async (req, res) => {
|
||||
if (Object.keys(req.query).length > 0) {
|
||||
log.debug('Request Query', req.query);
|
||||
/*
|
||||
@@ -495,6 +536,14 @@ app.get('/join/', OIDCAuth, async (req, res) => {
|
||||
*/
|
||||
const { room, name, audio, video, screen, notify, hide, token } = checkXSS(req.query);
|
||||
|
||||
const OIDCUserAuthenticated = OIDC.enabled && req.oidc.isAuthenticated();
|
||||
|
||||
log.debug('Direct Join', {
|
||||
OIDCUserAuthenticated: OIDCUserAuthenticated,
|
||||
authenticated: hostCfg.authenticated,
|
||||
host_protected: hostCfg.protected,
|
||||
});
|
||||
|
||||
let peerUsername,
|
||||
peerPassword = '';
|
||||
let isPeerValid = false;
|
||||
@@ -526,7 +575,7 @@ app.get('/join/', OIDCAuth, async (req, res) => {
|
||||
}
|
||||
|
||||
// Peer valid going to auth as host
|
||||
if (hostCfg.protected && isPeerValid && isPeerPresenter && !hostCfg.authenticated) {
|
||||
if ((hostCfg.protected && isPeerValid && isPeerPresenter && !hostCfg.authenticated) || OIDCUserAuthenticated) {
|
||||
const ip = getIP(req);
|
||||
hostCfg.authenticated = true;
|
||||
authHost.setAuthorizedIP(ip, true);
|
||||
@@ -548,12 +597,23 @@ app.get('/join/', OIDCAuth, async (req, res) => {
|
||||
});
|
||||
|
||||
// Join Room by id
|
||||
app.get('/join/:roomId', OIDCAuth, function (req, res) {
|
||||
app.get('/join/:roomId', function (req, res) {
|
||||
// log.debug('Join to room', { roomId: req.params.roomId });
|
||||
if (hostCfg.authenticated) {
|
||||
const OIDCUserAuthenticated = OIDC.enabled && req.oidc.isAuthenticated();
|
||||
|
||||
if (OIDCUserAuthenticated || hostCfg.authenticated || authHost.isRoomActive()) {
|
||||
log.debug('/join/room', {
|
||||
OIDCUserAuthenticated: OIDCUserAuthenticated,
|
||||
authenticated: hostCfg.authenticated,
|
||||
host_protected: hostCfg.protected,
|
||||
activeRoom: authHost.isRoomActive(),
|
||||
});
|
||||
|
||||
if (hostCfg.protected) authHost.setRoomActive();
|
||||
|
||||
res.sendFile(views.client);
|
||||
} else {
|
||||
if (hostCfg.protected) {
|
||||
if (!OIDC.enabled && hostCfg.protected) {
|
||||
return res.sendFile(views.login);
|
||||
}
|
||||
res.redirect('/');
|
||||
@@ -908,8 +968,8 @@ io.sockets.on('connect', async (socket) => {
|
||||
*/
|
||||
socket.on('disconnect', async (reason) => {
|
||||
for (let channel in socket.channels) {
|
||||
await removePeerFrom(channel);
|
||||
removeIP(socket);
|
||||
await removePeerFrom(channel);
|
||||
}
|
||||
log.debug('[' + socket.id + '] disconnected', { reason: reason });
|
||||
delete sockets[socket.id];
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mirotalk",
|
||||
"version": "1.3.28",
|
||||
"version": "1.3.29",
|
||||
"description": "A free WebRTC browser-based video call",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
@@ -51,7 +51,7 @@
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"ngrok": "^5.0.0-beta.2",
|
||||
"nodemailer": "^6.9.13",
|
||||
"openai": "^4.40.2",
|
||||
"openai": "^4.41.1",
|
||||
"qs": "^6.12.1",
|
||||
"socket.io": "^4.7.5",
|
||||
"swagger-ui-express": "^5.0.0",
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.3.28
|
||||
* @version 1.3.29
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user