[mirotalksfu] - improve security
هذا الالتزام موجود في:
@@ -777,10 +777,7 @@ function startServer() {
|
|||||||
|
|
||||||
log.debug('[Join] - Connected presenters grp by roomId', presenters);
|
log.debug('[Join] - Connected presenters grp by roomId', presenters);
|
||||||
|
|
||||||
const isPresenter =
|
const isPresenter = await isPeerPresenter(socket.room_id, peer_name, peer_uuid);
|
||||||
Object.keys(presenters[socket.room_id]).length > 1 &&
|
|
||||||
presenters[socket.room_id]['peer_name'] == peer_name &&
|
|
||||||
presenters[socket.room_id]['peer_uuid'] == peer_uuid;
|
|
||||||
|
|
||||||
roomList
|
roomList
|
||||||
.get(socket.room_id)
|
.get(socket.room_id)
|
||||||
@@ -1069,6 +1066,15 @@ function startServer() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function isPeerPresenter(room_id, peer_name, peer_uuid) {
|
||||||
|
const isPresenter =
|
||||||
|
Object.keys(presenters[room_id]).length > 1 &&
|
||||||
|
presenters[room_id]['peer_name'] === peer_name &&
|
||||||
|
presenters[room_id]['peer_uuid'] === peer_uuid;
|
||||||
|
log.debug(peer_name, { isPresenter: isPresenter });
|
||||||
|
return isPresenter;
|
||||||
|
}
|
||||||
|
|
||||||
async function getPeerGeoLocation(ip) {
|
async function getPeerGeoLocation(ip) {
|
||||||
const endpoint = config.IPLookup.getEndpoint(ip);
|
const endpoint = config.IPLookup.getEndpoint(ip);
|
||||||
log.debug('Get peer geo', { ip: ip, endpoint: endpoint });
|
log.debug('Get peer geo', { ip: ip, endpoint: endpoint });
|
||||||
|
|||||||
@@ -553,16 +553,13 @@ th {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.msg-a {
|
a {
|
||||||
color: #fff;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
.msg-a:hover {
|
a:hover {
|
||||||
color: grey;
|
color: grey !important;
|
||||||
transition: all 0.3s ease-in-out;
|
transition: all 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
#chat-msg-a {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------
|
/*--------------------------------------------------------------
|
||||||
# Chat room input area
|
# Chat room input area
|
||||||
|
|||||||
@@ -2723,7 +2723,8 @@ class RoomClient {
|
|||||||
isChatPasteTxt = false;
|
isChatPasteTxt = false;
|
||||||
return this.userLog('info', 'No participants in the room', 'top-end');
|
return this.userLog('info', 'No participants in the room', 'top-end');
|
||||||
}
|
}
|
||||||
let peer_msg = this.formatMsg(chatMessage.value.trim());
|
chatMessage.value = filterXSS(chatMessage.value.trim());
|
||||||
|
let peer_msg = this.formatMsg(chatMessage.value);
|
||||||
if (!peer_msg) {
|
if (!peer_msg) {
|
||||||
return this.cleanMessage();
|
return this.cleanMessage();
|
||||||
}
|
}
|
||||||
@@ -2794,7 +2795,8 @@ class RoomClient {
|
|||||||
},
|
},
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.value) {
|
if (result.value) {
|
||||||
let peer_msg = this.formatMsg(result.value.trim());
|
result.value = filterXSS(result.value.trim());
|
||||||
|
let peer_msg = this.formatMsg(result.value);
|
||||||
if (!peer_msg) {
|
if (!peer_msg) {
|
||||||
return this.cleanMessage();
|
return this.cleanMessage();
|
||||||
}
|
}
|
||||||
@@ -2848,27 +2850,37 @@ class RoomClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
appendMessage(side, img, fromName, fromId, msg, toId, toName) {
|
appendMessage(side, img, fromName, fromId, msg, toId, toName) {
|
||||||
let time = this.getTimeNow();
|
//
|
||||||
let msgBubble = toId == 'all' ? 'msg-bubble' : 'msg-bubble-private';
|
const getSide = filterXSS(side);
|
||||||
let replyMsg = fromId === this.peer_id ? `<hr/>Private message to ${toName}` : '';
|
const getImg = filterXSS(img);
|
||||||
let message = toId == 'all' ? msg : msg + replyMsg;
|
const getFromName = filterXSS(fromName);
|
||||||
|
const getFromId = filterXSS(fromId);
|
||||||
|
const getMsg = filterXSS(msg);
|
||||||
|
const getToId = filterXSS(toId);
|
||||||
|
const getToName = filterXSS(toName);
|
||||||
|
const time = this.getTimeNow();
|
||||||
|
|
||||||
|
const msgBubble = getToId == 'all' ? 'msg-bubble' : 'msg-bubble-private';
|
||||||
|
const replyMsg = getFromId === this.peer_id ? `<hr/>Private message to ${getToName}` : '';
|
||||||
|
const message = getToId == 'all' ? getMsg : getMsg + replyMsg;
|
||||||
|
|
||||||
let msgHTML = `
|
let msgHTML = `
|
||||||
<div id="msg-${chatMessagesId}" class="msg ${side}-msg">
|
<div id="msg-${chatMessagesId}" class="msg ${getSide}-msg">
|
||||||
<img class="msg-img" src="${img}" />
|
<img class="msg-img" src="${getImg}" />
|
||||||
<div class=${msgBubble}>
|
<div class=${msgBubble}>
|
||||||
<div class="msg-info">
|
<div class="msg-info">
|
||||||
<div class="msg-info-name">${fromName}</div>
|
<div class="msg-info-name">${getFromName}</div>
|
||||||
<div class="msg-info-time">${time}</div>
|
<div class="msg-info-time">${time}</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="${chatMessagesId}" class="msg-text">${message}
|
<div id="${chatMessagesId}" class="msg-text">${message}
|
||||||
<hr/>`;
|
<hr/>`;
|
||||||
// add btn direct reply to private message
|
// add btn direct reply to private message
|
||||||
if (fromId != this.peer_id) {
|
if (getFromId != this.peer_id) {
|
||||||
msgHTML += `
|
msgHTML += `
|
||||||
<button
|
<button
|
||||||
class="fas fa-paper-plane"
|
class="fas fa-paper-plane"
|
||||||
id="msg-private-reply-${chatMessagesId}"
|
id="msg-private-reply-${chatMessagesId}"
|
||||||
onclick="rc.sendMessageTo('${fromId}','${fromName}')"
|
onclick="rc.sendMessageTo('${getFromId}','${getFromName}')"
|
||||||
></button>`;
|
></button>`;
|
||||||
}
|
}
|
||||||
msgHTML += `
|
msgHTML += `
|
||||||
@@ -2886,7 +2898,7 @@ class RoomClient {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
this.collectMessages(time, fromName, msg);
|
this.collectMessages(time, getFromName, getMsg);
|
||||||
chatMsger.insertAdjacentHTML('beforeend', msgHTML);
|
chatMsger.insertAdjacentHTML('beforeend', msgHTML);
|
||||||
chatMsger.scrollTop += 500;
|
chatMsger.scrollTop += 500;
|
||||||
this.setTippy('msg-delete-' + chatMessagesId, 'Delete', 'top');
|
this.setTippy('msg-delete-' + chatMessagesId, 'Delete', 'top');
|
||||||
@@ -2930,31 +2942,35 @@ class RoomClient {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
formatMsg(message) {
|
formatMsg(msg) {
|
||||||
|
const message = filterXSS(msg);
|
||||||
if (message.trim().length == 0) return;
|
if (message.trim().length == 0) return;
|
||||||
if (this.isHtml(message)) return this.sanitizeHtml(message);
|
if (this.isHtml(message)) return this.sanitizeHtml(message);
|
||||||
if (this.isValidHttpURL(message)) {
|
if (this.isValidHttpURL(message)) {
|
||||||
if (isImageURL(message)) return '<img src="' + message + '" alt="img" width="180" height="auto"/>';
|
if (this.isImageURL(message)) return this.getImage(message);
|
||||||
if (this.isVideoTypeSupported(message)) return this.getIframe(message);
|
//if (this.isVideoTypeSupported(message)) return this.getIframe(message);
|
||||||
return '<a href="' + message + '" target="_blank" class="msg-a">' + message + '</a>';
|
return this.getLink(message);
|
||||||
}
|
}
|
||||||
if (isChatMarkdownOn) return marked.parse(message);
|
if (isChatMarkdownOn) return marked.parse(message);
|
||||||
let pre = '<pre>' + message + '</pre>';
|
if (isChatPasteTxt && this.getLineBreaks(message) > 1) {
|
||||||
if (isChatPasteTxt) {
|
|
||||||
isChatPasteTxt = false;
|
isChatPasteTxt = false;
|
||||||
return pre;
|
return this.getPre(message);
|
||||||
}
|
|
||||||
if (this.getLineBreaks(message) > 1) {
|
|
||||||
return pre;
|
|
||||||
}
|
}
|
||||||
|
if (this.getLineBreaks(message) > 1) return this.getPre(message);
|
||||||
|
console.log('FormatMsg', message);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
sanitizeHtml(str) {
|
sanitizeHtml(input) {
|
||||||
const tagsToReplace = { '&': '&', '<': '<', '>': '>' };
|
const map = {
|
||||||
const replaceTag = (tag) => tagsToReplace[tag] || tag;
|
'&': '&',
|
||||||
const safe_tags_replace = (str) => str.replace(/[&<>]/g, replaceTag);
|
'<': '<',
|
||||||
return safe_tags_replace(str);
|
'>': '>',
|
||||||
|
'"': '"',
|
||||||
|
"'": ''',
|
||||||
|
'/': '/',
|
||||||
|
};
|
||||||
|
return input.replace(/[&<>"'/]/g, (m) => map[m]);
|
||||||
}
|
}
|
||||||
|
|
||||||
isHtml(str) {
|
isHtml(str) {
|
||||||
@@ -2966,28 +2982,76 @@ class RoomClient {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
isValidHttpURL(str) {
|
isValidHttpURL(input) {
|
||||||
let url;
|
const pattern = new RegExp(
|
||||||
try {
|
'^(https?:\\/\\/)?' + // protocol
|
||||||
url = new URL(str);
|
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
|
||||||
} catch (_) {
|
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
|
||||||
return false;
|
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
|
||||||
}
|
'(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
|
||||||
return url.protocol === 'http:' || url.protocol === 'https:';
|
'(\\#[-a-z\\d_]*)?$',
|
||||||
|
'i',
|
||||||
|
); // fragment locator
|
||||||
|
return pattern.test(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
getIframe(url) {
|
isImageURL(input) {
|
||||||
let is_youtube = this.getVideoType(url) == 'na' ? true : false;
|
return input.match(/\.(jpeg|jpg|gif|png|tiff|bmp)$/) != null;
|
||||||
let video_audio_url = is_youtube ? this.getYoutubeEmbed(url) : url;
|
}
|
||||||
return `
|
|
||||||
<iframe
|
getImage(input) {
|
||||||
title="Chat-IFrame"
|
const url = filterXSS(input);
|
||||||
src="${video_audio_url}"
|
const div = document.createElement('div');
|
||||||
width="auto"
|
const img = document.createElement('img');
|
||||||
frameborder="0"
|
img.setAttribute('src', url);
|
||||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
img.setAttribute('width', '200px');
|
||||||
allowfullscreen
|
img.setAttribute('height', 'auto');
|
||||||
></iframe>`;
|
div.appendChild(img);
|
||||||
|
console.log('GetImg', div.firstChild.outerHTML);
|
||||||
|
return div.firstChild.outerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLink(input) {
|
||||||
|
const url = filterXSS(input);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const linkText = document.createTextNode(url);
|
||||||
|
a.setAttribute('href', url);
|
||||||
|
a.setAttribute('target', '_blank');
|
||||||
|
a.appendChild(linkText);
|
||||||
|
div.appendChild(a);
|
||||||
|
console.log('GetLink', div.firstChild.outerHTML);
|
||||||
|
return div.firstChild.outerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPre(input) {
|
||||||
|
const text = filterXSS(input);
|
||||||
|
const pre = document.createElement('pre');
|
||||||
|
const div = document.createElement('div');
|
||||||
|
pre.textContent = text;
|
||||||
|
div.appendChild(pre);
|
||||||
|
console.log('GetPre', div.firstChild.outerHTML);
|
||||||
|
return div.firstChild.outerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
getIframe(input) {
|
||||||
|
const url = filterXSS(input);
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const is_youtube = this.getVideoType(url) == 'na' ? true : false;
|
||||||
|
const video_audio_url = is_youtube ? this.getYoutubeEmbed(url) : url;
|
||||||
|
iframe.setAttribute('title', 'Chat-IFrame');
|
||||||
|
iframe.setAttribute('src', video_audio_url);
|
||||||
|
iframe.setAttribute('width', 'auto');
|
||||||
|
iframe.setAttribute('frameborder', '0');
|
||||||
|
iframe.setAttribute(
|
||||||
|
'allow',
|
||||||
|
'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture',
|
||||||
|
);
|
||||||
|
iframe.setAttribute('allowfullscreen', 'allowfullscreen');
|
||||||
|
div.appendChild(iframe);
|
||||||
|
console.log('GetIFrame', div.firstChild.outerHTML);
|
||||||
|
return div.firstChild.outerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
getLineBreaks(message) {
|
getLineBreaks(message) {
|
||||||
|
|||||||
المرجع في مشكلة جديدة
حظر مستخدم