Javascript - block image-request and replace requested img-url with another - javascript

I have some Google-Scripts on my website and unfortunately one of them loads some additional scripts and images over http instead of https (my website is delivered over https). I managed to get the scripts loaded over https with the following code (from this question):
Object.defineProperty(HTMLScriptElement.prototype, 'src', {
get: function(url) {
return this.getAttribute('src')
},
set: function(url) {
//console.log(url);
var prefix = "http://";
if (url.startsWith(prefix))
url = "https://" + url.substr(prefix.length);
//console.log('being set: ' + url);
this.setAttribute('src', url);
}
});
But there are a few image files, which are still loaded over http. These files are not available over https.
My thought was to download these images and put them on my server and load them from there. Is there a way with JavaScript to overwrite the image path? Of course, I could use jQuery but before this, I have to block the image-request before it's fired. Otherwise I have the Problem of mixed content on my page.
So let's put it together:
- page is loaded and after some time a certain user-action (in my case submitting a form) happens
- based on this action an additional script is loaded which places a virtual keyboard on my page
- this keyboard has some images which could not be loaded over https so I want to block these requests
- then, I want to replace the blocked image-urls with my custom image-urls
Is this possible?
Thanks!

You can try shimming a JavaScript based HTTP proxy that intercepts http requests preflight. There's a popular mocking JavaScript library that does that called pretender,
https://github.com/pretenderjs/pretender/blob/master/pretender.js#L266
I think you can use pretender's code to help you figure out how to intercept the http requests preflight and reroute them to a proxy of your choice that supports https.

Related

Manifest V3 web extension overwrite response body

How would I overwrite the response body for an image with a dynamic value in a Manifest V3 Chrome extension?
This overwrite would happen in the background, as per the Firefox example, (see below) meaning no attaching debuggers or requiring users to press a button every time the page loads to modify the response.
I'm creating a web extension that would store an image in the extension's IndexedDB storage and then override the response body with that image on requests to a certain image. A redirect to a dataurl: I have it working in a Manifest V2 extension in Firefox via the browser.webRequest.onBeforeRequest api with the following code, but browser.webRequest and MV2 are depreciated in Chrome. In MV3, browser.webRequest was replaced with browser.declarativeNetRequest, but it doesn't have the same level of access, as you can only redirect and modify headers, not the body.
Firefox-compatible example:
browser.webRequest.onBeforeRequest.addListener(
(details) => {
const request = browser.webRequest.filterResponseData(details.requestId);
request.onstart = async () => {
request.write(racetrack);
request.disconnect();
};
},
{
urls: ['https://www.example.com/image.png'],
},
['requestBody', 'blocking']
);
The Firefox solution is the only one that worked for me, albeit being exlusive to Firefox. I attempted to write a POC userscript with xhook to modify the content of a DOM image element, but it didn't seem to return the modified image as expected. Previously, I tried using a redirect to a data URI and an external image, but while the redirect worked fine, the website threw an error that it couldn't load the required resources.
I'm guessing I'm going to have to write a content script that injects a Service Worker (unexplored territory for me) into the page and create a page rule that redirects, say /extension-injected-sw.js to either a web-available script, but I'm not too sure about how to pull that off, or if I'd still be able to have the service worker communicate with the extension, or if that would even work at all. Or is there a better way to do this that I'm overlooking?
Thank you for your time!

How to intercept all http request and change url to https

I have some 3rd parties JavaScript files in my code which includes some another JavaScript files which are loaded after some event. I don`t have control to change code inside 3rd party JavaScript file.
My website is hosted on https and included files are loading over http since browser does not allow this to load and says "mix content blocked".
Can I write interceptor that will intercept this call and will change http to https.
When you are including a 3rd party library in your code, the loading browser will make the request to the server where the code is hosted. You can download the code, if it's available and there is no legal issues to do so, and host it on your server. You have to understand that not all data needs to go through https (to increase performance for example).
Take a look at this link to have a better understanding of the issue and how the prevent it.
Thanks for your comments but I don`t believe I should change 3rd party libraries as there might be some legal issues with it.
But I found something which can solve my issue by intercepting all the http calls and forward it to https by adding following code in your JavaScript at global.
Object.defineProperty(HTMLScriptElement.prototype, 'src', {
get: function() {
return this.getAttribute('src')
},
set: function(url) {
var prefix = "http://";
if (url.startsWith(prefix))
url = "https://" + url.substr(prefix.length);
console.log('being set: ' + url);
this.setAttribute('src', url);
}
});
Originally posted here : Force JavaScript to load additional resources over https

