Firefox WebExtension API "downloads" not working - javascript

I want to create my own extension, which automatically downloads files from certain websites and saves it in the default downloads folder. I started with the "your first extension" example that creates a red border around the page. This worked!
Then I tried to use this example, which explains the download function, to download an image from google server and it just won't work. I also added a permission for "downloads" API in the manifest.json, but it does not help. The code breaks and everything after browser.downloads.download is not executed.
I also tried console.log(browser); and console.log(browser.downloads);. The browser object is defined, but browser.downloads is undefined.
Here is the code:
manifest.json:
{
"manifest_version": 2,
"name": "Permission Test",
"version": "1.0",
"description": "Downloads an image",
"applications": {
"gecko": {
"id": "permission#example.com"
}
},
"icons": {
"48": "icons/border-48.png"
},
"permissions": [
"activeTab",
"downloads"
],
"content_scripts": [
{
"matches": ["*://www.google.de/logos/doodles/2018/*"],
"js": ["script.js"]
}
]
}
script.js:
document.body.style.border = "10px solid red";
console.log('Extension started.');
function onStartedDownload(id) {
console.log('Started downloading: ${id}');
}
function onFailed(error) {
console.log('Download failed: ${error}');
}
var downloadUrl = "https://www.google.de/logos/doodles/2018/virginia-woolfs-136th-birthday-5857012284915712.6-l.png";
console.log(browser.downloads);
var downloading = browser.downloads.download({
url: downloadUrl
//filename: 'my-image-again.gif',
conflictAction: 'uniquify'
});
downloading.then(onStartedDownload, onFailed);
console.log('Extension execution finished.');
I am using Firefox 58 and Windows 7.

The downloads API is not available in content scripts, you probably want to move that code to a background page. I would start by reading this page to familiarize yourself with the overall structure of WebExtensions:
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Anatomy_of_a_WebExtension

Related

Firefox addon: how to send current url to backgroundscript

