Chrome Extension NativeMessaging 'connectNative' undefined - javascript

I am trying to implement a chrome extension using runtime.connectNative and postMessage. I am following the chrome documentation, downloaded the native messaging example which I'm trying to run without any changes, while the code for the native host application can be found here.
However, I'm getting the error:
Uncaught TypeError: Cannot read property 'connectNative' of undefined.
The error is being triggered from the javascript extension file, in this line:
port = chrome.runtime.connectNative(hostName);
while the extension is being loaded from the manifest like so:
"app": {
"launch": {
"local_path": "main.html"
}
}
Any ideas how to solve the problem please?
Chrome version 34, tested on windows 7, 8.1

The immediate problem is that you are not running the sample code correctly. The larger problem is that Google has not provided comprehensive documentation on how to use this sample code.
The Native Messaging example you referenced only links to the sample code for the Chrome extension. After searching around I was able to find related sample code for the native messaging host application. To get the sample code for both the Chrome extension and native messaging host application together you'll want to download nativeMessaging.zip. In that zip file you'll also find some brief instructions on how to install the native messaging host on Windows, Linux and Mac OS X. I'll tell you right now that the instructions are incomplete as they do not tell you how to install the Chrome extension. Additionally the scripts for installing and uninstalling the native messaging host do not work as-is on OS X. See below for my installation instructions and corrected scripts.
How to install the sample extension and native host application
Download and unzip the nativeMessaging.zip file.
Install the Chrome extension
In Chrome enter chrome://extensions/ in the address bar
Click the “Load unpacked extension...” button
Navigate to the unzipped nativeMessaging directory and select the app directory for import
Install the native messaging host application
For OS X and Linux you’ll need to add execute permission to some of the files. Run the command: chmod a+rx nativeMessaging/host/install_host.sh nativeMessaging/host/native-messaging-example-host nativeMessaging/host/uninstall_host.sh
For OS X you’ll need to fix some bugs in nativeMessaging/host/install_host.sh and nativeMessaging/host/uninstall_host.sh. See below for the corrected scripts.
For OS X, Linux and Windows follow the instructions in nativeMessaging/README.txt
Run the Chrome extension
In Chrome enter chrome://apps/ in the address bar
Click on the Native Messaging Example app icon
After the app loads you should see a single button named “Connect.” Click that button and you should see the native messaging host application launch automatically.
Corrected nativeMessaging/host/install_host.sh
#!/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
TARGET_DIR="/Library/Google/Chrome/NativeMessagingHosts"
else
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
# 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.
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.
Corrected nativeMessaging/host/uninstall_host.sh
#!/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
TARGET_DIR="/Library/Google/Chrome/NativeMessagingHosts"
else
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.

I would like to provide a python 3 version of the script to replace native-messaging-example-host. It is tested with Chrome v86 and works as expected. Note that python kernel crashes when tkinter window is closed - this is because of binary data exchange inside threading which causes thread to be hard locked (more info here). I added a command exit to be send from chrome app to stop thread's waiting for another stdin. After receiving it, python won't crash on exit.
Python 3 version (tested with 3.7.4):
# 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()
Disclaimer: I used 2to3 utility for initial conversion to python 3. I also adopted changes from a webextensions (firefox) version of the nativeMessage API example (it is simplified and not using tkinter gui).

Related

Launching on android WEBAPP with ADB

