console.log(window.location.protocol); var url = `${window.location.protocol}//${window.location.hostname}/_larpix`; var params = new URLSearchParams(window.location.search); const collapseDmsBtn = document.getElementById("collapse-dms"); const collapseGroupsBtn = document.getElementById("collapse-groups"); const addDmBtn = document.getElementById("add-dm-btn"); const addGroupBtn = document.getElementById("add-group-btn"); const sidebarHome = document.getElementById("sidebar-home"); const sidebarHomeButton = sidebarHome.children.item(1); const sidebarHomeIndicator = sidebarHome.children.item(0); const sidebarAdd = document.getElementById("sidebar-add"); const sidebarAddButton = sidebarAdd.children.item(1); const sidebarAddIndicator = sidebarAdd.children.item(0); const roomDetailsBar = document.getElementById("roomdetailsbar"); const roomContent = document.getElementsByTagName("roomcontent")[0]; const roomsBar = document.getElementById("roomsbar"); const sideBar = document.getElementsByTagName("sidebar")[0]; const roomContentMain = document.getElementsByTagName("roomcontent2")[0]; const roomContentBar = roomContent.children[0]; function delay(time) { return new Promise(resolve => setTimeout(resolve, time)); } async function packetEncPass(pass, key, username) { return await encryptWithNonce(pass, key, getNonce(username, key)); } async function getNonce(username, key) { let nonce; let fetchRes = await (await fetch(`${url}/nextnonce?u=${username}`)).text(); try { nonce = await decryptString(fetchRes, key); } catch(err) { nonce = await decryptString(fetchRes, ""); } return nonce; } async function encryptWithNonce(value, key, nonce) { return await encryptString(value, nonce + key); } async function calcCommunicationKeyClient(p, g, pubServer) { const secretClientBytes = window.crypto.getRandomValues(new Uint8Array(512)); const secretClient = BigInt('0x' + Array.from(secretClientBytes).map(b => b.toString(16).padStart(2, '0')).join('')); const pubClient = power(BigInt(g), secretClient, BigInt(p)); const sharedSecret = power(BigInt(pubServer), secretClient, BigInt(p)); let sharedSecretStr = sharedSecret.toString(16); if (sharedSecretStr.length % 2 !== 0) { sharedSecretStr = '0' + sharedSecretStr; } const sharedSecretBytes = new Uint8Array(sharedSecretStr.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); const hashBuffer = await window.crypto.subtle.digest('SHA-256', sharedSecretBytes); const aesKey = new Uint8Array(hashBuffer); return [pubClient.toString(), aesKey]; } function keyDataFromServerJson(jsonFromServer) { const data = JSON.parse(jsonFromServer); const p = BigInt(data.p); const g = BigInt(data.g); const pubServer = BigInt(data.pubServer); return [p, g, pubServer, data.idKey] } function base64ToUint8(base64) { return Uint8Array.from(atob(base64), c => c.charCodeAt(0)); } function uint8ToBase64(uint8) { return fixBase64Padding(btoa(String.fromCharCode(...uint8))); } async function encrypt(plainText, keyBytes) { const iv = window.crypto.getRandomValues(new Uint8Array(16)); const encoder = new TextEncoder(); const data = encoder.encode(plainText); const cryptoKey = await window.crypto.subtle.importKey( "raw", keyBytes, "AES-CBC", false, ["encrypt"] ); const encryptedContent = await window.crypto.subtle.encrypt( {name: "AES-CBC", iv: iv}, cryptoKey, data ); const result = new Uint8Array(iv.length + encryptedContent.byteLength); result.set(iv); result.set(new Uint8Array(encryptedContent), iv.length); return uint8ToBase64(result); } async function decrypt(cipherTextBase64, keyBytes) { const fullData = base64ToUint8(cipherTextBase64); const iv = fullData.slice(0, 16); const cipherData = fullData.slice(16); const cryptoKey = await window.crypto.subtle.importKey( "raw", keyBytes, "AES-CBC", false, ["decrypt"] ); const decrypted = await window.crypto.subtle.decrypt( {name: "AES-CBC", iv: iv}, cryptoKey, cipherData ); return new TextDecoder().decode(decrypted); } async function getCryptoKey(passphrase) { const encoder = new TextEncoder(); const data = encoder.encode(passphrase); const hash = await crypto.subtle.digest('SHA-256', data); return await crypto.subtle.importKey('raw', hash, {name: 'AES-CBC'}, false, ['encrypt', 'decrypt']); } async function encryptBytes(plainBytes, passphrase) { const key = await getCryptoKey(passphrase); const iv = crypto.getRandomValues(new Uint8Array(16)); const encryptedContent = await crypto.subtle.encrypt( {name: 'AES-CBC', iv: iv}, key, plainBytes ); const result = new Uint8Array(iv.length + encryptedContent.byteLength); result.set(iv); result.set(new Uint8Array(encryptedContent), iv.length); return result; } async function decryptBytes(combinedBytes, passphrase) { const key = await getCryptoKey(passphrase); const iv = combinedBytes.slice(0, 16); const data = combinedBytes.slice(16); const decryptedContent = await crypto.subtle.decrypt( {name: 'AES-CBC', iv: iv}, key, data ); return new Uint8Array(decryptedContent); } async function encryptString(plainText, passphrase) { const encoder = new TextEncoder(); const data = encoder.encode(plainText); const pwHash = await crypto.subtle.digest('SHA-256', encoder.encode(passphrase)); const key = await crypto.subtle.importKey( 'raw', pwHash, {name: 'AES-CBC'}, false, ['encrypt'] ); const iv = crypto.getRandomValues(new Uint8Array(16)); const encrypted = await crypto.subtle.encrypt( {name: 'AES-CBC', iv: iv}, key, data ); const combined = new Uint8Array(iv.length + encrypted.byteLength); combined.set(iv); combined.set(new Uint8Array(encrypted), iv.length); return fixBase64Padding(btoa(String.fromCharCode(...combined))); } async function decryptString(base64Text, passphrase) { const encoder = new TextEncoder(); const combined = new Uint8Array(atob(base64Text).split("").map(c => c.charCodeAt(0))); const pwHash = await crypto.subtle.digest('SHA-256', encoder.encode(passphrase)); const key = await crypto.subtle.importKey( 'raw', pwHash, {name: 'AES-CBC'}, false, ['decrypt'] ); const iv = combined.slice(0, 16); const data = combined.slice(16); const decrypted = await crypto.subtle.decrypt( {name: 'AES-CBC', iv: iv}, key, data ); return new TextDecoder().decode(decrypted); } async function fetchPost(url, value) { let response = await fetch(url, { method: "POST", credentials: "omit", body: value, headers: { "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash)) } }); let data = await response.text(); return data; } async function fetchPostEnc(url, value) { let nonce = await getNonce(username, passwordHash); let response = await fetch(url, { method: "POST", credentials: "omit", body: await encryptWithNonce(value, passwordHash, nonce), headers: { "secret": await encryptWithNonce(passwordHash, passwordHash, nonce) } }); let data = await response.text(); return data; } async function fetchAsync(url) { let response = await fetch(url, { method: "GET", credentials: "omit" }); let data = await response.text(); return data; } async function fetchAsyncWAuth(url) { let response = await fetch(url, { method: "GET", credentials: "omit", headers: { "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash)) } }); let data = await response.text(); return data; } async function getServerInfo(host){ console.log(`${window.location.protocol}//${host}/_larpix/serverinfo`) return JSON.parse(await fetchAsync(`${window.location.protocol}//${host}/_larpix/serverinfo`)); } async function Auth(username, password) { let passwordHash = await hashSHA3_512(password); let response = await fetch(`${url}/auth?u=${username}`, { method: "GET", credentials: "omit", headers: { "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash)) } }); let data = await response.text(); return data; } async function fetchEncrypted(request, body) { let nonce = await getNonce(username, passwordHash); let response = await fetch(`${url}/encryptedrequest?u=${username}`, { method: "POST", credentials: "omit", body: await encryptWithNonce( JSON.stringify({ string1: request, string2: body }) , passwordHash, nonce), headers: { "secret": await encryptWithNonce(passwordHash, passwordHash, nonce) } }); let data = await response.text(); return decryptString(data, passwordHash); } function power(base, exponent, mod) { let res = 1n; base = base % mod; while (exponent > 0n) { if (exponent % 2n === 1n) res = (res * base) % mod; base = (base * base) % mod; exponent = exponent / 2n; } return res; } function fixBase64Padding(base64String) { let str = base64String.replace(/-/g, '+').replace(/_/g, '/'); const pad = str.length % 4; if (pad) { if (pad === 1) { throw new Error(""); } str += '='.repeat(4 - pad); } return str; } function showNotification(message, type = 'info', duration = 3500) { let container = document.getElementById('notification-container'); if (!container) { container = document.createElement('div'); container.id = 'notification-container'; document.body.appendChild(container); } const notif = document.createElement('div'); notif.className = `notification ${type}`; notif.textContent = message; container.appendChild(notif); requestAnimationFrame(() => { requestAnimationFrame(() => { notif.classList.add('show'); }); }); setTimeout(() => { notif.classList.remove('show'); notif.addEventListener('transitionend', () => { notif.remove(); }); }, duration); } function showAction(message, actionid) { let container = document.getElementById('notification-container'); if (!container) { container = document.createElement('div'); container.id = 'notification-container'; document.body.appendChild(container); } const notif = document.createElement('div'); notif.className = `notification action`; notif.textContent = message; notif.id = `notification-${actionid}`; container.appendChild(notif); requestAnimationFrame(() => { requestAnimationFrame(() => { notif.classList.add('show'); }); }); } function clearAction(actionid) { let notif = document.getElementById(`notification-${actionid}`); notif.classList.remove('show'); notif.addEventListener('transitionend', () => { notif.remove(); }); } async function hashSHA3_512(input) { const encoder = new TextEncoder(); const data = encoder.encode(input); const hashBuffer = await crypto.subtle.digest('SHA-512', data); //-3 kiedys xddddddddddddddddd const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); return hashHex; } var password = ""; var username = ""; var passwordHash = ""; var host = ""; async function mainJS() { username = localStorage.getItem('username'); password = localStorage.getItem('password'); host = localStorage.getItem('host'); passwordHash = await hashSHA3_512(password); url = `${window.location.protocol}//${host}/_larpix`; } mainJS(); collapseDmsBtn.addEventListener("click", () => { collapseDmsBtn.classList.toggle("collapsed"); }); collapseGroupsBtn.addEventListener("click", () => { collapseGroupsBtn.classList.toggle("collapsed"); }); addDmBtn.addEventListener("click", () => { roomContentMain.innerHTML = `
Add a private, encrypted chat by entering a username