31 #include <QNetworkRequest>
32 #include <QNetworkReply>
33 #include <QNetworkCookie>
39 #include <QFutureInterface>
48 #include <xmlsettingsdialog/basesettingsmanager.h>
58 QUrl URLFromClientID (
const QString&
id,
const QStringList& scope)
60 auto url = QUrl::fromEncoded (
"https://oauth.vk.com/authorize?redirect_uri=http%3A%2F%2Foauth.vk.com%2Fblank.html&response_type=token&state=");
63 (
"scope", scope.join (
","));
69 const QString&
id,
const QStringList& scope,
71 QueueManager *queueMgr, QObject *parent)
74 , AccountHR_ (accName)
75 , AuthNAM_ (new QNetworkAccessManager (this))
76 , Cookies_ (new Util::CustomCookieJar (this))
79 , URL_ (URLFromClientID (ID_, scope))
80 , ScheduleTimer_ (new QTimer (this))
82 AuthNAM_->setCookieJar (Cookies_);
83 Cookies_->Load (cookies);
85 ScheduleTimer_->setSingleShot (
true);
86 connect (ScheduleTimer_,
89 SLOT (execScheduledRequest ()));
92 bool VkAuthManager::IsAuthenticated ()
const
94 return !Token_.isEmpty () &&
95 (!ValidFor_ || ReceivedAt_.secsTo (QDateTime::currentDateTime ()) < ValidFor_);
98 bool VkAuthManager::HadAuthentication ()
const
100 return !Token_.isEmpty () || !Cookies_->allCookies ().isEmpty ();
103 void VkAuthManager::UpdateScope (
const QStringList& scope)
105 const auto& newUrl = URLFromClientID (ID_, scope);
111 ReceivedAt_ = QDateTime ();
115 void VkAuthManager::GetAuthKey ()
117 if (!IsAuthenticated ())
123 for (
const auto& queue : PrioManagedQueues_)
125 for (
const auto& queue : ManagedQueues_)
132 InvokeQueues (Token_);
133 emit gotAuthKey (Token_);
139 iface.reportStarted ();
141 if (SilentMode_ && !IsAuthenticated ())
142 ReportFutureResult (iface, AuthKeyError_t { SilentMode {} });
146 &VkAuthManager::gotAuthKey,
147 [
this, iface] ()
mutable { ReportFutureResult (iface, Token_); });
151 return iface.future ();
154 auto VkAuthManager::ManageQueue (VkAuthManager::RequestQueue_ptr queue) -> ScheduleGuard_t
158 qWarning () << Q_FUNC_INFO
159 <<
"cannot manage request queue if queue manager wasn't set";
163 ManagedQueues_ << queue;
168 auto VkAuthManager::ManageQueue (VkAuthManager::PrioRequestQueue_ptr queue) -> ScheduleGuard_t
172 qWarning () << Q_FUNC_INFO
173 <<
"cannot manage request queue if queue manager wasn't set";
177 PrioManagedQueues_ << queue;
182 void VkAuthManager::SetSilentMode (
bool silent)
184 SilentMode_ = silent;
187 void VkAuthManager::InvokeQueues (
const QString& token)
189 ScheduleTrack (token);
191 for (
auto queue : PrioManagedQueues_)
192 while (!queue->isEmpty ())
194 const auto& pair = queue->takeFirst ();
195 const auto&
f = pair.first;
196 Queue_->Schedule ([
f, token] {
f (token); },
nullptr, pair.second);
199 for (
auto queue : ManagedQueues_)
200 while (!queue->isEmpty ())
202 const auto&
f = queue->takeFirst ();
203 Queue_->Schedule ([
f, token] {
f (token); });
207 void VkAuthManager::RequestURL (
const QUrl& url)
209 qDebug () << Q_FUNC_INFO << url;
210 auto reply = AuthNAM_->get (QNetworkRequest (url));
212 SIGNAL (finished ()),
214 SLOT (handleGotForm ()));
217 void VkAuthManager::RequestAuthKey ()
219 if (IsRequestScheduled_ && ScheduleTimer_->isActive ())
220 ScheduleTimer_->stop ();
226 IsRequesting_ =
true;
229 bool VkAuthManager::CheckReply (QUrl location)
231 if (location.path () !=
"/blank.html")
232 return CheckError (location);
234 location = QUrl::fromEncoded (location.toEncoded ().replace (
'#',
'?'));
235 const QUrlQuery query { location };
236 Token_ = query.queryItemValue (
"access_token");
237 ValidFor_ = query.queryItemValue (
"expires_in").toInt ();
238 ReceivedAt_ = QDateTime::currentDateTime ();
239 qDebug () << Q_FUNC_INFO << Token_ << ValidFor_;
240 IsRequesting_ =
false;
242 InvokeQueues (Token_);
243 emit gotAuthKey (Token_);
244 emit justAuthenticated ();
249 bool VkAuthManager::CheckError (
const QUrl& url)
251 if (url.path () !=
"/error")
254 const auto errNum = QUrlQuery { url }.queryItemValue (
"err").toInt ();
256 IsRequesting_ =
false;
258 qWarning () << Q_FUNC_INFO
270 tr (
"VK.com authentication for %1 failed because of error %2. "
271 "Report upstream please.")
275 Proxy_->GetEntityManager ()->HandleEntity (e);
280 void VkAuthManager::ScheduleTrack (
const QString& key)
285 if (!Proxy_->GetSettingsManager ()->property (
"TrackVK").toBool ())
290 QUrl url {
"https://api.vk.com/method/stats.trackVisitor" };
292 (
"access_token", key);
294 auto reply = AuthNAM_->get (QNetworkRequest { url });
296 SIGNAL (finished ()),
298 SLOT (deleteLater ()));
301 void VkAuthManager::clearAuthData ()
305 ReceivedAt_ = QDateTime ();
312 class CloseEventFilter :
public QObject
316 CloseEventFilter (
const F& handler, QObject *handlee)
317 : QObject { handlee }
318 , Handler_ { handler }
320 handlee->installEventFilter (
this);
323 bool eventFilter (QObject*, QEvent *event)
332 void VkAuthManager::reauth ()
334 auto view =
new QWebView;
335 view->setWindowTitle (tr (
"VK.com authentication for %1")
338 view->resize (800, 600);
339 view->page ()->setNetworkAccessManager (AuthNAM_);
345 SIGNAL (urlChanged (QUrl)),
347 SLOT (handleViewUrlChanged (QUrl)));
349 new CloseEventFilter { [
this] { emit authCanceled (); }, view };
352 void VkAuthManager::execScheduledRequest ()
354 IsRequestScheduled_ =
false;
359 void VkAuthManager::handleGotForm ()
361 auto reply = qobject_cast<QNetworkReply*> (sender ());
362 reply->deleteLater ();
364 if (reply->error () != QNetworkReply::NoError)
366 qWarning () << Q_FUNC_INFO
368 << reply->errorString ();
370 IsRequesting_ =
false;
372 if (!IsRequestScheduled_)
374 IsRequestScheduled_ =
true;
375 ScheduleTimer_->start (30000);
381 const auto& location = reply->header (QNetworkRequest::LocationHeader).toUrl ();
382 if (location.isEmpty ())
388 if (CheckReply (location))
391 RequestURL (location);
394 void VkAuthManager::handleViewUrlChanged (
const QUrl& url)
396 if (!CheckReply (url))
399 emit cookiesChanged (Cookies_->Save ());
400 sender ()->deleteLater ();