클라이언트가 시작될 때 삭제된 파일이나 디렉터리 정보를 IndexedDB에서 삭제하도록 개선

This commit is contained in:
static
2025-01-17 13:02:21 +09:00
parent 7aa6ba0eab
commit 620d174e9b
3 changed files with 54 additions and 4 deletions

View File

@@ -1,5 +1,5 @@
import type { ClientInit } from "@sveltejs/kit"; import type { ClientInit } from "@sveltejs/kit";
import { getClientKey, getMasterKeys, getHmacSecrets } from "$lib/indexedDB"; import { cleanupDanglingInfos, getClientKey, getMasterKeys, getHmacSecrets } from "$lib/indexedDB";
import { prepareFileCache } from "$lib/modules/file"; import { prepareFileCache } from "$lib/modules/file";
import { prepareOpfs } from "$lib/modules/opfs"; import { prepareOpfs } from "$lib/modules/opfs";
import { clientKeyStore, masterKeyStore, hmacSecretStore } from "$lib/stores"; import { clientKeyStore, masterKeyStore, hmacSecretStore } from "$lib/stores";
@@ -38,4 +38,6 @@ export const init: ClientInit = async () => {
prepareHmacSecretStore(), prepareHmacSecretStore(),
prepareOpfs(), prepareOpfs(),
]); ]);
cleanupDanglingInfos(); // Intended
}; };

View File

@@ -39,6 +39,10 @@ export const storeDirectoryInfo = async (directoryInfo: DirectoryInfo) => {
await filesystem.directory.put(directoryInfo); await filesystem.directory.put(directoryInfo);
}; };
export const deleteDirectoryInfo = async (id: number) => {
await filesystem.directory.delete(id);
};
export const getFileInfos = async (parentId: DirectoryId) => { export const getFileInfos = async (parentId: DirectoryId) => {
return await filesystem.file.where({ parentId }).toArray(); return await filesystem.file.where({ parentId }).toArray();
}; };
@@ -50,3 +54,33 @@ export const getFileInfo = async (id: number) => {
export const storeFileInfo = async (fileInfo: FileInfo) => { export const storeFileInfo = async (fileInfo: FileInfo) => {
await filesystem.file.put(fileInfo); await filesystem.file.put(fileInfo);
}; };
export const deleteFileInfo = async (id: number) => {
await filesystem.file.delete(id);
};
export const cleanupDanglingInfos = async () => {
const validDirectoryIds: number[] = [];
const validFileIds: number[] = [];
const queue: DirectoryId[] = ["root"];
while (true) {
const directoryId = queue.shift();
if (!directoryId) break;
const [subDirectories, files] = await Promise.all([
filesystem.directory.where({ parentId: directoryId }).toArray(),
filesystem.file.where({ parentId: directoryId }).toArray(),
]);
subDirectories.forEach(({ id }) => {
validDirectoryIds.push(id);
queue.push(id);
});
files.forEach(({ id }) => validFileIds.push(id));
}
await Promise.all([
filesystem.directory.where("id").noneOf(validDirectoryIds).delete(),
filesystem.file.where("id").noneOf(validFileIds).delete(),
]);
};

View File

@@ -4,9 +4,11 @@ import {
getDirectoryInfos as getDirectoryInfosFromIndexedDB, getDirectoryInfos as getDirectoryInfosFromIndexedDB,
getDirectoryInfo as getDirectoryInfoFromIndexedDB, getDirectoryInfo as getDirectoryInfoFromIndexedDB,
storeDirectoryInfo, storeDirectoryInfo,
deleteDirectoryInfo,
getFileInfos as getFileInfosFromIndexedDB, getFileInfos as getFileInfosFromIndexedDB,
getFileInfo as getFileInfoFromIndexedDB, getFileInfo as getFileInfoFromIndexedDB,
storeFileInfo, storeFileInfo,
deleteFileInfo,
type DirectoryId, type DirectoryId,
} from "$lib/indexedDB"; } from "$lib/indexedDB";
import { unwrapDataKey, decryptString } from "$lib/modules/crypto"; import { unwrapDataKey, decryptString } from "$lib/modules/crypto";
@@ -72,7 +74,13 @@ const fetchDirectoryInfoFromServer = async (
masterKey: CryptoKey, masterKey: CryptoKey,
) => { ) => {
const res = await callGetApi(`/api/directory/${id}`); const res = await callGetApi(`/api/directory/${id}`);
if (!res.ok) throw new Error("Failed to fetch directory information"); // TODO: Handle 404 if (res.status === 404) {
info.set(null);
await deleteDirectoryInfo(id as number);
} else if (!res.ok) {
throw new Error("Failed to fetch directory information");
}
const { const {
metadata, metadata,
subDirectories: subDirectoryIds, subDirectories: subDirectoryIds,
@@ -138,10 +146,16 @@ const fetchFileInfoFromServer = async (
masterKey: CryptoKey, masterKey: CryptoKey,
) => { ) => {
const res = await callGetApi(`/api/file/${id}`); const res = await callGetApi(`/api/file/${id}`);
if (!res.ok) throw new Error("Failed to fetch file information"); // TODO: Handle 404 if (res.status === 404) {
const metadata: FileInfoResponse = await res.json(); info.set(null);
await deleteFileInfo(id);
} else 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 { dataKey } = await unwrapDataKey(metadata.dek, masterKey);
const name = await decryptString(metadata.name, metadata.nameIv, dataKey); const name = await decryptString(metadata.name, metadata.nameIv, dataKey);
const createdAt = const createdAt =
metadata.createdAt && metadata.createdAtIv metadata.createdAt && metadata.createdAtIv