externally_connectable and Firefox WebExtensions - firefox-addon

I am trying to convert a Chrome Extension to Firefox using the new API WebExtension.
Everything works fine except the use of chrome.runtime.sendMessage() in a webpage. The goal is to communicate with the addon and pass some data.
For that, I am using the property "externally_connectable" as written here : can-a-site-invoke-a-browser-extension
background.js
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
sendResponse({
success: true,
message: 'ok'
});
return true; // Bug chrome, close channel otherwise
});
In webpage
chrome.runtime.sendMessage(EXTENSION_ID, {type: 'show', data: 'test'}, function(response) {
if (response.success && !response.success) {
console.log(response.message);
}
});
In chrome, the communication works fine but in Firefox, the code executed in the webpage doesn't work : "chrome is not defined".
Is there another var to use instead of "chrome" or is it not implemented ?
I've found nothing about this on the web :( Thanks

Web extensions do not support externally_connectable website scripts but you can communicate between website scripts and extension scripts as shown in this example
https://github.com/mdn/webextensions-examples/tree/master/page-to-extension-messaging

Try use WebExtension APIs with "browser" namespace
browser.runtime.sendMessage(...)
All available APIs on mozilla development
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#WebExtension_APIs

Related

Send message from app (popup.js) to JS (content.js) in Safari Web Extension (iOS 15)

I'm having trouble with a simple task. In Xcode 13, you can create a Safari Extension App (Safari Web Extension for iOS 15).
From looking around, the Shared Extension has various js resources: background.js, content.js, and popup.js.
Popup.js is the presented modal when you launch your Safari web extension. In popup.html, you can add elements to the popup DOM (such as text, button, etc). In my popup, I have a button which I have wired up in popup.js. When I press this button, I want to notify content.js of this event. How do I do this?
My current code adds an event listener to the button containing browser.runtime.sendMessage({ type: "start" }); in popup.js.
Xcode's template includes the following in content.js:
browser.runtime.sendMessage({ greeting: "hello" }).then((response) => {
console.log("Received response: ", response);
});
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log("Received request: ", request);
});
As far as I can tell, the JS is running in popup.js, but I am not seeing anything in console.log for content.js. Sidenote: console.log is really hard to use for iPhone Safari app.
I've found this documentation, but it only discusses passing message from macOS app to JS. I'm trying to pass message from iOS popup to content.js.
See if this works
const isChrome = !window["browser"] && !!chrome;
const browser = isChrome ? chrome : window["browser"];
function sendMessageToContent(message) {
browser.tabs.query({ active: true }).then(function (currentTabs) {
if (currentTabs[0].id >= 0) {
browser.tabs.sendMessage(currentTabs[0].id, message);
}
});
}

.NET + Angular - IIS Server refreshing localhost tab in chrome when request is made from fire fox

This is bizarre.
I have an angular app served from a .NET MVC project. When I make a request to the backend and complete the response the page refreshes. This only happens in chrome.
Here are the weird variations I've triggered:
1) Serve the app in Chrome, complete request, refreshes page.
2) Serve the app in Chrome, open FF to localhost (so the same page is open in two browsers), trigger the request in FF, request completes. FF does not restart, but the chrome tab does.
3) Serve the app in FF, request does not refresh the page. Open chrome to localhost, make the request from either FF or Chrome, page refreshes.
The .NET route hit just responds with a JsonResult after a file upload. This happens consistently after the completed request hits the subscription. Heres some relevent code:
// component
this.myService.uploadFile(formGroup, this.Id).subscribe(result =>
{
console.log(result);
});
// service
public uploadFile(form: FormGroup, id: number) {
const options = {
reportProgress: true,
};
const file: File = form.get('file').value;
const formData = new FormData();
formData.append('File', file, file.name);
formData.append('Id', id.toString());
const request = new HttpRequest('POST', '/file', formData, options);
return this.http.request(request)
.pipe<HttpEvent<any>>(
map((event) => {
return this.updateProgress(event, form);
}),
last()
);
}
I use this exact same format elsewhere in the app for another file upload component that has different requirements and I dont have any issues.
I only know enough .NET to be dangerous and I'm primarily an SPA developer. If you need some more information about the .NET configuration just ask. I'd really like to track this down.
UPDATE: I found this GitHub issue that describes a similar event only in chrome. I added return false and $event.preventDefault() both to the end of the upload() function (its the one called by the (click) event in the template) and at the end of the subscription scope.
I'm lost.

Firefox addon setting custom http header

