Merge branch 'dev' into refactor-to-atomic-patterns

This commit is contained in:
static
2025-01-29 00:02:57 +09:00
8 changed files with 34 additions and 15 deletions

View File

@@ -15,6 +15,7 @@ import type {
DuplicateFileScanRequest, DuplicateFileScanRequest,
DuplicateFileScanResponse, DuplicateFileScanResponse,
FileUploadRequest, FileUploadRequest,
FileUploadResponse,
} from "$lib/server/schemas"; } from "$lib/server/schemas";
import { import {
fileUploadStatusStore, fileUploadStatusStore,
@@ -131,7 +132,7 @@ const requestFileUpload = limitFunction(
return value; return value;
}); });
await axios.post("/api/file/upload", form, { const res = await axios.post("/api/file/upload", form, {
onUploadProgress: ({ progress, rate, estimated }) => { onUploadProgress: ({ progress, rate, estimated }) => {
status.update((value) => { status.update((value) => {
value.progress = progress; value.progress = progress;
@@ -141,11 +142,14 @@ const requestFileUpload = limitFunction(
}); });
}, },
}); });
const { file }: FileUploadResponse = res.data;
status.update((value) => { status.update((value) => {
value.status = "uploaded"; value.status = "uploaded";
return value; return value;
}); });
return { fileId: file };
}, },
{ concurrency: 1 }, { concurrency: 1 },
); );
@@ -156,7 +160,7 @@ export const uploadFile = async (
hmacSecret: HmacSecret, hmacSecret: HmacSecret,
masterKey: MasterKey, masterKey: MasterKey,
onDuplicate: () => Promise<boolean>, onDuplicate: () => Promise<boolean>,
) => { ): Promise<{ fileId: number; fileBuffer: ArrayBuffer } | undefined> => {
const status = writable<FileUploadStatus>({ const status = writable<FileUploadStatus>({
name: file.name, name: file.name,
parentId, parentId,
@@ -182,7 +186,7 @@ export const uploadFile = async (
value = value.filter((v) => v !== status); value = value.filter((v) => v !== status);
return value; return value;
}); });
return false; return undefined;
} }
const { const {
@@ -219,8 +223,8 @@ export const uploadFile = async (
form.set("content", new Blob([fileEncrypted.ciphertext])); form.set("content", new Blob([fileEncrypted.ciphertext]));
form.set("checksum", fileEncryptedHash); form.set("checksum", fileEncryptedHash);
await requestFileUpload(status, form); const { fileId } = await requestFileUpload(status, form);
return true; return { fileId, fileBuffer };
} catch (e) { } catch (e) {
status.update((value) => { status.update((value) => {
value.status = "error"; value.status = "error";

View File

@@ -50,7 +50,7 @@ export const createClient = async (encPubKey: string, sigPubKey: string, userId:
.insertInto("user_client") .insertInto("user_client")
.values({ user_id: userId, client_id: clientId }) .values({ user_id: userId, client_id: clientId })
.execute(); .execute();
return { clientId }; return { id: clientId };
}); });
}; };

View File

@@ -203,7 +203,7 @@ export const registerFile = async (params: NewFile) => {
throw new Error("Invalid arguments"); throw new Error("Invalid arguments");
} }
await db.transaction().execute(async (trx) => { return await db.transaction().execute(async (trx) => {
const mek = await trx const mek = await trx
.selectFrom("master_encryption_key") .selectFrom("master_encryption_key")
.select("version") .select("version")
@@ -259,6 +259,7 @@ export const registerFile = async (params: NewFile) => {
new_name: params.encName, new_name: params.encName,
}) })
.execute(); .execute();
return { id: fileId };
}); });
}; };

View File

@@ -60,3 +60,8 @@ export const fileUploadRequest = z.object({
lastModifiedAtIv: z.string().base64().nonempty(), lastModifiedAtIv: z.string().base64().nonempty(),
}); });
export type FileUploadRequest = z.infer<typeof fileUploadRequest>; export type FileUploadRequest = z.infer<typeof fileUploadRequest>;
export const fileUploadResponse = z.object({
file: z.number().int().positive(),
});
export type FileUploadResponse = z.infer<typeof fileUploadResponse>;

