프론트엔드에서의 파일 업로드 임시 구현

This commit is contained in:
static
2025-01-04 23:19:44 +09:00
parent a62d44038a
commit 9b14e833be
5 changed files with 58 additions and 4 deletions

View File

@@ -9,6 +9,7 @@ node_modules
/.svelte-kit /.svelte-kit
/build /build
/data /data
/library
# OS # OS
.DS_Store .DS_Store

1
.gitignore vendored
View File

@@ -8,6 +8,7 @@ node_modules
/.svelte-kit /.svelte-kit
/build /build
/data /data
/library
# OS # OS
.DS_Store .DS_Store

View File

@@ -5,12 +5,14 @@
import CreateBottomSheet from "./CreateBottomSheet.svelte"; import CreateBottomSheet from "./CreateBottomSheet.svelte";
import CreateDirectoryModal from "./CreateDirectoryModal.svelte"; import CreateDirectoryModal from "./CreateDirectoryModal.svelte";
import DirectoryEntry from "./DirectoryEntry.svelte"; import DirectoryEntry from "./DirectoryEntry.svelte";
import { decryptDirectroyMetadata, requestDirectroyCreation } from "./service"; import { decryptDirectroyMetadata, requestDirectroyCreation, requestFileUpload } from "./service";
import IconAdd from "~icons/material-symbols/add"; import IconAdd from "~icons/material-symbols/add";
let { data } = $props(); let { data } = $props();
let fileInput: HTMLInputElement | undefined = $state();
let isCreateBottomSheetOpen = $state(false); let isCreateBottomSheetOpen = $state(false);
let isCreateDirectoryModalOpen = $state(false); let isCreateDirectoryModalOpen = $state(false);
@@ -51,12 +53,21 @@
); );
isCreateDirectoryModalOpen = false; isCreateDirectoryModalOpen = false;
}; };
const uploadFile = () => {
const file = fileInput?.files?.[0];
if (!file) return;
requestFileUpload(file, data.id, $masterKeyStore?.get(1)!, $clientKeyStore?.signKey!);
};
</script> </script>
<svelte:head> <svelte:head>
<title>파일</title> <title>파일</title>
</svelte:head> </svelte:head>
<input bind:this={fileInput} onchange={uploadFile} type="file" class="hidden" />
<div class="px-4"> <div class="px-4">
{#if data.id !== "root"} {#if data.id !== "root"}
{#if !metadata} {#if !metadata}
@@ -95,7 +106,7 @@
}} }}
onFileUpload={() => { onFileUpload={() => {
isCreateBottomSheetOpen = false; isCreateBottomSheetOpen = false;
// TODO fileInput?.click();
}} }}
/> />
<CreateDirectoryModal bind:isOpen={isCreateDirectoryModalOpen} onCreateClick={createDirectory} /> <CreateDirectoryModal bind:isOpen={isCreateDirectoryModalOpen} onCreateClick={createDirectory} />

View File

@@ -15,7 +15,7 @@
</script> </script>
<BottomSheet bind:isOpen> <BottomSheet bind:isOpen>
<div class="flex w-full flex-col"> <div class="flex w-full flex-col py-4">
<EntryButton onclick={onDirectoryCreate}> <EntryButton onclick={onDirectoryCreate}>
<div class="flex h-12 items-center justify-center gap-x-4"> <div class="flex h-12 items-center justify-center gap-x-4">
<IconCreateNewFolder class="text-2xl text-yellow-500" /> <IconCreateNewFolder class="text-2xl text-yellow-500" />

View File

@@ -7,8 +7,14 @@ import {
unwrapDataKey, unwrapDataKey,
encryptData, encryptData,
decryptData, decryptData,
digestMessage,
signRequestBody,
} from "$lib/modules/crypto"; } from "$lib/modules/crypto";
import type { DirectroyInfoResponse, DirectoryCreateRequest } from "$lib/server/schemas"; import type {
DirectroyInfoResponse,
DirectoryCreateRequest,
FileUploadRequest,
} from "$lib/server/schemas";
import type { MasterKey } from "$lib/stores"; import type { MasterKey } from "$lib/stores";
export const decryptDirectroyMetadata = async ( export const decryptDirectroyMetadata = async (
@@ -43,3 +49,38 @@ export const requestDirectroyCreation = async (
signKey, signKey,
); );
}; };
export const requestFileUpload = async (
file: File,
parentId: "root" | number,
masterKey: MasterKey,
signKey: CryptoKey,
) => {
const { dataKey } = await generateDataKey();
const fileEncrypted = await encryptData(await file.arrayBuffer(), dataKey);
const fileEncryptedHash = await digestMessage(fileEncrypted.ciphertext);
const nameEncrypted = await encryptData(new TextEncoder().encode(file.name), dataKey);
const form = new FormData();
form.set(
"metadata",
await signRequestBody<FileUploadRequest>(
{
parentId,
mekVersion: masterKey.version,
dek: await wrapDataKey(dataKey, masterKey.key),
contentHash: encodeToBase64(fileEncryptedHash),
contentIv: fileEncrypted.iv,
name: encodeToBase64(nameEncrypted.ciphertext),
nameIv: nameEncrypted.iv,
},
signKey,
),
);
form.set("content", new Blob([fileEncrypted.ciphertext]));
// TODO: Progress, Scheduling, ...
const xhr = new XMLHttpRequest();
xhr.open("POST", "/api/file/upload");
xhr.send(form);
};