Is there a method to launch a web app using adb?
The web app is created using manifest.json and save on android using chrome browser.
I've tried to get the package name of the web application using adb shell pm list packages but nothing seems to match.
I want to launch my web app this way adb shell am start -n com.package.name/com.package.name.ActivityName
I've also tried this way adb shell am start -a android.intent.action.VIEW -d "url". This works but it is not what I am looking for.
Assuming you are coming from Javascript world (as you could have done this by looking at adb logs), this should be what you are looking for
adb shell am start -a com.google.android.apps.chrome.webapps.WebappManager.ACTION_START_WEBAPP -n com.android.chrome/org.chromium.chrome.browser.webapps.WebappLauncherActivity --es "org.chromium.chrome.browser.webapp_url" "{your_url}" --es "org.chromium.chrome.browser.webapp_mac" "{webapp_mac}"
Note that this url has to match the url/url-ending you have mentioned in the start_url that you have mentioned in the manifest.json of yours, else it will just open it as another chrome tab.
Another caveat here is you have to pass web app mac validation check, which is done by the core android class mentioned here - WebappAuthenticator
Chrome does not keep a store of valid URLs for installed web apps
(because it cannot know when any have been uninstalled). Therefore,
upon installation, it tells the Launcher a message authentication code
(MAC) along with the URL for the web app, and then Chrome can verify
the MAC when starting e.g. {#link #FullScreenActivity}. Chrome can
thus distinguish between legitimate, installed web apps and arbitrary
other URLs.
I gave it a shot to open one of the webapps I own. I gave up after a bit, getting lost in the cryptic algos. Maybe you will have some luck with it. All the best!!!

Device Orientation API not working with local webserver

While working with the Device Orientation API I noticed something strange.
The following online demo works perfectly (except for "compassneedscalibration"): https://www.audero.it/demo/device-orientation-api-demo.html
But when I clone the Soucecode locally and provide the Web page via a local Web server* the API seems to not be available anymore. Although using the same browser tab. Also no Messages, warnings or errors appear in the JavaScript console.
The Web page states:
deviceorientation event not supported
devicemotion event not supported
compassneedscalibration event not supported
Am I doing something wrong? Or is this an intended behavior or a bug?
I will need to provide my web app by a local web server.
I am using "Chrome 79.0.3945.93" on "Android 7.1.1;VNS-L21 Build/NMF26V"
*) python3 -m http.server
I found out that you need to provide the wep page via an Encrypted HTTPS connection on order to access the Device Orientation API and also some mediaDevices.
A simple way of providing HTTPS pages during development (not production) is this simple python webserver:
#!/usr/bin/env python3
# Based on http://www.piware.de/2011/01/creating-an-https-server-in-python/
# generate server.xml with the following command:
# openssl req -new -x509 -keyout key.pem -out server.pem -days 365 -nodes
# run as follows:
# python3 simple-https-server.py
# then in your browser, visit:
# https://localhost:4443
import http.server
import ssl
import os
directory_of_script = os.path.dirname(os.path.abspath(__file__))
#server_address = ('localhost', 4443)
server_address = ('', 4443)
httpd = http.server.HTTPServer(server_address, http.server.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket,
server_side=True,
certfile=os.path.join(directory_of_script, "server.pem") ,
keyfile=os.path.join(directory_of_script, "key.pem"),
ssl_version=ssl.PROTOCOL_TLS)
httpd.serve_forever()

deploying js with python and spacy lib

I have never setup things this way, I got it running locally but have no clue how I should have do it when I deploy it into an ec2 server
I have a node app running already in ec2 server but recently I have added spaCy into one of my api.
The basic logic is calling the api which runs node and part of the js script uses spawn to process the proc.py file and do some calculation with outputs.
I have tried the following below to setup on my server but of course it failed when calling the api
my original node app is in /var/www/myApp
I used sudo apt install virtualenv then inside my /var/www/myApp I ran the command virtualenv venv which creates the virtual environment...
I did a source venv/bin/activate to get into the virtual environment
Then I started running the commands to install spacy mentioned in the spacy documentation https://github.com/explosion/spaCy
used this command to install pip install -U spacy and python -m spacy download en
Then I ran python -m spacy validate to see if spacy is installed which I got
Installed models (spaCy v2.0.11)
/var/www/myApp/venv/local/lib/python2.7/site-packages/spacy
TYPE NAME MODEL VERSION
package en-core-web-sm en_core_web_sm 2.0.0 ✔
link en en_core_web_sm 2.0.0 ✔
which I believe this means the installation is a success.
But after this, I am not sure what I should do to continue.
I tried running my api but getting this as an error message "err": "Traceback (most recent call last):\n"
I would believe the spacy module is not being called that's why I am getting this error but I am not sure what I should do to get this working.
Would really appreciate for any help, thanks in advance for any advices.
EDIT:
my proc.py code is below
if __name__ == '__main__':
import sys
import json
import spacy
nlp = spacy.load('en')
text = sys.argv[1]
doc = nlp(text)
all_noun_tokens = [ token.lemma_ for token in doc
if (token.pos_ == 'PROPN'
or token.pos_ == 'NOUN'
or token.tag_ == 'NN'
or token.tag_ == 'NNP') ]
print(json.dumps(all_noun_tokens))
P.S. I am wondering if there's any config that I need to do in order for my app to find where the virtuanenv is so it can detect the spacy module?

