From b5260e150a3fb351f6233d970811b27dd9056116 Mon Sep 17 00:00:00 2001 From: Simeon Vincent Date: Fri, 12 Jul 2024 18:42:56 -0700 Subject: [PATCH 1/7] Update native-messaging to use python3, clarify instructions Fixes #560 --- native-messaging/README.md | 56 ++++++++++++++++++-------- native-messaging/add-on/background.js | 18 ++++++++- native-messaging/add-on/manifest.json | 2 +- native-messaging/app/ping_pong.json | 2 +- native-messaging/app/ping_pong.py | 7 ++-- native-messaging/app/ping_pong_win.bat | 2 +- 6 files changed, 63 insertions(+), 24 deletions(-) diff --git a/native-messaging/README.md b/native-messaging/README.md index 60fce8a0..86228a95 100644 --- a/native-messaging/README.md +++ b/native-messaging/README.md @@ -4,36 +4,60 @@ The WebExtension, which can be found under "add-on", connects to the native appl The native application, which can be found under "app", listens for messages from the WebExtension. When it receives a message, the native application sends a response message whose payload is just "pong". The native application is written in Python. -## Setup ## +## Setup To get this working, there's a little setup to do. -### Mac OS/Linux setup ### +### Linux/macOS setup -1. Check that the [file permissions](https://en.wikipedia.org/wiki/File_system_permissions) for "ping_pong.py" include the `execute` permission. -2. Edit the "path" property of "ping_pong.json" to point to the location of "ping_pong.py" on your computer. -3. copy "ping_pong.json" to the correct location on your computer. See [App manifest location ](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find the correct location for your OS. +1. Make sure that you have Python 3 installed, and that your system's PATH environment variable includes the path to Python by executing the following command: -### Windows setup ### + ```bash + > which python3 + /usr/local/bin/python3 + ``` -1. Check you have Python installed, and that your system's PATH environment variable includes the path to Python. See [Using Python on Windows](https://docs.python.org/2/using/windows.html). You'll need to restart the web browser after making this change, or the browser won't pick up the new environment variable. -2. Edit the "path" property of "ping_pong.json" to point to the location of "ping_pong_win.bat" on your computer. Note that you'll need to escape the Windows directory separator, like this: `"path": "C:\\Users\\MDN\\native-messaging\\app\\ping_pong_win.bat"`. -3. Edit "ping_pong_win.bat" to refer to the location of "ping_pong.py" on your computer. -4. Add a registry key containing the path to "ping_pong.json" on your computer. See [App manifest location ](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find details of the registry key to add. + If you don't see the path of the application as above, you most likely need to install Python 3 on your computer. See [Using Python on Unix platforms](https://docs.python.org/3/using/unix.html) or [Using Python on a Mac](https://docs.python.org/3/using/windows.html). Restart the web browser after making this change in order for Firefox to pick up the new PATH environment variable. -To assist in troubleshooting on Windows, there is a script called `check_config_win.py`. Running this from the command line should give you an idea of any problems. +2. Make sure that the [file permissions](https://en.wikipedia.org/wiki/File_system_permissions) for `app/ping_pong.py` include the `execute` permission. See [this article by RedHat](https://www.redhat.com/sysadmin/linux-file-permissions-explained) for more information. -## Testing the example ## +3. Update the `"path"` field in `app/ping_pong.json` to be the full path to your `app/ping_pong.py` file. -First, install the add-on. Visit `about:debugging#/runtime/this-firefox` or, from `about:debugging` click "This Firefox" (or "This Nightly" in the Nightly version of Firefox), click "Load Temporary Add-on", and open the add-on's "manifest.json". + For example, if you cloned this repository into `/Users/MDN/webextensions-examples/`, you would update the file like this: -Now, open the extension's console using the "Inspect" button - this is where you'll see communication between the browser and native app. + ```json + "path": "/Users/MDN/webextensions-examples/native-messaging/app/ping_pong.py" + ``` + +4. Copy `app/ping_pong.json` to the correct location on your computer. There are too many options to list here; see the [Linux](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#linux) and [macOS](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#macos) secitons of [App manifest location ](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find the correct location for your OS and personal preference. + +### Windows setup + +1. Make sure that you have Python 3 installed and that your system's PATH environment variable includes the path to Python. See [Using Python on Windows](https://docs.python.org/3/using/windows.html). You'll need to restart the web browser after making this change, or the browser won't pick up the new environment variable. + +2. Update the `"path"` field in `app\ping_pong.json` to use the full path of `app\ping_pong_win.bat` on your computer. Be aware that you'll need to escape the Windows directory separator (`\`). + + For example, if you cloned this repository into `C:\Users\MDN\webextensions-examples\`, you would update the JSON file like this: + + ```json + "path": "C:\\Users\\MDN\\webextensions-examples\\native-messaging\\app\\ping_pong_win.bat" + ``` + +3. Update `app\ping_pong_win.bat` to use the full path of `app\ping_pong.py` on your computer. + +4. Add a registry key containing the full path of `app\ping_pong.json` on your computer. See [App manifest location](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find details of the registry key to add. + +To assist in troubleshooting on Windows, there is a script next to this README file named `check_config_win.py`. Running this in a command shell should help you discover of any problems. + +## Testing the example + +First, install the add-on. Visit `about:debugging#/runtime/this-firefox` or, from `about:debugging` click "This Firefox" (or "This Nightly" in the Nightly version of Firefox), click "Load Temporary Add-on", and open the add-on's `manifest.json`. + +Now, open the extension's console using the "Inspect" button - this is where you'll see communication between the browser and native app. You should see a new browser action icon in the toolbar. Click it. You should see output like this in the console: Sending: ping Received: pong3 -If you're running Python 2.x, you'll see "pong2" as the response instead. - If you don't see this output, see the [Troubleshooting guide](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_messaging#Troubleshooting) for ideas. diff --git a/native-messaging/add-on/background.js b/native-messaging/add-on/background.js index 020e6edd..d1e07dcf 100644 --- a/native-messaging/add-on/background.js +++ b/native-messaging/add-on/background.js @@ -4,14 +4,28 @@ On startup, connect to the "ping_pong" app. let port = browser.runtime.connectNative("ping_pong"); /* -Listen for messages from the app. +Listen for messages from the app and log them to the console. */ port.onMessage.addListener((response) => { console.log("Received: " + response); }); /* -On a click on the browser action, send the app a message. +Listen for the native messaging port closing. +*/ +port.onDisconnect.addListener((port) => { + if (port.error) { + console.log(`Disconnected due to an error: ${port.error.message}`); + } else { + // The port closed for an unspecified reason. If this occurred right after + // calling `browser.runtime.connectNative()` there may have been a problem + // starting the the native messaging client in the first place. + console.log(`Disconnected`, port); + } +}); + +/* +When the extension's action icon is clicked, send the app a message. */ browser.browserAction.onClicked.addListener(() => { console.log("Sending: ping"); diff --git a/native-messaging/add-on/manifest.json b/native-messaging/add-on/manifest.json index 0a7800c1..d0555584 100644 --- a/native-messaging/add-on/manifest.json +++ b/native-messaging/add-on/manifest.json @@ -22,7 +22,7 @@ "browser_action": { "default_icon": "icons/message.svg" }, - + "permissions": ["nativeMessaging"] } diff --git a/native-messaging/app/ping_pong.json b/native-messaging/app/ping_pong.json index a257b181..a19e0c29 100644 --- a/native-messaging/app/ping_pong.json +++ b/native-messaging/app/ping_pong.json @@ -1,7 +1,7 @@ { "name": "ping_pong", "description": "Example host for native messaging", - "path": "/path/to/native-messaging/app/ping_pong.py", + "path": "/Users/svincent/dev/webextensions-examples/native-messaging/app/ping_pong.py", "type": "stdio", "allowed_extensions": [ "ping_pong@example.org" ] } diff --git a/native-messaging/app/ping_pong.py b/native-messaging/app/ping_pong.py index e9343800..895d5e5e 100755 --- a/native-messaging/app/ping_pong.py +++ b/native-messaging/app/ping_pong.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import sys import json @@ -19,7 +19,7 @@ def getMessage(): # given its content. def encodeMessage(messageContent): # https://docs.python.org/3/library/json.html#basic-usage - # To get the most compact JSON representation, you should specify + # To get the most compact JSON representation, you should specify # (',', ':') to eliminate whitespace. # We want the most compact representation because the browser rejects # messages that exceed 1 MB. @@ -37,6 +37,7 @@ def sendMessage(encodedMessage): receivedMessage = getMessage() if receivedMessage == "ping": sendMessage(encodeMessage("pong3")) + except AttributeError: # Python 2.x version (if sys.stdin.buffer is not defined) # Read a message from stdin and decode it. @@ -52,7 +53,7 @@ def getMessage(): # given its content. def encodeMessage(messageContent): # https://docs.python.org/3/library/json.html#basic-usage - # To get the most compact JSON representation, you should specify + # To get the most compact JSON representation, you should specify # (',', ':') to eliminate whitespace. # We want the most compact representation because the browser rejects # messages that exceed 1 MB. diff --git a/native-messaging/app/ping_pong_win.bat b/native-messaging/app/ping_pong_win.bat index aac2019f..0d52af96 100644 --- a/native-messaging/app/ping_pong_win.bat +++ b/native-messaging/app/ping_pong_win.bat @@ -1,3 +1,3 @@ @echo off -call python C:\path\to\ping_pong.py +call python3 C:\path\to\ping_pong.py From 55c434810eca5f5b1a4be4d0a5b821d47b884d39 Mon Sep 17 00:00:00 2001 From: Simeon Vincent Date: Wed, 17 Jul 2024 12:28:41 -0700 Subject: [PATCH 2/7] Remove Python 2 support --- native-messaging/app/ping_pong.py | 97 ++++++++++--------------------- 1 file changed, 30 insertions(+), 67 deletions(-) diff --git a/native-messaging/app/ping_pong.py b/native-messaging/app/ping_pong.py index 895d5e5e..39e3d117 100755 --- a/native-messaging/app/ping_pong.py +++ b/native-messaging/app/ping_pong.py @@ -4,70 +4,33 @@ import json import struct -try: - # Python 3.x version - # Read a message from stdin and decode it. - def getMessage(): - rawLength = sys.stdin.buffer.read(4) - if len(rawLength) == 0: - sys.exit(0) - messageLength = struct.unpack('@I', rawLength)[0] - message = sys.stdin.buffer.read(messageLength).decode('utf-8') - return json.loads(message) - - # Encode a message for transmission, - # given its content. - def encodeMessage(messageContent): - # https://docs.python.org/3/library/json.html#basic-usage - # To get the most compact JSON representation, you should specify - # (',', ':') to eliminate whitespace. - # We want the most compact representation because the browser rejects - # messages that exceed 1 MB. - encodedContent = json.dumps(messageContent, separators=(',', ':')).encode('utf-8') - encodedLength = struct.pack('@I', len(encodedContent)) - return {'length': encodedLength, 'content': encodedContent} - - # Send an encoded message to stdout - def sendMessage(encodedMessage): - sys.stdout.buffer.write(encodedMessage['length']) - sys.stdout.buffer.write(encodedMessage['content']) - sys.stdout.buffer.flush() - - while True: - receivedMessage = getMessage() - if receivedMessage == "ping": - sendMessage(encodeMessage("pong3")) - -except AttributeError: - # Python 2.x version (if sys.stdin.buffer is not defined) - # Read a message from stdin and decode it. - def getMessage(): - rawLength = sys.stdin.read(4) - if len(rawLength) == 0: - sys.exit(0) - messageLength = struct.unpack('@I', rawLength)[0] - message = sys.stdin.read(messageLength) - return json.loads(message) - - # Encode a message for transmission, - # given its content. - def encodeMessage(messageContent): - # https://docs.python.org/3/library/json.html#basic-usage - # To get the most compact JSON representation, you should specify - # (',', ':') to eliminate whitespace. - # We want the most compact representation because the browser rejects - # messages that exceed 1 MB. - encodedContent = json.dumps(messageContent, separators=(',', ':')) - encodedLength = struct.pack('@I', len(encodedContent)) - return {'length': encodedLength, 'content': encodedContent} - - # Send an encoded message to stdout - def sendMessage(encodedMessage): - sys.stdout.write(encodedMessage['length']) - sys.stdout.write(encodedMessage['content']) - sys.stdout.flush() - - while True: - receivedMessage = getMessage() - if receivedMessage == "ping": - sendMessage(encodeMessage("pong2")) +# Read a message from stdin and decode it. +def getMessage(): + rawLength = sys.stdin.buffer.read(4) + if len(rawLength) == 0: + sys.exit(0) + messageLength = struct.unpack('@I', rawLength)[0] + message = sys.stdin.buffer.read(messageLength).decode('utf-8') + return json.loads(message) + +# Encode a message for transmission, given its content. +def encodeMessage(messageContent): + # https://docs.python.org/3/library/json.html#basic-usage + # To get the most compact JSON representation, you should specify + # (',', ':') to eliminate whitespace. + # We want the most compact representation because the browser rejects + # messages that exceed 1 MB. + encodedContent = json.dumps(messageContent, separators=(',', ':')).encode('utf-8') + encodedLength = struct.pack('@I', len(encodedContent)) + return {'length': encodedLength, 'content': encodedContent} + +# Send an encoded message to stdout +def sendMessage(encodedMessage): + sys.stdout.buffer.write(encodedMessage['length']) + sys.stdout.buffer.write(encodedMessage['content']) + sys.stdout.buffer.flush() + +while True: + receivedMessage = getMessage() + if receivedMessage == "ping": + sendMessage(encodeMessage("pong")) From 2d767fa652a97837edbcd1ee8ce2f5fc3fc2c063 Mon Sep 17 00:00:00 2001 From: Simeon Vincent Date: Wed, 17 Jul 2024 12:29:06 -0700 Subject: [PATCH 3/7] Add doc link for additional help --- native-messaging/add-on/background.js | 1 + 1 file changed, 1 insertion(+) diff --git a/native-messaging/add-on/background.js b/native-messaging/add-on/background.js index d1e07dcf..f4c9b092 100644 --- a/native-messaging/add-on/background.js +++ b/native-messaging/add-on/background.js @@ -20,6 +20,7 @@ port.onDisconnect.addListener((port) => { // The port closed for an unspecified reason. If this occurred right after // calling `browser.runtime.connectNative()` there may have been a problem // starting the the native messaging client in the first place. + // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging#troubleshooting console.log(`Disconnected`, port); } }); From cdf409a9bfe04ff2135ec414405a309658216686 Mon Sep 17 00:00:00 2001 From: Simeon Vincent Date: Wed, 17 Jul 2024 12:34:18 -0700 Subject: [PATCH 4/7] Note directory restrictions on macOS --- native-messaging/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/native-messaging/README.md b/native-messaging/README.md index 86228a95..a3de3a09 100644 --- a/native-messaging/README.md +++ b/native-messaging/README.md @@ -10,6 +10,8 @@ To get this working, there's a little setup to do. ### Linux/macOS setup +0. (macOS) Make sure that you did not copy this extension into the Desktop, Documents, or Downloads folders in your home directory. macOS has access restrictions on these directories that will prevent the Python script from executing as expected. + 1. Make sure that you have Python 3 installed, and that your system's PATH environment variable includes the path to Python by executing the following command: ```bash From 8a66c92283db0976fb2c1f13faec321ac8cc201f Mon Sep 17 00:00:00 2001 From: Simeon Vincent Date: Wed, 17 Jul 2024 12:35:32 -0700 Subject: [PATCH 5/7] Update native-messaging/app/ping_pong.json Co-authored-by: Rob Wu --- native-messaging/app/ping_pong.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native-messaging/app/ping_pong.json b/native-messaging/app/ping_pong.json index a19e0c29..a257b181 100644 --- a/native-messaging/app/ping_pong.json +++ b/native-messaging/app/ping_pong.json @@ -1,7 +1,7 @@ { "name": "ping_pong", "description": "Example host for native messaging", - "path": "/Users/svincent/dev/webextensions-examples/native-messaging/app/ping_pong.py", + "path": "/path/to/native-messaging/app/ping_pong.py", "type": "stdio", "allowed_extensions": [ "ping_pong@example.org" ] } From d2d2255f77b425fffec3710e16663ed45d98e0a4 Mon Sep 17 00:00:00 2001 From: Simeon Vincent Date: Thu, 18 Jul 2024 15:22:39 -0700 Subject: [PATCH 6/7] Apply suggestions from code review Co-authored-by: rebloor --- native-messaging/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/native-messaging/README.md b/native-messaging/README.md index a3de3a09..2b8febf3 100644 --- a/native-messaging/README.md +++ b/native-messaging/README.md @@ -10,16 +10,16 @@ To get this working, there's a little setup to do. ### Linux/macOS setup -0. (macOS) Make sure that you did not copy this extension into the Desktop, Documents, or Downloads folders in your home directory. macOS has access restrictions on these directories that will prevent the Python script from executing as expected. +0. (macOS) Store this extension in a location other than the Desktop, Documents, or Downloads folders in your home directory. macOS has access restrictions on these directories that prevent the Python script from executing as expected. -1. Make sure that you have Python 3 installed, and that your system's PATH environment variable includes the path to Python by executing the following command: +1. Make sure you have Python 3 installed, and your system's PATH environment variable includes the path to Python. You can check by executing this command: ```bash > which python3 /usr/local/bin/python3 ``` - If you don't see the path of the application as above, you most likely need to install Python 3 on your computer. See [Using Python on Unix platforms](https://docs.python.org/3/using/unix.html) or [Using Python on a Mac](https://docs.python.org/3/using/windows.html). Restart the web browser after making this change in order for Firefox to pick up the new PATH environment variable. + If you don't see the path for Python, install Python 3. See [Using Python on Unix platforms](https://docs.python.org/3/using/unix.html) (for Linux) or [Using Python on a Mac](https://docs.python.org/3/using/mac.html). After making this change, restart Firefox so it picks up the new PATH environment variable. 2. Make sure that the [file permissions](https://en.wikipedia.org/wiki/File_system_permissions) for `app/ping_pong.py` include the `execute` permission. See [this article by RedHat](https://www.redhat.com/sysadmin/linux-file-permissions-explained) for more information. @@ -35,11 +35,11 @@ To get this working, there's a little setup to do. ### Windows setup -1. Make sure that you have Python 3 installed and that your system's PATH environment variable includes the path to Python. See [Using Python on Windows](https://docs.python.org/3/using/windows.html). You'll need to restart the web browser after making this change, or the browser won't pick up the new environment variable. +1. Make sure that you have Python 3 installed and that your system's PATH environment variable includes the path to Python. See [Using Python on Windows](https://docs.python.org/3/using/windows.html). After making this change, restart Firefox so it picks up the new PATH environment variable. -2. Update the `"path"` field in `app\ping_pong.json` to use the full path of `app\ping_pong_win.bat` on your computer. Be aware that you'll need to escape the Windows directory separator (`\`). +2. Update the `"path"` field in `app\ping_pong.json` to use the full path of `app\ping_pong_win.bat` on your computer. Be aware that you must escape the Windows directory separator (`\`). - For example, if you cloned this repository into `C:\Users\MDN\webextensions-examples\`, you would update the JSON file like this: + For example, if you cloned this repository into `C:\Users\MDN\webextensions-examples\`, you update the JSON file like this: ```json "path": "C:\\Users\\MDN\\webextensions-examples\\native-messaging\\app\\ping_pong_win.bat" @@ -55,7 +55,7 @@ To assist in troubleshooting on Windows, there is a script next to this README f First, install the add-on. Visit `about:debugging#/runtime/this-firefox` or, from `about:debugging` click "This Firefox" (or "This Nightly" in the Nightly version of Firefox), click "Load Temporary Add-on", and open the add-on's `manifest.json`. -Now, open the extension's console using the "Inspect" button - this is where you'll see communication between the browser and native app. +Now, open the extension's console using the "Inspect" button. This is where you see communication between the browser and native app. You should see a new browser action icon in the toolbar. Click it. You should see output like this in the console: From 735dee777c51ca595bbca0311ce239e312764674 Mon Sep 17 00:00:00 2001 From: rebloor Date: Wed, 23 Oct 2024 14:29:04 +1300 Subject: [PATCH 7/7] Update README.md Example now simply returns "pong" --- native-messaging/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native-messaging/README.md b/native-messaging/README.md index 2b8febf3..1cb028dc 100644 --- a/native-messaging/README.md +++ b/native-messaging/README.md @@ -60,6 +60,6 @@ Now, open the extension's console using the "Inspect" button. This is where you You should see a new browser action icon in the toolbar. Click it. You should see output like this in the console: Sending: ping - Received: pong3 + Received: pong If you don't see this output, see the [Troubleshooting guide](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_messaging#Troubleshooting) for ideas.