I'm writing a Chrome extension where I would like to access the Chrome Storage API from the Devtools page. The chrome.storage.local variable (with the get/set functions) are available, but when I call them the callback never get's called. When I use my background page to access the storage API it works as expected.
I could, of course, send the request via the background page and pass it to the Devtools page through messages but I'm looking for a more cleaner approach. Am I doing something wrong?
I hope that you understand my question, to illustrate my problem I have created a little sample of what I'm coping with, ready for download here; http://g2f.nl/0w2kko9.
It includes the following test which verifies that the API is available but does not work as expected;
document.getElementById("p").innerHTML += "chrome.storage.local.set = " + !!chrome.storage.local.set
+ "<br>chrome.storage.local.get = " + !!chrome.storage.local.get;
chrome.storage.local.set( {'foo' : 'bar'} , function () {
document.getElementById("p").innerHTML += '<br>foo = bar';
});
setTimeout(function () {
document.getElementById("p").innerHTML += '<br>That was one second';
chrome.storage.local.get('foo', function (result) {
document.getElementById("p").innerHTML += '<br>foo = ' + result;
});
}, 1000);
Related
when reading BOOKS on scribd.com the download functionality is not enabled. even browsing through the html source code I was unable to download the actual book. Great stuff ... but HOW did they do this ?
I am looking to implement something similar, to display a pdf (or converted from pdf) in such a way that the visitor cannot download the file
Most solutions I have seen are based on obfusticating the url.. but with a little effort people can find the url and download the file. ScribD seems to have covered this quite well..
Any suggestions , ideas how to implement such a download protection ?
It actually works dinamically building the HTML based on AJAX requests made while you're flipping pages. It is not image based. That's why you're finding it difficult to download the content.
However, it is not that safe for now. I present a solution below to download books that is working today (27th Jan 2020) not for teaching you how to do that (it is not legal), but to show you how you should prevent (or, at least, making it harder) users from downloading content if you're building something similar.
If you have a paid account and open the book page (the one that opens when you click 'Start Reading'), you can download an image of each book page by loading a library such as dom-to-image.
For instance, you could load the library using the developer tools (all code shown below must be typed in the page console):
if (injectDomToImage == undefined) {
var injectDomToImage = document.createElement('script');
injectDomToImage.src = "https://cdnjs.cloudflare.com/ajax/libs/dom-to-image/2.6.0/dom-to-image.min.js";
document.getElementsByTagName('head')[0].appendChild(injectDomToImage);
}
And then, you could define functions such as these:
function downloadPage(page, prefix) {
domtoimage.toJpeg(document.getElementsByClassName('reader_and_banner_container')[0], {
quality: 1,
})
.then(function(dataUrl) {
var link = document.createElement('a');
link.download = `${prefix}_page_${page}.jpg`;
link.href = dataUrl;
link.click();
nextPage(page, prefix);
});
}
function checkPageChanged(page, oldPageCounter, prefix) {
let newPageCounter = $('.page_counter').html();
if (oldPageCounter === newPageCounter) {
setTimeout(function() {
checkPageChanged(page, oldPageCounter, prefix);
}, 500);
} else {
setTimeout(function() {
downloadPage(page + 1, prefix);
}, 500);
}
}
function nextPage(page, prefix) {
let oldPageCounter = $('.page_counter').html();
$('.next_btn').trigger('click');
// Wait until page counter has changed (page loading has finished).
checkPageChanged(page + 1, oldPageCounter, prefix);
}
function download(prefix) {
downloadPage(1, prefix);
}
Finally, you could download each book page as a JPG image using:
download('test_');
It will download each page as test_page_.jpg
In order to prevent such type of 'robot', they could, for example, have used Re-CAPTCHA v3 that works in background seeking for 'robot'-like behaviour.
I have a script to test that - on click - generates an iFrame which downloads a file. How can I intercept the response with CasperJS?
I already tried the sequence:
casper.click('element');
casper.withFrame('frame', function(){
console.log(this.getCurrentUrl()); // only return about:blank, but should have URL
console.log("content: " + this.getHTML()); // Yep, empty HMTL
this.on('resource.received', function(resource){
console.log(resource.url); // never executed
});
});
I need the content of the file but can not really produce the URL without clicking the element or changing the script I'm testing.
Ideas?
I tried other events, but none got fired when downloading via the iframe. I found another solution that works - but if you have something better, I'd like to try it.
Here it comes:
// Check downloaded File
.then(function(){
// Fetch URL via internals
var url = this.evaluate(function(){
return $('__saveReportFrame').src; // JavaScript function in the page
});
var file = fs.absolute('plaintext.txt');
this.download(url, file);
var fileString = fs.read(file);
// Whatever test you want to make
test.assert(fileString.match(/STRING/g) !== null, 'Downloaded File is good');
})
I am working on a chrome extension, and really want to have my chrome option page access the data in the IndexedDB, but there seems no support for this?
Error as:
Uncaught TypeError: Cannot read property 'transaction' of undefined option.js:42
var request = indexedDB.open(DB_NAME, DB_VERSION);
//console.log(request); /* The created indexedDB can be checked */
request.onsuccess = function (evt) {
console.log("Database Open Successfully: " + evt);
db = this.result;
/* Get the initialised logIndex*/
var storeLog = db.transaction(DB_STORE1, 'readonly').objectStore(DB_STORE1);
var req = storeLog.openCursor(null, 'prev');
req.onsuccess = function (evt) {
console.log("Inner Successfully");
}
req.onerror = function(evt){
console.error("Inner error" + evt.target.errorCode);
}
};
request.onerror = function (evt) {
console.error("Database Error: " + evt.target.errorCode);
};
want to know whether it is possible to access the IndexedDB in the "chrome option_page"
A short answer to your stated question is "yes, IndexedDB is fully supported in extension pages". The fact that your request.onsuccess is fired is sufficient evidence to that.
It seems like your problems are not specific to Chrome Extensions; I suggest that you look at some IndexedDB tutorials like this one to debug your code.
Note that you might need to request "unlimitedStorage" permission in the manifest to store large amounts of data.
I have an XAgent I have created that works just fine via window.location but I can't get it to work via AJAX. This agent is called from a delete button on a popup div, so rather than writing to my responseStream in my XAgent, I'd prefer to just run my agent and close my popup via javascript when it is finished.
My XAgent is called by the URL doc.$DBPath.value + "/xAgent_DeleteDemand.xsp?open&id=" + doc.$DocUNID.value and looks like this:
javascript:importPackage(foo);
try {
var url:java.lang.String = context.getUrl().toString();
print(url);
if (param.containsKey("id")) {
var unid = param.get("id");
} else {
throw "No unid given";
}
XAgent.deleteDemand(unid);
} catch (e) {
print(e);
}
My actual code is in the foo package but that doesn't seem relevant because I'm not even getting my URL printed. I can say the the URL being generated and called works just fine using window.location so it is safe to assume that the problem is elsewhere.
I have a sneaking suspicion that maybe context doesn't have any meaning when called via AJAX from a non XPage app, but I don't know for sure.
I don't think there is anything special about my AJAX code but here it is just in case. It has been working fine for a long time.
function createAJAXRequest(retrievalURL, responseFunction) {
if (window.ActiveXObject) {
AJAXReq = new ActiveXObject("Microsoft.XMLHTTP");
} else if (window.XMLHttpRequest) {
AJAXReq = new XMLHttpRequest();
}
showHideIndicator("block")
var currentTime = new Date()
AJAXReq.open("GET", retrievalURL + "&z=" + currentTime.getTime());
AJAXReq.onreadystatechange = eval(responseFunction);
AJAXReq.send(null);
}
I'm not sure what the immediate problem would be, but as some troubleshooting steps:
The resultant URL is just server-relative and not on a different server+protocol combination, right?
Do you see anything on the browser's debug console when clicking the button?
Is there an entry in the browser's debug Network panel for the request at all?
I'm working on a Firefox addon development with Addon-Builder. I have no idea about how to implement Chrome extension 's chrome.tabs.sendMessage API in Firefox addon. The code is like this (the code is in the background.js, something like main.js in the Firefox addon):
function sendMessageToTabs(message, callbackFunc){
chrome.tabs.query({}, function(tabsArray){
for(var i=0; i<tabsArray.length; i++){
//console.log("Tab id: "+tabsArray[i].id);
chrome.tabs.sendMessage(tabsArray[i].id,message,callbackFunc);
}
});
}
So, How can I achieve this?
In add-ons build using the Add-on SDK, content scripts are managed by main.js. There's no built-in way to access all of your add-on's content scripts. To send a message to all tabs, you need to manually keep track of the content scripts.
One-way messages are easily implemented by the existing APIs. Callbacks are not built-in, though.
My browser-action SDK library contains a module called "messaging", which implements the Chrome messaging API. In the following example, the content script and the main script use an object called "extension". This object exposes the onMessage and sendMessage methods, modelled after the Chrome extension messaging APIs.
The following example adds a content script to every page on Stack Overflow, and upon click, the titles of the tabs are logged to the console (the one opened using Ctrl + Shift + J).
lib/main.js
// https://github.com/Rob--W/browser-action-jplib/blob/master/lib/messaging.js
const { createMessageChannel, messageContentScriptFile } = require('messaging');
const { PageMod } = require('sdk/page-mod');
const { data } = require('sdk/self');
// Adds the message API to every page within the add-on
var ports = [];
var pagemod = PageMod({
include: ['http://stackoverflow.com/*'],
contentScriptWhen: 'start',
contentScriptFile: [messageContentScriptFile, data.url('contentscript.js')],
contentScriptOptions: {
channelName: 'whatever you want',
endAtPage: false
},
onAttach: function(worker) {
var extension = createMessageChannel(pagemod.contentScriptOptions, worker.port);
ports.push(extension);
worker.on('detach', function() {
// Remove port from list of workers when the content script is deactivated.
var index = ports.indexOf(extension);
if (index !== -1) ports.splice(index, 1);
});
}
});
function sendMessageToTabs(message, callbackFunc) {
for (var i=0; i<ports.length; i++) {
ports[i].sendMessage(message, callbackFunc);
}
}
// Since we've included the browser-action module, we can use it in the demo
var badge = require('browserAction').BrowserAction({
default_title: 'Click to send a message to all tabs on Stack Overflow'
});
badge.onClicked.addListener(function() {
sendMessageToTabs('gimme title', function(response) {
// Use console.error to make sure that the log is visible in the console.
console.error(response);
});
});
For the record, the interesting part of main.js is inside the onAttach event.
data/contentscript.js
extension.onMessage.addListener(function(message, sender, sendResponse) {
if (message === 'gimme title') {
sendResponse(document.title);
}
});