weblogic undeploy apps command line

I have a requirement where i need to undeploy war files in weblogic using command line, the below code does it for me :
java weblogic.Deployer -adminurl t3://localhost:8001 -user weblogic -password password123 -name <name> -undeploy
But the file names change after every deployment, i,e (file 1.0.0 and file 1.1.1).
i need a command in such a way so that it undeploys all the files present in that server.
can any body let me know how to undeploy all files at a single go ?
Thanks in advance,
Vishal
I have found out how to undeploy all the apps :
List Apps:
import sys
connect('weblogic','weblogic10','http://autowfm-vmh:7259')
cd("AppDeployments")
app = ls(returnMap='true')
domainRuntime()
cd("AppRuntimeStateRuntime/AppRuntimeStateRuntime")
i=1
f = open('filename.txt','w')
for appName in app:
print >>f, appName
i=i+1
f.close()
exit()
Undeploy :
import os
connect('weblogic','weblogic','http://localhost:7001')
target='AdminServer'
f = open(r'D:\filename.txt','r')
print f
for i in range(10):
line=f.readline()
line1=line[:-1]
appName='./'+line1
print '*****************'+appName
undeploy(appName=line1)
exit()
If you want to script a more generic answer you can list all the apps via:
java -cp /opt/ora/mw/wlserver_10.3/server/lib/weblogic.jar weblogic.Deployer
-adminurl t3://host:port -username weblogic -password weblogic1 -listapps
And then parse that output to begin removing apps.
The <name> should be the module name not the file (war or ear) name. Using the -undeploycommand without the -targets and -submoduletargets flags completely removes the application or standalone module from all WebLogic Server instances and untargets all JMS sub-module resources.
BTW, Adding the -graceful option would allow current HTTP clients to complete their work before undeploying.
Note: Undeploying a deployment unit does not remove the original source files used for deployment. It only removes the deployment's configuration from the domain, as well as any deployment files that WebLogic Server created during deployment (for example, files copied with stage deployment mode and files uploaded to the Administration Server).
I have found out how to undeploy all the apps without using files
def undeployWars():
cd("AppDeployments")
namesWars = ls(returnMap='true')
for nameWar in namesWars:
undeploy(nameWar)
connect('weblogic', 'weblogic01', 't3://localhost:7001')
undeployWars()
disconnect()
exit()

How to register a url protocol handler in Node.js

