pulsar-web/src/services/message/message.ts
2026-01-20 14:09:05 -05:00

175 lines
3.7 KiB
TypeScript

import {
fetchMessageApi,
createMessageApi,
updateMessageApi,
removeMessageApi,
} from "../../api/message";
import { deleteChannelMessage, setChannelMessage } from "../../store/channel";
import { deleteAttachment } from "../../store/file";
import { deleteMessage, setMessage } from "../../store/message";
import { state } from "../../store/state";
import {
base64ToBuffer,
bufferToBase64,
decryptData,
encryptData,
generateIv,
} from "../crypto";
import { fetchMedia } from "../file";
const fetchMessage = async (id: string, communityId: string) => {
const data = await fetchMessageApi({
id: id,
});
if (typeof data.error === "string") {
return;
}
try {
const decrypted = await decryptMessage(communityId, data.text, data.iv);
if (!decrypted) {
return;
}
setMessage({
...data,
text: decrypted,
});
} catch {}
data.attachments.forEach((attachmentId) => {
fetchMedia(communityId, attachmentId);
});
};
const createMessage = async (
communityId: string,
channelId: string,
text: string,
attachments: string[],
replyToId?: string,
) => {
const encrypted = await encryptMessage(communityId, text);
if (!encrypted) {
return;
}
const [encryptedMessage, iv] = encrypted;
const data = await createMessageApi({
text: encryptedMessage,
iv: iv,
channelId: channelId,
replyToId: replyToId,
attachments: attachments,
});
if (typeof data.error === "string") {
return;
}
setMessage({
...data,
text: text,
decryptionStatus: true,
});
attachments.forEach((attachmentId) => {
deleteAttachment(attachmentId);
});
};
const updateMessage = async (id: string, text: string, communityId: string) => {
const encrypted = await encryptMessage(communityId, text);
if (!encrypted) {
return;
}
const [encryptedMessage, iv] = encrypted;
const data = await updateMessageApi({
id: id,
iv: iv,
text: encryptedMessage,
});
if (typeof data.error === "string") {
return;
}
setMessage({
...data,
text: text,
decryptionStatus: true,
});
};
const removeMessage = async (id: string, channelId?: string) => {
const data = await removeMessageApi({
id: id,
});
if (typeof data.error === "string") {
return;
}
deleteMessage();
if (channelId) {
deleteChannelMessage(channelId, id);
}
};
const encryptMessage = async (
communityId: string,
text: string,
): Promise<[string, string] | undefined> => {
const key = state.community.communities[communityId]?.derivedKey;
if (!key) {
return;
}
const iv = generateIv();
if (text.length === 0) {
return ["", bufferToBase64(iv.buffer)];
}
const encrypted = await encryptData<string>({
key: key,
iv: iv,
data: text,
});
return [bufferToBase64(encrypted), bufferToBase64(iv.buffer)];
};
const decryptMessage = async (
communityId: string,
text: string,
iv: string,
): Promise<string | undefined> => {
const key = state.community.communities[communityId]?.derivedKey;
if (!key) {
return;
}
const ivBytes = base64ToBuffer(iv);
const textBytes = base64ToBuffer(text);
if (!ivBytes || !textBytes) {
return;
}
return await decryptData<string>({
key: key,
iv: new Uint8Array(ivBytes),
encryptedData: textBytes,
});
};
export {
fetchMessage,
createMessage,
updateMessage,
removeMessage,
encryptMessage,
decryptMessage,
};