I'm building a firefox addon and want to set a custom HTTP header.
I've already done some googling and found Setting HTTP headers from a Firefox extension
I however can't get it working.
I've tried placing it in my main.js and when that didn't work in one of my content scripts.
while in main.js the entire addon stops working, can't get a clear error from it though.
When in the content script just that script stops working.
Can anyone help?
For the addon-sdk you need to change that example a bit to look like this:
var chrome = require("chrome");
chrome.Cc["#mozilla.org/observer-service;1"].getService( chrome.Ci.nsIObserverService ).addObserver({
observe : function(subject, topic, data) {
var channel = subject.QueryInterface( chrome.Ci.nsIHttpChannel );
if ( /mysite/.test( channel.originalURI.host ) ) {
channel.setRequestHeader("x-mysite-extended", "true", false);
}
}
},"http-on-modify-request",false);
Note the mysite, you'll want to replace that with your host site and the headers with your headers.

Links will not open in iframe target in an iOS standalone web app

I am running into a pickle. When I view my web app within mobile safari via iOS 6, I am able to successfully open up my basic target links <a href="link.html" target="mainframe"into my retrospective iframe <iframe src="http://www.linkexample.org/" name="mainframe"></iframe>
Though when the app is opened via standalone all the links exit out of the app and into Mobile Safari. You can see a working example at http://lacitilop.com/m2
Anyone have any suggestions on how to fix this?
You'll need to write some javascript to change the src of the iframe.
For a start, get your app working so that links will not open Safari by using something like the following (it's using jquery by the way):
if (window.navigator.standalone) {
$(document).on(
"click",
"a",
function (event) {
event.preventDefault();
var aurl = $(event.target).attr("href");
if (aurl) {
location.href = $(event.target).attr("href");
}
else {
location.href = this;
}
}
);
}
then you'll need to modify it to work with iframes too.
For more iphone app stuff you'll want to look at this:
http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html

Embedding NPAPI plugin in background using just Firefox Addon SDK

I have recently developed a NPAPI plugin (using FireBreath) in combination with a Google Chrome Extension. I am embedding the plugin using the background.html page and access it from multiple extension pages. Thus, the plugin remains loaded in the background page (until the extension is unloaded or the browser is closed).
I am now searching for the easiest way to port this extension to Firefox. Using the Addon SDK and it's API, i can reproduce the communication between the addon code and HTML user interface.
As there is no such global background DOM as in the Chrome Extension, how would I load the NPAPI plugin just once, without inserting it in every page of the app UI?
I've seen that using a XUL overlay would allow that - is there a way using just the addon sdk?
Edit: I've created an answer to this question with a minimal solution to this problem using page-workers.
You'll want to look at the page-worker module:
https://addons.mozilla.org/en-US/developers/docs/sdk/1.8/packages/addon-kit/page-worker.html
The caveat I would give is that the NPAPI plugin might have made assumptions about visibility or other details of the environment it is running in that simply don't apply in the page-worker environment. If you run into errors, I'd be interested to hear them!
The following code provides a minimal working solution to the problem using the page-workers as as canuckistani suggested.
Note: This solution requires the addon-sdk's unsafeWindow to access the plugin member methods. If there's a better solution that does not depend on that, feel free to send a me a note/comment.
data/background.html
<html>
<head>
<script type="text/javascript" charset="utf-8">
function pluginLoaded() {
// Create an event once plugin is loaded
// This allows the contentscript to detect plugin state
var evt = document.createEvent("CustomEvent");
evt.initCustomEvent("pluginLoaded", true, false, null);
window.dispatchEvent(evt);
}
</script>
</head>
<body>
<object id="myplugin" type="application/x-myplugin" width="0" height="0">
<param name="onload" value="pluginLoaded" />
</object>
</body>
</html>
data/background.js
var module = null;
window.addEventListener("pluginLoaded", function( event ) {
// set the module through unsafeWindow
module = unsafeWindow.document.getElementById("myplugin");
module = XPCNativeWrapper.unwrap(module);
self.port.emit("pluginLoaded");
});
// Handle incoming requests to the plugin
self.port.on("pluginCall", function(msg) {
var response;
if (module) {
// Call NPAPI-plugin member method
response = module[msg.method].apply(this, msg.args);
} else {
response = {error: true, error_msg: "Module not loaded!"};
}
self.port.emit("pluginResponse", {data: response});
});
main.js
// Create background page that loads NPAPI plugin
var plugin = require("page-worker").Page({
contentURL: data.url("background.html"),
contentScriptFile: data.url("background.js"),
contentScriptWhen: "ready"
});
// Send request to plugin
plugin.port.emit("pluginCall", message);

Resources