Manipulate website which has been called from another website with Greasmonkey [duplicate] - javascript

This question already has answers here:
Fire Greasemonkey script on AJAX request
(2 answers)
Closed 7 years ago.
I have the following situation:
A website gets data from another html-file("news.html") which gets called every 10s or so
I want to manipulate the data from the news.html
I thought I could set up a greasemonkey script which manipulates the news.html and thus also the main website.
However this assumption was wrong: When I open the news.html in my browser, the news are manipulated (in terms of data - just to clarify this), but when I visit the main website the news don't get manipulated.
I think that greasemonkey does not work when the website is not opened "directly" in the browser, but with ajax/jQuery/....
Is there any known workaround for this?
Thanks in advance!

You can't change files that are on a server with greasemonkey unless the API for some reason leaves that exposed. Whatever you are changing is just local to you.

For simple pages, it's safest to wrap your greasemonkey scripts in at least an unload handler: According to the "Authoring" page at http://greasemonkey.mozdev.org/authoring.html,
User scripts are executed after the DOM is fully loaded, but before
onload occurs. This means that your scripts can begin immediately and
don't need to wait for onload. However, replacing large parts of the
DOM (e.g. using innerHTML or outerHTML) at this early stage of
rendering is known to cause Firefox some trouble. In this case, you'll
have more success if you call your code in response to the load event
instead:
window.addEventListener("load", function(e) {
document.innerHTML = "Hello, world!";
}, false);
However, if the "main site" is constructing itself via a secondary ajax call to news.html, that won't be enough, because the data you want to manipulate won't be in the DOM yet when your script runs on the main site. You'll need to delay your script's execution until after the main site has finished doing its thing, so that when you try to do your thing there'll be the thing there for you to do your thing to. So to speak.
Have your script observe the DOM and wait to run until after news.html has been injected into the main site, or be lazy and start it after a sufficiently-long setTimeout.
(A clarification based on discussion in comments: Greasemonkey will only act on the site that was actually loaded in the browser; it will not act directly on every XHR request that site makes, even if that url was #included in the script. So if site "foo.com" ajax-injects content from "bar.com/news.html", and the browser loaded "foo.com", greasemonkey will not directly modify the "bar.com/news.html" request foo.com made; it can only work with the DOM that foo.com constructs based on what it got from news.html.)

Related

Wistia E-v1.js script being loaded twice

So I am calling the wistia script with a script tag in my head like this:
<script charSet='ISO-8859-1' src='//fast.wistia.com/assets/external/E-v1.js' async defer data-script='wistia' />
However, when I check out the network tab on Chrome, I notice that the E-v1.js script from Wistia is being loaded twice, which is rather significant as it is a 273kb script.
The first load of the script is from https://fast.wistia.com/assets/external/E-v1.js, the location to which I have called it.
However, the second load of the script comes from an iframe, despite me not having put any iframes on the page. This iframe calls the script even on webpages which do not contain any wistia videos. The referrer is: https://fast.wistia.com/embed/iframe_shim?domain=com.
What's going on here? I assume this is some trying-to-be-helpful behaviour from wistia to lazy load their script via an iframe, but it's already loaded...
So I contacted Wistia and got an answer. Their development practices are not exactly intuitive.
Here's what the guy said:
The iframe_shim is a way of tracking the visitor_key for stats tracking, and storing that information on the fast.wistia domain rather than your domain. For a more lightweight method of doing that, you can set window.wistiaIframeShim = false in script tags on your page, and that will stop E-v1.js from loading again. Visitors will then be tracked via a cookie and localstorage directly on your domain instead of the fast.wistia.com domain. As far as I know this shouldn't be problematic, and we'll eventually be changing how that works to make it more efficient, it just hasn't been prioritized yet.
So they seem to load it twice from two different origins just to store a tiny amount of information on their own domain rather than on the client. Seems ridicuous to me, but I can confirm as of right now that all you have to do is change that window variable.
THE FIX: window.wistiaIframeShim = false

Is there an alternative to preprocessorScript for Chrome DevTools extensions?

I want to create a custom profiler for Javascript as a Chrome DevTools Extension. To do so, I'd have to instrument all Javascript code of a website (parse to AST, inject hooks, generate new source). This should've been easily possible using chrome.devtools.inspectedWindow.reload() and its parameter preprocessorScript described here: https://developer.chrome.com/extensions/devtools_inspectedWindow.
Unfortunately, this feature has been removed (https://bugs.chromium.org/p/chromium/issues/detail?id=438626) because nobody was using it.
Do you know of any other way I could achieve the same thing with a Chrome Extension? Is there any other way I can replace an incoming Javascript source with a changed version? This question is very specific to Chrome Extensions (and maybe extensions to other browsers), I'm asking this as a last resort before going a different route (e.g. dedicated app).
Use the Chrome Debugging Protocol.
First, use DOMDebugger.setInstrumentationBreakpoint with eventName: "scriptFirstStatement" as a parameter to add a break-point to the first statement of each script.
Second, in the Debugger Domain, there is an event called scriptParsed. Listen to it and if called, use Debugger.setScriptSource to change the source.
Finally, call Debugger.resume each time after you edited a source file with setScriptSource.
Example in semi-pseudo-code:
// Prevent code being executed
cdp.sendCommand("DOMDebugger.setInstrumentationBreakpoint", {
eventName: "scriptFirstStatement"
});
// Enable Debugger domain to receive its events
cdp.sendCommand("Debugger.enable");
cdp.addListener("message", (event, method, params) => {
// Script is ready to be edited
if (method === "Debugger.scriptParsed") {
cdp.sendCommand("Debugger.setScriptSource", {
scriptId: params.scriptId,
scriptSource: `console.log("edited script ${params.url}");`
}, (err, msg) => {
// After editing, resume code execution.
cdg.sendCommand("Debugger.resume");
});
}
});
The implementation above is not ideal. It should probably listen to the breakpoint event, get to the script using the associated event data, edit the script and then resume. Listening to scriptParsed and then resuming the debugger are two things that shouldn't be together, it could create problems. It makes for a simpler example, though.
On HTTP you can use the chrome.webRequest API to redirect requests for JS code to data URLs containing the processed JavaScript code.
However, this won't work for inline script tags. It also won't work on HTTPS, since the data URLs are considered unsafe. And data URLs are can't be longer than 2MB in Chrome, so you won't be able to redirect to large JS files.
If the exact order of execution of each script isn't important you could cancel the script requests and then later send a message with the script content to the page. This would make it work on HTTPS.
To address both issues you could redirect the HTML page itself to a data URL, in order to gain more control. That has a few negative consequences though:
Can't reload page because URL is fixed to data URL
Need to add or update <base> tag to make sure stylesheet/image URLs go to the correct URL
Breaks ajax requests that require cookies/authentication (not sure if this can be fixed)
No support for localStorage on data URLs
Not sure if this works: in order to fix #1 and #4 you could consider setting up an HTML page within your Chrome extension and then using that as the base page instead of a data URL.
Another idea that may or may not work: Use chrome.debugger to modify the source code.

Load external page and Replace text

Would it be possible to load an external page inside a container and replace text elements?
We work with ad campaigns and earn a percentage whenever a user signs up.
Can a script replace certain words? For instance “User” to “Usuario” or “Password” to “Contraseña” without affecting the original website or its functions.
Note: These links always pass through a redirection.
Example:
http://a2g-secure.com/?E=/0yTeQmWHoKOlN6zUciCXQwUzfnVGPGN&s1=
Note 2: Using an iframe is out of the question due to “Same-origin policy”.
I'm not sure if this answers your question, but you might find it useful.
(Perhaps you might give a step-by-step example of what you're trying to accomplish?)
If we assume that a browser attempts to retrieve page P from a proxy which first retrieves the content of page P from its actual home and then performs some transformation on its content before returning that page content to the browser, what you're describing is a Reverse HTTP Proxy and is a very well-known page serving technique.
Rather than performing complex transformations at the server (which require specialized knowledge of the page layout), this technique is usually used to inject a single line into the retrieved source that calls a JavaScript file to actually perform the required transformation at the browser.
So in essence:
Browser requests Page P from Proxy 1.
Proxy 1 retrieves the actual Page P from its real home, Server 2.
Proxy 1 adds the line <script src="//proxy1.com/transform.js"></script> to the source of Page P.
Proxy 1 then returns the modified source of Page P to Browser.
Once the Browser has received the page content, the JavaScript file is also retrieved, which can then modify the page contents in any way required.
This technique can be used to solve your "Same origin policy" issue by loading an iframe from a URL that points to the same server as that which provided the parent or owning page of the iframe which acts as proxy, like:
http://example.com/?proxy_target=//server2.com/pageP.html
Thus, the browser only "sees" content from a single server.
You would need to load the external page server-side, and then you can do whatever you want with it. You can do serverside string replacement, or you can do it later in javascript.
But, remember that as soon as you add a whole webpage into for example a div in your own page, the css from your page will affect it.
Plus, you would need to manipulate all the links in the documents, to have absolute urls. If the page depends on ajax, there is pretty much no way to accomplish what you want to do.
If on the other hand the pages you will be loading are static html, it is possible, though there are a lot of things you need to take care of before you can actually present the page to the user, like adjusting links, urls to stylesheets and so on.
It seems you are trying to localize a website on the fly, using your server as a proxy for that content. Does it make sense? If that's the case, depending on the size of your operation, there are several proxy translation services out there (I'll name them if needed).
Basically, they scrape a website, providing a way for you to translate and host the translated content. Of course, this depends on your relationship with the content providers. You should also take this into consideration, since modifying content, even for translation, can be a copyright problem.
All things considered, if you trust the provider's javascript, the solution involves scraping the content, as mentioned in other answers, and serving that modified content. You really need to trust the origin...
update per request
http://www.easyling.com
http://www.smartling.com
http://www.motionpoint.com
http://www.lionbridge.com/solutions/translation-proxy/
http://www.sajan.com/translation-proxy-technology-and-traditional-website-translation-understanding-your-options/
They are all aimed at enterprise-grade projects, but I would say Easyling is the most accessible.
Hope this helps.
Using the .load() callback function, this will replace the text
$(function(){
$("#Content").load("http://example.com?user=Usuario",function() {
$(this).html($(this).html().replace("user", +get param value+));
});
redirection u can use
// similar behavior as an HTTP redirect
window.location.replace("url");
// similar behavior as clicking on a link
window.location.href = "url";
The answer is NO, not without using a server-side proxy. For a really good overview of how to use a proxy, see this YUI page: https://developer.yahoo.com/javascript/howto-proxy.html (Be patient, as it will take time to load, but the illustrations are worth it!)
When I try to do this in jsfiddle to see what data that the 3 parameters contain, then the error below appears:
$(function() {
$(this).load('https://stackoverflow.com/questions/36003367/load-external-page-and-replace-text', function(responseText, textStatus, jqXHR){
debugger;
});
});
ERROR:
XMLHttpRequest cannot load Load external page and Replace text.
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://fiddle.jshell.net' is therefore not allowed access.

Chrome App messaging and 'loadstop' vs. .load() timing

I am developing a Chrome App with webviews. Pages intended for the webviews may also run in a regular browser. If inside a webview, pages send messages to the main App, but apparently they need to get a message from the App first, in order to know where to send their messages.
No problem - the main App sends a message as soon as it sees a 'loadstop' event which tells the pages where to send messages to. If a page is not in a webview then it never gets the message.
The problem is, I need to know when a page should stop waiting for the message and assume it is NOT in a webview.
When does 'loadstop' occur, relative to events in the page such as jQuery's .ready or .load? Is there a way to trap or trigger an event guaranteed to occur after 'loadstop' MIGHT be seen in the main App and a message sent and received by the webview's JavaScript.
When does 'loadstop' occur, relative to events in the page such as jQuery's .ready or .load?
According to the documentation for the loadstop event:
Fired when all frame-level loads in a guest page (including all its subframes) have completed. This includes navigation within the current document as well as subframe document-level loads, but does not include asynchronous resource loads.
This would suggest it's more akin to jQuery's .ready(), which executes after the DOM tree is loaded, but before waiting for asset (.css, .js) downloads.
Keep an eye on that documentation page; it's already much improved since two weeks ago.
Is there a way to trap or trigger an event guaranteed to occur after 'loadstop' MIGHT be seen in the main App and a message sent and received by the webview's JavaScript?
Your manifest.json declares your my-app-main.js background script (and your webview permission) which launches your my-webview-wrapper.html which includes your <webview> tag and also inlines some javascript (or sources a my-webview-wrapper.js file) that assigns event listeners to your webview via an onload function as such:
onload = function() {
webview = document.getElementById("the-id-attribute-of-my-webview");
webview.addEventListener("<EVENT>", function() {
// the cool stuff you want to do
}
}
<EVENT> can be any of the webview DOM events listed in the documentation I linked (including loadstop). Your main app shouldn't really care that any of this is happening. (It's async! It's javascript! It's magic!)
If you're still confused, just poke around Google's webview sample on GitHub.

Execute javascript retrieved with AJAX in Chrome extension

I am writing a chrome extension that injects a div into a website with a content script. The content script makes an AJAX request to a website that I cleared in the manifest.json file and it inserts the data into the div with innerHTML. Part of what the AJAX request returns is javascript that needs to be executed. The AJAX request from within the content script works fine.
When I make the same AJAX request from a regular website, the javascript that is returned executes just fine, but when I make the AJAX request from the content script it does not execute. No errors are displayed in the console. I don't want to reload the website, if possible.
I assume that this is a security 'feature' and not a bug. How can I turn off or circumvent this behavior?
First off what Rob W said is very important, if you don't already know it, a good explanation of the different environment a content script runs in is useful.
You might want to check this out. It's not 100% what you're looking for but the main part is there. Basically from your background page (if you don't have one already create one), you use chrome.tabs.executeScript() to execute the script you've downloaded. That runs the javascript in the real page context instead of the "content script" context. All you need now is to get that script (in string form) to the background page, and determine the tabId to execute it on (from the sender tab)
You can use chrome.extension.sendMessage to send it to the background page, and in the background.js, use chrome.extension.onMessage to receive the message with your script. From there use the sender argument to get the tabId (sender.tab.id), and build your executeScript call.
One more helpful hint, page scripts (dynamic javascript executions) in chrome by default don't show up in any set way in the chrome debugger, but you can append something like this to the string of your javascript:
"\n//# sourceURL=/myFolder/myDynamicJavascript.js"
This will make this script always show up with the "/myFolder/myDynamicJavascript.js" path for the chrome debugger, allowing you to set breakpoints in the js code you've inserted. It's a lifesaver.

Categories