This commit is contained in:
rosetta
2026-01-30 05:01:05 +02:00
commit 83f38dc63f
327 changed files with 18725 additions and 0 deletions

View File

@@ -0,0 +1,198 @@
import { useContext, useEffect, useState } from "react";
import { useDownloadStatus } from "../TransportProvider/useDownloadStatus";
import { useUploadStatus } from "../TransportProvider/useUploadStatus";
import { useFileStorage } from "../../hooks/useFileStorage";
import { usePublicKey } from "../AccountProvider/usePublicKey";
import { usePrivatePlain } from "../AccountProvider/usePrivatePlain";
import { decodeWithPassword, encodeWithPassword, generateMd5 } from "../../crypto/crypto";
import { useTransport } from "../TransportProvider/useTransport";
import { useDialogsCache } from "../DialogProvider/useDialogsCache";
import { useConsoleLogger } from "../../hooks/useConsoleLogger";
import { Attachment, AttachmentType } from "../ProtocolProvider/protocol/packets/packet.message";
import { useMemory } from "../MemoryProvider/useMemory";
import { DialogContext } from "../DialogProvider/DialogProvider";
import { useSaveAvatar } from "../AvatarProvider/useSaveAvatar";
import { AVATAR_PASSWORD_TO_ENCODE } from "@/app/constants";
import { useDialog } from "../DialogProvider/useDialog";
export enum DownloadStatus {
DOWNLOADED,
NOT_DOWNLOADED,
PENDING,
DECRYPTING,
DOWNLOADING,
ERROR
}
export function useAttachment(attachment: Attachment, keyPlain: string) {
const uuidRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
const uploadedPercentage = useUploadStatus(attachment.id);
const downloadPercentage = useDownloadStatus(attachment.id);
const [downloadStatus, setDownloadStatus] = useMemory("attachment-downloaded-status-" + attachment.id, DownloadStatus.PENDING, true);
const [downloadTag, setDownloadTag] = useState("");
const {readFile, writeFile} = useFileStorage();
const { downloadFile } = useTransport();
const publicKey = usePublicKey();
const privatePlain = usePrivatePlain();
const {updateAttachmentInDialogCache} = useDialogsCache();
const {info} = useConsoleLogger('useAttachment');
const {updateAttachmentsInMessagesByAttachmentId} = useDialog();
const context = useContext(DialogContext);
if(!context) {
throw new Error("useAttachment must be used within a DialogProvider");
}
const {dialog} = context;
const saveAvatar = useSaveAvatar();
useEffect(() => {
calcDownloadStatus();
}, []);
const getPreview = () => {
if(attachment.preview.split("::")[0].match(uuidRegex)){
/**
* Это тег загрузки
*/
return attachment.preview.split("::").splice(1).join("::");
}
return attachment.preview;
}
const calcDownloadStatus = async () => {
if(attachment.preview.split("::")[0].match(uuidRegex)){
/**
* Это тег загрузки
*/
setDownloadTag(attachment.preview.split("::")[0]);
}
if(!attachment.preview.split("::")[0].match(uuidRegex)){
/**
* Там не тег загрузки, значит это наш файл
*/
setDownloadStatus(DownloadStatus.DOWNLOADED);
return;
}
if (downloadStatus == DownloadStatus.DOWNLOADED) {
return;
}
if(attachment.type == AttachmentType.FILE){
/**
* Если это файл, то он хранится не в папке медиа,
* а в загрузках
*/
const preview = getPreview();
const filename = preview.split("::")[1];
let pathInDownloads = window.downloadsPath + "/Rosetta Downloads/" + filename;
const fileData = await readFile(pathInDownloads, false);
if(fileData){
setDownloadStatus(DownloadStatus.DOWNLOADED);
return;
}
setDownloadStatus(DownloadStatus.NOT_DOWNLOADED);
return;
}
if(attachment.type == AttachmentType.AVATAR){
/**
* Если это аватар, то он хранится не в папке медиа,
* а в папке аватарок
*/
const fileData = await readFile(`a/${await generateMd5(attachment.id + publicKey)}`);
if(fileData){
setDownloadStatus(DownloadStatus.DOWNLOADED);
return;
}
setDownloadStatus(DownloadStatus.NOT_DOWNLOADED);
return;
}
const fileData = await readFile(`m/${await generateMd5(attachment.id + publicKey)}`);
if(fileData){
setDownloadStatus(DownloadStatus.DOWNLOADED);
return;
}
setDownloadStatus(DownloadStatus.NOT_DOWNLOADED);
}
const getBlob = async () => {
if(attachment.blob && attachment.blob != ""){
return attachment.blob;
}
const folder = (attachment.type == AttachmentType.AVATAR) ? "a" : "m";
const fileData = await readFile(`${folder}/${await generateMd5(attachment.id + publicKey)}`);
if (!fileData) {
return "";
}
const password = (attachment.type == AttachmentType.AVATAR) ? AVATAR_PASSWORD_TO_ENCODE : privatePlain;
const decryptedData = await decodeWithPassword(password, Buffer.from(fileData, 'binary').toString());
return decryptedData;
}
const download = async () => {
if(downloadStatus == DownloadStatus.DOWNLOADED){
return;
}
if (downloadTag == "") {
return;
}
setDownloadStatus(DownloadStatus.DOWNLOADING);
info("Downloading attachment: " + downloadTag);
let downloadedBlob = '';
try {
downloadedBlob = await downloadFile(attachment.id,
downloadTag);
} catch (e) {
console.info(e);
info("Error downloading attachment: " + attachment.id);
setDownloadStatus(DownloadStatus.ERROR);
return;
}
setDownloadStatus(DownloadStatus.DECRYPTING);
//console.info("Decrypted attachment ", Buffer.from(keyPlain, 'binary').toString('hex'));
const decrypted = await decodeWithPassword(keyPlain, downloadedBlob);
setDownloadTag("");
if(attachment.type == AttachmentType.FILE) {
/**
* Если это файл то шифрованную копию не пишем,
* пишем его сразу в загрузки
*/
const preview = getPreview();
const filename = preview.split("::")[1];
let buffer = Buffer.from(decrypted.split(",")[1], 'base64');
let pathInDownloads = window.downloadsPath + "/Rosetta Downloads/" + filename;
await writeFile(pathInDownloads, buffer, false);
setDownloadStatus(DownloadStatus.DOWNLOADED);
return;
}
if(attachment.type == AttachmentType.AVATAR) {
/**
* Аватарки, пишем их в папку аватарок
*/
const avatarPath = `a/${await generateMd5(attachment.id + publicKey)}`;
await writeFile(avatarPath,
Buffer.from(await encodeWithPassword(AVATAR_PASSWORD_TO_ENCODE, decrypted)));
setDownloadStatus(DownloadStatus.DOWNLOADED);
saveAvatar(dialog, avatarPath, decrypted);
return;
}
/**
* Если это не файл, то обновляем состояние кэша,
* и пишем шифрованную копию
*/
updateAttachmentInDialogCache(attachment.id, decrypted);
updateAttachmentsInMessagesByAttachmentId(attachment.id, decrypted);
await writeFile(`m/${await generateMd5(attachment.id + publicKey)}`,
Buffer.from(await encodeWithPassword(privatePlain, decrypted)).toString('binary'));
setDownloadStatus(DownloadStatus.DOWNLOADED);
}
return {
uploadedPercentage,
downloadPercentage,
downloadStatus,
getPreview,
getBlob,
download
};
}