From c25d42d51511e426931ad38e2888b1992094d5ef Mon Sep 17 00:00:00 2001 From: static Date: Thu, 9 Jan 2025 04:52:52 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9E=90=EC=9E=98=ED=95=9C=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=202=20=EB=B0=8F=20TopBar=EA=B0=80?= =?UTF-8?q?=20=EC=83=81=EB=8B=A8=EC=97=90=20=EA=B3=A0=EC=A0=95=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8D=98=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .prettierignore | 3 + README.md | 4 +- src/lib/components/TopBar.svelte | 2 +- src/lib/modules/file.ts | 32 +++++----- .../(fullscreen)/file/[id]/+page.svelte | 8 +-- .../(main)/directory/[[id]]/+page.svelte | 31 +++++----- .../DirectoryEntries/DirectoryEntries.svelte | 4 +- src/routes/(main)/directory/[[id]]/service.ts | 58 +++++++++---------- 8 files changed, 70 insertions(+), 72 deletions(-) diff --git a/.prettierignore b/.prettierignore index 0d5b39a..0f54b15 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,3 +5,6 @@ yarn.lock # Output /drizzle + +# Documents +*.md diff --git a/README.md b/README.md index c862ee0..f2d2028 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - πŸ”’ μ‚¬μš©μžμ˜ λ―Έλ””μ–΄λŠ” ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μ•”ν˜Έν™”ν•œ μƒνƒœλ‘œ μ €μž₯λΌμš”. - πŸ”‘ 메타 데이터도 ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μ•”ν˜Έν™”λΌμš”. - ⚠️ κ²€μƒ‰μ˜ μš©μ΄μ„±μ„ μœ„ν•΄, μŠ€ν‚€λ§ˆλŠ” μ•”ν˜Έν™”λ˜μ§€ μ•Šμ•„μš”. - - ⚠️ 파일의 MIME νƒ€μž…κ³Ό 같은 일뢀 메타 λ°μ΄ν„°λŠ” μ•”ν˜Έν™”λ˜μ§€ μ•Šμ•„μš”. + - ⚠️ 파일의 MIME νƒ€μž…κ³Ό 같은 일뢀 메타 λ°μ΄ν„°λŠ” μ•”ν˜Έν™”λ˜μ§€ μ•Šμ•„μš”. - πŸ“± μ—¬λŸ¬ λ””λ°”μ΄μŠ€μ—μ„œ λ™μ‹œμ— μ ‘κ·Όν•  수 μžˆμ–΄μš”. ## How to Install @@ -36,7 +36,7 @@ docker compose up --build -d |`JWT_REFRESH_TOKEN_EXPIRES`||`14d`|Refresh Token의 유효 μ‹œκ°„μ΄μ—μš”.| |`USER_CLIENT_CHALLENGE_EXPIRES`||`5m`|μ•”ν˜Έ ν‚€λ₯Ό μ„œλ²„μ— 처음 등둝할 λ•Œ μ‚¬μš©λ˜λŠ” μ±Œλ¦°μ§€μ˜ 유효 μ‹œκ°„μ΄μ—μš”.| |`TOKEN_UPGRADE_CHALLENGE_EXPIRES`||`5m`|μ•”ν˜Έ 킀와 ν•¨κ»˜ λ‘œκ·ΈμΈν•  λ•Œ μ‚¬μš©λ˜λŠ” μ±Œλ¦°μ§€μ˜ 유효 μ‹œκ°„μ΄μ—μš”.| -|`TRUST_PROXY`|||μ‹ λ’°ν•  수 μžˆλŠ” λ¦¬λ²„μŠ€ ν”„λ‘μ‹œμ˜ μˆ˜μ˜ˆμš”. μ„€μ •ν•  경우, 1 μ΄μƒμ˜ μ •μˆ˜λ‘œ μ„€μ •ν•΄ μ£Όμ„Έμš”. λ¦¬λ²„μŠ€ ν”„λ‘μ‹œμ—μ„œ `X-Forwarded-For` HTTP 헀더λ₯Ό μ˜¬λ°”λ₯΄κ²Œ μ„€μ •ν•˜λ„λ‘ ꡬ성해 μ£Όμ„Έμš”.| +|`TRUST_PROXY`|||μ‹ λ’°ν•  수 μžˆλŠ” λ¦¬λ²„μŠ€ ν”„λ‘μ‹œμ˜ μˆ˜μ˜ˆμš”. μ„€μ •ν•  경우 1 μ΄μƒμ˜ μ •μˆ˜λ‘œ μ„€μ •ν•΄ μ£Όμ„Έμš”. ν”„λ‘μ‹œμ—μ„œ `X-Forwarded-For` HTTP 헀더λ₯Ό μ˜¬λ°”λ₯΄κ²Œ μ„€μ •ν•˜λ„λ‘ ꡬ성해 μ£Όμ„Έμš”.| |`NODE_ENV`||`production`|ArkVault의 μ‚¬μš© μš©λ„μ˜ˆμš”. `production`인 경우, μ»¨ν…Œμ΄λ„ˆκ°€ 싀행될 λ•Œλ§ˆλ‹€ DB λ§ˆμ΄κ·Έλ ˆμ΄μ…˜μ΄ μžλ™μœΌλ‘œ μ‹€ν–‰λΌμš”.| |`PORT`||`80`|ArkVault μ„œλ²„μ˜ ν¬νŠΈμ˜ˆμš”.| |`CONTAINER_UID`||`0`|Docker μ»¨ν…Œμ΄λ„ˆμ— λ§€ν•‘ν•  UIDμ˜ˆμš”. NFS와 ν•¨κ»˜ μ‚¬μš©ν•  경우 섀정이 ν•„μš”ν•  수 μžˆμ–΄μš”.| diff --git a/src/lib/components/TopBar.svelte b/src/lib/components/TopBar.svelte index 9881d6d..6691feb 100644 --- a/src/lib/components/TopBar.svelte +++ b/src/lib/components/TopBar.svelte @@ -16,7 +16,7 @@ }); -
+
diff --git a/src/lib/modules/file.ts b/src/lib/modules/file.ts index e5e71a6..2e25399 100644 --- a/src/lib/modules/file.ts +++ b/src/lib/modules/file.ts @@ -1,4 +1,4 @@ -import { writable } from "svelte/store"; +import { writable, type Writable } from "svelte/store"; import { callGetApi } from "$lib/hooks"; import { unwrapDataKey, decryptString } from "$lib/modules/crypto"; import type { DirectoryInfoResponse, FileInfoResponse } from "$lib/server/schemas"; @@ -9,7 +9,11 @@ import { type FileInfo, } from "$lib/stores/file"; -const fetchDirectoryInfo = async (directoryId: "root" | number, masterKey: CryptoKey) => { +const fetchDirectoryInfo = async ( + directoryId: "root" | number, + masterKey: CryptoKey, + infoStore: Writable, +) => { const res = await callGetApi(`/api/directory/${directoryId}`); if (!res.ok) throw new Error("Failed to fetch directory information"); const { metadata, subDirectories, files }: DirectoryInfoResponse = await res.json(); @@ -33,12 +37,7 @@ const fetchDirectoryInfo = async (directoryId: "root" | number, masterKey: Crypt }; } - const info = directoryInfoStore.get(directoryId); - if (info) { - info.update(() => newInfo); - } else { - directoryInfoStore.set(directoryId, writable(newInfo)); - } + infoStore.update(() => newInfo); }; export const getDirectoryInfo = (directoryId: "root" | number, masterKey: CryptoKey) => { @@ -50,11 +49,15 @@ export const getDirectoryInfo = (directoryId: "root" | number, masterKey: Crypto directoryInfoStore.set(directoryId, info); } - fetchDirectoryInfo(directoryId, masterKey); + fetchDirectoryInfo(directoryId, masterKey, info); return info; }; -const fetchFileInfo = async (fileId: number, masterKey: CryptoKey) => { +const fetchFileInfo = async ( + fileId: number, + masterKey: CryptoKey, + infoStore: Writable, +) => { const res = await callGetApi(`/api/file/${fileId}`); if (!res.ok) throw new Error("Failed to fetch file information"); const metadata: FileInfoResponse = await res.json(); @@ -69,12 +72,7 @@ const fetchFileInfo = async (fileId: number, masterKey: CryptoKey) => { name: await decryptString(metadata.name, metadata.nameIv, dataKey), }; - const info = fileInfoStore.get(fileId); - if (info) { - info.update(() => newInfo); - } else { - fileInfoStore.set(fileId, writable(newInfo)); - } + infoStore.update(() => newInfo); }; export const getFileInfo = (fileId: number, masterKey: CryptoKey) => { @@ -86,6 +84,6 @@ export const getFileInfo = (fileId: number, masterKey: CryptoKey) => { fileInfoStore.set(fileId, info); } - fetchFileInfo(fileId, masterKey); + fetchFileInfo(fileId, masterKey, info); return info; }; diff --git a/src/routes/(fullscreen)/file/[id]/+page.svelte b/src/routes/(fullscreen)/file/[id]/+page.svelte index c5e822e..63e8a7c 100644 --- a/src/routes/(fullscreen)/file/[id]/+page.svelte +++ b/src/routes/(fullscreen)/file/[id]/+page.svelte @@ -67,11 +67,9 @@ 파일 -
-
- -
-
+
+ +
{#snippet viewerLoading(message: string)}

{message}

diff --git a/src/routes/(main)/directory/[[id]]/+page.svelte b/src/routes/(main)/directory/[[id]]/+page.svelte index 95d05db..ea67a0b 100644 --- a/src/routes/(main)/directory/[[id]]/+page.svelte +++ b/src/routes/(main)/directory/[[id]]/+page.svelte @@ -61,22 +61,23 @@
-
- {#if data.id !== "root"} - - {/if} -
+ {#if data.id !== "root"} + + {/if} {#if $info} - {#key $info} - goto(`/${type}/${id}`)} - onEntryMenuClick={(entry) => { - selectedEntry = entry; - isDirectoryEntryMenuBottomSheetOpen = true; - }} - /> - {/key} + {@const topMargin = data.id === "root" ? "mt-4" : ""} +
+ {#key $info} + goto(`/${type}/${id}`)} + onEntryMenuClick={(entry) => { + selectedEntry = entry; + isDirectoryEntryMenuBottomSheetOpen = true; + }} + /> + {/key} +
{/if}
diff --git a/src/routes/(main)/directory/[[id]]/DirectoryEntries/DirectoryEntries.svelte b/src/routes/(main)/directory/[[id]]/DirectoryEntries/DirectoryEntries.svelte index b3cd2dd..ea8a984 100644 --- a/src/routes/(main)/directory/[[id]]/DirectoryEntries/DirectoryEntries.svelte +++ b/src/routes/(main)/directory/[[id]]/DirectoryEntries/DirectoryEntries.svelte @@ -42,7 +42,7 @@ {#if info.subDirectoryIds.length + info.fileIds.length > 0} -
+
{#each subDirectoryInfos as subDirectory} {/each} @@ -51,7 +51,7 @@ {/each}
{:else} -
+

폴더가 λΉ„μ–΄ μžˆμ–΄μš”.

{/if} diff --git a/src/routes/(main)/directory/[[id]]/service.ts b/src/routes/(main)/directory/[[id]]/service.ts index 8f47262..3000080 100644 --- a/src/routes/(main)/directory/[[id]]/service.ts +++ b/src/routes/(main)/directory/[[id]]/service.ts @@ -1,11 +1,5 @@ import { callPostApi } from "$lib/hooks"; -import { - encodeToBase64, - generateDataKey, - wrapDataKey, - encryptData, - encryptString, -} from "$lib/modules/crypto"; +import { generateDataKey, wrapDataKey, encryptData, encryptString } from "$lib/modules/crypto"; import type { DirectoryRenameRequest, DirectoryCreateRequest, @@ -28,42 +22,46 @@ export const requestDirectoryCreation = async ( masterKey: MasterKey, ) => { const { dataKey, dataKeyVersion } = await generateDataKey(); - const nameEncrypted = await encryptData(new TextEncoder().encode(name), dataKey); + const nameEncrypted = await encryptString(name, dataKey); await callPostApi("/api/directory/create", { parentId, mekVersion: masterKey.version, dek: await wrapDataKey(dataKey, masterKey.key), dekVersion: dataKeyVersion.toISOString(), - name: encodeToBase64(nameEncrypted.ciphertext), + name: nameEncrypted.ciphertext, nameIv: nameEncrypted.iv, }); }; -export const requestFileUpload = (file: File, parentId: "root" | number, masterKey: MasterKey) => { - return new Promise(async (resolve, reject) => { - const { dataKey, dataKeyVersion } = await generateDataKey(); - const fileEncrypted = await encryptData(await file.arrayBuffer(), dataKey); - const nameEncrypted = await encryptString(file.name, dataKey); +export const requestFileUpload = async ( + file: File, + parentId: "root" | number, + masterKey: MasterKey, +) => { + 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])); + 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])); + return new Promise((resolve, reject) => { // TODO: Progress, Scheduling, ... - const xhr = new XMLHttpRequest(); + const xhr = new XMLHttpRequest(); xhr.addEventListener("load", () => { if (xhr.status === 200) { resolve();