5

I wrote the following Greasemonkey script to prevent myself from accessing a few web apps (web sites), usually these I feel a bit addicted to. This is the closest I got to prevent my Browsers to display these sites:

// ==UserScript==
// @name        blocko
// @include     *
// ==/UserScript==

window.addEventListener('load', function() {
    let sites = ['example-1.com', 'example-2.com', 'example-3.com'];
    let dotTLD_andAllAfterIt = /\..+/;
    let href = window.location.href;
    for (let i = 0; i < sites.length; i++) {
        if (href.includes(sites[i])) {
            let domain = sites[i].replace(dotTLD_andAllAfterIt, '');
            document.body.innerHTML =`
                <div style="direction: ltr; position: fixed; top: 0; z-index: 999999; display: block; width: 100%; height: 100%; background: red">
                  <p style="position: relative; top: 40%; display: block; font-size: 66px; font-weight: bold; color: #fff; margin: 0 auto; text-align: center">
                    Enough with this ${domain} bullshit!
                  </p>
                </div>
          `;
        }
    }
}, true);

I'm not satisfied of my achievement here as this script gets me into the site and I need to wait 1/2/3/4 or even 5 or more seconds in rare cases, until the site will vanish and the message I print to the screen with red background will appear instead. Thus I'm unwillingly exposed to the site's content, from which I want to avoid.

I desire to prevent the browser from even navigating into a website, through JavaScript. There is a Chrome addon named "BlockSite" that helps with this and I tried to examine its (huge) source code but failed to understand how it prevents the user to be moved into a website, unlike my script above that moves the user to the website but vanishes the website with a message after a few seconds (after the load event was triggered).

Please share a way to totally prevent yourself of moving into a website, as with "BlockSite".

Osi
  • 1
  • 3
  • 9
  • 30
  • Are you going to make a browser plugin/extension or the script should be implemented inside a website? – sultan Mar 10 '18 at 14:05
  • Hello! I don't plan to create a browser extension. The functionality should work within the scope of a particular domain. – Osi Mar 10 '18 at 14:32
  • Edit `hosts` file to include something like `127.0.0.1 example-1.com`. A simple Google search ("edit hosts file to prevent access to website") could help. – Iván Nokonoko Mar 22 '18 at 12:00

4 Answers4

5

As a solution you can override onclick method of all links in your website. Then decide to let a user to follow the link or not.

const blackList = [`example-1.com`, `example-2.com`]

function onClick(event) {
  const href = this.href.match(/^(?:https?:)?(?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n]+)/i)
  if (!href) return
  const domain = href[1]
  if (blackList.includes(domain)) {
    event.stopPropagation()
    event.preventDefault()
    document.body.innerHTML =`
      <p>
        Enough with this ${domain} bullshit!
      </p>
    `;
  }
}

const elements = document.getElementsByTagName(`a`);
for(let element of elements) {
  element.onclick = onClick
}

.: UPDATE :.

Ok, let me explain the code above.

The code adds click listener to all links (<a href="...">...</a>) of your current page. When a user clicks the function above would be triggered.

const href = this.href.match - we extract from the href only domain part in order to compare does the url exist in our blackList or not -> if (blackList.includes(domain)).

this - refers to the link property href for more info check this article.

Here is a demo and here is the source code.

sultan
  • 4,543
  • 2
  • 24
  • 32
  • Must we use the regex? – Osi Mar 17 '18 at 11:03
  • Please consider adding some comments where you see fit. – Osi Mar 17 '18 at 13:23
  • 1
    @user9303970 ok, I have updated my answer with some explanations – sultan Mar 17 '18 at 14:33
  • 1
    Sultan, have you tested the code, I tried to test, to me it doesn't work... Also, do you agree to give a few words on the regex in a second update, maybe present it's different "contexts" or groups of matching characters by their context. – Osi Mar 23 '18 at 02:14
  • @user9303970 check it here https://codesandbox.io/s/6xmq2pnl2k https://6xmq2pnl2k.codesandbox.io/ – sultan Mar 23 '18 at 05:27
5

You need to wait so long as you are using a window load Event. You need to use DOMContentLoaded event instead. The difference is explained here on this answer.

It will work much faster if you change

window.addEventListener('load', function() {
   //Your Code
}, true);

To

document.addEventListener("DOMContentLoaded", function(event) {
   //Your Code
});

Lots of free extensions are available to block unwanted domains. Let me know if you want to build one for chrome, in that case I can further assist.

Update: Deleted following paragraph based on comments

But if you want to make your own extention then you need to be browser specific. As you need to write different extensions for different browsers.

