파일/디렉터리 목록 캐싱 추가

This commit is contained in:
static
2025-01-06 19:19:43 +09:00
parent 47850e1421
commit 10b7472ee9
13 changed files with 293 additions and 241 deletions

90
src/lib/modules/file.ts Normal file
View File

@@ -0,0 +1,90 @@
import { writable } from "svelte/store";
import { callGetApi } from "$lib/hooks";
import { unwrapDataKey, decryptString } from "$lib/modules/crypto";
import type { DirectoryInfoResponse, FileInfoResponse } from "$lib/server/schemas";
import {
directoryInfoStore,
fileInfoStore,
type DirectoryInfo,
type FileInfo,
} from "$lib/stores/file";
const fetchDirectoryInfo = async (directoryId: "root" | number, masterKey: CryptoKey) => {
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();
let newInfo: DirectoryInfo;
if (directoryId === "root") {
newInfo = {
id: "root",
subDirectoryIds: subDirectories,
fileIds: files,
};
} else {
const { dataKey } = await unwrapDataKey(metadata!.dek, masterKey);
newInfo = {
id: directoryId,
dataKey,
dataKeyVersion: metadata!.dekVersion,
name: await decryptString(metadata!.name, metadata!.nameIv, dataKey),
subDirectoryIds: subDirectories,
fileIds: files,
};
}
const info = directoryInfoStore.get(directoryId);
if (info) {
info.update(() => newInfo);
} else {
directoryInfoStore.set(directoryId, writable(newInfo));
}
};
export const getDirectoryInfo = (directoryId: "root" | number, masterKey: CryptoKey) => {
// TODO: MEK rotation
let info = directoryInfoStore.get(directoryId);
if (!info) {
info = writable(null);
directoryInfoStore.set(directoryId, info);
}
fetchDirectoryInfo(directoryId, masterKey);
return info;
};
const fetchFileInfo = async (fileId: number, masterKey: CryptoKey) => {
const res = await callGetApi(`/api/file/${fileId}`);
if (!res.ok) throw new Error("Failed to fetch file information");
const metadata: FileInfoResponse = await res.json();
const { dataKey } = await unwrapDataKey(metadata.dek, masterKey);
const newInfo: FileInfo = {
id: fileId,
dataKey,
dataKeyVersion: metadata.dekVersion,
contentIv: metadata.contentIv,
name: await decryptString(metadata.name, metadata.nameIv, dataKey),
};
const info = fileInfoStore.get(fileId);
if (info) {
info.update(() => newInfo);
} else {
fileInfoStore.set(fileId, writable(newInfo));
}
};
export const getFileInfo = (fileId: number, masterKey: CryptoKey) => {
// TODO: MEK rotation
let info = fileInfoStore.get(fileId);
if (!info) {
info = writable(null);
fileInfoStore.set(fileId, info);
}
fetchFileInfo(fileId, masterKey);
return info;
};

View File

@@ -1,11 +0,0 @@
import { unwrapDataKey, decryptString } from "$lib/modules/crypto";
import type { FileInfoResponse } from "$lib/server/schemas";
export const decryptFileMetadata = async (metadata: FileInfoResponse, masterKey: CryptoKey) => {
const { dataKey } = await unwrapDataKey(metadata.dek, masterKey);
return {
dataKey,
dataKeyVersion: metadata.dekVersion,
name: await decryptString(metadata.name, metadata.nameIv, dataKey),
};
};

30
src/lib/stores/file.ts Normal file
View File

@@ -0,0 +1,30 @@
import type { Writable } from "svelte/store";
export type DirectoryInfo =
| {
id: "root";
dataKey?: undefined;
dataKeyVersion?: undefined;
name?: undefined;
subDirectoryIds: number[];
fileIds: number[];
}
| {
id: number;
dataKey: CryptoKey;
dataKeyVersion: Date;
name: string;
subDirectoryIds: number[];
fileIds: number[];
};
export interface FileInfo {
id: number;
dataKey: CryptoKey;
dataKeyVersion: Date;
contentIv: string;
name: string;
}
export const directoryInfoStore = new Map<"root" | number, Writable<DirectoryInfo | null>>();
export const fileInfoStore = new Map<number, Writable<FileInfo | null>>();

View File

@@ -1 +1,2 @@
export * from "./file";
export * from "./key";