diff --git a/_archive/mv2/api/nativeMessaging/README.txt b/_archive/mv2/api/nativeMessaging/README.md similarity index 94% rename from _archive/mv2/api/nativeMessaging/README.txt rename to _archive/mv2/api/nativeMessaging/README.md index c0269460..547d4492 100644 --- a/_archive/mv2/api/nativeMessaging/README.txt +++ b/_archive/mv2/api/nativeMessaging/README.md @@ -4,9 +4,11 @@ messaging API that allows to communicate with a native application. In order for this example to work you must first install the native messaging host from the host directory. -To install the host: +## To install the host: + + +**On Windows:** -On Windows: Run install_host.bat script in the host directory. This script installs the native messaging host for the current user, by creating a registry key @@ -17,7 +19,8 @@ On Windows: HKLM. Note that you need to have python installed. -On Mac and Linux: +**On Mac and Linux:** + Run install_host.sh script in the host directory: host/install_host.sh By default the host is installed only for the user who runs the script, but if diff --git a/_archive/mv2/api/nativeMessaging/host/install_host.sh b/_archive/mv2/api/nativeMessaging/host/install_host.sh index f968c379..c1d70581 100755 --- a/_archive/mv2/api/nativeMessaging/host/install_host.sh +++ b/_archive/mv2/api/nativeMessaging/host/install_host.sh @@ -6,15 +6,17 @@ set -e DIR="$( cd "$( dirname "$0" )" && pwd )" -if [ "$(uname -s)" = "Darwin" ]; then - if [ "$(whoami)" = "root" ]; then +if [ $(uname -s) == 'Darwin' ]; then + if [ "$(whoami)" == "root" ]; then TARGET_DIR="/Library/Google/Chrome/NativeMessagingHosts" + chmod a+x "$DIR/native-messaging-example-host" else TARGET_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts" fi else - if [ "$(whoami)" = "root" ]; then + if [ "$(whoami)" == "root" ]; then TARGET_DIR="/etc/opt/chrome/native-messaging-hosts" + chmod a+x "$DIR/native-messaging-example-host" else TARGET_DIR="$HOME/.config/google-chrome/NativeMessagingHosts" fi @@ -29,11 +31,11 @@ mkdir -p "$TARGET_DIR" cp "$DIR/$HOST_NAME.json" "$TARGET_DIR" # Update host path in the manifest. -HOST_PATH=$DIR/native-messaging-example-host +HOST_PATH="$DIR/native-messaging-example-host" ESCAPED_HOST_PATH=${HOST_PATH////\\/} sed -i -e "s/HOST_PATH/$ESCAPED_HOST_PATH/" "$TARGET_DIR/$HOST_NAME.json" # Set permissions for the manifest so that all users can read it. chmod o+r "$TARGET_DIR/$HOST_NAME.json" -echo "Native messaging host $HOST_NAME has been installed." +echo Native messaging host $HOST_NAME has been installed. diff --git a/_archive/mv2/api/nativeMessaging/host/native-messaging-example-host b/_archive/mv2/api/nativeMessaging/host/native-messaging-example-host index 8c94ed85..08f41623 100755 --- a/_archive/mv2/api/nativeMessaging/host/native-messaging-example-host +++ b/_archive/mv2/api/nativeMessaging/host/native-messaging-example-host @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -9,11 +9,11 @@ import struct import sys import threading -import Queue +import queue as Queue try: - import Tkinter - import tkMessageBox + import tkinter as Tkinter + import tkinter.messagebox except ImportError: Tkinter = None @@ -27,7 +27,7 @@ if sys.platform == "win32": # Helper function that sends a message to the webapp. def send_message(message): # Write message size. - sys.stdout.write(struct.pack('I', len(message))) + sys.stdout.buffer.write(struct.pack('I', len(message))) # Write the message itself. sys.stdout.write(message) sys.stdout.flush() @@ -37,7 +37,7 @@ def read_thread_func(queue): message_number = 0 while 1: # Read the message length (first 4 bytes). - text_length_bytes = sys.stdin.read(4) + text_length_bytes = sys.stdin.buffer.read(4) if len(text_length_bytes) == 0: if queue: @@ -45,10 +45,13 @@ def read_thread_func(queue): sys.exit(0) # Unpack message length as 4 byte integer. - text_length = struct.unpack('i', text_length_bytes)[0] + text_length = struct.unpack('@I', text_length_bytes)[0] # Read the text (JSON object) of the message. - text = sys.stdin.read(text_length).decode('utf-8') + text = sys.stdin.buffer.read(text_length).decode('utf-8') + + if text == '{"text":"exit"}': + break if queue: queue.put(text) @@ -57,22 +60,22 @@ def read_thread_func(queue): send_message('{"echo": %s}' % text) if Tkinter: - class NativeMessagingWindow(Tkinter.Frame): + class NativeMessagingWindow(tkinter.Frame): def __init__(self, queue): self.queue = queue - Tkinter.Frame.__init__(self) + tkinter.Frame.__init__(self) self.pack() - self.text = Tkinter.Text(self) + self.text = tkinter.Text(self) self.text.grid(row=0, column=0, padx=10, pady=10, columnspan=2) - self.text.config(state=Tkinter.DISABLED, height=10, width=40) + self.text.config(state=tkinter.DISABLED, height=10, width=40) - self.messageContent = Tkinter.StringVar() - self.sendEntry = Tkinter.Entry(self, textvariable=self.messageContent) + self.messageContent = tkinter.StringVar() + self.sendEntry = tkinter.Entry(self, textvariable=self.messageContent) self.sendEntry.grid(row=1, column=0, padx=10, pady=10) - self.sendButton = Tkinter.Button(self, text="Send", command=self.onSend) + self.sendButton = tkinter.Button(self, text="Send", command=self.onSend) self.sendButton.grid(row=1, column=1, padx=10, pady=10) self.after(100, self.processMessages) @@ -93,14 +96,14 @@ if Tkinter: try: send_message(text) except IOError: - tkMessageBox.showinfo('Native Messaging Example', + tkinter.messagebox.showinfo('Native Messaging Example', 'Failed to send message.') sys.exit(1) def log(self, message): - self.text.config(state=Tkinter.NORMAL) - self.text.insert(Tkinter.END, message + "\n") - self.text.config(state=Tkinter.DISABLED) + self.text.config(state=tkinter.NORMAL) + self.text.insert(tkinter.END, message + "\n") + self.text.config(state=tkinter.DISABLED) def Main(): diff --git a/api-samples/nativeMessaging/README.md b/api-samples/nativeMessaging/README.md new file mode 100644 index 00000000..617277a0 --- /dev/null +++ b/api-samples/nativeMessaging/README.md @@ -0,0 +1,34 @@ +# Native Messaging + +This directory contains an example of Chrome extension that uses [Native Messaging](https://developer.chrome.com/docs/extensions/develop/concepts/native-messaging) to communicate with a native application. + +## Running this extension + +1. Clone this repository. +2. Load this directory in Chrome as an [unpacked extension](https://developer.chrome.com/docs/extensions/mv3/getstarted/development-basics/#load-unpacked). +3. Follow the installation instructions below. +4. Open the popup. +5. Send messages from either the native application or extension. + +## To install the host: + +### Windows + +Run `install_host.bat` script in the host directory. + +This script installs the native messaging host for the current user, by creating a registry key +` HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.google.chrome.example.echo` +and setting its default value to the full path to `host\com.google.chrome.example.echo-win.json`. + +If you want to install the native messaging host for all users, change HKCU to HKLM. + +Note that you need to have Python installed. + +### Mac and Linux + +Run `install_host.sh` script in the host directory: `host/install_host.sh` + +By default the host is installed only for the user who runs the script, but if +you run it with admin privileges (i.e. `sudo host/install_host.sh`), then the +host will be installed for all users. You can later use `host/uninstall_host.sh` +to uninstall the host. diff --git a/api-samples/nativeMessaging/extension/icon-128.png b/api-samples/nativeMessaging/extension/icon-128.png new file mode 100644 index 00000000..c3bd2fd4 Binary files /dev/null and b/api-samples/nativeMessaging/extension/icon-128.png differ diff --git a/api-samples/nativeMessaging/extension/main.html b/api-samples/nativeMessaging/extension/main.html new file mode 100644 index 00000000..fae39532 --- /dev/null +++ b/api-samples/nativeMessaging/extension/main.html @@ -0,0 +1,18 @@ + + + + +
+ + + + + + + + + diff --git a/api-samples/nativeMessaging/extension/main.js b/api-samples/nativeMessaging/extension/main.js new file mode 100644 index 00000000..1dbb2786 --- /dev/null +++ b/api-samples/nativeMessaging/extension/main.js @@ -0,0 +1,55 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let message; +let port = null; + +function appendMessage(text) { + document.getElementById('response').innerHTML += '' + text + '
'; +} + +function updateUiState() { + if (port) { + document.getElementById('connect-button').style.display = 'none'; + document.getElementById('input-text').style.display = 'block'; + document.getElementById('send-message-button').style.display = 'block'; + } else { + document.getElementById('connect-button').style.display = 'block'; + document.getElementById('input-text').style.display = 'none'; + document.getElementById('send-message-button').style.display = 'none'; + } +} + +function sendNativeMessage() { + message = { text: document.getElementById('input-text').value }; + port.postMessage(message); + appendMessage('Sent message: ' + JSON.stringify(message) + ''); +} + +function onNativeMessage(message) { + appendMessage('Received message: ' + JSON.stringify(message) + ''); +} + +function onDisconnected() { + appendMessage('Failed to connect: ' + chrome.runtime.lastError.message); + port = null; + updateUiState(); +} + +function connect() { + var hostName = 'com.google.chrome.example.echo'; + appendMessage('Connecting to native messaging host ' + hostName + ''); + port = chrome.runtime.connectNative(hostName); + port.onMessage.addListener(onNativeMessage); + port.onDisconnect.addListener(onDisconnected); + updateUiState(); +} + +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('connect-button').addEventListener('click', connect); + document + .getElementById('send-message-button') + .addEventListener('click', sendNativeMessage); + updateUiState(); +}); diff --git a/api-samples/nativeMessaging/extension/manifest.json b/api-samples/nativeMessaging/extension/manifest.json new file mode 100644 index 00000000..00d328b1 --- /dev/null +++ b/api-samples/nativeMessaging/extension/manifest.json @@ -0,0 +1,17 @@ +{ + "manifest_version": 3, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcBHwzDvyBQ6bDppkIs9MP4ksKqCMyXQ/A52JivHZKh4YO/9vJsT3oaYhSpDCE9RPocOEQvwsHsFReW2nUEc6OLLyoCFFxIb7KkLGsmfakkut/fFdNJYh0xOTbSN8YvLWcqph09XAY2Y/f0AL7vfO1cuCqtkMt8hFrBGWxDdf9CQIDAQAB", + "name": "Native Messaging Example", + "version": "1.0", + "description": "Send a message to a native application.", + "action": { + "default_title": "Native Messaging Example", + "default_popup": "main.html" + }, + "icons": { + "128": "icon-128.png" + }, + "permissions": [ + "nativeMessaging" + ] +} diff --git a/api-samples/nativeMessaging/host/com.google.chrome.example.echo-win.json b/api-samples/nativeMessaging/host/com.google.chrome.example.echo-win.json new file mode 100644 index 00000000..84e54484 --- /dev/null +++ b/api-samples/nativeMessaging/host/com.google.chrome.example.echo-win.json @@ -0,0 +1,13 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +{ + "name": "com.google.chrome.example.echo", + "description": "Chrome Native Messaging API Example Host", + "path": "native-messaging-example-host.bat", + "type": "stdio", + "allowed_origins": [ + "chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/" + ] +} diff --git a/api-samples/nativeMessaging/host/com.google.chrome.example.echo.json b/api-samples/nativeMessaging/host/com.google.chrome.example.echo.json new file mode 100644 index 00000000..dfeae04f --- /dev/null +++ b/api-samples/nativeMessaging/host/com.google.chrome.example.echo.json @@ -0,0 +1,13 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +{ + "name": "com.google.chrome.example.echo", + "description": "Chrome Native Messaging API Example Host", + "path": "HOST_PATH", + "type": "stdio", + "allowed_origins": [ + "chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/" + ] +} diff --git a/api-samples/nativeMessaging/host/install_host.bat b/api-samples/nativeMessaging/host/install_host.bat new file mode 100644 index 00000000..8b88ab8c --- /dev/null +++ b/api-samples/nativeMessaging/host/install_host.bat @@ -0,0 +1,7 @@ +:: Copyright 2014 The Chromium Authors. All rights reserved. +:: Use of this source code is governed by a BSD-style license that can be +:: found in the LICENSE file. + +:: Change HKCU to HKLM if you want to install globally. +:: %~dp0 is the directory containing this bat script and ends with a backslash. +REG ADD "HKCU\Software\Google\Chrome\NativeMessagingHosts\com.google.chrome.example.echo" /ve /t REG_SZ /d "%~dp0com.google.chrome.example.echo-win.json" /f diff --git a/api-samples/nativeMessaging/host/install_host.sh b/api-samples/nativeMessaging/host/install_host.sh new file mode 100755 index 00000000..e5b62a8b --- /dev/null +++ b/api-samples/nativeMessaging/host/install_host.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +set -e + +DIR="$( cd "$( dirname "$0" )" && pwd )" +if [ $(uname -s) == 'Darwin' ]; then + if [ "$(whoami)" == "root" ]; then + # Due to macOS permission changes we need to put the host in /Applications + HOST_PATH="/Applications/native-messaging-example-host" + cp "$DIR/native-messaging-example-host" $HOST_PATH + + TARGET_DIR="/Library/Google/Chrome/NativeMessagingHosts" + chmod a+x "$DIR/native-messaging-example-host" + else + # Due to macOS permission changes we need to put the host in ~/Applications + HOST_PATH="/Users/$USER/Applications/native-messaging-example-host" + cp "$DIR/native-messaging-example-host" $HOST_PATH + + TARGET_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts" + fi +else + HOST_PATH="$DIR/native-messaging-example-host" + if [ "$(whoami)" == "root" ]; then + TARGET_DIR="/etc/opt/chrome/native-messaging-hosts" + chmod a+x "$DIR/native-messaging-example-host" + else + TARGET_DIR="$HOME/.config/google-chrome/NativeMessagingHosts" + fi +fi + +HOST_NAME=com.google.chrome.example.echo + +# Create directory to store native messaging host. +mkdir -p "$TARGET_DIR" + +# Copy native messaging host manifest. +cp "$DIR/$HOST_NAME.json" "$TARGET_DIR" + +# Update host path in the manifest. +ESCAPED_HOST_PATH=${HOST_PATH////\\/} +sed -i -e "s/HOST_PATH/$ESCAPED_HOST_PATH/" "$TARGET_DIR/$HOST_NAME.json" + +# Set permissions for the manifest so that all users can read it. +chmod o+r "$TARGET_DIR/$HOST_NAME.json" + +echo Native messaging host $HOST_NAME has been installed. diff --git a/api-samples/nativeMessaging/host/native-messaging-example-host b/api-samples/nativeMessaging/host/native-messaging-example-host new file mode 100644 index 00000000..08f41623 --- /dev/null +++ b/api-samples/nativeMessaging/host/native-messaging-example-host @@ -0,0 +1,131 @@ +#!/usr/bin/python3 +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# A simple native messaging host. Shows a Tkinter dialog with incoming messages +# that also allows to send message back to the webapp. + +import struct +import sys +import threading +import queue as Queue + +try: + import tkinter as Tkinter + import tkinter.messagebox +except ImportError: + Tkinter = None + +# On Windows, the default I/O mode is O_TEXT. Set this to O_BINARY +# to avoid unwanted modifications of the input/output streams. +if sys.platform == "win32": + import os, msvcrt + msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) + msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) + +# Helper function that sends a message to the webapp. +def send_message(message): + # Write message size. + sys.stdout.buffer.write(struct.pack('I', len(message))) + # Write the message itself. + sys.stdout.write(message) + sys.stdout.flush() + +# Thread that reads messages from the webapp. +def read_thread_func(queue): + message_number = 0 + while 1: + # Read the message length (first 4 bytes). + text_length_bytes = sys.stdin.buffer.read(4) + + if len(text_length_bytes) == 0: + if queue: + queue.put(None) + sys.exit(0) + + # Unpack message length as 4 byte integer. + text_length = struct.unpack('@I', text_length_bytes)[0] + + # Read the text (JSON object) of the message. + text = sys.stdin.buffer.read(text_length).decode('utf-8') + + if text == '{"text":"exit"}': + break + + if queue: + queue.put(text) + else: + # In headless mode just send an echo message back. + send_message('{"echo": %s}' % text) + +if Tkinter: + class NativeMessagingWindow(tkinter.Frame): + def __init__(self, queue): + self.queue = queue + + tkinter.Frame.__init__(self) + self.pack() + + self.text = tkinter.Text(self) + self.text.grid(row=0, column=0, padx=10, pady=10, columnspan=2) + self.text.config(state=tkinter.DISABLED, height=10, width=40) + + self.messageContent = tkinter.StringVar() + self.sendEntry = tkinter.Entry(self, textvariable=self.messageContent) + self.sendEntry.grid(row=1, column=0, padx=10, pady=10) + + self.sendButton = tkinter.Button(self, text="Send", command=self.onSend) + self.sendButton.grid(row=1, column=1, padx=10, pady=10) + + self.after(100, self.processMessages) + + def processMessages(self): + while not self.queue.empty(): + message = self.queue.get_nowait() + if message == None: + self.quit() + return + self.log("Received %s" % message) + + self.after(100, self.processMessages) + + def onSend(self): + text = '{"text": "' + self.messageContent.get() + '"}' + self.log('Sending %s' % text) + try: + send_message(text) + except IOError: + tkinter.messagebox.showinfo('Native Messaging Example', + 'Failed to send message.') + sys.exit(1) + + def log(self, message): + self.text.config(state=tkinter.NORMAL) + self.text.insert(tkinter.END, message + "\n") + self.text.config(state=tkinter.DISABLED) + + +def Main(): + if not Tkinter: + send_message('"Tkinter python module wasn\'t found. Running in headless ' + + 'mode. Please consider installing Tkinter."') + read_thread_func(None) + sys.exit(0) + + queue = Queue.Queue() + + main_window = NativeMessagingWindow(queue) + main_window.master.title('Native Messaging Example') + + thread = threading.Thread(target=read_thread_func, args=(queue,)) + thread.daemon = True + thread.start() + + main_window.mainloop() + + sys.exit(0) + + +if __name__ == '__main__': + Main() diff --git a/api-samples/nativeMessaging/host/native-messaging-example-host.bat b/api-samples/nativeMessaging/host/native-messaging-example-host.bat new file mode 100644 index 00000000..430179e9 --- /dev/null +++ b/api-samples/nativeMessaging/host/native-messaging-example-host.bat @@ -0,0 +1,6 @@ +@echo off +:: Copyright (c) 2013 The Chromium Authors. All rights reserved. +:: Use of this source code is governed by a BSD-style license that can be +:: found in the LICENSE file. + +python "%~dp0/native-messaging-example-host" %* diff --git a/api-samples/nativeMessaging/host/uninstall_host.bat b/api-samples/nativeMessaging/host/uninstall_host.bat new file mode 100644 index 00000000..5c2631f1 --- /dev/null +++ b/api-samples/nativeMessaging/host/uninstall_host.bat @@ -0,0 +1,7 @@ +:: Copyright 2014 The Chromium Authors. All rights reserved. +:: Use of this source code is governed by a BSD-style license that can be +:: found in the LICENSE file. + +:: Deletes the entry created by install_host.bat +REG DELETE "HKCU\Software\Google\Chrome\NativeMessagingHosts\com.google.chrome.example.echo" /f +REG DELETE "HKLM\Software\Google\Chrome\NativeMessagingHosts\com.google.chrome.example.echo" /f diff --git a/api-samples/nativeMessaging/host/uninstall_host.sh b/api-samples/nativeMessaging/host/uninstall_host.sh new file mode 100755 index 00000000..04f18843 --- /dev/null +++ b/api-samples/nativeMessaging/host/uninstall_host.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +set -e + +if [ "$(uname -s)" = "Darwin" ]; then + if [ "$(whoami)" = "root" ]; then + HOST_PATH="/Applications/native-messaging-example-host" + rm $HOST_PATH + TARGET_DIR="/Library/Google/Chrome/NativeMessagingHosts" + else + HOST_PATH="/Users/$USER/Applications/native-messaging-example-host" + rm $HOST_PATH + TARGET_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts" + fi +else + if [ "$(whoami)" = "root" ]; then + TARGET_DIR="/etc/opt/chrome/native-messaging-hosts" + else + TARGET_DIR="$HOME/.config/google-chrome/NativeMessagingHosts" + fi +fi + +HOST_NAME=com.google.chrome.example.echo +rm "$TARGET_DIR/com.google.chrome.example.echo.json" +echo "Native messaging host $HOST_NAME has been uninstalled."