From 122970a6eabe2765524f4a658c7f95118c56a9b4 Mon Sep 17 00:00:00 2001 From: static Date: Mon, 12 Jan 2026 12:47:37 +0900 Subject: [PATCH] =?UTF-8?q?HMAC=20=EA=B3=84=EC=82=B0=EC=9D=84=20Web=20Work?= =?UTF-8?q?er=EC=97=90=EC=84=9C=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/modules/crypto/hmac.worker.ts | 30 +++++++++++++++++++++++++++ src/lib/modules/crypto/hmacWorker.ts | 25 ++++++++++++++++++++++ src/lib/modules/file/upload.svelte.ts | 21 ++++--------------- 3 files changed, 59 insertions(+), 17 deletions(-) create mode 100644 src/lib/modules/crypto/hmac.worker.ts create mode 100644 src/lib/modules/crypto/hmacWorker.ts diff --git a/src/lib/modules/crypto/hmac.worker.ts b/src/lib/modules/crypto/hmac.worker.ts new file mode 100644 index 0000000..5d32189 --- /dev/null +++ b/src/lib/modules/crypto/hmac.worker.ts @@ -0,0 +1,30 @@ +import { hmac } from "@noble/hashes/hmac.js"; +import { sha256 } from "@noble/hashes/sha2.js"; + +interface ComputeMessage { + type: "compute"; + file: File; + hmacSecret: ArrayBuffer; +} + +type WorkerMessage = ComputeMessage; + +self.onmessage = async (event: MessageEvent) => { + const { type } = event.data; + + if (type === "compute") { + const { file, hmacSecret } = event.data; + + const h = hmac.create(sha256, new Uint8Array(hmacSecret)); + const reader = file.stream().getReader(); + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + h.update(value); + } + + const result = h.digest(); + self.postMessage({ type: "result", hmac: result }, { transfer: [result.buffer] }); + } +}; diff --git a/src/lib/modules/crypto/hmacWorker.ts b/src/lib/modules/crypto/hmacWorker.ts new file mode 100644 index 0000000..041eb71 --- /dev/null +++ b/src/lib/modules/crypto/hmacWorker.ts @@ -0,0 +1,25 @@ +import HmacWorker from "./hmac.worker?worker"; + +export const computeFileHmac = async (file: File, hmacSecret: CryptoKey): Promise => { + const worker = new HmacWorker(); + const hmacSecretRaw = await crypto.subtle.exportKey("raw", hmacSecret); + + return new Promise((resolve, reject) => { + worker.onmessage = (event: MessageEvent<{ type: "result"; hmac: Uint8Array }>) => { + if (event.data.type === "result") { + resolve(event.data.hmac); + worker.terminate(); + } + }; + + worker.onerror = (error) => { + reject(error); + worker.terminate(); + }; + + worker.postMessage( + { type: "compute", file, hmacSecret: hmacSecretRaw }, + { transfer: [hmacSecretRaw] }, + ); + }); +}; diff --git a/src/lib/modules/file/upload.svelte.ts b/src/lib/modules/file/upload.svelte.ts index 9e9f784..ed116f5 100644 --- a/src/lib/modules/file/upload.svelte.ts +++ b/src/lib/modules/file/upload.svelte.ts @@ -1,13 +1,8 @@ import ExifReader from "exifreader"; import { limitFunction } from "p-limit"; import { CHUNK_SIZE } from "$lib/constants"; -import { - encodeToBase64, - generateDataKey, - wrapDataKey, - encryptString, - createHmacStream, -} from "$lib/modules/crypto"; +import { encodeToBase64, generateDataKey, wrapDataKey, encryptString } from "$lib/modules/crypto"; +import { computeFileHmac } from "$lib/modules/crypto/hmacWorker"; import { Scheduler } from "$lib/modules/scheduler"; import { generateThumbnail } from "$lib/modules/thumbnail"; import { uploadBlob } from "$lib/modules/upload"; @@ -56,16 +51,8 @@ export const clearUploadedFiles = () => { const requestDuplicateFileScan = limitFunction( async (file: File, hmacSecret: HmacSecret, onDuplicate: () => Promise) => { - const hmacStream = await createHmacStream(hmacSecret.secret); - const reader = file.stream().getReader(); - - while (true) { - const { done, value } = await reader.read(); - if (done) break; - hmacStream.update(value); - } - - const fileSigned = encodeToBase64(hmacStream.digest()); + const hmacResult = await computeFileHmac(file, hmacSecret.secret); + const fileSigned = encodeToBase64(hmacResult); const files = await trpc().file.listByHash.query({ hskVersion: hmacSecret.version, contentHmac: fileSigned,