diff --git a/public/index.html b/public/index.html index 6fe25ac..f373b0d 100644 --- a/public/index.html +++ b/public/index.html @@ -93,6 +93,18 @@ background: var(--x-color-border, rgba(127, 127, 127, 0.35)); } .toolbar-icon-button span { font-size: 16px; line-height: 1; } + .toolbar-autosave-warn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + margin-left: 6px; + color: var(--x-color-warning, #c97a00); + font-size: 16px; + cursor: help; + } + .toolbar-autosave-warn[hidden] { display: none; } .panel { border-right: 1px solid var(--x-color-border, rgba(127, 127, 127, 0.2)); padding: 12px; diff --git a/src/bareforge/dnd/drag.cljs b/src/bareforge/dnd/drag.cljs index 2248101..a3cae29 100644 --- a/src/bareforge/dnd/drag.cljs +++ b/src/bareforge/dnd/drag.cljs @@ -229,22 +229,22 @@ (let [^js br (.getBoundingClientRect host) sl (.-scrollLeft host) st (.-scrollTop host) - ^js nodes (.querySelectorAll host "[data-bareforge-id]") - out (volatile! [])] - (dotimes [i (.-length nodes)] - (let [^js el (.item nodes i) - id (.getAttribute el "data-bareforge-id")] - (when (and id (not= id "root")) - (let [^js eb (.getBoundingClientRect el) - left (+ (- (.-left eb) (.-left br)) sl) - top (+ (- (.-top eb) (.-top br)) st) - rect {:left left - :top top - :right (+ left (.-width eb)) - :bottom (+ top (.-height eb))}] - (when (rects-overlap? marquee-rect rect) - (vswap! out conj id)))))) - @out)) + ^js nodes (.querySelectorAll host "[data-bareforge-id]")] + (into [] + (keep (fn [i] + (let [^js el (.item nodes i) + id (.getAttribute el "data-bareforge-id")] + (when (and id (not= id "root")) + (let [^js eb (.getBoundingClientRect el) + left (+ (- (.-left eb) (.-left br)) sl) + top (+ (- (.-top eb) (.-top br)) st) + rect {:left left + :top top + :right (+ left (.-width eb)) + :bottom (+ top (.-height eb))}] + (when (rects-overlap? marquee-rect rect) + id)))))) + (range (.-length nodes))))) (defn- commit-marquee! [^js e] (let [^js host (canvas-el) diff --git a/src/bareforge/doc/sanitize.cljs b/src/bareforge/doc/sanitize.cljs index 0131781..6f0d1f4 100644 --- a/src/bareforge/doc/sanitize.cljs +++ b/src/bareforge/doc/sanitize.cljs @@ -2,14 +2,20 @@ "Pure sanitisation helpers for the two doc fields that ship raw user-supplied strings into the DOM: `:inner-html` (raw SVG/HTML on `:raw-html-slot?` components like x-icon) and `:attrs` URL values - (`href`, `src`, …). + (`href`, `src`, …). Plus an identifier-shape scanner that guards + the export pipeline against doc fields that the codegen later + interpolates verbatim into emitted JS / CLJS source. - Two layers of protection: + Three layers of protection: - **Block-list scanners** (`unsafe-findings`): given a doc, return a vector of `[path reason]` entries naming each suspect site. Used at the load boundary by `storage/project-file/validate-project` to refuse a malicious payload outright with an explanatory message. + Covers XSS payloads in `:inner-html` / URL attrs **and** unsafe + identifier shapes in attr keys, binding keys, field / action + names, and trigger action-refs (everything codegen splices into + a JS or CLJS string literal). - **Best-effort sanitisers** (`sanitize-svg-fragment`, `sanitize-doc`): strip the obvious payloads — `