View File

@@ -63,7 +63,7 @@ export const registerUserClient = async (
} }
try { try {
const { clientId } = await createClient(encPubKey, sigPubKey, userId); const { id: clientId } = await createClient(encPubKey, sigPubKey, userId);
return { challenge: await createUserClientChallenge(ip, userId, clientId, encPubKey) }; return { challenge: await createUserClientChallenge(ip, userId, clientId, encPubKey) };
} catch (e) { } catch (e) {
if (e instanceof IntegrityError && e.message === "Public key(s) already registered") { if (e instanceof IntegrityError && e.message === "Public key(s) already registered") {

View File

@@ -131,11 +131,12 @@ export const uploadFile = async (
throw new Error("Invalid checksum"); throw new Error("Invalid checksum");
} }
await registerFile({ const { id: fileId } = await registerFile({
...params, ...params,
path, path,
encContentHash: hash, encContentHash: hash,
}); });
return { fileId };
} catch (e) { } catch (e) {
await safeUnlink(path); await safeUnlink(path);

View File

@@ -2,7 +2,7 @@ import { getContext, setContext } from "svelte";
import { callGetApi, callPostApi } from "$lib/hooks"; import { callGetApi, callPostApi } from "$lib/hooks";
import { storeHmacSecrets } from "$lib/indexedDB"; import { storeHmacSecrets } from "$lib/indexedDB";
import { generateDataKey, wrapDataKey, unwrapHmacSecret, encryptString } from "$lib/modules/crypto"; import { generateDataKey, wrapDataKey, unwrapHmacSecret, encryptString } from "$lib/modules/crypto";
import { deleteFileCache, uploadFile } from "$lib/modules/file"; import { storeFileCache, deleteFileCache, uploadFile } from "$lib/modules/file";
import type { import type {
DirectoryRenameRequest, DirectoryRenameRequest,
DirectoryCreateRequest, DirectoryCreateRequest,
@@ -77,7 +77,11 @@ export const requestFileUpload = async (
masterKey: MasterKey, masterKey: MasterKey,
onDuplicate: () => Promise<boolean>, onDuplicate: () => Promise<boolean>,
) => { ) => {
return await uploadFile(file, parentId, hmacSecret, masterKey, onDuplicate); const res = await uploadFile(file, parentId, hmacSecret, masterKey, onDuplicate);
if (!res) return false;
storeFileCache(res.fileId, res.fileBuffer); // Intended
return true;
}; };
export const requestEntryRename = async (entry: SelectedEntry, newName: string) => { export const requestEntryRename = async (entry: SelectedEntry, newName: string) => {

View File

@@ -1,8 +1,12 @@
import Busboy from "@fastify/busboy"; import Busboy from "@fastify/busboy";
import { error, text } from "@sveltejs/kit"; import { error, json } from "@sveltejs/kit";
import { Readable, Writable } from "stream"; import { Readable, Writable } from "stream";
import { authorize } from "$lib/server/modules/auth"; import { authorize } from "$lib/server/modules/auth";
import { fileUploadRequest } from "$lib/server/schemas"; import {
fileUploadRequest,
fileUploadResponse,
type FileUploadResponse,
} from "$lib/server/schemas";
import { uploadFile } from "$lib/server/services/file"; import { uploadFile } from "$lib/server/services/file";
import type { RequestHandler } from "./$types"; import type { RequestHandler } from "./$types";
@@ -87,8 +91,8 @@ export const POST: RequestHandler = async ({ locals, request }) => {
if (!metadata || content) error(400, "Invalid request body"); if (!metadata || content) error(400, "Invalid request body");
content = file; content = file;
await uploadFile(metadata, content, checksum); const { fileId } = await uploadFile(metadata, content, checksum);
resolve(text("File uploaded", { headers: { "Content-Type": "text/plain" } })); resolve(json(fileUploadResponse.parse({ file: fileId } satisfies FileUploadResponse)));
}), }),
); );
bb.on("finish", () => rejectChecksum(new Error("Invalid request body"))); bb.on("finish", () => rejectChecksum(new Error("Invalid request body")));