Files
arkvault/src/routes/(main)/directory/[[id]]/service.ts
static d7396945df Date 관련 Zod 스키마 수정
z.coerce.date()가 아닌 z.string().datetime()을 사용하도록 변경하여, 번거롭더라도 버그를 줄일 수 있는 방향으로 수정하였습니다.
2025-01-08 22:08:20 +09:00

104 lines
3.0 KiB
TypeScript

import { callPostApi } from "$lib/hooks";
import {
encodeToBase64,
generateDataKey,
wrapDataKey,
encryptData,
encryptString,
} from "$lib/modules/crypto";
import type {
DirectoryRenameRequest,
DirectoryCreateRequest,
FileRenameRequest,
FileUploadRequest,
} from "$lib/server/schemas";
import type { MasterKey } from "$lib/stores";
export interface SelectedDirectoryEntry {
type: "directory" | "file";
id: number;
dataKey: CryptoKey;
dataKeyVersion: Date;
name: string;
}
export const requestDirectoryCreation = async (
name: string,
parentId: "root" | number,
masterKey: MasterKey,
) => {
const { dataKey, dataKeyVersion } = await generateDataKey();
const nameEncrypted = await encryptData(new TextEncoder().encode(name), dataKey);
await callPostApi<DirectoryCreateRequest>("/api/directory/create", {
parentId,
mekVersion: masterKey.version,
dek: await wrapDataKey(dataKey, masterKey.key),
dekVersion: dataKeyVersion.toISOString(),
name: encodeToBase64(nameEncrypted.ciphertext),
nameIv: nameEncrypted.iv,
});
};
export const requestFileUpload = (file: File, parentId: "root" | number, masterKey: MasterKey) => {
return new Promise<void>(async (resolve, reject) => {
const { dataKey, dataKeyVersion } = await generateDataKey();
const fileEncrypted = await encryptData(await file.arrayBuffer(), dataKey);
const nameEncrypted = await encryptString(file.name, dataKey);
const form = new FormData();
form.set(
"metadata",
JSON.stringify({
parentId,
mekVersion: masterKey.version,
dek: await wrapDataKey(dataKey, masterKey.key),
dekVersion: dataKeyVersion.toISOString(),
contentType: file.type,
contentIv: fileEncrypted.iv,
name: nameEncrypted.ciphertext,
nameIv: nameEncrypted.iv,
} satisfies FileUploadRequest),
);
form.set("content", new Blob([fileEncrypted.ciphertext]));
// TODO: Progress, Scheduling, ...
const xhr = new XMLHttpRequest();
xhr.addEventListener("load", () => {
if (xhr.status === 200) {
resolve();
} else {
reject(new Error(xhr.responseText));
}
});
xhr.open("POST", "/api/file/upload");
xhr.send(form);
});
};
export const requestDirectoryEntryRename = async (
entry: SelectedDirectoryEntry,
newName: string,
) => {
const newNameEncrypted = await encryptString(newName, entry.dataKey);
if (entry.type === "directory") {
await callPostApi<DirectoryRenameRequest>(`/api/directory/${entry.id}/rename`, {
dekVersion: entry.dataKeyVersion.toISOString(),
name: newNameEncrypted.ciphertext,
nameIv: newNameEncrypted.iv,
});
} else {
await callPostApi<FileRenameRequest>(`/api/file/${entry.id}/rename`, {
dekVersion: entry.dataKeyVersion.toISOString(),
name: newNameEncrypted.ciphertext,
nameIv: newNameEncrypted.iv,
});
}
};
export const requestDirectoryEntryDeletion = async (entry: SelectedDirectoryEntry) => {
await callPostApi(`/api/${entry.type}/${entry.id}/delete`);
};