mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-14 22:08:45 +00:00
로그인할 때마다 다른 디바이스에서 삭제된 파일을 스캔하여 현재 디바이스에서도 삭제하도록 구현
This commit is contained in:
@@ -55,6 +55,10 @@ export const deleteDirectoryInfo = async (id: number) => {
|
|||||||
await filesystem.directory.delete(id);
|
await filesystem.directory.delete(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getAllFileInfos = async () => {
|
||||||
|
return await filesystem.file.toArray();
|
||||||
|
};
|
||||||
|
|
||||||
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();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -341,6 +341,11 @@ export const getAllFilesByCategory = async (
|
|||||||
return files.map(({ file_id, depth }) => ({ id: file_id, isRecursive: depth > 0 }));
|
return files.map(({ file_id, depth }) => ({ id: file_id, isRecursive: depth > 0 }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getAllFileIds = async (userId: number) => {
|
||||||
|
const files = await db.selectFrom("file").select("id").where("user_id", "=", userId).execute();
|
||||||
|
return files.map(({ id }) => id);
|
||||||
|
};
|
||||||
|
|
||||||
export const getAllFileIdsByContentHmac = async (
|
export const getAllFileIdsByContentHmac = async (
|
||||||
userId: number,
|
userId: number,
|
||||||
hskVersion: number,
|
hskVersion: number,
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ export const fileThumbnailUploadRequest = z.object({
|
|||||||
});
|
});
|
||||||
export type FileThumbnailUploadRequest = z.input<typeof fileThumbnailUploadRequest>;
|
export type FileThumbnailUploadRequest = z.input<typeof fileThumbnailUploadRequest>;
|
||||||
|
|
||||||
|
export const fileListResponse = z.object({
|
||||||
|
files: z.number().int().positive().array(),
|
||||||
|
});
|
||||||
|
export type FileListResponse = z.output<typeof fileListResponse>;
|
||||||
|
|
||||||
export const duplicateFileScanRequest = z.object({
|
export const duplicateFileScanRequest = z.object({
|
||||||
hskVersion: z.number().int().positive(),
|
hskVersion: z.number().int().positive(),
|
||||||
contentHmac: z.string().base64().nonempty(),
|
contentHmac: z.string().base64().nonempty(),
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { v4 as uuidv4 } from "uuid";
|
|||||||
import { IntegrityError } from "$lib/server/db/error";
|
import { IntegrityError } from "$lib/server/db/error";
|
||||||
import {
|
import {
|
||||||
registerFile,
|
registerFile,
|
||||||
|
getAllFileIds,
|
||||||
getAllFileIdsByContentHmac,
|
getAllFileIdsByContentHmac,
|
||||||
getFile,
|
getFile,
|
||||||
setFileEncName,
|
setFileEncName,
|
||||||
@@ -148,6 +149,11 @@ export const uploadFileThumbnail = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getFileList = async (userId: number) => {
|
||||||
|
const fileIds = await getAllFileIds(userId);
|
||||||
|
return { files: fileIds };
|
||||||
|
};
|
||||||
|
|
||||||
export const scanDuplicateFiles = async (
|
export const scanDuplicateFiles = async (
|
||||||
userId: number,
|
userId: number,
|
||||||
hskVersion: number,
|
hskVersion: number,
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
import { callGetApi } from "$lib/hooks";
|
import { callGetApi } from "$lib/hooks";
|
||||||
|
import { getAllFileInfos } from "$lib/indexedDB/filesystem";
|
||||||
import { decryptData } from "$lib/modules/crypto";
|
import { decryptData } from "$lib/modules/crypto";
|
||||||
import {
|
import {
|
||||||
getFileCache,
|
getFileCache,
|
||||||
storeFileCache,
|
storeFileCache,
|
||||||
|
deleteFileCache,
|
||||||
getFileThumbnailCache,
|
getFileThumbnailCache,
|
||||||
storeFileThumbnailCache,
|
storeFileThumbnailCache,
|
||||||
|
deleteFileThumbnailCache,
|
||||||
downloadFile,
|
downloadFile,
|
||||||
} from "$lib/modules/file";
|
} from "$lib/modules/file";
|
||||||
import { getThumbnailUrl } from "$lib/modules/thumbnail";
|
import { getThumbnailUrl } from "$lib/modules/thumbnail";
|
||||||
import type { FileThumbnailInfoResponse } from "$lib/server/schemas";
|
import type { FileThumbnailInfoResponse, FileListResponse } from "$lib/server/schemas";
|
||||||
|
|
||||||
export const requestFileDownload = async (
|
export const requestFileDownload = async (
|
||||||
fileId: number,
|
fileId: number,
|
||||||
@@ -41,3 +44,18 @@ export const requestFileThumbnailDownload = async (fileId: number, dataKey: Cryp
|
|||||||
storeFileThumbnailCache(fileId, thumbnailBuffer); // Intended
|
storeFileThumbnailCache(fileId, thumbnailBuffer); // Intended
|
||||||
return getThumbnailUrl(thumbnailBuffer);
|
return getThumbnailUrl(thumbnailBuffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const requestDeletedFilesCleanup = async () => {
|
||||||
|
const res = await callGetApi("/api/file/list");
|
||||||
|
if (!res.ok) return;
|
||||||
|
|
||||||
|
const { files: liveFiles }: FileListResponse = await res.json();
|
||||||
|
const liveFilesSet = new Set(liveFiles);
|
||||||
|
const maybeCachedFiles = await getAllFileInfos();
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
maybeCachedFiles
|
||||||
|
.filter(({ id }) => !liveFilesSet.has(id))
|
||||||
|
.flatMap(({ id }) => [deleteFileCache(id), deleteFileThumbnailCache(id)]),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
requestLogin,
|
requestLogin,
|
||||||
requestClientRegistrationAndSessionUpgrade,
|
requestClientRegistrationAndSessionUpgrade,
|
||||||
requestMasterKeyDownload,
|
requestMasterKeyDownload,
|
||||||
|
requestDeletedFilesCleanup,
|
||||||
} from "./service";
|
} from "./service";
|
||||||
|
|
||||||
let { data } = $props();
|
let { data } = $props();
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
$masterKeyStore ||
|
$masterKeyStore ||
|
||||||
(await requestMasterKeyDownload($clientKeyStore!.decryptKey, $clientKeyStore!.verifyKey))
|
(await requestMasterKeyDownload($clientKeyStore!.decryptKey, $clientKeyStore!.verifyKey))
|
||||||
) {
|
) {
|
||||||
|
await requestDeletedFilesCleanup();
|
||||||
await goto(data.redirectPath);
|
await goto(data.redirectPath);
|
||||||
} else {
|
} else {
|
||||||
await redirect("/client/pending");
|
await redirect("/client/pending");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { callPostApi } from "$lib/hooks";
|
|||||||
import type { LoginRequest } from "$lib/server/schemas";
|
import type { LoginRequest } from "$lib/server/schemas";
|
||||||
|
|
||||||
export { requestLogout } from "$lib/services/auth";
|
export { requestLogout } from "$lib/services/auth";
|
||||||
|
export { requestDeletedFilesCleanup } from "$lib/services/file";
|
||||||
export {
|
export {
|
||||||
requestClientRegistrationAndSessionUpgrade,
|
requestClientRegistrationAndSessionUpgrade,
|
||||||
requestMasterKeyDownload,
|
requestMasterKeyDownload,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
importClientKeys,
|
importClientKeys,
|
||||||
requestClientRegistrationAndSessionUpgrade,
|
requestClientRegistrationAndSessionUpgrade,
|
||||||
requestInitialMasterKeyAndHmacSecretRegistration,
|
requestInitialMasterKeyAndHmacSecretRegistration,
|
||||||
|
requestDeletedFilesCleanup,
|
||||||
} from "./service";
|
} from "./service";
|
||||||
|
|
||||||
import IconKey from "~icons/material-symbols/key";
|
import IconKey from "~icons/material-symbols/key";
|
||||||
@@ -104,6 +105,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await requestDeletedFilesCleanup();
|
||||||
await goto("/client/pending?redirect=" + encodeURIComponent(data.redirectPath));
|
await goto("/client/pending?redirect=" + encodeURIComponent(data.redirectPath));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { deserializeClientKeys } from "$lib/modules/key";
|
|||||||
import { clientKeyStore } from "$lib/stores";
|
import { clientKeyStore } from "$lib/stores";
|
||||||
|
|
||||||
export { requestLogout } from "$lib/services/auth";
|
export { requestLogout } from "$lib/services/auth";
|
||||||
|
export { requestDeletedFilesCleanup } from "$lib/services/file";
|
||||||
export {
|
export {
|
||||||
requestClientRegistrationAndSessionUpgrade,
|
requestClientRegistrationAndSessionUpgrade,
|
||||||
requestInitialMasterKeyAndHmacSecretRegistration,
|
requestInitialMasterKeyAndHmacSecretRegistration,
|
||||||
|
|||||||
11
src/routes/api/file/list/+server.ts
Normal file
11
src/routes/api/file/list/+server.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { json } from "@sveltejs/kit";
|
||||||
|
import { authorize } from "$lib/server/modules/auth";
|
||||||
|
import { fileListResponse, type FileListResponse } from "$lib/server/schemas";
|
||||||
|
import { getFileList } from "$lib/server/services/file";
|
||||||
|
import type { RequestHandler } from "./$types";
|
||||||
|
|
||||||
|
export const GET: RequestHandler = async ({ locals }) => {
|
||||||
|
const { userId } = await authorize(locals, "activeClient");
|
||||||
|
const { files } = await getFileList(userId);
|
||||||
|
return json(fileListResponse.parse({ files } satisfies FileListResponse));
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user