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()
Related
I'm working on a python flask app for practice. I want to access the getCurrentPosition() of JS to get the geolocation. However, as the app is running on http://localhost:5000/ I'm getting an error that getCurrentPosition() and watchPosition() are deprecated on insecure origins.
Is there a way that it will work on the flask localhost server?
I have found the resolution. Geolocation can only be used in HTTPS requests.
In order to convert your localhost flask app to HTTPS from HTTP, you have to use OpenSSL to create a key and certificate.
Follow the below step to set up your HTTPS environment for the flask localhost server
If you have installed Git then OpenSSL command comes in a package. Open git bash where you want to store the files.
Run the below command in Git Bash.
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
Change your app.run() method in python script to below
context = (r"{path}\certificate.pem", r"{path}\key.pem")
if __name__ == '__main__':
app.run(host='0.0.0.0',port=5000,debug=True,ssl_context=context)
path refers to the location directory where the key and certificate files are stored.
EDIT
I think the problem might be that the WebSocket connection does not go through the proxy node.js. How to authorize the connection of the WebSocket?
I have a web app hosted on a nodeJS server. On the same vm I also have a shiny serveur hosting an app. I use node to redirect traffic to port 3838 (shiny) when a somes URL are requested.
I use this code on node :
app.use('/the-shiny-app', proxy({target: 'http://localhost:3838', changeOrigin: true}));
With this setting everything works fine on the shiny app when I go on mydomain/the-shiny-app/* except when I try to run code in a code box.
When I try to run code I get this error on the chrome console :
Connection closed. Info: {"type":"close","code":4503,"reason":"The application unexpectedly exited","wasClean":true}
An example of what I mean by code box :
if I do not use node.js and I redirect the traffic (on OS level) from port 80 directly to 3838 everything works fine.
sudo iptables -A PREROUTING -t nat -p tcp --dport 80 -j REDIRECT --to-ports 3838
I do not know exactly what kind of exchange is made between the browser and the shiny server when we run code, but maybe the protocol used is blocked by node.js.
I found the problem. As Antony Gibbs said you need to setup a WebSocket upgrade. I'm using http-proxy-middleware you cans find the doc here : https://github.com/chimurai/http-proxy-middleware
I am using windows 2012 server and want to host some static HTML/CSS/JS/image files on a nodejs based web server. I do not want to use IIS as I want to take advantages of HTTP2 & want to push files from server to client. I looked at Using node.js as a simple web server which talks about how to create a node based webserver. Another option is to use http-server node package.
My question is:
These solutions are over two year old. Do we have a better option available now?
Does any of these two options supports HTTP2?
I would prefer using a existing node module rather then reinventing the wheel.
You could try NGINX, it can support HTTP/2. http://nginx.org/en/docs/windows.html
Run your node applications by using default node, nodemon, pm2...
Then use NGINX as a static web server and you can reverse proxy your node apps.
If you want to use Node then this article seems to cover the basics: https://webapplog.com/http2-server-push-node-express/ and it seems the node-spdy module is the best option (it includes support for HTTP/2 despite the name). There is a node-http2 module but it seems much less well maintained and doesn't support Express (the most popular HTTP framework for Node).
However, as discussed in the comments, while not the question you asked, I recommend running a traditional web server (e.g. Apache, Nginx or IIS) in front of NodeJS or any other traditionally back end server. While NodeJS is very flexible and most (if not all) of the functionality of a webserver can be added to it, a traditional web server comes out of the box with a lot of functionality and requires just configuration rather than programming and/or pulling in multiple other modules to set it up properly.
For just serving static files Node seems the wrong solution to me so, for the rest of my answer I'll discuss not not using Node directly for the reasons given above but instead using a front end webserver.
I don't know IIS too well but from a quick Google it seems HTTP/2 was only introduced in IIS 10 and, as far as I know, even IIS 10 doesn't support Push except through API calls so I agree with your decision not to use that for now.
Nginx could be installed instead of IIS, as suggested, and while it supports HTTP/2 it doesn't yet support HTTP/2 (though Cloudflare have added it and run on Nginx so imagine it won't be long coming).
Apache fully supports HTTP/2 including server push. Packaged windows versions of Apache can be downloaded from Apache Lounge so is probably the easiest way of supporting HTTP/2 push on Windows Server and would be my recommendation for the scenario you've given.
While I mostly use Apache on Linux boxes I've a number of servers on Windows and have quite happily been running Apache on that as a Service (so it automatically restarts on server reboot) with no issues so not sure what "bad experience" you had previously but it really is quite stable to me.
To set up Apache on a Windows Server use the following steps:
Download the last version from Apache Lounge.
Unzip the files and save them to C:\ (or C:\Program Files\ if you prefer but update all the config to change the default C:\apache24 to C:\Program Files\)
Edit the conf\httpd.conf file to check ServerRoot, DocumentRoot and any Directory values are set to where you want it (C:\Apache24 by default).
Run a DOS->Command Prompt as Administrator
In the Administrator CD to the Apache location and the bin director.
Run httpd.exe and deal with any error messages (note port 80 must be free so stop anything else running on that report).
Check you get the default "It works!" message on http://localhost/
Install Apache as a service by killing the httpd.exe process and instead running httpd.exe -install.
Start the Apache24 service and again verify you get the "It works!" message on http://localhost/
To add HTTP/2 and HTTPS (necessary for HTTP/2 on all browsers), uncomment the following lines from httpd.conf:
LoadModule http2_module modules/mod_http2.so
...
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
...
LoadModule ssl_module modules/mod_ssl.so
...
Include conf/extra/httpd-ssl.conf
Install a cert and key to conf/server.crt and conf/server.key - note Apache 2.4 expects the cert file to include the cert plus any intermediary certs in X509 Base 64 DER format so should look something like this when opened in a text editor:
-----BEGIN CERTIFICATE-----
MII...etc.
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MII...etc.
-----END CERTIFICATE-----
Where the first cert is the server cert and the 2nd and subsequent certs are the intermediaries.
You should make sure you're running good HTTPS config (the defaults in Apache are very poor), but the defaults will do for now. I've a blog post on that here.
Restart Apache in the service menu and check you can access https://localhost (ignoring any cert error assuming your cert does not cover localhost).
To add HTTP/2 to Apache
Edit the conf/extra/httpd-ssl.conf file to add the following near the top (e.g. after the Listen 443 line):
Protocols h2 http/1.1
Restart Apache in the service menu and check you can access https://localhost (ignoring any cert error assuming your cert does not cover localhost) and you should see h2 as the protocol in the developer tools of your web browser.
To use HTTP/2 push in Apache add the following to push a style sheet:
Header add Link "</path/to/css/styles.css>;rel=preload;as=style" env=!cssloaded
And you should see it pushed to your page in developer tools. Again, I've a blog post on that if you want more information on this.
If you do want to use Node for some (or all) of your calls you can uncomment the following line from conf/httpd.conf:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
And then add the following config:
ProxyPass /nodecontent http://127.0.0.1:8000/
Which will send any of those requests to node service running on port 8000. Restart to pick up this config.
If your node service adds any HTTP headers like this:
link:</path/to/style/styles.css>;rel=preload;as=style
Then Apache should pick them up and push them too. For example if using Express you can use the following to set the headers:
app.get('/test/', function (req, res) {
res.header('link','</path/to/style.css>;rel=preload;as=style');
res.send('This is a test page which also uses Apache to push a CSS file!\n');
});
Finally, while on the subject of HTTP/2 push this article includes a lot of interesting food for thought: https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/
I know this is a fairly old question, but I thought I would give an answer for those that come here looking for info.
Node now has a native http2 module and there are some examples on the web that show exactly how to implement a static web server.
NOTE: At the time of this answer Node 9.6.1 is current and the native module is still experimental
Example https://dexecure.com/blog/how-to-create-http2-static-file-server-nodejs-with-examples/
NOTE: I have no affiliation to the author of the example
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).
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