From 8a397e9c3874ab15b9ab8353e1591241a6dd46ae Mon Sep 17 00:00:00 2001 From: Marcel <40896559+hackthedev@users.noreply.github.com> Date: Sun, 17 May 2026 22:35:18 +0200 Subject: [PATCH 01/27] thank god --- electron/modules/settings.js | 6 +-- electron/package-lock.json | 3 +- electron/package.json | 2 +- electron/web/js/content/messages.js | 4 +- electron/web/js/content/socket.js | 84 ++++++++++++++--------------- 5 files changed, 47 insertions(+), 52 deletions(-) diff --git a/electron/modules/settings.js b/electron/modules/settings.js index d190566..8caf7a3 100644 --- a/electron/modules/settings.js +++ b/electron/modules/settings.js @@ -90,7 +90,7 @@ class Settings { let chatsPath = path.join(Settings.appDataDir, "chats") // create it if it doesnt exist - if(!fsNormal.existsSync(chatsPath)) fsNormal.mkdirSync(chatsPath) + if(!fsNormal.existsSync(chatsPath)) fsNormal.mkdirSync(chatsPath, { recursive: true }) let chatIds = await fs.readdir(chatsPath); let chats = {} @@ -115,7 +115,7 @@ class Settings { if(!data) throw new Error("data is required") let messagesPath = path.join(Settings.appDataDir, "chats", chatId, "messages"); - if(!fsNormal.existsSync(messagesPath)) fsNormal.mkdirSync(messagesPath); + if(!fsNormal.existsSync(messagesPath)) fsNormal.mkdirSync(messagesPath, { recursive: true }); fs.writeFile(path.join(messagesPath, `${messageId}.json`), JSON.stringify(data, null, 4)); @@ -134,7 +134,7 @@ class Settings { let messagesPath = path.join(Settings.appDataDir, "chats", chatId, "messages") // create it if it doesnt exist - if(!fsNormal.existsSync(messagesPath)) fsNormal.mkdirSync(messagesPath) + if(!fsNormal.existsSync(messagesPath)) fsNormal.mkdirSync(messagesPath, { recursive: true }) let messageIds = await fs.readdir(messagesPath); let messages = {} diff --git a/electron/package-lock.json b/electron/package-lock.json index 1c11dc8..c10c1a4 100644 --- a/electron/package-lock.json +++ b/electron/package-lock.json @@ -16,7 +16,7 @@ }, "devDependencies": { "electron": "^40.4.1", - "electron-builder": "^26.0.12" + "electron-builder": "^26.8.1" } }, "node_modules/@develar/schema-utils": { @@ -2142,7 +2142,6 @@ "integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", diff --git a/electron/package.json b/electron/package.json index 838ac19..74e57fd 100644 --- a/electron/package.json +++ b/electron/package.json @@ -20,7 +20,7 @@ }, "devDependencies": { "electron": "^40.4.1", - "electron-builder": "^26.0.12" + "electron-builder": "^26.8.1" }, "build": { "appId": "com.dcts.client", diff --git a/electron/web/js/content/messages.js b/electron/web/js/content/messages.js index d28f7cd..35c7adb 100644 --- a/electron/web/js/content/messages.js +++ b/electron/web/js/content/messages.js @@ -273,7 +273,6 @@ function getInnerChatContentElement() { async function renderChat(chatId, customChatObject = null) { let activeChat = customChatObject ?? await Client().GetChat(chatId); - if (!activeChat) throw new Error("Chat not found"); await setChatHeader(activeChat); @@ -285,6 +284,8 @@ async function renderChat(chatId, customChatObject = null) { let chatHost = activeChat?.home_server ?? activeChat?.host ?? null; if (!chatHost) throw new Error("No chat host found!"); + + await setChatSocket(chatHost); await connectToSocketHost(chatHost); if (!activeChat?.isServer) { @@ -318,7 +319,6 @@ async function renderInboxElementsInChat(chat, initial = false) { if (!chat) throw new Error("No chat for rendering inbox messages"); let messages = await Client().GetChatMessages(chat.gid); - console.log(messages) if (!Array.isArray(messages)) { messages = Object.values(messages).map(item => item.data ?? item); diff --git a/electron/web/js/content/socket.js b/electron/web/js/content/socket.js index 4a98e28..18bae19 100644 --- a/electron/web/js/content/socket.js +++ b/electron/web/js/content/socket.js @@ -25,60 +25,67 @@ async function waitForSocket(socket) { } const sockets = new Map(); - -function getChatSocket() { - return sockets.get("remote") - ?? [...sockets.values()][0] - ?? null; -} - -function getHomeSocket() { - return [...sockets.values()].find(socket => socket?.isHomeServer === true) - ?? null; -} +let activeChatHost = null; async function getSocket(host) { host = extractHost(host); + if (!host) throw new Error("host is required"); - let homeServer = extractHost(await Client().GetHomeServer()); - let socketKey = host === homeServer ? host : "remote"; - - if (sockets.has(socketKey)) { - let existingSocket = sockets.get(socketKey); - - if (socketKey === "remote" && existingSocket.host !== host) { - existingSocket.disconnect(); - sockets.delete(socketKey); - } else { - return existingSocket; - } - } + if (sockets.has(host)) return sockets.get(host); let socket = io.connect(`${getProtocol(host)}://${host}`, { reconnection: true }); socket.host = host; - socket.isHomeServer = host === homeServer; - - sockets.set(socketKey, socket); + socket.isHomeServer = extractHost(await Client().GetHomeServer()) === host; socket.on("connect", async () => { + console.log(`connected to ${host}`); await socketHello(socket, host); - console.log(`Connected to host ${host} via socket`); + + if (!socket.didRegisterSocketListeners) { + registerSocketListeners(socket); + socket.didRegisterSocketListeners = true; + } }); + socket.on("disconnect", () => { + sockets.delete(host); + if (activeChatHost === host) activeChatHost = null; + }); + + sockets.set(host, socket); return socket; } -function terminateSocket(address) { - address = extractHost(address); +async function setChatSocket(host) { + host = extractHost(host); + let socket = await getSocket(host); + await waitForSocket(socket); + + activeChatHost = host; + return socket; +} + +async function getChatSocket(host = null) { + if (host) return await getSocket(extractHost(host)); + if (activeChatHost) return sockets.get(activeChatHost) ?? null; + return null; +} + +function getHomeSocket() { + return [...sockets.values()].find(s => s?.isHomeServer === true) ?? null; +} - let socket = sockets.get(address); +function terminateSocket(host) { + host = extractHost(host); + let socket = sockets.get(host); if (!socket) return false; socket.disconnect(); - sockets.delete(address); + sockets.delete(host); + if (activeChatHost === host) activeChatHost = null; return true; } @@ -180,18 +187,7 @@ async function sendMessage(text, targetPublicKey, host, test = false){ payload.message = await Client().SignJson(payload.message) return await new Promise(async (resolve, reject) => { - (await getChatSocket()).emit("/messenger/send", {message: payload.message, sessionId}, async function (response){ - - if(!response?.error){ - let existingChat = await Client().GetChat(targetGid); - if(!existingChat) await startNewChat({ - identifier: `${targetGid}@${host}`, - automate: true - }) - - await Client().SaveChatMessage(targetGid, payload.message) - } - + (await getChatSocket(host)).emit("/messenger/send", {message: payload.message, sessionId}, async function (response){ resolve(response) }) }) From d3093c16552d86e8c77687ded4b6981ef4c95602 Mon Sep 17 00:00:00 2001 From: Marcel <40896559+hackthedev@users.noreply.github.com> Date: Sun, 17 May 2026 23:14:31 +0200 Subject: [PATCH 02/27] Fixed states? --- electron/modules/settings.js | 13 +++--- electron/web/js/content/messages.js | 67 +++++++++++++++++++++++++---- electron/web/js/content/socket.js | 36 ++++++++++++++-- 3 files changed, 97 insertions(+), 19 deletions(-) diff --git a/electron/modules/settings.js b/electron/modules/settings.js index 8caf7a3..b99d35e 100644 --- a/electron/modules/settings.js +++ b/electron/modules/settings.js @@ -51,23 +51,20 @@ class Settings { static Message = class { static async saveChat(chatId, data = {}) { if (!chatId) throw new Error("chatId is required") - if(Object.keys(data || {}).length === 0) throw new Error("Data was empty") + if (Object.keys(data || {}).length === 0) throw new Error("data was empty") - let chatPath = path.join(Settings.appDataDir, "chats", chatId) let chatMessagesPath = path.join(Settings.appDataDir, "chats", chatId, "messages") let chatConfigPath = path.join(Settings.appDataDir, "chats", chatId, "config.json") // if the directory doesnt exist create it. // we use the chatMessagePath here because that will also create the chatPath path // as we use "recursive: true" - if(!fsNormal.existsSync(chatMessagesPath)){ - fsNormal.mkdirSync(path.join(chatMessagesPath), { recursive: true }); + if (!fsNormal.existsSync(chatMessagesPath)) { + fsNormal.mkdirSync(chatMessagesPath, { recursive: true }); } - // also create the config file for the chat itself if it doesnt exist - if(!fsNormal.existsSync(chatConfigPath)){ - await fs.writeFile(chatConfigPath, JSON.stringify(data, null, 4)); - } + // always overwrite the config so it stays up to date + await fs.writeFile(chatConfigPath, JSON.stringify(data, null, 4)); Settings.settings.client ??= {} Settings.settings.client.lastOnline = new Date().getTime(); diff --git a/electron/web/js/content/messages.js b/electron/web/js/content/messages.js index 35c7adb..beff78c 100644 --- a/electron/web/js/content/messages.js +++ b/electron/web/js/content/messages.js @@ -81,7 +81,7 @@ async function fetchServerInbox(host) { let serverChatSelector = getContentElement().querySelector(`.chats .chat[data-gid="${chatId}"]`); if (serverChatSelector) serverChatSelector.remove(); - getContentElement().querySelector(`.chats`).insertAdjacentHTML("beforeend", ` + getContentElement().querySelector(`.chats .list`).insertAdjacentHTML("beforeend", `
@@ -165,11 +165,20 @@ async function fetchMessengerChats(timestamp = 0) { `) } + // make sure the chat exists before saving any message let existingChat = await Client().GetChat(authorGid) - if(!existingChat) await startNewChat({ - identifier: `${authorGid}@${authorHomeServer}`, - automate: true - }) + if (!existingChat) { + await Client().SaveChat(authorGid, { + publicKey: authorPublicKey, + gid: authorGid, + title: `@${authorGid}`, + host: authorHomeServer, + home_server: authorHomeServer, + lastMessage: null, + icon: null, + }); + } + await Client().SaveChatMessage(authorGid, message); } else{ @@ -189,6 +198,48 @@ async function fetchMessengerChats(timestamp = 0) { }) } +async function refreshChatEntry(chatGid) { + let chatsElement = getContentElement().querySelector(`.chats .list`); + if (!chatsElement) return; + + let chat = await Client().GetChat(chatGid); + if (!chat) return; + + let messages = Object.values(await Client().GetChatMessages(chatGid) ?? {}) + .map(item => item.data ?? item) + .sort((a, b) => (a?.timestamp ?? 0) - (b?.timestamp ?? 0)); + + let gid = await Client().GenerateGid(await Client().GetPublicKey()); + let lastMessage = messages.at(-1) ?? null; + + let decryptedLastMessage = null; + if (lastMessage) { + try { + decryptedLastMessage = await decryptUserMessage(lastMessage[gid]); + } catch { + decryptedLastMessage = null; + } + } + + let chatName = chat?.title ?? "Unknown"; + let latestMessage = decryptedLastMessage ?? `@${chat?.host ?? chat?.home_server}`; + + // remove old entry and re-insert at top so newest chat bubbles up + let existing = chatsElement.querySelector(`.chat[data-gid="${chatGid}"]`); + if (existing) existing.remove(); + + chatsElement.insertAdjacentHTML("afterbegin", ` +
+
+
+
${chatName}
+ ${latestMessage ? `
${latestMessage}
` : ""} +
+
${messages.length}
+
+ `); +} + async function renderMessages() { getContentElement().innerHTML = ` @@ -201,6 +252,7 @@ async function renderMessages() { ${Icon.display("message_add")}
+
@@ -214,7 +266,7 @@ async function renderMessages() { let gid = await Client().GenerateGid(await Client().GetPublicKey()); - addChatEntries(getContentElement().querySelector(`.chats`)) + addChatEntries(getContentElement().querySelector(`.chats .list`)) async function addChatEntries(element) { if (!element) throw new Error("Element not found for adding chat element"); @@ -245,7 +297,6 @@ async function renderMessages() { chat.lastMessage = await decryptUserMessage(chat.lastMessage) } - let chatName = chat?.title ?? "Unkown" let latestMessage = chat.lastMessage ?? `@${chat?.host ?? chat?.data?.host ?? chat?.data?.home_server}`// will need to actually decrypt this @@ -360,7 +411,7 @@ async function renderInboxElementsInChat(chat, initial = false) { } // if we actually open a chat we will just scroll down - if (initial) { + if (initial && getInnerChatContentElement()) { ChatTools.Scroll.scrollDown(getInnerChatContentElement()) } } diff --git a/electron/web/js/content/socket.js b/electron/web/js/content/socket.js index 18bae19..facc258 100644 --- a/electron/web/js/content/socket.js +++ b/electron/web/js/content/socket.js @@ -128,11 +128,41 @@ async function socketHello(socket, address){ async function registerSocketListeners(socket){ socket.on("/messenger/receive", async (message) => { - let myMessage = message[await Client().GenerateGid(await Client().GetPublicKey())] message.messageId = message.timestamp; - await Client().SaveChatMessage(message?.author?.gid, message) - if(message?.type === "user_message") await renderUserMessage(message, getInnerChatContentElement()) + let authorGid = message?.author?.gid; + let authorPublicKey = message?.author?.publicKey; + let authorHomeServer = message?.author?.home_server; + + let ownGid = await Client().GenerateGid(await Client().GetPublicKey()); + + // if we are the author, save under the target — otherwise save under the author + let targetGid = message?.targetIdentifier + ? await Client().GenerateGid(message.targetIdentifier) + : null; + + let chatGid = authorGid === ownGid ? targetGid : authorGid; + if (!chatGid) return console.error("could not determine chat partner gid", message); + + // make sure the chat exists before saving any message + let existingChat = await Client().GetChat(chatGid) + if (!existingChat) { + await Client().SaveChat(chatGid, { + publicKey: authorGid === ownGid ? message.targetIdentifier : authorPublicKey, + gid: chatGid, + title: `@${chatGid}`, + host: authorHomeServer, + home_server: authorHomeServer, + lastMessage: null, + icon: null, + }); + } + + // update the chat entry in the sidebar so the latest message and badge show up + await refreshChatEntry(chatGid); + + await Client().SaveChatMessage(chatGid, message) + if(message?.type === "user_message" && getInnerChatContentElement()) await renderUserMessage(message, getInnerChatContentElement()) }) } From 3ad5a8e9a8225dcb4105467947ad2f5b9893cf84 Mon Sep 17 00:00:00 2001 From: Marcel <40896559+hackthedev@users.noreply.github.com> Date: Sun, 17 May 2026 23:36:18 +0200 Subject: [PATCH 03/27] Update default.css --- electron/web/css/themes/default/default.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/electron/web/css/themes/default/default.css b/electron/web/css/themes/default/default.css index 6071af7..d674e01 100644 --- a/electron/web/css/themes/default/default.css +++ b/electron/web/css/themes/default/default.css @@ -119,7 +119,10 @@ a { } .layout > .content-container > .content > .message-page-container > .chat-content > .content > .message-container { - background-color: hsl(from var(--accent) h s calc(l * 1)); + background-color: hsl(from var(--accent) h calc(s * 0.5) calc(l * 0.5)); +} +.layout > .content-container > .content > .message-page-container > .chat-content > .content > .message-container > .meta { + color: hsl(from var(--main) h s calc(l * 10) / 100%); } .layout > .content-container > .content > .message-page-container > .chat-content > .content > .message-container.mine{ background-color: hsl(from var(--main) h s calc(l * 3)); @@ -131,7 +134,7 @@ a { background-color: hsl(from var(--main) h s calc(l * 8) / 10%); } -.layout > .content-container > .content > .message-page-container > .chat-content > .content > .message-container > .meta { +.layout > .content-container > .content > .message-page-container > .chat-content > .content > .message-container.mine > .meta { color: hsl(from var(--main) h s calc(l * 6) / 100%); } From a894bd8d2024c24f520c25ee24a6e0afb6e8965b Mon Sep 17 00:00:00 2001 From: Marcel <40896559+hackthedev@users.noreply.github.com> Date: Sun, 17 May 2026 23:48:24 +0200 Subject: [PATCH 04/27] Update messages.css --- electron/web/css/content/messages.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/electron/web/css/content/messages.css b/electron/web/css/content/messages.css index c08d91e..1a8b670 100644 --- a/electron/web/css/content/messages.css +++ b/electron/web/css/content/messages.css @@ -112,6 +112,12 @@ font-size: 14px; position: relative; } +.layout > .content-container > .content > .message-page-container .chats .chat .latestMessage img, +.layout > .content-container > .content > .message-page-container .chats .chat .latestMessage video, +.layout > .content-container > .content > .message-page-container .chats .chat .latestMessage audio, +.layout > .content-container > .content > .message-page-container .chats .chat .latestMessage iframe{ + display: none; +} .layout > .content-container > .content > .message-page-container .chats .chat .latestMessage p{ position: relative; margin: 0; From 7298063f75c7d7cda57690dff5c46a6adb09bbdd Mon Sep 17 00:00:00 2001 From: Marcel <40896559+hackthedev@users.noreply.github.com> Date: Mon, 18 May 2026 21:25:07 +0200 Subject: [PATCH 05/27] added updater - experimental --- electron/index.js | 60 ++++++++++++++++++++++++++ electron/package-lock.json | 86 +++++++++++++++++++++----------------- electron/package.json | 5 ++- 3 files changed, 110 insertions(+), 41 deletions(-) diff --git a/electron/index.js b/electron/index.js index 0bdbd96..3c0ed2a 100644 --- a/electron/index.js +++ b/electron/index.js @@ -6,6 +6,7 @@ const { nativeImage, session, desktopCapturer, + dialog, Notification, net, } = require("electron"); @@ -21,6 +22,9 @@ const Settings = require("./modules/settings"); const FrontendLibs = require("@hackthedev/frontend-libs").default; let libDir = path.join(path.resolve(), "web", "js", "libs"); +const AppUpdater = require("@hackthedev/app-updater").default; +//const AppUpdater = require("E:\\network-z-dev\\app-updater\\index.mjs").default; + let win = null; const applicationDataDir = path.join(app.getPath("documents"), "dcts"); @@ -166,6 +170,62 @@ app.commandLine.appendSwitch( ); app.whenReady().then(async () => { + // Check for fucking update + let updateCheck = await AppUpdater.check("https://dcts.community/app/electron", { + includeOsUrl: true, + version: app.getVersion() + }) + + + // if available show prompt + if(updateCheck?.available){ + let result = await dialog.showMessageBox({ + type: "question", + buttons: ["Update", "Not now"], + defaultId: 0, + cancelId: 1, + title: "DCTS Client Update available", + message: "It seems that a new version of the DCTS Client is available. Do you wanna download it?", + detail: `Current Version: ${updateCheck?.current}\nAvailable Version: ${updateCheck?.remote}` + }); + + if(result.response === 0){ + let progressWindow = new BrowserWindow({ + width: 400, + height: 160, + resizable: false, + minimizable: false, + maximizable: false, + autoHideMenuBar: true + }); + + await progressWindow.loadURL(`data:text/html, + +

DCTS Update

+
Starting download...
+ + `); + + if(updateCheck?.downloadUrl){ + let file = await AppUpdater.downloadFile( + updateCheck.downloadUrl, + (data) => { + progressWindow.webContents.executeJavaScript(` + document.getElementById("status").innerText = + "Downloading... ${data.progress}%"; + `); + } + ); + + progressWindow.webContents.executeJavaScript(` + document.getElementById("status").innerText = + "Finished: ${file.replaceAll("\\", "\\\\")}"; + `); + } + } + } + + await Settings.initSettings(applicationDataDir); // youtube embed fix — header spoofing diff --git a/electron/package-lock.json b/electron/package-lock.json index c10c1a4..365b539 100644 --- a/electron/package-lock.json +++ b/electron/package-lock.json @@ -1,14 +1,15 @@ { "name": "DCTS", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "DCTS", - "version": "1.0.0", - "license": "ISC", + "version": "1.0.1", + "license": "UNLICENSED", "dependencies": { + "@hackthedev/app-updater": "^1.0.1", "@hackthedev/dsync-sign": "^1.0.14", "@hackthedev/frontend-libs": "^1.0.5", "cors": "^2.8.6", @@ -63,9 +64,9 @@ "license": "MIT" }, "node_modules/@electron/asar/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -357,9 +358,9 @@ "license": "MIT" }, "node_modules/@electron/universal/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -482,6 +483,12 @@ "node": ">= 10.0.0" } }, + "node_modules/@hackthedev/app-updater": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@hackthedev/app-updater/-/app-updater-1.0.1.tgz", + "integrity": "sha512-I04nyJNUFtJsiHrxGGg5KJuKQEhudyCn1Majp73PCQP1ubY8fm3mAcHpEksu7R07poLogwLMhGpk2KLU9el0DA==", + "license": "UNLICENSED" + }, "node_modules/@hackthedev/dsync-sign": { "version": "1.0.14", "resolved": "https://registry.npmjs.org/@hackthedev/dsync-sign/-/dsync-sign-1.0.14.tgz", @@ -888,9 +895,9 @@ } }, "node_modules/@xmldom/xmldom": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", - "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", + "version": "0.8.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz", + "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==", "dev": true, "license": "MIT", "engines": { @@ -1345,9 +1352,9 @@ "optional": true }, "node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -1517,9 +1524,9 @@ "license": "MIT" }, "node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -2113,9 +2120,9 @@ "license": "MIT" }, "node_modules/dir-compare/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -2142,6 +2149,7 @@ "integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", @@ -2291,9 +2299,9 @@ } }, "node_modules/electron": { - "version": "40.4.1", - "resolved": "https://registry.npmjs.org/electron/-/electron-40.4.1.tgz", - "integrity": "sha512-N1ZXybQZL8kYemO8vAeh9nrk4mSvqlAO8xs0QCHkXIvRnuB/7VGwEehjvQbsU5/f4bmTKpG+2GQERe/zmKpudQ==", + "version": "40.10.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-40.10.0.tgz", + "integrity": "sha512-e7XVcAfyWoFQGS7ZhgxeNn0AijHaqgRCa6uA6TYOrvBWv8smI6JILvMR/8DYBIn07oqvxDLRC90tu/xa2cJCow==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2791,9 +2799,9 @@ "license": "MIT" }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -3042,9 +3050,9 @@ "license": "MIT" }, "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -3388,9 +3396,9 @@ "license": "ISC" }, "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "dev": true, "license": "MIT", "engines": { @@ -3588,9 +3596,9 @@ "license": "MIT" }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "dev": true, "license": "MIT" }, @@ -4299,9 +4307,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "peer": true, diff --git a/electron/package.json b/electron/package.json index 74e57fd..140d447 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,9 +1,9 @@ { "name": "DCTS", "productName": "DCTS", - "version": "1.0.0", + "version": "1.0.1", "description": "", - "license": "ISC", + "license": "UNLICENSED", "author": "", "type": "commonjs", "main": "index.js", @@ -13,6 +13,7 @@ "build": "electron-builder" }, "dependencies": { + "@hackthedev/app-updater": "^1.0.1", "@hackthedev/dsync-sign": "^1.0.14", "@hackthedev/frontend-libs": "^1.0.5", "cors": "^2.8.6", From 4e64bc95a04d779ebd10cb59cb5d6bce095efc7a Mon Sep 17 00:00:00 2001 From: Marcel <40896559+hackthedev@users.noreply.github.com> Date: Sat, 23 May 2026 03:34:39 +0200 Subject: [PATCH 06/27] added sanitizing features - wip --- electron/web/js/libs/chat-tools/ChatTools.js | 184 +- electron/web/js/libs/chat-tools/quill.js | 11560 +++++++++++++++++ 2 files changed, 11729 insertions(+), 15 deletions(-) create mode 100644 electron/web/js/libs/chat-tools/quill.js diff --git a/electron/web/js/libs/chat-tools/ChatTools.js b/electron/web/js/libs/chat-tools/ChatTools.js index 2b0cdce..047b258 100644 --- a/electron/web/js/libs/chat-tools/ChatTools.js +++ b/electron/web/js/libs/chat-tools/ChatTools.js @@ -247,11 +247,11 @@ class ChatTools { if (t) embed += "?start=" + parseInt(t); return ` -
- ${url}
+
+ ${ChatTools.Sanitize.forRender(url)}