[mirotalksfu] - Improve config.js.template, add .env.template, update dep

هذا الالتزام موجود في:
Miroslav Pejic
2025-03-29 00:54:08 +01:00
الأصل 531b1342c5
التزام e3511513bc
19 ملفات معدلة مع 1594 إضافات و834 حذوفات

عرض الملف

@@ -6,21 +6,21 @@ const colors = require('colors');
const config = require('./config');
config.console.colors ? colors.enable() : colors.disable();
config.system?.console?.colors ? colors.enable() : colors.disable();
const options = {
depth: null,
colors: config.console.colors,
colors: config.system?.console?.colors || false,
};
module.exports = class Logger {
constructor(appName = 'miroTalkSfu') {
this.appName = colors.yellow(appName);
this.debugOn = config.console.debug;
this.debugOn = config.system?.console?.debug || true;
this.timeStart = Date.now();
this.timeEnd = null;
this.timeElapsedMs = null;
this.tzOptions = {
timeZone: process.env.TZ || config.console.timeZone || 'UTC',
timeZone: process.env.TZ || config.system?.console?.timeZone || 'UTC',
hour12: false,
};
}

عرض الملف

@@ -20,12 +20,12 @@ class Mattermost {
password,
commands = '/sfu',
texts = '/sfu',
} = config.mattermost || {};
} = config.integrations.mattermost || {};
if (!enabled) return; // Check if Mattermost integration is enabled
this.app = app;
this.allowed = config.api.allowed && config.api.allowed.mattermost;
this.allowed = config.api?.allowed?.mattermost || false;
this.token = token;
this.serverUrl = serverUrl;
this.username = username;

عرض الملف

