Firefox addon SDK replace request - javascript

I tried to replace by a local script the url of scripts loaded by websites.
I tried to channel.redirectTo() with data.url() and chrome:// (with contentaccessible=yes flag in manifest), but doesn't work, so I compared a regex pattern, if true, it will cancel the XHR GET request.
For example
<script src="http://url/to/script.js"></script>
become
<script src="resource://url/to/new/script.js"></script>
or
<script src="chrome://url/to/new/script.js"></script>
Now I need to replace the url or inject my new script to the page
main.js
var listener = function (event) {
var channel = event.subject.QueryInterface(Ci.nsIHttpChannel);
var match = someFunctionToMatchRegex(channel.URI.spec);
if (match) {
channel.cancel(Cr.NS_BINDING_ABORTED);
}
};
events.on("http-on-modify-request", listener);

I have a redirect module here which is a good example for what you want to do. You might be able to use it, though the module only takes specific urls and not reg expressions at the moment. I'd certainly take a pull request to make this change though.
The code basically just uses redirectTo as you mention, so something else is wrong.

Related

Chrome extension express url

So At the moment, My code is listening in, and I want it to listen and then see any url which belongs under "https://www.stackoverflow.com/questions/*"
How do I go about using the asterisk in my current code to make sure that all of the website can use my function ?
var regex = /^((ftp|http|https):\/\/)?(www.)?(?!.*(ftp|http|https|www.))[a-zA-Z0-9_-]+(\.[a-zA-Z]+)+((\/)[\w#]+)*(\/\w+\?[a-zA-Z0-9_]+=\w+(&[a-zA-Z0-9_]+=\w+)*)?$/gm;
var str = ["http://www.whatevershop this is/jackets/#", "https://www.whatevershop this is/shoes/#"];
var matches_array = str.match(regex);
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
chrome.extension.getBackgroundPage().console.log(tab.url);
if (matches_array == tab.url) {
chrome.tabs.executeScript(null, {
file: "test.js"
});
}
});
The issue is when I use the asterisk (*) at the end of the slash (/) it doesn't actually let me use every single url, only the one which I enter ?
Any fixes ?
UPDATE:
Ive edited it as told, including the url and function still wont run :(
var regex = /^((ftp|http|https):\/\/)?(www.)?(?!.*(ftp|http|https|www.))[a-zA-Z0-9_-]+(\.[a-zA-Z]+)+((\/[\w#-]+)*(\/\w+\?[a-zA-Z0-9_]+=\w+(&[a-zA-Z0-9_]+=\w+)*)?$/gm;
And the str code is var str = ["http://www.whateversiteyouneed.com/shop/#", "https://www.whateversiteyouneed.com/shop/#"];
Bare in mind on the site, there are different categories, hence why the # is in place to allow it to use all of the different locations.
I'm still wondering why the script wont run though.
It's something in the script which isn't actually seeing the new url ?
If you only want your script executed on specific urls then in your manifest add a section for content_scripts with an array of urls allowed. This is a lot simpler than using tab update events and regex and has wildcards
e.g.
"content_scripts": [
{
"matches": ["*://*.whatever.com/dogs/*"],
"js": ["test.js"],
"run_at": "document_end",
}
]
Note it's an array of arrays, so you can put as many urls in 'matches' as you wish and with the outer array, you could have different scripts on different domains. Not that that's a common use case. See extension match patterns
With this approach, the script is injected automatically and by default is inject once the page is idle, which is usually equivalent to after document ready. I usually use document_end if my code is to execute immediately. If the code will be invoked by a message from the background, e.g. by context menus, you can load at start.

chrome.tabs.executeScript and injection only into pages that pass matches filter in manifest.json

I'm attempting to perform programmatic injection of my content script into open tabs after my Chrome extension is reloaded or updated.
My script may call the following method for an arbitrary tab:
var manifest = chrome.app.getDetails();
var scripts = manifest.content_scripts[0].js;
chrome.tabs.executeScript(nTabID, {
file: scripts[0]
});
This works, except when I try to load it into a page that was not supposed to have a content script running according to the matches clause in the manifest.json. I get the following exception:
Cannot access contents of url "actual-url-here". Extension manifest
must request permission to access this host.
So my question. Is there a way to parse the page URL and see if it matches matches clause from manifest.json and prevent calling chrome.tabs.executeScript for unnecessary URL?
PS. I understand that one "hacky" solution is to catch-and-ignore exceptions. So I'm not asking for it.
When you use chrome.tabs.query for a list of tabs, use the url attribute to filter by a match patterns. As of Chrome 39, this key also supports an array of match patterns. If you need to support Chrome 38 or earlier, or if you got the tabs without chrome.tabs.query, use the parse_match_pattern function from this answer to filter tabs. To use it, copy that function and include it within your (background) page (e.g. by pasting it before the following snippet).
var content_scripts = chrome.runtime.getManifest().content_scripts;
// Exclude CSS files - CSS is automatically inserted.
content_scripts = content_scripts.filter(function(content_script) {
return content_script.js && content_script.js.length > 0;
});
content_scripts.forEach(function(content_script) {
try {
// NOTE: an array of patterns is only supported in Chrome 39+
chrome.tabs.query({
url: content_script.matches
}, injectScripts);
} catch (e) {
// NOTE: This requires the "tabs" permission!
chrome.tabs.query({
}, function(tabs) {
var parsed = content_script.matches.map(parse_match_pattern);
var pattern = new RegExp(parsed.join('|'));
tabs = tabs.filter(function(tab) {
return pattern.test(tab.url);
});
injectScripts(tabs);
});
}
function injectScripts(tabs) {
tabs.forEach(function(tab) {
content_script.js.forEach(function(js) {
chrome.tabs.executeScript(tab.id, {
file: js
});
});
});
}
});
The previous snippet inserts a content script in all tabs. It is your responsibility to make sure that inserting the script does not conflict with an earlier/later instance of your script.
Mimicking the all_frames and match_about_blank functionality is slightly more complex, because the chrome.tabs.executeScript API cannot be used to target specific frames (crbug.com/63979). If you want to inject in frames as well, then you have to insert in every tab (because there might be a frame under the non-matching top-level frame that matches the URL) and check the page's URL within the content script.
Finally, note that your content script must also deal with the fact that it may run at a point different from "run_at". In particular, content scripts that rely on "run_at":"document_start" might fail to work because calling chrome.tabs.executeScript will cause a script to be injected far past the document_start phase.

bookmarklet: click for random specified links from a host domain

tl;dr: A bookmarklet that opens in a new tab: random link (with specified multiple html-classes) from a specified domain and code that works with current logins. Thank you.
short version of butchered code:
javascript:
(
var % 20 site = domain.com
function() {
window.location.host == site
void(window.open(document.links[Math.floor(document.querySelectorAll("a.class1, a.class2"))].href, '_blank'))
}();
//beautified with: http://jsbeautifier.org/
To whom it may concern:
I have searched around for a while and even considered switching services but although some come close or are similar to my particular request, none have served to address everything the request entails.
Execute the script on a specific domain even when no page from said domain is currently open. If login authentication for attaining the information or data for execution is required, read or work in conjunction with existing session.
Fetch from a specific domain host, a random link out of all links on that domain with a certain html-class (or indeed otherwise) using preferably, css-selectors.
Open the results in a new tab.
From butchering such similarities, the result became something like this:
//bookmarklet
javascript:
//anonymous function+ wrapped code before execution
(
// function global variables for quick substitution
var %20 site = domain.com
function(){
//set domain for script execution
window.location.host == site
//open new tab for
void(window.open(document.links
//random link
[Math.floor
//with specific classes (elements found with css selectors)
(document.querySelectorAll("a.class1, a.class2"))
]//end random-query
.href,'_blank' //end page-open
)//end link-open
)//end "void"
}//end function defintion
//execute
();
//(tried) checked with:
//http://www.javascriptlint.com/online_lint.php
Lastly, i have attained at most, basic css knowledge. I apologise if this request has anybody headdesking, palming or otherwise in gtfo mode. It is only too sad there is apparently no tag for "Warning: I DIY-ed this stuff" in StackExchange. However, i still would like answers that go into a bit of depth of explaining why and what each correction and modification is.
Thank you presently, for your time and effort.
Theoretically, the following code should do what you want:
window.addEventListener('load', function ( ) {
var query = 'a.class1[href], a.class2[href]';
var candidates = document.querySelectorAll(query);
var choice = Math.floor(Math.random() * candidates.length);
window.open(candidates.item(choice).href, 'randomtab');
}, true);
window.location.href = 'http://domain.com';
But it doesn't, because the possibility to retain event listeners across a page unload could be abused and browsers protect you against such abuse.
Instead, you can manually load the domain of your choice and then click a simpler bookmarklet with the following code:
var query = 'a.class1[href], a.class2[href]';
var candidates = document.querySelectorAll(query);
var choice = Math.floor(Math.random() * candidates.length);
window.open(candidates.item(choice).href, 'randomtab');
You could wrap the above in javascript:(function ( ) { ... })(); and minify as before, but it already works if you just minify it and only slap a javascript: in front.
I understand your situation of being an absolute beginner and posting "DIY" code, but I'm still not going to explain step-by-step why this code works and yours doesn't. The first version of the code above is complex to explain to a beginner, and the list of issues with the code in the question is too long to discuss all of them. You'll be better off by studying more Javascript; a good resource with tutorials is MDN.

Remove an injected analytics library from browser memory in Bigcommerce?

How can we remove this script injector system and clear functions from memory?
Briefing) Recently the malfeasants at Bigcommerce created an analytics injector (JS) under guise of "monitoring" that is locked in a global variable. They have pushed it to all their 50,000 front facing stores without consent from any OP's. This puts in 2 JS libraries and sets up (plain code) triggers for them to track customer, behavior, and store plans throwing data to their shared 3rd party analytics bay. The issue is that although they run the code, they do not own rights to put in 3rd party libraries like this across thousands of domains out of their realm. Does anyone have ideas on how we can kill this + remove from memory? Is this even legal for them to do?
1) The injector is found in the shared global %%GLOBAL_AdditionalScriptTags%% in the HTMLhead.html panel, which means it non-accessible. The AdditionalScriptTags is also dynamic, meaning it loads different JS helpers based on what page is being requested. Removing the variable is a no-go for that reason.
2) The injector uses various DSL variables PHP side to build out its settings. Here is what it looks like in <head> as I browse logged into our store as a customer. This is putting 2 lines for 2 separate libraries which I will define below (note certain tokens hidden as 1234)
(function(){
window.analytics||(window.analytics=[]),window.analytics.methods=["debug","identify","track","trackLink","trackForm","trackClick","trackSubmit","page","pageview","ab","alias","ready","group","on","once","off","initialize"],window.analytics.factory=function(a){return function(){var b=Array.prototype.slice.call(arguments);return b.unshift(a),window.analytics.push(b),window.analytics}};for(var i=0;i<window.analytics.methods.length;i++){var method=window.analytics.methods[i];window.analytics[method]=window.analytics.factory(method)}window.analytics.load=function(){var a=document.createElement("script");a.type="text/javascript",a.async=!0,a.src="http://cdn2.bigcommerce.com/r6cb05f0157ab6c6a38c325c12cfb4eb064cc3d6f/app/assets/js/analytics.min.js";var b=document.getElementsByTagName("script")[0];b.parentNode.insertBefore(a,b)},window.analytics.SNIPPET_VERSION="2.0.8",window.analytics.load();
// uncomment the following line to turn analytics.js debugging on
// shows verbose events and other useful information
// analytics.debug();
var storeId = '123456',
userId = '921';
// initialize with Fornax and Segment.io
var providers = {
Fornax: {
host: 'https://analytics.bigcommerce.com',
cdn: 'http://cdn2.bigcommerce.com/r6cb05f0157ab6c6a38c325c12cfb4eb064cc3d6f/app/assets/js/fornax.min.js',
defaultEventProperties: {
storeId: storeId
}
},
'Segment.io': {
apiKey: '1sbkkbifdq'
}
};
var fornaxEnabled = false;
var segmentIOEnabled = false;
var isStorefront = true;
if (!fornaxEnabled) {
delete providers.Fornax;
}
if (!segmentIOEnabled || isStorefront) {
delete providers['Segment.io'];
}
analytics.initialize(providers);
// identify this user
analytics.identify(
userId || null,
{"name":"Test Dude","email":"test#test.com","storeHash":"123456","storeId":123456,"namespace":"bc.customers","storeCountry":"United States","experiments":{"shopping.checkout.cart_to_paid":"legacy_ui","search.storefront.backend":"mysql"},"storefront_session_id":"6b546880d5c34eec4194b5825145ad60d312bdfe"}
);
})();
3) The output libraries are found as 2 references in the <head> and as you see if you own/demo a BC store, are rather un-touchable:
<script type="text/javascript" async="" src="http://cdn2.bigcommerce.com/r6cb05f0157ab6c6a38c325c12cfb4eb064cc3d6f/app/assets/js/fornax.min.js"></script>
<script type="text/javascript" async="" src="http://cdn2.bigcommerce.com/r6cb05f0157ab6c6a38c325c12cfb4eb064cc3d6f/app/assets/js/analytics.min.js"></script>
How can we break the injector and these trackers and prevent them from loading? Is there a way to remove their functions from memory? Speaking on behalf of many thousands of OP's and segment.io here, we are all at our wits end with this.
I've been hacking away at this too and I found something that works well to disable most/all of it.
Before this line:
%%GLOBAL_AdditionalScriptTags%%
Use this code:
<script type="text/javascript">
window.bcanalytics = function () {};
</script>
So you will end up with something like this:
%%GLOBAL_AdditionalScriptTags%%
<script type="text/javascript">
window.bcanalytics = function () {};
</script>
The <script> tags from part 3 of your question will still load as those are always PREpended before the first non-commented out <script> tag, but most, if not all, the analytics functionality will break, including external calls, and even fornax.js won't load. Hope this helps.
Per the question I linked, for you case to at least remove the scripts from Step 3 this is what you should do :
var xhr = new XMLHttpRequest,
content,
doc,
scripts;
xhr.open( "GET", document.URL, false );
xhr.send(null);
content = xhr.responseText;
doc = document.implementation.createHTMLDocument(""+(document.title || ""));
doc.open();
doc.write(content);
doc.close();
scripts = doc.getElementsByTagName("script");
//Modify scripts as you please
[].forEach.call( scripts, function( script ) {
if(script.getAttribute("src") == "http://cdn2.bigcommerce.com/r6cb05f0157ab6c6a38c325c12cfb4eb064cc3d6f/app/assets/js/fornax.min.js"
|| script.getAttribute("src") == "http://cdn2.bigcommerce.com/r6cb05f0157ab6c6a38c325c12cfb4eb064cc3d6f/app/assets/js/analytics.min.js") {
script.removeAttribute("src");
}
});
//Doing this will activate all the modified scripts and the "old page" will be gone as the document is replaced
document.replaceChild( document.importNode(doc.documentElement, true), document.documentElement);
You must make sure that this is the first thing to run, otherwise the other scripts can and will be executed.

Re-Direct with document.url.match

My goal is to redirect my website to (/2012/index.php)
ONLY IF the user goes to ( http://www.neonblackmag.com )
ELSE IF
the user goes to ( http://neonblackmag.com.s73231.gridserver.com ) they will not be re-directed... ( this way i can still work on my website and view it from this url ( the temp url )
I have tried the following script and variations, i have been unsuccessful in getting this to work thus far....
<script language="javascript">
if (document.URL.match("http://www.neonblackmag.com/")); {
location.replace("http://www.neonblackmag.com/2012"); }
</script>
This should work:
<script type="text/javascript">
if(location.href.match(/www.neonblackmag.com/)){
location.replace("http://www.neonblackmag.com/2012");
}
</script>
You should use regular expression as an argument of match (if you're not using https you can drop match for http://...
In your solution the semicolon after if should be removed - and I think that's it, mine is using location.href instead of document.URL.
You can also match subfolders using location.href.match(/www.neonblackmag.com\/subfolder/) etc
Cheers
G.
document.url doesn't appear to be settable, afaict. You probably want window.location
<script type="text/javascript">
if (window.location.hostname === "www.neonblackmag.com") {
window.location.pathname = '/2012';
}
</script>
(Don't use language="javascript". It's deprecated.)
Anyone at any time can disable JavaScript and continue viewing your site. There are better ways to do this, mostly on the server side.
To directly answer your questions, this code will do what you want. Here's a fiddle for it.
var the_url = window.location.href;
document.write(the_url);
// This is our pretend URL
// Remove this next line in production
var the_url = 'http://www.neonblackmag.com/';
if (the_url.indexOf('http://www.neonblackmag.com/') !== -1)
window.location.href = 'http://www.neonblackmag.com/2012/index.php';
else
alert('Welcome');
As I said, this can be easily bypassed. It'd be enough to stop a person who can check email and do basic Google searches.
On the server side is where you really have power. In your PHP code you can limit requests to only coming from your IP, or only any other variable factor, and no one can get in. If you don't like the request, send them somewhere else instead of giving them the page.
header('Location: /2012/index.php'); // PHP code for a redirect
There are plenty of other ways to do it, but this is one of the simpler. Others include, redirecting the entire domain, or creating a test sub domain and only allow requests to that.

Categories