Catching keyboard shortcut outside of a browser using a browser extension? - javascript

I have a project where I require a Push-to-Talk feature. I came to the conclusion that it may be do-able if I create an extension/plugin for Chrome/Firefox. The site is HTML5 based with WebRTC and I would like to implement a alternative plugin/extension users can download that will allow them to use push to talk outside of the browser. I.e. when the browser is minimized but the website is still open in the browser.
I want the plugin/extension to still listen for the keystrokes. Is this do-able? Or do I need to create an application the users can download where the application will make a hook into the websites webrtc API and allow the users to use Push-to-Talk? I would rather like to stay away from the users having to download a .exe and much rather them just able to install a plugin/extension for their Chrome or Firefox browsers.

It is doable in principle in Chrome, as you can define global shortcuts with chrome.commands:
Manifest:
"commands": {
"push-to-talk": {
"suggested_key": {
"default": "Ctrl+Shift+1"
},
"description": "Activate push-to-talk",
"global": true
}
},
Background:
chrome.commands.onCommand.addListener(function(command) {
if(command == "push-to-talk"){
// Do whatever you want, e.g. bring focus to browser,
// pass commands to page with content scripts etc.
}
});

Related

How to check if a Firefox WebExtension is installed or not with page JavaScript?

I have developed a WebExtension for Firefox and my website works with the extension as a prerequisite. I need to check programmatically whether the extension is installed or not and if not ask the user to install it.
I am not able to find a way how to check this operation of whether my extension is already installed in the user's browser.
Editor note: Methods available in Firefox differ from those available in Chrome, so this question is not a duplicate.
Important note to begin with: A page can't query if an extension is installed without explicit help from the extension. This is done to prevent browser fingerprinting and/or preventing sites from denying content if certain extensions are installed.
WebExtensions are largely built upon the same principles as Chrome extensions. As such, this question is relevant: Check whether user has a Chrome extension installed.
However, some of the best methods available in Chrome are currently unavailable in Firefox:
You can't use external messaging from a webpage (through externally_connectable) as it's not available in FF.
You can't use web-accessible resources for checking presence since Firefox intentionally shields them from fingerprinting:
The files will then be available using a URL like:
moz-extension://<random-UUID>/<path/to/resource>
This UUID is randomly generated for every browser instance and is not your extension's ID. This prevents websites from fingerprinting the extensions a user has installed.
As such, what are your options? The page can't talk directly to the extension context (background), and the background can't directly affect the page; you need a Content script to interact with the page content.
How can page code and a content script communicate? They are isolated from each other unless content script does something about it.
First off, generic tricks that work in both FF and Chrome:
You can create or modify a DOM element on the page from a content script and look for those modifications in the page.
// Content script
let beacon = document.createElement("div");
beacon.classname = browser.runtime.id;
document.body.appendChild(beacon);
// Page script
// Make sure this runs after the extension code
if (document.getElementsByClassName("expected-extension-id").length) {
// Installed
} else {
// Not installed
}
You can use postMessage to communicate between contexts, though it's clunky to use as a bidirectional channel.
Here's documentation and sample WebExtension.
// Content script code
window.postMessage({
direction: "from-content-script",
message: "Message from extension"
}, "*");
// Page code
window.addEventListener("message", function(event) {
if (event.source == window &&
event.data.direction &&
event.data.direction == "from-content-script") {
// Assume extension is now installed
}
});
You can use custom DOM events in a similar way.
There are interesting Firefox-specific approaches as well:
You can share code with the page using exportFunction or cloneInto:
// Content script
function usefulFunction() {
/* ... */
}
const extensionInterface = {
usefulFunction
}
window.wrappedJSObject.extensionInterface =
cloneInto(extensionInterface, window, {cloneFunctions: true});
// Page code
if (typeof window.extensionInterface !== "undefined") {
// Installed
window.extensionInterface.usefulFunction();
} else {
// Not installed
}

WebdriverIO automation testing when JavaScript is disabled

