improve ergonomy

This commit is contained in:
Sam Hadow 2025-03-10 17:27:25 +01:00
parent 874aeb8897
commit f4b251aeb3
6 changed files with 86 additions and 61 deletions

View File

@ -55,7 +55,7 @@ io.on('connection', async (socket) => {
const roomid = room.substring(5); const roomid = room.substring(5);
const members = await database.getRoomMembers(roomid); const members = await database.getRoomMembers(roomid);
members.forEach(memberRoom => { 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('message: ' + msg + ', sender: ' + session.id);
console.log(session.publicKey); console.log(session.publicKey);

View File

@ -8,8 +8,12 @@ const chatController = {
if (!pubkey) { if (!pubkey) {
return res.status(400).json({ error: "Missing publicKey" }); return res.status(400).json({ error: "Missing publicKey" });
} }
await database.createRoom(req.session.publicKey, stringutils.pemToHex(pubkey)); const hexKey = stringutils.pemToHex(pubkey)
return res.status(201).json({ message: "Room created successfully." }); const roomid = await database.createRoom(req.session.publicKey, hexKey);
return res.status(201).json({ message: "Room created successfully.",
roomid: roomid,
peer: hexKey
});
} catch (error) { } catch (error) {
console.error("Error creating the room:", error); console.error("Error creating the room:", error);
return res.status(500).json({ error: "Failed to create the room" }); return res.status(500).json({ error: "Failed to create the room" });

View File

@ -1,6 +1,7 @@
import { genKeys, sharedKey } from "./ecdh.js"; import { genKeys, sharedKey } from "./ecdh.js";
import { keccakAEAD } from "./aead.js"; import { keccakAEAD } from "./aead.js";
import { keccakKDF } from "./kdf.js"; import { keccakKDF } from "./kdf.js";
import { render_room, render_rooms_wrapper } from "./rooms.js";
const socket = io(); const socket = io();
let secret = null; let secret = null;
@ -9,6 +10,8 @@ let dh_ratchets = {};
let sending_ratchets = {}; let sending_ratchets = {};
let receiving_ratchets = {}; let receiving_ratchets = {};
render_rooms_wrapper();
function init_ratchets(order, user_pubkey) { function init_ratchets(order, user_pubkey) {
let dh_ratchet = new keccakKDF() let dh_ratchet = new keccakKDF()
let key_1 = dh_ratchet.init(sharedsecret[user_pubkey], new Uint8Array(0)); 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}`); 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 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 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); 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); append_message(1, plaintext, messages);
} else { } 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') { if (document.getElementById(`room-${room}`).style.display === 'block') {
window.scrollTo(0, document.body.scrollHeight); window.scrollTo(0, document.body.scrollHeight);

View File

@ -1,3 +1,4 @@
import { render_room } from "./rooms.js";
// handle key presses (close/confirm) // handle key presses (close/confirm)
document.addEventListener("keydown", async function(event) { document.addEventListener("keydown", async function(event) {
@ -45,6 +46,8 @@ export async function addConfirm() {
throw new Error('Failed to add'); throw new Error('Failed to add');
} else { } else {
inputFieldPublicKey.value = ''; inputFieldPublicKey.value = '';
location.reload(); const { roomid, peer } = await response.json();
render_room(roomid, peer);
} }
addPopup.style.display = 'none';
} }

View File

@ -1,68 +1,84 @@
import { create_listener } from "./chat.js"; import { create_listener } from "./chat.js";
render_rooms_wrapper()
async function render_rooms_wrapper() { async function render_rooms_wrapper() {
const room_info = await request_rooms(); const room_info = await request_rooms();
console.log(room_info); 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'); const roomsContainer = document.getElementById('rooms');
roomsContainer.innerHTML = ''; roomsContainer.innerHTML = '';
const tabBar = document.createElement('div'); const tabBar = document.createElement('div');
tabBar.id = 'rooms-tabbar';
tabBar.className = 'tab-bar'; tabBar.className = 'tab-bar';
roomsContainer.appendChild(tabBar); roomsContainer.appendChild(tabBar);
const contentContainer = document.createElement('div'); const contentContainer = document.createElement('div');
contentContainer.className = 'room-content-container'; contentContainer.className = 'room-content-container';
contentContainer.id = 'rooms-container';
roomsContainer.appendChild(contentContainer); roomsContainer.appendChild(contentContainer);
let roomDiv = null;
let tabButton = null;
room_info.forEach(([roomId, pubkey], index) => { room_info.forEach(([roomId, pubkey], index) => {
// tab button ({roomDiv, tabButton} = render_room(roomId, pubkey));
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);
// show first room by default // show first room by default
if (index === 0) { if (index === 0) {
@ -71,8 +87,6 @@ function render_rooms(room_info) {
} else { } else {
roomDiv.style.display = 'none'; roomDiv.style.display = 'none';
} }
create_listener(form, input, messagesUl);
}); });
} }
@ -102,3 +116,5 @@ async function request_rooms() {
const { rooms } = await response.json(); const { rooms } = await response.json();
return rooms; return rooms;
} }
export { render_room, render_rooms_wrapper };

View File

@ -7,9 +7,4 @@ const socket = io(URL, {
withCredentials: true withCredentials: true
}); });
// log during dev
socket.onAny((event, ...args) => {
console.log(event, args);
});
export default socket; export default socket;