800 lines
35 KiB
JavaScript
800 lines
35 KiB
JavaScript
var apx = apx || {};
|
|
|
|
apx.privatri = {};
|
|
apx.privatri.templates = {};
|
|
|
|
const apiUrl = "http://admin.apxtri.farm.test/api/apxtri/privatri"
|
|
const tribe = "apxtri";
|
|
|
|
apx.privatri.loadwco = async (id, dataObj = {}, ctx = null) => {
|
|
// 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
|
|
)}`
|
|
);
|
|
|
|
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);
|
|
};
|
|
|
|
async function getOldestPrivatriids(db, storeName) {
|
|
const keysArray = await apx.indexedDB.getAllKeys(db, storeName);
|
|
|
|
const oldestPerUuid = {};
|
|
|
|
for (const key of keysArray) {
|
|
const [uuid, timestampStr] = key.split("_");
|
|
const timestamp = Number(timestampStr);
|
|
|
|
if (!oldestPerUuid[uuid] || timestamp < oldestPerUuid[uuid].timestamp) {
|
|
oldestPerUuid[uuid] = { key, timestamp };
|
|
};
|
|
};
|
|
|
|
const oldestKeysArray = Object.values(oldestPerUuid).map(obj => obj.key)
|
|
|
|
const threadsArray = [];
|
|
|
|
for (key of oldestKeysArray) {
|
|
threadsArray.push(await apx.indexedDB.get(db, storeName, key));
|
|
};
|
|
|
|
return threadsArray;
|
|
};
|
|
|
|
apx.privatri.syncronizeBackend = async (alias, lastConnection) => {
|
|
const threadsArray = await getOldestPrivatriids("privatri", "messages");
|
|
|
|
for (const threadObj of threadsArray) {
|
|
try {
|
|
const response = await fetch(`${apiUrl}/${tribe}/${threadObj.thread}?since=${lastConnection}`);
|
|
|
|
if (response.ok === false) {
|
|
throw new Error("HTTP error");
|
|
};
|
|
|
|
console.log(response);
|
|
|
|
// for (const message of response) {
|
|
// await apx.indexedDB.set("privatri", "messages", message);
|
|
// };
|
|
} catch (error) {
|
|
const displayToastAlert = async (message) => {
|
|
return await apx.privatri.loadwco("toastAlert", { message });
|
|
};
|
|
|
|
document.querySelector("body").insertAdjacentHTML("beforeend", await displayToastAlert("An error occurred while synchronizing messages. Please try again later."));
|
|
};
|
|
};
|
|
};
|
|
|
|
apx.privatri.templates.scripts = {
|
|
createThread: async () => {
|
|
const bodyEl = document.querySelector("body");
|
|
const autoDeletionBtnElArray = document.querySelectorAll("li.autoDeletionBtn");
|
|
|
|
const displayToastAlert = async (message) => {
|
|
return await apx.privatri.loadwco("toastAlert", { message });
|
|
};
|
|
|
|
autoDeletionBtnElArray.forEach(btn => {
|
|
btn.addEventListener("click", () => {
|
|
autoDeletionBtnElArray.forEach(btn => btn.classList.remove("bg-base-200"));
|
|
btn.classList.add("bg-base-200");
|
|
});
|
|
});
|
|
|
|
document.querySelector("#createThreadBtn").addEventListener("click", async () => {
|
|
const { publicKey, privateKey } = await apx.crypto.genKey();
|
|
|
|
const messageObj = await (async (publicKey) => {
|
|
const uuid = apx.crypto.genUUID();
|
|
const timestamp = Date.now();
|
|
const alias = await apx.crypto.encryptMessage(JSON.parse(localStorage.getItem("admin")).headers.xalias, publicKey);
|
|
|
|
return {
|
|
privatriid: `${uuid}_${timestamp}`,
|
|
thread: uuid,
|
|
timestamp: timestamp,
|
|
owner: alias,
|
|
title: await apx.crypto.encryptMessage(document.querySelector("#threadNameInput").value, publicKey),
|
|
sender_alias: alias,
|
|
publicKey: publicKey,
|
|
aliases: [
|
|
alias
|
|
],
|
|
message: await apx.crypto.encryptMessage(document.querySelector("#threadDescriptionInput").value, publicKey),
|
|
dt_autodestruction: (() => {
|
|
const selectedBtn = Array.from(autoDeletionBtnElArray).find(btn => btn.classList.contains("bg-base-200"));
|
|
return parseInt(selectedBtn ? selectedBtn.getAttribute("data-auto-deletion") : 0, 10);
|
|
})(),
|
|
urgencydeletion: document.querySelector('input[type="checkbox"].toggle').checked
|
|
};
|
|
})(publicKey);
|
|
|
|
try {
|
|
const response = await fetch(`${apiUrl}/${tribe}/${messageObj.thread}`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"xdays": admin.headers.xdays,
|
|
"xalias": admin.headers.xalias,
|
|
"xlang": admin.headers.xlang,
|
|
"xtribe": admin.headers.xtribe,
|
|
"xapp": admin.headers.xapp,
|
|
"xuuid": admin.headers.xuuid
|
|
},
|
|
body: JSON.stringify(messageObj)
|
|
});
|
|
|
|
if (response.ok === false) {
|
|
throw new Error("HTTP error");
|
|
};
|
|
|
|
await apx.indexedDB.set("privatri", "threads", { uuid: messageObj.thread, privateKey: privateKey });
|
|
await apx.indexedDB.set("privatri", "messages", messageObj);
|
|
|
|
bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("Thread created successfully."));
|
|
} catch (error) {
|
|
bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("An error occurred while creating the thread. Please try again later."));
|
|
};
|
|
});
|
|
},
|
|
inviteAlias: async () => {
|
|
const url = "https://www.facebook.com/";
|
|
|
|
const bodyEl = document.querySelector("body");
|
|
const qrCodeCanvasEl = document.querySelector("#qrCodeCanvas");
|
|
const invitationLinkInputEl = document.querySelector("#invitationLinkInput");
|
|
|
|
const displayToastAlert = async (message) => {
|
|
return await apx.privatri.loadwco("toastAlert", { message });
|
|
};
|
|
|
|
const qrCode = new QRCodeStyling({
|
|
width: 425,
|
|
height: 425,
|
|
type: "svg",
|
|
data: url,
|
|
image: "static/img/icons/privatri.png",
|
|
dotsOptions: {
|
|
color: "#ffffff",
|
|
type: "rounded"
|
|
},
|
|
backgroundOptions: {
|
|
color: getComputedStyle(bodyEl).backgroundColor || "#000000",
|
|
},
|
|
imageOptions: {
|
|
crossOrigin: "anonymous",
|
|
margin: 20
|
|
}
|
|
});
|
|
|
|
qrCode.append(qrCodeCanvasEl);
|
|
|
|
invitationLinkInputEl.value = url;
|
|
|
|
copyBtn.addEventListener("click", async () => {
|
|
navigator.clipboard.writeText(invitationLinkInputEl.value);
|
|
|
|
bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("Invitation link copied to clipboard."));
|
|
|
|
setTimeout(() => {
|
|
bodyEl.lastElementChild.remove();
|
|
}, 3000);
|
|
});
|
|
},
|
|
threadAliasList: async () => {
|
|
const bodyEl = document.querySelector("body");
|
|
const aliasListContainerEl = document.querySelector("#aliasListContainer");
|
|
|
|
let aliasesArray = [];
|
|
|
|
const newAlias = async (alias) => {
|
|
return await apx.privatri.loadwco("alias", { alias });
|
|
};
|
|
|
|
const displayToastAlert = async (message) => {
|
|
return await apx.privatri.loadwco("toastAlert", { message });
|
|
};
|
|
|
|
const params = new URLSearchParams(window.location.search);
|
|
const uuid = params.get("uuid");
|
|
|
|
const privateKey = (await apx.indexedDB.get("privatri", "threads", uuid)).privateKey;
|
|
|
|
const privatriidArray = await getOldestPrivatriids("privatri", "messages");
|
|
|
|
privatriidArray.forEach(async privatriid => {
|
|
if (privatriid.thread === uuid) {
|
|
messageObj = privatriid;
|
|
aliasesArray = messageObj.aliases;
|
|
const ownerAlias = messageObj.owner;
|
|
|
|
for (const alias of aliasesArray) {
|
|
aliasListContainerEl.insertAdjacentHTML("beforeend", await newAlias({
|
|
decrypted: (await apx.crypto.decryptMessage(alias, privateKey)).data,
|
|
crypted: alias
|
|
}));
|
|
};
|
|
|
|
document.querySelectorAll("button.removeAliasBtn").forEach(btn => {
|
|
btn.addEventListener("click", async () => {
|
|
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);
|
|
btn.parentElement.parentElement.remove();
|
|
|
|
privatriidArray.forEach(async privatriid => {
|
|
if (privatriid.split("_")[0] === uuid) {
|
|
const messageObj = await apx.indexedDB.get("privatri", "messages", privatriid);
|
|
messageObj.aliases = aliasesArray;
|
|
|
|
await apx.indexedDB.set("privatri", "messages", messageObj);
|
|
};
|
|
});
|
|
} else {
|
|
bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You cannot remove the owner of the thread."));
|
|
|
|
setTimeout(() => {
|
|
bodyEl.lastElementChild.remove();
|
|
}, 3000);
|
|
};
|
|
} else {
|
|
bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to remove this alias."));
|
|
|
|
setTimeout(() => {
|
|
bodyEl.lastElementChild.remove();
|
|
}, 3000);
|
|
};
|
|
});
|
|
});
|
|
};
|
|
});
|
|
},
|
|
threadSettings: async () => {
|
|
const bodyEl = document.querySelector("body");
|
|
const threadNameInputEl = document.querySelector("#threadNameInput");
|
|
const autoDeletionBtnElArray = document.querySelectorAll("li.autoDeletionBtn");
|
|
const applyModificationsBtnEl = document.querySelector("#applyModificationsBtn");
|
|
|
|
const displayToastAlert = async (message) => {
|
|
return await apx.privatri.loadwco("toastAlert", { message });
|
|
};
|
|
|
|
let messageObj = {};
|
|
|
|
const params = new URLSearchParams(window.location.search);
|
|
const uuid = params.get("uuid");
|
|
|
|
const privateKey = (await apx.indexedDB.get("privatri", "threads", uuid)).privateKey;
|
|
|
|
const privatriidArray = await getOldestPrivatriids("privatri", "messages");
|
|
let ownerAlias = "";
|
|
|
|
privatriidArray.forEach(async privatriid => {
|
|
if (privatriid.thread === uuid) {
|
|
messageObj = privatriid;
|
|
ownerAlias = messageObj.owner;
|
|
|
|
threadNameInputEl.value = (await apx.crypto.decryptMessage(messageObj.title, privateKey)).data;
|
|
|
|
(Array.from(autoDeletionBtnElArray).find(el => el.getAttribute("data-auto-deletion") === String(messageObj.dt_autodestruction))).classList.add("bg-base-200");
|
|
|
|
if (messageObj.urgencydeletion === true) {
|
|
document.querySelector('input[type="checkbox"].toggle').checked = true;
|
|
};
|
|
};
|
|
});
|
|
|
|
applyModificationsBtnEl.addEventListener("click", async () => {
|
|
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"));
|
|
return parseInt(selectedBtn ? selectedBtn.getAttribute("data-auto-deletion") : 0, 10);
|
|
})();
|
|
messageObj.urgencydeletion = document.querySelector('input[type="checkbox"].toggle').checked;
|
|
|
|
await apx.indexedDB.set("privatri", "messages", messageObj);
|
|
} else {
|
|
bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to edit this thread."));
|
|
|
|
setTimeout(() => {
|
|
bodyEl.lastElementChild.remove();
|
|
}, 3000);
|
|
};
|
|
});
|
|
|
|
autoDeletionBtnElArray.forEach(btn => {
|
|
btn.addEventListener("click", () => {
|
|
autoDeletionBtnElArray.forEach(btn => btn.classList.remove("bg-base-200"));
|
|
btn.classList.add("bg-base-200");
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
apx.ready(async () => {
|
|
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);
|
|
|
|
const privatriidArray = await getOldestPrivatriids("privatri", "messages");
|
|
console.log(privatriidArray);
|
|
|
|
const thread = async (name, uuid) => {
|
|
return await apx.privatri.loadwco("thread", { uuid, name });
|
|
};
|
|
|
|
for (const privatriidObj of privatriidArray) {
|
|
const obj = await apx.indexedDB.get("privatri", "messages", privatriidObj.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));
|
|
};
|
|
});
|
|
});
|
|
|
|
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");
|
|
|
|
if (templateName === "threadAliasList" || templateName === "threadSettings") {
|
|
window.history.pushState({}, "", `${window.location.pathname}?uuid=${threadPageEl.getAttribute("data-uuid")}`);
|
|
};
|
|
|
|
bodyEl.innerHTML = await apx.privatri.loadwco(templateName);
|
|
|
|
await apx.privatri.templates.scripts[templateName]();
|
|
});
|
|
});
|
|
})();
|
|
|
|
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) => {
|
|
const messageTemplate = await apx.privatri.loadwco("message", { 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", `<img onclick="attachEventDisplayAttachment(this)" class="w-20 h-20 object-cover rounded" src="data:${attachment.fileType};base64,${attachment.content}" alt="${attachment.filename}"/>`);
|
|
});
|
|
|
|
return messageNode.outerHTML;
|
|
};
|
|
|
|
const editMessage = async (timestamp, message) => {
|
|
return await apx.privatri.loadwco("editMessage", { message, date: formatDate(timestamp) });
|
|
};
|
|
|
|
const displayToastAlert = async (message) => {
|
|
return await apx.privatri.loadwco("toastAlert", { 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("admin")).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 = "";
|
|
|
|
try {
|
|
const response = await fetch(`${apiUrl}/`);
|
|
|
|
if (response.ok === false) {
|
|
throw new Error("HTTP error");
|
|
};
|
|
|
|
await apx.indexedDB.set("privatri", "messages", messageObj);
|
|
} catch (error) {
|
|
bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("An error occurred while sending the message. Please try again later."));
|
|
};
|
|
};
|
|
});
|
|
|
|
window.addEventListener("beforeunload", () => {
|
|
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("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);
|
|
// };
|
|
|
|
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("admin")).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("admin")).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));
|
|
};
|
|
};
|
|
};
|
|
});
|
|
}); |