+
+
+
\ No newline at end of file
diff --git a/wco/privatri/privatri.js b/wco/privatri/privatri.js
index f1d28b5..a7baf37 100644
--- a/wco/privatri/privatri.js
+++ b/wco/privatri/privatri.js
@@ -1,506 +1,25 @@
-import apx from "./apx.js";
-import { getOldestPrivatriids, syncronizeBackend } from "./utils.js";
-
-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");
- const month = String(date.getMonth() + 1).padStart(2, "0");
- const year = date.getFullYear();
- const hours = String(date.getHours()).padStart(2, "0");
- const minutes = String(date.getMinutes()).padStart(2, "0");
-
- return `${day}/${month}/${year} ${hours}:${minutes}`;
-};
-
-searchInputEl.addEventListener("input", () => {
- const value = searchInputEl.value.toLowerCase();
-
- Array.from(threadsContainerEl.children).forEach(child => {
- if (child.querySelector("li > div").textContent.toLowerCase().includes(value)) {
- child.style.display = "block";
- } else {
- child.style.display = "none";
- };
- });
-});
-
-threadFilterOptionsElArray.forEach(option => {
- option.addEventListener("click", async () => {
- const filter = option.getAttribute("data-filter");
-
- if (filter === "date") {
- Array.from(threadsContainerEl.children).sort((a, b) => {
- return a.querySelector("li > span").getAttribute("data-timestamp") - b.querySelector("li > span").getAttribute("data-timestamp");
- }).forEach(child => {
- threadsContainerEl.appendChild(child);
- });
- } else if (filter === "name") {
- Array.from(threadsContainerEl.children).sort((a, b) => {
- return a.querySelector("li > div").textContent.localeCompare(b.querySelector("li > div").textContent);
- }).forEach(child => {
- threadsContainerEl.appendChild(child);
- });
- };
- });
-});
-
-const sendNewMessage = async (timestamp, message, attachmentsArray) => {
- let messageTemplate = "";
-
- await fetch("./message.mustache")
- .then(res => res.text())
- .then(template => {
- messageTemplate = template;
- });
-
- messageTemplate = Mustache.render(messageTemplate, { timestamp, message, date: formatDate(timestamp) });
-
- const tempNode = document.createElement("div");
- tempNode.innerHTML = messageTemplate;
- const messageNode = tempNode.firstElementChild;
-
- attachmentsArray.forEach(attachment => {
- messageNode.querySelector("div.attachmentsContainer").insertAdjacentHTML("beforeend", `

`);
- });
-
- return messageNode.outerHTML;
-};
-
-const editMessage = async (timestamp, message) => {
- let editMessageTemplate = "";
-
- await fetch("./editMessage.mustache")
- .then(res => res.text())
- .then(template => {
- editMessageTemplate = template;
- });
-
- return Mustache.render(editMessageTemplate, { message, date: formatDate(timestamp) });
-};
-
-const displayToastAlert = async (message) => {
- let toastAlertTemplate = "";
-
- await fetch("./toastAlert.mustache")
- .then(res => res.text())
- .then(template => {
- toastAlertTemplate = template;
- });
-
- return Mustache.render(toastAlertTemplate, { message });
-};
-
-sendMessageBtn.addEventListener("click", async () => {
- const message = messageInputEl.value.trim();
-
- 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);
-
- return {
- privatriid: `${threadPageEl.getAttribute("data-uuid")}_${timestamp}`,
- timestamp: timestamp,
- sender_alias: alias,
- message: await apx.crypto.encryptMessage(message, publicKey),
- attachments: await (async () => {
- const attachmentsArray = [];
- const localAttachmentsArray = JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`)) || [];
-
- if (localAttachmentsArray.length > 0) {
- for (const attachment of localAttachmentsArray) {
- attachmentsArray.push(
- {
- fileType: attachment.fileType,
- filename: attachment.filename,
- content: await apx.crypto.encryptMessage(attachment.content, publicKey)
- }
- );
- };
- };
-
- return attachmentsArray;
- })()
- };
- })((await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messagesContainerEl.firstElementChild.getAttribute("data-timestamp")}`)).publicKey);
-
- const newMessageHTML = await sendNewMessage(messageObj.timestamp, message, JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`)) || []);
-
- sessionStorage.removeItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`);
-
- messagesContainerEl.insertAdjacentHTML("beforeend", newMessageHTML);
-
- messageInputEl.value = "";
-
- // Faire un post sur l'endpoint /privatri
-
- await apx.indexedDB.set("privatri", "messages", messageObj);
- };
-});
-
-document.addEventListener("DOMContentLoaded", async () => {
- const lastConnection = JSON.parse(localStorage.getItem("lastConnection")) || Date.now();
-
- await syncronizeBackend(lastConnection);
-
- const privatriidArray = await getOldestPrivatriids("privatri", "messages");
-
- const thread = async (name, uuid) => {
- let threadTemplate = "";
-
- await fetch("./thread.mustache")
- .then(res => res.text())
- .then(template => {
- threadTemplate = template;
- });
-
- return Mustache.render(threadTemplate, { uuid, name });
- };
-
- for (const privatriid of privatriidArray) {
- const obj = await apx.indexedDB.get("privatri", "messages", privatriid)
-
- const privateKey = (await apx.indexedDB.get("privatri", "threads", obj.thread)).privateKey;
- const name = (await apx.crypto.decryptMessage(obj.title, privateKey)).data;
-
- threadsContainerEl.insertAdjacentHTML("beforeend", await thread(name, obj.thread));
- };
-
- Array.from(threadsContainerEl.children).forEach(child => {
- child.addEventListener("click", async () => {
- const uuid = child.getAttribute("data-uuid");
-
- const messagesObj = await new Promise((resolve, reject) => {
- const request = indexedDB.open("privatri", 1);
-
- request.onsuccess = (event) => {
- const db = event.target.result;
-
- const transaction = db.transaction("messages", "readonly");
- const store = transaction.objectStore("messages");
- const cursorRequest = store.openCursor();
-
- const result = [];
- cursorRequest.onsuccess = (event) => {
- const cursor = event.target.result;
-
- if (cursor) {
- const obj = cursor.value;
- const keyUuid = obj.privatriid.split("_")[0];
-
- if (keyUuid === uuid) {
- result.push(obj);
- };
- cursor.continue();
- } else {
- resolve(result);
- };
- };
-
- cursorRequest.onerror = (event) => reject(event);
- };
-
- request.onerror = (event) => reject(event);
- });
-
- threadPageEl.setAttribute("data-uuid", uuid);
- threadPageEl.querySelector("#threadName").innerText = (await apx.crypto.decryptMessage(messagesObj[0].title, (await apx.indexedDB.get("privatri", "threads", uuid)).privateKey)).data;
-
- messagesContainerEl.innerHTML = "";
-
- let privateKey = "";
-
- for (const message of messagesObj) {
- if (privateKey === "") {
- privateKey = (await apx.indexedDB.get("privatri", "threads", message.thread)).privateKey;
- };
-
- const decryptedMessage = (await apx.crypto.decryptMessage(message.message, privateKey)).data;
-
- let decryptedAttachments = [];
-
- if (message.attachments !== undefined) {
- decryptedAttachments = await (async () => {
- const attachmentsArray = [];
-
- if (message.attachments.length > 0) {
- for (const attachment of message.attachments) {
- attachmentsArray.push({
- fileType: attachment.fileType,
- filename: attachment.filename,
- content: (await apx.crypto.decryptMessage(attachment.content, privateKey)).data
- });
- };
- };
-
- return attachmentsArray;
- })();
- };
-
- messagesContainerEl.insertAdjacentHTML("beforeend", await sendNewMessage(message.timestamp, decryptedMessage, decryptedAttachments));
- };
- });
- });
-
- 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");
-
- if (templateName === "threadAliasList" || templateName === "threadSettings") {
- window.history.pushState({}, "", `${window.location.pathname}?uuid=${threadPageEl.getAttribute("data-uuid")}`);
- };
-
- await fetch(`./${templateName}.mustache`)
- .then(res => res.text())
- .then(template => {
- template = Mustache.render(template, {});
-
- bodyEl.innerHTML = template;
- });
-
- const script = document.createElement("script");
-
- script.type = "module";
- script.src = `./${templateName}.js`;
-
- bodyEl.appendChild(script);
- });
- });
-});
-
-window.addEventListener("beforeunload", () => {
- if (apx)
- localStorage.setItem("lastConnection", JSON.stringify(Date.now()));
-});
-
-window.attachDeleteMessageEvent = async function attachDeleteMessageEvent(btn) {
- const messageEl = btn.parentElement.parentElement.parentElement;
-
- 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 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);
- };
-
- 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)) {
- await apx.indexedDB.del("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`);
-
- messageEl.remove();
- } else {
- bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to delete this message."));
-
- setTimeout(() => {
- bodyEl.lastElementChild.remove();
- }, 3000);
- };
-};
-
-window.attachEditMessageEvent = async function attachEditMessageEvent(btn) {
- const messageEl = btn.parentElement.parentElement.parentElement;
-
- 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) {
- const messageValue = messageEl.querySelector("div.message").innerText;
-
- const attachmentsArray = (() => {
- const attachmentsArray = [];
-
- messageEl.querySelector("div.attachmentsContainer").querySelectorAll("img").forEach(img => {
- attachmentsArray.push(
- {
- fileType: img.getAttribute("src").match(/^data:(.*);base64,/)[1],
- filename: img.getAttribute("alt"),
- content: img.getAttribute("src").split(",")[1]
- }
- );
- });
-
- return attachmentsArray;
- })();
-
- messageEl.innerHTML = await editMessage(parseInt(messageEl.getAttribute("data-timestamp"), 10), messageEl.querySelector("div.message").innerText);
-
- messageEl.querySelector("button.cancelEditBtn").addEventListener("click", async () => {
- const messageObj = await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`);
-
- messageEl.innerHTML = await sendNewMessage(messageObj.timestamp, messageValue, attachmentsArray);
- });
-
- messageEl.querySelector("button.saveEditBtn").addEventListener("click", async () => {
- const newMessageValue = messageEl.querySelector("textarea").value.trim();
-
- if (newMessageValue !== "") {
- const privateKey = (await apx.indexedDB.get("privatri", "threads", threadPageEl.getAttribute("data-uuid"))).privateKey;
-
- const messageObj = await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`);
-
- messageObj.message = await apx.crypto.encryptMessage(newMessageValue, privateKey),
-
- await apx.indexedDB.set("privatri", "messages", messageObj);
-
- messageEl.innerHTML = await sendNewMessage(messageObj.timestamp, newMessageValue, attachmentsArray);
- };
- });
- } else {
- bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to edit this message."));
-
- setTimeout(() => {
- bodyEl.lastElementChild.remove();
- }, 3000);
- };
-};
-
-window.attachEventDisplayAttachment = function(img) {
- let overlay = document.getElementById("imageOverlay");
-
- if (overlay === null) {
- overlay = document.createElement('div');
-
- overlay.id = "imageOverlay";
- overlay.style.position = "fixed";
- overlay.style.top = 0;
- overlay.style.left = 0;
- overlay.style.width = "100vw";
- overlay.style.height = "100vh";
- overlay.style.background = "rgba(0, 0, 0, 0.75)";
- overlay.style.display = "flex";
- overlay.style.alignItems = "center";
- overlay.style.justifyContent = "center";
- overlay.style.zIndex = 999;
-
- overlay.onclick = () => {
- overlay.remove();
- };
-
- document.body.appendChild(overlay);
- } else {
- overlay.innerHTML = "";
- overlay.style.display = "flex";
- };
-
- const fullScreenImage = document.createElement("img");
-
- fullScreenImage.src = img.src;
- fullScreenImage.alt = img.alt;
- fullScreenImage.style.maxWidth = "90vw";
- fullScreenImage.style.maxHeight = "90vh";
- overlay.appendChild(fullScreenImage);
-};
-
-document.querySelector("#attachmentsBtn").addEventListener("click", () => {
- attachmentsInputEl.click();
-});
-
-attachmentsInputEl.addEventListener("change", async () => {
- const filesArray = Array.from(attachmentsInputEl.files);
- const maxFileSize = 5 * 1024 * 1024;
- const maxSize = 512;
-
- for (const file of filesArray) {
- if (file.size <= maxFileSize) {
- const attachmentObj = await new Promise((resolve, reject) => {
- const attachmentObj = {
- fileType: file.type,
- filename: file.name,
- content: ""
- };
-
- const img = new Image();
-
- img.onload = () => {
- if (img.width > maxSize || img.height > maxSize) {
- let width = img.width;
- let height = img.height;
-
- if (width > maxSize) {
- height *= maxSize / width;
- width = maxSize;
- };
-
- if (height > maxSize) {
- width *= maxSize / height;
- height = maxSize;
- };
-
- const canvas = document.createElement("canvas");
- canvas.width = width;
- canvas.height = height;
-
- const ctx = canvas.getContext("2d");
-
- ctx.drawImage(img, 0, 0, width, height);
-
- canvas.toBlob(blob => {
- const reader = new FileReader();
-
- reader.onload = (event) => {
- attachmentObj.content = event.target.result.split(",")[1];
-
- resolve(attachmentObj);
- };
-
- reader.onerror = reject;
- reader.readAsDataURL(blob);
- }, "image/jpeg", 0.8);
- } else {
- const reader = new FileReader();
-
- reader.onload = (event) => {
- attachmentObj.content = event.target.result.split(",")[1];
-
- resolve(attachmentObj);
- };
-
- reader.onerror = reject;
- reader.readAsDataURL(file);
- };
- };
-
- img.onerror = reject;
- img.src = URL.createObjectURL(file);
-
- return attachmentObj;
- });
-
- if (sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`) === null) {
- sessionStorage.setItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`, JSON.stringify([attachmentObj]));
- } else {
- const attachmentsArray = JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`));
- attachmentsArray.push(attachmentObj);
-
- sessionStorage.setItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`, JSON.stringify(attachmentsArray));
- };
- };
- };
-});
\ No newline at end of file
+var apx = apx || {};
+apx.privatri = {};
+apx.privatri.loadwco = async (id, ctx) => {
+ // check if not authenticate, do nothing cause by default screensignin and wait authentification
+ // if authenticate, if url xhash then redirect if no url then change wco-link=screenmyworld
+ // if (dayjs(apx.data.headers.xdays).diff(dayjs(), "hours") >= 24) apx.apxauth.checkisauth();
+ //load main.mustache of the component
+ //when wco-xxx change it run this function
+ console.log(
+ `Load wconame:privatri apx.privatri.loadwco with id:${id} and ctx: ${JSON.stringify(
+ ctx
+ )}`
+ );
+ //refresh thread from BE
+ const threadlist = apx.privatri.getthread(apx.data.headers.xalias,1000000)
+ const tpldataname = `${apx.data.pagename}_${id}_privatri`;
+ const privatriid = document.getElementById(id);
+ privatriid.innerHTML = Mustache.render(apx.data.tpl.privatrimain, threadlist);
+
+}
+
+apx.privatri.getthread=async(alias,timestamp)=>{
+ //store in indexdb the thread
+ return true
+}
\ No newline at end of file
diff --git a/wco/privatri/alias.mustache b/wco/privatri_mathieu/alias.mustache
similarity index 100%
rename from wco/privatri/alias.mustache
rename to wco/privatri_mathieu/alias.mustache
diff --git a/wco/privatri/apx.js b/wco/privatri_mathieu/apx.js
similarity index 100%
rename from wco/privatri/apx.js
rename to wco/privatri_mathieu/apx.js
diff --git a/wco/privatri/assets/icon.png b/wco/privatri_mathieu/assets/icon.png
similarity index 100%
rename from wco/privatri/assets/icon.png
rename to wco/privatri_mathieu/assets/icon.png
diff --git a/wco/privatri/createThread.js b/wco/privatri_mathieu/createThread.js
similarity index 100%
rename from wco/privatri/createThread.js
rename to wco/privatri_mathieu/createThread.js
diff --git a/wco/privatri/createThread.mustache b/wco/privatri_mathieu/createThread.mustache
similarity index 100%
rename from wco/privatri/createThread.mustache
rename to wco/privatri_mathieu/createThread.mustache
diff --git a/wco/privatri/editMessage.mustache b/wco/privatri_mathieu/editMessage.mustache
similarity index 100%
rename from wco/privatri/editMessage.mustache
rename to wco/privatri_mathieu/editMessage.mustache
diff --git a/wco/privatri/inviteAlias.js b/wco/privatri_mathieu/inviteAlias.js
similarity index 100%
rename from wco/privatri/inviteAlias.js
rename to wco/privatri_mathieu/inviteAlias.js
diff --git a/wco/privatri/inviteAlias.mustache b/wco/privatri_mathieu/inviteAlias.mustache
similarity index 100%
rename from wco/privatri/inviteAlias.mustache
rename to wco/privatri_mathieu/inviteAlias.mustache
diff --git a/wco/privatri/main_fr.html b/wco/privatri_mathieu/main_fr.html
similarity index 100%
rename from wco/privatri/main_fr.html
rename to wco/privatri_mathieu/main_fr.html
diff --git a/wco/privatri/main_fr.mustache b/wco/privatri_mathieu/main_fr.mustache
similarity index 100%
rename from wco/privatri/main_fr.mustache
rename to wco/privatri_mathieu/main_fr.mustache
diff --git a/wco/privatri/message.mustache b/wco/privatri_mathieu/message.mustache
similarity index 100%
rename from wco/privatri/message.mustache
rename to wco/privatri_mathieu/message.mustache
diff --git a/wco/privatri/output.css b/wco/privatri_mathieu/output.css
similarity index 100%
rename from wco/privatri/output.css
rename to wco/privatri_mathieu/output.css
diff --git a/wco/privatri_mathieu/privatri.js b/wco/privatri_mathieu/privatri.js
new file mode 100644
index 0000000..f1d28b5
--- /dev/null
+++ b/wco/privatri_mathieu/privatri.js
@@ -0,0 +1,506 @@
+import apx from "./apx.js";
+import { getOldestPrivatriids, syncronizeBackend } from "./utils.js";
+
+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");
+ const month = String(date.getMonth() + 1).padStart(2, "0");
+ const year = date.getFullYear();
+ const hours = String(date.getHours()).padStart(2, "0");
+ const minutes = String(date.getMinutes()).padStart(2, "0");
+
+ return `${day}/${month}/${year} ${hours}:${minutes}`;
+};
+
+searchInputEl.addEventListener("input", () => {
+ const value = searchInputEl.value.toLowerCase();
+
+ Array.from(threadsContainerEl.children).forEach(child => {
+ if (child.querySelector("li > div").textContent.toLowerCase().includes(value)) {
+ child.style.display = "block";
+ } else {
+ child.style.display = "none";
+ };
+ });
+});
+
+threadFilterOptionsElArray.forEach(option => {
+ option.addEventListener("click", async () => {
+ const filter = option.getAttribute("data-filter");
+
+ if (filter === "date") {
+ Array.from(threadsContainerEl.children).sort((a, b) => {
+ return a.querySelector("li > span").getAttribute("data-timestamp") - b.querySelector("li > span").getAttribute("data-timestamp");
+ }).forEach(child => {
+ threadsContainerEl.appendChild(child);
+ });
+ } else if (filter === "name") {
+ Array.from(threadsContainerEl.children).sort((a, b) => {
+ return a.querySelector("li > div").textContent.localeCompare(b.querySelector("li > div").textContent);
+ }).forEach(child => {
+ threadsContainerEl.appendChild(child);
+ });
+ };
+ });
+});
+
+const sendNewMessage = async (timestamp, message, attachmentsArray) => {
+ let messageTemplate = "";
+
+ await fetch("./message.mustache")
+ .then(res => res.text())
+ .then(template => {
+ messageTemplate = template;
+ });
+
+ messageTemplate = Mustache.render(messageTemplate, { timestamp, message, date: formatDate(timestamp) });
+
+ const tempNode = document.createElement("div");
+ tempNode.innerHTML = messageTemplate;
+ const messageNode = tempNode.firstElementChild;
+
+ attachmentsArray.forEach(attachment => {
+ messageNode.querySelector("div.attachmentsContainer").insertAdjacentHTML("beforeend", `

`);
+ });
+
+ return messageNode.outerHTML;
+};
+
+const editMessage = async (timestamp, message) => {
+ let editMessageTemplate = "";
+
+ await fetch("./editMessage.mustache")
+ .then(res => res.text())
+ .then(template => {
+ editMessageTemplate = template;
+ });
+
+ return Mustache.render(editMessageTemplate, { message, date: formatDate(timestamp) });
+};
+
+const displayToastAlert = async (message) => {
+ let toastAlertTemplate = "";
+
+ await fetch("./toastAlert.mustache")
+ .then(res => res.text())
+ .then(template => {
+ toastAlertTemplate = template;
+ });
+
+ return Mustache.render(toastAlertTemplate, { message });
+};
+
+sendMessageBtn.addEventListener("click", async () => {
+ const message = messageInputEl.value.trim();
+
+ 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);
+
+ return {
+ privatriid: `${threadPageEl.getAttribute("data-uuid")}_${timestamp}`,
+ timestamp: timestamp,
+ sender_alias: alias,
+ message: await apx.crypto.encryptMessage(message, publicKey),
+ attachments: await (async () => {
+ const attachmentsArray = [];
+ const localAttachmentsArray = JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`)) || [];
+
+ if (localAttachmentsArray.length > 0) {
+ for (const attachment of localAttachmentsArray) {
+ attachmentsArray.push(
+ {
+ fileType: attachment.fileType,
+ filename: attachment.filename,
+ content: await apx.crypto.encryptMessage(attachment.content, publicKey)
+ }
+ );
+ };
+ };
+
+ return attachmentsArray;
+ })()
+ };
+ })((await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messagesContainerEl.firstElementChild.getAttribute("data-timestamp")}`)).publicKey);
+
+ const newMessageHTML = await sendNewMessage(messageObj.timestamp, message, JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`)) || []);
+
+ sessionStorage.removeItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`);
+
+ messagesContainerEl.insertAdjacentHTML("beforeend", newMessageHTML);
+
+ messageInputEl.value = "";
+
+ // Faire un post sur l'endpoint /privatri
+
+ await apx.indexedDB.set("privatri", "messages", messageObj);
+ };
+});
+
+document.addEventListener("DOMContentLoaded", async () => {
+ const lastConnection = JSON.parse(localStorage.getItem("lastConnection")) || Date.now();
+
+ await syncronizeBackend(lastConnection);
+
+ const privatriidArray = await getOldestPrivatriids("privatri", "messages");
+
+ const thread = async (name, uuid) => {
+ let threadTemplate = "";
+
+ await fetch("./thread.mustache")
+ .then(res => res.text())
+ .then(template => {
+ threadTemplate = template;
+ });
+
+ return Mustache.render(threadTemplate, { uuid, name });
+ };
+
+ for (const privatriid of privatriidArray) {
+ const obj = await apx.indexedDB.get("privatri", "messages", privatriid)
+
+ const privateKey = (await apx.indexedDB.get("privatri", "threads", obj.thread)).privateKey;
+ const name = (await apx.crypto.decryptMessage(obj.title, privateKey)).data;
+
+ threadsContainerEl.insertAdjacentHTML("beforeend", await thread(name, obj.thread));
+ };
+
+ Array.from(threadsContainerEl.children).forEach(child => {
+ child.addEventListener("click", async () => {
+ const uuid = child.getAttribute("data-uuid");
+
+ const messagesObj = await new Promise((resolve, reject) => {
+ const request = indexedDB.open("privatri", 1);
+
+ request.onsuccess = (event) => {
+ const db = event.target.result;
+
+ const transaction = db.transaction("messages", "readonly");
+ const store = transaction.objectStore("messages");
+ const cursorRequest = store.openCursor();
+
+ const result = [];
+ cursorRequest.onsuccess = (event) => {
+ const cursor = event.target.result;
+
+ if (cursor) {
+ const obj = cursor.value;
+ const keyUuid = obj.privatriid.split("_")[0];
+
+ if (keyUuid === uuid) {
+ result.push(obj);
+ };
+ cursor.continue();
+ } else {
+ resolve(result);
+ };
+ };
+
+ cursorRequest.onerror = (event) => reject(event);
+ };
+
+ request.onerror = (event) => reject(event);
+ });
+
+ threadPageEl.setAttribute("data-uuid", uuid);
+ threadPageEl.querySelector("#threadName").innerText = (await apx.crypto.decryptMessage(messagesObj[0].title, (await apx.indexedDB.get("privatri", "threads", uuid)).privateKey)).data;
+
+ messagesContainerEl.innerHTML = "";
+
+ let privateKey = "";
+
+ for (const message of messagesObj) {
+ if (privateKey === "") {
+ privateKey = (await apx.indexedDB.get("privatri", "threads", message.thread)).privateKey;
+ };
+
+ const decryptedMessage = (await apx.crypto.decryptMessage(message.message, privateKey)).data;
+
+ let decryptedAttachments = [];
+
+ if (message.attachments !== undefined) {
+ decryptedAttachments = await (async () => {
+ const attachmentsArray = [];
+
+ if (message.attachments.length > 0) {
+ for (const attachment of message.attachments) {
+ attachmentsArray.push({
+ fileType: attachment.fileType,
+ filename: attachment.filename,
+ content: (await apx.crypto.decryptMessage(attachment.content, privateKey)).data
+ });
+ };
+ };
+
+ return attachmentsArray;
+ })();
+ };
+
+ messagesContainerEl.insertAdjacentHTML("beforeend", await sendNewMessage(message.timestamp, decryptedMessage, decryptedAttachments));
+ };
+ });
+ });
+
+ 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");
+
+ if (templateName === "threadAliasList" || templateName === "threadSettings") {
+ window.history.pushState({}, "", `${window.location.pathname}?uuid=${threadPageEl.getAttribute("data-uuid")}`);
+ };
+
+ await fetch(`./${templateName}.mustache`)
+ .then(res => res.text())
+ .then(template => {
+ template = Mustache.render(template, {});
+
+ bodyEl.innerHTML = template;
+ });
+
+ const script = document.createElement("script");
+
+ script.type = "module";
+ script.src = `./${templateName}.js`;
+
+ bodyEl.appendChild(script);
+ });
+ });
+});
+
+window.addEventListener("beforeunload", () => {
+ if (apx)
+ localStorage.setItem("lastConnection", JSON.stringify(Date.now()));
+});
+
+window.attachDeleteMessageEvent = async function attachDeleteMessageEvent(btn) {
+ const messageEl = btn.parentElement.parentElement.parentElement;
+
+ 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 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);
+ };
+
+ 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)) {
+ await apx.indexedDB.del("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`);
+
+ messageEl.remove();
+ } else {
+ bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to delete this message."));
+
+ setTimeout(() => {
+ bodyEl.lastElementChild.remove();
+ }, 3000);
+ };
+};
+
+window.attachEditMessageEvent = async function attachEditMessageEvent(btn) {
+ const messageEl = btn.parentElement.parentElement.parentElement;
+
+ 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) {
+ const messageValue = messageEl.querySelector("div.message").innerText;
+
+ const attachmentsArray = (() => {
+ const attachmentsArray = [];
+
+ messageEl.querySelector("div.attachmentsContainer").querySelectorAll("img").forEach(img => {
+ attachmentsArray.push(
+ {
+ fileType: img.getAttribute("src").match(/^data:(.*);base64,/)[1],
+ filename: img.getAttribute("alt"),
+ content: img.getAttribute("src").split(",")[1]
+ }
+ );
+ });
+
+ return attachmentsArray;
+ })();
+
+ messageEl.innerHTML = await editMessage(parseInt(messageEl.getAttribute("data-timestamp"), 10), messageEl.querySelector("div.message").innerText);
+
+ messageEl.querySelector("button.cancelEditBtn").addEventListener("click", async () => {
+ const messageObj = await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`);
+
+ messageEl.innerHTML = await sendNewMessage(messageObj.timestamp, messageValue, attachmentsArray);
+ });
+
+ messageEl.querySelector("button.saveEditBtn").addEventListener("click", async () => {
+ const newMessageValue = messageEl.querySelector("textarea").value.trim();
+
+ if (newMessageValue !== "") {
+ const privateKey = (await apx.indexedDB.get("privatri", "threads", threadPageEl.getAttribute("data-uuid"))).privateKey;
+
+ const messageObj = await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`);
+
+ messageObj.message = await apx.crypto.encryptMessage(newMessageValue, privateKey),
+
+ await apx.indexedDB.set("privatri", "messages", messageObj);
+
+ messageEl.innerHTML = await sendNewMessage(messageObj.timestamp, newMessageValue, attachmentsArray);
+ };
+ });
+ } else {
+ bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to edit this message."));
+
+ setTimeout(() => {
+ bodyEl.lastElementChild.remove();
+ }, 3000);
+ };
+};
+
+window.attachEventDisplayAttachment = function(img) {
+ let overlay = document.getElementById("imageOverlay");
+
+ if (overlay === null) {
+ overlay = document.createElement('div');
+
+ overlay.id = "imageOverlay";
+ overlay.style.position = "fixed";
+ overlay.style.top = 0;
+ overlay.style.left = 0;
+ overlay.style.width = "100vw";
+ overlay.style.height = "100vh";
+ overlay.style.background = "rgba(0, 0, 0, 0.75)";
+ overlay.style.display = "flex";
+ overlay.style.alignItems = "center";
+ overlay.style.justifyContent = "center";
+ overlay.style.zIndex = 999;
+
+ overlay.onclick = () => {
+ overlay.remove();
+ };
+
+ document.body.appendChild(overlay);
+ } else {
+ overlay.innerHTML = "";
+ overlay.style.display = "flex";
+ };
+
+ const fullScreenImage = document.createElement("img");
+
+ fullScreenImage.src = img.src;
+ fullScreenImage.alt = img.alt;
+ fullScreenImage.style.maxWidth = "90vw";
+ fullScreenImage.style.maxHeight = "90vh";
+ overlay.appendChild(fullScreenImage);
+};
+
+document.querySelector("#attachmentsBtn").addEventListener("click", () => {
+ attachmentsInputEl.click();
+});
+
+attachmentsInputEl.addEventListener("change", async () => {
+ const filesArray = Array.from(attachmentsInputEl.files);
+ const maxFileSize = 5 * 1024 * 1024;
+ const maxSize = 512;
+
+ for (const file of filesArray) {
+ if (file.size <= maxFileSize) {
+ const attachmentObj = await new Promise((resolve, reject) => {
+ const attachmentObj = {
+ fileType: file.type,
+ filename: file.name,
+ content: ""
+ };
+
+ const img = new Image();
+
+ img.onload = () => {
+ if (img.width > maxSize || img.height > maxSize) {
+ let width = img.width;
+ let height = img.height;
+
+ if (width > maxSize) {
+ height *= maxSize / width;
+ width = maxSize;
+ };
+
+ if (height > maxSize) {
+ width *= maxSize / height;
+ height = maxSize;
+ };
+
+ const canvas = document.createElement("canvas");
+ canvas.width = width;
+ canvas.height = height;
+
+ const ctx = canvas.getContext("2d");
+
+ ctx.drawImage(img, 0, 0, width, height);
+
+ canvas.toBlob(blob => {
+ const reader = new FileReader();
+
+ reader.onload = (event) => {
+ attachmentObj.content = event.target.result.split(",")[1];
+
+ resolve(attachmentObj);
+ };
+
+ reader.onerror = reject;
+ reader.readAsDataURL(blob);
+ }, "image/jpeg", 0.8);
+ } else {
+ const reader = new FileReader();
+
+ reader.onload = (event) => {
+ attachmentObj.content = event.target.result.split(",")[1];
+
+ resolve(attachmentObj);
+ };
+
+ reader.onerror = reject;
+ reader.readAsDataURL(file);
+ };
+ };
+
+ img.onerror = reject;
+ img.src = URL.createObjectURL(file);
+
+ return attachmentObj;
+ });
+
+ if (sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`) === null) {
+ sessionStorage.setItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`, JSON.stringify([attachmentObj]));
+ } else {
+ const attachmentsArray = JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`));
+ attachmentsArray.push(attachmentObj);
+
+ sessionStorage.setItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`, JSON.stringify(attachmentsArray));
+ };
+ };
+ };
+});
\ No newline at end of file
diff --git a/wco/privatri/thread.mustache b/wco/privatri_mathieu/thread.mustache
similarity index 100%
rename from wco/privatri/thread.mustache
rename to wco/privatri_mathieu/thread.mustache
diff --git a/wco/privatri/threadAliasList.js b/wco/privatri_mathieu/threadAliasList.js
similarity index 100%
rename from wco/privatri/threadAliasList.js
rename to wco/privatri_mathieu/threadAliasList.js
diff --git a/wco/privatri/threadAliasList.mustache b/wco/privatri_mathieu/threadAliasList.mustache
similarity index 100%
rename from wco/privatri/threadAliasList.mustache
rename to wco/privatri_mathieu/threadAliasList.mustache
diff --git a/wco/privatri/threadSettings.js b/wco/privatri_mathieu/threadSettings.js
similarity index 100%
rename from wco/privatri/threadSettings.js
rename to wco/privatri_mathieu/threadSettings.js
diff --git a/wco/privatri/threadSettings.mustache b/wco/privatri_mathieu/threadSettings.mustache
similarity index 100%
rename from wco/privatri/threadSettings.mustache
rename to wco/privatri_mathieu/threadSettings.mustache
diff --git a/wco/privatri/toastAlert.mustache b/wco/privatri_mathieu/toastAlert.mustache
similarity index 100%
rename from wco/privatri/toastAlert.mustache
rename to wco/privatri_mathieu/toastAlert.mustache
diff --git a/wco/privatri/utils.js b/wco/privatri_mathieu/utils.js
similarity index 100%
rename from wco/privatri/utils.js
rename to wco/privatri_mathieu/utils.js
diff --git a/wwws/admin/src/privatri_fr.html b/wwws/admin/src/privatri_fr.html
new file mode 100644
index 0000000..9b2ebad
--- /dev/null
+++ b/wwws/admin/src/privatri_fr.html
@@ -0,0 +1,57 @@
+
+
+
+
+
Accès Privé
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wwws/admin/src/tpldata/privatri_main_privatri.json b/wwws/admin/src/tpldata/privatri_main_privatri.json
new file mode 100644
index 0000000..1c240d9
--- /dev/null
+++ b/wwws/admin/src/tpldata/privatri_main_privatri.json
@@ -0,0 +1,30 @@
+{
+ "menuapp": [
+ {
+ "onclick": "onclick='apx.privatri.notificationsMenu();'",
+ "title": "Notification",
+ "comment": "./notificationsMenu.html"
+ },
+ {
+ "onclick": "onclick='apx.privatri.addthread();'",
+ "title": "Nouveau fil",
+ "comment": "./newMenu3.html"
+ },
+ {
+ "onclick": "href='apxid_fr.html'",
+ "title": "Compte",
+ "comment": ""
+ }
+ ],
+ "searchplaceholder": "Recherche parmis les fils",
+ "sortoptions": [
+ {
+ "title": "Tri par date",
+ "onclick": "onclick='apx.privatri.sortby('bydate');'"
+ },
+ {
+ "title": "Tri par NOM DE FIL",
+ "onclick": "onclick='apx.privatri.sortby('bytitlethread');'"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/wwws/itm/admin.json b/wwws/itm/admin.json
index e39c4f0..47e3c5b 100644
--- a/wwws/itm/admin.json
+++ b/wwws/itm/admin.json
@@ -73,6 +73,22 @@
"Pagans": "apxtri/models//tplstrings/Pagans",
"Persons": "apxtri/models/tplstrings/Persons"
}
+ },
+ "privatri": {
+ "version": 1,
+ "profils": [
+ "anonymous"
+ ],
+ "tpl": {
+ "privatrimain": "apxtri/objects/wco/privatri/main.mustache"
+ },
+ "tpldata": {
+ "privatri_main_privatri": "apxtri/objects/wwws/admin/src/tpldata/privatri_main_privatri"
+ },
+ "schema": [],
+ "ref": {},
+ "wco": {},
+ "appdata": {}
}
}
}