Force http protocol in Javascript file from local protocol

We are using HTML5 to develope an phone app, which means that our local protocol on the phone is file://. We are trying to include Opentable's widget on our page for now. But their widget JS link looks like:
<script type='text/javascript> src='//secure.opentable.com/widget/reservation/loader?rid=27763&domain=com&type=standard&theme=standard&lang=en&overlay=false&iframe=true'></script>
Note that it starts with
//secure.opentable.com
So it will get our file:// protocol automatically. But even I change it to
https://secure.opentable.com
It still does not work on local. I noticed that in their JS source, they still used "//" which will somehow still get our "file://" protocol.
Here is the error after I change the link to https://secure.opentable.com/...
Failed to load resource: The requested URL was not found on this
server.
file://www.opentable.com/widget/reservation/canvas?rid=27763&domain=com&type=standard&theme=standard&lang=en&overlay=false&insideiframe=true
I noticed that in the console it looks like:
How can I make it work for a local environment?
Thanks!
Maybe this will work:
$(document).ready(function() {
$("iframe[src^='//www.opentable.com']").attr('src', function(i, oldsrc) {
return "https:" + oldsrc;
});
);
It waits until the document is ready, which should be after the new IFRAME is added to the DOM, then it replaces its src with one with the https: protocol.

What are the ways to load JavaScript or CSS without executing them?

I'm aware of dynamic script/css loading by adding <style> or <link> tags to head or body of the page, but then it will be executed by browser once downloaded. I was thinking about other ways to download but do not execute javascript/css code. First what comes in my mind was XMLHttpRequest:
//simple execution received script
var executeScript = function(code){
eval(code);
};
//create XMLHttpRequest in cross-browser manner
var xhr = createXMLHTTPObject();
//check whether file is loaded
var checkStatus = function(){
if(xhr.readyState == 4){
if(xhr.status >= 200 && xhr.status < 300 || xhr == 304){
executeScript(xhr.responseText);
}
else {//error
}
}
};
//do request
xhr.open('get','http://podlipensky.com/examples/dynamicscript/hey.js', true);
xhr.onreadystatechange = checkStatus;
xhr.send(null);
But in this case we're limited with scripts from the same domain because of the Same Origin Policy (although we can try workaround it with CORS)
Another approach, I was thinking about is to add dynamically iframe to the page and then add script tag to the iframe, so the script will be executed once it downloaded, but it happens in context of another page - iframe.
Are there any other ways to download and not execute the script?
UPDATE:
One of the reasons why it would be useful to download, but not execute javascript/css is to pre-load third-party libraries, but use them only on demand.
Just found out one more option to load script/css asynchronously (without conflicting to SOP) - is to use <object> tag:
<object data="http://podlipensky.com/examples/dynamicscript/hey.js" />
Found this approach here. So I'm just sharing with you my findings, hope it will be useful.
You can also use an iframe and use the script/css URL as the src of the frame (so it isn't evaluated/applied at all), although you'd want to be sure in that case that the JavaScript/CSS was delivered with Content-Type text/plain to avoid unfortunate things happening with < characters and such. Although you should run into SOP issues with this approach as well, on a decent browser, if the iframe src is from a different origin.
Other than that, I think you largely have it covered with the options you list.
If your script simplty defines a function then it can be executed without actually running anything. Of course, this would require collaboration from both sides ala JSONP
//jsonp
var result = {/*...*/};
//missingnonp
var f = function(){ /**/ };
Assuming you control the server that delivers the page, into which you want to load the JS in question, the easiest way is to submit the URL via AJAX to your server, load it from there (e.g. via PHP file_get_contents($url);) and get it back as a result of the AJAX call.

Running a JS method once to initiate variable when the chrome extension is loaded once?

I need to load a var by getting JSON from a webservice, so my question is where does this code go? I tried to put it in the content script but XHR would fail there.
Any suggestions?
Starting from Chrome 13 content scripts can also perform XHR requests (before only background pages could). So you can put your code wherever you like.
If it doesn't work then you probably didn't specify domain permissions (or trying to connect to non-80 port, to non-http(s) protocol etc).

Categories