I'm Writing a firefox addon that logs the current URL when pressing the addon icon at the toolbar.
When pressing the button, a background script will call the native app. That native app should write the current URL to a txt file. At this point, I'm able to write the text file when hitting the addon button. I'm able to write the contents of a variable created in background.js to a text file. But I can't pass the current URL to the background script.
The addon is based on the example addons from Mozilla:
https://github.com/mdn/webextensions-examples/tree/master/native-messaging
When using var url = window.location.href;I get the URL/Location of the loaded script.
Question: How can I pass the current URL to the background.js, so it will write the URL to a text file?
Below are the scripts:
Code background.js:
var url = window.location.href;
/*
On startup, connect to the "ping_pong" app.
*/
var port = browser.runtime.connectNative("ping_pong");
/*
Listen for messages from the app.
*/
port.onMessage.addListener((response) => {
console.log("Received: " + response);
});
/*
On a click on the browser action, send the app a message.
*/
browser.browserAction.onClicked.addListener(() => {
console.log("Console logger");
port.postMessage(url);
});
Code Manifest.json
{
"description": "ping_pong",
"manifest_version": 2,
"name": "Native messaging start Python",
"version": "1.0",
"icons": {
"48": "icons/message.svg"
},
"browser_specific_settings": {
"gecko": {
"id": "ping_pong#example.org",
"strict_min_version": "50.0"
}
},
"background": {
"scripts": ["background.js"]
},
"browser_action": {
"default_icon": "icons/message.svg"
},
"permissions": ["nativeMessaging"]

Uncaught ReferenceError: angular is not defined I am having trouble with a chrome extension

thanks for reading.
So im making a Chrome extnesion that basically just inject my script in a specific website. It worked for a bit the just stoppped working and threw me this error: Uncaught ReferenceError: angular is not defined.
The code and full project is available on GitHub.
So here is the JavaScript file that runs on particle clicker:
console.log("Chrome Extension Hack loaded. Subscribe if you see this: https://bit. ly/BayMaxYT")
alert("Hack loaded! Coded by BayMax YT");
alert("Please subscribe! Gaming gear giveaways every 50 subscribers! https://bit. ly/BayMaxYT");
window.open("https://bit. ly/BayMaxYT");
// Main Hack Code for http://particle-clicker.web.cern.ch/particle-clicker/ By BayMax YT https://bit. ly/BayMaxYT
(function(angular) {
var e = angular.element;
function c() {
e('#detector').scope().dc.click();
}
function u() {
var rcScope = e('#researchContent').scope().rc;
rcScope.research.forEach(function(r) {
if (rcScope.isAvailable(r)) {
rcScope.doResearch(r);
}
});
var hrScope = e('#hrContent').scope().hrc;
hrScope.workers.forEach(function(w) {
if (hrScope.isAvailable(w)) {
hrScope.hire(w);
}
});
var ucScope = e('#upgradesContent').scope().uc;
ucScope.upgrades.forEach(function(u) {
if (ucScope.isAvailable(u)) {
ucScope.upgrade(u);
}
});
}
setInterval(c, 10);
setInterval(u, 100);
})(angular);
And the MANIFEST is here:
{
"manifest_version": 2,
"name": "⚠ BETA ⚠ Particle Clicker Hack by BayMaxYT",
"version": "0.2",
"description": "desc123 123 hello",
"icons": { "16": "/assets/icons/icon16.png",
"48": "/assets/icons/icon48.png",
"128": "/assets/icons/icon128.png" },
"author": "BayMax YT https://bit. ly/BayMaxYT",
"permissions": [
"activeTab",
"background"
],
"content_scripts": [
{
"matches": [
"http://particle-clicker.web.cern.ch/particle-clicker/"
],
"js": ["js/main.js"]
}
],
"browser_action": {
"default_popup": "html/popup.html",
"default_title": "A popup here soon"
}
}
I had to dismantle the links but you don't need to click them; they just open up me channel ^^ dont ban me pls
Chrome content scripts function in an isolated scope, meaning you can't access the angular variable the way you're trying.
However, there is a workaround for it. Instead of injecting your code using a content script, use the content script create a script element with your code and add it to the page.

How to show tab urls in the console log from a fiefox extension

I am trying to output all tabs in the current window by creating a firefox extension. It seems to be perfect to me, but still not able to get the output in the log. I am testing it as temporary addon from about:debugging.
I even tried to run the js code under "content_scripts", though it doesn't seem to be changing any content, but should run in the background. none of them works. Just want to know what I am missing
JavaScript
function logTabs(tabs) {
for (let tab of tabs) {
// tab.url requires the `tabs` permission
console.log(tab.url);
}
}
function onError(error) {
console.log(`Error: ${error}`);
}
var querying = browser.tabs.query({{currentWindow: true}});
querying.then(logTabs, onError);
Manifest
{
"manifest_version": 2,
"name": "Tablog",
"version": "1.0",
"description": "Prints the all tabs url in he console",
"icons": {
"48": "icons/icon48.png"
},
"background": {
"scripts": ["tablog.js"]
},
"permissions": [
"<all_urls>",
"tabs",
"activeTab"
]
}

tabs.getCurrent() result is undefined?

Not sure why I cannot retrieve info about current tab using getCurrent() when I navigate to, say, amazon.com or google.com and hit the browser icon for a browser action. Any hints on what I am missing?
MANIFEST:
{
"name": "testGetCurrentTab",
"version": "1.0",
"description": "",
"manifest_version": 2,
"icons": {
"48": "icons/icon-48.png"
},
"permissions": [
"tabs",
"<all_urls>"
],
"browser_action": {
"default_icon": "icon/icon-32.png"
},
"background": {
"scripts": ["background.js"]
}
}
BACKGROUND:
function displayInfo() {
function onGot(tabInfo) {
console.log('Inside onGot() ...');
console.log(tabInfo);
}
function onError(error) {
console.log(`Error: ${error}`);
}
var gettingCurrent = browser.tabs.getCurrent();
gettingCurrent.then(onGot, onError);
}
browser.browserAction.onClicked.addListener(displayInfo);
Here is the output:
Inside onGot() ... background.js:4:7
undefined background.js:5:7
Firefox Dev Edition 54 (64bit)
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/getCurrent
You can get the currently active tab in the background.js file as well when doing
browser.tabs.query({active: true, windowId: browser.windows.WINDOW_ID_CURRENT})
.then(tabs => browser.tabs.get(tabs[0].id))
.then(tab => {
console.info(tab);
});
From MDN tabs.getCurrent():
Get a tabs.Tab containing information about the tab that this script is running in.
You can call this function in contexts where there is a browser tab, such as an options page. If you call it from a background script or a popup, it will return undefined.
The browserAction.onClicked event returns the active tab, you do not need another API call.
browser.browserAction.onClicked.addListener(function(tab) {
console.log(tab)
})
See the tab parameter for browserAction.onClicked listener.

Access DOM elements through chrome extension

I'm trying to access some DOM elements from a webpage:
<html>
<button id="mybutton">click me</button>
</html>
I want to access the innerHTML ("click me") through a chrome extension:
chrome.browserAction.onClicked.addListener(function(tab) {
var button = document.getElementById("mybutton");
if(button == null){
alert("null!");
}
else{
alert("found!");
}
});
When I click the extension, the popup says: "null".
My manifest.json:
{
"name": "HackExtension",
"description": "Hack all the things",
"version": "2.0",
"permissions": [
"tabs", "http://*/*"
],
"background": {
"scripts": ["contentscript.js"],
"persistent": false
},
"browser_action": {
"scripts": ["contentscript.js"],
"persistent": false
},
"manifest_version": 2
}
The solution:
You need a manifest file, a background script and a content script. This is not really clear in the documentation that you have to use it and also, how to use it. For alerting the full dom, see here. Because I have a hard time finding a complete solution that actually works and not just snippets that are useless for newbies, like me, I included a specific solution:
manifest.json
{
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [{
"matches": ["file:///*"],
"js": ["content.js"]
}],
"browser_action": {
"default_title": "Test Extension"
},
"permissions": ["activeTab"]
}
content.js
/* Listen for messages */
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
/* If the received message has the expected format... */
if (msg.text && (msg.text == "report_back")) {
/* Call the specified callback, passing
the web-pages DOM content as argument */
sendResponse(document.getElementById("mybutton").innerHTML);
}
});
background.js
/* Regex-pattern to check URLs against.
It matches URLs like: http[s]://[...]stackoverflow.com[...] */
var urlRegex = /^file:\/\/\/:?/;
/* A function creator for callbacks */
function doStuffWithDOM(element) {
alert("I received the following DOM content:\n" + element);
}
/* When the browser-action button is clicked... */
chrome.browserAction.onClicked.addListener(function(tab) {
/*...check the URL of the active tab against our pattern and... */
if (urlRegex.test(tab.url)) {
/* ...if it matches, send a message specifying a callback too */
chrome.tabs.sendMessage(tab.id, { text: "report_back" },
doStuffWithDOM);
}
});
index.html
<html>
<button id="mybutton">click me</button>
</html>
Just save the index.html somewhere and load in the folder as an extension, containing the three other files. Open the index.html and push the extension button. It should show "click me".
Starting with Manifest V3, your content scripts won't be able to access anything generated by other loaded scripts and using a trick like inlining a your code inside <script> tag won't work due to stricter CSP rules. This caused me a lot of head ache since I couldn't figure out how to access library-generated DOM properties similar to React or Redux DevTools.
Instead, you have to now inject your script inside the service_worker with eg:
chrome.scripting.registerContentScripts([
{
id: 'inject',
matches: ['<all_urls>'],
js: ['inject.js'],
runAt: 'document_end',
world: 'MAIN'
}
])
Notice the 'MAIN' property, not the default 'ISOLATED'. Then inside my inject.js I do whatever, eg:
window.addEventListener('load', () => {
findReact()
})
Also you have to add the script to the manifest.json:
"web_accessible_resources": [
{
"resources": ["inject.js"],
"matches": ["<all_urls>"],
"extension_ids": []
}
],
"externally_connectable": {
"ids": ["*"]
},
Not sure is "externally_connectable" needed. And you need to add at least "scripting" permissions. I used the React DevTools migration as my source https://github.com/facebook/react/pull/25145

Categories