Is there a way in WebdriverIO framework to launch the browser with JavaScript disabled?
I want to automate a scenario with JavaScript being disabled. But, when I manually disable the JavaScript in Chrome, or Firefox and run the WDIO scripts, the browser always opens with JavaScript enabled.
Not anymore. (but you have a workaround below)
This used to be easily achieved using the chromium switches. But considering all driver implementations (chromedriver, geckodriver, etc.) now require JavaScript to drive your spawned browser instance, it's no longer possible.
It was achieved via chromeOptions arguments/switches:
capabilities: [{
maxInstances: 2,
browserName: config[env].browser,
chromeOptions: {
args: ['--disable-javascript',
'--disable-javascript-harmony-shipping'
]
}
}]
!!! LATER EDIT: You can achieve this by loading a custom profile.
Start your WebdriverIO test case, but add a browser.debug() after you load your page;
In the address bar, type chrome://settings/content and in the modal, check the Do not allow any site to run JavaScript. Click Done. Now go to a random page and notice JavaScript has been blocked on it:
Now we have to save this custom profile and load it each time you start a WebdriverIO test case. Type chrome://version in your address bar. Notice the Profile Path value. Copy the content of the folder (e.g.: For C:\Users\<yourUserName>\Desktop\scoped_dir18256_17319\Default, copy the scoped_dir18256_17319 folder on your Desktop). This folder contains all the actions (search history, extensions installed, accounts saved... in our case, JavaScript disabled option) on THIS current instance.
Now all we need to do, is add the path to that folder in your wdio.config.js file as a chromeOptions argument:
chromeOptions: {
//extensions: ['./browserPlugins/Avira-SafeSearch-Plus_v1.5.1.crx'],
args: [ '--user-data-dir=/Users/<yourUserName>/Desktop/scoped_dir18256_17319'
]
}
Now all you have to do is run your test cases with this custom profile and JavaScript will be blocked on all websites. Hope this is the behavior you are looking for as there is no other way to achieve this behavior.
Cheers!

Google Chrome Application Native Messaging

So I wrote a question here earlier about opening native software (browsers) in my chrome application with PNaCl,NaCl, or NPAPI which I guess are not allowed anymore or were never allowed depending on which we are talking about. So a user pointed me to Native Messaging, and I am just trying to create something that will open a users HTML file in a browser they chose.
So they have index.html and they want to test it in Firefox, Chrome, and IE so they run each one and test.
Documentation
https://developer.chrome.com/extensions/nativeMessaging
Example from Google
http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/nativeMessaging/host/
This is my first time dealing with this stuff and I don't want to have my users go to a REGEDIT file and add it and blah blah blah. It should be simple as possible, they download my app and it's done.
Native Messaging Manifest --- (which not 100% sure where to put it)
{
"name": "com.kandidesigns.kodex",
"description": "Kodex is a Chrome Application to make programming websites easier and efficient",
"path": "C:\\Program Files\\My Application\\chrome_native_messaging_host.exe",
"type": "stdio", //standard input or standard output not sure which one to use
"allowed_origins": [
"chrome-extension://bbbgompnaiddjohgmdhmienllkjkilap/"
]
}
Permissions have inside the apps manifest : "nativeMessaging"
BATCH program to run a file
SET /p ID="Enter browser"
SET /p URL="Enter URL"
IF "%ID%"=="0" start chrome %URL%
IF "%ID%"=="1" start firefox %URL%
IF "%ID%"=="2" start edge %URL%
IF "%ID%"=="3" start internet explorer %URL%
IF "%ID%"=="4" start safari %URL%
ELSE ECHO "No browser found by that classification"
Never wrote a bat file to figure out where to go and what to open etc... Here is
another tutorial I've watched which is very low and pathetic sorry.
https://www.youtube.com/watch?v=H82-9hg1Plg
Anyways if someone could lead me the right way and assist on this I'd be greatly appreciated.
The manifest file they are referring to is an independent file, not to be confused with your application manifest. Just declare a new json file, and introduce the code for the manifest (in the documentation, the file should be named nmh-manifest.json). The file can be located anywhere in the system file, but you'll need to describe the full path.
Here is a reference for a demo app implementing Native Messaging: https://chromium.googlesource.com/chromium/src/+/master/chrome/common/extensions/docs/examples/api/nativeMessaging

How to add "open link in app mode" to right-click menu in chrome?

app mode: chrome window without navigation panel(address+tab bars). Run this in terminal
google-chrome --app=http://stackoverflow.com/
I want to open a website in app mode directly from chrome. Is there an extension that adds such option? If not how do I write a small extension that does just that? I never wrote a chrome extension but I have some experience with html and javascript. Thanks
Edit: Main issue is chrome.windows.create has no "app" option for CreateType. I guess we can't do anything about it.
There is a way using chrome.management API.
chrome.management.generateAppForLink("http://stackoverflow.com/", "Stack Overflow", function(info) {
chrome.management.setLaunchType(info.id, "OPEN_AS_WINDOW", function() {
chrome.management.launchApp(info.id);
})
});
Note that the above code requires a user gesture (which is undocumented). For examples, see Invoking activeTab. Activating a context menu should be sufficient as a gesture.
However, this will create an app in the app launcher permanently. On the plus side, it will not create duplicates for the same URL/Title.
You can call chrome.management.uninstall(id), but it will require a confirmation from the user.

