From 4c26b4c534415c0d9344e09dd3a3ff4a5669ae56 Mon Sep 17 00:00:00 2001 From: adlee-was-taken Date: Sun, 12 Apr 2026 11:52:35 -0400 Subject: [PATCH] fix: remove file picker from popup setup wizard Chrome closes popups when file pickers steal focus. Instead, check chrome.storage.local for an existing image (pushed by init wizard), and redirect to the full-page setup.html if no image is found. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/popup/components/setup-wizard.ts | 87 +++++++++---------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/extension/src/popup/components/setup-wizard.ts b/extension/src/popup/components/setup-wizard.ts index c571477..9d1f887 100644 --- a/extension/src/popup/components/setup-wizard.ts +++ b/extension/src/popup/components/setup-wizard.ts @@ -10,6 +10,17 @@ let wizardConfig: Partial = { let wizardImageBase64: string | null = null; export function renderSetupWizard(app: HTMLElement): void { + // Check if image is already in storage (e.g. pushed by init wizard). + if (!wizardImageBase64) { + chrome.storage.local.get(['imageBase64'], (result: Record) => { + if (result.imageBase64) { + wizardImageBase64 = result.imageBase64; + // Re-render now that we have the image. + renderSetupWizard(app); + } + }); + } + const state = getState(); // Progress bar. @@ -120,66 +131,46 @@ function attachStep0Listeners(): void { }); } -// --- Step 1: Reference image upload --- +// --- Step 1: Reference image --- +// +// Chrome closes the popup when a file picker steals focus, which makes +// in-popup file uploads unreliable. Instead we check if an image is +// already in chrome.storage.local (pushed by the init wizard or a +// previous setup). If not, we link the user to the full-page setup.html +// where the file picker works without focus issues. function renderStep1(): string { + if (wizardImageBase64) { + // Image already loaded (from storage or previous attempt). + return ` +
+

reference image

+

✓ reference image loaded

+
+ + +
+
+ `; + } + return `

reference image

- Upload the JPEG that contains your embedded secret. - This is the second factor for vault decryption. + No reference image found. Use the full-page setup wizard to + upload your reference image — file pickers don't work reliably + in the popup.

-
- - ${wizardImageBase64 - ? '

image loaded

' - : '

click to select JPEG

'} -
- +
`; } function attachStep1Listeners(): void { - const fileDrop = document.getElementById('file-drop')!; - const fileInput = document.getElementById('file-input') as HTMLInputElement; - - fileDrop.addEventListener('click', () => fileInput.click()); - - fileInput.addEventListener('change', () => { - const file = fileInput.files?.[0]; - if (!file) return; - - const reader = new FileReader(); - reader.onload = () => { - try { - const result = reader.result as string; - // Remove the data:image/jpeg;base64, prefix. - const base64 = result.split(',')[1] ?? result; - wizardImageBase64 = base64; - // Update UI without a full re-render to avoid resetting file input state. - const dropEl = document.getElementById('file-drop'); - if (dropEl) { - dropEl.classList.add('has-file'); - const p = dropEl.querySelector('p'); - if (p) p.textContent = `image loaded (${(file.size / 1024).toFixed(0)} KB)`; - } - const nextBtn = document.getElementById('next-btn') as HTMLButtonElement; - if (nextBtn) nextBtn.disabled = false; - } catch (err) { - setState({ error: `Failed to read image: ${err}` }); - } - }; - reader.onerror = () => { - setState({ error: 'Failed to read image file' }); - }; - reader.readAsDataURL(file); - }); - document.getElementById('back-btn')?.addEventListener('click', () => { wizardStep = 0; setState({ error: null }); @@ -190,6 +181,12 @@ function attachStep1Listeners(): void { wizardStep = 2; setState({ error: null }); }); + + document.getElementById('open-setup-btn')?.addEventListener('click', () => { + // Open the full-page setup wizard in a new tab. + chrome.tabs.create({ url: chrome.runtime.getURL('setup.html') }); + window.close(); + }); } // --- Step 2: Test unlock ---