LeechCraft 0.6.70-17609-g3dde4097dd
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
customcookiejar.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
9#include "customcookiejar.h"
10#include <set>
11#include <algorithm>
12#include <QNetworkCookie>
13#include <QtDebug>
14#include <QDateTime>
15#include <util/sll/util.h>
16
17namespace LC::Util
18{
20 : QNetworkCookieJar (parent)
21 {
22 }
23
25 {
26 FilterTrackingCookies_ = filter;
27 }
28
29 void CustomCookieJar::SetEnabled (bool enabled)
30 {
31 Enabled_ = enabled;
32 }
33
35 {
36 MatchDomainExactly_ = enabled;
37 }
38
40 {
41 WL_ = list;
42 }
43
45 {
46 BL_ = list;
47 }
48
49 QByteArray CustomCookieJar::Save () const
50 {
51 return Save (allCookies ());
52 }
53
54 QByteArray CustomCookieJar::Save (const QList<QNetworkCookie>& cookies)
55 {
56 QByteArray result;
57 for (const auto& cookie : cookies)
58 {
59 result += cookie.toRawForm ();
60 result += '\n';
61 }
62 return result;
63 }
64
65 namespace
66 {
67 bool IsExpired (const QNetworkCookie& cookie, const QDateTime& now)
68 {
69 return !cookie.isSessionCookie () && cookie.expirationDate () < now;
70 }
71 }
72
73 void CustomCookieJar::Load (const QByteArray& data)
74 {
76 QList<QNetworkCookie> filteredCookies;
77 for (const auto& ba : data.split ('\n'))
78 cookies << QNetworkCookie::parseCookies (ba);
79
80 const auto& now = QDateTime::currentDateTime ();
81 for (const auto& cookie : cookies)
82 {
83 if (FilterTrackingCookies_ &&
84 cookie.name ().startsWith ("__utm"))
85 continue;
86
87 if (IsExpired (cookie, now))
88 continue;
89
90 filteredCookies << cookie;
91 }
92 emit cookiesAdded (filteredCookies);
93 setAllCookies (filteredCookies);
94 }
95
97 {
98 const auto& cookies = allCookies ();
99
101 result.reserve (cookies.size ());
102
103 const auto& now = QDateTime::currentDateTime ();
104
105 QList<QNetworkCookie> removed;
106 for (const auto& cookie : cookies)
107 {
108 if (IsExpired (cookie, now))
109 {
110 removed << cookie;
111 continue;
112 }
113
114 if (result.contains (cookie))
115 continue;
116
117 result << cookie;
118 }
119 qDebug () << Q_FUNC_INFO << cookies.size () << result.size ();
120 setAllCookies (result);
121
122 if (!removed.isEmpty ())
123 emit cookiesRemoved (removed);
124 }
125
127 {
128 if (!Enabled_)
129 return {};
130
131 QList<QNetworkCookie> filtered;
132 for (const auto& cookie : QNetworkCookieJar::cookiesForUrl (url))
133 if (!filtered.contains (cookie))
134 filtered << cookie;
135 return filtered;
136 }
137
138 namespace
139 {
140 bool MatchDomain (const QString& rawDomain, const QString& rawCookieDomain)
141 {
142 auto normalize = [] (QStringView s)
143 {
144 return s.startsWith ('.') ? s.mid (1) : s;
145 };
146 const auto& domain = normalize (rawDomain);
147 const auto& cookieDomain = normalize (rawCookieDomain);
148
149 if (domain == cookieDomain)
150 return true;
151
152 const auto idx = domain.indexOf (cookieDomain);
153 return idx > 0 && domain.at (idx - 1) == '.';
154 }
155
156 bool Check (const QList<QRegularExpression>& list, const QString& str)
157 {
158 return std::any_of (list.begin (), list.end (),
159 [&str] (const auto& rx) { return str == rx.pattern () || rx.match (str).hasMatch (); });
160 }
161
162 struct CookiesDiff
163 {
164 QList<QNetworkCookie> Added_;
165 QList<QNetworkCookie> Removed_;
166 };
167
168 auto CookieToTuple (const QNetworkCookie& c)
169 {
170 return std::make_tuple (c.isHttpOnly (),
171 c.isSecure (),
172 c.isSessionCookie (),
173 c.name (),
174 c.domain (),
175 c.path (),
176 c.value (),
177 c.expirationDate ());
178 }
179
180 struct CookieLess
181 {
182 bool operator() (const QNetworkCookie& left, const QNetworkCookie& right) const
183 {
184 return CookieToTuple (left) < CookieToTuple (right);
185 }
186 };
187
188 CookiesDiff CheckDifferences (const QList<QNetworkCookie>& previousList,
189 const QList<QNetworkCookie>& currentList)
190 {
191 using Set_t = std::set<QNetworkCookie, CookieLess>;
192 const Set_t previous { previousList.begin (), previousList.end () };
193 const Set_t current { currentList.begin (), currentList.end () };
194
195 CookiesDiff diff;
196 std::set_difference (previous.begin (), previous.end (),
197 current.begin (), current.end (),
198 std::back_inserter (diff.Removed_),
199 CookieLess {});
200 std::set_difference (current.begin (), current.end (),
201 previous.begin (), previous.end (),
202 std::back_inserter (diff.Added_),
203 CookieLess {});
204 return diff;
205 }
206 }
207
208 bool CustomCookieJar::setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
209 {
210 if (!Enabled_)
211 return false;
212
213 QList<QNetworkCookie> filtered;
214 filtered.reserve (cookieList.size ());
215 for (auto cookie : cookieList)
216 {
217 if (cookie.domain ().isEmpty ())
218 cookie.setDomain (url.host ());
219
220 bool checkWhitelist = false;
221 const auto wlGuard = Util::MakeScopeGuard ([&]
222 {
223 if (checkWhitelist && Check (WL_, cookie.domain ()))
224 filtered << cookie;
225 });
226
227 if (MatchDomainExactly_ && !MatchDomain (url.host (), cookie.domain ()))
228 {
229 checkWhitelist = true;
230 continue;
231 }
232
233 if (FilterTrackingCookies_ &&
234 cookie.name ().startsWith ("__utm"))
235 {
236 checkWhitelist = true;
237 continue;
238 }
239
240 if (!Check (BL_, cookie.domain ()))
241 filtered << cookie;
242 }
243
244 const auto& existing = cookiesForUrl (url);
245 if (existing.isEmpty ())
246 emit cookiesAdded (filtered);
247 else
248 {
249 const auto& diff = CheckDifferences (existing, filtered);
250 if (!diff.Removed_.isEmpty ())
251 emit cookiesRemoved (diff.Removed_);
252 if (!diff.Added_.isEmpty ())
253 emit cookiesAdded (diff.Added_);
254 }
255
256 return QNetworkCookieJar::setCookiesFromUrl (filtered, url);
257 }
258}
detail::ScopeGuard< F > MakeScopeGuard(const F &f)
Returns an object performing passed function on scope exit.
Definition util.h:155