HMAC 계산을 Web Worker에서 처리하도록 변경

This commit is contained in:
static
2026-01-12 12:47:37 +09:00
parent b636d75ea0
commit 122970a6ea
3 changed files with 59 additions and 17 deletions

View File

@@ -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<WorkerMessage>) => {
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] });
}
};

View File

@@ -0,0 +1,25 @@
import HmacWorker from "./hmac.worker?worker";
export const computeFileHmac = async (file: File, hmacSecret: CryptoKey): Promise<Uint8Array> => {
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] },
);
});
};

View File

@@ -1,13 +1,8 @@
import ExifReader from "exifreader"; import ExifReader from "exifreader";
import { limitFunction } from "p-limit"; import { limitFunction } from "p-limit";
import { CHUNK_SIZE } from "$lib/constants"; import { CHUNK_SIZE } from "$lib/constants";
import { import { encodeToBase64, generateDataKey, wrapDataKey, encryptString } from "$lib/modules/crypto";
encodeToBase64, import { computeFileHmac } from "$lib/modules/crypto/hmacWorker";
generateDataKey,
wrapDataKey,
encryptString,
createHmacStream,
} from "$lib/modules/crypto";
import { Scheduler } from "$lib/modules/scheduler"; import { Scheduler } from "$lib/modules/scheduler";
import { generateThumbnail } from "$lib/modules/thumbnail"; import { generateThumbnail } from "$lib/modules/thumbnail";
import { uploadBlob } from "$lib/modules/upload"; import { uploadBlob } from "$lib/modules/upload";
@@ -56,16 +51,8 @@ export const clearUploadedFiles = () => {
const requestDuplicateFileScan = limitFunction( const requestDuplicateFileScan = limitFunction(
async (file: File, hmacSecret: HmacSecret, onDuplicate: () => Promise<boolean>) => { async (file: File, hmacSecret: HmacSecret, onDuplicate: () => Promise<boolean>) => {
const hmacStream = await createHmacStream(hmacSecret.secret); const hmacResult = await computeFileHmac(file, hmacSecret.secret);
const reader = file.stream().getReader(); const fileSigned = encodeToBase64(hmacResult);
while (true) {
const { done, value } = await reader.read();
if (done) break;
hmacStream.update(value);
}
const fileSigned = encodeToBase64(hmacStream.digest());
const files = await trpc().file.listByHash.query({ const files = await trpc().file.listByHash.query({
hskVersion: hmacSecret.version, hskVersion: hmacSecret.version,
contentHmac: fileSigned, contentHmac: fileSigned,