From 5443d045db707b938eeaf32092b579bf0a64df36 Mon Sep 17 00:00:00 2001 From: marlon-erler Date: Sun, 21 Jul 2024 22:42:32 +0200 Subject: [PATCH] cleanup, add handleStringifiedFile and addFile --- dist/index.js | 96 +++++++++++++++++++++++++----------- src/Model/Utility/utility.ts | 16 +++++- src/Model/chatModel.ts | 75 ++++++++++++++++++---------- src/Model/fileModel.ts | 15 +++++- 4 files changed, 145 insertions(+), 57 deletions(-) diff --git a/dist/index.js b/dist/index.js index 4427c29f..195b465d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -276,6 +276,12 @@ return element; } + // src/Model/Utility/typeSafety.ts + var DATA_VERSION = "v2"; + function checkIsValidObject(object) { + return object.dataVersion == DATA_VERSION; + } + // src/Model/Utility/utility.ts function createTimestamp() { return (/* @__PURE__ */ new Date()).toISOString(); @@ -284,18 +290,21 @@ return JSON.stringify(data, null, 4); } function parse(string) { - return JSON.parse(string); + try { + return JSON.parse(string); + } catch { + return {}; + } + } + function parseValidObject(string) { + const parsed = parse(string); + if (checkIsValidObject(parsed) == false) return null; + return parsed; } function localeCompare(a, b) { return a.localeCompare(b); } - // src/Model/Utility/typeSafety.ts - var DATA_VERSION = "v2"; - function checkIsValidObject(object) { - return object.dataVersion == DATA_VERSION; - } - // src/Model/storageModel.ts var PATH_COMPONENT_SEPARATOR = "\\"; var StorageModel = class _StorageModel { @@ -425,6 +434,24 @@ chatMessages: (id) => [DATA_VERSION, "chat", id, "messages"] }; + // src/Model/fileModel.ts + var FileModel = class { + chatModel; + // handler + handleStringifiedFile = (stringifiedFile) => { + const file = parseValidObject(stringifiedFile); + if (file == null) return; + }; + // methods + addFile = (file) => { + this.chatModel.sendMessage("", file); + }; + // init + constructor(chatModel) { + this.chatModel = chatModel; + } + }; + // src/Model/Utility/crypto.ts var IV_SIZE = 12; var ENCRYPTION_ALG = "AES-GCM"; @@ -516,6 +543,7 @@ storageModel; settingsModel; chatListModel; + fileModel; // data id; info; @@ -569,9 +597,12 @@ }; addMessage = async (chatMessage) => { await this.decryptMessage(chatMessage); - const messagePath = this.getMessagePath(chatMessage.id); - this.storageModel.writeStringifiable(messagePath, chatMessage); - this.chatMessageHandler(chatMessage); + if (chatMessage.body != "") { + const messagePath = this.getMessagePath(chatMessage.id); + this.storageModel.writeStringifiable(messagePath, chatMessage); + this.chatMessageHandler(chatMessage); + } + this.fileModel.handleStringifiedFile(chatMessage.stringifiedFile); }; // delete delete = () => { @@ -613,7 +644,7 @@ return sorted; } // messaging - sendMessage = async (body) => { + sendMessage = async (body, file) => { const senderName = this.settingsModel.username; if (senderName == "") return false; const allChannels = [this.info.primaryChannel]; @@ -621,20 +652,19 @@ allChannels.push(secondaryChannel); } const combinedChannel = allChannels.join("/"); - if (this.info.encryptionKey != "") { - body = await encryptString(body, this.info.encryptionKey); - } - const chatMessage = _ChatModel.createChatMessage( + const chatMessage = await _ChatModel.createChatMessage( combinedChannel, senderName, - body + this.info.encryptionKey, + body, + file ); this.addMessage(chatMessage); this.connectionModel.sendMessageOrStore(chatMessage); return true; }; handleMessage = (body) => { - const chatMessage = _ChatModel.parseMessage(body); + const chatMessage = parseValidObject(body); if (chatMessage == null) return; chatMessage.status = "received" /* Received */; this.addMessage(chatMessage); @@ -648,7 +678,12 @@ chatMessage.body, this.info.encryptionKey ); + const decryptedFile = await decryptString( + chatMessage.stringifiedFile ?? "", + this.info.encryptionKey + ); chatMessage.body = decryptedBody; + chatMessage.stringifiedFile = decryptedFile; }; setMessageHandler = (handler) => { this.chatMessageHandler = handler; @@ -667,6 +702,7 @@ this.loadColor(); this.subscribe(); connectionModel2.setMessageSentHandler(this.handleMessageSent); + this.fileModel = new FileModel(this); } // utility static generateChatInfo = (primaryChannel) => { @@ -677,25 +713,29 @@ hasUnreadMessages: false }; }; - static createChatMessage = (channel, sender, body) => { - return { + static createChatMessage = async (channel, sender, encryptionKey, body, file) => { + const chatMessage = { dataVersion: "v2", id: v4_default(), channel, sender, body, dateSent: createTimestamp(), - status: "outbox" /* Outbox */ + status: "outbox" /* Outbox */, + stringifiedFile: "" }; - }; - static parseMessage = (string) => { - try { - const parsed = parse(string); - if (checkIsValidObject(parsed) == false) return null; - return parsed; - } catch { - return null; + if (file != void 0) { + const stringifiedFile = stringify(file); + chatMessage.stringifiedFile = stringifiedFile; } + if (encryptionKey != "") { + chatMessage.body = await encryptString(chatMessage.body, encryptionKey); + chatMessage.stringifiedFile = await encryptString( + chatMessage.stringifiedFile, + encryptionKey + ); + } + return chatMessage; }; }; diff --git a/src/Model/Utility/utility.ts b/src/Model/Utility/utility.ts index 1eab1a66..f7ec6386 100644 --- a/src/Model/Utility/utility.ts +++ b/src/Model/Utility/utility.ts @@ -1,3 +1,5 @@ +import { checkIsValidObject } from "./typeSafety"; + // date export function createTimestamp(): string { return new Date().toISOString(); @@ -9,10 +11,20 @@ export function stringify(data: any): string { } export function parse(string: string): any { - return JSON.parse(string); + try { + return JSON.parse(string); + } catch { + return {}; + } +} + +export function parseValidObject(string: string): T|null { + const parsed: any = parse(string); + if (checkIsValidObject(parsed) == false) return null; + return parsed; } // sort export function localeCompare(a: string, b: string): number { return a.localeCompare(b); -} \ No newline at end of file +} diff --git a/src/Model/chatModel.ts b/src/Model/chatModel.ts index 5ea96edd..b5eb74c6 100644 --- a/src/Model/chatModel.ts +++ b/src/Model/chatModel.ts @@ -1,13 +1,18 @@ // this file is responsible for managing chats. +import FileModel, { File } from "./fileModel"; import StorageModel, { storageKeys } from "./storageModel"; -import { createTimestamp, parse } from "./Utility/utility"; +import { + createTimestamp, + parse, + parseValidObject, + stringify, +} from "./Utility/utility"; import { decryptString, encryptString } from "./Utility/crypto"; import ChatListModel from "./chatListModel"; import { Color } from "../ViewModel/colors"; import ConnectionModel from "./connectionModel"; -import FileModel from "./fileModel"; import SettingsModel from "./settingsModel"; import { checkIsValidObject } from "./Utility/typeSafety"; import { v4 } from "uuid"; @@ -85,9 +90,16 @@ export default class ChatModel { addMessage = async (chatMessage: ChatMessage): Promise => { await this.decryptMessage(chatMessage); - const messagePath: string[] = this.getMessagePath(chatMessage.id); - this.storageModel.writeStringifiable(messagePath, chatMessage); - this.chatMessageHandler(chatMessage); + + // message + if (chatMessage.body != "") { + const messagePath: string[] = this.getMessagePath(chatMessage.id); + this.storageModel.writeStringifiable(messagePath, chatMessage); + this.chatMessageHandler(chatMessage); + } + + // file + this.fileModel.handleStringifiedFile(chatMessage.stringifiedFile); }; // delete @@ -140,7 +152,7 @@ export default class ChatModel { } // messaging - sendMessage = async (body: string): Promise => { + sendMessage = async (body: string, file?: File): Promise => { const senderName = this.settingsModel.username; if (senderName == "") return false; @@ -150,14 +162,13 @@ export default class ChatModel { } const combinedChannel: string = allChannels.join("/"); - if (this.info.encryptionKey != "") { - body = await encryptString(body, this.info.encryptionKey); - } - const chatMessage: ChatMessage = ChatModel.createChatMessage( + const chatMessage: ChatMessage = await ChatModel.createChatMessage( combinedChannel, senderName, - body + this.info.encryptionKey, + body, + file ); this.addMessage(chatMessage); @@ -166,7 +177,7 @@ export default class ChatModel { }; handleMessage = (body: string): void => { - const chatMessage: ChatMessage | null = ChatModel.parseMessage(body); + const chatMessage: ChatMessage | null = parseValidObject(body); if (chatMessage == null) return; chatMessage.status = ChatMessageStatus.Received; @@ -183,7 +194,12 @@ export default class ChatModel { chatMessage.body, this.info.encryptionKey ); + const decryptedFile: string = await decryptString( + chatMessage.stringifiedFile ?? "", + this.info.encryptionKey + ); chatMessage.body = decryptedBody; + chatMessage.stringifiedFile = decryptedFile; }; setMessageHandler = (handler: (chatMessage: ChatMessage) => void): void => { @@ -227,12 +243,14 @@ export default class ChatModel { }; }; - static createChatMessage = ( + static createChatMessage = async ( channel: string, sender: string, - body: string - ): ChatMessage => { - return { + encryptionKey: string, + body: string, + file?: File + ): Promise => { + const chatMessage: ChatMessage = { dataVersion: "v2", id: v4(), @@ -243,17 +261,22 @@ export default class ChatModel { dateSent: createTimestamp(), status: ChatMessageStatus.Outbox, + stringifiedFile: "", }; - }; - - static parseMessage = (string: string): ChatMessage | null => { - try { - const parsed: any = parse(string); - if (checkIsValidObject(parsed) == false) return null; - return parsed; - } catch { - return null; + if (file != undefined) { + const stringifiedFile = stringify(file); + chatMessage.stringifiedFile = stringifiedFile; } + + if (encryptionKey != "") { + chatMessage.body = await encryptString(chatMessage.body, encryptionKey); + chatMessage.stringifiedFile = await encryptString( + chatMessage.stringifiedFile, + encryptionKey + ); + } + + return chatMessage; }; } @@ -284,5 +307,5 @@ export interface ChatMessage { status?: ChatMessageStatus; - stringifiedFile?: string; + stringifiedFile: string; } diff --git a/src/Model/fileModel.ts b/src/Model/fileModel.ts index ab459c85..3cb74fd2 100644 --- a/src/Model/fileModel.ts +++ b/src/Model/fileModel.ts @@ -1,10 +1,23 @@ // this file is responsible for managing files within chats. -import ChatModel from "./chatModel"; +import ChatModel, { ChatMessage } from "./chatModel"; + +import { parseValidObject } from "./Utility/utility"; export default class FileModel { chatModel: ChatModel; + // handler + handleStringifiedFile = (stringifiedFile: string): void => { + const file: File | null = parseValidObject(stringifiedFile); + if (file == null) return; + }; + + // methods + addFile = (file: File): void => { + this.chatModel.sendMessage("", file); + }; + // init constructor(chatModel: ChatModel) { this.chatModel = chatModel;