fix(panes): harden the persisted host map against unsafe pane ids

A pane id is plugin-controlled, and it becomes a KEY in the persisted
{ paneId: hostId } map. `__proto__` and friends are not ids, they are booby
traps:

  - `map['__proto__'] = 'window'` on a plain object corrupts the map, and
    can reach Object.prototype.
  - `map[id]` on a polluted (or hand-edited) object can return a value straight
    off the prototype chain for a pane that was never remembered at all — so a
    pane could be "restored" to a host nobody ever put it in.

Three layers, because each is a one-liner:

  - Reject `__proto__` / `constructor` / `prototype` as pane ids at
    registration, so they never reach storage.
  - Re-key whatever comes out of localStorage onto a null-prototype object, so
    a corrupt or hand-edited value cannot smuggle a prototype in.
  - Read with an own-property check.

Also from the same review:

  - Removed `window.__fbPaneWindows`. It was exposed for pane-desktop.js back
    when that file needed to reach the window handles; the rewrite dropped that
    need and nothing has referenced it since. Dead global, and its comment
    described a collaborator that no longer exists.
  - Corrected the /pane cache comment. It claimed a stale page would leave the
    window blank, which stopped being true when the readiness check gained a
    `doc.body` fallback — it would still work, just without the pane window's
    own layout. A comment that describes a failure mode the code no longer has
    is worse than no comment.

Signed-off-by: topkoa <topkoa@gmail.com>
This commit is contained in:
topkoa
2026-07-12 19:39:57 -04:00
parent cb425ed48d
commit 82aa8a757e
3 changed files with 1761 additions and 1740 deletions
-5
View File
@@ -278,9 +278,4 @@
window.addEventListener('beforeunload', () => {
wins.forEach((w) => { if (!w.closed) { try { w.close(); } catch (e) { /* ignore */ } } });
});
// Exposed for pane-desktop.js, which upgrades this host in place rather than
// registering a competing one — the window still has to be opened HERE, by
// window.open(), or there would be no document to adopt into.
window.__fbPaneWindows = { FRAME_PREFIX, get: (id) => wins.get(id) || null };
})();