@@ -34,8 +34,8 @@ module.exports = class Room {
this._hostOnlyRecording = false;
// ##########################
this.recording = {
recSyncServerRecording: config?.server?.recording?.enabled || false,
recSyncServerEndpoint: config?.server?.recording?.endpoint || '',
recSyncServerRecording: config?.media?.recording?.enabled || false,
recSyncServerEndpoint: config?.media?.recording?.endpoint || '',
};
// ##########################
this._moderator = {
@@ -49,9 +49,9 @@ module.exports = class Room {
chat_cant_chatgpt: false,
media_cant_sharing: false,
};
this.survey = config.survey;
this.redirect = config.redirect;
this.videoAIEnabled = config?.videoAI?.enabled || false;
this.survey = config?.features?.survey;
this.redirect = config?.features?.redirect;
this.videoAIEnabled = config?.integrations?.videoAI?.enabled || false;
this.peers = new Map();
this.bannedPeers = [];
this.webRtcTransport = config.mediasoup.webRtcTransport;
@@ -62,12 +62,12 @@ module.exports = class Room {
// RTMP configuration
this.rtmpFileStreamer = null;
this.rtmpUrlStreamer = null;
this.rtmp = config.server.rtmp || false;
this.rtmp = config?.media?.rtmp || false;
// Polls
this.polls = [];
this.isHostProtected = config.host.protected;
this.isHostProtected = config?.security?.host?.protected || false;
// Share Media
this.shareMediaData = {};

عرض الملف

@@ -1,8 +1,7 @@
'use strict';
const config = require('./config');
const ffmpegPath =
config.server.rtmp && config.server.rtmp.ffmpegPath ? config.server.rtmp.ffmpegPath : '/usr/bin/ffmpeg';
const ffmpegPath = config.media?.rtmp?.ffmpegPath || '/usr/bin/ffmpeg';
const ffmpeg = require('fluent-ffmpeg');
ffmpeg.setFfmpegPath(ffmpegPath);

عرض الملف

@@ -3,8 +3,7 @@
const config = require('./config');
const { PassThrough } = require('stream');
const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath =
config.server.rtmp && config.server.rtmp.ffmpegPath ? config.server.rtmp.ffmpegPath : '/usr/bin/ffmpeg';
const ffmpegPath = config.media?.rtmp?.ffmpegPath || '/usr/bin/ffmpeg';
ffmpeg.setFfmpegPath(ffmpegPath);
const Logger = require('./Logger');

عرض الملف

@@ -1,8 +1,7 @@
'use strict';
const config = require('./config');
const ffmpegPath =
config.server.rtmp && config.server.rtmp.ffmpegPath ? config.server.rtmp.ffmpegPath : '/usr/bin/ffmpeg';
const ffmpegPath = config.media?.rtmp?.ffmpegPath || '/usr/bin/ffmpeg';
const ffmpeg = require('fluent-ffmpeg');
ffmpeg.setFfmpegPath(ffmpegPath);

عرض الملف

@@ -64,7 +64,7 @@ dev dependencies: {
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.7.99
* @version 1.8.00
*
*/
@@ -107,8 +107,8 @@ const packageJson = require('../../package.json');
const { v4: uuidv4 } = require('uuid');
const crypto = require('crypto-js');
const RtmpStreamer = require('./RtmpStreamer.js'); // Import the RtmpStreamer class
const rtmpCfg = config.server.rtmp;
const rtmpDir = rtmpCfg && rtmpCfg.dir ? rtmpCfg.dir : 'rtmp';
const rtmpCfg = config?.media?.rtmp;
const rtmpDir = rtmpCfg?.dir || 'rtmp';
// File and Url Rtmp streams count
let rtmpFileStreamsCount = 0;
@@ -120,14 +120,14 @@ const nodemailer = require('./lib/nodemailer');
// Slack API
const CryptoJS = require('crypto-js');
const qS = require('qs');
const slackEnabled = config.slack.enabled;
const slackSigningSecret = config.slack.signingSecret;
const slackEnabled = config?.integrations?.slack?.enabled || false;
const slackSigningSecret = config?.integrations?.slack?.signingSecret || '';
const app = express();
const options = {
cert: fs.readFileSync(path.join(__dirname, config.server.ssl.cert), 'utf-8'),
key: fs.readFileSync(path.join(__dirname, config.server.ssl.key), 'utf-8'),
cert: fs.readFileSync(path.join(__dirname, config?.server?.ssl.cert || '../ssl/cert.pem'), 'utf-8'),
key: fs.readFileSync(path.join(__dirname, config?.server?.ssl.key || '../ssl/key.pem'), 'utf-8'),
};
const corsOptions = {
@@ -143,38 +143,38 @@ const io = socketIo(server, {
cors: corsOptions,
});
const host = config.server.hostUrl || `http://localhost:${config.server.listen.port}`;
const trustProxy = !!config.server.trustProxy;
const host = config?.server?.hostUrl || `http://localhost:${config?.server?.listen?.port || 3010}`;
const trustProxy = Boolean(config?.server?.trustProxy);
const jwtCfg = {
JWT_KEY: (config.jwt && config.jwt.key) || 'mirotalksfu_jwt_secret',
JWT_EXP: (config.jwt && config.jwt.exp) || '1h',
JWT_KEY: config?.security?.jwt?.key || 'mirotalksfu_jwt_secret',
JWT_EXP: config?.security?.jwt?.exp || '1h',
};
const hostCfg = {
protected: config.host.protected,
user_auth: config.host.user_auth,
users: config.host.users,
users_from_db: config.host.users_from_db,
users_api_room_allowed: config.host.users_api_room_allowed,
users_api_rooms_allowed: config.host.users_api_rooms_allowed,
users_api_endpoint: config.host.users_api_endpoint,
users_api_secret_key: config.host.users_api_secret_key,
api_room_exists: config.host.api_room_exists,
users: config.host.users,
authenticated: !config.host.protected,
protected: config?.security?.host?.protected,
authenticated: !config?.security?.host?.protected,
user_auth: config?.security?.host?.user_auth,
users: config?.security?.host?.users,
users_from_db: config?.security?.host?.users_from_db,
users_api_room_allowed: config?.security?.host?.users_api_room_allowed,
users_api_rooms_allowed: config?.security?.host?.users_api_rooms_allowed,
users_api_endpoint: config?.security?.host?.users_api_endpoint,
users_api_secret_key: config?.security?.host?.users_api_secret_key,
api_room_exists: config?.security?.host?.api_room_exists,
presenters: config?.security?.host?.presenters,
};
const restApi = {
basePath: '/api/v1', // api endpoint path
docs: host + '/api/v1/docs', // api docs
allowed: config.api?.allowed,
allowed: config.api?.allowed || {},
};
// Sentry monitoring
const sentryEnabled = config.sentry.enabled;
const sentryDSN = config.sentry.DSN;
const sentryTracesSampleRate = config.sentry.tracesSampleRate;
const sentryEnabled = config.integrations?.sentry?.enabled || false;
const sentryDSN = config.integrations.sentry.DSN;
const sentryTracesSampleRate = config.integrations.sentry.tracesSampleRate;
if (sentryEnabled) {
Sentry.init({
dsn: sentryDSN,
@@ -202,7 +202,7 @@ const webhook = {
};
// Discord Bot
const { enabled, commands, token } = config.discord || {};
const { enabled, commands, token } = config?.integrations?.discord || {};
if (enabled && commands.length > 0 && token) {
const discordBot = new Discord(token, commands);
@@ -218,12 +218,12 @@ const defaultStats = {
// OpenAI/ChatGPT
let chatGPT;
if (config.chatGPT.enabled) {
if (config.chatGPT.apiKey) {
if (config?.integrations?.chatGPT?.enabled) {
if (config?.integrations?.chatGPT?.apiKey) {
const { OpenAI } = require('openai');
const configuration = {
basePath: config.chatGPT.basePath,
apiKey: config.chatGPT.apiKey,
basePath: config?.integrations?.chatGPT?.basePath,
apiKey: config?.integrations?.chatGPT?.apiKey,
};
chatGPT = new OpenAI(configuration);
} else {
@@ -232,18 +232,18 @@ if (config.chatGPT.enabled) {
}
// OpenID Connect
const OIDC = config.oidc ? config.oidc : { enabled: false };
const OIDC = config?.security?.oidc || { enabled: false };
// directory
const dir = {
public: path.join(__dirname, '../../', 'public'),
rec: path.join(__dirname, '../', config?.server?.recording?.dir ? config.server.recording.dir + '/' : 'rec/'),
rtmp: path.join(__dirname, '../', config?.rtmp?.dir ? config.rtmp.dir + '/' : 'rtmp/'),
public: path.join(__dirname, '../../public'),
rec: path.join(__dirname, '../', config?.media?.recording?.dir || 'rec', '/'),
rtmp: path.join(__dirname, '../', config?.media?.rtmp?.dir || 'rtmp', '/'),
};
// Rec directory create and set max file size
const recMaxFileSize = config?.server?.recording?.maxFileSize || 1 * 1024 * 1024 * 1024; // 1GB default
const serverRecordingEnabled = config?.server?.recording?.enabled;
const recMaxFileSize = config?.media?.recording?.maxFileSize || 1 * 1024 * 1024 * 1024; // 1GB default
const serverRecordingEnabled = config?.media?.recording?.enabled || false;
if (serverRecordingEnabled) {
log.debug('Server Recording enabled creating dir', dir.rtmp);
if (!fs.existsSync(dir.rec)) {
@@ -306,7 +306,7 @@ let nextMediasoupWorkerIdx = 0;
// Autodetect announcedAddress with multiple fallback services
if (!announcedAddress && IP === '0.0.0.0') {
const detectPublicIp = async () => {
const services = config.services?.ip || [
const services = config.system?.services?.ip || [
'http://api.ipify.org',
'http://ipinfo.io/ip',
'http://ifconfig.me/ip',
@@ -554,12 +554,12 @@ function startServer() {
// UI buttons configuration
app.get('/config', (req, res) => {
res.status(200).json({ message: config.ui ? config.ui.buttons : false });
res.status(200).json({ message: config?.ui?.buttons || false });
});
// Brand configuration
app.get('/brand', (req, res) => {
res.status(200).json({ message: config.ui ? config.ui.brand : false });
res.status(200).json({ message: config?.ui?.brand || false });
});
// main page
@@ -780,7 +780,7 @@ function startServer() {
// Get stats endpoint
app.get('/stats', (req, res) => {
const stats = config.stats ? config.stats : defaultStats;
const stats = config?.features?.stats || defaultStats;
// log.debug('Send stats', stats);
res.send(stats);
});
@@ -833,12 +833,9 @@ function startServer() {
authorizedIps: authHost.getAuthorizedIPs(),
});
const isPresenter =
config.presenters && config.presenters.join_first
? true
: config.presenters &&
config.presenters.list &&
config.presenters.list.includes(username).toString();
const isPresenter = Boolean(
hostCfg?.presenters?.join_first || hostCfg?.presenters?.list?.includes(username),
);
const token = encodeToken({ username: username, password: password, presenter: isPresenter });
const allowedRooms = await getUserAllowedRooms(username, password);
@@ -848,8 +845,7 @@ function startServer() {
if (isPeerValid) {
log.debug('PEER LOGIN OK', { ip: ip, authorized: true });
const isPresenter =
config.presenters && config.presenters.list && config.presenters.list.includes(username).toString();
const isPresenter = hostCfg?.presenters?.list?.includes(username) || false;
const token = encodeToken({ username: username, password: password, presenter: isPresenter });
const allowedRooms = await getUserAllowedRooms(username, password);
return res.status(200).json({ message: token, allowedRooms: allowedRooms });
@@ -982,7 +978,9 @@ function startServer() {
return res.status(400).send('RTMP server is not enabled or missing the config');
}
const domainName = config.ngrok.enabled ? 'localhost' : req.headers.host.split(':')[0];
const domainName = config?.integrations?.ngrok?.enabled
? 'localhost'
: req.headers.host?.split(':')[0] || 'localhost';
const rtmpServer = rtmpCfg.server != '' ? rtmpCfg.server : false;
const rtmpServerAppName = rtmpCfg.appName != '' ? rtmpCfg.appName : 'live';
@@ -1283,7 +1281,7 @@ function startServer() {
// ####################################################
function getServerConfig(tunnel = false) {
return {
const safeConfig = {
// Network & Connectivity
network: {
server_listen: host,
@@ -1301,68 +1299,74 @@ function startServer() {
// Security & Authentication
security: {
cors_options: corsOptions,
cors: corsOptions,
jwtCfg: jwtCfg,
hostProtected: hostCfg.protected || hostCfg.user_auth ? hostCfg : false,
ip_lookup_enabled: config.IPLookup?.enabled ? config.IPLookup : false,
oidc: OIDC.enabled ? OIDC : false,
host: hostCfg?.protected || hostCfg?.user_auth ? hostCfg : { presenters: hostCfg.presenters },
ip_lookup: config.integrations?.IPLookup?.enabled ? config.integrations.IPLookup : false,
oidc: OIDC?.enabled ? OIDC : false,
middleware: {
IpWhitelist: config?.security?.middleware?.IpWhitelist?.enabled
? config.security.middleware.IpWhitelist
: false,
//...
},
},
// API & Services
api: {
rest_api: restApi,
webhook: webhook,
presenters: config.presenters,
webhook: webhook.enabled ? webhook : false,
},
// Media Configuration
media: {
mediasoup: {
listenInfos: config.mediasoup.webRtcTransport.listenInfos,
worker_bin: mediasoup.workerBin,
server_version: mediasoup.version,
client_version: mediasoupClient.version,
listenInfos: config.mediasoup?.webRtcTransport?.listenInfos,
worker_bin: mediasoup?.workerBin,
server_version: mediasoup?.version,
client_version: mediasoupClient?.version,
},
rtmp_enabled: rtmpCfg.enabled ? rtmpCfg : false,
videoAI_enabled: config.videoAI.enabled ? config.videoAI : false,
server_recording: config?.server?.recording,
rtmp_enabled: rtmpCfg?.enabled ? rtmpCfg : false,
videoAI_enabled: config.integrations?.videoAI?.enabled ? config.integrations.videoAI : false,
server_recording: config?.media?.recording?.enabled ? config.media.recording : false,
},
// Communication Integrations
integrations: {
discord: config.discord?.enabled ? config.discord : false,
mattermost: config.mattermost?.enabled ? config.mattermost : false,
slack: slackEnabled ? config.slack : false,
chatGPT: config.chatGPT?.enabled ? config.chatGPT : false,
email_alerts: config.email?.alert ? config.email : false,
discord: config.integrations?.discord?.enabled ? config.integrations.discord : false,
mattermost: config.integrations?.mattermost?.enabled ? config.integrations.mattermost : false,
slack: slackEnabled ? config.integrations?.slack : false,
chatGPT: config.integrations?.chatGPT?.enabled ? config.integrations.chatGPT : false,
email_alerts: config?.integrations?.email?.alert ? config.integrations.email : false,
},
// UI & Branding
ui: {
brand: config.ui.brand,
buttons: config.ui.buttons,
middleware: config.middleware,
brand: config.ui?.brand,
buttons: config.ui?.buttons,
},
// Monitoring & Analytics
monitoring: {
sentry: sentryEnabled ? config.sentry : false,
stats: config.stats?.enabled ? config.stats : false,
system_info: config.systemInfo,
sentry: sentryEnabled ? config.integrations?.sentry : false,
stats: config.features?.stats?.enabled ? config.features.stats : false,
system_info: config.system?.info,
},
// Features & Functionality
features: {
survey: config.survey?.enabled ? config.survey : false,
redirect: config.redirect?.enabled ? config.redirect : false,
survey: config.features?.survey?.enabled ? config.features.survey : false,
redirect: config.features?.redirect?.enabled ? config.features.redirect : false,
},
// Version Information
versions: {
app: packageJson.version,
app: packageJson?.version,
node: process.versions.node,
},
};
return safeConfig;
}
// ####################################################
@@ -1371,8 +1375,8 @@ function startServer() {
async function ngrokStart() {
try {
await ngrok.authtoken(config.ngrok.authToken);
const listener = await ngrok.forward({ addr: config.server.listen.port });
await ngrok.authtoken(config?.integrations?.ngrok?.authToken);
const listener = await ngrok.forward({ addr: config?.server?.listen?.port });
const tunnelUrl = listener.url();
log.info('Server config', getServerConfig(tunnelUrl));
} catch (err) {
@@ -1386,7 +1390,7 @@ function startServer() {
// START SERVER
// ####################################################
server.listen(config.server.listen.port, () => {
server.listen(config?.server?.listen?.port || 3010, () => {
log.log(
`%c
@@ -1401,7 +1405,7 @@ function startServer() {
'font-family:monospace',
);
if (config.ngrok.enabled && config.ngrok.authToken !== '') {
if (config?.integrations?.ngrok?.enabled && config?.integrations?.ngrok?.authToken !== '') {
return ngrokStart();
}
log.info('Server config', getServerConfig());
@@ -1527,7 +1531,7 @@ function startServer() {
const peer_ip = getIpSocket(socket);
// Get peer Geo Location
if (config.IPLookup.enabled && peer_ip != '::1') {
if (config?.integrations?.IPLookup?.enabled && peer_ip != '::1') {
dataObject.peer_geo = await getPeerGeoLocation(peer_ip);
}
@@ -1569,10 +1573,10 @@ function startServer() {
return cb('unauthorized');
}
is_presenter =
const is_presenter =
presenter === '1' ||
presenter === 'true' ||
(config.presenters.join_first && room.getPeersCount() === 0);
(hostCfg?.presenters?.join_first && room?.getPeersCount() === 0);
log.debug('[Join] - HOST PROTECTED - USER AUTH check peer', {
ip: peer_ip,
@@ -1637,7 +1641,7 @@ function startServer() {
is_presenter: is_presenter,
};
// first we check if the username match the presenters username
if (config.presenters && config.presenters.list && config.presenters.list.includes(peer_name)) {
if (hostCfg?.presenters?.list?.includes(peer_name)) {
presenters[socket.room_id][socket.id] = presenter;
} else {
// if not match the presenters username, the first one join room is the presenter
@@ -2486,7 +2490,7 @@ function startServer() {
socket.on('getChatGPT', async ({ time, room, name, prompt, context }, cb) => {
if (!roomExists(socket)) return;
if (!config.chatGPT.enabled) return cb({ message: 'ChatGPT seems disabled, try later!' });
if (!config?.integrations?.chatGPT?.enabled) return cb({ message: 'ChatGPT seems disabled, try later!' });
// https://platform.openai.com/docs/api-reference/completions/create
try {
@@ -2494,10 +2498,10 @@ function startServer() {
context.push({ role: 'user', content: prompt });
// Call OpenAI's API to generate response
const completion = await chatGPT.chat.completions.create({
model: config.chatGPT.model || 'gpt-3.5-turbo',
model: config?.integrations?.chatGPT?.model || 'gpt-3.5-turbo',
messages: context,
max_tokens: config.chatGPT.max_tokens,
temperature: config.chatGPT.temperature,
max_tokens: config?.integrations?.chatGPT?.max_tokens,
temperature: config?.integrations?.chatGPT?.temperature,
});
// Extract message from completion
const message = completion.choices[0].message.content.trim();
@@ -2532,14 +2536,14 @@ function startServer() {
// https://docs.heygen.com/reference/list-avatars-v2
socket.on('getAvatarList', async ({}, cb) => {
if (!config.videoAI.enabled || !config.videoAI.apiKey)
if (!config?.integrations?.videoAI?.enabled || !config?.integrations?.videoAI?.apiKey)
return cb({ error: 'Video AI seems disabled, try later!' });
try {
const response = await axios.get(`${config.videoAI.basePath}/v2/avatars`, {
const response = await axios.get(`${config?.integrations?.videoAI?.basePath}/v2/avatars`, {
headers: {
'Content-Type': 'application/json',
'X-Api-Key': config.videoAI.apiKey,
'X-Api-Key': config?.integrations?.videoAI?.apiKey,
},
});
@@ -2556,14 +2560,14 @@ function startServer() {
// https://docs.heygen.com/reference/list-voices-v2
socket.on('getVoiceList', async ({}, cb) => {
if (!config.videoAI.enabled || !config.videoAI.apiKey)
if (!config?.integrations?.videoAI?.enabled || !config?.integrations?.videoAI?.apiKey)
return cb({ error: 'Video AI seems disabled, try later!' });
try {
const response = await axios.get(`${config.videoAI.basePath}/v2/voices`, {
const response = await axios.get(`${config?.integrations?.videoAI?.basePath}/v2/voices`, {
headers: {
'Content-Type': 'application/json',
'X-Api-Key': config.videoAI.apiKey,
'X-Api-Key': config?.integrations?.videoAI?.apiKey,
},
});
@@ -2582,12 +2586,12 @@ function startServer() {
socket.on('streamingNew', async ({ quality, avatar_id, voice_id }, cb) => {
if (!roomExists(socket)) return;
if (!config.videoAI.enabled || !config.videoAI.apiKey)
if (!config?.integrations?.videoAI?.enabled || !config?.integrations?.videoAI?.apiKey)
return cb({ error: 'Video AI seems disabled, try later!' });
try {
const voice = voice_id ? { voice_id: voice_id } : {};
const response = await axios.post(
`${config.videoAI.basePath}/v1/streaming.new`,
`${config?.integrations?.videoAI?.basePath}/v1/streaming.new`,
{
quality,
avatar_id,
@@ -2597,7 +2601,7 @@ function startServer() {
headers: {
accept: 'application/json',
'content-type': 'application/json',
'x-api-key': config.videoAI.apiKey,
'x-api-key': config?.integrations?.videoAI?.apiKey,
},
},
);
@@ -2617,17 +2621,17 @@ function startServer() {
socket.on('streamingStart', async ({ session_id, sdp }, cb) => {
if (!roomExists(socket)) return;
if (!config.videoAI.enabled || !config.videoAI.apiKey)
if (!config?.integrations?.videoAI?.enabled || !config?.integrations?.videoAI?.apiKey)
return cb({ error: 'Video AI seems disabled, try later!' });
try {
const response = await axios.post(
`${config.videoAI.basePath}/v1/streaming.start`,
`${config?.integrations?.videoAI?.basePath}/v1/streaming.start`,
{ session_id, sdp },
{
headers: {
'Content-Type': 'application/json',
'X-Api-Key': config.videoAI.apiKey,
'X-Api-Key': config?.integrations?.videoAI?.apiKey,
},
},
);
@@ -2647,17 +2651,17 @@ function startServer() {
socket.on('streamingICE', async ({ session_id, candidate }, cb) => {
if (!roomExists(socket)) return;
if (!config.videoAI.enabled || !config.videoAI.apiKey)
if (!config?.integrations?.videoAI?.enabled || !config?.integrations?.videoAI?.apiKey)
return cb({ error: 'Video AI seems disabled, try later!' });
try {
const response = await axios.post(
`${config.videoAI.basePath}/v1/streaming.ice`,
`${config?.integrations?.videoAI?.basePath}/v1/streaming.ice`,
{ session_id, candidate },
{
headers: {
'Content-Type': 'application/json',
'X-Api-Key': config.videoAI.apiKey,
'X-Api-Key': config?.integrations?.videoAI?.apiKey,
},
},
);
@@ -2677,12 +2681,12 @@ function startServer() {
socket.on('streamingTask', async ({ session_id, text }, cb) => {
if (!roomExists(socket)) return;
if (!config.videoAI.enabled || !config.videoAI.apiKey)
if (!config?.integrations?.videoAI?.enabled || !config?.integrations?.videoAI?.apiKey)
return cb({ error: 'Video AI seems disabled, try later!' });
try {
const response = await axios.post(
`${config.videoAI.basePath}/v1/streaming.task`,
`${config?.integrations?.videoAI?.basePath}/v1/streaming.task`,
{
session_id,
text,
@@ -2690,7 +2694,7 @@ function startServer() {
{
headers: {
'Content-Type': 'application/json',
'X-Api-Key': config.videoAI.apiKey,
'X-Api-Key': config?.integrations?.videoAI?.apiKey,
},
},
);
@@ -2710,19 +2714,19 @@ function startServer() {
socket.on('streamingInterrupt', async ({ session_id, text }, cb) => {
if (!roomExists(socket)) return;
if (!config.videoAI.enabled || !config.videoAI.apiKey)
if (!config?.integrations?.videoAI?.enabled || !config?.integrations?.videoAI?.apiKey)
return cb({ error: 'Video AI seems disabled, try later!' });
try {
const response = await axios.post(
`${config.videoAI.basePath}/v1/streaming.interrupt`,
`${config?.integrations?.videoAI?.basePath}/v1/streaming.interrupt`,
{
session_id,
},
{
headers: {
'Content-Type': 'application/json',
'X-Api-Key': config.videoAI.apiKey,
'X-Api-Key': config?.integrations?.videoAI?.apiKey,
},
},
);
@@ -2741,10 +2745,11 @@ function startServer() {
socket.on('talkToOpenAI', async ({ text, context }, cb) => {
if (!roomExists(socket)) return;
if (!config.videoAI.enabled || !config.videoAI.apiKey)
if (!config?.integrations?.videoAI?.enabled || !config?.integrations?.videoAI?.apiKey)
return cb({ error: 'Video AI seems disabled, try later!' });
try {
const systemLimit = config.videoAI.systemLimit;
const systemLimit = config?.integrations?.videoAI?.systemLimit;
const arr = {
messages: [...context, { role: 'system', content: systemLimit }, { role: 'user', content: text }],
model: 'gpt-3.5-turbo',
@@ -2769,18 +2774,19 @@ function startServer() {
socket.on('streamingStop', async ({ session_id }, cb) => {
if (!roomExists(socket)) return;
if (!config.videoAI.enabled || !config.videoAI.apiKey)
if (!config?.integrations?.videoAI?.enabled || !config?.integrations?.videoAI?.apiKey)
return cb({ error: 'Video AI seems disabled, try later!' });
try {
const response = await axios.post(
`${config.videoAI.basePath}/v1/streaming.stop`,
`${config?.integrations?.videoAI?.basePath}/v1/streaming.stop`,
{
session_id,
},
{
headers: {
'Content-Type': 'application/json',
'X-Api-Key': config.videoAI.apiKey,
'X-Api-Key': config?.integrations?.videoAI?.apiKey,
},
},
);
@@ -2820,7 +2826,12 @@ function startServer() {
if (!isPresenter) return cb(false);
const room = getRoom(socket);
const host = config.ngrok.enabled ? 'localhost' : socket.handshake.headers.host.split(':')[0];
const DEFAULT_HOST = 'localhost';
const host = config?.ngrok?.enabled
? DEFAULT_HOST
: socket?.handshake?.headers?.host?.split(':')[0] || DEFAULT_HOST;
const rtmp = await room.startRTMP(socket.id, room, host, 1935, `../${rtmpDir}/${file}`);
if (rtmp !== false) rtmpFileStreamsCount++;
@@ -2864,7 +2875,12 @@ function startServer() {
if (!isPresenter) return cb(false);
const room = getRoom(socket);
const host = config.ngrok.enabled ? 'localhost' : socket.handshake.headers.host.split(':')[0];
const DEFAULT_HOST = 'localhost';
const host = config?.integrations?.ngrok?.enabled
? DEFAULT_HOST
: socket?.handshake?.headers?.host?.split(':')[0] || DEFAULT_HOST;
const rtmp = await room.startRTMPfromURL(socket.id, room, host, 1935, inputVideoURL);
if (rtmp !== false) rtmpUrlStreamsCount++;
@@ -3266,11 +3282,7 @@ function startServer() {
function isPeerPresenter(room_id, peer_id, peer_name, peer_uuid) {
try {
if (
config.presenters &&
config.presenters.join_first &&
(!presenters[room_id] || !presenters[room_id][peer_id])
) {
if (hostCfg?.presenters?.join_first && (!presenters[room_id] || !presenters[room_id][peer_id])) {
// Presenter not in the presenters config list, disconnected, or peer_id changed...
for (const [existingPeerID, presenter] of Object.entries(presenters[room_id] || {})) {
if (presenter.peer_name === peer_name) {
@@ -3286,13 +3298,13 @@ function startServer() {
}
const isPresenter =
(config.presenters &&
config.presenters.join_first &&
typeof presenters[room_id] === 'object' &&
Object.keys(presenters[room_id][peer_id]).length > 1 &&
presenters[room_id][peer_id]['peer_name'] === peer_name &&
presenters[room_id][peer_id]['peer_uuid'] === peer_uuid) ||
(config.presenters && config.presenters.list && config.presenters.list.includes(peer_name));
// First condition: join_first validation
(hostCfg?.presenters?.join_first &&
presenters[room_id]?.[peer_id]?.peer_name === peer_name &&
presenters[room_id]?.[peer_id]?.peer_uuid === peer_uuid &&
Object.keys(presenters[room_id]?.[peer_id] || {}).length > 1) ||
// Fallback condition: list check
hostCfg?.presenters?.list?.includes(peer_name);
log.debug('isPeerPresenter', {
room_id: room_id,
@@ -3491,7 +3503,7 @@ function startServer() {
// Get allowed rooms for user from config.js file
if (hostCfg.protected && !hostCfg.users_from_db) {
const isOIDCEnabled = config.oidc && config.oidc.enabled;
const isOIDCEnabled = config?.security?.oidc?.enabled;
const user = hostCfg.users.find((user) => user.displayname === username || user.username === username);
@@ -3512,7 +3524,7 @@ function startServer() {
if (!username || !room) return false;
const isOIDCEnabled = config.oidc && config.oidc.enabled;
const isOIDCEnabled = config?.security?.oidc?.enabled;
if (hostCfg.protected || hostCfg.user_auth) {
// Check if allowed room for user from DB...
@@ -3539,7 +3551,7 @@ function startServer() {
}
}
const isInPresenterLists = config.presenters.list.includes(username);
const isInPresenterLists = hostCfg?.presenters?.list?.includes(username);
if (isInPresenterLists) {
log.debug('isRoomAllowedForUser - user in presenters list room allowed', room);
@@ -3571,7 +3583,7 @@ function startServer() {
}
async function getPeerGeoLocation(ip) {
const endpoint = config.IPLookup.getEndpoint(ip);
const endpoint = config?.integrations?.IPLookup?.getEndpoint(ip);
log.debug('Get peer geo', { ip: ip, endpoint: endpoint });
return axios
.get(endpoint)

عرض الملف

@@ -6,8 +6,8 @@ const CryptoJS = require('crypto-js');
const config = require('./config');
const { v4: uuidV4 } = require('uuid');
const JWT_KEY = (config.jwt && config.jwt.key) || 'mirotalksfu_jwt_secret';
const JWT_EXP = (config.jwt && config.jwt.exp) || '1h';
const JWT_KEY = config.security?.jwt?.key || 'mirotalksfu_jwt_secret';
const JWT_EXP = config.security?.jwt?.exp || '1h';
module.exports = class ServerApi {
constructor(host = null, authorization = null) {

تم حذف اختلاف الملف لأن الملف كبير جداً تحميل الاختلاف

عرض الملف

@@ -9,12 +9,13 @@ const log = new Logger('NodeMailer');
// EMAIL CONFIG
// ####################################################
const EMAIL_HOST = config.email ? config.email.host : false;
const EMAIL_PORT = config.email ? config.email.port : false;
const EMAIL_USERNAME = config.email ? config.email.username : false;
const EMAIL_PASSWORD = config.email ? config.email.password : false;
const EMAIL_SEND_TO = config.email ? config.email.sendTo : false;
const EMAIL_ALERT = config.email ? config.email.alert : false;
const emailConfig = config.integrations?.email || {};
const EMAIL_ALERT = emailConfig.alert || false;
const EMAIL_HOST = emailConfig.host || false;
const EMAIL_PORT = emailConfig.port || false;
const EMAIL_USERNAME = emailConfig.username || false;
const EMAIL_PASSWORD = emailConfig.password || false;
const EMAIL_SEND_TO = emailConfig.sendTo || false;
if (EMAIL_ALERT && EMAIL_HOST && EMAIL_PORT && EMAIL_USERNAME && EMAIL_PASSWORD && EMAIL_SEND_TO) {
log.info('Email', {

عرض الملف

@@ -4,11 +4,10 @@ const config = require('../config');
const Logger = require('../Logger');
const log = new Logger('RestrictAccessByIP');
const IpWhitelistEnabled = config.middleware ? config.middleware.IpWhitelist.enabled : false;
const allowedIPs = config.middleware ? config.middleware.IpWhitelist.allowed : [];
const { enabled = false, allowedIPs = [] } = config?.security?.middleware?.IpWhitelist || {};
const restrictAccessByIP = (req, res, next) => {
if (!IpWhitelistEnabled) return next();
if (!enabled) return next();
//
const clientIP =
req.headers['x-forwarded-for'] || req.headers['X-Forwarded-For'] || req.socket.remoteAddress || req.ip;