WebBrowser/CookieJar/CookieJar.py

branch
QtWebEngine
changeset 4845
2d22ff71c005
parent 4631
5c1a96925da4
child 4886
b56735d36159
diff -r 69ee7965ba27 -r 2d22ff71c005 WebBrowser/CookieJar/CookieJar.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/CookieJar/CookieJar.py	Sat Mar 12 16:49:36 2016 +0100
@@ -0,0 +1,435 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a QNetworkCookieJar subclass with various accept policies.
+"""
+
+from __future__ import unicode_literals
+
+import os
+
+from PyQt5.QtCore import pyqtSignal, pyqtSlot, QSettings
+from PyQt5.QtNetwork import QNetworkCookieJar, QNetworkCookie
+
+from WebBrowser.WebBrowserWindow import WebBrowserWindow
+
+from Utilities.AutoSaver import AutoSaver
+import Utilities
+import Preferences
+
+
+class CookieJar(QNetworkCookieJar):
+    """
+    Class implementing a QNetworkCookieJar subclass with various accept
+    policies.
+    
+    @signal cookiesChanged() emitted after the cookies have been changed
+    """
+    cookiesChanged = pyqtSignal()
+    
+    AcceptAlways = 0
+    AcceptNever = 1
+    AcceptOnlyFromSitesNavigatedTo = 2
+    AcceptMax = 2
+
+    KeepUntilExpire = 0
+    KeepUntilExit = 1
+    KeepMax = 1
+    
+    Allow = 0
+    Block = 1
+    AllowForSession = 2
+    
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent object (QObject)
+        """
+        super(CookieJar, self).__init__(parent)
+        
+        self.__loaded = False
+        self.__acceptCookies = self.AcceptOnlyFromSitesNavigatedTo
+        self.__saveTimer = AutoSaver(self, self.__save)
+        
+        self.__cookies = []
+        
+        self.__cookiesFile = os.path.join(Utilities.getConfigDir(),
+                                          "web_browser", "cookies.ini")
+        self.__load()
+        
+        # TODO: Qt 5.6
+##        self.__store = WebBrowserWindow.webProfile.cookieStore()
+##        self.__store.cookieAdded.connect(self.__cookieAdded)
+##        self.__store.cookieRemoved.connect(self.__cookieRemoved)
+    
+    def close(self):
+        """
+        Public slot to close the cookie jar.
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        if self.__keepCookies == self.KeepUntilExit:
+            self.clear()
+        self.__saveTimer.saveIfNeccessary()
+    
+    def clear(self):
+        """
+        Public method to clear all cookies.
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        self.__cookies = []
+        # TODO: Qt 5.6
+##        self.__store.deleteAllCookies()
+        self.cookiesChanged.emit()
+    
+    def removeCookies(self, cookies):
+        """
+        Public method to remove a cookie.
+        
+        @param cookies list of cookies to be removed
+        @type list of QNetworkCookie
+        """
+        wasBlocked = self.blockSignals(True)
+        # TODO: Qt 5.6
+##        for cookie in cookies:
+##            self.__store.deleteCookie(cookie)
+        self.blockSignals(wasBlocked)
+        
+        self.cookiesChanged.emit()
+    
+    def __load(self):
+        """
+        Private method to load the cookies settings.
+        """
+        if self.__loaded:
+            return
+        
+        cookieSettings = QSettings(self.__cookiesFile, QSettings.IniFormat)
+        
+        # load exceptions
+        self.__exceptionsBlock = Preferences.toList(
+            cookieSettings.value("Exceptions/block"))
+        self.__exceptionsAllow = Preferences.toList(
+            cookieSettings.value("Exceptions/allow"))
+        self.__exceptionsAllowForSession = Preferences.toList(
+            cookieSettings.value("Exceptions/allowForSession"))
+        self.__exceptionsBlock.sort()
+        self.__exceptionsAllow.sort()
+        self.__exceptionsAllowForSession.sort()
+        
+        self.__acceptCookies = Preferences.getWebBrowser("AcceptCookies")
+        self.__keepCookies = Preferences.getWebBrowser("KeepCookiesUntil")
+        if self.__keepCookies == self.KeepUntilExit:
+            self.clear()
+        
+        self.__filterTrackingCookies = Preferences.toBool(
+            Preferences.getWebBrowser("FilterTrackingCookies"))
+        
+        self.__loaded = True
+        self.cookiesChanged.emit()
+    
+    def __save(self):
+        """
+        Private method to save the cookies settings.
+        """
+        if not self.__loaded:
+            return
+        
+        cookieSettings = QSettings(self.__cookiesFile, QSettings.IniFormat)
+        
+        cookieSettings.setValue("Exceptions/block", self.__exceptionsBlock)
+        cookieSettings.setValue("Exceptions/allow", self.__exceptionsAllow)
+        cookieSettings.setValue("Exceptions/allowForSession",
+                                self.__exceptionsAllowForSession)
+        
+        Preferences.setWebBrowser("AcceptCookies", self.__acceptCookies)
+        Preferences.setWebBrowser("KeepCookiesUntil", self.__keepCookies)
+        Preferences.setWebBrowser("FilterTrackingCookies",
+                                  self.__filterTrackingCookies)
+    
+    @pyqtSlot(QNetworkCookie)
+    def __cookieAdded(self, cookie):
+        """
+        Private slot handling the addition of a cookie.
+        
+        @param cookie cookie which was added
+        @type QNetworkCookie
+        """
+        if self.__rejectCookie(cookie, cookie.domain()):
+            # TODO: Qt 5.6
+##            self.__store.deleteCookie(cookie)
+            return
+        
+        self.__cookies.append(cookie)
+        self.cookiesChanged.emit()
+    
+    @pyqtSlot(QNetworkCookie)
+    def __cookieRemoved(self, cookie):
+        """
+        Private slot handling the removal of a cookie.
+        
+        @param cookie cookie which was removed
+        @type QNetworkCookie
+        """
+        if cookie in self.__cookies:
+            self.__cookies.remove(cookie)
+            self.cookiesChanged.emit()
+    
+    def __rejectCookie(self, cookie, cookieDomain):
+        """
+        Public method to test, if a cookie shall be rejected.
+        
+        @param cookie cookie to be tested
+        @type QNetworkCookie
+        @param cookieDomain domain of the cookie
+        @type str
+        @return flag indicating the cookie shall be rejected
+        @rtype bool
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        eBlock = self.__isOnDomainList(self.__exceptionsBlock, cookieDomain)
+        eAllow = not eBlock and \
+            self.__isOnDomainList(self.__exceptionsAllow, cookieDomain)
+        eAllowSession = not eBlock and \
+            not eAllow and \
+            self.__isOnDomainList(
+                self.__exceptionsAllowForSession, cookieDomain)
+        
+        if self.__acceptCookies == self.AcceptNever:
+            if not eAllow and not eAllowSession:
+                return True
+        
+        if self.__acceptCookies == self.AcceptAlways:
+            if eBlock:
+                return True
+        
+        if self.__acceptCookies == self.AcceptOnlyFromSitesNavigatedTo:
+            url = WebBrowserWindow.mainWindow().getWindow().currentBrowser()\
+                .url()
+            if url.isValid():
+                host = url.host()
+            else:
+                host = ""
+            if not self.__matchDomain(cookieDomain, host):
+                return True
+        
+        if self.__filterTrackingCookies and cookie.name().startsWith(b"__utm"):
+            return True
+        
+        return False
+    
+    def acceptPolicy(self):
+        """
+        Public method to get the accept policy.
+        
+        @return current accept policy
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        return self.__acceptCookies
+    
+    def setAcceptPolicy(self, policy):
+        """
+        Public method to set the accept policy.
+        
+        @param policy accept policy to be set
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        if policy > self.AcceptMax:
+            return
+        if policy == self.__acceptCookies:
+            return
+        
+        self.__acceptCookies = policy
+        self.__saveTimer.changeOccurred()
+    
+    def keepPolicy(self):
+        """
+        Public method to get the keep policy.
+        
+        @return keep policy
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        return self.__keepCookies
+    
+    def setKeepPolicy(self, policy):
+        """
+        Public method to set the keep policy.
+        
+        @param policy keep policy to be set
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        if policy > self.KeepMax:
+            return
+        if policy == self.__keepCookies:
+            return
+        
+        self.__keepCookies = policy
+        self.__saveTimer.changeOccurred()
+    
+    def blockedCookies(self):
+        """
+        Public method to return the list of blocked domains.
+        
+        @return list of blocked domains (list of strings)
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        return self.__exceptionsBlock
+    
+    def allowedCookies(self):
+        """
+        Public method to return the list of allowed domains.
+        
+        @return list of allowed domains (list of strings)
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        return self.__exceptionsAllow
+    
+    def allowForSessionCookies(self):
+        """
+        Public method to return the list of allowed session cookie domains.
+        
+        @return list of allowed session cookie domains (list of strings)
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        return self.__exceptionsAllowForSession
+    
+    def setBlockedCookies(self, list_):
+        """
+        Public method to set the list of blocked domains.
+        
+        @param list_ list of blocked domains (list of strings)
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        self.__exceptionsBlock = list_[:]
+        self.__exceptionsBlock.sort()
+        self.__saveTimer.changeOccurred()
+    
+    def setAllowedCookies(self, list_):
+        """
+        Public method to set the list of allowed domains.
+        
+        @param list_ list of allowed domains (list of strings)
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        self.__exceptionsAllow = list_[:]
+        self.__exceptionsAllow.sort()
+        self.__saveTimer.changeOccurred()
+    
+    def setAllowForSessionCookies(self, list_):
+        """
+        Public method to set the list of allowed session cookie domains.
+        
+        @param list_ list of allowed session cookie domains (list of strings)
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        self.__exceptionsAllowForSession = list_[:]
+        self.__exceptionsAllowForSession.sort()
+        self.__saveTimer.changeOccurred()
+    
+    def filterTrackingCookies(self):
+        """
+        Public method to get the filter tracking cookies flag.
+        
+        @return filter tracking cookies flag (boolean)
+        """
+        return self.__filterTrackingCookies
+    
+    def setFilterTrackingCookies(self, filterTrackingCookies):
+        """
+        Public method to set the filter tracking cookies flag.
+        
+        @param filterTrackingCookies filter tracking cookies flag (boolean)
+        """
+        self.__filterTrackingCookies = filterTrackingCookies
+    
+    def __isOnDomainList(self, rules, domain):
+        """
+        Private method to check, if either the rule matches the domain exactly
+        or the domain ends with ".rule".
+        
+        @param rules list of rules (list of strings)
+        @param domain domain name to check (string)
+        @return flag indicating a match (boolean)
+        """
+        for rule in rules:
+            if rule.startswith("."):
+                if domain.endswith(rule):
+                    return True
+                
+                withoutDot = rule[1:]
+                if domain == withoutDot:
+                    return True
+            else:
+                domainEnding = domain[-(len(rule) + 1):]
+                if domainEnding and \
+                   domainEnding[0] == "." and \
+                   domain.endswith(rule):
+                    return True
+                
+                if rule == domain:
+                    return True
+        
+        return False
+    
+    def __matchDomain(self, cookieDomain, siteDomain):
+        """
+        Private method to check, if a URLs host matches a cookie domain
+        according to RFC 6265.
+        
+        @param cookieDomain domain of the cookie
+        @type str
+        @param siteDomain domain or host of an URL
+        @type str
+        @return flag indicating a match
+        @rtype bool
+        """
+        if cookieDomain.startswith("."):
+            cookieDomain = cookieDomain[1:]
+        if siteDomain.startswith("."):
+            siteDomain = siteDomain[1:]
+        
+        if cookieDomain == siteDomain:
+            return True
+        
+        if not siteDomain.endswith(cookieDomain):
+            return False
+        
+        index = siteDomain.find(cookieDomain)
+        return index > 0 and siteDomain[index - 1] == "."
+    
+    def cookies(self):
+        """
+        Public method to get the cookies of the cookie jar.
+        
+        @return list of all cookies (list of QNetworkCookie)
+        """
+        return self.__cookies

eric ide

mercurial