diff --git a/wco/crypto/crypto.js b/wco/crypto/crypto.js index cd533c6..bf68e74 100644 --- a/wco/crypto/crypto.js +++ b/wco/crypto/crypto.js @@ -3,72 +3,74 @@ var apx = apx || {}; apx.crypto = apx.crypto || {}; apx.crypto.genKey = async (uuid) => { - return await openpgp.generateKey({ - type: "ecc", - curve: "curve25519", - userIDs: [ - { - alias: uuid, - }, - ], - passphrase: "", - format: "armored", - }); + return await openpgp.generateKey({ + type: "ecc", + curve: "curve25519", + userIDs: [ + { + alias: uuid, + }, + ], + passphrase: "", + format: "armored", + }); }; apx.crypto.encryptMessage = async (message, publicKey) => { - publicKey = await openpgp.readKey({ - armoredKey: publicKey, - }); + publicKey = await openpgp.readKey({ + armoredKey: publicKey, + }); - return await openpgp.encrypt({ - message: await openpgp.createMessage({ - text: message, - }), - encryptionKeys: publicKey, - }); + return await openpgp.encrypt({ + message: await openpgp.createMessage({ + text: message, + }), + encryptionKeys: publicKey, + }); }; apx.crypto.decryptMessage = async (encryptedMessage, privateKey) => { - privateKey = await openpgp.readPrivateKey({ - armoredKey: privateKey, - }); + privateKey = await openpgp.readPrivateKey({ + armoredKey: privateKey, + }); - const message = await openpgp.readMessage({ - armoredMessage: encryptedMessage, - }); + const message = await openpgp.readMessage({ + armoredMessage: encryptedMessage, + }); - return await openpgp.decrypt({ - message, - decryptionKeys: privateKey, - }); + return await openpgp.decrypt({ + message, + decryptionKeys: privateKey, + }); }; + apx.crypto.isSignedby = async ( - alias, - publicKey, - detachedSignature, - message + alias, + publicKey, + detachedSignature, + message ) => { - const publickey = await openpgp.readKey({ armoredKey: publicKey }); - const msg = await openpgp.createMessage({ text: message }); - const signature = await openpgp.readSignature({ - armoredSignature: atob(detachedSignature), // parse detached signature - }); - const verificationResult = await openpgp.verify({ - msg, // Message object - signature, - verificationKeys: publickey, - }); - const { verified, keyID } = verificationResult.signatures[0]; - try { - await verified; // throws on invalid signature - //console.log("Signed by key id " + keyID.toHex()); - return KeyId.toHex().alias == alias; - } catch (e) { - console.log("Signature could not be verified: " + e.message); - return false; - } + const publickey = await openpgp.readKey({ armoredKey: publicKey }); + const msg = await openpgp.createMessage({ text: message }); + const signature = await openpgp.readSignature({ + armoredSignature: atob(detachedSignature), // parse detached signature + }); + const verificationResult = await openpgp.verify({ + msg, // Message object + signature, + verificationKeys: publickey, + }); + const { verified, keyID } = verificationResult.signatures[0]; + try { + await verified; // throws on invalid signature + //console.log("Signed by key id " + keyID.toHex()); + return KeyId.toHex().alias == alias; + } catch (e) { + console.log("Signature could not be verified: " + e.message); + return false; + } }; + apx.crypto.sign = async (message, privateKey) => { privateKey = await openpgp.readPrivateKey( { @@ -118,4 +120,19 @@ apx.crypto.verifySignature = async (message, signature, publicKey) => { }; }; -export default apx; +apx.crypto.genUUID = () => { + const uuidTemplate = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"; + return uuidTemplate.replace(/[xy]/g, (char) => { + const random = Math.random() * 16 | 0; + + let value; + + if (char === "x") { + value = random; + } else { + value = (random & 0x3) | 0x8; + }; + + return value.toString(16); + }); +}; \ No newline at end of file diff --git a/wco/privatri/privatri.js b/wco/privatri/privatri.js index b001e84..411837e 100644 --- a/wco/privatri/privatri.js +++ b/wco/privatri/privatri.js @@ -14,8 +14,10 @@ apx.privatri.loadwco = async (id, dataObj = {}, ctx = null) => { ctx )}` ); - - const template = JSON.parse(localStorage.getItem("admin")).tpl[`privatri${id}`]; + + const templatesObj = JSON.parse(localStorage.getItem("admin")).tpl; + + const template = Object.entries(templatesObj).find(([key]) => key.toLowerCase() === `privatri${id}`.toLocaleLowerCase())?.[1]; return Mustache.render(template, dataObj); }; @@ -42,11 +44,11 @@ apx.privatri.templates.scripts = { document.querySelector("#createThreadBtn").addEventListener("click", async () => { const { publicKey, privateKey } = await apx.crypto.genKey(); - + const messageObj = await (async (publicKey) => { - const uuid = crypto.randomUUID(); + const uuid = apx.crypto.genUUID(); const timestamp = Date.now(); - const alias = await apx.crypto.encryptMessage(JSON.parse(localStorage.getItem("apx")).data.headers.xalias, publicKey); + const alias = await apx.crypto.encryptMessage(JSON.parse(localStorage.getItem("admin")).headers.xalias, publicKey); return { privatriid: `${uuid}_${timestamp}`, @@ -153,7 +155,7 @@ apx.privatri.templates.scripts = { document.querySelectorAll("button.removeAliasBtn").forEach(btn => { btn.addEventListener("click", async () => { - if (JSON.parse(localStorage.getItem("apx")).data.headers.xalias === (await apx.crypto.decryptMessage(ownerAlias, privateKey)).data) { + if (JSON.parse(localStorage.getItem("admin")).headers.xalias === (await apx.crypto.decryptMessage(ownerAlias, privateKey)).data) { if (btn.getAttribute("data-alias") !== ownerAlias) { const alias = btn.getAttribute("data-alias"); aliasesArray = aliasesArray.filter(a => a !== alias); @@ -222,7 +224,7 @@ apx.privatri.templates.scripts = { }); applyModificationsBtnEl.addEventListener("click", async () => { - if (JSON.parse(localStorage.getItem("apx")).data.headers.xalias === (await apx.crypto.decryptMessage(ownerAlias, privateKey)).data) { + if (JSON.parse(localStorage.getItem("admin")).headers.xalias === (await apx.crypto.decryptMessage(ownerAlias, privateKey)).data) { messageObj.title = await apx.crypto.encryptMessage(threadNameInputEl.value, privateKey); messageObj.dt_autodestruction = (() => { const selectedBtn = Array.from(autoDeletionBtnElArray).find(btn => btn.classList.contains("bg-base-200")); @@ -253,9 +255,26 @@ async function getOldestPrivatriids(dbName, storeName) { return new Promise((resolve, reject) => { const request = indexedDB.open(dbName, 1); + request.onupgradeneeded = (event) => { + const db = event.target.result; + + if (!db.objectStoreNames.contains("threads")) { + db.createObjectStore("threads", { keyPath: "uuid" }); + }; + + if (!db.objectStoreNames.contains("messages")) { + db.createObjectStore("messages", { keyPath: "privatriid" }); + }; + }; + request.onsuccess = (event) => { const db = event.target.result; + if (!db.objectStoreNames.contains(storeName)) { + resolve([]); + return; + }; + const transaction = db.transaction(storeName, "readonly"); const store = transaction.objectStore(storeName); const cursorRequest = store.openCursor(); @@ -288,10 +307,18 @@ async function getOldestPrivatriids(dbName, storeName) { }; apx.ready(async () => { - await (async () => { - console.log("ok") - document.querySelector("body").innerHTML = await apx.privatri.loadwco("main"); + document.querySelector("body").innerHTML = await apx.privatri.loadwco("main", JSON.parse(localStorage.getItem("admin")).tpldata.privatri_main_privatri); + const bodyEl = document.querySelector("body"); + const searchInputEl = document.querySelector("#threadSearchBar"); + const threadFilterOptionsElArray = document.querySelector("#threadFilterOptions").querySelectorAll("li"); + const threadsContainerEl = document.querySelector("#threadsContainer"); + const threadPageEl = document.querySelector("#threadPage"); + const messageInputEl = document.getElementById("messageInput"); + const messagesContainerEl = document.querySelector("#messagesContainer"); + const attachmentsInputEl = document.querySelector("#attachmentsInput"); + + await (async () => { const lastConnection = JSON.parse(localStorage.getItem("lastConnection")) || Date.now(); await apx.privatri.syncronizeBackend(apx.data.headers.xalias, lastConnection); @@ -299,7 +326,7 @@ apx.ready(async () => { const privatriidArray = await getOldestPrivatriids("privatri", "messages"); const thread = async (name, uuid) => { - return await apx.privatri.loadwco("threadAliasList", { uuid, name }); + return await apx.privatri.loadwco("thread", { uuid, name }); }; for (const privatriid of privatriidArray) { @@ -386,11 +413,13 @@ apx.ready(async () => { }; }); }); - + + threadsContainerEl.children[0]?.click(); + document.querySelectorAll("a").forEach(link => { link.addEventListener("click", async (event) => { event.preventDefault(); - + window.history.replaceState({}, document.title, window.location.pathname); const templateName = link.getAttribute("data-template"); @@ -399,22 +428,13 @@ apx.ready(async () => { window.history.pushState({}, "", `${window.location.pathname}?uuid=${threadPageEl.getAttribute("data-uuid")}`); }; - bodyEl.firstElementChild.innerHTML = await apx.privatri.loadwco(templateName); + bodyEl.innerHTML = await apx.privatri.loadwco(templateName); await apx.privatri.templates.scripts[templateName](); }); }); })(); - const bodyEl = document.querySelector("body"); - const searchInputEl = document.querySelector("#threadSearchBar"); - const threadFilterOptionsElArray = document.querySelector("#threadFilterOptions").querySelectorAll("li"); - const threadsContainerEl = document.querySelector("#threadsContainer"); - const threadPageEl = document.querySelector("#threadPage"); - const messageInputEl = document.getElementById("messageInput"); - const messagesContainerEl = document.querySelector("#messagesContainer"); - const attachmentsInputEl = document.querySelector("#attachmentsInput"); - function formatDate(timestamp) { const date = new Date(timestamp); const day = String(date.getDate()).padStart(2, "0"); @@ -486,7 +506,7 @@ apx.ready(async () => { if (message !== "") { const messageObj = await (async (publicKey) => { const timestamp = Date.now(); - const alias = await apx.crypto.encryptMessage(JSON.parse(localStorage.getItem("apx")).data.headers.xalias, publicKey); + const alias = await apx.crypto.encryptMessage(JSON.parse(localStorage.getItem("admin")).headers.xalias, publicKey); return { privatriid: `${threadPageEl.getAttribute("data-uuid")}_${timestamp}`, @@ -538,28 +558,28 @@ apx.ready(async () => { const privateKey = (await apx.indexedDB.get("privatri", "threads", threadPageEl.getAttribute("data-uuid"))).privateKey; - const signatureMessage = `${JSON.parse(localStorage.getItem("apx")).data.headers.xalias}_${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`; + const signatureMessage = `${JSON.parse(localStorage.getItem("admin")).headers.xalias}_${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`; const signature = await apx.crypto.sign(signatureMessage, privateKey); let verified = false; - try { - verified = await fetch("", { - method: "GET", - body: JSON.stringify({ - message: signatureMessage, - signature: signature, - uuid: threadPageEl.getAttribute("data-uuid"), - timestamp: messageEl.getAttribute("data-timestamp"), - }) - }); - } catch (error) { - console.error("Error while verifying signature:", error); - }; + // try { + // verified = await fetch("", { + // method: "GET", + // body: JSON.stringify({ + // message: signatureMessage, + // signature: signature, + // uuid: threadPageEl.getAttribute("data-uuid"), + // timestamp: messageEl.getAttribute("data-timestamp"), + // }) + // }); + // } catch (error) { + // console.error("Error while verifying signature:", error); + // }; - const authorAlias = await apx.crypto.decryptMessage((await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`)).sender_alias, privateKey).data; + const authorAlias = (await apx.crypto.decryptMessage((await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`)).sender_alias, privateKey)).data; - if ((JSON.parse(localStorage.getItem("apx")).data.headers.xalias === authorAlias) && (verified === true)) { + if ((JSON.parse(localStorage.getItem("admin")).headers.xalias === authorAlias) && (verified === true)) { await apx.indexedDB.del("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`); messageEl.remove(); @@ -577,7 +597,7 @@ apx.ready(async () => { const authorAlias = (await apx.crypto.decryptMessage((await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`)).sender_alias, (await apx.indexedDB.get("privatri", "threads", threadPageEl.getAttribute("data-uuid"))).privateKey)).data; - if (JSON.parse(localStorage.getItem("apx")).data.headers.xalias === authorAlias) { + if (JSON.parse(localStorage.getItem("admin")).headers.xalias === authorAlias) { const messageValue = messageEl.querySelector("div.message").innerText; const attachmentsArray = (() => { diff --git a/wwws/admin/src/privatri_fr.html b/wwws/admin/src/privatri_fr.html index 9b2ebad..691a14b 100644 --- a/wwws/admin/src/privatri_fr.html +++ b/wwws/admin/src/privatri_fr.html @@ -43,8 +43,9 @@ - + +