Repository: qutebrowser/qutebrowser

Issue:
Whitelist for host block lists
Is it possible to unblock a blocked host?



Discussion:
Unfortunately not easily - are you talking about a permanent unblocking or a temporary override?

What host are you having trouble with? If it's something legitimate, it might make sense to get the author of the block list to unblock it as well.

For temporary unblocking, see #273.

But I agree there should be some kind of whitelist as well.

It is to permanently unblock sumome.com 

That's on multiple blocklists:

```
$  python3 scripts/hostblock_blame.py sumome.com
config path: /home/florian/.config/qutebrowser/qutebrowser.conf
checking http://www.malwaredomainlist.com/hostslist/hosts.txt...
checking http://someonewhocares.org/hosts/hosts...
FOUND sumome.com in http://someonewhocares.org/hosts/hosts:
    127.0.0.1 load.sumome.com
FOUND sumome.com in http://someonewhocares.org/hosts/hosts:
    127.0.0.1 sumome.com
checking http://winhelp2002.mvps.org/hosts.zip...
FOUND sumome.com in http://winhelp2002.mvps.org/hosts.zip:
    0.0.0.0 sumome.com
FOUND sumome.com in http://winhelp2002.mvps.org/hosts.zip:
    0.0.0.0 load.sumome.com
checking http://malwaredomains.lehigh.edu/files/justdomains.zip...
checking http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext...
```

So I think a whitelist would be the right approach here. I'll rename the issue and tag it as "easy", as it should be relatively simple to add that feature - contributions would be very welcome, as I'm drowning in work currently!


Resolving patch:
diff --git a/qutebrowser/browser/network/networkmanager.py b/qutebrowser/browser/network/networkmanager.py
--- a/qutebrowser/browser/network/networkmanager.py
+++ b/qutebrowser/browser/network/networkmanager.py
@@ -20,6 +20,7 @@
 """Our own QNetworkAccessManager."""
 
 import collections
+import fnmatch
 
 from PyQt5.QtCore import (pyqtSlot, pyqtSignal, PYQT_VERSION, QCoreApplication,
                           QUrl, QByteArray)
@@ -49,6 +50,22 @@ def init():
         QSslSocket.setDefaultCiphers(good_ciphers)
 
 
+def is_whitelisted_domain(host):
+    """Check if the given host is on the adblock whitelist.
+
+    Args:
+        host: The host of the request as string.
+    """
+    whitelist = config.get('content', 'host-blocking-whitelist')
+    if whitelist is None:
+        return False
+
+    for pattern in whitelist:
+        if fnmatch.fnmatch(host, pattern.lower()):
+            return True
+    return False
+
+
 class SslError(QSslError):
 
     """A QSslError subclass which provides __hash__ on Qt < 5.4."""
@@ -347,7 +364,8 @@ def createRequest(self, op, req, outgoing_data):
         host_blocker = objreg.get('host-blocker')
         if (op == QNetworkAccessManager.GetOperation and
                 req.url().host() in host_blocker.blocked_hosts and
-                config.get('content', 'host-blocking-enabled')):
+                config.get('content', 'host-blocking-enabled') and
+                not is_whitelisted_domain(req.url().host())):
             log.webview.info("Request to {} blocked by host blocker.".format(
                 req.url().host()))
             return networkreply.ErrorNetworkReply(
diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py
--- a/qutebrowser/config/configdata.py
+++ b/qutebrowser/config/configdata.py
@@ -735,6 +735,14 @@ def data(readonly=False):
              SettingValue(typ.Bool(), 'true'),
              "Whether host blocking is enabled."),
 
+            ('host-blocking-whitelist',
+             SettingValue(typ.List(none_ok=True), ''),
+             "List of domains that should always be loaded, despite being "
+             "ad-blocked.\n\n"
+             "Domains may contain * and ? wildcards and are otherwise "
+             "required to exactly match the requested domain.\n\n"
+             "Local domains are always exempt from hostblocking."),
+
             readonly=readonly
         )),
 


Test patch: