Sat, 12 Mar 2016 16:49:36 +0100
Continued porting the web browser.
- added cookies stuff
# -*- 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