diff --git a/html/attachment.svg b/html/attachment.svg index 2c06bc2..31ff977 100644 --- a/html/attachment.svg +++ b/html/attachment.svg @@ -1,160 +1,56 @@ - + + - - - - - - - - - - - - - - image/svg+xml - - - - image/svg+xml - - Mail Attachment - 2005-11-04 - - - Andreas Nilsson - - - http://tango-project.org - - - attachment - file - - - - - - Garrett Lesage - - - - - - - - - - - - - - - - - - - + inkscape:zoom="14.3" + inkscape:cx="30" + inkscape:cy="30" + inkscape:window-x="-2" + inkscape:window-y="24" + inkscape:window-maximized="1" + inkscape:current-layer="svg4573" /> \ No newline at end of file diff --git a/html/chat.html b/html/chat.html index 06874bc..0bbdb80 100644 --- a/html/chat.html +++ b/html/chat.html @@ -1,12 +1,40 @@ -
- - - - - -
+
+
+ + +
+ + + + + + + + + + + + + +
+
+
+
diff --git a/html/messagetable.php b/html/messagetable.php index 2421a5d..efa6efa 100644 --- a/html/messagetable.php +++ b/html/messagetable.php @@ -4,7 +4,9 @@ try { $db = new mysqli("mysql", "root", $_SERVER["MYSQL_ENV_MYSQL_ROOT_PASSWORD"]); $db->query("create database if not exists safechat;"); $db->select_db("safechat"); - $db->query('create table if not exists message (id int primary key not null auto_increment, time timestamp default current_timestamp, user varchar(50) not null, msg text not null);'); + $db->query('create table if not exists message (id int primary key not null auto_increment, time timestamp default current_timestamp, user varchar(50) not null, msg longtext not null);'); + $db->query('set global max_allowed_packet=1000000000'); + $db->query('set global net_buffer_length=1000000'); } catch (Exception $e) { echo json_encode(null); } diff --git a/html/safechat.css b/html/safechat.css index 5cb690f..b2491fd 100644 --- a/html/safechat.css +++ b/html/safechat.css @@ -3,6 +3,12 @@ padding: 0; } +@media (min-resolution: 120dpi) { + html { + font-size: 120%; + } +} + p { padding: .5em 0 1em 0; } @@ -31,6 +37,23 @@ form input#msg { flex-grow: 4; } +.buttongroup { + flex-grow: 0; + display: flex; + flex-direction: row; + flex-wrap: nowrap; +} +.buttongroup .toolbutton { + flex-grow: 1; + text-align: center; +} +.toolbutton label img { + height: 1.5em; +} +.toolbutton input { + display:none; +} + table { width: 100%; } @@ -74,13 +97,16 @@ td:last-child { } } #status.error { - background-color: lightred; + background-color: red; + color: black; } #status.notice { background-color: yellow; + color: black; } #status.success { background-color: lightgreen; + color: black; } #main { @@ -93,36 +119,58 @@ td:last-child { #msgs .msg { border: 1px solid black; margin: 1ex; - padding: 1ex; border-radius: 2ex; - -moz-border-radius: 1em; - -webkit-border-radius: 1em; + -moz-border-radius: 2ex; + -webkit-border-radius: 2ex; + display: block; + width: auto; + height: auto; + max-width: 60%; } #msgs .me { float: left; + background-color: lightgray; } #msgs .other { float: right; + background-color: lightyellow; } #msgs .msg .header { - border-bottom: 1px solid black; + border: 1px solid black; + border-radius: 2ex 2ex 0 0; + -moz-border-radius: 2ex 2ex 0 0; + -webkit-border-radius: 2ex 2ex 0 0; + /*border-radius: 2ex; + -moz-border-radius: 2ex; + -webkit-border-radius: 2ex;*/ margin-bottom: .25ex; padding-bottom: .25ex; position: relative; height: 1em; + padding: .5ex 1ex .5ex 1ex; +} +#msgs .msg .header { + background-color: lightgreen; } #msgs .msg .header .date { font-size: xx-small; float: left; - /*position: absolute; - left: 0;*/ + padding: 0 1ex 0 0; } #msgs .msg .header .sender { font-size: small; float: right; - /*position: absolute; - right: 0;*/ + padding: 0 0 0 1ex; } #msgs .msg .text { float: left; + padding: .5ex 1ex .5ex 1ex; +} +#msgs .msg img { + display: block; + width: 99%; +} + +#preview img { + height: 4em; } diff --git a/html/safechat.js b/html/safechat.js index 3a46a6e..3d8e77d 100644 --- a/html/safechat.js +++ b/html/safechat.js @@ -1,5 +1,6 @@ -var password = null; -var username = null; +var password = null; // password, only stored temporary, until reload +var username = null; // username, only used during registration +var filecontent = new Array(); // temporary storage for attachments function error(data, stay) { $("#status").fadeOut("slow", function() { @@ -11,7 +12,7 @@ function error(data, stay) { $("#status").html(data); console.log("error: "+data); } else { - $("#status").html('
'+JSON.stringify(data)+'
'); + $("#status").html('error'); console.log("error: "+JSON.stringify(data)); } } else { @@ -151,18 +152,46 @@ function userid() { return publicKey().keys[0].getUserIds()[0]; } +function clearmessage() { + filecontent = new Array(); + $('#preview').empty(); + $("#msg").val(""); + notice("message cleared"); +} + +function attachments(files, id) { + if (files) files.forEach(function(file) { + //if (file.content.length<1000000) { + var img = document.createElement('img'); + img.src = 'data:'+file.type+';base64,' + file.content; + $(id).append(img); + //} + }); +} + function fileupload(evt) { if (!window.FileReader) return error("your browser dows not support file upload", true); - var reader = new FileReader(); - reader.onload = function(evt) { - if (evt.target.readyState!=2) - return notice("ReadyState="+evt.target.readyState); - if (evt.target.error) return error("error reading file", true); - filecontent = evt.target.result; - success(filecontent); + for (var i=0, f; f=evt.target.files[i]; ++i) { + var file = f; + var reader = new FileReader(); + reader.onload = function(evt) { + if (evt.target.error) return error("error reading file", true); + if (evt.target.readyState==0) return notice("waiting for data ..."); + if (evt.target.readyState==1) return notice("loading data ..."); + var base64 = btoa(evt.target.result); + filecontent.push({type: file.type, content: base64}); + if (file.type.match('^image/')) { + var img = document.createElement('img'); + img.src = 'data:'+file.type+';base64,' + base64; + $("#preview").append(img); + success('image of type '+file.type+' is ready to be sent'); + } else { + success('file of type '+file.type+' is ready to be sent'); + } + } + reader.readAsBinaryString(file); } - reader.readAsText(evt.target.files[0]); } function setreceiver(name) { @@ -171,83 +200,101 @@ function setreceiver(name) { $("#msg").focus(); } -var startmsg = 0; +var startmsg = 0; // number of last downloaded message function get() { var beeped = false; $.post("get.php", {start: startmsg}).done(function(res) { var msgs = JSON.parse(res); if (msgs) { msgs.forEach(function(e) { - if (startmsg
'+ - ''+ - (new Date(1000*Number(e["time"]))).toLocaleString()+ - ''+ - ''+ - e["user"]+ - '
'+ - msg.text+ - '
'); - $('#id'+(e["id"])).emoticonize(); - if (!beeped) - (new Audio("A-Tone-His_Self-1266414414.mp3")) - .play(); - beeped = true; - }); -// .catch(function(e) { -// error("decryption of message failed", true); -// }); + setTimeout(get, 10000); + return error("key of receiver not found", true); } + var message = openpgp.message.readArmored(e.msg); + var privkey = privateKey().keys[0]; + if (privkey.decrypt(password)) + openpgp.decryptAndVerifyMessage(privkey, key.keys, message) + .then(function(msg) { + var message = JSON.parse(msg.text); + $("#msgs") // todo: check msg.signatures[0].valid + .prepend('
'+ + ''+ + (new Date(1000*Number(e.time))).toLocaleString()+ + ''+ + ''+ + e.user+ + '
'+ + '
'+ + message.text+ + '
'); + attachments(message.files, '#id'+e.id+' .text'); + $('#id'+e.id).emoticonize(); + if (!beeped) + (new Audio("A-Tone-His_Self-1266414414.mp3")) + .play(); + beeped = true; + }) + .catch(function(e) { + // not for me + }); }).fail(function(e) { error("get sender's key from server failed", true); }); }); } - setTimeout(get, 10000); - }).fail(error); + }).fail(function(e) { + error("get messages failed") + }); + setTimeout(get, 10000); } function sendmessage(recv, txt) { + notice("1/3 preparing message ..."); + $("#message").fadeOut("slow"); $.post("pubkey.php", {user: recv}).done(function(pk) { var res=JSON.parse(pk); var key=openpgp.key.readArmored(res); if (!res||key.err) { + $("#message").fadeIn("slow"); error("key of receiver not found", true); return; } var privkey = privateKey().keys[0]; privkey.decrypt(password); - openpgp.signAndEncryptMessage(key.keys.concat(publicKey().keys), privkey, txt) + var message = JSON.stringify({text: txt, files: filecontent}); + notice("2/3 encrypting message ..."); + openpgp.signAndEncryptMessage(key.keys.concat(publicKey().keys), privkey, message) .then(function(msg) { + notice("3/3 sending message ..."); $.post("send.php", {user: userid(), msg: msg}) .done(function(res) { if (JSON.parse(res)) { - $("#msg").val(""); + $("#message").fadeIn("slow"); + clearmessage(); success("message sent"); - } else error("error sending message", true); + } else { + $("#message").fadeIn("slow"); + error("error sending message", true); + } }) .fail(error); }) .catch(function(e) { + $("#message").fadeIn("slow"); error("encryption of message failed", true); }); }).fail(function(e) { + $("#message").fadeIn("slow"); error("get receiver's key from server failed", true); }); + $("#message").fadeIn("slow"); } function setpw(pwd) { diff --git a/html/send.php b/html/send.php index 365b4d8..84aca1f 100644 --- a/html/send.php +++ b/html/send.php @@ -4,7 +4,12 @@ try { $user = $db->real_escape_string($_REQUEST['user']); $msg = $db->real_escape_string($_REQUEST['msg']); $q = $db->query("insert into message (user, msg) values ('$user', '$msg');"); - echo json_encode(true); + if ($q) { + echo json_encode(true); + } else { + error_log("Error storing message: ".$db->error); + echo json_encode(false); + } } catch (Exception $e) { echo json_encode(false); }