public_html/js/own_components/index.js
var JSE = null;
var socket = null;
var SOCKETIO_URL = "";
var KEY_SIZE = 2048;
var PLAIN_PASSWORD = "";
var MIN_PASSWORD_LENGTH = 8;
// save a cache of chats
var CHATS = {};
var USERS = [];
function init()
{
getConfig();
document.getElementById('profileImageInput').addEventListener('change', uploadProfileImage, false);
document.getElementById('fileInput').addEventListener('change', uploadFile, false);
// Get notification permission
Notification.requestPermission(function(permission){});
}
function setUpSocketIOEvents()
{
socket.on("newMessage", newMessageRecived);
socket.on("readMessage", readMessage);
socket.on("connect", setUpIORooms);
socket.on("reconnect", reconnectedToServer);
socket.on("disconnect", disconnectedFromServer);
}
function getConfig()
{
$.getJSON("/api/config", function(data){
SOCKETIO_URL = location.protocol + "//" + location.host ;//data.SOCKETIO_URL;
KEY_SIZE = data.KEY_SIZE;
socket = io(SOCKETIO_URL);
JSE = new JSEncrypt({default_key_size: KEY_SIZE});
setUpIORooms();
setUpSocketIOEvents();
showWelcome();
// SetUp Pushbullet Link
$("#pushbulletSignInLink").attr("href", data.pushbullet);
}).fail(function(e){
dangerAlert("Unable to load configuration info");
});
}
// Show danger alert
function dangerAlert(msg)
{
Materialize.toast(msg, 4000);
}
// Show Success alert
function successAlert(msg)
{
Materialize.toast(msg, 4000);
}
function showRegisterUserModal()
{
$("#loginAndRegister").openModal();
}
function registerUser()
{
PLAIN_PASSWORD = $("#passwordRegTxt").val();
var email = $("#emailRegTxt").val();
var username = $("#usernameRegTxt").val();
if(PLAIN_PASSWORD.length < MIN_PASSWORD_LENGTH)
{
return dangerAlert("Your password must be at least "+ MIN_PASSWORD_LENGTH +" characters!");
}
// user password will be the plain password and email Hash
var password = CryptoJS.SHA256(email + PLAIN_PASSWORD);
password = password.toString(CryptoJS.enc.Base64);
successAlert("Generating your encryption keys, please wait..");
// Generate public/private keys
JSE.getKey(function () {
var private_key = JSE.getPrivateKey();
var public_key = JSE.getPublicKey();
successAlert("Encryption keys generated! Contacting to the server..");
// encrypt private key
var private_keyEnc = CryptoJS.AES.encrypt(private_key, PLAIN_PASSWORD).toString();
//alert(private_keyEnc);
var registrationData = {
username: username,
email: email,
password: password,
public_key: public_key,
private_key: private_keyEnc,
picture: null
};
socket.emit("register", registrationData, resgistrationResponse);
});
}
function resgistrationResponse(err, r)
{
if(err)
{
return dangerAlert(err);
}
successAlert("Successfuly!");
localStorage.setItem("username", r.username);
localStorage.setItem("password", r.password);
localStorage.setItem("public_key", r.public_key);
localStorage.setItem("private_keyEnc", r.private_key); // Encrypted with plain text password!
var private_key = CryptoJS.enc.Latin1.stringify( CryptoJS.AES.decrypt(r.private_key, PLAIN_PASSWORD) );
localStorage.setItem("private_key", private_key);
// Reset for security
PLAIN_PASSWORD = "";
location.reload();
}
function logInUser()
{
PLAIN_PASSWORD = $("#passwordLogInTxt").val();
var email = $("#emailLogInTxt").val();
// user password will be the plain password and email Hash
var password = CryptoJS.SHA256(email + PLAIN_PASSWORD);
password = password.toString(CryptoJS.enc.Base64);
socket.emit("login", password, resgistrationResponse);
}
function isLoggedIn()
{
return localStorage.username && localStorage.password && localStorage.private_key && localStorage.public_key;
}
function showWelcome()
{
if(isLoggedIn())
{
$("#logUserBtn").removeClass("green");
$("#logUserBtn").addClass("red");
$("#logUserBtn").attr("data-tooltip", "Log Out");
$("#welcomeUsername").html(localStorage.getItem("username"));
getChats();
socket.emit("getUserInfo", localStorage.getItem("username"), function(err, data){
$("#imageProfile").prop("src", data.picture);
$("#imageProfile").attr("data-tooltip", data.username);
});
}
else
{
showRegisterUserModal();
}
}
function disconnectedFromServer()
{
dangerAlert("You have lost the connection with the server. We will try to reconnect as soon as possible.");
}
function reconnectedToServer()
{
successAlert("Reconnected to the server!");
}
function setUpIORooms()
{
if(isLoggedIn())
{
socket.emit("join", localStorage.getItem("password"));
}
}
function logOut()
{
if(isLoggedIn())
{
if(confirm("Do you want to log out?"))
{
localStorage.clear();
location.reload();
}
}
else
{
showRegisterUserModal();
}
}
function scrollToRecentMessage()
{
var conversation = document.getElementById("chatWindow");
conversation.scrollTop = conversation.scrollHeight;
}
function sendMessage()
{
var username = $("#chatWith").html();
var message = $("#messageTxt").val();
$("#messageTxt").val("");
$("#chatWindow").prepend(getMessageChatTemplate(username, message, 1, true, 0));
sendMessageTo(username, message);
}
function newMessageRecived(data)
{
if(!searchUserInfoOnCache(data.username))
{
getChats();
}
var username = $("#chatWith").html();
var isFile = data.isFile ? 1 : 0;
saveMessageOnCache( "[0"+ isFile +"]"+data.message, data.username );
JSE.setPrivateKey(localStorage.getItem("private_key"));
var message = isFile ? data.message : JSE.decrypt(data.message);
var picture = searchUserInfoOnCache(data.username).picture;
if(username == data.username)
{
markAsRead(data.username);
$("#chatWindow").prepend(getMessageChatTemplate(username, message, 0, 0, isFile));
}
else
{
successAlert("New message from " + data.username);
var unread = parseInt( $("#"+data.username+"_unread").html() );
$("#"+data.username+"_unread").html(unread + 1);
}
var nMessage = isFile ? "Sent new file" : message;
showNavigatorNotification(data.username, nMessage, picture);
}
function readMessage(username)
{
var actUsername = $("#chatWith").html();
searchUserInfoOnCache(username).ounread = 0;
if(actUsername == username)
{
$(".unread").html("done_all");
}
}
function saveMessageOnCache(msg, username)
{
if(CHATS[username])
{
CHATS[username].splice(0, 0, msg);
}
}
function deleteMessages()
{
if(confirm("Are you sure? Your history with this user will be deleted, but not his history chat."))
{
var username = $("#chatWith").html();
deleteMessagesWith(username);
}
}
function deleteMessagesWith(username)
{
var data = {
username: username
};
socket.emit("deleteMessagesWith", data, function(err, messages){
if(err)
{
return dangerAlert(err);
}
successAlert("Deleted!");
/*
console.log(messages);
for(m in messages)
{
JSE.setPrivateKey(localStorage.getItem("private_key"));
message = JSE.decrypt(m);
console.log(message);
}
*/
});
}
function sendMessageTo(username, msg)
{
var messageData = {
username: username,
msgFrom: "", // After of encrypt
msgTo: "" // After of encrypt
};
socket.emit("getUserPublicKey", username, function(err, public_key){
if(err)
{
return dangerAlert(err);
}
// Encrypt message to send
JSE.setPublicKey(public_key);
messageData.msgTo = JSE.encrypt(msg);
JSE.setPublicKey(localStorage.getItem("public_key"));
messageData.msgFrom = JSE.encrypt(msg);
socket.emit("sendMessage", messageData, function(err, r){
if(err)
{
return dangerAlert(err);
}
searchUserInfoOnCache(username).ounread++;
saveMessageOnCache( "[10]"+messageData.msgFrom, username );
});
});
}
function getChats()
{
var data = {};
socket.emit("getChats", data, function(err, r){
if(err)
{
return dangerAlert(err);
}
USERS = r;
renderRecentChats(r);
});
}
function renderRecentChats(chats)
{
$("#userChats").html("");
for(c in chats)
{
var username = chats[c].username;
var picture = chats[c].picture;
var unread = chats[c].unread;
$("#userChats").append(getRecentChatTemplate(picture, username, unread));
}
}
function getRecentChatTemplate(picture, username, unread)
{
var template = '<a class="recentChat" href="#!" style="color:#92959E"><li class="clearfix" onclick="getMessagesWith(\'{username}\')">'
+'<img src="{picture}" alt="avatar" onerror="setDefaultPicture(this)" class="circle" style="width:50px;height:50px" />'
+'<div class="about">'
+'<div class="name">{username}</div>'
+' <div class="status">'
+' <span id="{username}_unread">{unread}</span> unread messages'
+' </div>'
+'</div>'
+'</li></a>';
template = template.replace(/\{username\}/g, username).replace(/\{picture\}/g, picture).replace(/\{unread\}/g, unread);
return template;
}
function setDefaultPicture(obj)
{
obj.src = "data:image/jpeg;base64,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";
}
function getMessagesWith(username)
{
var data = {
username: username,
start: 0
};
if(CHATS[username])
{
return renderChatMessages(CHATS[username], username);
}
getMessagesWithPetition(data);
}
function getMoreMessagesWithLinkClick()
{
var username = $("#chatWith").html();
getMoreMessagesWith(username);
}
function getMoreMessagesWith(username)
{
var data = {
username: username,
start: CHATS[username].length
};
getMessagesWithPetition(data);
}
function getMessagesWithPetition(data)
{
socket.emit("getMessagesWith", data, function(err, messages){
if(err)
{
return dangerAlert(err);
}
if(CHATS[data.username])
{
CHATS[data.username] = CHATS[data.username].concat(messages);
}
else
{
CHATS[data.username] = messages;
}
renderChatMessages(CHATS[data.username], data.username);
});
}
function markAsRead(username)
{
var data = {
username: username
};
socket.emit("markAsRead", data, function(err, messages){});
$("#"+username+"_unread").html(0);
}
function renderChatMessages(messages, username)
{
markAsRead(username);
var user = searchUserInfoOnCache(username);
$("#chatWindow").html("");
$("#chatWith").html(username);
$("#chatPicture").prop("src", user.picture || "");
$("#chatNumMessages").html(messages.length);
var myMsgs = 0;
for(m in messages)
{ // Message Schema: [sender]encryptedMessage -> Sender = 1 (if is me) or = 0 is not me
var msg = messages[m];
JSE.setPrivateKey(localStorage.getItem("private_key"));
var isMe = parseInt( msg[1] );
var isFile = parseInt( msg[2] );
var isUnread = (myMsgs < user.ounread);
myMsgs = isMe ? myMsgs+1 : myMsgs;
var realMessage = msg.replace(/\[[0-9]+\]/g, "");
var message = isFile ? realMessage : JSE.decrypt(realMessage);
$("#chatWindow").append(getMessageChatTemplate(username, message, isMe, isUnread, isFile));
}
}
function getMessageChatTemplate(username, message, isMe, isUnread, isFile)
{
var alignClass = "align-right";
var myMessage = "message my-message";
var otherMessage = "message other-message float-right";
var messageClass = otherMessage;
var usernamePosition = '<span class="message-data-name"><i class="fa fa-circle online"></i> {username}</span><span class="message-data-time"></span>';
if(isMe == 0)
{
alignClass = "";
messageClass = myMessage;
usernamePosition = '<span class="message-data-time" ></span> <span class="message-data-name" >{username}</span> <i class="fa fa-circle me"></i>';
}
else
{
username = localStorage.getItem("username");
}
var unRead = isUnread ? "done" : "done_all";
var unReadHidden = isMe ? "" : "style='display:none'";
var template = '<li class="clearfix">'
+'<div class="message-data '+alignClass+'">'
+ usernamePosition
+'</div>'
+'<div class="'+ messageClass +'">'
+'{message}'
+'<i class="material-icons unread right" '+ unReadHidden +'>'+ unRead +'</i>'
+'</div>'
+'</li>';
// parse links, sanitize..
message = parseMessage(message);
if(isFile)
{
message = "<a href='#!' onclick='downloadFile(\""+ message +"\")'><i class='material-icons'>attach_file</i> Shared File </a>";
}
template = template.replace(/\{username\}/g, username).replace(/\{message\}/g, message);
return template;
}
function filterRecentChats()
{
var chats = $(".recentChat");
var username = $("#recentSearchTxt").val();
for(c in chats)
{
var cUsername = $(chats[c]).find(".name").html();
if(cUsername.indexOf(username) < 0 && username != "")
{
$(chats[c]).hide();
}
else
{
$(chats[c]).show();
}
}
}
function newChat()
{
$("#newChat").openModal();
}
function createChat()
{
var username = $("#newChatUsernameTxt").val();
var message = $("#newChatMessageTxt").val();
sendMessageTo(username, message);
getChats();
}
function showEditProfile()
{
$("#editProfileImage").prop("src", $("#imageProfile").prop("src") );
$("#editProfile").openModal();
}
function uploadProfileImage(evt)
{
var f = evt.target.files[0];
// Only process image files.
if (!f.type.match('image.*'))
{
return;
}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function(theFile) {
return function(e) {
var image = e.target.result;
$("#editProfileImage").prop("src", image);
var data = {
picture: image
};
socket.emit("updateProfile", data, function(err, d){
if(err)
{
return dangerAlert(err);
}
$("#imageProfile").prop("src", image);
});
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
function uploadFile(evt)
{
var f = evt.target.files[0];
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function(theFile) {
return function(e) {
var username = $("#chatWith").html();
socket.emit("getUserPublicKey", username, function(err, public_key){
var randomKey = CryptoJS.lib.WordArray.random(128/8).toString();
var content = CryptoJS.AES.encrypt(e.target.result, randomKey).toString();
JSE.setPublicKey(public_key);
var fileTo = JSE.encrypt(randomKey);
JSE.setPublicKey(localStorage.getItem("public_key"));
var fileFrom = JSE.encrypt(randomKey);
var data = {
content: content,
fileFrom: fileFrom,
fileTo: fileTo,
name: f.name,
username: username
};
socket.emit("sendFile", data, function(err, d){
if(err)
{
return dangerAlert(err);
}
var username = $("#chatWith").html();
saveMessageOnCache( "[11]"+d, username );
$("#chatWindow").prepend(getMessageChatTemplate(username, d, 1, true, 1));
});
});
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
function downloadFile(id)
{
socket.emit("downloadFile", id, function(err, data){
if(err)
{
return dangerAlert(err);
}
// Decrypt key file
JSE.setPrivateKey(localStorage.getItem('private_key'));
var kFile = JSE.decrypt(data.key);
var content = CryptoJS.enc.Latin1.stringify( CryptoJS.AES.decrypt(data.content, kFile) );
//window.open(content);
$("#chatFileIframe").attr("src", content);
$("#chatFileDownloadLink").attr("href", content);
$("#chatFileDownloadLink").attr("download", data.name);
$("#chatFileName").html(data.name);
$("#chatFileDeleteLink").unbind();
$("#chatFileDeleteLink").on("click", function(){ event.stopPropagation(); deleteFile(id); });
$("#chatFileModal").openModal();
});
}
function deleteFile(id)
{
if(confirm("Are you sure you want to delete this file?"))
{
socket.emit("deleteFile", id, function(err, data){
if(err)
{
return dangerAlert(err);
}
successAlert("Deleted!");
});
}
}
function searchUserInfoOnCache(username)
{
for(u in USERS)
{
if(USERS[u].username == username)
{
return USERS[u];
}
}
}
function checkSendMessage(e)
{
var code = (e.keyCode ? e.keyCode : e.which);
if(code == 13)
{ //Enter keycode
sendMessage();
e.stopPropagation();
}
}
function sanitize(str)
{
str = str.replace(/</g, '<');
str = str.replace(/>/g, '>');
str = str.replace(/\"/g, '"');
str = str.replace(/\'/g, ''');
return str;
}
function parseLinks(str)
{
str = str.replace(/(https?:\/\/[^ ]+)/g, '<a href="$1" target="_blank">$1</a>');
return str;
}
function parseMessage(str)
{
str = sanitize(str);
str = parseLinks(str);
return str;
}
function showNavigatorNotification(username, message, icon)
{
var nTitle = username + " has sent you a message";
var nBody = sanitize(message);
var notification = new Notification(nTitle, {body:nBody, icon: icon});
}
function materializeInit()
{ // Materialize needs it..
$('.collapsible').collapsible({
accordion : false // A setting that changes the collapsible behavior to expandable instead of the default accordion style
});
$('.tooltipped').tooltip({delay: 50});
}