From: Bill Erickson Date: Wed, 23 Nov 2016 21:38:30 +0000 (-0500) Subject: Hatch declarative message extension style X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=a7181279472c2437a9a78d57882b8c5fdbcb3ecc;p=working%2FHatch.git Hatch declarative message extension style Avoid the requirement to hard-code the allowed externally_connectable hosts by letting the extension ask for permissions instead. Signed-off-by: Bill Erickson --- diff --git a/INSTALL.adoc b/INSTALL.adoc index 6aa36a1cb6..d971cc03ee 100644 --- a/INSTALL.adoc +++ b/INSTALL.adoc @@ -77,20 +77,6 @@ $ ./hatch.sh test === Setup Chrome Extension === -==== Tweak Extension Values ==== - -Edit extension/app/manifest.json and change the "evergreen.example.org" value -found here to the hostname of your Evergreen server. - -[source,js] -------------------------------------------------------------------------- -... -"externally_connectable": { - "matches": ["*://evergreen.example.org/*"] -} -... -------------------------------------------------------------------------- - NOTE: At time of writing, the Evergreen server used must have the patches included in the http://git.evergreen-ils.org/?p=working/Evergreen.git;a=shortlog;h=refs/heads/user/berick/lp1640255-hatch-native-messaging[Hatch Native Messaging working branch]. diff --git a/extension/app/content.js b/extension/app/content.js new file mode 100644 index 0000000000..07ce8b7165 --- /dev/null +++ b/extension/app/content.js @@ -0,0 +1,72 @@ +/* ----------------------------------------------------------------------- + * Copyright 2016 King County Library System + * Bill Erickson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ----------------------------------------------------------------------- + * + * Hatch Content Script. + * + * Relays messages between the browser tab and the Hatch extension.js + * script. + */ + +console.debug('Loading Hatch relay content script'); + +// Tell the page DOM we're here. +document.body.setAttribute('hatch-is-open', '4-8-15-16-23-42'); + +/** + * Open a port to our extension. + */ +var port = chrome.runtime.connect(); + +/** + * Relay all messages received from the extension back to the tab + */ +port.onMessage.addListener(function(message) { + + /* + console.debug( + "Content script received from extension: "+ JSON.stringify(message)); + */ + + window.postMessage(message, location.origin); +}); + + +/** + * Receive messages from the browser tab and relay them to the + * Hatch extension script. + */ +window.addEventListener("message", function(event) { + + // We only accept messages from ourselves + if (event.source != window) return; + + var message = event.data; + + // Ignore broadcast messages. We only care about messages + // received from our browser tab/page. + if (message.from != 'page') return; + + /* + console.debug( + "Content script received from page: " + JSON.stringify(message)); + */ + + // standard Hatch-bound message; relay to extension. + port.postMessage(message); + +}, false); + + + diff --git a/extension/app/extension.js b/extension/app/extension.js new file mode 100644 index 0000000000..a8a72ff69e --- /dev/null +++ b/extension/app/extension.js @@ -0,0 +1,147 @@ +/* ----------------------------------------------------------------------- + * Copyright 2016 King County Library System + * Bill Erickson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ----------------------------------------------------------------------- + */ + +// Singleton connection to Hatch +var hatchPort = null; + +// Map of tab identifers to tab-specific connection ports. +var browserPorts = {}; + + +/** + * Handle response messages received from Hatch. + */ +function onNativeMessage(message) { + var tabId = message.clientid; + + if (tabId) { + if (browserPorts[tabId]) { + message.from = 'extension'; + browserPorts[tabId].postMessage(message); + + } else { + console.warn( + "Hatch message contains port ID " + tabId + + " which was not found in the browser tab map. " + + "Unable to deliver response to browser"); + } + + } else { + console.warn("Hatch response does not contain a 'clientid' value. " + + "Unable to deliver response to browser"); + } +} + +/** + * Called when the connection to Hatch goes away. + */ +function onDisconnected() { + console.warn("Hatch connection failed: " + chrome.runtime.lastError.message); + hatchPort = null; + browserPorts = {}; +} + + +/** + * Called when our content script opens connection to this extension. + */ +chrome.runtime.onConnect.addListener(function(port) { + var tabId = port.sender.tab.id; + + browserPorts[tabId] = port; + console.debug('new port connected with id ' + tabId); + + port.onMessage.addListener(function(msg) { + console.debug("Received message from browser on port " + tabId); + + if (!msg) { // belt+suspenders + console.warn("Received NULL message"); + return; + } + + // tag the message with the browser tab ID for response routing. + msg.clientid = tabId; + + if (msg.action == 'init') { + // "init" messages require origin info. + // Extract just the protocol + host + msg.origin = port.sender.url.match(/https?:\/\/[^\/]+/)[0]; + console.debug("Init'ing message with origin: " + msg.origin); + } + + hatchPort.postMessage(msg); + }); + + port.onDisconnect.addListener(function() { + console.log("Removing port " + tabId + " on tab disconnect"); + delete browserPorts[tabId]; + }); +}); + + +function setPageActionRules() { + // Replace all rules on extension reload + chrome.declarativeContent.onPageChanged.removeRules(undefined, function() { + chrome.declarativeContent.onPageChanged.addRules([ + { + conditions: [ + new chrome.declarativeContent.PageStateMatcher({ + pageUrl : { + pathPrefix : '/eg/staff/', + schemes : ['https'] + }, + css: ["eg-navbar"] // match on + }) + ], + actions: [ + new chrome.declarativeContent.RequestContentScript({ + 'js': ['content.js'] + }) + ] + } + ]); + }); +} + +chrome.browserAction.onClicked.addListener(function (tab) { + chrome.permissions.request({ + origins: ['https://*/eg/staff/*'] + }, function (ok) { + if (ok) { + console.log('access granted'); + } else if (chrome.runtime.lastError) { + alert('Permission Error: ' + chrome.runtime.lastError.message); + } else { + alert('Optional permission denied.'); + } + }); +}); + + +/** + * Link the page action icon to loading the content script + */ +chrome.runtime.onInstalled.addListener(setPageActionRules); + +/** + * Connect to Hatch on startup. + */ +var hostName = "org.evergreen_ils.hatch"; +console.debug("Connecting to native messaging host: " + hostName); +hatchPort = chrome.runtime.connectNative(hostName); +hatchPort.onMessage.addListener(onNativeMessage); +hatchPort.onDisconnect.addListener(onDisconnected); + diff --git a/extension/app/main.js b/extension/app/main.js deleted file mode 100644 index 64b49c4e3f..0000000000 --- a/extension/app/main.js +++ /dev/null @@ -1,114 +0,0 @@ -/* ----------------------------------------------------------------------- - * Copyright 2016 King County Library System - * Bill Erickson - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * ----------------------------------------------------------------------- - */ - -// Singleton connection to Hatch -var hatchPort = null; - -// Map of tab identifers to tab-specific connection ports. -var browserPorts = {}; - - -/** - * Handle response messages received from Hatch. - */ -function onNativeMessage(message) { - var tabId = message.clientid; - - if (tabId) { - if (browserPorts[tabId]) { - browserPorts[tabId].postMessage(message); - - } else { - console.warn( - "Hatch message contains port ID " + tabId + - " which was not found in the browser tab map. " + - "Unable to deliver response to browser"); - } - - } else { - console.warn("Hatch response does not contain a 'clientid' value. " + - "Unable to deliver response to browser"); - } -} - -/** - * Called when the connection to Hatch goes away. - */ -function onDisconnected() { - console.warn("Failed to connect: " + chrome.runtime.lastError.message); - hatchPort = null; - browserPorts = {}; -} - -/** - * Respond to 'ping' requests to let the browser know we exist. - */ -chrome.runtime.onMessageExternal.addListener( - function(request, sender, sendResponse) { - if (request && request.ping) { - console.debug("Got 'ping' request from tab: " + sender.tab.id); - sendResponse({pong : true}); - } - return true; - } -); - -/** - * Called when a browser tab opens a connection to this extension. - */ -chrome.runtime.onConnectExternal.addListener(function(port) { - var tabId = port.sender.tab.id; - - browserPorts[tabId] = port; - console.debug('new port connected with id ' + tabId); - - port.onMessage.addListener(function(msg) { - console.debug("Received message from browser on port " + tabId); - - if (!msg) { // belt+suspenders - console.warn("Received NULL message"); - return; - } - - // tag the message with the browser tab ID for response routing. - msg.clientid = tabId; - - if (msg.action == 'init') { - // "init" messages require origin info. - // Extract just the protocol + host - msg.origin = port.sender.url.match(/https?:\/\/[^\/]+/)[0]; - console.debug("Init'ing message with origin: " + msg.origin); - } - - hatchPort.postMessage(msg); - }); - - port.onDisconnect.addListener(function() { - console.log("Removing port " + tabId + " on tab disconnect"); - delete browserPorts[tabId]; - }); -}); - - -/** - * Connect to Hatch on startup. - */ -var hostName = "org.evergreen_ils.hatch"; -console.debug("Connecting to native messaging host: " + hostName); -hatchPort = chrome.runtime.connectNative(hostName); -hatchPort.onMessage.addListener(onNativeMessage); -hatchPort.onDisconnect.addListener(onDisconnected); - diff --git a/extension/app/manifest.json b/extension/app/manifest.json index 902cb48b04..ec39606ff9 100644 --- a/extension/app/manifest.json +++ b/extension/app/manifest.json @@ -1,17 +1,22 @@ { // Extension ID: knldjmfmopnpolahpmmgbagdohdnhkik "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcBHwzDvyBQ6bDppkIs9MP4ksKqCMyXQ/A52JivHZKh4YO/9vJsT3oaYhSpDCE9RPocOEQvwsHsFReW2nUEc6OLLyoCFFxIb7KkLGsmfakkut/fFdNJYh0xOTbSN8YvLWcqph09XAY2Y/f0AL7vfO1cuCqtkMt8hFrBGWxDdf9CQIDAQAB", - "name": "Hatch Native Messaging Extension", + "name": "Hatch Native Messenger", "version": "1.0", "manifest_version": 2, "description": "Relays messages to/from Hatch.", "background" : { - "scripts" : ["main.js"] + "scripts" : ["extension.js"] + }, + "browser_action": { + "default_title": "Hatch" }, "permissions": [ - "nativeMessaging" + "nativeMessaging", + "declarativeContent" + ], + "optional_permissions": [ + "https://*/eg/staff/*" ], - "externally_connectable": { - "matches": ["*://evergreen.example.org/*"] - } + "minimum_chrome_version": "38" }