사소한 리팩토링

This commit is contained in:
static
2026-01-12 20:50:19 +09:00
parent 00b9858db7
commit a4912c8952
21 changed files with 132 additions and 180 deletions

View File

@@ -19,13 +19,13 @@ export const generateHmacSecret = async () => {
};
export const signMessageHmac = async (message: Blob, hmacSecret: CryptoKey) => {
const worker = new HmacWorker();
const stream = message.stream();
const hmacSecretRaw = new Uint8Array(await crypto.subtle.exportKey("raw", hmacSecret));
const worker = new HmacWorker();
return new Promise<Uint8Array>((resolve, reject) => {
worker.onmessage = (event: MessageEvent<ResultMessage>) => {
resolve(event.data.result);
worker.onmessage = ({ data }: MessageEvent<ResultMessage>) => {
resolve(data.result);
worker.terminate();
};

View File

@@ -1,6 +1,6 @@
import axios from "axios";
import { limitFunction } from "p-limit";
import { CHUNK_SIZE, ENCRYPTION_OVERHEAD } from "$lib/constants";
import { ENCRYPTED_CHUNK_SIZE } from "$lib/constants";
import { decryptChunk, concatenateBuffers } from "$lib/modules/crypto";
export interface FileDownloadState {
@@ -100,7 +100,7 @@ export const downloadFile = async (id: number, dataKey: CryptoKey, isLegacy: boo
return await decryptFile(
state,
fileEncrypted,
isLegacy ? fileEncrypted.byteLength : CHUNK_SIZE + ENCRYPTION_OVERHEAD,
isLegacy ? fileEncrypted.byteLength : ENCRYPTED_CHUNK_SIZE,
dataKey,
);
} catch (e) {

View File

@@ -1,7 +1,7 @@
import { LRUCache } from "lru-cache";
import { writable, type Writable } from "svelte/store";
import { browser } from "$app/environment";
import { decryptData } from "$lib/modules/crypto";
import { decryptChunk } from "$lib/modules/crypto";
import type { SummarizedFileInfo } from "$lib/modules/filesystem";
import { readFile, writeFile, deleteFile, deleteDirectory } from "$lib/modules/opfs";
import { getThumbnailUrl } from "$lib/modules/thumbnail";
@@ -20,12 +20,7 @@ const fetchFromServer = async (fileId: number, dataKey: CryptoKey) => {
const res = await fetch(`/api/file/${fileId}/thumbnail/download`);
if (!res.ok) return null;
const thumbnailEncrypted = await res.arrayBuffer();
const thumbnailBuffer = await decryptData(
thumbnailEncrypted.slice(12),
thumbnailEncrypted.slice(0, 12),
dataKey,
);
const thumbnailBuffer = await decryptChunk(await res.arrayBuffer(), dataKey);
void writeFile(`/thumbnail/file/${fileId}`, thumbnailBuffer);
return getThumbnailUrl(thumbnailBuffer);

View File

@@ -58,8 +58,7 @@ const requestDuplicateFileScan = limitFunction(
) => {
state.status = "encryption-pending";
const hmacResult = await signMessageHmac(file, hmacSecret.secret);
const fileSigned = encodeToBase64(hmacResult);
const fileSigned = encodeToBase64(await signMessageHmac(file, hmacSecret.secret));
const files = await trpc().file.listByHash.query({
hskVersion: hmacSecret.version,
contentHmac: fileSigned,
@@ -171,7 +170,7 @@ const requestFileUpload = limitFunction(
await uploadBlob(uploadId, file, dataKey, {
onProgress(s) {
state.progress = s.progress;
state.rate = s.rateBps;
state.rate = s.rate;
},
});

View File

@@ -3,27 +3,32 @@ import pLimit from "p-limit";
import { ENCRYPTION_OVERHEAD, CHUNK_SIZE } from "$lib/constants";
import { encryptChunk, digestMessage, encodeToBase64 } from "$lib/modules/crypto";
type UploadStats = {
progress: number; // 0..1 (암호화 후 기준)
rateBps: number; // bytes/sec
uploadedBytes: number;
totalBytes: number;
};
interface UploadStats {
progress: number;
rate: number;
}
const createSpeedMeter = (timeWindow = 1500) => {
const samples: { t: number; b: number }[] = [];
let lastSpeed = 0;
return (bytesNow?: number) => {
if (!bytesNow) return lastSpeed;
function createSpeedMeter(windowMs = 1500) {
const samples: Array<{ t: number; b: number }> = [];
return (bytesNow: number) => {
const now = performance.now();
samples.push({ t: now, b: bytesNow });
const cutoff = now - windowMs;
const cutoff = now - timeWindow;
while (samples.length > 2 && samples[0]!.t < cutoff) samples.shift();
const first = samples[0]!;
const dt = now - first.t;
const db = bytesNow - first.b;
return dt > 0 ? (db / dt) * 1000 : 0;
lastSpeed = dt > 0 ? (db / dt) * 1000 : 0;
return lastSpeed;
};
}
};
const uploadChunk = async (
uploadId: string,
@@ -66,10 +71,10 @@ export const uploadBlob = async (
if (!onProgress) return;
const uploadedBytes = uploadedByChunk.reduce((a, b) => a + b, 0);
const rateBps = speedMeter(uploadedBytes);
const rate = speedMeter(uploadedBytes);
const progress = Math.min(1, uploadedBytes / totalBytes);
onProgress({ progress, rateBps, uploadedBytes, totalBytes });
onProgress({ progress, rate });
};
const onChunkProgress = (idx: number, loaded: number) => {
@@ -84,7 +89,7 @@ export const uploadBlob = async (
limit(() =>
uploadChunk(
uploadId,
i + 1, // 1-based chunk index
i + 1,
blob.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE),
dataKey,
onChunkProgress,
@@ -93,11 +98,5 @@ export const uploadBlob = async (
),
);
// 완료 보정
onProgress?.({
progress: 1,
rateBps: 0,
uploadedBytes: totalBytes,
totalBytes,
});
onProgress?.({ progress: 1, rate: speedMeter() });
};