How to debug a js script whose name changes - javascript

I'd like to debug a js script whose name changes every time that it's loaded (a timestamp is added at the end of the file, for preventing caching).
For this reason, if I set a breakpoint and then reload the page, the debugger loads the new file and does not stop on the old one.
Is there any tool for any browser (better for IE) to achieve my goal?

For this reason I'm using debugger; function and add to those JS code parts, when I need to stop debugger.
It works good when you have always changing script and not depend on browser type.
function someFn() {
debugger;
...
}

Related

Disable ``console.clear()``

I came across a website that runs this code:
function check(){console.clear();before = new Date().getTime();…
^^^^^^^^^^^^^^^
on load, discarding valuable console messages. How can I make Firefox
ignore console.clear() globally?
I wonder why that even exists in the first place. It should not be
possible for a website to delete potentially relevant debugging output.
You can solve this in two ways,
First, you can write a firefox extension which executes a javascript on page load and assigns empty function to console.clear. So, it doesn't throw any error if its called.
console.clear = () => {}
References for building extension to run on page load
Chrome Extension: Make it run every page load
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Modify_a_web_page
Secondly, you can load the page once and open devtools and goto sources and search for console.clear and add breakpoints every where its called and reload the page. The code execution will stop when the console.clear is called for the first time and again you can goto console and assign console.clear with empty function and override.
Reference for Using BreakPoints in Firefox
https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Set_a_breakpoint
Since you're asking about Firefox, if you don't want to write your own extension, you can use the one that already exists:
Disallow Console Clear Firefox Addon
It is right to hijack the console.clear on page load.
Here just a tip/record.
For some sites, there would be no explicit word console.clear in the sources. (And sadly, currently Firefox's Preserve Log option might still not be as powerful as Chrome's)
But the hijack might still work even!
BTW it might happen that "directly reassigning console.clear in console" not works.
So just try it.

How can I define a property on the tab's main window object?

I'm trying to define the property jQuery on the window object from a content script with code in the setter. That way, when the actual jQuery object is defined, I can use it right away. I seem to be unable to get it right, though.
The target website is Outlook.com. That's the webmail version of Outlook.
I tried to put the code in the content script directly, but even if I put "all_frames": true in the content_scripts section of the manifest (so the code gets injected into every frame), it isn't working.
function afterInit(){
var _jQuery;
console.log('This gets logged');
Object.defineProperty(window, 'jQuery', {
get: function() { return _jQuery; },
set: function(newValue) {
_jQuery = $ = newValue;
console.log('This is never logged!');
$(document.body).append($('<span>I want to use jQuery here</span>'));
}
});
}
afterInit();
I verified that window.jQuery is properly defined afterwards by the actual jQuery function/object, but my setter code is never executed.
I also tried it with message passing: I send a message with the code as a string to a background script, and use executeScript to execute it on the correct tab, but this also doesn't work.
chrome.runtime.sendMessage(
{action:'jQueryPreInit', value: '('+afterInit.toString()+')();'});
And in my background script:
chrome.runtime.onMessage.addListener(function(message, sender, callback) {
switch (message.action){
case "jQueryPreInit": chrome.tabs.executeScript(sender.tab.id, {code: message.value});
}
});
If I put something else than the Object.defineProperty code in the executeScript code, that works fine. I only have problems defining the property.
(quotes are from a comment)
I want to use the jQuery provided by the page itself. I could try inserting the same jQuery file as Outlook does and hope it gets loaded from cache, but I'd rather just keep my extension as clean as possible, and use what is already available.
Your attempt at optimizing the extension is not workable / not recommended.
First off, you will not be able to use the page's code anyway because of the isolation between content script and webpage code. You cannot obtain a reference to page's own jQuery/$.
But let's for a moment suppose that you could. And then the site updates jQuery to another version, renames the jQuery object or stops using it entirely, which is outside your control. Result: your extension is broken. This is, partially, the rationale behind the isolation in the first place.
As a result of the context isolation, you are guaranteed there are no conflicts between your copy of jQuery and whatever runs on the site. So you don't need to worry about that: use your copy, and use the standard $ to access it.
Bundling a <100 KB file with your extension as a one-time download that makes sure code is available 100% of the time and with at worst disk-access latency is not making it less "clean", quite the opposite. It's a common practice and is enshrined in the docs.
Looking at your actual code, it executes in the content script context (regardless whether it's through manifest or executeScript), not in the page context. As such, no matter what the page does, $ will not be defined there.
I verified that window.jQuery is properly defined afterwards by the actual jQuery function/object [...]
I assume that you tried to execute window.jQuery in the console; by default, that executes it in the page context, not in your content script context (therefore, not reflecting the state of the content script context and not invoking your getter/setter). If you want to test your content script, you need to change top in the context drop-down above the console to your extension's context.
All that said, however,
When all is said and done, I want to use jQuery's ajaxSuccess function to execute code every time an e-mail is opened in the read pane.
Here we've got a problem. Since the content script code and webpage code are isolated, your code will never know about AJAX executing in the page's copy (not through ajaxSuccess, anyway).
Possible courses of action:
Rely on other methods to detect the event you want. Perhaps monitoring the DOM.
Inject some code into the page itself; the only way to do so is by injecting a <script> tag into the page from the content script. There, you can access the page's copy of jQuery, attach your listener and message your content script when something happens.
Rely on the background page to detect activity you need with webRequest API. This will likely intercept the AJAX calls, but will not give you the reply contents.
Final note: this may not be as simple as AJAX calls; perhaps the page maintains a WebSocket connection to get realtime push updates. Tapping into this is trickier.
Thanks to Xan, I found there are only two ways to do this.
The first is by adding a <script> element to the DOM containing the appropriate code. This is a pretty extensive StackOverflow answer on how to do that: https://stackoverflow.com/a/9517879/125938.
The second is using Javascript pseudo-URLs and the window.location object. By assigning window.location a bookmarklet-style URL containing Javascript, you also bypass certain security measures. In the content script, put:
location = 'javascript:(' + (function(){
var _jQuery;
Object.defineProperty(window, 'jQuery', {
get: function() { return _jQuery; },
set: function(newValue) {
_jQuery = $ = newValue;
console.log('totally logged!');
$('<span>jQuery stuff here</span>');
}
});
}).toString().replace(/\n/g, ' ')+')();';
The reason I/you were originally failing to define it, was because both methods of code injection we were using, caused our code to be sandboxed into isolated worlds: https://developer.chrome.com/extensions/content_scripts#execution-environment. Meaning, they share the page's DOM and could communicate through it, but they can't access each other's window object directly.

Chrome console - breakpoint over whole file

is there any option to set something like "breakpoint" on a file in chrome console (kindof shortcut to set breakpoint on every line of code in the file)?
Would be extremely useful when trying to understand 3rd party scripts that you know are executed but have no idea which part of code and from where is executed when.
My current example use case: I downloaded a script (form validation) which does not work as expected. The fastest way to solve the problem would be to pause execution anytime JS runtime enters this file and start exploring it from there.
I think this will be of use to you. I've recently been doing some work on the JavaScript Breakpoint Collection Chrome Extension created by Matt Zeunert, which allows you to inject breakpoints into your code at runtime - including breaking on property access/modifications, functions, scrolling events, etc. You can break on any arbitrary objects as well as the predefined ones using the console API.
Check out the project here.
If you can enumerate the functions publicly exposed by your third party script (for example if they are all properties of an object, or is their name has a pattern) you can make another script which dynamically replaces all those functions and force a break point :
thirdpartfunc = (function () {
var oldfunc = thirdpartfunc;
return function () {
debugger;
oldfunc.call(null, arguments);
}());
With the appropriate binding to this (if any applicable).
If you know the function(s) being called, you can use function breakpoints
debug(function);
function(...args);
When you call the function, it will hit the breakpoint. These aren't saved on page reload, but you can set a line breakpoint once you hit the function breakpoint.
This can get kinda tedious though.
If you have a array of functions, you can do
[function0, function1].map(debug)
#Tibos answer in another post would be good if there was some sort of babel transform to insert debugger; at the start of every function, instead of inserting it manually.
The quickest way for me was to do a global replace of the function declarations in the source, adding "debugger;" at the start.
In other words, replace
function [^{]*{
with
$0 debugger;
Your regexp may vary depending on the escapes you need. For example:
function [^{]*\{
You may also need more than one pattern to handle all the function declarations you have.
This has nothing to do with the Chrome console though.
No. You would have to add breakpoints to the various function entry points that file contains to catch everywhere it could enter.
Can't you just place a breakpoint at the first line of every function in the file of interest?

Firefox Extension: Access the DOM Before It's Loaded

I'm trying to create a Firefox extension that fires my Javascript code before any of the current page's Javascript is fired. My Javascript code will basically control whether or not the page's Javascript code can be executed or denied.
I first started out by trying to follow this answer, but I couldn't really figure out how to get it to work and realized I was relying on onDOMContentLoaded, which loads after the Javascript has already executed.
I then turned my attention toward XPCOM, but once again didn't really understand what the Firefox tutorials were telling me.
I've recently been trying to make an extension through Firebug, but I seem to hit the same problem... only having access to the Javascript after it's been parsed/executed. Here's the resulting code that I wrote. I think if I could access the file's objects in the onExamineResponse event, my problem could be solved, but I don't know how to do that... I'm talking about this code:
BeepbopListener.prototype = {
onRequest: function(context, file) {
...
},
onExamineResponse: function(context, file) {
FBTrace.sysout("onexamineresponse " + file); // this returns something like
// '[xpconnect wrapped (nsISupports, nsIHttpChannel, nsIRequest, nsIUploadChannel, nsITraceableChannel, nsIHttpChannelInternal)]'
// but I don't know how to access those elements...
var pattern = /\.js$/;
if (pattern.test(file.href) && FBTrace.DBG_BEEPBOP) {
FBTrace.sysout("ONEXAMINE DOESN'T EVEN GET IN THIS IF SO YOU WON'T SEE THIS");
}
},
...
};
So my question is... is there a tutorial out there that shows me how I can get access to all Javascript code on a page before it's executed? Also, if anyone has any helpful insight, I'd love to hear it. Oh, and if y'all need more code from me, just let me know, and I'll post it.
You can access a new document before any JavaScript code runs by listening to the content-document-global-created observer notification. However, the document will be empty at this point and JavaScript code will run as soon as the parser adds a <script> tag - you cannot really prevent it. Here are the options to control script execution that I am aware of.
1) Disable all JavaScript for a window using nsIDocShell.allowJavascript:
wnd.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShell)
.allowJavascript = false;
This is an all or nothing approach. Note that JavaScript stays disabled even when a new document loads into the same frame.
2) Implement the nsIContentPolicy interface in an XPCOM component and register it in the content-policy category (via nsICategoryManager). Your shouldLoad() function will be able to block scripts selectively - but it will only called for external scripts (meaning <script src="...">), not for inline scripts on the page.
3) Use JavaScript debugger service to intercept script execution. You could use jsdIDebuggerService.interruptHook to step through JavaScript execution and abort the script whenever you like. But that would slow down JavaScript execution very significantly of course. At the very least you should use jsdIDebuggerService.addFilter() to restrict it to a particular document, otherwise you will slow down the entire browser (including browser UI).
I'm trying to create a Firefox extension that fires my Javascript code before any of the current page's Javascript is fired. My Javascript code will basically control whether or not the page's Javascript code can be executed or denied.
Start by completely preventing the document from getting parsed altogether then on the side, fetch the same document, do any processing on this document and then inject the resulting document in the page. Here is how I currently do just that https://stackoverflow.com/a/36097573/6085033

Canceling dynamic script by removing script tag doesn't work in FF

I'm adding dynamic script by creating a script tag, setting its source and then adding the tag to the DOM. It works as expected, the script is getting downloaded and executes. However sometimes I would like to cancel script execution before it was downloaded. So I do it by removing the script tag from the DOM.
In IE9, Chrome and Safari it works as expected - after the script tag is removed from the DOM it doesn't execute.
However it doesn't work in Firefox - script executes even if I remove it from the DOM or change it its src to "" or anything else I tried, I cannot stop the execution of a script after it was added to the DOM. Any suggestions?
Thanks!
How about some sort of callback arrangement? Rather than have the dynamically added script simply execute itself when it loads, have it call a function within your main script which will decide whether to go ahead. You could have the main script's function simply return true or false (execute / don't execute), or it could accept a callback function as a parameter so that it can decide exactly when to start the dynamic script - that way if you had several dynamic scripts the main script could wait until they're all loaded and then execute them in a specific order.
In your main script JS:
function dynamicScriptLoaded(scriptId,callback) {
if (scriptId === something && someOtherCondition())
callback();
// or store the callback for later, put it on a timeout, do something
// to sequence it with other callbacks from other dynamic scripts,
// whatever...
}
In your dynamically added script:
function start() {
doMyThing();
doMyOtherThing();
}
if (window.dynamicScriptLoaded)
dynamicScriptLoaded("myIdOrName",start);
else
start();
The dynamic script checks to see if there is a dynamicScriptLoaded() function defined, expecting it to be in the main script (feel free to upgrade this to a more robust test, i.e., checking that dynamicScriptLoaded actually is a function). If it is defined it calls it, passing a callback function. If it isn't defined it assumes it is OK to go ahead and execute itself - or you can put whatever fallback functionality there that you like.
UPDATE: I changed the if test above since if(dynamicScriptLoaded) would give an error if the function didn't exist, whereas if(window.dynamicScriptLoaded) will work. Assuming the function is global - obviously this could be changed if using a namespacing scheme.
In the year since I originally posted this answer I've become aware that the yepnope.js loader allows you to load a script without executing it, so it should be able to handle the situation blankSlate mentioned in the comment below. yepnope.js is only 1.7kb.

Categories