HTML transient modal window

We have a legacy web application. At various places it opens a window with the help of Privilege Manager on Firefox to get the needed result.
Some of these windows open a Java applet or a PDF document.
The client machines are updating Firefox and Privilege Manager is gone.
What is the easiest way around it?
The problems are :
There must be only one instance of the pop-up at anyone time. This could be done by selecting appropriate window name on window.open() call.
If the window is opened again (by means of user action), it should not reload but just focus to bring it to the foreground (I have seen I can keep a reference to the window on JavaScript to do that)
It basically really must be transient/modal so that the client cannot leave the current page or reload or any other kind of interaction with the parent window (except opening/refocusing the child window) without closing the child window first. I have no idea how to do that.
Do anyone has an idea how to do that?
The client is only Firefox (it works in a special kiosk configuration) on Linux.
I read somewhere that I could somehow write an extension but I am basically clueless about extensions and its API.
Edit1:
Example of (simplified) legacy code. Not really sure if all the permissions were required, but this is it: This function opens a window that stays over the parent window and prevents any interaction from the user with the parent window.
function fWindowOpen(url, name) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserWrite");
netscape.security.PrivilegeManager
.enablePrivilege("CapabilityPreferencesAccess");
netscape.security.PrivilegeManager
.enablePrivilege("UniversalPreferencesWrite");
netscape.security.PrivilegeManager
.enablePrivilege("UniversalPreferencesRead");
netscape.security.PrivilegeManager.enablePrivilege("UniversalFileRead");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
window.open(
url,
name,
"screenX=70,dependent=yes,menubar=0,toolbar=0,width=900,height=700,modal=1,dialog=1"
);
}
function fnCapture(){
fWindowOpen("/path/to/document_or_japplet/page","_blank");
}
HTML:
<button value="Capture" property="btnCapture" onclick="javascript:fnCapture();"/>
Edit2: Solution
On a typical extension, on the xul code, define this javascript code:
var dialogExt = {
listener: function(evt) {
// Do work with parameters read through evt.target.getAttribute("attribute_name")
window.openDialog(evt.target.getAttribute("url"), evt.target.getAttribute("name"), evt.target.getAttribute("features"));
}
}
// from examples
document.addEventListener("dialogExtEvent", function(e){ dialogExt.listener(e); }, false, true);
Then, on the web page:
var element = document.createElement("dialogExtElement");
element.setAttribute("url", url);
element.setAttribute("name", name);
element.setAttribute("features", features);
document.documentElement.appendChild(element);
var evt = document.createEvent("Events");
evt.initEvent("dialogExtEvent", true, false);
element.dispatchEvent(evt);
Now, maybe I am missing some security checks to let the code work if it originates from the same host, and how to handle a reference to the document that requested the dialog as means of interaction between the dialog window and it's opener.
The Privilege Manager was deprecated in Firefox 12 and removed in Firefox 17 (briefly restored).
You might want to look into Window.showModalDialog(). However, it is deprecated and is expected to go away within the year, or in 2016 if you go with an extended service release (ESR) of Firefox 38. It may be a temporary solution while you develop an extension.
In order to accomplish the same tasks, you will need to write an extension and ask the user to install it (from Bypassing Security Restrictions and Signing Code, the old information about Privilege Manager):
Sites that require additional permissions should now ask Firefox users to install an extension, which can interact with non-privileged pages if needed.
It is possible to write such an extension using any of the three different extension types:
XUL overlay
Restartless/Bootstrap
Add-on SDK
For the first two types, you would use window.open(). The modal option is in "Features requiring privileges". You will probably also want to look at Window.openDialog().
For the Add-on SDK, you would normally use the open() function in the SDK's window/utils module. Here, again, you will probably want to look at openDialog().
It appears you may be opening content that is supplied from the web in these modal windows. It is unlikely that you will get an extension approved to be hosted on AMO which opens content in such windows which in not included in the add-on release. This does not mean you can not develop the extension and have it installed on your kiosk clients without hosting it on AMO. However, there are additional restrictions in development for Firefox this year which will make this significantly more difficult, see: "Introducing Extension Signing: A Safer Add-on Experience".
You should be able to get similiar window.open behavior, including support for the modal option from the sdk's window/utils module.
You will have to install the onclick listener with a content script, send a message to the addon-main through its port and then open that window from the addon main.

Categories