10 #include <QNetworkRequest>
11 #include <QNetworkReply>
12 #include <QNetworkCookie>
17 #include <QFutureInterface>
28 #include <xmlsettingsdialog/basesettingsmanager.h>
34 QUrl URLFromClientID (
const QString&
id,
const QStringList& scope)
36 auto url = QUrl::fromEncoded (
"https://oauth.vk.com/authorize?redirect_uri=http%3A%2F%2Foauth.vk.com%2Fblank.html&response_type=token&state=");
38 (QStringLiteral (
"client_id"), id)
39 (QStringLiteral (
"scope"), scope.join (
','));
45 const QString&
id,
const QStringList& scope,
50 , AccountHR_ (accName)
51 , AuthNAM_ (
new QNetworkAccessManager (
this))
55 , URL_ (URLFromClientID (ID_, scope))
56 , ScheduleTimer_ (
new QTimer (
this))
58 AuthNAM_->setCookieJar (Cookies_);
59 Cookies_->Load (cookies);
61 ScheduleTimer_->setSingleShot (
true);
62 connect (ScheduleTimer_,
67 IsRequestScheduled_ =
false;
76 return !Token_.isEmpty () &&
77 (!ValidFor_ || ReceivedAt_.secsTo (QDateTime::currentDateTime ()) < ValidFor_);
82 return !Token_.isEmpty () || !Cookies_->allCookies ().isEmpty ();
87 const auto& newUrl = URLFromClientID (ID_, scope);
93 ReceivedAt_ = QDateTime ();
105 for (
const auto& queue : PrioManagedQueues_)
107 for (
const auto& queue : ManagedQueues_)
114 InvokeQueues (Token_);
121 iface.reportStarted ();
129 [
this, iface] ()
mutable { ReportFutureResult (iface, Token_); });
133 return iface.future ();
140 qWarning () << Q_FUNC_INFO
141 <<
"cannot manage request queue if queue manager wasn't set";
145 ManagedQueues_ << queue;
154 qWarning () << Q_FUNC_INFO
155 <<
"cannot manage request queue if queue manager wasn't set";
159 PrioManagedQueues_ << queue;
166 SilentMode_ = silent;
169 void VkAuthManager::InvokeQueues (
const QString& token)
171 ScheduleTrack (token);
173 for (
auto queue : PrioManagedQueues_)
174 while (!queue->isEmpty ())
176 const auto& pair = queue->takeFirst ();
177 const auto&
f = pair.first;
178 Queue_->
Schedule ([
f, token] {
f (token); },
nullptr, pair.second);
181 for (
auto queue : ManagedQueues_)
182 while (!queue->isEmpty ())
184 const auto&
f = queue->takeFirst ();
189 void VkAuthManager::RequestURL (
const QUrl& url)
191 qDebug () << Q_FUNC_INFO << url;
192 auto reply = AuthNAM_->get (QNetworkRequest (url));
194 &QNetworkReply::finished,
196 [
this, reply] { HandleGotForm (reply); });
199 void VkAuthManager::RequestAuthKey ()
201 if (IsRequestScheduled_ && ScheduleTimer_->isActive ())
202 ScheduleTimer_->stop ();
208 IsRequesting_ =
true;
211 bool VkAuthManager::CheckReply (QUrl location)
213 if (location.path () !=
"/blank.html"_ql)
214 return CheckError (location);
216 location = QUrl::fromEncoded (location.toEncoded ().replace (
'#',
'?'));
217 const QUrlQuery query { location };
218 Token_ = query.queryItemValue (QStringLiteral (
"access_token"));
219 ValidFor_ = query.queryItemValue (QStringLiteral (
"expires_in")).toInt ();
220 ReceivedAt_ = QDateTime::currentDateTime ();
221 qDebug () << Q_FUNC_INFO << Token_ << ValidFor_;
222 IsRequesting_ =
false;
224 InvokeQueues (Token_);
231 bool VkAuthManager::CheckError (
const QUrl& url)
233 if (url.path () !=
"/error"_ql)
236 const auto errNum = QUrlQuery { url }.queryItemValue (QStringLiteral (
"err")).toInt ();
238 IsRequesting_ =
false;
240 qWarning () << Q_FUNC_INFO
252 tr (
"VK.com authentication for %1 failed because of error %2. "
253 "Report upstream please.")
257 Proxy_->GetEntityManager ()->HandleEntity (e);
262 void VkAuthManager::ScheduleTrack (
const QString& key)
267 if (!Proxy_->GetSettingsManager ()->property (
"TrackVK").toBool ())
272 QUrl url { QStringLiteral (
"https://api.vk.com/method/stats.trackVisitor") };
273 Util::UrlOperator { url }
274 (QStringLiteral (
"access_token"), key);
276 auto reply = AuthNAM_->get (QNetworkRequest { url });
278 &QNetworkReply::finished,
280 &QNetworkReply::deleteLater);
287 ReceivedAt_ = QDateTime ();
294 class CloseEventFilter :
public QObject
298 CloseEventFilter (
const F& handler, QObject *handlee)
299 : QObject { handlee }
300 , Handler_ { handler }
302 handlee->installEventFilter (
this);
305 bool eventFilter (QObject*, QEvent *event)
override
316 const auto& browsers = Proxy_->GetPluginsManager ()->GetAllCastableTo<
IWebBrowser*> ();
317 if (browsers.isEmpty ())
320 tr (
"Could not authenticate %1 since authentication requires a browser plugin. "
321 "Consider installing one like Poshuku.")
324 Proxy_->GetEntityManager ()->HandleEntity (e);
330 Browser_ = browsers.value (0)->CreateWidget ();
331 auto viewWidget = Browser_->GetQWidget ();
332 viewWidget->setWindowTitle (tr (
"VK.com authentication for %1")
335 viewWidget->resize (800, 600);
338 Browser_->Load (URL_);
340 SIGNAL (urlChanged (
const QUrl&)),
342 SLOT (handleUrlChanged (
const QUrl&)));
344 new CloseEventFilter { [
this] { emit
authCanceled (); }, viewWidget };
347 void VkAuthManager::HandleGotForm (QNetworkReply *reply)
349 reply->deleteLater ();
351 if (reply->error () != QNetworkReply::NoError &&
352 reply->error () != QNetworkReply::AuthenticationRequiredError)
354 qWarning () << Q_FUNC_INFO
356 << reply->errorString ();
358 IsRequesting_ =
false;
360 if (!IsRequestScheduled_)
362 IsRequestScheduled_ =
true;
363 ScheduleTimer_->start (30000);
369 const auto& location = reply->header (QNetworkRequest::LocationHeader).toUrl ();
370 if (location.isEmpty ())
376 if (CheckReply (location))
379 RequestURL (location);
382 void VkAuthManager::handleUrlChanged (
const QUrl& url)
384 if (!CheckReply (url))