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;
74 return !Token_.isEmpty () &&
75 (!ValidFor_ || ReceivedAt_.secsTo (QDateTime::currentDateTime ()) < ValidFor_);
80 return !Token_.isEmpty () || !Cookies_->allCookies ().isEmpty ();
85 const auto& newUrl = URLFromClientID (ID_, scope);
91 ReceivedAt_ = QDateTime ();
103 for (
const auto& queue : PrioManagedQueues_)
105 for (
const auto& queue : ManagedQueues_)
112 InvokeQueues (Token_);
119 iface.reportStarted ();
127 [
this, iface] ()
mutable { ReportFutureResult (iface, Token_); });
131 return iface.future ();
138 qWarning () << Q_FUNC_INFO
139 <<
"cannot manage request queue if queue manager wasn't set";
143 ManagedQueues_ << queue;
152 qWarning () << Q_FUNC_INFO
153 <<
"cannot manage request queue if queue manager wasn't set";
157 PrioManagedQueues_ << queue;
164 SilentMode_ = silent;
167 void VkAuthManager::InvokeQueues (
const QString& token)
169 ScheduleTrack (token);
171 for (
auto queue : PrioManagedQueues_)
172 while (!queue->isEmpty ())
174 const auto& pair = queue->takeFirst ();
175 const auto& f = pair.first;
176 Queue_->
Schedule ([f, token] { f (token); },
nullptr, pair.second);
179 for (
auto queue : ManagedQueues_)
180 while (!queue->isEmpty ())
182 const auto& f = queue->takeFirst ();
183 Queue_->
Schedule ([f, token] { f (token); });
187 void VkAuthManager::RequestURL (
const QUrl& url)
189 qDebug () << Q_FUNC_INFO << url;
190 auto reply = AuthNAM_->get (QNetworkRequest (url));
192 &QNetworkReply::finished,
194 [
this, reply] { HandleGotForm (reply); });
197 void VkAuthManager::RequestAuthKey ()
199 if (IsRequestScheduled_ && ScheduleTimer_->isActive ())
200 ScheduleTimer_->stop ();
206 IsRequesting_ =
true;
209 bool VkAuthManager::CheckReply (QUrl location)
211 if (location.path () !=
"/blank.html"_ql)
212 return CheckError (location);
214 location = QUrl::fromEncoded (location.toEncoded ().replace (
'#',
'?'));
215 const QUrlQuery query { location };
216 Token_ = query.queryItemValue (QStringLiteral (
"access_token"));
217 ValidFor_ = query.queryItemValue (QStringLiteral (
"expires_in")).toInt ();
218 ReceivedAt_ = QDateTime::currentDateTime ();
219 qDebug () << Q_FUNC_INFO << Token_ << ValidFor_;
220 IsRequesting_ =
false;
222 InvokeQueues (Token_);
229 bool VkAuthManager::CheckError (
const QUrl& url)
231 if (url.path () !=
"/error"_ql)
234 const auto errNum = QUrlQuery { url }.queryItemValue (QStringLiteral (
"err")).toInt ();
236 IsRequesting_ =
false;
238 qWarning () << Q_FUNC_INFO
250 tr (
"VK.com authentication for %1 failed because of error %2. "
251 "Report upstream please.")
255 Proxy_->GetEntityManager ()->HandleEntity (e);
260 void VkAuthManager::ScheduleTrack (
const QString& key)
265 if (!Proxy_->GetSettingsManager ()->property (
"TrackVK").toBool ())
270 QUrl url { QStringLiteral (
"https://api.vk.com/method/stats.trackVisitor") };
271 Util::UrlOperator { url }
272 (QStringLiteral (
"access_token"), key);
274 auto reply = AuthNAM_->get (QNetworkRequest { url });
276 &QNetworkReply::finished,
278 &QNetworkReply::deleteLater);
285 ReceivedAt_ = QDateTime ();
292 class CloseEventFilter :
public QObject
296 CloseEventFilter (
const F& handler, QObject *handlee)
297 : QObject { handlee }
298 , Handler_ { handler }
300 handlee->installEventFilter (
this);
303 bool eventFilter (QObject*, QEvent *event)
override
305 if (event->type () == QEvent::Close)
314 const auto& browsers = Proxy_->GetPluginsManager ()->GetAllCastableTo<
IWebBrowser*> ();
315 if (browsers.isEmpty ())
318 tr (
"Could not authenticate %1 since authentication requires a browser plugin. "
319 "Consider installing one like Poshuku.")
322 Proxy_->GetEntityManager ()->HandleEntity (e);
327 auto view = browsers.value (0)->GetWidget ();
328 auto viewWidget = view->GetQWidget ();
329 viewWidget->setWindowTitle (tr (
"VK.com authentication for %1")
331 viewWidget->setWindowFlags (Qt::Window);
332 viewWidget->resize (800, 600);
337 SIGNAL (urlChanged (
const QUrl&)),
339 SLOT (handleUrlChanged (
const QUrl&)));
341 new CloseEventFilter { [
this] { emit
authCanceled (); }, viewWidget };
344 void VkAuthManager::HandleGotForm (QNetworkReply *reply)
346 reply->deleteLater ();
348 if (reply->error () != QNetworkReply::NoError &&
349 reply->error () != QNetworkReply::AuthenticationRequiredError)
351 qWarning () << Q_FUNC_INFO
353 << reply->errorString ();
355 IsRequesting_ =
false;
357 if (!IsRequestScheduled_)
359 IsRequestScheduled_ =
true;
360 ScheduleTimer_->start (30000);
366 const auto& location = reply->header (QNetworkRequest::LocationHeader).toUrl ();
367 if (location.isEmpty ())
373 if (CheckReply (location))
376 RequestURL (location);
379 void VkAuthManager::handleUrlChanged (
const QUrl& url)
381 if (!CheckReply (url))
385 sender ()->deleteLater ();
Base class for plugins that provide a web browser.
A customized cookie jar with additional features.
void Load(const QByteArray &data)
A simple scheduling manager for a queue of functors.
void Schedule(std::function< void()> functor, QObject *dependent=nullptr, QueuePriority prio=QueuePriority::Normal)
Adds the given functor.
ScheduleGuard_t ManageQueue(RequestQueue_ptr)
bool HadAuthentication() const
QFuture< AuthKeyResult_t > GetAuthKeyFuture()
bool IsAuthenticated() const
void UpdateScope(const QStringList &)
std::variant< SilentMode > AuthKeyError_t
void cookiesChanged(const QByteArray &)
void gotAuthKey(const QString &)
VkAuthManager(const QString &accountName, const QString &clientId, const QStringList &scope, const QByteArray &cookies, const ICoreProxy_ptr &, QueueManager *=nullptr, QObject *=nullptr)
Manipulates query part of an QUrl object.
std::shared_ptr< ICoreProxy > ICoreProxy_ptr
detail::ScopeGuard< F > MakeScopeGuard(const F &f)
Returns an object performing passed function on scope exit.
Entity MakeNotification(const QString &header, const QString &text, Priority priority)
An utility function to make a Entity with notification.