Thunderbird 67 Extension doesn't inject Content Script in the main tab - firefox-addon

I'm making a Thunderbird Extension through the WebExtension Api (with popup) and i've some difficulties running a Content script to get some elements (attachments list of the current mail for example) directly from Thunderbird interface.
I've made a popup.html , a popup.js and a contentScript.js that runs when the popup is opened. Apparently contentScript.js doesn't run in the main Thunderbird tab, but runs smoothly when i open a new tab (with url) through code.
$(document).ready(function(){
console.log('Try to execute contentScript');
// -- create new tab --
// browser.tabs.create({
// url: 'https://example.org'
// });
// -- execute script in current tab --
browser.tabs.executeScript({
file: 'scripts/contentScript.js'
});
});
// from contentScript.js
console.log('contentScript.js - Injected');
In console i expected "contentScript.js - Injected" but this only appens when i am not in the main Thunderbird tab.
When i am in the main tab it shows only "Try to execute contentScript" then nothing appens, no errors.
Thunderbird extension are evolving right now from the old legacy method (overlay of xul files) to the actual WebExtension Api used by most of the browsers, but there are some differences: in Firefox the extension works without any problem, so i supposed that the main tab of Thunderbird is somehow protected from content injection.
My objective here is to get the attachments list and other elements directly from the interface, but apparently i can't.

Related

Does Electron support drag-and-dropping a file path into another application?

In C# WinForms, I could do this
var data = new DataObject(DataFormats.FileDrop, filePaths);
myControl.DoDragDrop(data, DragDropEffects.Copy);
to make another application, such as Notepad, open the file specified by filePaths. The code is similar in WPF or even in JavaFX. The file path can be any arbitrary file path that is accessible within the system, such as C:\Windows\win.ini or \\myFileServer\sharedDir\sharedFile.txt. I mean making Notepad OPEN the file, NOT displaying the file path text in its editing area. That is, I am d&d'ing a file path, not a string that contains the file path.
Can I do the same thing if I make a desktop application with Electron (only for desktops; don't care about web/mobile)? I have tested it with VS Code, which is said to be created with Electron, and when I dragged a file from its "Explorer" into Notepad, nothing happened. When I did it into Notepad++, it just displayed the file path string in its editing area, so I am guessing Electron doesn't support it, but I want to make it sure.
Yes, there even is a full example in the Electron documentation about this.
Short summary of the example code: when a specific DOM element is being dragged, the renderer sends an event to the main process. For the dragstart event to fire, the DOM element needs to have the attribute draggable="true". In this example, we pass the filename of the file to be dragged along in the message to the main process.
document.getElementById("foo").ondragstart = event => {
event.preventDefault();
ipcRenderer.send("my-drag-start", "test-file.txt");
}
The main process handles the IPC message from the renderer and starts the drag operation. Note that you need to specify an icon to be attached to the cursor during the drag operation, triggering an error message if left out.
ipcMain.on("my-drag-start", (event, filePath) => {
event.sender.startDrag({
file: path.join(__dirname, filePath),
icon: path.join(__dirname, "dnd.png"),
});
});

Detect empty, new tab openings in Google Chrome

I just published a Google Chrome extension which loads background images into new, empty tabs. The plugin is found here in the Chrome Web Store.
For detecting new and empty tabs, I need to ask for "tab" permissions in the extension's manifest.json. This, however, gives the extension the permission to read the browser's history. Not all users will want this and we don't actually need it. Is there a way to detect empty tabs without this permission requirement? Currently our check looks like this:
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab){
if (changeInfo.status == "loading" && tab.url == 'chrome://newtab/')
{ /* load background into tab */ }
});
If you want to customize the new tab page you should add this to your manifest:
"chrome_url_overrides": {
"newtab": "newtab.html"
}
Then place the script you are currently injecting into new tab pages as a <script> tag in the newtab.html file. That won't cause that permission message.

Firefox add-on works with "jpm run", but not whith .xpi file generated with "jpm xpi"

