5cd09213d011
fix: standalone notes editor pastes as plain text through the shared handleRichTextPaste guard (PB-26-009) — pasted rich HTML can no longer enter the extension-origin DOM live; guard extracted from the inline editor so both editors share one paste handler; bump 5.0.8→5.0.9
- time
- 2026-08-30 00:16 UTC · 1 month ago
- machine
- koh2
- agent
- glm-5.3-flash
- session
- pb-26 audit fixes
- parent
- 2ee6e8b00769
↓ peach-browser-5cd09213.tar.gzatlas at this save
files changed5 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/popup/views/NoteEditor.tsx+12 −12src/popup/views/NotesEditor.tsx+3 −1manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach Password Manager",4- "version": "5.0.8",4+ "version": "5.0.9",55 "description": "Zero-knowledge password manager",66 "browser_specific_settings": {77 "gecko": {manifest.json+1 −1
@@ -2,7 +2,7 @@22 "manifest_version": 3,33 "minimum_chrome_version": "116",44 "name": "Peach Password Manager",5- "version": "5.0.8",5+ "version": "5.0.9",66 "description": "Zero-knowledge password manager",77 "action": {88 "default_popup": "src/popup/index.html",package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "peach",3- "version": "5.0.8",3+ "version": "5.0.9",44 "description": "Zero-knowledge password manager",55 "license": "GPL-3.0-only",66 "type": "module",src/popup/views/NoteEditor.tsx+12 −12
@@ -107,6 +107,17 @@107107 entryKey?: string;108108 }109109 110+// PB-26-009: shared by the inline editor and the standalone notes editor —111+// pasted rich HTML must never enter the extension-origin DOM live. CSP blocks112+// inline script execution, but outbound <img>/<style> beacons remain possible.113+// insertText keeps the body clean and wrapping intact, and fires `input` so114+// autosave handlers persist the change.115+export function handleRichTextPaste(e: ClipboardEvent) {116+ e.preventDefault();117+ const text = e.clipboardData?.getData("text/plain") ?? "";118+ document.execCommand("insertText", false, text);119+}120+110121 export function NoteEditorInline(props: NoteEditorInlineProps) {111122 let editorRef: HTMLDivElement | undefined;112123 @@ -128,17 +139,6 @@128139 editorRef?.focus();129140 }130141 131- // Paste as plain text. The live editor writes innerHTML directly and only132- // load-time content is sanitized (toHtml); pasted HTML would otherwise carry133- // foreign inline styles (white-space:pre kills wrapping) and disallowed tags.134- // insertText keeps the body clean and wrapping intact, and fires `input` so135- // onContentChange persists the change.136- function handlePaste(e: ClipboardEvent) {137- e.preventDefault();138- const text = e.clipboardData?.getData("text/plain") ?? "";139- document.execCommand("insertText", false, text);140- }141-142142 function handleKeyDown(e: KeyboardEvent) {143143 const mod = e.metaKey || e.ctrlKey;144144 // Only intercept shortcuts for non-alphanumeric keys to avoid swallowing@@ -156,7 +156,7 @@156156 class="peach-note-editor-body peach-note-editor-body--inline"157157 contenteditable="true"158158 onKeyDown={handleKeyDown}159- onPaste={handlePaste}159+ onPaste={handleRichTextPaste}160160 onInput={() => props.onContentChange?.(editorRef?.innerHTML ?? "")}161161 onBlur={() => props.onBlur?.(editorRef?.innerHTML ?? "")}162162 aria-multiline="true"src/popup/views/NotesEditor.tsx+3 −1
@@ -2,7 +2,7 @@22 import type { VaultEntry } from "../../shared/types";33 import { sendMessage } from "../../shared/bridge";44 import { NoteToolbar, type ToolbarExec } from "../components/NoteToolbar";5-import { toHtml } from "./NoteEditor";5+import { toHtml, handleRichTextPaste } from "./NoteEditor";66 77 const AUTOSAVE_MS = 800;88 const SAVED_DISPLAY_MS = 1500;@@ -201,6 +201,7 @@201201 bodyRef?.focus();202202 }203203 }}204+ onPaste={handleRichTextPaste}204205 aria-label="Note title"205206 />206207 @@ -221,6 +222,7 @@221222 if (mod && e.key === "i") { e.preventDefault(); exec("italic"); }222223 if (mod && e.key === "u") { e.preventDefault(); exec("underline"); }223224 }}225+ onPaste={handleRichTextPaste}224226 aria-label="Note body"225227 aria-multiline="true"226228 />