Intercept XMLHttpRequest from Greasemonkey script fails - xmlhttprequest

I seek to manipulate the XMLHttpRequest done by a website using Greasemonkey (version 4.9 installed). Interception should be simple (How can I intercept XMLHttpRequests from a Greasemonkey script?) but does not work for me. Maybe things changed with newer versions of Greasemonkey?
I obviously tried the examples in the linked question, but they don't have any effect - nothing printed in the console although I have an console.log(...) in my customised open function.
Next, I gave unsafeWindow a try. It should not be needed. My userscript runs with #grant none and documentation (see here) says my script should run in the content scope.
With unsafeWindow I get an effect but it breaks XMLHttpRequest completely
// ==UserScript==
// #name Test
// #version 1
// #include *
// #run-at document-start
// #grant none
// ==/UserScript==
"use strict";
let realOpen = unsafeWindow.XMLHttpRequest.prototype.open
console.log("Real: " + realOpen)
unsafeWindow.XMLHttpRequest.prototype.open = function() {
console.log("Called for " + this + " with URL: " + arguments[0])
//call original
return realOpen.apply(this, arguments)
};
window.addEventListener ("load", function() {
console.log ("Page loaded");
});
console.log("Unsafe: ", unsafeWindow.XMLHttpRequest.prototype.open.toString())
console.log("Normal: ", XMLHttpRequest.prototype.open.toString())
This gives following output in console:
Real: function open() {
[native code]
}
Unsafe: function() {
console.log("Called for " + this + " with URL: " + arguments[0])
//call original
return realOpen.apply(this, arguments)
}
Normal: function open(method, url) {
// only include method and url parameters so the function length is set properly
if (arguments.length >= 2) {
let newUrl = new URL(arguments[1], document.location.href);
arguments[1] = newUrl.toString();
}
return origOpen.apply(this, arguments);
}
==> Page loaded
As mentioned, function of XMLHttpRequest is broken. When I use the Firefox developer console to have a further look I get this
>> window.XMLHttpRequest.prototype.open
Restricted { }
Any properties set on window (like window.foobar = "foobar") do not exist in console, but those set on unsafeWindow do. I assume this has to do with Greasemonkey's sandboxing.
Why are there two versions of XMLHttpRequest even when I use #grant none? Why is my custom function restricted? Can I avoid that? Why does it work without problems when I install event listener on window?

Next, I gave unsafeWindow a try. It should not be needed. My userscript runs with #grant none and documentation (see here) says my script should run in the content scope.
This is wrong for Greasemonkey 4 as stated in its announcement:
Due to the more limited abilities that the new extension system gives us, we are currently unable to make #grant none scripts work in the same way. Most importantly, they have a different connection to unsafeWindow. For the short term at least, it's a good idea to adopt cloneInto and exportFunction.
See also this other question Firefox doesn't respect Object.defineProperty() from a Greasemonkey script?
This change explain the observations, but no idea why adding listener to window work.

Related

Possible to manipulate CasperJS assertions?

My CasperJS asserts seem to be overly strict. I have a function where I am trying to test the names of client logo images from an array, using Casperjs. However I do not seem to be able to use a variable from a forLoop in casperJS.
I understand there are probably hoisting issues that I am not accounting for, but this does not seem to be the primary problem. I have tried several things to resolve hoisting issues, such as immediately invoked functions, try catch blocks, and using ES6 term "Let" in my loop. None seem to work. Then I notice if I simply hard-code the string my variable should represent, and stick a console.log into my assert of a PASSING test, right before the return, the passing test fails.
Here is my failing code
var clients = 'https://www.google.com/';
var logoArray = ["images/logos/AC.png", "images/logos/Affiny.png", "images/logos/ffintus.png", "images/logos/agileAsset.png"]
function checkClientsArrayTest() {
casper.test.begin('The layout is as expected', 10, function suite(test) {
casper.start(clients, function () {
casper.then(function () {
for (var i = 0; i < logoArray.length; i++) {
try { throw i }
catch (ii) {
console.log(ii);
console.log(i);
test.assertEvalEquals(function () {
return document.querySelectorAll('div.client_logo a img')[ii].getAttribute('src')
.match(logoArray[ii]).toString();
}, logoArray[ii], 'Test searches for Client Logos in DOM.');
}
}
});
}).run(function () {
test.done();
});
});
}
If I change logoArray[ii] to a hardcoded string from the first index of the array, it passes. If I consolelog logoArray[ii], it seems to be what I expect. But if I pass a variable to the assert, or even stick a console.log inside of it, the test fails with the following
Running check for the layout of URL: https://www.google.com
0
0
FAIL Test searches for Client Logos in DOM.
type: assertEvalEquals
file: headlessTester.js
subject: null
fn: undefined
params: undefined
expected: "images/logos/AC.png"
Is this an issue of me getting hoisting wrong (shouldn't fail by sticking in a logger if this is the case afaik), or is this due to strictly structured asserts in CasperJS?

How to write custom messages on passed tests with jasmine and protractor?

I'm looking a way to add custom messages on succeeded tests with protractor and jasmine.
There're many ways to customize messages on failure, like jasmine-custom-message node package or simply:
expect(column.get(0)).toEqual("7", "This is not something I've expected");
But I haven't found a way to add custom messages on success. I'm using protractor-jasmine2-html-reporter to generate my reports, but successful tests only display a "passed" or "0 failure" messages and I'd like to be more explicit about what am I testing and why the tests passed.
You want to write a custom matcher for Jasmine. You want to include them in the protractor.conf.js file so they are accessible over the entire project
https://jasmine.github.io/2.0/custom_matcher.html
Here is an example of comparing numbers with the message printing off if there is an error. The error if you run this will be Expected 7 to be 8 (Expected Error). Note, this is including it in the spec using the beforeEach.
var customMatchers = {
toBeEqualWithMessage: function(util, customEqualityTesters) {
return {
compare: function(actual, expected, message) {
var result = {};
result.pass = util.equals(actual, expected, customEqualityTesters);
if (!result.pass) {
result.message = "Expected " + actual + " to be " + expected + " (" + message + ")";
}
return result;
}
};
}
};
describe('Custom Matcher', function(){
beforeEach(function() { jasmine.addMatchers(customMatchers);});
it('should use a matcher', function(){
expect(7).toBeEqualWithMessage(7,"No error because they match");
expect(7).not.toBeEqualWithMessage(8,"No error because of the 'not'");
expect(7).toBeEqualWithMessage(8,"Expected Error");
});
});
FYI: The doc has a result.message for a passing case, but I don't know where that is used, maybe a verbose print out.

Automatically close PhantomJs after running script

I want to run PhantomJs scripts from my program, but since the scripts may not be written by me, I need to make sure PhantomJs exits after the execution are either completed or fails for any reason (e.g., invalid syntax, timeout, etc). So far, All I've read says you must always include the instruction phantom.exit() for PhantomJs to exit. Is there any way to automatically close PhantomJs after it executes a given script?
Thanks.
Create a file run-javascript.js:
var system = require('system');
try {
for (var i=1; i<system.args.length; i++) {
var scriptFileName = system.args[i];
console.log("Running " + scriptFileName + " ...");
require(scriptFileName);
}
}
catch(error) {
console.log(error);
console.log(error.stack);
}
finally {
phantom.exit();
}
Then to run your file myscript.js:
phantomjs run-javascript.js ./myscript.js
You have to include an explicit path for the myscript.js, i.e. ./myscript.js, otherwise phantomjs will look for the script as a module.
There are three execution scenarios that are handled here:
Successful execution, in which case phantom.exit() is called in the finally clause.
Error in the script being run, in which case the require function prints a stacktrace and returns (without throwing any error to the calling code).
Error running the script (e.g. it doesn't exist), in which case the catch clause prints out the stacktrace and phantom.exit() is called in the finally clause.

How to access a function defined in a previous YUI.use() call

[I'm a YUI newbie]
I'm writing a Chrome extension that needs to change the contents of a web page created using the YUI3 framework.
I've identified that the extension, which injects javascript that runs in the page after it is loaded, must call a function that was previously defined in a YUI.add() call.
The original YUI code that runs is something like this:
YUI.add("uuu", function (c) {
...
c.theObject = niceStuff;
}
...
YUI().use("uuu", function (c) {
c.theObject.doSomething();
}
Is it possible that after this code runs, I can access a function of c.theObject?
(I understand this might go against YUI3's nice sandbox mechanism, but it's what I need to get the job done here).
You might have problems because any time a YUI() instance is created, it builds you a new sandbox. With a few exceptions, YUI modules are completely boxed by their sandbox context. For example:
YUI().use('node', function(Y1) {
YUI().use('node', function(Y2) {
assert(Y1.Node === Y2.Node) // fails!
});
});
It's very possible that you may not be able to access the specific instance of theObject that you need, if it's never assigned to a variable outside the sandbox function scope. If any instance of theObject will do, you can just call into the YUI API and get your own version to play with.
This works for me: http://jsfiddle.net/sMAQx/1/
One way to do it is to capture the YUI() instance after you 'use' it. Like this:
YUI().add("uuu", function (c) {
c.theObject = 'foo';
})
var yInstance = YUI().use("uuu", function (c) {
c.theObject = 'booyaa';
})
yInstance.use('uuu',function(c){
console.log(c.theObject)
})
// booyaa

How to register component interface in wxwebconnect?

I'm doing an experiment with wxWebConnect test application, incorporating the xpcom tutorial at "http://nerdlife.net/building-a-c-xpcom-component-in-windows/"
I adapt MyComponent class as necessary to compile together with testapp.exe (not as separate dll), and on MyApp::OnInit I have the following lines:
ns_smartptr<nsIComponentRegistrar> comp_reg;
res = NS_GetComponentRegistrar(&comp_reg.p);
if (NS_FAILED(res))
return false;
ns_smartptr<nsIFactory> prompt_factory;
CreateMyComponentFactory(&prompt_factory.p);
nsCID prompt_cid = MYCOMPONENT_CID;
res = comp_reg->RegisterFactory(prompt_cid,
"MyComponent",
"#mozilla.org/mycomp;1",
prompt_factory);
Those lines are copied from GeckoEngine::Init(), using the same mechanism to register PromptService, etc. The code compiles well and testapp.exe is running as expected.
I put javascript test as below :
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
const cid = "#mozilla.org/mycomp;1";
obj = Components.classes[cid].createInstance();
alert(typeof obj);
// bind the instance we just created to our interface
alert(Components.interfaces.nsIMyComponent);
obj = obj.QueryInterface(Components.interfaces.nsIMyComponent);
} catch (err) {
alert(err);
return;
}
and get the following exception:
Could not convert JavaScript argument arg 0 [nsISupport.QueryInterface]
The first alert says "object", so the line
Components.classes[cid].createInstance()
is returning the created instance.
The second alert says "undefined", so the interface nsIMyComponent is not recognized by XULRunner.
How to dynamically registering nsIMyComponent interface in wxWebConnect environment ?
Thx
I'm not sure what is happening here. The first thing I would check is that your component is scriptable (I assume it is, since the demo you copy from is). The next thing I would check is whether you can instantiate other, standard XULRunner components and get their interface (try something like "alert('Components.interfaces.nsIFile');" - at least in my version of wxWebConnect this shows an alert box with string "nsIFile".
Also, I think it would be worth checking the Error Console to make sure there are no errors or warnings reported. A magic string to do that (in Javascript) is:
window.open('chrome://global/content/console.xul', '', 'chrome,dialog=no,toolbar,resizable');