🐛 Fix unexpected corner case between SES hardening and transit (#8663)

* Revert "🐛 Fix plugin sandbox freezing CLJS Proxy constructor breaking Transit encoding"

This reverts commit 27a934dcfd.

* 🐛 Fix unexpected corner case between SES hardening and transit

The cause of the issue is a race condition between plugin loading
and the first time js/Date objects are encoded using transit. Transit
encoder populates the prototype of the Date object the first time a
Date instance is encoded, but if SES freezes the Date prototype before
transit, an strange exception will be raised on encoding any object
that contains Date instances.

Example of the exception:

Cannot define property transit$guid$4a57baf3-8824-4930-915a-fa905479a036,
object is not extensible
This commit is contained in:
Andrey Antukh
2026-03-18 09:53:22 +01:00
committed by GitHub
parent 0f24cf26f6
commit 5482ee211e
2 changed files with 15 additions and 12 deletions

View File

@@ -8,6 +8,8 @@
(:require
[app.common.data.macros :as dm]
[app.common.logging :as log]
[app.common.time :as ct]
[app.common.transit :as t]
[app.common.types.objects-map]
[app.common.uuid :as uuid]
[app.config :as cf]
@@ -100,6 +102,15 @@
(defn ^:export init
[options]
;; WORKAROUND: we set this really not usefull property for signal a
;; sideffect and prevent GCC remove it. We need it because we need
;; to populate the Date prototype with transit related properties
;; before SES hardning is applied on loading MCP plugin
(unchecked-set js/globalThis "penpotStartDate"
(-> (ct/now)
(t/encode-str)
(t/decode-str)))
;; Before initializing anything, check if the browser has loaded
;; stale JS from a previous deployment. If so, do a hard reload so
;; the browser fetches fresh assets matching the current index.html.
@@ -110,7 +121,6 @@
(do
(some-> (unchecked-get options "defaultTranslations")
(i18n/set-default-translations))
(mw/init!)
(i18n/init)
(cur/init-styles)

View File

@@ -466,17 +466,10 @@
#?(:cljs
(def Proxy
(let [ctor (app.util.object/class
:name "Proxy"
:extends js/Object
:constructor (constantly nil))]
;; Remove the `constructor` data property from the prototype so that
;; SES `harden` (used by the plugin sandbox) does not traverse from a
;; proxy instance back to this constructor function and freeze it.
;; If the constructor is frozen before Transit's `typeTag` helper sets
;; its cache property, Transit throws "object is not extensible".
(js-delete (.-prototype ctor) "constructor")
ctor)))
(app.util.object/class
:name "Proxy"
:extends js/Object
:constructor (constantly nil))))
(defmacro reify
"A domain specific variation of reify that creates anonymous objects