From 24ba4b8d15b22167e61aaae7b576624e2f40a588 Mon Sep 17 00:00:00 2001 From: Snider <631881+Snider@users.noreply.github.com> Date: Mon, 2 Feb 2026 01:53:52 +0000 Subject: [PATCH] feat(borg-stmf): add file support to encryptFormData - Implemented `readFileAsBase64` helper using FileReader. - Updated `encryptFormData` to support `File` objects by reading them asynchronously as base64 and populating `FormField` structure. - Updated `encryptFormData` to accept optional `metadata` and `serverPublicKey` to support more flexible usage. - Refactored `enableInterceptor` to use `encryptFormData`, reducing code duplication and enabling file support for intercepted forms. - Added `node_modules/` to `.gitignore` to prevent accidental commits of dependencies. --- .gitignore | 2 ++ js/borg-stmf/src/index.ts | 69 ++++++++++++++++++++++++++------------- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index d3a3066..f59bfc9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ demo-track.smsg # Dev artifacts .playwright-mcp/ +node_modules/ +*.log diff --git a/js/borg-stmf/src/index.ts b/js/borg-stmf/src/index.ts index 8c4078e..2752118 100644 --- a/js/borg-stmf/src/index.ts +++ b/js/borg-stmf/src/index.ts @@ -102,30 +102,48 @@ export class BorgSTMF { /** * Encrypt a FormData object */ - async encryptFormData(formData: globalThis.FormData): Promise { + async encryptFormData( + formData: globalThis.FormData, + metadata?: Record, + serverPublicKey?: string + ): Promise { this.ensureInitialized(); const fields: Record = {}; + const promises: Promise[] = []; formData.forEach((value, key) => { if (value instanceof File) { // Handle file uploads - read as base64 // Note: For large files, consider chunking or streaming this.log('File field detected:', key, value.name); - // For now, skip files - they need async reading - // TODO: Add file support with FileReader + const promise = readFileAsBase64(value).then((base64) => { + fields[key] = { + name: key, + value: base64, + type: 'file', + filename: value.name, + mime: value.type, + }; + }); + promises.push(promise); } else { fields[key] = value.toString(); } }); + await Promise.all(promises); + + const meta = { + origin: window.location.origin, + timestamp: Date.now().toString(), + ...metadata, + }; + const payload = await this.wasm!.encryptFields( fields, - this.config.serverPublicKey, - { - origin: window.location.origin, - timestamp: Date.now().toString(), - } + serverPublicKey || this.config.serverPublicKey, + meta ); return { @@ -218,22 +236,16 @@ export class BorgSTMF { // Encrypt the form const originalFormData = new window.FormData(form); - const fields: Record = {}; - originalFormData.forEach((value, key) => { - if (!(value instanceof File)) { - fields[key] = value.toString(); - } - }); + const metadata: Record = {}; + if (form.id) { + metadata.formId = form.id; + } - const payload = await this.wasm!.encryptFields( - fields, - serverKey, - { - origin: window.location.origin, - timestamp: Date.now().toString(), - formId: form.id || undefined, - } + const { payload } = await this.encryptFormData( + originalFormData, + metadata, + serverKey ); // Callback after encryption @@ -337,6 +349,19 @@ export function createBorgSTMF(config: BorgSTMFConfig): BorgSTMF { return new BorgSTMF(config); } +function readFileAsBase64(file: File): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + const result = reader.result as string; + const base64 = result.split(',')[1]; + resolve(base64); + }; + reader.onerror = () => reject(reader.error); + reader.readAsDataURL(file); + }); +} + // Export types for the Go interface declare class Go { constructor();