8fa1082f4aae
fix Mayan decode via createImageBitmap; reattach toolbar popup after successful import in detached window
- time
- 2026-05-01 13:40 UTC · 5 months ago
- machine
- koh2
- parent
- 5cf135768dc8
↓ peach-browser-8fa1082f.tar.gzatlas at this save
files changed3 files
manifest.firefox.json+1 −1manifest.json+1 −1src/popup/views/Lock.tsx+25 −9manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.20.0",4+ "version": "2.21.0",55 "description": "Zero-knowledge password manager",66 "browser_specific_settings": {77 "gecko": {manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.20.0",4+ "version": "2.21.0",55 "description": "Zero-knowledge password manager",66 "action": {77 "default_popup": "src/popup/index.html",src/popup/views/Lock.tsx+25 −9
@@ -424,12 +424,22 @@424424 const [showIntro, setShowIntro] = createSignal(false);425425 const [pendingUnlock, setPendingUnlock] = createSignal(false);426426 427+ const isDetachedWindow = new URLSearchParams(location.search).has("detached");428+429+ async function reattachPopup() {430+ if (!isDetachedWindow) return;431+ // Reopen the normal toolbar popup then discard the detached window.432+ try { await (chrome.action as { openPopup?: () => Promise<void> }).openPopup?.(); } catch {}433+ window.close();434+ }435+427436 async function handleRestoreSuccess() {428437 const seen = await storageGet("peach_shown_restore_intro").catch(() => null);429438 if (!seen) {430439 setShowIntro(true);431440 } else {432441 await props.onUnlock();442+ await reattachPopup();433443 }434444 }435445 @@ -437,6 +447,7 @@437447 await storageSet("peach_shown_restore_intro", "true").catch(() => {});438448 setShowIntro(false);439449 await props.onUnlock();450+ await reattachPopup();440451 }441452 442453 return (@@ -834,15 +845,20 @@834845 setEntryLine(null);835846 setError(null);836847 try {837- const reader = new FileReader();838- const base64 = await new Promise<string>((res, rej) => {839- reader.onload = () => res(reader.result as string);840- reader.onerror = () => rej(new Error("read error"));841- reader.readAsDataURL(file);842- });843- const result = await handleMayanDecode(base64);844- if (!result.ok) { setError(result.reason); return; }845- setDecoded(result.payload);848+ const { decodeMayan } = await import("../../crypto/mayan");849+ const bitmap = await createImageBitmap(file);850+ const MAX_DIM = 1500;851+ const scale = Math.min(1, MAX_DIM / Math.max(bitmap.width, bitmap.height));852+ const canvas = document.createElement("canvas");853+ canvas.width = Math.round(bitmap.width * scale);854+ canvas.height = Math.round(bitmap.height * scale);855+ const ctx = canvas.getContext("2d")!;856+ ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);857+ bitmap.close();858+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);859+ const payload = decodeMayan(imageData);860+ if (!payload) { setError("Could not read this Mayan code. Try a clearer image."); return; }861+ setDecoded(payload);846862 } catch {847863 setError("Could not read this Mayan code. Try a clearer image.");848864 } finally {