diff --git a/background.js b/background.js index 323105f..6ee71d1 100644 --- a/background.js +++ b/background.js @@ -1,9 +1,32 @@ -importScripts("sessionGrabber.js"); +// Chrome runs this file as a service worker, which pulls in its siblings itself. +// Firefox has no background service workers and runs it as an event page +// instead, with sessionGrabber.js already loaded from background.scripts. +if (typeof importScripts === "function") { + importScripts("sessionGrabber.js"); +} -chrome.runtime.onMessageExternal.addListener(function (msg, sender, sendResponse) { - if (msg.ping && msg.ping == 'hello') { - sendResponse({pong: "hello"}); +// Messages from remote-sli.de. Chrome lets the site send them here directly +// (externally_connectable); Firefox doesn't let web pages message an extension +// at all, so there util/siteBridge.js relays what the site posts to its window. +function handleSiteMessage(msg, sendResponse) { + if (msg.session) { + grabSession(msg.session); + } + // Always answer: the site closes the tab it opened for a session once it hears back + sendResponse(msg.ping == 'hello' ? {pong: "hello"} : {}); +} + +function isSiteSender(sender) { + try { + var host = new URL(sender.url).hostname; + return host == "remote-sli.de" || host.endsWith(".remote-sli.de"); + } catch (ignored) { + return false; } +} + +chrome.runtime.onMessageExternal.addListener(function (msg, sender, sendResponse) { + handleSiteMessage(msg, sendResponse); }); // The badge belongs to the tab the controller runs in. Messages from the injected @@ -27,6 +50,9 @@ function setRemoteCountBadge(sender, data) { // Handle messages from the pageController script chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) { + if (msg.action == 'siteMessage' && isSiteSender(sender)) { + handleSiteMessage(msg.message || {}, sendResponse); + } if (msg.action == 'socketEvent') { var event = msg.event; var data = msg.data; diff --git a/index.js b/index.js index abafb37..36b5f10 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,8 @@ var app = angular.module("app", []); +// Shown in the session's connection info, so tell the two builds apart +var INJECTOR = chrome.runtime.getURL("").indexOf("moz-extension:") === 0 ? "extension_firefox" : "extension_chrome"; + // chrome.tabs.getSelected is gone in MV3; the popup always belongs to the current window. function withActiveTab(callback) { chrome.tabs.query({active: true, currentWindow: true}, function (tabs) { @@ -71,7 +74,7 @@ app.controller("mainCtrl", function ($scope, $timeout) { }, args: [{ session: $scope.session.session, - injector: 'extension_chrome' + injector: INJECTOR }] }); }).then(function () { diff --git a/inject/controller b/inject/controller index b9fe1f8..7f11f75 160000 --- a/inject/controller +++ b/inject/controller @@ -1 +1 @@ -Subproject commit b9fe1f8002b5cc7a11140b4ec5947cf991c139ae +Subproject commit 7f11f75ce07e102795953f0c9c89fac13f0ee7e6 diff --git a/manifest.json b/manifest.json index 433750a..01f5508 100644 --- a/manifest.json +++ b/manifest.json @@ -5,7 +5,18 @@ "version": "1.2.0", "author": "inventivetalent", "homepage_url": "https://remote-sli.de", - "minimum_chrome_version": "102", + "minimum_chrome_version": "121", + "browser_specific_settings": { + "gecko": { + "id": "remoteslide@inventivetalent.org", + "strict_min_version": "140.0", + "data_collection_permissions": { + "required": [ + "websiteContent" + ] + } + } + }, "action": { "default_icon": "img/logo-128.png", "default_popup": "index.html" @@ -32,7 +43,11 @@ "extension_pages": "script-src 'self'; object-src 'self'" }, "background": { - "service_worker": "background.js" + "service_worker": "background.js", + "scripts": [ + "sessionGrabber.js", + "background.js" + ] }, "content_scripts": [ { @@ -54,6 +69,15 @@ "util/preziInjector.js" ], "all_frames": true + }, + { + "matches": [ + "*://*.remote-sli.de/*" + ], + "js": [ + "util/siteBridge.js" + ], + "run_at": "document_start" } ], "web_accessible_resources": [ diff --git a/sessionGrabber.js b/sessionGrabber.js index 4027353..a48727d 100644 --- a/sessionGrabber.js +++ b/sessionGrabber.js @@ -1,24 +1,22 @@ -console.log("Waiting for session message...") -chrome.runtime.onMessageExternal.addListener(function (msg, sender, sendResponse) { - if (msg.session) { - console.log("Session msg: " + JSON.stringify(msg)) - chrome.storage.local.get(["session"], function (items) { - var oldSession = items.session; +// Stores a session that remote-sli.de handed over (see handleSiteMessage in background.js) +function grabSession(session) { + console.log("Session msg: " + JSON.stringify(session)) + chrome.storage.local.get(["session"], function (items) { + var oldSession = items.session; - msg.session.sessionTime = new Date().valueOf(); - chrome.storage.local.set({"session": msg.session}); - if (!oldSession || oldSession.session != msg.session.session) { - console.log("notification created") - chrome.notifications.create('new-session-created-notification', { - type: 'basic', - iconUrl: 'img/logo-128.png', - title: 'Session Updated', - message: 'A new session has been created\n' + - 'Click the icon to start presenting!', - contextMessage: msg.session.session - }, function (notificationId) { - }); - } - }); - } -}); \ No newline at end of file + session.sessionTime = new Date().valueOf(); + chrome.storage.local.set({"session": session}); + if (!oldSession || oldSession.session != session.session) { + console.log("notification created") + chrome.notifications.create('new-session-created-notification', { + type: 'basic', + iconUrl: 'img/logo-128.png', + title: 'Session Updated', + message: 'A new session has been created\n' + + 'Click the icon to start presenting!', + contextMessage: session.session + }, function (notificationId) { + }); + } + }); +} diff --git a/util/siteBridge.js b/util/siteBridge.js new file mode 100644 index 0000000..7cc0280 --- /dev/null +++ b/util/siteBridge.js @@ -0,0 +1,20 @@ +// Firefox has no externally_connectable, so remote-sli.de can't message the +// extension the way it does in Chrome. Instead it posts the same messages to its +// own window, and this relays them to the background and posts the answers back: +// page -> {channel: "remoteslide", direction: "to-extension", id, message} +// page <- {channel: "remoteslide", direction: "to-page", id, response} +window.addEventListener("message", function (event) { + var data = event.data; + if (event.source !== window || !data || data.channel !== "remoteslide" || data.direction !== "to-extension") { + return; + } + chrome.runtime.sendMessage({action: "siteMessage", message: data.message}, function (response) { + void chrome.runtime.lastError; + window.postMessage({ + channel: "remoteslide", + direction: "to-page", + id: data.id, + response: response + }, window.location.origin); + }); +});