Identity fingerprint in profile pop-up & Peer info pop-up
This commit is contained in:
parent
3681626c48
commit
01e593bbc5
@ -58,7 +58,7 @@ input[type="file"] {
|
||||
padding: 20px 70px;
|
||||
background-color: #2B2F31;
|
||||
border-radius: 10px;
|
||||
font-size: 1.3em;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.popup_background {
|
||||
height: 100%;
|
||||
@ -117,6 +117,15 @@ input[type="file"] {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.popup .session_info h2 {
|
||||
text-align: center;
|
||||
}
|
||||
.popup .session_info p:first-of-type, .popup .session_info pre {
|
||||
display: inline-block;
|
||||
}
|
||||
.popup .session_info p:nth-of-type(2) {
|
||||
margin-top: 0;
|
||||
}
|
||||
.button_row {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
@ -156,6 +165,13 @@ input[type="file"] {
|
||||
font-weight: bold;
|
||||
display: inline;
|
||||
}
|
||||
#me>div:hover p {
|
||||
color: var(--accent);
|
||||
}
|
||||
#identity_fingerprint {
|
||||
text-align: center;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
#left_panel ul:last-of-type, #msg_log {
|
||||
flex-grow: 1;
|
||||
}
|
||||
@ -233,6 +249,10 @@ input[type="file"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
#chat_header>div:hover p {
|
||||
color: var(--accent);
|
||||
}
|
||||
#chat_header>div>p {
|
||||
font-weight: bold;
|
||||
|
@ -61,6 +61,7 @@
|
||||
</main>
|
||||
<script>
|
||||
//replaced by web server
|
||||
let identityFingerprint = "IDENTITY_FINGERPRINT";
|
||||
let isIdentityProtected = IS_IDENTITY_PROTECTED;
|
||||
let websocketPort = WEBSOCKET_PORT;
|
||||
</script>
|
||||
|
@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
const ENTER_KEY_CODE = 13;
|
||||
let identity_name = undefined;
|
||||
let identityName = undefined;
|
||||
let socket = null;
|
||||
let notificationAllowed = false;
|
||||
let currentSessionId = -1;
|
||||
@ -60,7 +60,7 @@ document.getElementById("delete_conversation").onclick = function() {
|
||||
}
|
||||
document.getElementById("add_contact").onclick = function() {
|
||||
socket.send("contact "+currentSessionId+" "+sessionsData.get(currentSessionId).name);
|
||||
sessionsData.get(currentSessionId).is_contact = true;
|
||||
sessionsData.get(currentSessionId).isContact = true;
|
||||
displayHeader();
|
||||
displaySessions();
|
||||
}
|
||||
@ -78,9 +78,9 @@ document.getElementById("remove_contact").onclick = function() {
|
||||
button.onclick = function() {
|
||||
socket.send("uncontact "+currentSessionId);
|
||||
let session = sessionsData.get(currentSessionId);
|
||||
session.is_contact = false;
|
||||
session.is_verified = false;
|
||||
if (!session.is_online) {
|
||||
session.isContact = false;
|
||||
session.isVerified = false;
|
||||
if (!session.isOnline) {
|
||||
sessionsData.delete(currentSessionId);
|
||||
msgHistory.get(currentSessionId).length = 0;
|
||||
}
|
||||
@ -93,7 +93,44 @@ document.getElementById("remove_contact").onclick = function() {
|
||||
showPopup(mainDiv);
|
||||
}
|
||||
document.getElementById("verify").onclick = function() {
|
||||
socket.send("fingerprints "+currentSessionId);
|
||||
let session = sessionsData.get(currentSessionId);
|
||||
if (typeof session !== "undefined") {
|
||||
let mainDiv = document.createElement("div");
|
||||
mainDiv.appendChild(generatePopupWarningTitle());
|
||||
let instructions = document.createElement("p");
|
||||
instructions.textContent = "Compare the following fingerprints by a trusted way of communication (such as real life) and be sure they match.";
|
||||
mainDiv.appendChild(instructions);
|
||||
let p_local = document.createElement("p");
|
||||
p_local.textContent = "Local fingerprint:";
|
||||
mainDiv.appendChild(p_local);
|
||||
let pre_local = document.createElement("pre");
|
||||
pre_local.textContent = beautifyFingerprint(identityFingerprint);
|
||||
mainDiv.appendChild(pre_local);
|
||||
let p_peer = document.createElement("p");
|
||||
p_peer.textContent = "Peer fingerprint:";
|
||||
mainDiv.appendChild(p_peer);
|
||||
let pre_peer = document.createElement("pre");
|
||||
pre_peer.textContent = beautifyFingerprint(session.fingerprint);
|
||||
mainDiv.appendChild(pre_peer);
|
||||
let buttonRow = document.createElement("div");
|
||||
buttonRow.classList.add("button_row");
|
||||
let verifyButton = document.createElement("button");
|
||||
verifyButton.textContent = "They match";
|
||||
verifyButton.onclick = function() {
|
||||
socket.send("verify "+currentSessionId);
|
||||
sessionsData.get(currentSessionId).isVerified = true;
|
||||
removePopup();
|
||||
displayHeader();
|
||||
displaySessions();
|
||||
};
|
||||
buttonRow.appendChild(verifyButton);
|
||||
let cancelButton = document.createElement("button");
|
||||
cancelButton.textContent = "They don't match";
|
||||
cancelButton.onclick = removePopup;
|
||||
buttonRow.appendChild(cancelButton);
|
||||
mainDiv.appendChild(buttonRow);
|
||||
showPopup(mainDiv);
|
||||
}
|
||||
}
|
||||
document.getElementById("logout").onclick = function() {
|
||||
let mainDiv = document.createElement("div");
|
||||
@ -141,125 +178,9 @@ document.getElementById("attach_file").onchange = function(event) {
|
||||
document.getElementById("file_cancel").onclick = function() {
|
||||
socket.send("abort "+currentSessionId);
|
||||
}
|
||||
|
||||
//source: https://stackoverflow.com/a/14919494
|
||||
function humanFileSize(bytes, dp=1) {
|
||||
const thresh = 1000;
|
||||
if (Math.abs(bytes) < thresh) {
|
||||
return bytes + ' B';
|
||||
}
|
||||
const units = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
let u = -1;
|
||||
const r = 10**dp;
|
||||
do {
|
||||
bytes /= thresh;
|
||||
++u;
|
||||
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
|
||||
return bytes.toFixed(dp) + ' ' + units[u];
|
||||
}
|
||||
//source: https://www.w3schools.com/js/js_cookies.asp
|
||||
function getCookie(cname) {
|
||||
var name = cname + "=";
|
||||
var decodedCookie = decodeURIComponent(document.cookie);
|
||||
var ca = decodedCookie.split(';');
|
||||
for(var i = 0; i <ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
socket = new WebSocket("ws://"+location.hostname+":"+websocketPort+"/ws");
|
||||
socket.onopen = function() {
|
||||
console.log("Connected");
|
||||
socket.send(getCookie("aira_auth")); //authenticating websocket connection
|
||||
window.onfocus = function() {
|
||||
if (currentSessionId != -1) {
|
||||
socket.send("set_seen "+currentSessionId);
|
||||
}
|
||||
}
|
||||
if (Notification.permission === "granted") {
|
||||
notificationAllowed = true;
|
||||
} else if (Notification.permission !== "denied") {
|
||||
Notification.requestPermission().then(function (permission) {
|
||||
if (permission === "granted") {
|
||||
notificationAllowed = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
socket.onmessage = function(msg) {
|
||||
if (typeof msg.data == "string") {
|
||||
console.log("Message: "+msg.data);
|
||||
let args = msg.data.split(" ");
|
||||
switch (args[0]) {
|
||||
case "disconnected":
|
||||
onDisconnected(args[1]);
|
||||
break;
|
||||
case "new_session":
|
||||
onNewSession(args[1], args[2] === "true", msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
break;
|
||||
case "new_message":
|
||||
onNewMessage(args[1], args[2] === "true", msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
break;
|
||||
case "file":
|
||||
onFileReceived(args[1], args[2], msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
break;
|
||||
case "file_transfer":
|
||||
onNewFileTransfer(args[1], args[2], args[3], args[4], args[5], args[6]);
|
||||
break;
|
||||
case "ask_large_file":
|
||||
onAskLargeFile(args[1], args[2], args[3], args[4]);
|
||||
break;
|
||||
case "file_accepted":
|
||||
onFileAccepted(args[1]);
|
||||
break;
|
||||
case "aborted":
|
||||
onFileAborted(args[1]);
|
||||
break;
|
||||
case "inc_file_transfer":
|
||||
onIncFileTransfer(args[1], parseInt(args[2]));
|
||||
break;
|
||||
case "load_sent_msg":
|
||||
onMsgLoad(args[1], args[2] === "true", msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
break;
|
||||
case "load_sent_file":
|
||||
onFileLoad(args[1], args[2] === "true", args[3], msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+4));
|
||||
break;
|
||||
case "name_told":
|
||||
onNameTold(args[1], msg.data.slice(args[0].length+args[1].length+2));
|
||||
break;
|
||||
case "is_contact":
|
||||
onIsContact(args[1], args[2] === "true", msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
break;
|
||||
case "not_seen":
|
||||
setNotSeen(msg.data.slice(args[0].length+1));
|
||||
break;
|
||||
case "fingerprints":
|
||||
onFingerprints(args[1], args[2]);
|
||||
break;
|
||||
case "set_name":
|
||||
onNameSet(msg.data.slice(args[0].length+1));
|
||||
break;
|
||||
case "password_changed":
|
||||
onPasswordChanged(args[1] === "true", args[2] === "true");
|
||||
break;
|
||||
case "logout":
|
||||
logout();
|
||||
}
|
||||
}
|
||||
}
|
||||
socket.onclose = function() {
|
||||
console.log("Disconnected");
|
||||
}
|
||||
let msg_log = document.getElementById("msg_log");
|
||||
msg_log.onscroll = function() {
|
||||
if (sessionsData.get(currentSessionId).is_contact) {
|
||||
if (sessionsData.get(currentSessionId).isContact) {
|
||||
if (msg_log.scrollTop < 30) {
|
||||
socket.send("load_msgs "+currentSessionId);
|
||||
}
|
||||
@ -268,14 +189,18 @@ msg_log.onscroll = function() {
|
||||
let profile_div = document.querySelector("#me>div");
|
||||
profile_div.onclick = function() {
|
||||
let mainDiv = document.createElement("div");
|
||||
let avatar = generateAvatar(identity_name);
|
||||
let avatar = generateAvatar(identityName);
|
||||
mainDiv.appendChild(avatar);
|
||||
let fingerprint = document.createElement("pre");
|
||||
fingerprint.id = "identity_fingerprint";
|
||||
fingerprint.textContent = beautifyFingerprint(identityFingerprint);
|
||||
mainDiv.appendChild(fingerprint);
|
||||
let sectionName = document.createElement("section");
|
||||
sectionName.textContent = "Name:";
|
||||
let inputName = document.createElement("input");
|
||||
inputName.id = "new_name";
|
||||
inputName.type = "text";
|
||||
inputName.value = identity_name;
|
||||
inputName.value = identityName;
|
||||
sectionName.appendChild(inputName);
|
||||
let saveNameButton = document.createElement("button");
|
||||
saveNameButton.textContent = "Save";
|
||||
@ -370,21 +295,167 @@ profile_div.onclick = function() {
|
||||
mainDiv.appendChild(sectionDelete);
|
||||
showPopup(mainDiv);
|
||||
}
|
||||
let chatHeader = document.getElementById("chat_header");
|
||||
chatHeader.children[0].onclick = function() {
|
||||
let session = sessionsData.get(currentSessionId);
|
||||
if (typeof session !== "undefined") {
|
||||
let mainDiv = document.createElement("div");
|
||||
mainDiv.classList.add("session_info");
|
||||
mainDiv.appendChild(generateAvatar(session.name));
|
||||
let h2 = document.createElement("h2");
|
||||
h2.textContent = session.name;
|
||||
mainDiv.appendChild(h2);
|
||||
let pFingerprint = document.createElement("p");
|
||||
pFingerprint.textContent = "Fingerprint:";
|
||||
mainDiv.appendChild(pFingerprint);
|
||||
let pre = document.createElement("pre");
|
||||
pre.textContent = ' '+beautifyFingerprint(session.fingerprint);
|
||||
mainDiv.appendChild(pre);
|
||||
if (session.isOnline) {
|
||||
let pIp = document.createElement("p");
|
||||
pIp.textContent = "IP: "+session.ip;
|
||||
mainDiv.appendChild(pIp);
|
||||
let pConnection = document.createElement("p");
|
||||
pConnection.textContent = "Connection: ";
|
||||
if (session.outgoing) {
|
||||
pConnection.textContent += "outgoing";
|
||||
} else {
|
||||
pConnection.textContent += "incomming";
|
||||
}
|
||||
mainDiv.appendChild(pConnection);
|
||||
}
|
||||
showPopup(mainDiv);
|
||||
}
|
||||
}
|
||||
document.querySelector("#refresher button").onclick = function() {
|
||||
socket.send("refresh");
|
||||
}
|
||||
|
||||
function onNewSession(sessionId, outgoing, name) {
|
||||
//source: https://stackoverflow.com/a/14919494
|
||||
function humanFileSize(bytes, dp=1) {
|
||||
const thresh = 1000;
|
||||
if (Math.abs(bytes) < thresh) {
|
||||
return bytes + ' B';
|
||||
}
|
||||
const units = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
let u = -1;
|
||||
const r = 10**dp;
|
||||
do {
|
||||
bytes /= thresh;
|
||||
++u;
|
||||
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
|
||||
return bytes.toFixed(dp) + ' ' + units[u];
|
||||
}
|
||||
//source: https://www.w3schools.com/js/js_cookies.asp
|
||||
function getCookie(cname) {
|
||||
var name = cname + "=";
|
||||
var decodedCookie = decodeURIComponent(document.cookie);
|
||||
var ca = decodedCookie.split(';');
|
||||
for(var i = 0; i <ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
socket = new WebSocket("ws://"+location.hostname+":"+websocketPort+"/ws");
|
||||
socket.onopen = function() {
|
||||
console.log("Connected");
|
||||
socket.send(getCookie("aira_auth")); //authenticating websocket connection
|
||||
window.onfocus = function() {
|
||||
if (currentSessionId != -1) {
|
||||
socket.send("set_seen "+currentSessionId);
|
||||
}
|
||||
}
|
||||
if (Notification.permission === "granted") {
|
||||
notificationAllowed = true;
|
||||
} else if (Notification.permission !== "denied") {
|
||||
Notification.requestPermission().then(function (permission) {
|
||||
if (permission === "granted") {
|
||||
notificationAllowed = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
socket.onmessage = function(msg) {
|
||||
if (typeof msg.data == "string") {
|
||||
console.log("Message: "+msg.data);
|
||||
let args = msg.data.split(" ");
|
||||
switch (args[0]) {
|
||||
case "disconnected":
|
||||
onDisconnected(args[1]);
|
||||
break;
|
||||
case "new_session":
|
||||
onNewSession(args[1], args[2] === "true", args[3], args[4], msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+args[4].length+5));
|
||||
break;
|
||||
case "new_message":
|
||||
onNewMessage(args[1], args[2] === "true", msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
break;
|
||||
case "file":
|
||||
onFileReceived(args[1], args[2], msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
break;
|
||||
case "file_transfer":
|
||||
onNewFileTransfer(args[1], args[2], args[3], args[4], args[5], args[6]);
|
||||
break;
|
||||
case "ask_large_file":
|
||||
onAskLargeFile(args[1], args[2], args[3], args[4]);
|
||||
break;
|
||||
case "file_accepted":
|
||||
onFileAccepted(args[1]);
|
||||
break;
|
||||
case "aborted":
|
||||
onFileAborted(args[1]);
|
||||
break;
|
||||
case "inc_file_transfer":
|
||||
onIncFileTransfer(args[1], parseInt(args[2]));
|
||||
break;
|
||||
case "load_sent_msg":
|
||||
onMsgLoad(args[1], args[2] === "true", msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
break;
|
||||
case "load_sent_file":
|
||||
onFileLoad(args[1], args[2] === "true", args[3], msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+4));
|
||||
break;
|
||||
case "name_told":
|
||||
onNameTold(args[1], msg.data.slice(args[0].length+args[1].length+2));
|
||||
break;
|
||||
case "is_contact":
|
||||
onIsContact(args[1], args[2] === "true", args[3], msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+4));
|
||||
break;
|
||||
case "not_seen":
|
||||
setNotSeen(msg.data.slice(args[0].length+1));
|
||||
break;
|
||||
case "set_name":
|
||||
onNameSet(msg.data.slice(args[0].length+1));
|
||||
break;
|
||||
case "password_changed":
|
||||
onPasswordChanged(args[1] === "true", args[2] === "true");
|
||||
break;
|
||||
case "logout":
|
||||
logout();
|
||||
}
|
||||
}
|
||||
}
|
||||
socket.onclose = function() {
|
||||
console.log("Disconnected");
|
||||
}
|
||||
|
||||
function onNewSession(sessionId, outgoing, fingerprint, ip, name) {
|
||||
if (sessionsData.has(sessionId)) {
|
||||
let session = sessionsData.get(sessionId);
|
||||
session.is_online = true;
|
||||
session.isOnline = true;
|
||||
session.outgoing = outgoing;
|
||||
session.ip = ip;
|
||||
displaySessions();
|
||||
if (currentSessionId == sessionId) {
|
||||
displayChatBottom();
|
||||
}
|
||||
} else {
|
||||
addSession(sessionId, name, outgoing, false, false, true);
|
||||
addSession(sessionId, name, outgoing, fingerprint, ip, false, false, true);
|
||||
}
|
||||
}
|
||||
function onNameTold(sessionId, name) {
|
||||
@ -401,14 +472,14 @@ function setNotSeen(str_sessionIds) {
|
||||
}
|
||||
displaySessions();
|
||||
}
|
||||
function onIsContact(sessionId, verified, name) {
|
||||
function onIsContact(sessionId, verified, fingerprint, name) {
|
||||
if (sessionsData.has(sessionId)) {
|
||||
let session = sessionsData.get(sessionId);
|
||||
session.is_contact = true;
|
||||
session.is_verified = verified;
|
||||
session.isContact = true;
|
||||
session.isVerified = verified;
|
||||
onNameTold(sessionId, name);
|
||||
} else {
|
||||
addSession(sessionId, name, true, true, verified, false);
|
||||
addSession(sessionId, name, undefined, fingerprint, undefined, true, verified, false);
|
||||
}
|
||||
}
|
||||
function onMsgOrFileReceived(sessionId, outgoing, body) {
|
||||
@ -556,63 +627,20 @@ function onFileLoad(sessionId, outgoing, uuid, fileName) {
|
||||
function onDisconnected(sessionId) {
|
||||
pendingFiles.delete(sessionId);
|
||||
let session = sessionsData.get(sessionId);
|
||||
if (session.is_contact) {
|
||||
session.is_online = false;
|
||||
if (session.isContact) {
|
||||
session.isOnline = false;
|
||||
} else {
|
||||
sessionsData.delete(sessionId);
|
||||
}
|
||||
if (currentSessionId == sessionId) {
|
||||
displayChatBottom();
|
||||
}
|
||||
if (currentSessionId == sessionId && !session.is_contact) {
|
||||
if (currentSessionId == sessionId && !session.isContact) {
|
||||
currentSessionId = -1;
|
||||
document.getElementById("chat_header").classList.add("offline");
|
||||
chatHeader.classList.add("offline");
|
||||
}
|
||||
displaySessions();
|
||||
}
|
||||
function onFingerprints(local, peer) {
|
||||
let beautifyFingerprints = function(f) {
|
||||
for (let i=4; i<f.length; i+=5) {
|
||||
f = f.slice(0, i)+" "+f.slice(i);
|
||||
}
|
||||
return f;
|
||||
};
|
||||
let mainDiv = document.createElement("div");
|
||||
mainDiv.appendChild(generatePopupWarningTitle());
|
||||
let instructions = document.createElement("p");
|
||||
instructions.textContent = "Compare the following fingerprints by a trusted way of communication (such as real life) and be sure they match.";
|
||||
mainDiv.appendChild(instructions);
|
||||
let p_local = document.createElement("p");
|
||||
p_local.textContent = "Local fingerprint:";
|
||||
mainDiv.appendChild(p_local);
|
||||
let pre_local = document.createElement("pre");
|
||||
pre_local.textContent = beautifyFingerprints(local);
|
||||
mainDiv.appendChild(pre_local);
|
||||
let p_peer = document.createElement("p");
|
||||
p_peer.textContent = "Peer fingerprint:";
|
||||
mainDiv.appendChild(p_peer);
|
||||
let pre_peer = document.createElement("pre");
|
||||
pre_peer.textContent = beautifyFingerprints(peer);
|
||||
mainDiv.appendChild(pre_peer);
|
||||
let buttonRow = document.createElement("div");
|
||||
buttonRow.classList.add("button_row");
|
||||
let verifyButton = document.createElement("button");
|
||||
verifyButton.textContent = "They match";
|
||||
verifyButton.onclick = function() {
|
||||
socket.send("verify "+currentSessionId);
|
||||
sessionsData.get(currentSessionId).is_verified = true;
|
||||
removePopup();
|
||||
displayHeader();
|
||||
displaySessions();
|
||||
};
|
||||
buttonRow.appendChild(verifyButton);
|
||||
let cancelButton = document.createElement("button");
|
||||
cancelButton.textContent = "They don't match";
|
||||
cancelButton.onclick = removePopup;
|
||||
buttonRow.appendChild(cancelButton);
|
||||
mainDiv.appendChild(buttonRow);
|
||||
showPopup(mainDiv);
|
||||
}
|
||||
function onFileReceived(sessionId, uuid, file_name) {
|
||||
msgHistory.get(sessionId).push([false, true, [uuid, file_name]]);
|
||||
onMsgOrFileReceived(sessionId, false, file_name);
|
||||
@ -623,15 +651,15 @@ function onFileSent(sessionId, uuid, file_name) {
|
||||
dislayHistory();
|
||||
}
|
||||
}
|
||||
function onNameSet(new_name) {
|
||||
function onNameSet(newName) {
|
||||
removePopup();
|
||||
identity_name = new_name;
|
||||
identityName = newName;
|
||||
displayProfile();
|
||||
}
|
||||
function onPasswordChanged(success, is_protected) {
|
||||
function onPasswordChanged(success, isProtected) {
|
||||
if (success) {
|
||||
removePopup();
|
||||
isIdentityProtected = is_protected;
|
||||
isIdentityProtected = isProtected;
|
||||
} else {
|
||||
let input = document.querySelector("input[type=\"password\"]");
|
||||
input.value = "";
|
||||
@ -640,29 +668,37 @@ function onPasswordChanged(success, is_protected) {
|
||||
}
|
||||
}
|
||||
|
||||
function addSession(sessionId, name, outgoing, is_contact, is_verified, is_online) {
|
||||
function beautifyFingerprint(f) {
|
||||
for (let i=4; i<f.length; i+=5) {
|
||||
f = f.slice(0, i)+" "+f.slice(i);
|
||||
}
|
||||
return f;
|
||||
};
|
||||
function addSession(sessionId, name, outgoing, fingerprint, ip, isContact, isVerified, isOnline) {
|
||||
sessionsData.set(sessionId, {
|
||||
"name": name,
|
||||
"outgoing": outgoing,
|
||||
"is_contact": is_contact,
|
||||
"is_verified": is_verified,
|
||||
"fingerprint": fingerprint,
|
||||
"ip": ip,
|
||||
"isContact": isContact,
|
||||
"isVerified": isVerified,
|
||||
"seen": true,
|
||||
"is_online": is_online,
|
||||
"isOnline": isOnline,
|
||||
});
|
||||
msgHistory.set(sessionId, []);
|
||||
displaySessions();
|
||||
}
|
||||
function displaySessions() {
|
||||
let online_sessions = document.getElementById("online_sessions");
|
||||
online_sessions.innerHTML = "";
|
||||
let offline_sessions = document.getElementById("offline_sessions");
|
||||
offline_sessions.innerHTML = "";
|
||||
let onlineSessions = document.getElementById("online_sessions");
|
||||
onlineSessions.innerHTML = "";
|
||||
let offlineSessions = document.getElementById("offline_sessions");
|
||||
offlineSessions.innerHTML = "";
|
||||
sessionsData.forEach(function (session, sessionId) {
|
||||
let session_element = generateSession(sessionId, session);
|
||||
if (session.is_online) {
|
||||
online_sessions.appendChild(session_element);
|
||||
let sessionElement = generateSession(sessionId, session);
|
||||
if (session.isOnline) {
|
||||
onlineSessions.appendChild(sessionElement);
|
||||
} else {
|
||||
offline_sessions.appendChild(session_element) ;
|
||||
offlineSessions.appendChild(sessionElement) ;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -671,26 +707,25 @@ function logout() {
|
||||
}
|
||||
function displayProfile() {
|
||||
profile_div.innerHTML = "";
|
||||
profile_div.appendChild(generateAvatar(identity_name));
|
||||
profile_div.appendChild(generateAvatar(identityName));
|
||||
let p = document.createElement("p");
|
||||
p.textContent = identity_name;
|
||||
p.textContent = identityName;
|
||||
profile_div.appendChild(p);
|
||||
}
|
||||
function displayHeader() {
|
||||
let chat_header = document.getElementById("chat_header");
|
||||
chat_header.children[0].innerHTML = "";
|
||||
chat_header.className = 0;
|
||||
chatHeader.children[0].innerHTML = "";
|
||||
chatHeader.className = 0;
|
||||
let session = sessionsData.get(currentSessionId);
|
||||
if (typeof session === "undefined") {
|
||||
chat_header.style.display = "none";
|
||||
chatHeader.style.display = "none";
|
||||
} else {
|
||||
chat_header.children[0].appendChild(generateAvatar(session.name));
|
||||
chat_header.children[0].appendChild(generateName(session.name));
|
||||
chat_header.style.display = "flex";
|
||||
if (session.is_contact) {
|
||||
chat_header.classList.add("is_contact");
|
||||
if (session.is_verified) {
|
||||
chat_header.classList.add("is_verified");
|
||||
chatHeader.children[0].appendChild(generateAvatar(session.name));
|
||||
chatHeader.children[0].appendChild(generateName(session.name));
|
||||
chatHeader.style.display = "flex";
|
||||
if (session.isContact) {
|
||||
chatHeader.classList.add("is_contact");
|
||||
if (session.isVerified) {
|
||||
chatHeader.classList.add("is_verified");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -742,10 +777,10 @@ function generateSession(sessionId, session) {
|
||||
} else {
|
||||
li.classList.add("incomming");
|
||||
}
|
||||
if (session.is_contact) {
|
||||
if (session.isContact) {
|
||||
li.classList.add("is_contact");
|
||||
}
|
||||
if (session.is_verified) {
|
||||
if (session.isVerified) {
|
||||
li.classList.add("is_verified");
|
||||
}
|
||||
if (!session.seen) {
|
||||
@ -814,7 +849,7 @@ function displayChatBottom(speed = undefined) {
|
||||
if (typeof session === "undefined") {
|
||||
msgBox.removeAttribute("style");
|
||||
} else {
|
||||
if (session.is_online) {
|
||||
if (session.isOnline) {
|
||||
msgBox.style.display = "flex";
|
||||
} else {
|
||||
msgBox.removeAttribute("style");
|
||||
@ -873,7 +908,7 @@ function dislayHistory(scrollToBottom = true) {
|
||||
msgHistory.get(currentSessionId).forEach(entry => {
|
||||
let name;
|
||||
if (entry[0]) { //outgoing msg
|
||||
name = identity_name;
|
||||
name = identityName;
|
||||
} else {
|
||||
name = sessionsData.get(currentSessionId).name;
|
||||
}
|
||||
|
30
src/main.rs
30
src/main.rs
@ -93,16 +93,25 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc<RwLo
|
||||
let session_manager = global_vars.read().unwrap().session_manager.clone();
|
||||
ui_connection.set_name(&session_manager.get_my_name());
|
||||
session_manager.list_contacts().into_iter().for_each(|contact|{
|
||||
ui_connection.set_as_contact(contact.0, &contact.1, contact.2);
|
||||
ui_connection.set_as_contact(contact.0, &contact.1, contact.2, &crypto::generate_fingerprint(&contact.3));
|
||||
session_manager.last_loaded_msg_offsets.write().unwrap().insert(contact.0, 0);
|
||||
load_msgs(session_manager.clone(), &mut ui_connection, &contact.0);
|
||||
});
|
||||
session_manager.sessions.read().unwrap().iter().for_each(|session| {
|
||||
ui_connection.on_new_session(session.0, &session.1.name, session.1.outgoing, session.1.file_download.as_ref());
|
||||
ui_connection.on_new_session(
|
||||
session.0,
|
||||
&session.1.name,
|
||||
session.1.outgoing,
|
||||
&crypto::generate_fingerprint(&session.1.peer_public_key),
|
||||
session.1.ip,
|
||||
session.1.file_download.as_ref()
|
||||
);
|
||||
});
|
||||
let not_seen = session_manager.list_not_seen();
|
||||
if not_seen.len() > 0 {
|
||||
ui_connection.set_not_seen(not_seen);
|
||||
{
|
||||
let not_seen = session_manager.not_seen.read().unwrap();
|
||||
if not_seen.len() > 0 {
|
||||
ui_connection.set_not_seen(not_seen.clone());
|
||||
}
|
||||
}
|
||||
session_manager.get_saved_msgs().into_iter().for_each(|msgs| {
|
||||
ui_connection.load_msgs(&msgs.0, &msgs.1);
|
||||
@ -181,13 +190,6 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc<RwLo
|
||||
Err(e) => print_error!(e)
|
||||
}
|
||||
}
|
||||
"fingerprints" => {
|
||||
let session_id: usize = args[1].parse().unwrap();
|
||||
let (local, peer) = session_manager.get_public_keys(&session_id);
|
||||
let local = crypto::generate_fingerprint(&local);
|
||||
let peer = crypto::generate_fingerprint(&peer);
|
||||
ui_connection.fingerprints(&local, &peer);
|
||||
}
|
||||
"verify" => {
|
||||
let session_id: usize = args[1].parse().unwrap();
|
||||
match session_manager.set_verified(&session_id) {
|
||||
@ -509,9 +511,11 @@ fn index_not_logged_in(global_vars: &Arc<RwLock<GlobalVars>>) -> HttpResponse {
|
||||
async fn handle_index(req: HttpRequest) -> HttpResponse {
|
||||
let global_vars = req.app_data::<Data<Arc<RwLock<GlobalVars>>>>().unwrap();
|
||||
if is_authenticated(&req) {
|
||||
let global_vars_read = global_vars.read().unwrap();
|
||||
HttpResponse::Ok().body(
|
||||
include_str!("frontend/index.html")
|
||||
.replace("WEBSOCKET_PORT", &global_vars.read().unwrap().websocket_port.to_string())
|
||||
.replace("IDENTITY_FINGERPRINT", &crypto::generate_fingerprint(&global_vars_read.session_manager.get_my_public_key()))
|
||||
.replace("WEBSOCKET_PORT", &global_vars_read.websocket_port.to_string())
|
||||
.replace("IS_IDENTITY_PROTECTED", &Identity::is_protected().unwrap().to_string())
|
||||
)
|
||||
} else {
|
||||
|
@ -9,7 +9,7 @@ use session::Session;
|
||||
use ed25519_dalek::PUBLIC_KEY_LENGTH;
|
||||
use uuid::Uuid;
|
||||
use platform_dirs::UserDirs;
|
||||
use crate::{constants, discovery, identity::{Contact, Identity}, utils::{get_unix_timestamp, get_not_used_path}, print_error};
|
||||
use crate::{constants, crypto, discovery, identity::{Contact, Identity}, print_error, utils::{get_unix_timestamp, get_not_used_path}};
|
||||
use crate::ui_interface::UiConnection;
|
||||
|
||||
#[derive(Display, Debug, PartialEq, Eq)]
|
||||
@ -19,7 +19,7 @@ pub enum SessionError {
|
||||
TransmissionCorrupted,
|
||||
BufferTooLarge,
|
||||
InvalidSessionId,
|
||||
Unknown
|
||||
Unknown,
|
||||
}
|
||||
|
||||
enum SessionCommand {
|
||||
@ -55,7 +55,8 @@ pub struct LargeFileDownload {
|
||||
pub struct SessionData {
|
||||
pub name: String,
|
||||
pub outgoing: bool,
|
||||
peer_public_key: [u8; PUBLIC_KEY_LENGTH],
|
||||
pub peer_public_key: [u8; PUBLIC_KEY_LENGTH],
|
||||
pub ip: IpAddr,
|
||||
sender: Sender<SessionCommand>,
|
||||
pub file_download: Option<LargeFileDownload>,
|
||||
}
|
||||
@ -68,7 +69,7 @@ pub struct SessionManager {
|
||||
loaded_contacts: RwLock<HashMap<usize, Contact>>,
|
||||
pub last_loaded_msg_offsets: RwLock<HashMap<usize, usize>>,
|
||||
pub saved_msgs: Mutex<HashMap<usize, Vec<(bool, Vec<u8>)>>>,
|
||||
not_seen: RwLock<Vec<usize>>,
|
||||
pub not_seen: RwLock<Vec<usize>>,
|
||||
mdns_service: Mutex<Option<Service>>,
|
||||
listener_stop_signal: Mutex<Option<Sender<()>>>,
|
||||
}
|
||||
@ -480,6 +481,7 @@ impl SessionManager {
|
||||
}
|
||||
};
|
||||
if let Some(mut session) = session {
|
||||
let ip = session.get_ip();
|
||||
let mut is_contact = false;
|
||||
let session_data = {
|
||||
let mut sessions = session_manager.sessions.write().unwrap();
|
||||
@ -493,9 +495,10 @@ impl SessionManager {
|
||||
if is_new_session && session_manager.is_identity_loaded() { //check if we didn't logged out during the handshake
|
||||
let (sender, receiver) = mpsc::channel(32);
|
||||
let session_data = SessionData{
|
||||
name: session.get_ip(),
|
||||
name: ip.to_string(),
|
||||
outgoing,
|
||||
peer_public_key,
|
||||
ip,
|
||||
sender: sender,
|
||||
file_download: None,
|
||||
};
|
||||
@ -524,7 +527,7 @@ impl SessionManager {
|
||||
if let Some(session_data) = session_data {
|
||||
let (session_id, receiver) = session_data;
|
||||
session_manager.with_ui_connection(|ui_connection| {
|
||||
ui_connection.on_new_session(&session_id, &session.get_ip(), outgoing, None);
|
||||
ui_connection.on_new_session(&session_id, &ip.to_string(), outgoing, &crypto::generate_fingerprint(&peer_public_key), ip, None);
|
||||
});
|
||||
if !is_contact {
|
||||
match session.encrypt_and_send(&protocol::ask_name()).await {
|
||||
@ -567,24 +570,14 @@ impl SessionManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list_contacts(&self) -> Vec<(usize, String, bool)> {
|
||||
self.loaded_contacts.read().unwrap().iter().map(|c| (*c.0, c.1.name.clone(), c.1.verified)).collect()
|
||||
pub fn list_contacts(&self) -> Vec<(usize, String, bool, [u8; PUBLIC_KEY_LENGTH])> {
|
||||
self.loaded_contacts.read().unwrap().iter().map(|c| (*c.0, c.1.name.clone(), c.1.verified, c.1.public_key)).collect()
|
||||
}
|
||||
|
||||
pub fn get_saved_msgs(&self) -> HashMap<usize, Vec<(bool, Vec<u8>)>> {
|
||||
self.saved_msgs.lock().unwrap().clone()
|
||||
}
|
||||
|
||||
pub fn get_peer_public_key(&self, session_id: &usize) -> Option<[u8; PUBLIC_KEY_LENGTH]> {
|
||||
let sessions = self.sessions.read().unwrap();
|
||||
let session = sessions.get(session_id)?;
|
||||
Some(session.peer_public_key)
|
||||
}
|
||||
|
||||
pub fn list_not_seen(&self) -> Vec<usize> {
|
||||
self.not_seen.read().unwrap().clone()
|
||||
}
|
||||
|
||||
pub fn set_seen(&self, session_id: usize, seen: bool) {
|
||||
let mut not_seen = self.not_seen.write().unwrap();
|
||||
if seen {
|
||||
@ -608,7 +601,7 @@ impl SessionManager {
|
||||
}
|
||||
|
||||
pub fn add_contact(&self, session_id: usize, name: String) -> Result<(), rusqlite::Error> {
|
||||
let contact = self.identity.read().unwrap().as_ref().unwrap().add_contact(name, self.get_peer_public_key(&session_id).unwrap())?;
|
||||
let contact = self.identity.read().unwrap().as_ref().unwrap().add_contact(name, self.sessions.read().unwrap().get(&session_id).unwrap().peer_public_key)?;
|
||||
self.loaded_contacts.write().unwrap().insert(session_id, contact);
|
||||
self.last_loaded_msg_offsets.write().unwrap().insert(session_id, 0);
|
||||
Ok(())
|
||||
@ -671,8 +664,8 @@ impl SessionManager {
|
||||
msgs
|
||||
}
|
||||
|
||||
pub fn get_public_keys(&self, session_id: &usize) -> ([u8; PUBLIC_KEY_LENGTH], [u8; PUBLIC_KEY_LENGTH]) {
|
||||
(self.identity.read().unwrap().as_ref().unwrap().get_public_key(), self.loaded_contacts.read().unwrap().get(session_id).unwrap().public_key)
|
||||
pub fn get_my_public_key(&self) -> [u8; PUBLIC_KEY_LENGTH] {
|
||||
self.identity.read().unwrap().as_ref().unwrap().get_public_key()
|
||||
}
|
||||
|
||||
pub fn get_my_name(&self) -> String {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{io::ErrorKind, convert::TryInto};
|
||||
use std::{convert::TryInto, io::ErrorKind, net::IpAddr};
|
||||
use tokio::{net::TcpStream, io::{AsyncReadExt, AsyncWriteExt}};
|
||||
use ed25519_dalek;
|
||||
use ed25519_dalek::{ed25519::signature::Signature, Verifier, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH};
|
||||
@ -48,8 +48,8 @@ impl Session {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_ip(&self) -> String {
|
||||
self.stream.peer_addr().unwrap().ip().to_string()
|
||||
pub fn get_ip(&self) -> IpAddr {
|
||||
self.stream.peer_addr().unwrap().ip()
|
||||
}
|
||||
|
||||
async fn socket_read(&mut self, buff: &mut [u8]) -> Result<usize, SessionError> {
|
||||
|
@ -1,9 +1,9 @@
|
||||
use std::net::TcpStream;
|
||||
use std::net::{IpAddr, TcpStream};
|
||||
use tungstenite::{WebSocket, protocol::Role, Message};
|
||||
use crate::{protocol, session_manager::LargeFileDownload};
|
||||
|
||||
mod ui_messages {
|
||||
use std::{iter::FromIterator, str::from_utf8};
|
||||
use std::{iter::FromIterator, net::IpAddr, str::from_utf8};
|
||||
use tungstenite::Message;
|
||||
use uuid::Uuid;
|
||||
use crate::{print_error, session_manager::{protocol, LargeFileDownload, FileState}, utils::to_uuid_bytes};
|
||||
@ -27,8 +27,8 @@ mod ui_messages {
|
||||
pub fn on_disconnected(session_id: &usize) -> Message {
|
||||
simple_event("disconnected", session_id)
|
||||
}
|
||||
pub fn on_new_session(session_id: &usize, name: &str, outgoing: bool) -> Message {
|
||||
Message::from(format!("new_session {} {} {}", session_id, outgoing, name))
|
||||
pub fn on_new_session(session_id: &usize, name: &str, outgoing: bool, fingerprint: &str, ip: IpAddr) -> Message {
|
||||
Message::from(format!("new_session {} {} {} {} {}", session_id, outgoing, fingerprint, ip, name))
|
||||
}
|
||||
pub fn on_file_received(session_id: &usize, buffer: &[u8]) -> Option<Message> {
|
||||
let uuid = Uuid::from_bytes(to_uuid_bytes(&buffer[1..17])?);
|
||||
@ -98,11 +98,8 @@ mod ui_messages {
|
||||
pub fn on_name_told(session_id: &usize, name: &str) -> Message {
|
||||
Message::from(format!("name_told {} {}", session_id, name))
|
||||
}
|
||||
pub fn set_as_contact(session_id: usize, name: &str, verified: bool) -> Message {
|
||||
Message::from(format!("is_contact {} {} {}", session_id, verified, name))
|
||||
}
|
||||
pub fn fingerprints(local: &str, peer: &str) -> Message {
|
||||
Message::from(format!("fingerprints {} {}", local, peer))
|
||||
pub fn set_as_contact(session_id: usize, name: &str, verified: bool, fingerprint: &str) -> Message {
|
||||
Message::from(format!("is_contact {} {} {} {}", session_id, verified, fingerprint, name))
|
||||
}
|
||||
pub fn set_name(new_name: &str) -> Message {
|
||||
Message::from(format!("set_name {}", new_name))
|
||||
@ -156,8 +153,8 @@ impl UiConnection {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
pub fn on_new_session(&mut self, session_id: &usize, name: &str, outgoing: bool, file_transfer: Option<&LargeFileDownload>) {
|
||||
self.write_message(ui_messages::on_new_session(session_id, name, outgoing));
|
||||
pub fn on_new_session(&mut self, session_id: &usize, name: &str, outgoing: bool, fingerprint: &str, ip: IpAddr, file_transfer: Option<&LargeFileDownload>) {
|
||||
self.write_message(ui_messages::on_new_session(session_id, name, outgoing, fingerprint, ip));
|
||||
if let Some(file_transfer) = file_transfer {
|
||||
self.write_message(ui_messages::new_file_transfer(session_id, file_transfer));
|
||||
}
|
||||
@ -172,8 +169,8 @@ impl UiConnection {
|
||||
pub fn inc_file_transfer(&mut self, session_id: &usize, chunk_size: u64) {
|
||||
self.write_message(ui_messages::inc_file_transfer(session_id, chunk_size));
|
||||
}
|
||||
pub fn set_as_contact(&mut self, session_id: usize, name: &str, verified: bool) {
|
||||
self.write_message(ui_messages::set_as_contact(session_id, name, verified));
|
||||
pub fn set_as_contact(&mut self, session_id: usize, name: &str, verified: bool, fingerprint: &str) {
|
||||
self.write_message(ui_messages::set_as_contact(session_id, name, verified, fingerprint));
|
||||
}
|
||||
pub fn load_msgs(&mut self, session_id: &usize, msgs: &Vec<(bool, Vec<u8>)>) {
|
||||
msgs.into_iter().rev().for_each(|msg| {
|
||||
@ -186,9 +183,6 @@ impl UiConnection {
|
||||
pub fn set_not_seen(&mut self, session_ids: Vec<usize>) {
|
||||
self.write_message(ui_messages::set_not_seen(session_ids));
|
||||
}
|
||||
pub fn fingerprints(&mut self, local: &str, peer: &str) {
|
||||
self.write_message(ui_messages::fingerprints(local, peer));
|
||||
}
|
||||
pub fn set_name(&mut self, new_name: &str) {
|
||||
self.write_message(ui_messages::set_name(new_name));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user