File indexing completed on 2024-12-22 04:43:19
0001 /* 0002 This file is part of the KDE project. 0003 0004 SPDX-FileCopyrightText: 2018 Stefano Crocco <stefano.crocco@alice.it> 0005 0006 SPDX-License-Identifier: LGPL-2.1-or-later 0007 */ 0008 0009 #ifndef WEBENGINEPARTCOOKIEJAR_H 0010 #define WEBENGINEPARTCOOKIEJAR_H 0011 0012 #include "interfaces/cookiejar.h" 0013 #include "qtwebengine6compat.h" 0014 0015 #include <QObject> 0016 #include <QNetworkCookie> 0017 #include <QHash> 0018 #include <QUrl> 0019 #include <QWebEngineCookieStore> 0020 #include <QStringList> 0021 #include <QVariant> 0022 #include <QVector> 0023 #include <QDBusInterface> 0024 #include <QSet> 0025 0026 #include "kwebenginepartlib_export.h" 0027 0028 class QDebug; 0029 class QWidget; 0030 class QWebEngineProfile; 0031 class QDBusPendingCallWatcher; 0032 0033 /** 0034 * @brief Class which enforces the Cookie user settings and allows access to the cookies in the store 0035 * 0036 * @note All functions which access the cookie store are asynchronous 0037 */ 0038 class KWEBENGINEPARTLIB_EXPORT WebEnginePartCookieJar6 : public KonqInterfaces::CookieJar 0039 { 0040 Q_OBJECT 0041 0042 public: 0043 0044 /** 0045 * @brief Constructor 0046 * 0047 * @param [in,out] prof the profile containing the store to synchronize with 0048 * @param parent the parent object 0049 */ 0050 WebEnginePartCookieJar6(QWebEngineProfile* prof, QObject* parent = nullptr); 0051 0052 /** 0053 * @brief Destructor 0054 */ 0055 ~WebEnginePartCookieJar6() override; 0056 0057 /** 0058 * @brief A set with all cookies in the cookie store 0059 * @return a set with all cookies in the cookie store 0060 * @note This function is synchronous, as it doesn't access the store but returns the cookies already inserted in #m_cookies. 0061 * It is possible that a cookie has been added to the store but the store hasn't yet emitted the corresponding `cookieAdded()` 0062 * signal: in this case, that cookie won't be included in the returned value. 0063 */ 0064 QSet<QNetworkCookie> cookies() const override; 0065 0066 public slots: 0067 0068 /** 0069 * @brief Asks the store to remove all cookies 0070 * 0071 * @note This will also reset the choices made by the user for all cookies 0072 */ 0073 void removeAllCookies() override; 0074 0075 /** 0076 * @brief Asks the store to remove all cookies from a domain 0077 * @param domain the domain whose cookies should be removed. A leading dot is ignored 0078 * @note This will also reset the choices made by the user for the removed cookies 0079 */ 0080 void removeCookiesWithDomain(const QString &domain) override; 0081 0082 /** 0083 * @brief Asks the store to remove the given cookies 0084 * 0085 * If you need to remove multiple cookies, it's better to call this rather than 0086 * calling removeCookie() multiple times, as this will only update the cookie advice 0087 * file once (if needed) 0088 * @note This will also reset the choices made by the user for the removed cookies 0089 */ 0090 void removeCookies(const QVector<QNetworkCookie> & cookies) override; 0091 0092 /** 0093 * @brief Asks the store to remove the given cookie 0094 * @param cookie the cookie to remove 0095 * @param origin only remove the cookie if it originates from this URL 0096 * @note This will also reset the choices made by the user for the removed cookie 0097 */ 0098 void removeCookie(const QNetworkCookie &cookie, const QUrl &origin=QUrl()) override; 0099 0100 /** 0101 * @brief Asks the cookie store to remove all session cookies 0102 */ 0103 void removeSessionCookies() override; 0104 0105 private slots: 0106 0107 /** 0108 * @brief Read the cookie configuration settings from the configuration file 0109 * 0110 * If cookies have been disabled, the cookie store is emptied. All other 0111 * configuration changes won't be applied to cookies already in the store. 0112 * They will be applied next time the cookie jar is created (most likely, when 0113 * the application is next started). 0114 */ 0115 void applyConfiguration(); 0116 0117 /** 0118 * @brief Slot called in response to the `QWebEngineCookieStore::cookieAdded` signal 0119 * 0120 * It checks whether the policy chosen by the user allows accepting the cookie and 0121 * removes it if it doesn't. If, instead, the cookie can be accepted, it adds it 0122 * to #m_cookies. 0123 * @note Theoretically, most of what this method does should be done by filterCookie(). 0124 * Unfortunately, that function doesn't have access to the cookie details it would 0125 * need, so we need to do it here. This means that even cookies which should be rejected 0126 * are actually added and then removed. 0127 */ 0128 void handleCookieAdditionToStore(const QNetworkCookie &cookie); 0129 0130 /** 0131 * @brief Removes the given cookie from the list of cookies. 0132 * 0133 * This slot is called in response to `QWebEngineCookieStore::cookieRemoved` signal. 0134 * 0135 * @param cookie the cookie to remove 0136 */ 0137 void removeCookieFromSet(const QNetworkCookie &cookie); 0138 0139 /** 0140 * @brief The path of the file where to save the choices made by the user for single cookies 0141 * @return The path of the file where to save the choices made by the user for single cookies 0142 */ 0143 static QString cookieAdvicePath(); 0144 0145 static QString cookieDataPath(); 0146 0147 /** 0148 * @brief Saves to file the choices the user made for individual cookies 0149 */ 0150 void saveCookieAdvice(); 0151 0152 /** 0153 * @brief Reads from file the choices the user made for individual cookies 0154 */ 0155 void readCookieAdvice(); 0156 0157 void loadCookies(); 0158 0159 private: 0160 0161 /** 0162 * @brief An identifier for a cookie 0163 * 0164 * The identifier is made by the cookie's name, domain and path 0165 */ 0166 struct CookieIdentifier{ 0167 0168 /** 0169 * @brief Default constructor 0170 */ 0171 CookieIdentifier(){} 0172 0173 /** 0174 * @brief Constructor 0175 * 0176 * @param cookie the cookie to create the identifier for 0177 */ 0178 CookieIdentifier(const QNetworkCookie &cookie); 0179 0180 /** 0181 * @brief Constructor 0182 * 0183 * @param n the cookie's name 0184 * @param d the cookie's domain 0185 * @param p the cookie's path 0186 */ 0187 CookieIdentifier(const QString &n, const QString &d, const QString &p); 0188 0189 /** 0190 * Comparison operator 0191 * 0192 * Two cookies are equal if all their fields are equal 0193 * @param other the identifier to compare this identifier to 0194 * @return `true` if the two identifiers' name, domain and path are equal and `false` if at least one of them is different 0195 */ 0196 bool operator== (const CookieIdentifier &other) const {return name == other.name && domain == other.domain && path == other.path;} 0197 0198 QString name; ///< The name of the cookie 0199 QString domain; ///< The domain of the cookie 0200 QString path; ///< The path of the cookie 0201 0202 }; 0203 0204 /** 0205 * @brief Decides what to do with a cookie according to the policy chosen by the user 0206 * 0207 * This method compares the cookie with the settings in #m_policy and returns the appropriate action. 0208 * If needed, it calls askCookieQuestion() to ask the user what to do. 0209 * @param cookie the cookie 0210 * @return the CookieAdvice describing what to do with the cookie 0211 */ 0212 CookieAdvice decideCookieAction(const QNetworkCookie cookie); 0213 0214 /** 0215 * @brief Asks the user what to do with a given cookie 0216 * 0217 * It displays a dialog where the user can choose whether to accept the cookie, reject it or accept it 0218 * only for the current session. 0219 * 0220 * In the dialog, the user can also decide to apply his choice to all cookies or to the cookies from 0221 * the same domain. If he does, then the configuration file is changed accordingly. 0222 * @param cookie the cookie 0223 * @return what to do with the cookie 0224 */ 0225 CookieAdvice askCookieQuestion(const QNetworkCookie cookie); 0226 0227 /** 0228 * @brief Updates the policy in the configuration file 0229 * 0230 * This is only called if, when asked what to do about a cookie, the user chooses to apply its choice 0231 * to all cookies or to the cookies from the same domain. 0232 */ 0233 void writeConfig(); 0234 0235 friend QDebug operator<<(QDebug, const CookieIdentifier &); 0236 friend QDataStream& operator>>(QDataStream &ds, WebEnginePartCookieJar6::CookieIdentifier &id); 0237 friend QDataStream& operator<<(QDataStream &ds, const WebEnginePartCookieJar6::CookieIdentifier &id); 0238 0239 using CookieIdentifierList = QList<CookieIdentifier>; 0240 0241 /** 0242 * @brief Decides whether to accept or not a cookie 0243 * 0244 * In theory, this function should use the policy chosen by the user to decide whether to accept or reject the cookie. 0245 * However, to do so, it would need details about the cookie which aren't provided by @p req. Because of this, this 0246 * function only rejects the cookie in two circumstances: 0247 * - if cookies are completely disabled 0248 * - if it's a third party cookie and the policy forbids accepting third party cookies 0249 * In all other cases, this function accepts the cookie, leaving to handleCookieAdditionToStore() the task of removing 0250 * it if needed. 0251 * @note It's not clear whether accepting the cookie and then removing it has the same effect as rejecting it in the first 0252 * place. However, it's the best that can be done without reducing the range of policies the user can choose from. 0253 * 0254 * @param req the request to filter 0255 * @return `false` if cookies are disabled or if @p cookie is a third party cookie and third party cookies have been disabled 0256 * and `true` otherwise 0257 * @sa handleCookieAdditionToStore() 0258 */ 0259 bool filterCookie(const QWebEngineCookieStore::FilterRequest &req); 0260 0261 /** 0262 * @brief The `QWebEngineCookieStore` to use 0263 */ 0264 QWebEngineCookieStore* m_cookieStore; 0265 0266 /** 0267 * @brief Overload of `qHash` for a CookieIdentifier 0268 * 0269 * @param id: the other identifier 0270 * @param seed: the seed 0271 * @return The hash value of the identifier 0272 */ 0273 friend qHashReturnType qHash(const CookieIdentifier &id, uint seed){return qHash(QStringList{id.name, id.domain, id.path}, seed);}; 0274 0275 /** 0276 * @brief The cookies stored in #m_cookieStore 0277 * 0278 * This is needed to implement CookieJar::cookies(), since `QWebEngineCookieStore` doesn't allow to retrieve the list of 0279 * cookies. 0280 */ 0281 QSet<QNetworkCookie> m_cookies; 0282 0283 0284 /** 0285 * @brief Struct describing the cookie policy chosen by the user 0286 */ 0287 struct CookiePolicy { 0288 bool cookiesEnabled = true; ///< Whether cookies are enabled or should all be rejected 0289 bool rejectThirdPartyCookies = true; ///< Whether third party cookies should all be rejected 0290 bool acceptSessionCookies = true; ///< Whether session cookies should be accepted by default 0291 CookieAdvice defaultPolicy = CookieAdvice::Accept; ///< What to do for cookies which don't match any other rule 0292 /** 0293 * @brief What to do for cookies belonging to specific domains 0294 * 0295 * Each entry has the domain as key and the action to carry out for cookies of that domain as value 0296 */ 0297 QHash<QString, CookieAdvice> domainExceptions; 0298 /** 0299 * @brief What to do for specific cookies 0300 * 0301 * Each entry has the cookie identifier as key and the action as value 0302 */ 0303 QHash<CookieIdentifier, CookieAdvice> cookieExceptions; 0304 }; 0305 CookiePolicy m_policy; ///< The policy to apply to cookies 0306 }; 0307 0308 /** 0309 * @brief Overload of `qHash` for a `QNetworkCookie` 0310 * 0311 * @param cookie: the cookie 0312 * @param seed: the seed 0313 * @return The hash value of the cookie 0314 */ 0315 qHashReturnType qHash(const QNetworkCookie &cookie, uint seed); 0316 0317 /** 0318 * @brief Overload of operator `<<` to allow a WebEnginePartCookieJar6::CookieIdentifier to be written to a `QDebug` 0319 * 0320 * @param deb the debug object 0321 * @param id the identifier to write 0322 * @return the debug object 0323 */ 0324 QDebug operator<<(QDebug deb, const WebEnginePartCookieJar6::CookieIdentifier &id); 0325 0326 /** 0327 * @brief override of operator `>>` allowing to read a CookieIdentifier from a `QDataStream` 0328 * @param ds the `QDataStream` to read the CookieIdentifier from 0329 * @param id the CookieIdentifier to read to @p ds 0330 * @return @p ds 0331 */ 0332 QDataStream& operator>>( QDataStream &ds, WebEnginePartCookieJar6::CookieIdentifier &id); 0333 0334 /** 0335 * @brief override of operator `<<` allowing to write a CookieIdentifier to a `QDataStream` 0336 * @param ds the `QDataStream` to write the CookieIdentifier to 0337 * @param id the CookieIdentifier to write to @p ds 0338 * @return @p ds 0339 */ 0340 QDataStream& operator<< (QDataStream &ds, const WebEnginePartCookieJar6::CookieIdentifier &id); 0341 0342 QDataStream& operator<< (QDataStream &ds, const QNetworkCookie &cookie); 0343 QDataStream& operator>> (QDataStream &ds, QNetworkCookie &cookie); 0344 0345 #endif // WEBENGINEPARTCOOKIEJAR_H