diff --git a/src/app.js b/src/app.js index 09bde4a..6926c62 100644 --- a/src/app.js +++ b/src/app.js @@ -55,7 +55,7 @@ io.on('connection', async (socket) => { const roomid = room.substring(5); const members = await database.getRoomMembers(roomid); members.forEach(memberRoom => { - socket.to(memberRoom).emit('chat message', msg, roomid, tag, iv, nonce); + socket.to(memberRoom).emit('chat message', msg, roomid, tag, iv, nonce, session.publicKey); }); console.log('message: ' + msg + ', sender: ' + session.id); console.log(session.publicKey); diff --git a/src/controllers/chat.js b/src/controllers/chat.js index 22ce936..2d5bd7d 100644 --- a/src/controllers/chat.js +++ b/src/controllers/chat.js @@ -8,8 +8,12 @@ const chatController = { if (!pubkey) { return res.status(400).json({ error: "Missing publicKey" }); } - await database.createRoom(req.session.publicKey, stringutils.pemToHex(pubkey)); - return res.status(201).json({ message: "Room created successfully." }); + const hexKey = stringutils.pemToHex(pubkey) + const roomid = await database.createRoom(req.session.publicKey, hexKey); + return res.status(201).json({ message: "Room created successfully.", + roomid: roomid, + peer: hexKey + }); } catch (error) { console.error("Error creating the room:", error); return res.status(500).json({ error: "Failed to create the room" }); diff --git a/src/public/chat.js b/src/public/chat.js index 1ce8ddf..c058591 100644 --- a/src/public/chat.js +++ b/src/public/chat.js @@ -1,6 +1,7 @@ import { genKeys, sharedKey } from "./ecdh.js"; import { keccakAEAD } from "./aead.js"; import { keccakKDF } from "./kdf.js"; +import { render_room, render_rooms_wrapper } from "./rooms.js"; const socket = io(); let secret = null; @@ -9,6 +10,8 @@ let dh_ratchets = {}; let sending_ratchets = {}; let receiving_ratchets = {}; +render_rooms_wrapper(); + function init_ratchets(order, user_pubkey) { let dh_ratchet = new keccakKDF() let key_1 = dh_ratchet.init(sharedsecret[user_pubkey], new Uint8Array(0)); @@ -31,16 +34,20 @@ function init_ratchets(order, user_pubkey) { } -socket.on('chat message', (msg, room, tag_received, iv, nonce) => { +socket.on('chat message', (msg, room, tag_received, iv, nonce, pubkey_received) => { console.log(`received: ${msg}`); - const messages = document.getElementById(`messages-${room}`); + let messages = document.getElementById(`messages-${room}`); + if (!messages) { + render_room(room, pubkey_received); + 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-', ''); let {plaintext, tag} = decrypt_message(msg, pubkey, fromHexString(iv), fromHexString(nonce), associated_data); - if (tag === tag_received) { + if (tag === tag_received && pubkey == pubkey_received) { append_message(1, plaintext, messages); } else { - append_message(2, "Corrupted message. Tags do not match.", messages); + append_message(2, "Corrupted message.", messages); } if (document.getElementById(`room-${room}`).style.display === 'block') { window.scrollTo(0, document.body.scrollHeight); diff --git a/src/public/popups-logged.js b/src/public/popups-logged.js index e4d19fd..90cea81 100644 --- a/src/public/popups-logged.js +++ b/src/public/popups-logged.js @@ -1,3 +1,4 @@ +import { render_room } from "./rooms.js"; // handle key presses (close/confirm) document.addEventListener("keydown", async function(event) { @@ -45,6 +46,8 @@ export async function addConfirm() { throw new Error('Failed to add'); } else { inputFieldPublicKey.value = ''; - location.reload(); + const { roomid, peer } = await response.json(); + render_room(roomid, peer); } + addPopup.style.display = 'none'; } diff --git a/src/public/rooms.js b/src/public/rooms.js index 7799bfc..e20da6e 100644 --- a/src/public/rooms.js +++ b/src/public/rooms.js @@ -1,68 +1,84 @@ import { create_listener } from "./chat.js"; -render_rooms_wrapper() - async function render_rooms_wrapper() { const room_info = await request_rooms(); console.log(room_info); - render_rooms(room_info); + render_all_rooms(room_info); } -function render_rooms(room_info) { +function render_room(roomId, pubkey) { + const tabBar = document.getElementById('rooms-tabbar'); + const contentContainer = document.getElementById('rooms-container'); + + // tab button + const tabButton = document.createElement('button'); + tabButton.className = 'tab-button'; + tabButton.textContent = roomId; + tabButton.dataset.roomId = roomId; + tabButton.addEventListener('click', () => openRoom(roomId)); + tabBar.appendChild(tabButton); + + // room content + const roomDiv = document.createElement('div'); + roomDiv.id = `room-${roomId}`; + roomDiv.className = 'room-content'; + + // public key textarea + const pubKeyText = document.createElement('textarea'); + pubKeyText.value = pubkey; + pubKeyText.readOnly = true; + roomDiv.appendChild(pubKeyText); + + // messages list + const messagesUl = document.createElement('ul'); + messagesUl.id = `messages-${roomId}`; + messagesUl.className = `key-${pubkey}`; + roomDiv.appendChild(messagesUl); + + // message form + const form = document.createElement('form'); + form.id = `form-${roomId}`; + form.className = `key-${pubkey}`; + + const input = document.createElement('input'); + input.id = `input-${roomId}`; + input.className = `key-${pubkey}`; + input.autocomplete = 'off'; + + const button = document.createElement('button'); + button.textContent = 'Send'; + + form.appendChild(input); + form.appendChild(button); + roomDiv.appendChild(form); + contentContainer.appendChild(roomDiv); + + create_listener(form, input, messagesUl); + + roomDiv.style.display = 'none'; + + return {roomDiv, tabButton}; +} + +function render_all_rooms(room_info) { const roomsContainer = document.getElementById('rooms'); roomsContainer.innerHTML = ''; const tabBar = document.createElement('div'); + tabBar.id = 'rooms-tabbar'; tabBar.className = 'tab-bar'; roomsContainer.appendChild(tabBar); const contentContainer = document.createElement('div'); contentContainer.className = 'room-content-container'; + contentContainer.id = 'rooms-container'; roomsContainer.appendChild(contentContainer); + let roomDiv = null; + let tabButton = null; + room_info.forEach(([roomId, pubkey], index) => { - // tab button - const tabButton = document.createElement('button'); - tabButton.className = 'tab-button'; - tabButton.textContent = roomId; - tabButton.dataset.roomId = roomId; - tabButton.addEventListener('click', () => openRoom(roomId)); - tabBar.appendChild(tabButton); - - // room content - const roomDiv = document.createElement('div'); - roomDiv.id = `room-${roomId}`; - roomDiv.className = 'room-content'; - - // public key textarea - const pubKeyText = document.createElement('textarea'); - pubKeyText.value = pubkey; - pubKeyText.readOnly = true; - roomDiv.appendChild(pubKeyText); - - // messages list - const messagesUl = document.createElement('ul'); - messagesUl.id = `messages-${roomId}`; - messagesUl.className = `key-${pubkey}`; - roomDiv.appendChild(messagesUl); - - // message form - const form = document.createElement('form'); - form.id = `form-${roomId}`; - form.className = `key-${pubkey}`; - - const input = document.createElement('input'); - input.id = `input-${roomId}`; - input.className = `key-${pubkey}`; - input.autocomplete = 'off'; - - const button = document.createElement('button'); - button.textContent = 'Send'; - - form.appendChild(input); - form.appendChild(button); - roomDiv.appendChild(form); - contentContainer.appendChild(roomDiv); + ({roomDiv, tabButton} = render_room(roomId, pubkey)); // show first room by default if (index === 0) { @@ -71,8 +87,6 @@ function render_rooms(room_info) { } else { roomDiv.style.display = 'none'; } - - create_listener(form, input, messagesUl); }); } @@ -102,3 +116,5 @@ async function request_rooms() { const { rooms } = await response.json(); return rooms; } + +export { render_room, render_rooms_wrapper }; diff --git a/src/socket.js b/src/socket.js index 3a08f59..c167c67 100644 --- a/src/socket.js +++ b/src/socket.js @@ -7,9 +7,4 @@ const socket = io(URL, { withCredentials: true }); -// log during dev -socket.onAny((event, ...args) => { - console.log(event, args); -}); - export default socket;