Replacing the entire HTML document of a website from a Chrome Extension - javascript

I'm working on a Chrome extension that blocks websites, but not using the Chrome built-in blocking methods. The reason for customising, is I need to display a custom block page for each website blocked - the same template, with details as to why this particular site is blocked.
In my content.js file I store a full HTML template of a 'this site is blocked' page in a var called template (as I couldn't figure out loading it from a file inside the Extension, I'm a Python coder by day...). The manifest contains a large list of URLs, so if the content.js script has been loaded, this site should be blocked (or checked to see if locally the user has allowed it with 'allow anyway'). If a site should be blocked, the only thing I've gotten to work is:
var template = `<html>...full web page template removed...</html>`;
chrome.runtime.sendMessage({method: "getSite", site: window.location.host.toString()}, (response) => {
console.log(response.data);
document.body.innerHTML = renderTemplate(template, response.data);
});
The renderTemplate function just takes the HTML and does some find + replace with the response.data - which is data about the URL, fetched from a background script that's simply a .js file with a massive dictionary.
The problem is it obviously only replaces the <body>, and the websites CSS affects the block page. Is it possible to replace the entire page contents? Trying to replace the document.body entirely throws The provided value is not of type 'HTMLElement'.
I'm still learning both JS + extension development, any advice appreciated.

Use document.write
The problem that you are running into is that you are replacing the body, but not the head (or any <script>s that reside outside of the body).
To replace all html, you want to use document.write. Depending upon how you want to overwrite, you may want to call document.open and document.close.
Example
An example replacing all html is shown below:
newHTML = `<html>
<head>
<title>A Simple HTML Document</title>
</head>
<body>
<p>This is a very simple HTML document</p>
<p>It only has two paragraphs</p>
</body>
</html>`
document.open()
document.write(newHTML)
document.close()
Verification
Using Chrome Developer Tools (should be Options > More Tools > Developer Tools), we can navigate to the console and get the content
-> document.documentElement.outerHTML
<- html
<html><head>
<title>
A Simple HTML Document
</title>
</head>
<body>
<p>This is a very simple HTML document</p>
<p>It only has two paragraphs</p>
</body></html>"
This jsfiddle example shows what this looks like, and replaces the CSS background.

Related

How to hide src attribute value (url) in iframe tag?

Is there any tricks to hide the src url in iframe? Or maybe encrypt a part of the external url?
TLDR: No, You cant.
You can prevent it appearing at browser page source using JavaScript. But people still can see it with Inspect Element option.
And if you encrypt the URL, it won't work. HTML src must have a specific URL/File path. It can't understand encrypted text.
Still, If you want to hide it from page source, Try this:
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Document</title>
</head>
<body>
<iframe id="extframe" src=""></iframe>
<script src="script.js"></script>
</body>
</html>
JavaScript at script.js file:
var iframeUrl = document.querySelector('#extframe');
iframeUrl .setAttribute('src', 'https://stackoverflow.com/');
You can't. If the URL isn't in the HTML, how would the browser know where to get it?
One thing you could try is to obscure it to make it slightly harder for someone to find it. You could have the src attribute be blank and then when the document is ready fetch the URL value from the server in a separate AJAX request and update the iframe tag to include that value in the src.
This would be a fair amount of work, however, and wouldn't really accomplish anything. The only thing it would prevent is somebody finding it by viewing the page source. They can still look at the "current version" of the HTML in any web browser's debugging tools. (Right click on an element and inspect it, which is nearly ubiquitous at this point.) Or any other normal traffic-sniffing tools will see it plain as day.
Ultimately, if the web browser needs to know a piece of information, then that information needs to be visible on the client-side.

Javascript null error when using external script in a Rails app

I am using a banner ad from an ad service provider, similar to google adsense.
Instruction from their site state clearly and simply that all we need to do is to copy the below code to the body of our webpage
<!-- Begin Hsoub Ads Ad Place code -->
<script type="text/javascript"><!--
hsoub_adplace = [my account id];
hsoub_adplace_size = '728x90';
//--></script>
<script src="http://ads2.hsoub.com/show.js" type="text/javascript"></script>
<!-- End Hsoub Ads Ad Place code -->
I have copied and pasted into my rails app, inside a body of a view file but the banner is not getting displayed and I can see javascript error (with browser inspect source)
TypeError: document.getElementById(...) is null
ps: On old browsers the banner is getting displayed but never on recent versions of browsers.
ps2: The support of hsoub confirmed multiple times, there is no problem from their side (their code is fine and working on thousands of websites, and my account is active with no issues). And it must be a problem from my code.. I am thinking the way Rails handles javascript...
Can you please help me solve this error and get the banner displayed.
ps3: I am using rails 6.0.1 and turbolinks 5.2.0
you can check the error/source code online at https://tafqit.com/
The problem is caused by Rocket Loader feature of CloudFlare cdn service
Rocket Loader improves paint times for pages that include Javascript.
Visitors will have a better experience by seeing content load faster
and speed is also a factor in some search rankings.
Rocket Loader improves paint times by asynchronously loading your
Javascripts, including third party scripts, so that they do not block
rendering the content of your pages.
I disabled it and banner is appearing now.
I am going to guess that this is a script positioning issue. It looks like the script is possibly looking for elements that are not rendered yet, i.e. the document and document body is not ready. Move the scripts to the end of the page i.e. after the body tags and see if that helps. Otherwise please add the exact error and perhaps show a condensed view of your page and the scripts relative to the other elements.
<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Hello world</h1>
</body>
<script type="text/javascript">
hsoub_adplace = 12345;
hsoub_adplace_size = '728x90';
</script>
<script src="http://ads2.hsoub.com/show.js" type="text/javascript"></script>
</html>
I managed to get the iframe to load by moving the scripts
Scripts are (still) inside the body tags.

