diff --git a/src/public/chat.js b/src/public/chat.js index 9b122ce..1ce8ddf 100644 --- a/src/public/chat.js +++ b/src/public/chat.js @@ -36,12 +36,12 @@ socket.on('chat message', (msg, room, tag_received, iv, nonce) => { const messages = document.getElementById(`messages-${room}`); const associated_data = fromHexString(Array.from((document.getElementById('pubkey')).classList).find(className => className.startsWith('key-')).replace('key-', '')); const pubkey = Array.from(messages.classList).find(className => className.startsWith('key-')).replace('key-', ''); - const item = document.createElement('li'); let {plaintext, tag} = decrypt_message(msg, pubkey, fromHexString(iv), fromHexString(nonce), associated_data); - item.textContent = plaintext - console.log(tag); - console.log(tag_received); - messages.appendChild(item); + if (tag === tag_received) { + append_message(1, plaintext, messages); + } else { + append_message(2, "Corrupted message. Tags do not match.", messages); + } if (document.getElementById(`room-${room}`).style.display === 'block') { window.scrollTo(0, document.body.scrollHeight); } @@ -61,22 +61,24 @@ socket.on('key exchange', (user_pubkey, pubkey, part) => { sharedsecret[user_pubkey] = sharedKey(secret, fromHexString(pubkey)); socket.emit('key exchange', user_pubkey, toHexString(keys.pubkey), 2); console.log(`shared secret: ${toHexString(sharedsecret[user_pubkey])}`); - init_ratchets(0, user_pubkey) + init_ratchets(0, user_pubkey); break; case 2: sharedsecret[user_pubkey] = sharedKey(secret, fromHexString(pubkey)); console.log(`shared secret: ${toHexString(sharedsecret[user_pubkey])}`); - init_ratchets(1, user_pubkey) + init_ratchets(1, user_pubkey); break; } }); -export function create_listener(form, input) { +export function create_listener(form, input, messages) { form.addEventListener('submit', function(e) { e.preventDefault(); if (input.value) { + append_message(0, input.value, messages); + window.scrollTo(0, document.body.scrollHeight); const pubkey = Array.from(form.classList).find(className => className.startsWith('key-')).replace('key-', ''); - let {cipher, tag, iv, nonce} = encrypt_message(input.value, pubkey) + let {cipher, tag, iv, nonce} = encrypt_message(input.value, pubkey); socket.emit('chat message', cipher, form.id, tag, iv, nonce); input.value = ''; } @@ -90,12 +92,6 @@ function encrypt_message(message, user_pubkey) { let nonce = generateRandomUint8Array(); let associated_data = fromHexString(user_pubkey); let {cipher, tag} = keccakAEAD.encrypt(encryption_key, encoded_msg, iv, associated_data, nonce); - console.log(iv) - console.log(nonce) - console.log(associated_data) - console.log(encryption_key) - console.log(encoded_msg) - console.log(cipher) return {cipher: toHexString(cipher), tag: toHexString(tag), iv: toHexString(iv), @@ -107,12 +103,6 @@ function decrypt_message(cipher, user_pubkey, iv, nonce, associated_data) { let decryption_key = receiving_ratchets[user_pubkey].next(); let cipher_array = fromHexString(cipher); let {plaintext, tag} = keccakAEAD.decrypt(decryption_key, cipher_array, iv, associated_data, nonce); - console.log(iv) - console.log(nonce) - console.log(associated_data) - console.log(decryption_key) - console.log(plaintext) - console.log(cipher_array) return {plaintext: (new TextDecoder('utf-8')).decode(plaintext), tag: toHexString(tag) }; @@ -124,6 +114,28 @@ function generateRandomUint8Array(length = 16) { return randomArray; } +function append_message(type, text, messageUl) { + const item = document.createElement('li'); + const bubble = document.createElement('div'); + bubble.textContent = text; + switch (type) { + case 0: + bubble.className = "sent-msg"; + item.className = "sent"; + break; + case 1: + bubble.className = "received-msg"; + item.className = "received"; + break; + case 2: + bubble.className = "corrupted-msg"; + item.className = "corrupted"; + break; + } + item.appendChild(bubble); + messageUl.appendChild(item); +} + const fromHexString = (hexString) => Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))); diff --git a/src/public/rooms.js b/src/public/rooms.js index c10108c..7799bfc 100644 --- a/src/public/rooms.js +++ b/src/public/rooms.js @@ -72,7 +72,7 @@ function render_rooms(room_info) { roomDiv.style.display = 'none'; } - create_listener(form, input); + create_listener(form, input, messagesUl); }); } diff --git a/src/public/style.css b/src/public/style.css index 44a048b..3aefa54 100644 --- a/src/public/style.css +++ b/src/public/style.css @@ -59,6 +59,69 @@ body { color: #ffffff; } +/* Messages */ +.corrupted-msg { + display: inline-block; + max-width: 80%; + color: darkred; + font-weight: bold; + background-color: #ffcccc; + border: 1px solid darkred; + padding: 5px; + border-radius: 5px; + text-align: center; + margin: 5px 0; + word-break: break-word; +} + +.received-msg { + display: inline-block; + max-width: 80%; + color: black; + background-color: #90f5eb; + border: 1px solid darkblue; + padding: 5px; + border-radius: 5px; + text-align: left; + margin: 5px 0; + word-break: break-word; +} + +.sent-msg { + display: inline-block; + max-width: 80%; + color: black; + background-color: #00ff55; + border: 1px solid #177013; + padding: 5px; + border-radius: 5px; + text-align: right; + margin: 5px 0; + word-break: break-word; +} + +ul { + list-style-type: none; + padding: 0; + margin: 0; +} + +ul li { + width: 100%; +} + +li.received { + text-align: left; +} + +li.sent { + text-align: right; +} + +li.corrupted { + text-align: center; +} + /* Tabbed navigation */ .tab-bar { display: flex;