Security Fix and minor UI changes

Verify privKey of groupID when creating new group
Names and Messages are now added in textContent instead of innerHTML to prevent HTML injection
Both direct message and group message use the same IDB objectStore
Converted send message input to textarea : now users can send multi-line messages
Minor UI changes and fixes
Improved Enter Key Press :
Shift+Enter key will now insert a new line
(Enter key pressed without shift key will send message as before)
Enter key event to send message will now tigger on keydown instead of keyup
This commit is contained in:
sairajzero 2019-09-15 19:05:50 +05:30
parent ebd532b608
commit eaa3470cf4
3 changed files with 91 additions and 217 deletions

View File

@ -214,6 +214,20 @@ var floOpt = {
} catch (e) {
console.log(e);
}
},
verifyPrivKey: function (privateKeyHex, floID) {
try {
var key = new Bitcoin.ECKey(privateKeyHex);
if (key.priv == null)
return false;
key.setCompressed(true);
if (floID == key.getBitcoinAddress())
return true;
else
return false;
} catch (e) {
console.log(e);
}
}
}
//Script for AJAX, and register functions
@ -315,8 +329,8 @@ function broadcastTx(signedTxHash) {
function userDataStartUp() {
console.log("StartUp");
document.getElementById("sendMsgInput").addEventListener("keyup", (event) => {
if (event.keyCode === 13) {
document.getElementById("sendMsgInput").addEventListener("keydown", (event) => {
if (event.keyCode === 13 && !event.shiftKey) {
event.preventDefault();
sendMsg();
}
@ -342,15 +356,10 @@ function userDataStartUp() {
groups = result;
readMsgfromIDB().then(result => {
console.log(result);
readGroupMsgfromIDB().then(result => {
console.log(result);
initselfWebSocket();
pingSuperNodeForAwayMessages();
displayContacts();
const createClock = setInterval(checkStatusInterval, 30000);
}).catch(error => {
console.log(error);
});
initselfWebSocket();
pingSuperNodeForAwayMessages();
displayContacts();
const createClock = setInterval(checkStatusInterval, 30000);
}).catch(error => {
console.log(error);
});
@ -450,6 +459,12 @@ function getDatafromAPI() {
objectStore3.createIndex('floID', 'floID', {
unique: false
});
objectStore3.createIndex('groupID', 'groupID', {
unique: false
});
objectStore3.createIndex('sender', 'sender', {
unique: false
});
objectStore3.createIndex('type', 'type', {
unique: false
});
@ -459,21 +474,6 @@ function getDatafromAPI() {
objectStore4.createIndex('groupInfo', 'groupInfo', {
unique: false
});
var objectStore5 = db.createObjectStore("groupMsg", {
keyPath: 'time'
});
objectStore5.createIndex('text', 'text', {
unique: false
});
objectStore5.createIndex('groupID', 'groupID', {
unique: false
});
objectStore5.createIndex('type', 'type', {
unique: false
});
objectStore5.createIndex('sender', 'sender', {
unique: false
});
};
idb.onsuccess = (event) => {
var db = event.target.result;
@ -657,6 +657,13 @@ function readMsgfromIDB() {
createLi.style.display = 'none';
disp.appendChild(createLi);
}
for (floID in groups) {
var createLi = document.createElement('div');
createLi.setAttribute("id", floID);
createLi.setAttribute("class", "message-inner");
createLi.style.display = 'none';
disp.appendChild(createLi);
}
var idb = indexedDB.open("FLO_Chat");
idb.onerror = (event) => {
reject("Error in opening IndexedDB!");
@ -678,37 +685,6 @@ function readMsgfromIDB() {
});
}
function readGroupMsgfromIDB() {
return new Promise((resolve, reject) => {
var disp = document.getElementById("conversation");
for (floID in groups) {
var createLi = document.createElement('div');
createLi.setAttribute("id", floID);
createLi.setAttribute("class", "message-inner");
createLi.style.display = 'none';
disp.appendChild(createLi);
}
var idb = indexedDB.open("FLO_Chat");
idb.onerror = (event) => {
reject("Error in opening IndexedDB!");
};
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("groupMsg", "readwrite").objectStore("groupMsg");
obs.openCursor().onsuccess = (event) => {
var cursor = event.target.result;
if (cursor) {
createMsgElement(cursor.value);
cursor.continue();
} else {
resolve("Read Group Msgs from IDB");
}
};
db.close();
};
});
}
function storeMsg(data) {
var idb = indexedDB.open("FLO_Chat");
idb.onerror = (event) => {
@ -722,19 +698,6 @@ function storeMsg(data) {
};
}
function storeGroupMsg(data) {
var idb = indexedDB.open("FLO_Chat");
idb.onerror = (event) => {
console.log("Error in opening IndexedDB!");
};
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("groupMsg", "readwrite").objectStore("groupMsg");
obs.add(data);
db.close();
};
}
function storeSuperNodeMsg(data) {
var idb = indexedDB.open("FLO_Chat", 2);
idb.onerror = (event) => {
@ -780,11 +743,12 @@ function displayContacts() {
createLi.innerHTML = `<div class="col-sm-11 col-xs-11 sideBar-main">
<div class="row">
<div class="col-sm-12 col-xs-12 sideBar-name">
<span class="name-meta">${contacts[floID].name}</span><br/>
<span class="name-meta"></span><br/>
<span class="time-meta">@${floID}</span>
</div>
</div>
</div>`
createLi.querySelector("span.name-meta").textContent = contacts[floID].name;
listElement.appendChild(createLi);
}
for (floID in groups) {
@ -795,11 +759,12 @@ function displayContacts() {
createLi.innerHTML = `<div class="col-sm-11 col-xs-11 sideBar-main">
<div class="row">
<div class="col-sm-12 col-xs-12 sideBar-name">
<span class="name-meta">${groups[floID].name}</span><br/>
<span class="name-meta"></span><br/>
<span class="time-meta">#${floID}</span>
</div>
</div>
</div>`
createLi.querySelector("span.name-meta").textContent = groups[floID].name;
listElement.appendChild(createLi);
}
}
@ -858,7 +823,7 @@ function processIncomingData(data) {
type: "R"
}
createMsgElement(msgInfo);
storeGroupMsg(msgInfo);
storeMsg(msgInfo);
} else if (data.groupMsg !== undefined && data.groupMsg.group in groups) {
if (!(groups[data.groupMsg.group].members.includes(data.from)))
return
@ -873,11 +838,11 @@ function processIncomingData(data) {
type: "R"
}
createMsgElement(msgInfo);
storeGroupMsg(msgInfo);
storeMsg(msgInfo)
} else if (data.newGroup !== undefined) {
var groupInfoStr = floOpt.decryptData(data.newGroup.groupInfo.secret, data.newGroup.groupInfo.pubVal, privKey)
var groupInfo = JSON.parse(groupInfoStr);
if (floOpt.verifyData(groupInfoStr, data.newGroup.sign, contacts[groupInfo.creator].pubKey)) {
if (floOpt.verifyData(groupInfoStr, data.newGroup.sign, contacts[groupInfo.creator].pubKey) && floOpt.verifyPrivKey(groupInfo.privKey, groupInfo.floID)) {
groups[groupInfo.floID] = groupInfo;
searchIndex.add(groupInfo.floID, groupInfo.name + ' #' + groupInfo.floID);
storeGroup(groupInfoStr, groupInfo.floID);
@ -937,7 +902,7 @@ function createMsgElement(msgInfo) {
var msghd = '';
} else {
var msgEl = document.getElementById(msgInfo.groupID);
var msghd = `<b>${msgInfo.sender}</b>`;
var msghd = `<b>${msgInfo.sender}</b><br/>`;
}
if (!msgEl)
return;
@ -946,13 +911,14 @@ function createMsgElement(msgInfo) {
msgdiv.innerHTML = `<div class="col-sm-12 message-main-${type[msgInfo.type]}">
<div class="${type[msgInfo.type]}">
<span class="message-text">
${msghd}<br/>${msgInfo.text}
${msghd}<pre></pre>
</span>
<span class="message-time pull-right">
${getTime(msgInfo.time)}
</span>
</div>
</div>`;
msgdiv.querySelector("pre").textContent = msgInfo.text;
msgEl.appendChild(msgdiv);
} catch (e) {
console.log(e);
@ -1014,7 +980,7 @@ function changeReceiver(param) {
document.getElementById(receiverID).style.display = 'none';
//console.log(param.getAttribute("name"));
receiverID = param.getAttribute("name");
document.getElementById('recipient-floID').innerHTML = receiverID;
document.getElementById('recipient-floID').textContent = receiverID;
receiverStatus(false)
document.getElementById(receiverID).style.display = 'block';
document.getElementById("groupOptions").style.display = 'none';
@ -1159,7 +1125,7 @@ function sendGroupMsg(msg, time, sign) {
type: "S"
}
createMsgElement(msgInfo);
storeGroupMsg(msgInfo);
storeMsg(msgInfo);
}
function sendStoredSuperNodeMsgs(floID) {
@ -1261,11 +1227,12 @@ function createGroupDisplay(groupInfo) {
createLi.innerHTML = `<div class="col-sm-11 col-xs-11 sideBar-main">
<div class="row">
<div class="col-sm-12 col-xs-12 sideBar-name">
<span class="name-meta">${groupInfo.name}</span><br/>
<span class="name-meta"></span><br/>
<span class="time-meta">#${groupInfo.floID}</span>
</div>
</div>
</div>`;
createLi.querySelector("span.name-meta").textContent = groupInfo.name;
document.getElementById('contact-display').appendChild(createLi);
var createEl = document.createElement('div');
@ -1496,7 +1463,7 @@ function customCheckList(userList, ignoreList, okBtnVal = "Ok", okBtnType = "suc
var okButton = dialog.querySelector('button.ok');
var cancelButton = dialog.querySelector('button.cancel');
okButton.setAttribute("class", `ok btn btn-${okBtnType}`);
okButton.innerHTML = okBtnVal;
okButton.textContent = okBtnVal;
var grpNameInput = dialog.querySelector('input.grpName')
grpNameInput.style.display = (okBtnVal === "Create Group" ? "block" : "none");
grpNameInput.value = '';
@ -1508,11 +1475,11 @@ function customCheckList(userList, ignoreList, okBtnVal = "Ok", okBtnType = "suc
listEl.setAttribute('class', "btn btn-default listLabel");
listEl.setAttribute('name', userList[i]);
listEl.innerHTML = `
<span>${contacts[userList[i]].name}<br/>
<sub>@${userList[i]}</sub>
</span>
<span></span><br/>
<sub>@${userList[i]}</sub>
<input type="checkbox" class="badgebox" value="${userList[i]}">
<span class="badge">&check;</span>`;
listEl.querySelector("span").textContent = contacts[userList[i]].name;
userChecklist.appendChild(listEl);
}
return new Promise((resolve, reject) => {

View File

@ -43,12 +43,12 @@
<div class="row heading">
<span class="name-meta"><b>FLO Whatsapp </b> </span>
<!--
<div class="col-sm-1 col-xs-1 heading-dot pull-right">
<div class="col-sm-1 col-xs-1 heading-icon pull-right">
<i class="fa fa-ellipsis-v fa-2x pull-right" aria-hidden="true" onclick="min();"></i>
</div>
-->
<div class="col-sm-2 col-xs-2 heading-compose pull-right">
<div class="col-sm-2 col-xs-2 heading-icon pull-right">
<i class="fa fa-comments fa-2x pull-right" aria-hidden="true" onclick="createGroup();"></i>
</div>
<br />
@ -81,11 +81,11 @@
<!-- Heading -->
<div class="row heading">
<div class="col-sm-8 col-xs-8 heading-name">
<span class="heading-name-meta"><span id="recipient-status">O</span> &nbsp;&nbsp;<span
id="recipient-floID">Select Contact</span>
<span class="heading-name-meta"><span id="recipient-status">O</span> &nbsp;&nbsp;
<span id="recipient-floID">Select Contact</span>
</span>
</div>
<div class="col-sm-1 col-xs-1 heading-dot pull-right dropdown" id="groupOptions">
<div class="col-sm-1 col-xs-1 heading-icon pull-right dropdown" id="groupOptions">
<i class="fa fa-ellipsis-v fa-2x pull-right" aria-hidden="true"></i>
<div class="dropdown-content">
<li onclick="addGroupMembers()">Add Members</li>
@ -106,20 +106,20 @@
<!-- Reply Box -->
<div class="row reply">
<!--
<div class="col-sm-1 col-xs-1 reply-emojis">
<div class="col-sm-1 col-xs-1 reply-icon">
<i class="fa fa-smile-o fa-2x"></i>
</div>
-->
<div class="col-sm-9 col-xs-9 reply-main">
<input class="form-control" rows="1" id="sendMsgInput" placeholder="Type message"
autocomplete="off"></input>
<textarea class="form-control" rows="1" id="sendMsgInput" placeholder="Type message"
autocomplete="off"></textarea>
</div>
<!--
<div class="col-sm-1 col-xs-1 reply-recording">
<div class="col-sm-1 col-xs-1 reply-icon">
<i class="fa fa-microphone fa-2x" aria-hidden="true"></i>
</div>
-->
<div class="col-sm-1 col-xs-1 reply-send" onclick="sendMsg()">
<div class="col-sm-1 col-xs-1 reply-icon" onclick="sendMsg()">
<i class="fa fa-send fa-2x" aria-hidden="true"></i>
</div>
</div>

View File

@ -10,6 +10,20 @@ span {
box-sizing: border-box;
}
pre {
color: inherit;
padding: 0 !important;
margin: 0 !important;
font: inherit;
background-color: transparent;
border: 0;
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
}
body {
background: no-repeat fixed center;
background-size: cover;
@ -78,18 +92,6 @@ body {
z-index: 1000;
}
.heading-avatar {
padding: 0 !important;
cursor: pointer;
}
.heading-avatar-icon img {
border-radius: 50%;
height: 40px;
width: 40px;
}
.heading-name {
padding: 0 !important;
cursor: pointer;
@ -115,36 +117,17 @@ body {
color: white;
}
.heading-online {
display: none;
padding: 0 5px;
font-size: 12px;
color: #93918f;
}
.heading-compose {
.heading-icon {
padding: 0;
}
.heading-compose i {
.heading-icon i {
text-align: center;
padding: 5px;
color: #93918f;
cursor: pointer;
}
.heading-dot {
padding: 0;
margin-left: 10px;
}
.heading-dot i {
text-align: right;
padding: 5px;
color: #93918f;
cursor: pointer;
}
.searchBox {
padding: 0 !important;
margin: 0 !important;
@ -346,30 +329,28 @@ body {
.message-main-receiver {
/*padding: 10px 20px;*/
max-width: 60%;
max-width: 80%;
height: auto;
}
.message-main-sender {
padding: 3px 20px !important;
margin-left: 40% !important;
max-width: 60%;
margin-left: 20% !important;
max-width: 80%;
height: auto;
}
.message-text {
margin: 0 !important;
padding: 5px !important;
word-wrap: break-word;
padding: 0px !important;
font-weight: 200;
font-size: 14px;
padding-bottom: 0 !important;
height: auto;
word-break: break-word;
}
.message-time {
margin: 0 !important;
margin-left: 50px !important;
font-size: 12px;
text-align: right;
color: #9a9a9a;
@ -383,8 +364,6 @@ body {
border-radius: 10px 10px 10px 0;
background: #ffffff;
font-size: 12px;
word-wrap: break-word;
display: inline-block;
height: auto;
}
@ -396,8 +375,6 @@ body {
border-radius: 10px 10px 0 10px;
padding: 4px 10px 7px !important;
font-size: 12px;
display: inline-block;
word-wrap: break-word;
}
/*Reply*/
@ -411,33 +388,11 @@ body {
z-index: 1000;
}
.reply-emojis {
.reply-icon {
padding: 5px !important;
}
.reply-emojis i {
text-align: center;
padding: 5px 5px 5px 5px !important;
color: #93918f;
cursor: pointer;
}
.reply-recording {
padding: 5px !important;
}
.reply-recording i {
text-align: center;
padding: 5px !important;
color: #93918f;
cursor: pointer;
}
.reply-send {
padding: 5px !important;
}
.reply-send i {
.reply-icon i {
text-align: center;
padding: 5px !important;
color: #93918f;
@ -448,7 +403,7 @@ body {
padding: 2px 5px !important;
}
.reply-main input {
.reply-main textarea {
width: 100%;
resize: none;
overflow: hidden;
@ -459,9 +414,10 @@ body {
box-shadow: none;
height: 100%;
font-size: 16px;
overflow: hidden;
}
.reply-main input:focus {
.reply-main textarea:focus {
outline: none;
border: none;
text-indent: 5px;
@ -483,30 +439,11 @@ body {
font-size: 2.3em !important;
}
.heading-avatar {
padding: 0 !important;
}
.heading-avatar-icon img {
height: 50px;
width: 50px;
}
.heading-compose {
.heading-icon {
padding: 5px !important;
}
.heading-compose i {
color: #fff;
cursor: pointer;
}
.heading-dot {
padding: 5px !important;
margin-left: 10px !important;
}
.heading-dot i {
.heading-icon i {
color: #fff;
cursor: pointer;
}
@ -519,16 +456,6 @@ body {
height: 80px;
}
.sideBar-avatar {
text-align: left;
padding: 0 8px !important;
}
.avatar-icon img {
height: 55px;
width: 55px;
}
.sideBar-main {
padding: 0 !important;
}
@ -564,9 +491,7 @@ body {
padding: 0 !important;
margin: 0 !important;
height: 100%;
/*width: 100%;*/
border-left: 1px solid rgba(0, 0, 0, .08);
/*overflow-y: auto;*/
}
.message {
@ -577,11 +502,11 @@ body {
height: 70px;
}
.reply-emojis {
.reply-icon {
padding: 5px 0 !important;
}
.reply-emojis i {
.reply-icon i {
padding: 5px 2px !important;
font-size: 1.8em !important;
}
@ -594,24 +519,6 @@ body {
padding: 8px !important;
font-size: 18px;
}
.reply-recording {
padding: 5px 0 !important;
}
.reply-recording i {
padding: 5px 0 !important;
font-size: 1.8em !important;
}
.reply-send {
padding: 5px 0 !important;
}
.reply-send i {
padding: 5px 2px 5px 0 !important;
font-size: 1.8em !important;
}
}
.badgebox {