LeechCraft  0.6.70-18450-gabe19ee3b0
Modular cross-platform feature rich live environment.
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 
17 namespace 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  {
75  QList<QNetworkCookie> cookies;
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 
100  QList<QNetworkCookie> result;
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  {
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 }
Task< CheckResult_t > Check(QString dbPath)
QList< QNetworkCookie > Removed_
detail::ScopeGuard< F > MakeScopeGuard(const F &f)
Returns an object performing passed function on scope exit.
Definition: util.h:155
QList< QNetworkCookie > Added_