diff --git a/Cargo.toml b/Cargo.toml index fab2df6..f8ebcc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,4 +36,7 @@ multicast_dns = "0.5" #mDNS browser pnet_datalink = "0.27.2" base64 = "0.13.0" scrypt = "0.7.0" -zeroize = "1.2.0" \ No newline at end of file +zeroize = "1.2.0" + +[build-dependencies] +html-minifier = "3.0.11" \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..0d7f63f --- /dev/null +++ b/build.rs @@ -0,0 +1,44 @@ +use std::{env, fs::{File, read_to_string, create_dir}, path::Path, io::{Write, ErrorKind}}; + +#[allow(dead_code)] +fn minify_content(content: &str, language: &str) -> Option { + match language { + "html" => Some(html_minifier::minify(content).unwrap()), + "js" => Some(html_minifier::js::minify(content)), + "css" => Some(html_minifier::css::minify(content).unwrap()), + _ => None, + } +} + +#[allow(dead_code)] +fn minify_web_files() { + let out_dir = env::var("OUT_DIR").unwrap(); + let out_dir = Path::new(&out_dir); + let src_dir = Path::new("src/frontend"); + + if let Err(e) = create_dir(out_dir.join("commons")) { + if e.kind() != ErrorKind::AlreadyExists { + panic!("Failed to create \"commons\" directory"); + } + } + + [ + "login.html", + "index.html", + "index.css", + "index.js", + "commons/style.css", + "commons/script.js" + ].iter().for_each(|file_name| { + let file_name = Path::new(file_name); + let content = read_to_string(src_dir.join(file_name)).unwrap(); + let minified_content = minify_content(&content, file_name.extension().unwrap().to_str().unwrap()).unwrap(); + let mut dst = File::create(out_dir.join(file_name)).unwrap(); + dst.write(minified_content.as_bytes()).unwrap(); + }); +} + +fn main() { + #[cfg(not(debug_assertions))] + minify_web_files(); +} \ No newline at end of file diff --git a/src/frontend/commons/script.js b/src/frontend/commons/script.js index b0951a8..5a89c6b 100644 --- a/src/frontend/commons/script.js +++ b/src/frontend/commons/script.js @@ -1,6 +1,6 @@ -function generateAvatar(name){ +function generateAvatar(name) { let span = document.createElement("span"); - if (typeof name == "undefined"){ + if (typeof name == "undefined") { span.appendChild(document.createTextNode("?")); } else if (name.length > 0) { span.appendChild(document.createTextNode(name[0].toUpperCase())); diff --git a/src/frontend/index.js b/src/frontend/index.js index b2d3662..52ecd30 100644 --- a/src/frontend/index.js +++ b/src/frontend/index.js @@ -21,7 +21,7 @@ function onClickSession(event) { displaySessions(); displayHeader(); displayChatBottom(); - dislayHistory(); + displayHistory(); } } let ip_input = document.getElementById("ip_input"); @@ -45,7 +45,7 @@ document.getElementById("show_local_ips").onclick = function() { } mainDiv.appendChild(ul); showPopup(mainDiv); -} +}; let message_input = document.getElementById("message_input"); message_input.addEventListener("keyup", function(event) { if (event.key === "Enter") { @@ -68,17 +68,17 @@ document.getElementById("delete_conversation").onclick = function() { socket.send("delete_conversation "+currentSessionId); msgHistory.get(currentSessionId).length = 0; removePopup(); - dislayHistory(); - } + displayHistory(); + }; mainDiv.appendChild(button); showPopup(mainDiv); -} +}; document.getElementById("add_contact").onclick = function() { socket.send("contact "+currentSessionId+" "+sessionsData.get(currentSessionId).name); sessionsData.get(currentSessionId).isContact = true; displayHeader(); displaySessions(); -} +}; document.getElementById("remove_contact").onclick = function() { let mainDiv = document.createElement("div"); mainDiv.appendChild(generatePopupWarningTitle()); @@ -101,12 +101,12 @@ document.getElementById("remove_contact").onclick = function() { } displayHeader(); displaySessions(); - dislayHistory(); + displayHistory(); removePopup(); - } + }; mainDiv.appendChild(button); showPopup(mainDiv); -} +}; document.getElementById("verify").onclick = function() { let session = sessionsData.get(currentSessionId); if (typeof session !== "undefined") { @@ -146,7 +146,7 @@ document.getElementById("verify").onclick = function() { mainDiv.appendChild(buttonRow); showPopup(mainDiv); } -} +}; document.getElementById("logout").onclick = function() { let mainDiv = document.createElement("div"); mainDiv.appendChild(generatePopupWarningTitle()); @@ -161,7 +161,7 @@ document.getElementById("logout").onclick = function() { button.onclick = logout; mainDiv.appendChild(button); showPopup(mainDiv); -} +}; document.getElementById("attach_file").onchange = function(event) { let files = event.target.files; let useLargeFileTransfer = false; @@ -214,10 +214,10 @@ document.getElementById("attach_file").onchange = function(event) { }); }; } -} +}; document.getElementById("file_cancel").onclick = function() { socket.send("abort "+currentSessionId); -} +}; let msg_log = document.getElementById("msg_log"); msg_log.onscroll = function() { if (sessionsData.get(currentSessionId).isContact) { @@ -225,7 +225,7 @@ msg_log.onscroll = function() { socket.send("load_msgs "+currentSessionId); } } -} +}; let profile_div = document.querySelector("#me>div"); profile_div.onclick = function() { let mainDiv = document.createElement("div"); @@ -327,14 +327,14 @@ profile_div.onclick = function() { deleteButton.textContent = "Delete"; deleteButton.onclick = function() { socket.send("disappear"); - } + }; mainDiv.appendChild(deleteButton); showPopup(mainDiv); - } + }; sectionDelete.appendChild(deleteButton); mainDiv.appendChild(sectionDelete); showPopup(mainDiv); -} +}; let chatHeader = document.getElementById("chat_header"); chatHeader.children[0].onclick = function() { let session = sessionsData.get(currentSessionId); @@ -366,10 +366,10 @@ chatHeader.children[0].onclick = function() { } showPopup(mainDiv); } -} +}; document.querySelector("#refresher button").onclick = function() { socket.send("refresh"); -} +}; //source: https://stackoverflow.com/a/14919494 function humanFileSize(bytes, dp=1) { @@ -423,7 +423,7 @@ socket.onopen = function() { if (currentSessionId != -1) { socket.send("set_seen "+currentSessionId); } - } + }; if (Notification.permission === "granted") { notificationAllowed = true; } else if (Notification.permission !== "denied") { @@ -494,10 +494,10 @@ socket.onmessage = function(msg) { logout(); } } -} +}; socket.onclose = function() { console.log("Disconnected"); -} +}; function onNewSession(sessionId, outgoing, fingerprint, ip, name) { if (sessionsData.has(sessionId)) { @@ -542,7 +542,7 @@ function onIsContact(sessionId, verified, fingerprint, name) { } function onMsgOrFileReceived(sessionId, outgoing, body) { if (currentSessionId == sessionId) { - dislayHistory(); + displayHistory(); if (!document.hidden && !outgoing) { socket.send("set_seen "+sessionId); } @@ -631,14 +631,14 @@ function onAskLargeFiles(sessionId, encodedDownloadLocation, filesInfo) { if (currentSessionId == sessionId) { displayChatBottom(); } - } + }; buttonRow.appendChild(buttonDownload); let buttonRefuse = document.createElement("button"); buttonRefuse.textContent = "Refuse"; buttonRefuse.onclick = function() { removePopup(); socket.send("abort "+sessionId); - } + }; buttonRow.appendChild(buttonRefuse); mainDiv.appendChild(buttonRow); showPopup(mainDiv, false); @@ -688,13 +688,13 @@ function onIncFilesTransfer(sessionId, chunkSize) { function onMsgLoad(sessionId, outgoing, msg) { msgHistory.get(sessionId).unshift([outgoing, false, msg]); if (currentSessionId == sessionId) { - dislayHistory(false); + displayHistory(false); } } function onFileLoad(sessionId, outgoing, uuid, fileName) { msgHistory.get(sessionId).unshift([outgoing, true, [uuid, fileName]]); if (currentSessionId == sessionId) { - dislayHistory(false); + displayHistory(false); } } function onDisconnected(sessionId) { @@ -721,7 +721,7 @@ function onFileReceived(sessionId, uuid, file_name) { function onFileSent(sessionId, uuid, file_name) { msgHistory.get(sessionId).push([true, true, [uuid, file_name]]); if (currentSessionId == sessionId) { - dislayHistory(); + displayHistory(); } } function onNameSet(newName) { @@ -763,7 +763,7 @@ function beautifyFingerprint(f) { 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, @@ -994,7 +994,7 @@ function displayChatBottom(speed = undefined) { } } } -function dislayHistory(scrollToBottom = true) { +function displayHistory(scrollToBottom = true) { msg_log.style.display = "block"; msg_log.innerHTML = ""; let previousOutgoing = undefined; diff --git a/src/main.rs b/src/main.rs index 5546346..2b187f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -475,7 +475,11 @@ fn handle_login(req: HttpRequest, mut params: web::Form) -> HttpRes } fn get_login_body(error_msg: Option<&str>) -> Result { - Ok(include_str!("frontend/login.html") + #[cfg(debug_assertions)] + let html = fs::read_to_string("src/frontend/login.html").unwrap(); + #[cfg(not(debug_assertions))] + let html = include_str!(concat!(env!("OUT_DIR"), "/login.html")); + Ok(html .replace("ERROR_MSG", &match error_msg { Some(error_msg) => format!("Error: {}.", error_msg), None => String::new() @@ -546,7 +550,7 @@ async fn handle_index(req: HttpRequest) -> HttpResponse { #[cfg(debug_assertions)] let html = fs::read_to_string("src/frontend/index.html").unwrap(); #[cfg(not(debug_assertions))] - let html = include_str!("frontend/index.html"); + let html = include_str!(concat!(env!("OUT_DIR"), "/index.html")); HttpResponse::Ok().body( html .replace("AIRA_VERSION", env!("CARGO_PKG_VERSION")) @@ -571,13 +575,13 @@ fn handle_static(req: HttpRequest) -> HttpResponse { #[cfg(debug_assertions)] return response_builder.body(fs::read_to_string("src/frontend/index.js").unwrap()); #[cfg(not(debug_assertions))] - return response_builder.body(include_str!("frontend/index.js")); + return response_builder.body(include_str!(concat!(env!("OUT_DIR"), "/index.js"))); } "index.css" => { #[cfg(debug_assertions)] return response_builder.body(fs::read_to_string("src/frontend/index.css").unwrap()); #[cfg(not(debug_assertions))] - return response_builder.body(include_str!("frontend/index.css")); + return response_builder.body(include_str!(concat!(env!("OUT_DIR"), "/index.css"))); } "imgs" => { if splits[2] == "icons" && splits.len() <= 5 { @@ -625,12 +629,18 @@ fn handle_static(req: HttpRequest) -> HttpResponse { "commons" => { if splits.len() == 3 { match splits[2] { - "script.js" => return response_builder.content_type(JS_CONTENT_TYPE).body(include_str!("frontend/commons/script.js")), + "script.js" => { + response_builder.content_type(JS_CONTENT_TYPE); + #[cfg(debug_assertions)] + return response_builder.body(fs::read_to_string("src/frontend/commons/script.js").unwrap()); + #[cfg(not(debug_assertions))] + return response_builder.body(include_str!(concat!(env!("OUT_DIR"), "/commons/script.js"))) + } "style.css" => { #[cfg(debug_assertions)] return response_builder.body(fs::read_to_string("src/frontend/commons/style.css").unwrap()); #[cfg(not(debug_assertions))] - return response_builder.body(include_str!("frontend/commons/style.css")); + return response_builder.body(include_str!(concat!(env!("OUT_DIR"), "/commons/style.css"))); } _ => {} }