I am developing a command line node module and would like to be able to launch it via links on a website.
I want to register a custom protocol my-module:// such that links would have the following format: my-module://action:some-action and clicking on them would start the node package.
If there isn't a node API for this (I'm sure there won't be) then is there a way I can do it from node by invoking system commands?
It must work on Windows, Linux, and MacOS.
Its an interesting idea. I don't think there is currently a cross platform node.js solution out there. I did come across this thread of people asking for the same thing:
https://github.com/rogerwang/node-webkit/issues/951
Electron now supports it with the app.setAsDefaultProtocolClient API (since v0.37.4) for macOS and Windows.
It wouldn't be terribly difficult to write the library to do this.
Windows:
On the windows side you'd have to register the app as the application that handles that URI scheme.
You'll need to set up a registry entry for your application:
HKEY_CLASSES_ROOT
alert
(Default) = "URL:Alert Protocol"
URL Protocol = ""
DefaultIcon
(Default) = "alert.exe,1"
shell
open
command
(Default) = "C:\Program Files\Alert\alert.exe" "%1"
Then, when your application is run by windows, you should be able to see the arguments in process.argv[]. Make sure that you launch a shell to run node, not just your application directly.
Original MSDN article
Note this requires administrator privileges and sets the handler system-wide. To do it per user, you can use HKEY_CURRENT_USER\Software\Classes instead, as the Electron's implementation does it.
Apple:
The cited "OS X" article in the github comment is actually for iOS. I'd look at the following programming guide for info on registering an application to handle a URL scheme:
Apple Dev Documentation
In summary, you'll need to create a launch service and populate the .plist file with CFBundleURLTypes, this field is an array and should be populated with just the protocol name i.e. http
The following Super User Question has a better solution, but is a per user setting.
"The file you seek is ~/Library/Preferences/com.apple.LaunchServices.plist.
It holds an array called LSHandlers, and the Dictionary children that define an LSHandlerURLScheme can be modified accordingly with the LSHandlerRole."
Linux:
From what I can tell, there are several ways to accomplish this in Linux (surprise?)
Gnome has a tool that will let you register a url handler w3 archives
gconftool-2 -t string -s /desktop/gnome/url-handlers/tel/command "bin/vonage-call %s"
gconftool-2 -s /desktop/gnome/url-handlers/tel/needs_terminal false -t bool
gconftool-2 -t bool -s /desktop/gnome/url-handlers/tel/enabled true
Some of the lighter weight managers look like they allow you to create fake mime types and register them as URI Protocol handlers.
"Fake mime-types are created for URIs with various scheme like this:
application/x-xdg-protocol-
Applications supporting specific URI protocol can add the fake mime-type to their MimeType key in their desktop entry files. So it's easy to find out all applications installed on the system supporting a URI scheme by looking in mimeinfo.cache file. Again defaults.list file can be used to specify a default program for speficied URI type." wiki.lxde.org
KDE also supports their own method of handling URL Protocol Handlers:
Create a file: $KDEDIR/share/services/your.protocol and populate it with relevant data:
[Protocol]
exec=/path/to/player "%u"
protocol=lastfm
input=none
output=none
helper=true
listing=
reading=false
writing=false
makedir=false
deleting=false
from last.fm forums of all places
Hope that helps.
Here's how I did on Mac OS with an application NW.js :
Open the app /Applications/Utilities/Script Editor
type the following code in the editor
on open location this_URL
do shell script "/Applications/X.app/Contents/MacOS/x '" & this_URL & "'"
end open location
Replace X by the name of your App.
Save the script as an Application Bundle anywhere
Go to the script, right click then 'Show Package Contents' then edit Contents/info.plist
Add these lines at the end of the file, just before </dict></plist> :
<key>CFBundleIdentifier</key>
<string>com.mycompany.AppleScript.AppName</string> <!-- edit here -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>AppName</string> <!-- edit here -->
<key>CFBundleURLSchemes</key>
<array>
<string>myurlscheme</string> <!-- your url scheme here -->
</array>
</dict>
</array>
You can now open a link starting with myurlscheme: and see your app is opening!
Edit :
Looks like the module has changed the registration process for good:
const path = require('path');
const ProtocolRegistry = require('protocol-registry');
console.log('Registering...');
// Registers the Protocol
ProtocolRegistry.register({
protocol: 'testproto', // sets protocol for your command , testproto://**
command: `node ${path.join(__dirname, './tester.js')} $_URL_`, // this will be executed with a extra argument %url from which it was initiated
override: true, // Use this with caution as it will destroy all previous Registrations on this protocol
terminal: true, // Use this to run your command inside a terminal
script: false
}).then(async () => {
console.log('Successfully registered');
});
Original Answer :
There is an npm module for this purpose.
link :https://www.npmjs.com/package/protocol-registry
So to do this in nodejs you just need to run the code below:
First Install it
npm i protocol-registry
Then use the code below to register you entry file.
const path = require('path');
const ProtocolRegistry = require('protocol-registry');
console.log('Registering...');
// Registers the Protocol
ProtocolRegistry.register({
protocol: 'testproto', // set your app for testproto://**
command: `node ${path.join(__dirname, './index.js')}`, // this will be executed with a extra argument %url from which it was initiated
}).then(async () => {
console.log('Successfully registered');
});
Then suppose someone opens testproto://test
then a new terminal will be launched executing :
node yourapp/index.js testproto://test

Categories