Munim Munna
  • 17,178
  • 6
  • 29
  • 58
  • 1
    Your last paragraph isn't really true any more, since most major browsers (including Chrome, Firefox, and Edge, but unfortunately not Safari) support more or less the same cross-browser [WebExtension](https://developer.mozilla.org/en-US/Add-ons/WebExtensions) API. Conveniently, WebExtension [content scripts](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#Content_scripts) are also very similar to Greasemonkey / Tampermonkey user scripts, so that turning a user script into a stand-alone extension is fairly trivial (basically, just add a manifest.json file). – Ilmari Karonen Mar 21 '18 at 19:45
  • @IlmariKaronen I didn't know that, paragraph deleted. – Munim Munna Mar 21 '18 at 19:53
1

The best way to block a site from showing in your browser is to do it before it loads, using CSS. Something like this should do the job pretty well:

/* hide all child elements of <body> */
body > * {
  display: none !important;
}
/* just in case, hide text directly inside <body> too */
body {
  color: transparent !important;
  font-size: 0px !important;
}
/* inject an overlay to show a message and to cover up anything that might
   still somehow be visible after the styles above */
body::before {
  content: 'Enough with this BS!';
  display: block;
  width: 100%;
  height: 100%;
  position: fixed;
  z-index: 999999;
  text-align: center;
  font-size: 36pt;
  font-family: sans-serif;
  color: red;
  background: black;
}

With a user style extension like Stylus, you can just set the CSS above as a user style for all the domains you want to block. The extension will inject the user style to the page before it loads, completely preventing any content on the page from being even briefly visible.

Alternatively, you can also achieve a similar result by wrapping the style in a user script and injecting it to the page yourself. You can use the @run-at document-start header directive to make the user script run as early as possible, even before the page has loaded, again minimizing the risk of any actual page content showing even briefly:

// ==UserScript==
// @name        Enough with this BS
// @version     0.1
// @description Block any sites this script runs on with a rude message.
// @author      Ilmari Karonen
// @match       *://*.example.com/*
// @grant       none
// @run-at      document-start
// ==/UserScript==

var style = `
    /* hide all child elements of <body> */
    body > * {
      display: none !important;
    }
    /* just in case, hide text directly inside <body> too */
    body {
      color: transparent !important;
      font-size: 0px !important;
    }
    /* inject an overlay to show a message and to cover up anything that might
       still somehow be visible after the styles above */
    body::before {
      content: 'Enough with this ${location.hostname} BS!';
      display: block;
      width: 100%;
      height: 100%;
      position: fixed;
      z-index: 999999;
      text-align: center;
      font-size: 36pt;
      font-family: sans-serif;
      color: red;
      background: black;
    }`;

// Inject style into page
var styleElem = document.createElement( 'style' );
styleElem.type = 'text/css';
styleElem.textContent = style;
( document.head || document.documentElement ).appendChild( styleElem );

One advantage of this approach is that you can use JS to customize the style for each site, e.g. to include the name of the site in the message like above.

Note that the script above doesn't contain any regexps for matching the sites you want to block; instead, it uses @match expressions in the user script header to tell the user script manager to only run it on certain sites. (The example header above just blocks all content on example.com and any subdomains of it.)

One advantage of this is that it's more efficient that regexp matching, since the script won't run at all on any other pages; another is that most user script managers provide a UI for adding extra match and/or exclude patterns without having to edit the script directly.

(Also possibly worth noting is that I've embedded the style sheet in the JS code using an ES2015 template literal, since old-style JS strings cannot span multiple lines. The code highlighting here on SO doesn't seem to properly understand that syntax yet, which is why it looks a bit funny.)

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
1
  • Try this if want to stop: window.stop documentation (cannot stop the document in which it is contained from loading)
  • Try this if you want to prevent page reload/redirect link: onbeforeunload documentation (don't prevent loading automatically but allow a user to choose to follow the link or not)

    window.onbeforeunload = function(e) {
    
      var dialogText = 'Are you sure?';
    
       e.returnValue = dialogText;
    
       return dialogText;
    
    };
    
Alex Nikulin
  • 8,194
  • 4
  • 35
  • 37
  • This seems the best way, can you share a code to block the access to all sites in a given collection? – Osi Mar 26 '18 at 05:45
  • I re-comment, only because I really am not sure if you seen my comment. – Osi Mar 27 '18 at 01:10
  • I thumbed up your answer due to this seems to be a most promising approach. – Osi Mar 27 '18 at 01:10
  • thnx, I just not have enough time for a demo-answer)I edited my answer, probably my answer it is not very useful for you – Alex Nikulin Mar 27 '18 at 07:04