mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-12 21:08:46 +00:00
보안에 큰 도움이 되지 않는다고 판단하여 삭제하였습니다. 판단 근거는 다음과 같습니다. 1. Web Crypto API는 HTTPS 환경에서만 사용할 수 있음 2. 프론트엔드와 백엔드가 하나의 서버에서 제공되므로, 리버스 프록시에 의한 중간자 공격을 받지 않는가에 대한 직관적인 검증이 불가능함 3. 신뢰할 수 없는 리버스 프록시는 애초에 사용하지 않는 것이 맞음 다만 MEK에 대한 서명 등은 그대로 유지됩니다.
182 lines
5.2 KiB
Svelte
182 lines
5.2 KiB
Svelte
<script module lang="ts">
|
|
export interface SelectedDiretoryEntry {
|
|
type: "directory" | "file";
|
|
id: number;
|
|
name: string;
|
|
}
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
import { goto } from "$app/navigation";
|
|
import { TopBar } from "$lib/components";
|
|
import { FloatingButton } from "$lib/components/buttons";
|
|
import { masterKeyStore } from "$lib/stores";
|
|
import CreateBottomSheet from "./CreateBottomSheet.svelte";
|
|
import CreateDirectoryModal from "./CreateDirectoryModal.svelte";
|
|
import DeleteDirectoryEntryModal from "./DeleteDirectoryEntryModal.svelte";
|
|
import DirectoryEntry from "./DirectoryEntry.svelte";
|
|
import DirectoryEntryMenuBottomSheet from "./DirectoryEntryMenuBottomSheet.svelte";
|
|
import RenameDirectoryEntryModal from "./RenameDirectoryEntryModal.svelte";
|
|
import {
|
|
decryptDirectroyMetadata,
|
|
decryptFileMetadata,
|
|
requestDirectroyCreation,
|
|
requestFileUpload,
|
|
} from "./service";
|
|
|
|
import IconAdd from "~icons/material-symbols/add";
|
|
|
|
let { data } = $props();
|
|
|
|
let fileInput: HTMLInputElement | undefined = $state();
|
|
let selectedEntry: SelectedDiretoryEntry | undefined = $state();
|
|
|
|
let isCreateBottomSheetOpen = $state(false);
|
|
let isCreateDirectoryModalOpen = $state(false);
|
|
|
|
let isDirectoryEntryMenuBottomSheetOpen = $state(false);
|
|
let isRenameDirectoryEntryModalOpen = $state(false);
|
|
let isDeleteDirectoryEntryModalOpen = $state(false);
|
|
|
|
// TODO: FIX ME
|
|
const metadata = $derived.by(() => {
|
|
const { metadata } = data;
|
|
if (metadata && $masterKeyStore) {
|
|
return decryptDirectroyMetadata(metadata, $masterKeyStore.get(metadata.mekVersion)!.key);
|
|
}
|
|
});
|
|
const subDirectories = $derived.by(() => {
|
|
const { subDirectories } = data;
|
|
if ($masterKeyStore) {
|
|
return Promise.all(
|
|
subDirectories.map(async (subDirectory) => {
|
|
const metadata = subDirectory.metadata!;
|
|
return {
|
|
...(await decryptDirectroyMetadata(
|
|
metadata,
|
|
$masterKeyStore.get(metadata.mekVersion)!.key,
|
|
)),
|
|
id: subDirectory.id,
|
|
};
|
|
}),
|
|
).then((subDirectories) => {
|
|
subDirectories.sort((a, b) => a.name.localeCompare(b.name));
|
|
return subDirectories;
|
|
});
|
|
}
|
|
});
|
|
const files = $derived.by(() => {
|
|
const { files } = data;
|
|
if ($masterKeyStore) {
|
|
return Promise.all(
|
|
files.map(async (file) => ({
|
|
...(await decryptFileMetadata(file!, $masterKeyStore.get(file.mekVersion)!.key)),
|
|
id: file.id,
|
|
})),
|
|
).then((files) => {
|
|
files.sort((a, b) => a.name.localeCompare(b.name));
|
|
return files;
|
|
});
|
|
}
|
|
});
|
|
|
|
const createDirectory = async (name: string) => {
|
|
await requestDirectroyCreation(name, data.id, $masterKeyStore?.get(1)!);
|
|
isCreateDirectoryModalOpen = false;
|
|
};
|
|
|
|
const uploadFile = () => {
|
|
const file = fileInput?.files?.[0];
|
|
if (!file) return;
|
|
|
|
requestFileUpload(file, data.id, $masterKeyStore?.get(1)!);
|
|
};
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<title>파일</title>
|
|
</svelte:head>
|
|
|
|
<input bind:this={fileInput} onchange={uploadFile} type="file" class="hidden" />
|
|
|
|
<div class="px-4">
|
|
{#if data.id !== "root"}
|
|
{#if !metadata}
|
|
<TopBar />
|
|
{:else}
|
|
{#await metadata}
|
|
<TopBar />
|
|
{:then metadata}
|
|
<TopBar title={metadata.name} />
|
|
{/await}
|
|
{/if}
|
|
{/if}
|
|
<div class="my-4 pb-[4.5rem]">
|
|
{#if subDirectories}
|
|
{#await subDirectories then subDirectories}
|
|
{#each subDirectories as { id, name }}
|
|
<DirectoryEntry
|
|
{name}
|
|
onclick={() => goto(`/directory/${id}`)}
|
|
onOpenMenuClick={() => {
|
|
selectedEntry = { type: "directory", id, name };
|
|
isDirectoryEntryMenuBottomSheetOpen = true;
|
|
}}
|
|
type="directory"
|
|
/>
|
|
{/each}
|
|
{/await}
|
|
{/if}
|
|
{#if files}
|
|
{#await files then files}
|
|
{#each files as { id, name }}
|
|
<DirectoryEntry
|
|
{name}
|
|
onclick={() => goto(`/file/${id}`)}
|
|
onOpenMenuClick={() => {
|
|
selectedEntry = { type: "file", id, name };
|
|
isDirectoryEntryMenuBottomSheetOpen = true;
|
|
}}
|
|
type="file"
|
|
/>
|
|
{/each}
|
|
{/await}
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<FloatingButton
|
|
icon={IconAdd}
|
|
onclick={() => {
|
|
isCreateBottomSheetOpen = true;
|
|
}}
|
|
/>
|
|
|
|
<CreateBottomSheet
|
|
bind:isOpen={isCreateBottomSheetOpen}
|
|
onDirectoryCreateClick={() => {
|
|
isCreateBottomSheetOpen = false;
|
|
isCreateDirectoryModalOpen = true;
|
|
}}
|
|
onFileUploadClick={() => {
|
|
isCreateBottomSheetOpen = false;
|
|
fileInput?.click();
|
|
}}
|
|
/>
|
|
<CreateDirectoryModal bind:isOpen={isCreateDirectoryModalOpen} onCreateClick={createDirectory} />
|
|
|
|
<DirectoryEntryMenuBottomSheet
|
|
bind:isOpen={isDirectoryEntryMenuBottomSheetOpen}
|
|
bind:selectedEntry
|
|
onRenameClick={() => {
|
|
isDirectoryEntryMenuBottomSheetOpen = false;
|
|
isRenameDirectoryEntryModalOpen = true;
|
|
}}
|
|
onDeleteClick={() => {
|
|
isDirectoryEntryMenuBottomSheetOpen = false;
|
|
isDeleteDirectoryEntryModalOpen = true;
|
|
}}
|
|
/>
|
|
<RenameDirectoryEntryModal bind:isOpen={isRenameDirectoryEntryModalOpen} bind:selectedEntry />
|
|
<DeleteDirectoryEntryModal bind:isOpen={isDeleteDirectoryEntryModalOpen} bind:selectedEntry />
|