I'm using the Firefox Add-on SDK to develop a Firefox add-on.
I have followed the Getting Started tutorial.
Firefox version : 41.0.2
My Process is :
jpm run --> OK the add-on works fine
jpm xpi --> OK : Create #myAddon.xpi (JPM [info] Successfully created .xpi at ...)
Use of #myAddon.xpi --> NOK
When I tried to install the add-on in my Firefox ( Add-on -> install from file -> #myAddon.xpi ), I have a message "Install successfully". Looks good. BUT, the add-on doesn't work. Nothing happens.
So, why is the test with jpm run OK, but does not work after installing the .xpi file???
I can share the code with you, but how can this situation happen? If it works in test, I expect that it works in "release".
I get no error or warning.
High Level :
Index.js:
pageMod.PageMod({
include: "*",
contentScriptFile: [data.url("jquery-1.11.3.min.js"), data.url("./Compute.js")],
onAttach: function (worker) {
var currentUrl = tabs.activeTab.url;
param = currentUrl;
Request({
url: param,
onComplete: function (response) {
var parsed = JSON.parse(response.text);
worker.port.emit('got-request', parsed);
}
}).get();
}
data/Compute.js
self.port.on('got-request', function (data) {
console.log(data);
});
Edit (moved from comments):
I find something interesting.... Depending on the level of privacy in FireFox the addon will work or not. ( Options->Privacy->History "Remember history " or "Never remember history") - Remember history " --> addOn OK - "Never remember history" --> addOn NOK Any idea why
As you have determined, if you desire your Firefox Add-on SDK add-on to work in Private Browsing mode you need to have add the key private-browsing with a value of true in your package.json file.
If you are using no other permissions, you could add a line to your package.json file that looks like:
"permissions": {"private-browsing": true}
The Firefox documentation on writing SDK add-ons for private browsing mode specifically states that the require("sdk/private-browsing").isPrivate() method will return true when any of the following is the case (emphasis mine):
a private window, or
a tab belonging to a private window, or
a worker that's associated with a document hosted in a private window
any window, tab, or worker if the browser has been configured to never remember history (Options->Privacy->History)
If you do not have "private-browsing": true, then, as the documentation states, the following will be the case (emphasis mine):
the windows module will not list any private browser windows, generate any events for private browser windows, or let the add-on open any private browser windows
the tabs module will not list any tabs that belong to private browser windows, and the add-on won't receive any events for such tabs
any ui components will not be displayed in private browser windows
any menus or menu items created using the context-menu will not be shown in context menus that belong to private browser windows
the page-mod module will not attach content scripts to documents belonging to private browser windows
any panel objects will not be shown if the active window is a private browser window
the selection module will not include any selections made in private browser windows
The net effect will be that your add-on will appear to not work when the profile you are using is configured to never remember history without having the "private-browsing": true permission in your package.json.
If you do put that permission in your package.json file, you must use the private-browsing module, require("sdk/private-browsing").isPrivate(object), to check for being in a private window or tab. If you are in such a window or tab you need to not store any information about such environment.

How to create Firefox Extension to send active tab URL to its Native, similar to chrome native messaging and install it through msi

I have already developed a C# win form application and a chrome extension with native messaging (another C# console app) to fetch user's active tab url. I have also developed an msi setup in WiX to write under the registry (HKLM/SOFTWARE/Wow6432Node/Google/Chrome/Extensions and HKLM\SOFTWARE\Wow6432Node\Google\Chrome\NativeMessagingHosts) programmatically and tested the installation of the chrome extension by running the setup on different Windows 7 machines. I am publishing this extension on chrome web store and then I shall install the extension on several client computers.
I want to accomplish the same with Mozilla Firefox. I am newbie in this field and going through some Firefox developers guides (XPCOM, js-ctypes etc.) and getting little confused with multiple links.
It would be of great help if anyone can guide me towards the exact solution. Please note that, 1) I have to install the extension programmatically through the same msi package which already contains my own C# app and the chrome extension with native app and 2) the client machines will be Windows only but any version (XP (optional), 7, 8, Server anything).
EDIT:
According to Noitidart's answer, I have made an ffext.xpi from the 4 files (bootstrap.js, myWorker.js, chrome.manifest, install.rdf) and uploaded and installed on firefox, with no error, but nothing happens. At first, I am concentrating on the browser extension part and not the native for now and I just want to have a listener inside the js files such that whenever I switch to a different firefox tab or firefox window, an alert should show up from the browser itself (not from native at this moment) displaying the active tab's URL. I don't even understand how the js files will get called or executed, how this line myWorker.addEventListener('message', handleMessageFromWorker); will work or if I need to add some other listener.
Nothing is happening at all. How to debug or proceed from here? Please help.
To get the current url of the window do this:
aDOMWindow.gBrowser.currentURI.spec
To access all windows do this:
Cu.import('resource://gre/modules/Services.jsm');
let DOMWindows = Services.wm.getEnumerator(null);
while (DOMWindows.hasMoreElements()) {
let aDOMWindow = DOMWindows.getNext();
if (aDOMWindow.gBrowser) {
var currentURL = aDOMWindow.gBrowser.currentURI;
}
}
If you don't check for gBrowser the aDOMWindow.location will be a chrome path, very likely.
So putting this togather with a ChromeWorker (the ChromeWorker will access the js-ctypes) template here: https://github.com/Noitidart/ChromeWorker (this template is the bare minimum needed for communication between ChromeWorker and your js file, in this case bootstrap.js) (bootstrap.js is the js file that is required and is run, the 4 startup,shutdown,install,uninstall functions are required in bootstrap.js)
From bootstrap.js we would do, for now lets do it in startup:
function startup() {
loadAndSetupWorker(); //must do after startup
myWorker.postMessage({
aTopic: 'currentURL',
aURL: Services.wm.getMostRecentWindow('navigator:browser').gBrowser.currentURI.spec // recent window of type navigator:browser always has gBrowser
aLinkedPanel: Services.wm.getMostRecentWindow('navigator:browser').gBrowser.selectedTab.getAttribute('linkedpanel') //we use this to make sure to get the right tab/window on message back
});
}
Then in worker we'll do something like this:
self.onmessage = function(msg) {
switch (msg.data.aTopic) {
case 'currentURL':
var ret = msgBox(0, "alert from ctypes on windows, the url is:" + msg.data.aURL, "ctypes alert windows", MB_OK);
self.postMessage({
aTopic: 'currentURL-reply',
theLinkedPanel: msg.data.aLinkedPanel,
aResponde: aRet
});
break;
default:
throw 'no aTopic on incoming message to ChromeWorker';
}
}
Then back in bootstrap.js we'll receive this message and do something with it:
function handleMessageFromWorker(msg) {
console.log('incoming message from worker, msg:', msg);
switch (msg.data.aTopic) {
case 'currentURL-reply':
let DOMWindows = Services.wm.getEnumerator('navigator:browser');
while (DOMWindows.hasMoreElements()) {
let aDOMWindow = DOMWindows.getNext();
if (aDOMWindow.gBrowser && aDOMWindow.gBrowser.selectedTab.getAttribute('linkedpanel') == msg.data.theLinkedPanel) {
//this is our window, as the currently selected tab linkedpanel is same as one the worker dealt with
var currentURL = aDOMWindow.gBrowser.currentURI;
aDOMWindow.gBrowser.selectedTab.contentWindow.alert('the user was prompted with js-ctypes and the user clicked on:' + aRet);
break;
}
}
break;
default:
console.error('no handle for msg from worker of aTopic:', msg.data.aTopic);
}
}
so what this example does, is on install/startup of addon it gets the most recent browser windows url. it sends it to ctypes, ctypes throws a os level alert, and then ctypes sends back what the user clicked, then bootstrap.js finds that same window and that tab and with a javascript alert it tells what the jsctypes os level msgbox return value was.

"document" in mozilla extension js modules?

I am building Firefox extension, that creates single XMPP chat connection, that can be accessed from all tabs and windows, so I figured, that only way to to this, is to create connection in javascript module and include it on every browser window. Correct me if I am wrong...
EDIT: I am building traditional extension with xul overlays, not using sdk, and talking about those modules: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules
So I copied Strophe.js into js module. Strophe.js uses code like this:
/*_Private_ function that creates a dummy XML DOM document to serve as
* an element and text node generator.
*/
[---]
if (document.implementation.createDocument === undefined) {
doc = this._getIEXmlDom();
doc.appendChild(doc.createElement('strophe'));
} else {
doc = document.implementation
.createDocument('jabber:client', 'strophe', null);
}
and later uses doc.createElement() to create xml(or html?) nodes.
All worked fine, but in module I got error "Error: ReferenceError: document is not defined".
How to get around this?
(Larger piece of exact code: http://pastebin.com/R64gYiKC )
Use the hiddenDOMwindow
Cu.import("resource://gre/modules/Services.jsm");
var doc = Services.appShell.hiddenDOMWindow.document;
It sounds like you might not be correctly attaching your content script to the worker page. Make sure that you're using something like tabs.attach() to attach one or more content scripts to the worker page (see documentation here).
Otherwise you may need to wait for the DOM to load, waiting for the entire page to load
window.onload = function ()
{
Javascript code goes here
}
Should take at least diagnose that issue (even if the above isn't the best method to use in production). But if I had to wager, I'd say that you're not attaching the content script.

Resources