Turn of the Transient User Activation feature of Firefox - firefox

Can firefox be configured in the preferences or through the flags not to use the Transient User Activation feature?
I need to call getDisplayMedia() API in the window.load() event from some machines that are owned by me. However, due to the above feature, all similar apis are getting blocked.

I believe it is not possible to turn this feature off. Note that the Firefox behavior is following what the current web specification says:
If the relevant global object of this does not have transient activation, return a promise rejected with a DOMException object whose name attribute has the value InvalidStateError.
You can expect other browsers to follow this "recent" spec behavior change.

Related

Firefox Extension API - permissions.request may only be called from a user input handler?

I'm using the Firefox permissions API documented HERE
I'm having a problem with the request method, wherein all of my permissions requests result in:
Error: permissions.request may only be called from a user input handler
You can produce this in firefox by debugging any addon or extension and entering browser.permissions.request({origins: ["https://google.com/*"]}) into the console.
I find it hard to swallow that a permissions request must always have a user input event callback in the parent stack trace. I'm using Vue.js, and my Permissions are due to user interaction, but my user interactions are decoupled from the events they trigger.
What counts as a user input handler?
Why does it work like this?
Is there a good work-around?
Is there a good work-around"
I'd like to add onto Andrew's answer with some code examples.
As it turns out, promise chains destroy the browser's notion of what is and isn't triggered by a user input handler. Take the code below, for example:
document.getElementById('foo').addEventListener('click', event => {
browser.permissions.request({origins: ["https://google.com/*"]})
})
This code works as expected. I originally assumed that it was Vue.js's unique event handling framework that was eating my "browser events", such as when you do <div #click="somefunc"></div>. This actually works just fine, as long as you put your permissions request in somefunc.
Now it gets fun. If you replace your permissions request with a promise that resolves and then does a permissions request, VIOLA!
Promise.resolve('foobar').then(foobar => {
browser.permissions.request({origins: ["https://google.com/*"]})
})
Results in:
Error: permissions.request may only be called from a user input handler
Why does this happen?
I'm going to guess it has to do with stack traces. Firefox can't detect that a permission came from a stack with a user input event at the root if the permissions request happens in a promise chain.
I consider this to be a pretty egregious design choice. My app is large (>4K LoC) and to keep it simple I rely on promise chains to keep the spaghetti away. This has crippled my ability to write clean code, and as a result, I've moved from asking for optional_permissions and then prompting the user for permissions only when needed to just being overly permissive at the time of installation.
GG, Firefox.
What counts as a user input handler?
A DOM event handler that corresponds to user input (e.g., target.addEventHandler("click", ...) or a WebExtension event listener that corresponds to user input (e.g., browser.browserAction.onClicked.addListener(...)
Why does it work like this?
Partly for basic UX (if a user is not directly interacting with an extension and a prompt for the extension suddenly prompts up, it can easily confuse them), but also to avoid clickjacking attacks where the prompt is put up at a carefully chosen moment when the user is likely to be expecting some unrelated prompt.
Is there a good work-around?
I think just organizing your code so that you request permissions from a user input handler is probably your best bet.

How to share information between cooperating Firefox WebExtensions

I want to create a straightforward extension for Firefox.
User hovers over some word on any page
Pull the dictionary definition of that word from a file inside the extension
Display it while still hovered
I am new to Firefox add-ons and WebExtensions, so here's what I'm wondering:
I want the dictionary file(s) used by the extension to be local, instead of referring to some online website each time.
Any given user might be interested in a different part of the entire dictionary (it contains entries in different languages, users might only want their own 1 or 2 languages) so I want to avoid forcing every user to download the entire dictionary base.
The way I have seen similar add-ons handle that before Firefox 5.* is that they offer the search-and-display add-on separately from the dictionary files which are each available as add-ons in their own right, only actually doing stuff if you have the master add-on installed.
However, none of those examples seem to have been updated for the WebExtensions API and do not support more recent versions of Firefox.
I have also been unable to find how to communicate between web extensions so far.
My question being, how can I share information between 2 or more coorperating extensions to achieve what I described.
And actually, if this seems really stupid for some reason I'm unaware of, do point out any more reasonable alternatives that allow me to handle the dictionary files separately from the main extension.
Possibly related questions I found:
Communicating between 2 Firefox Add-Ons (Cross-Extension Communication)
This one is from 2010 however, thus out of date as far as I could tell.
Mozilla Addon Development - Communicating between windows with different domains
Kind of a similar situation, but they want to pull the definitions from an online source, rather than a local one.
The closest thing I found on the Mozilla browser extension website is communicating between add-on and some native applications, not quite what I need I think.
Communicating between add-ons is a normal part of the functionality of runtime.sendMessage(), runtime.connect(), runtime.onMessage, and runtime.onConnect.
Both runtime.sendMessage() and runtime.connect() have as their optional first parameter:
extensionId
For runtime.sendMessage(), this is:
string. The ID of the extension to send the message to. Include this to send the message to a different extension. If the intended recipient has set an ID explicitly using the applications key in manifest.json, then extensionId should have that value. Otherwise it should have the ID that was generated for the intended recipient.
If extensionId is omitted, the message will be sent to your own extension.
For runtime.connect(), this is:
string. The ID of the extension to connect to. If the target has set an ID explicitly using the applications key in manifest.json, then extensionId should have that value. Otherwise it should be have the ID that was generated for the target.
Both runtime.onMessage, and runtime.onConnect provide a sender property or parameter, either with the message, or as part of the port. This parameter/property is a runtime.MessageSender which includes an id property which is:
id
string. The ID of the extension that sent the message, if the message was sent by an extension. If the sender set an ID explicitly using the applications key in manifest.json, then id will have this value. Otherwise it will have the ID that was generated for the sender.
Note that in Firefox, before version 54, this value was the extension's internal ID (that is, the UUID that appears in the extension's URL).

Microsoft Edge browser how to read Clipboard data

I am unable to read clipboard data in Microsoft Edge browser. i am using the below javascript.
if (window.clipboardData && window.clipboardData.getData) { // IE
pastedText = window.clipboardData.getData('Text');
} else if (e.clipboardData && e.clipboardData.getData) { //non-IE
pastedText = e.clipboardData.getData('text/plain');
}
Non of the if/elseif block is executed in Edge. I tried using
e.originalEvent.clipboardData.getData('text/plain');
But I am getting 'Access is denied.' error.
Let me know, if anybody know how to fix this issue.
Edge does not currently support the clipboard api, but it is under consideration and likely to be added in near future.
I do not have edge, but it seems that you are not authorized to access the clipboard data. Is this on a website or are you calling this from within a JavaScript script executed locally?
Make sure the website is in the trusted sites.
See https://w3c.github.io/clipboard-apis/#clipboard-event-interfaces, or more precisely:
12.1 Privacy concerns
Untrusted scripts should not get uncontrolled access to a user's clipboard data. This specification assumes that granting access to the current clipboard data when a user explicitly initiates a paste operation from the user agent's trusted chrome is acceptable. However, implementors must proceed carefully, and as a minimum implement the precautions below:
Objects implementing the DataTransfer interface to return clipboard data must not be available outside the ClipboardEvent event handler.
If a script stores a reference to an object implementing the DataTransfer interface to use from outside the ClipboardEvent event handler, all methods must be no-ops when called outside the expected context.
Implementations must not let scripts create synthetic clipboard events to get access to real clipboard data except if configured to do so.
Implementations should not let scripts call document.execCommand('paste') unless the user has explicitly allowed it.
Implementations may choose to further limit the functionality provided by the DataTransfer interface. For example, an implementation may allow the user to disable this API, or configure which web sites should be granted access to it.

How do I access the Request object from RazorViewEngine?

I have subclassed RazorViewEngine so I can check for Request.Browser.IsMobileDevice and add a special mobile identifier to the view file name for it to grab. However I can't access the Request object. What should I do?
You can use either the HttpContext.Current.Request or Context.Request. Although understand how that IsMobileDevice works. It uses a browser file which contains a list of known user agents. As soon as a new device is built, that list is outdated, but in some cases may still identify the device to be mobile correctly. The recommended way is to use 51Degrees or to connect to the services it encompasses directly.

How can a bookmarklet access a Firefox extension (or vice versa)

I have written a Firefox extension that catches when a particular URL is entered and does some stuff. My main app launches Firefox with this URL. The URL contains sensitive information so I don't want it being stored in the history.
I'm concerned about the case where the extension is not installed. If its not installed and Firefox gets launched with the sensitive URL, it will get stored in history and there's nothing I can do about it. So my idea is to use a bookmarklet.
I will launch Firefox with "javascript:window.location.href='pleaseinstallthisplugin.html'; sensitiveinfo='blahblah'".
If the extension is not installed they will get redirected to a page that tells them to install it and the sensitive info won't get stored in the history. If the extension IS installed it will grab the information in the sensitiveinfo variable and do its thing.
My question is, can the bookmarklet call a method in the extension to pass the sensitive info (and if so, how) or can the extension catch when javascript is being called in the bookmarklet?
How can a bookmarklet and Firefox extension communicate?
p.s. The alternative means of getting around this situation would be for my main app to launch Firefox and communicate with the extension using sockets but I am loath to do that because I've run into too many issues over the years with users with crazy firewalls blocking socket communication. I'd like to do everything without sockets if possible.
As far as I know, bookmarklets can never access chrome files (extensions).
Bookmarklets are executed in the scope of the current document, which is almost always a content document. However, if you are passing it in via the command line, it seems to work:
/Applications/Namoroka.app/Contents/MacOS/firefox-bin javascript:alert\(Components\)
Accessing Components would throw if it was not allowed, but the alert displays the proper object.
You could use unsafeWindow to inject a global. You can add a mere property so that your bookmarklet only needs to detect whether the global is defined or not, but you should know that, as far as I know, there is no way to prohibit sites in a non-bookmarklet context from also sniffing for this same global (since it may be a privacy concern to some that sites can detect whether they are using the extension). I have confirmed in my own add-on which injects a global in a manner similar to that below that it does work in a bookmarklet as well as regular site context.
If you register an nsIObserver, e.g., where content-document-global-created is the topic, and then unwrap the subject, you can inject your global (see this if you need to inject something more sophisticated like an object with methods).
Here is some (untested) code which should do the trick:
var observerService = Cc['#mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
observerService.addObserver({observe: function (subject, topic, data) {
var unsafeWindow = XPCNativeWrapper.unwrap(subject);
unsafeWindow.myGlobal = true;
}}, 'content-document-global-created', false);
See this and this if you want an apparently easier way in an SDK add-on (not sure whether SDK postMessage communication would work as an alternative but with the apparently same concern that this would be exposed to non-bookmarklet contexts (i.e., regular websites) as well).

Resources