diff --git a/src/app.js b/src/app.js index 6926c62..97513d0 100644 --- a/src/app.js +++ b/src/app.js @@ -52,10 +52,9 @@ io.on('connection', async (socket) => { console.log('User disconnected'); }); socket.on('chat message', async (msg, room, tag, iv, nonce) => { - const roomid = room.substring(5); - const members = await database.getRoomMembers(roomid); + const members = await database.getRoomMembers(room); members.forEach(memberRoom => { - socket.to(memberRoom).emit('chat message', msg, roomid, tag, iv, nonce, session.publicKey); + socket.to(memberRoom).emit('chat message', msg, room, tag, iv, nonce, session.publicKey); }); console.log('message: ' + msg + ', sender: ' + session.id); console.log(session.publicKey); diff --git a/src/public/arrayutils.js b/src/public/arrayutils.js index 574e18c..9452144 100644 --- a/src/public/arrayutils.js +++ b/src/public/arrayutils.js @@ -19,4 +19,37 @@ function splitIntoChunks(data) { return chunks; } -export { concatUint8Arrays, splitIntoChunks }; +/* +Convert an ArrayBuffer into a string +from https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String +*/ +function ab2str(buf) { + return String.fromCharCode.apply(null, new Uint8Array(buf)); +} + +/* +Convert a string into an ArrayBuffer +from https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String +*/ +function str2ab(str) { + const buf = new ArrayBuffer(str.length); + const bufView = new Uint8Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; +} + +function generateRandomUint8Array(length = 16) { + const randomArray = new Uint8Array(length); + window.crypto.getRandomValues(randomArray); + return randomArray; +} + +const fromHexString = (hexString) => + Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))); + +const toHexString = (bytes) => + bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), ''); + +export { concatUint8Arrays, splitIntoChunks, ab2str, str2ab, fromHexString, toHexString, generateRandomUint8Array }; diff --git a/src/public/chat.js b/src/public/chat.js index 26bf244..73ad527 100644 --- a/src/public/chat.js +++ b/src/public/chat.js @@ -2,6 +2,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"; +import { fromHexString, toHexString, generateRandomUint8Array } from "./arrayutils.js"; const socket = io(); let secret = null; @@ -9,13 +10,15 @@ let sharedsecret = {}; let dh_ratchets = {}; let sending_ratchets = {}; let receiving_ratchets = {}; +let messages_exchanged = {}; +const max_messages_number = 5; 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)); - let key_2 = dh_ratchet.next(new Uint8Array(0)); + let key_2 = dh_ratchet.next(); dh_ratchets[user_pubkey] = dh_ratchet; let sending_ratchet = new keccakKDF(); let receiving_ratchet = new keccakKDF(); @@ -31,7 +34,7 @@ function init_ratchets(order, user_pubkey) { } sending_ratchets[user_pubkey] = sending_ratchet; receiving_ratchets[user_pubkey] = receiving_ratchet; - + messages_exchanged[user_pubkey] = 0; } socket.on('chat message', (msg, room, tag_received, iv, nonce, pubkey_received) => { @@ -55,6 +58,10 @@ socket.on('chat message', (msg, room, tag_received, iv, nonce, pubkey_received) }); socket.on('key exchange', (user_pubkey, pubkey, part) => { + key_exchange(user_pubkey, pubkey, part); +}); + +function key_exchange(user_pubkey, pubkey, part) { let keys = null; switch (part) { case 0: @@ -76,7 +83,14 @@ socket.on('key exchange', (user_pubkey, pubkey, part) => { init_ratchets(1, user_pubkey); break; } -}); +} + +function reset_ratchets(user_pubkey) { + if (messages_exchanged[user_pubkey] >= max_messages_number) { + key_exchange(user_pubkey, null, 0); + messages_exchanged[user_pubkey] = 0; + } +} export function create_listener(form, input, messages) { form.addEventListener('submit', function(e) { @@ -86,8 +100,10 @@ export function create_listener(form, input, 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); - socket.emit('chat message', cipher, form.id, tag, iv, nonce); + socket.emit('chat message', cipher, form.id.substring(5), tag, iv, nonce); input.value = ''; + messages_exchanged[pubkey] += 1; + reset_ratchets(pubkey); } }); } @@ -115,12 +131,6 @@ function decrypt_message(cipher, user_pubkey, iv, nonce, associated_data) { }; } -function generateRandomUint8Array(length = 16) { - const randomArray = new Uint8Array(length); - window.crypto.getRandomValues(randomArray); - return randomArray; -} - function append_message(type, text, messageUl) { const item = document.createElement('li'); const bubble = document.createElement('div'); @@ -143,12 +153,6 @@ function append_message(type, text, messageUl) { messageUl.appendChild(item); } -const fromHexString = (hexString) => - Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))); - -const toHexString = (bytes) => - bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), ''); - export async function reconnectSocket() { socket.disconnect(); console.log("Socket disconnected."); diff --git a/src/public/ecc.js b/src/public/ecc.js index b2bd6d6..569cfe2 100644 --- a/src/public/ecc.js +++ b/src/public/ecc.js @@ -1,23 +1,4 @@ -/* -Convert an ArrayBuffer into a string -from https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String -*/ -export function ab2str(buf) { - return String.fromCharCode.apply(null, new Uint8Array(buf)); -} - -/* -Convert a string into an ArrayBuffer -from https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String -*/ -export function str2ab(str) { - const buf = new ArrayBuffer(str.length); - const bufView = new Uint8Array(buf); - for (let i = 0, strLen = str.length; i < strLen; i++) { - bufView[i] = str.charCodeAt(i); - } - return buf; -} +import {ab2str, str2ab} from './arrayutils.js'; export function exportedKeyToPem(key, type) { let exportedAsString = ab2str(key); diff --git a/src/public/register.js b/src/public/register.js index 9c49de2..bb75dfa 100644 --- a/src/public/register.js +++ b/src/public/register.js @@ -1,5 +1,5 @@ - -import { ab2str, exportedKeyToPem, pemToKey, genKey } from "./ecc.js"; +import { exportedKeyToPem, pemToKey, genKey } from "./ecc.js"; +import { ab2str } from "./arrayutils.js" import { add_div_register_text } from "./registertext.js"; export async function registerConfirm() { diff --git a/src/views/index.pug b/src/views/index.pug index 928fcd1..84e1ab1 100644 --- a/src/views/index.pug +++ b/src/views/index.pug @@ -7,17 +7,12 @@ html(lang="en-US") link(rel="stylesheet" href="/style.css") script(src="/socket.io/socket.io.js", defer) script(src="/script.js", defer) - script(type="module", src="/ecc.js", defer) if isLoggedIn - script(type="module", src="/chat.js", defer) - script(src="/pubkey.js", defer) script(src="/noble-curves.js", defer) - script(type="module", src="/rooms.js", defer) - script(type="module", src="/ecdh.js", defer) + script(src="/pubkey.js", defer) script(type="module", src="/popups-logged.js", defer) - script(type="module", src="/keccak.js", defer) - script(type="module", src="/aead.js", defer) - script(type="module", src="/kdf.js", defer) + script(type="module", src="/rooms.js", defer) + script(type="module", src="/chat.js", defer) else script(type="module", src="/popups.js", defer) script(type="module", src="/register.js", defer) diff --git a/tests/ecc.test.js b/tests/ecc.test.js index 7072dc4..c69951b 100644 --- a/tests/ecc.test.js +++ b/tests/ecc.test.js @@ -1,4 +1,5 @@ -import { ab2str, str2ab, exportedKeyToPem, pemToKey, genKey } from '../src/public/ecc.js'; +import { exportedKeyToPem, pemToKey, genKey } from '../src/public/ecc.js'; +import { ab2str, str2ab } from '../src/public/arrayutils.js'; describe('ecc.js functions', () => {