External link Alternative for JS

hi am trying to create an external link for a java script program i created and i tried using https://www.000webhost.com but they blocked me, so pleases is there any better way i can do this, plus am still a learner in programming,
here is the code i created and i want it to be linked,
document.body.appendChild(document.createElement('script')).src='https://usscript1.000webhostapp.com/example1';
EDIT:
For hosting the JS source file on some external server for testing you can use sites like http://yourjavascript.com
You can search for more alternatives on Google but this one worked well for me :)
Original Answer:
As others pointed out in comments, you can simply put the source url of JavaScript program in src attribute of <script> tag...
<html>
<head>
<script src="https://usscript1.000webhostapp.com/example1.js"></script>
</head>
<body>...your website's body here...</body>
</html>
Regarding the blocking issue, make sure your src link to the JavaScript file is correct (by opening the link in seperate browser tab or have look at the console in inspect page window for any errors).
You can put the script on the same site and link to it as,
<html>
<head>
<script src="/example1.js"></script>
</head>
<body>...your website's body here...</body>
</html>
If you are facing issues with putting the file on your site, you can directly put the code of JavaScript program inside <script> tag like this...
<html>
<head>
<script>
...your JS program goes here...
</script>
</head>
<body>...your website's body here...</body>
</html>

JQuery - ScrollTop not working in Chrome Extension

I've been trying to figure this out for a while now, but I'm at my wit's end and have given up all hope.
Here is my unpacked chrome extension: nexrem.com/test/extension-test2 - Copy.zip
Exhibit A:
Navigate into the template folder
run test.html in Chrome
Click on the "Footer link"
Observe it scroll correctly to the footer
Exhibit B: Currently, the extension basically replaces the entirety of html on the page.
Install the unpacked extension
Go to some website (for the sake of testing, one that isn't filled with all sorts of scripts. or just make a local blank html file)
Click the extension icon in chrome
You will see the exact same page as when you ran just the test.html ;however, the jquery scrolling no longer works. I fail to understand why.
If someone can explain this to me, assist in a solution or at least point in the right direction, I'd greatly appreciate it!
According to load
jQuery uses the browser's .innerHTML property to parse the retrieved document and insert it into the current document. During this process, browsers often filter elements from the document such as <html>, <title>, or <head> elements. As a result, the elements retrieved by .load() may not be exactly the same as if the document were retrieved directly by the browser.
And after digging into your html code after you click the browser action, it seems the body tag is not included.
You can use the following code instead load
var template = chrome.extension.getURL('template/test.html');
console.log(template);
$.get(template, function(data) {
document.open();
document.write(data);
document.close();
$.cache = {};
}, "text");

How to cut out elements from a page with Chrome Extension

I'm making a chrome extension that loads an <iframe> of another site onto the New Tab page. Right now I'm loading YouTube's subscription page (don't worry about the Same-Origin issue, I solved that already), but now I'm trying to cut everything out of the page except the #content element (the subscription feed element).
Here's my code:
Background.html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="script.js"></script>
</head>
<iframe id="left" src="left.html" name="left"></iframe>
<iframe id="right" src="right.html" name="right"></iframe>
</html>
Left and Right .html
<!DOCTYPE html>
<html>
<body>
<input type="button" value="Load new document" id="loader">
</body>
<script type="text/javascript" src="window.js"></script>
</html>
Window.js
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("loader").addEventListener("click", loadUrl);
});
function loadUrl()
{
window.location = 'https://www.youtube.com/feed/subscriptions';
[].forEach.call(document.querySelectorAll(!'#content'),function(e){
e.parentNode.removeChild(e);
});
return false;
}
As you can see, right now I'm loading it in with a button. Once it's pressed, it loads YouTube and should cut out all the html except #content, but it's not. Is there another way to solve this, possibly with jQuery? Thanks!
document.querySelectorAll(!'#content')
won't meet your requirements, you should use the following instead if you do want to remove all elements except #content.
document.querySelectorAll('*:not(#content)')
#content isn't accessible to document, because the global document is on a different page - the page containing the iframes, but not their contents. Moreover, document.querySelectorAll(!'#content') is not a valid selector string - that will be interpreted as document.querySelectorAll(false) because ! of a non-empty string returns false.
You're going to have a hard time getting access to the contents of an iframe, just in general. Most browsers, like Chrome, won't event load the contents of an iframe if X-Frame-Options is set to SAMEORIGIN, which, for youtube, it certainly is.
Supposing you're getting around this (with a reverse proxy, perhaps?), you can get the contents of an iframe using JavaScript like so:
iframe.contentWindow.document
You can then use querySelector and friends on the iframe:
iframeDocument.querySelector('#content')
And if you want to cut out a node, you should remove() it:
iframeDocument.querySelector('#content').remove()
Now, having said all of that:
Don't do this.
You're abusing iframes, which requires some very creative (read: brittle, hacky) code, and Youtube certainly has a public API from which you can get access to someone's Youtube feed - and in a way that Youtube is far less likely to block by tightening security, or even by accident. (Suppose the HTML on their page changes, so #content contains everything. Or suppose they decide to check that the correct origin is requesting the page with JavaScript, and block you.)
What you want, you should use Youtube's API for.

Categories