Skip to content

Support Firefox - #5

Open
InventivetalentDev wants to merge 2 commits into
masterfrom
claude/zealous-meitner-fm8fqa
Open

InventivetalentDev wants to merge 2 commits into
masterfrom
claude/zealous-meitner-fm8fqa

Conversation

@InventivetalentDev

@InventivetalentDev InventivetalentDev commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

Makes the existing extension run in Firefox as well. It stays one codebase with one manifest for both browsers: each browser ignores the keys meant for the other.

Depends on RemoteSlide/RemoteSlide-Controller#3 (the submodule points at its commit 7f11f75) and, for sessions in Firefox, on RemoteSlide/remote-sli.de#11.

Changes

Manifest

  • browser_specific_settings.gecko:
    • Add-on ID remoteslide@inventivetalent.org. This becomes permanent once the add-on is submitted to AMO.
    • strict_min_version 140: the first release with Firefox's built-in data-consent prompt, and an ESR.
    • data_collection_permissions: websiteContent, because screenshots of the presented tab go to the server. AMO rejects new add-ons without this key.
  • background.scripts next to service_worker. Firefox has no background service workers and runs the scripts as an event page. Chrome ignores background.scripts from 121 on but refused such a manifest before that, so minimum_chrome_version goes from 102 to 121.
  • A content script on *://*.remote-sli.de/* for the session bridge (below).

Background

  • importScripts() only exists in the service worker. In Firefox, sessionGrabber.js comes from background.scripts instead.
  • Messages from the site (ping, session) go through a single handleSiteMessage(), whether they arrive directly (Chrome, externally_connectable) or through the bridge (Firefox). It always answers now, so the site can close its ?sessionOnly tab once the extension has the session. sessionGrabber.js becomes the grabSession() it calls.

Session bridge (util/siteBridge.js)
Firefox doesn't implement externally_connectable (bug 1319168), so remote-sli.de can't reach the extension with chrome.runtime.sendMessage() there.

  • The site posts the same messages to its own window, and this content script relays them to the background and posts the answers back.
  • It only relays messages whose source is the page's own window, and it only runs in the top frame.
  • The background only accepts them from remote-sli.de tabs. That is the same origin externally_connectable allows.

Popup
Reports the host as extension_firefox in Firefox, so the connection info tells the browsers apart.

Testing

Each browser was driven end to end against a local copy of the site, with remote-sli.de resolved to it:

Firefox 158 Firefox ESR 140 Chromium 141
Background starts, controller injects, host joins ✅ ✅ ✅
Remote key presses reach the page ✅ ✅ ✅
Overlay and laser dot ✅ ✅ ✅
Badge, popup ✅ ✅ ✅
Screenshots ✅ ⚠️ see below ✅
Site detects the extension, session stored, ?sessionOnly tab closes ✅ bridge ✅ bridge ✅ externally_connectable
No answer on other sites ✅ ✅ ✅

web-ext lint: 0 errors (2 before this change). The remaining warnings:

  • service_worker is ignored by Firefox (intended).
  • There is no Firefox for Android minimum version; Android isn't targeted.
  • An existing innerHTML use in util/preziVarBridge.js, plus the bundled AngularJS.

Known gaps

  • Screenshots on Firefox 140–151. Firefox leaves the granted <all_urls> host permission out of the check captureVisibleTab() makes. This happens right after install and also after a restart. Firefox changed this in 152, and I saw it working in ESR 153 and 158. On 140–151, screenshots rely on the activeTab grant from clicking the toolbar button, which is how control is started anyway. That grant lasts until the tab loads a new document, which also removes the controller. Hash and pushState navigation keep it. Raising strict_min_version to 152 would close the gap at the cost of ESR 140.
  • Not tested on the real sites in Firefox: Google Slides, slides.com and Prezi. Prezi is the riskiest, because util/preziInjector.js adds a <script src="moz-extension://…"> to the page, which the page's CSP might block in Firefox.
  • The version is still 1.2.0. Both stores need a higher version before upload.
  • AMO review may ask about the bundled AngularJS 1.5.8. The linter doesn't recognise it as a known library, and it is end-of-life.

Merging

Merge RemoteSlide/RemoteSlide-Controller#3 with a merge commit first. A squash merge plus branch deletion would leave 7f11f75 unreachable and break this submodule on fresh clones. If it does get squashed, repoint inject/controller at the squashed commit before merging this.

🤖 Generated with Claude Code

https://claude.ai/code/session_01P3g3vcYRESg89oZuTf7eP5

Firefox runs the existing MV3 extension with a few additions to the shared
manifest:

- browser_specific_settings.gecko: the add-on ID (mandatory for MV3 on
  AMO), strict_min_version 140 (the first release with the built-in data
  consent prompt; ESR 140), and data_collection_permissions declaring
  websiteContent, since screenshots of the presented tab go to the server
  (AMO rejects new add-ons without this key).
- background.scripts next to service_worker: Firefox has no background
  service workers and runs the scripts as an event page instead. Chrome
  ignores background.scripts from 121 on and refused the manifest before
  that, hence minimum_chrome_version 121. In the event page sessionGrabber.js
  comes from that list, as importScripts() only exists in the worker.
- The popup reports the host as extension_firefox in Firefox, so the
  connection info tells the two browsers apart.

Bumps the controller for the fix that lets scripting.executeScript() resolve
in Firefox, without which the overlay and laser pointer never loaded.

Checked end to end against a local copy of the site, in Firefox 158 and
ESR 140 and, for regressions, in Chromium 141: background start, controller
injection, host join, key presses, overlay, laser dot, badge, screenshots
and the popup.

One known gap: for an MV3 add-on, Firefox 140-151 never counts the granted
<all_urls> host permission in the check captureVisibleTab() makes (changed
in 152; seen working in ESR 153 and 158). There, screenshots rely on the
activeTab grant from clicking the toolbar button, which is how control is
started anyway. The grant lasts until the tab loads a new document, which
also removes the controller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P3g3vcYRESg89oZuTf7eP5
Firefox doesn't implement externally_connectable, so remote-sli.de cannot
reach the extension with chrome.runtime.sendMessage() there (Mozilla bug
1319168), and the popup never got a session. util/siteBridge.js, a
content script on remote-sli.de, now relays what the site posts to its own
window to the background and posts the answer back. The site falls back to
that channel when chrome.runtime isn't exposed (RemoteSlide/remote-sli.de,
same branch). Only messages from the page's own window are relayed, and
the background only takes them from remote-sli.de tabs, the same origin
externally_connectable allows.

Both channels end up in handleSiteMessage(), which now always answers, so
the site can close the ?sessionOnly tab once the extension has the session.
sessionGrabber.js becomes the grabSession() it calls.

Sets the Firefox add-on ID to remoteslide@inventivetalent.org.

Checked against the local site with remote-sli.de pointed at it, in
Firefox 158 and ESR 140 (bridge) and Chromium 141 (externally_connectable):
ping/pong, the stored session, the ?sessionOnly tab closing itself, and no
answer on other sites. The unchanged site fails the same check in Firefox.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P3g3vcYRESg89oZuTf7eP5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants