diff --git a/resources/binaries b/resources/binaries index 4a01edaec..ae7084718 160000 --- a/resources/binaries +++ b/resources/binaries @@ -1 +1 @@ -Subproject commit 4a01edaec7d67d3b2ae81aeea2a3c876216fbab8 +Subproject commit ae7084718c41afc01919779e58cd449e0eebd401 diff --git a/resources/graphics/misc/feedly.png b/resources/graphics/misc/feedly.png deleted file mode 100755 index c1a435bf7..000000000 Binary files a/resources/graphics/misc/feedly.png and /dev/null differ diff --git a/resources/rssguard.qrc b/resources/rssguard.qrc index 8afc998e6..ebe1079a2 100755 --- a/resources/rssguard.qrc +++ b/resources/rssguard.qrc @@ -9,7 +9,6 @@ graphics/rssguard_plain.png graphics/misc/adblock.png graphics/misc/adblock-disabled.png - graphics/misc/feedly.png graphics/misc/gmail.png graphics/misc/image-placeholder.png graphics/misc/inoreader.png diff --git a/rssguard.pro b/rssguard.pro index a79ca0e86..3baa022f2 100755 --- a/rssguard.pro +++ b/rssguard.pro @@ -563,11 +563,13 @@ equals(USE_WEBENGINE, true) { else { HEADERS += src/gui/messagepreviewer.h \ src/gui/messagetextbrowser.h \ - src/gui/newspaperpreviewer.h + src/gui/newspaperpreviewer.h \ + src/network-web/oauthhttphandler.h SOURCES += src/gui/messagepreviewer.cpp \ src/gui/messagetextbrowser.cpp \ - src/gui/newspaperpreviewer.cpp + src/gui/newspaperpreviewer.cpp \ + src/network-web/oauthhttphandler.cpp FORMS += src/gui/messagepreviewer.ui \ src/gui/newspaperpreviewer.ui diff --git a/src/gui/styleditemdelegatewithoutfocus.h b/src/gui/styleditemdelegatewithoutfocus.h index 153b81937..867e1e480 100755 --- a/src/gui/styleditemdelegatewithoutfocus.h +++ b/src/gui/styleditemdelegatewithoutfocus.h @@ -15,6 +15,20 @@ class StyledItemDelegateWithoutFocus : public QStyledItemDelegate { explicit StyledItemDelegateWithoutFocus(QObject* parent = 0); virtual ~StyledItemDelegateWithoutFocus(); + QSize sizeHint ( const QStyleOptionViewItem& option, const QModelIndex& index ) const + { + QSize siz = QStyledItemDelegate::sizeHint(option, index); + + /* QStyleOptionViewItem opt = option; + + initStyleOption(&opt, index); + QStyle* style = widget ? widget->style() : QApplication::style(); + + return style->sizeFromContents(QStyle::CT_ItemViewItem, &opt, QSize(), widget);*/ + + return siz; + } + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; }; diff --git a/src/network-web/oauth2service.cpp b/src/network-web/oauth2service.cpp index 8b96e86fb..d4f7a3209 100755 --- a/src/network-web/oauth2service.cpp +++ b/src/network-web/oauth2service.cpp @@ -26,10 +26,15 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" +#include "network-web/webfactory.h" #include "services/inoreader/definitions.h" #if defined(USE_WEBENGINE) #include "gui/dialogs/oauthlogin.h" +#else +#include "network-web/oauthhttphandler.h" + +Q_GLOBAL_STATIC(OAuthHttpHandler, qz_silent_acmanager) #endif #include @@ -38,21 +43,34 @@ #include #include -OAuth2Service::OAuth2Service(QString authUrl, QString tokenUrl, QString clientId, - QString clientSecret, QString scope, QObject* parent) +OAuth2Service::OAuth2Service(const QString& id_string, const QString& auth_url, const QString& token_url, const QString& client_id, + const QString& client_secret, const QString& scope, QObject* parent) : QObject(parent), m_timerId(-1), m_tokensExpireIn(QDateTime()) { + if (id_string.isEmpty()) { + m_id = "somerandomstring"; + } + else { + m_id = id_string; + } + m_redirectUrl = QSL(LOCALHOST_ADDRESS); m_tokenGrantType = QSL("authorization_code"); - m_tokenUrl = QUrl(tokenUrl); - m_authUrl = authUrl; + m_tokenUrl = QUrl(token_url); + m_authUrl = auth_url; - m_clientId = clientId; - m_clientSecret = clientSecret; + m_clientId = client_id; + m_clientSecret = client_secret; m_scope = scope; connect(&m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(tokenRequestFinished(QNetworkReply*))); - connect(this, &OAuth2Service::authCodeObtained, this, &OAuth2Service::retrieveAccessToken); + +#if !defined(USE_WEBENGINE) + connect(handler(), &OAuthHttpHandler::authGranted, this, &OAuth2Service::retrieveAccessToken); + connect(handler(), &OAuthHttpHandler::authRejected, [this](const QString& error_description) { + emit authFailed(); + }); +#endif } QString OAuth2Service::bearer() { @@ -105,6 +123,21 @@ void OAuth2Service::timerEvent(QTimerEvent* event) { QObject::timerEvent(event); } +QString OAuth2Service::id() const { + return m_id; +} + +void OAuth2Service::setId(const QString& id) { + m_id = id; +} + +#if !defined(USE_WEBENGINE) +OAuthHttpHandler* OAuth2Service::handler() { + return qz_silent_acmanager(); +} + +#endif + void OAuth2Service::retrieveAccessToken(QString auth_code) { QNetworkRequest networkRequest; @@ -155,7 +188,6 @@ void OAuth2Service::tokenRequestFinished(QNetworkReply* network_reply) { QByteArray repl = network_reply->readAll(); QJsonDocument json_document = QJsonDocument::fromJson(repl); QJsonObject root_obj = json_document.object(); - auto cod = network_reply->error(); qDebug() << "Token response:" << json_document.toJson(); @@ -276,15 +308,16 @@ void OAuth2Service::killRefreshTimer() { void OAuth2Service::retrieveAuthCode() { QString auth_url = m_authUrl + QString("?client_id=%1&scope=%2&" - "redirect_uri=%3&response_type=code&state=abcdef&" + "redirect_uri=%3&response_type=code&state=%4&" "prompt=consent&access_type=offline").arg(m_clientId, m_scope, - m_redirectUrl); + m_redirectUrl, + m_id); #if defined(USE_WEBENGINE) OAuthLogin login_page(qApp->mainFormWidget()); - connect(&login_page, &OAuthLogin::authGranted, this, &OAuth2Service::authCodeObtained); + connect(&login_page, &OAuthLogin::authGranted, this, &OAuth2Service::retrieveAccessToken); connect(&login_page, &OAuthLogin::authRejected, [this]() { logout(); emit authFailed(); @@ -295,7 +328,9 @@ void OAuth2Service::retrieveAuthCode() { QSystemTrayIcon::MessageIcon::Information); login_page.login(auth_url, m_redirectUrl); -#endif +#else - // TODO: For non-webengine version, user http-server and login via external browser. + // We run login URL in external browser, response is caught by light HTTP server. + qApp->web()->openUrlInExternalBrowser(auth_url); +#endif } diff --git a/src/network-web/oauth2service.h b/src/network-web/oauth2service.h index 7361edaad..382ce8c23 100755 --- a/src/network-web/oauth2service.h +++ b/src/network-web/oauth2service.h @@ -29,12 +29,16 @@ #include "network-web/silentnetworkaccessmanager.h" +#if !defined(USE_WEBENGINE) +#include "network-web/oauthhttphandler.h" +#endif + class OAuth2Service : public QObject { Q_OBJECT public: - explicit OAuth2Service(QString authUrl, QString tokenUrl, QString clientId, - QString clientSecret, QString scope, QObject* parent = 0); + explicit OAuth2Service(const QString& id_string, const QString& auth_url, const QString& token_url, + const QString& client_id, const QString& client_secret, const QString& scope, QObject* parent = 0); // Returns bearer HTTP header value. // NOTE: Only call this if isFullyLoggedIn() @@ -65,6 +69,9 @@ class OAuth2Service : public QObject { QString accessToken() const; void setAccessToken(const QString& access_token); + QString id() const; + void setId(const QString& id); + signals: void tokensReceived(QString access_token, QString refresh_token, int expires_in); void tokensRetrieveError(QString error, QString error_description); @@ -72,9 +79,6 @@ class OAuth2Service : public QObject { // User failed to authenticate or rejected it. void authFailed(); - // User enabled access. - void authCodeObtained(QString auth_code); - public slots: void retrieveAuthCode(); void retrieveAccessToken(QString auth_code); @@ -100,6 +104,7 @@ class OAuth2Service : public QObject { void timerEvent(QTimerEvent* event); private: + QString m_id; int m_timerId; QDateTime m_tokensExpireIn; QString m_accessToken; @@ -112,6 +117,12 @@ class OAuth2Service : public QObject { QString m_authUrl; QString m_scope; SilentNetworkAccessManager m_networkManager; + +#if !defined(USE_WEBENGINE) + + // Returns pointer to global silent network manager + static OAuthHttpHandler* handler(); +#endif }; #endif // OAUTH2SERVICE_H diff --git a/src/network-web/oauthhttphandler.cpp b/src/network-web/oauthhttphandler.cpp new file mode 100644 index 000000000..e6bd98049 --- /dev/null +++ b/src/network-web/oauthhttphandler.cpp @@ -0,0 +1,276 @@ +// For license of this file, see /LICENSE.md. + +#include "network-web/oauthhttphandler.h" + +#include "definitions/definitions.h" +#include "miscellaneous/application.h" + +#include + +#include +#include + +OAuthHttpHandler::OAuthHttpHandler(QObject* parent) : QObject(parent) { + m_text = tr("You can close this window now. Go back to %1").arg(APP_NAME); + + connect(&m_httpServer, &QTcpServer::newConnection, this, &OAuthHttpHandler::clientConnected); + + if (!m_httpServer.listen(m_listenAddress, 80)) { + qCritical("OAuth HTTP handler: Failed to start listening."); + } +} + +OAuthHttpHandler::~OAuthHttpHandler() { + if (m_httpServer.isListening()) { + m_httpServer.close(); + } +} + +void OAuthHttpHandler::clientConnected() { + QTcpSocket* socket = m_httpServer.nextPendingConnection(); + + QObject::connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater); + QObject::connect(socket, &QTcpSocket::readyRead, [this, socket]() { + readReceivedData(socket); + }); +} + +void OAuthHttpHandler::handleRedirection(const QVariantMap& data) { + if (data.isEmpty()) { + return; + } + + const QString error = data.value(QSL("error")).toString(); + const QString code = data.value(QSL("code")).toString(); + const QString received_state = data.value(QSL("state")).toString(); + + if (error.size()) { + const QString uri = data.value(QSL("error_uri")).toString(); + const QString description = data.value(QSL("error_description")).toString(); + + qWarning("OAuth HTTP handler: AuthenticationError: %s(%s): %s", qPrintable(error), qPrintable(uri), qPrintable(description)); + emit authRejected(description); + } + else if (code.isEmpty()) { + qWarning("OAuth HTTP handler: AuthenticationError: Code not received"); + emit authRejected(QSL("AuthenticationError: Code not received")); + } + else if (received_state.isEmpty()) { + qWarning("OAuth HTTP handler: State not received"); + emit authRejected(QSL("State not received")); + } + else { + emit authGranted(code); + } +} + +void OAuthHttpHandler::answerClient(QTcpSocket* socket, const QUrl& url) { + if (!url.path().remove(QL1C('/')).isEmpty()) { + qWarning("OAuth HTTP handler: Invalid request: %s", qPrintable(url.toString())); + } + else { + QVariantMap received_data; + const QUrlQuery query(url.query()); + const auto items = query.queryItems(); + + for (auto it = items.begin(), end = items.end(); it != end; ++it) { + received_data.insert(it->first, it->second); + } + + handleRedirection(received_data); + + const QByteArray html = QByteArrayLiteral("") + + qApp->applicationName().toUtf8() + + QByteArrayLiteral("") + + m_text.toUtf8() + + QByteArrayLiteral(""); + const QByteArray html_size = QString::number(html.size()).toUtf8(); + const QByteArray reply_message = QByteArrayLiteral("HTTP/1.0 200 OK \r\n" + "Content-Type: text/html; " + "charset=\"utf-8\"\r\n" + "Content-Length: ") + html_size + + QByteArrayLiteral("\r\n\r\n") + html; + + socket->write(reply_message); + } + + socket->disconnectFromHost(); +} + +void OAuthHttpHandler::readReceivedData(QTcpSocket* socket) { + if (!m_connectedClients.contains(socket)) { + m_connectedClients[socket].m_port = m_httpServer.serverPort(); + } + + QHttpRequest* request = &m_connectedClients[socket]; + bool error = false; + + if (Q_LIKELY(request->m_state == QHttpRequest::State::ReadingMethod)) { + if (Q_UNLIKELY(error = !request->readMethod(socket))) { + qWarning("OAuth HTTP handler: Invalid dethod"); + } + } + + if (Q_LIKELY(!error && request->m_state == QHttpRequest::State::ReadingUrl)) { + if (Q_UNLIKELY(error = !request->readUrl(socket))) { + qWarning("OAuth HTTP handler: Invalid URL"); + } + } + + if (Q_LIKELY(!error && request->m_state == QHttpRequest::State::ReadingStatus)) { + if (Q_UNLIKELY(error = !request->readStatus(socket))) { + qWarning("OAuth HTTP handler: Invalid status"); + } + } + + if (Q_LIKELY(!error && request->m_state == QHttpRequest::State::ReadingHeader)) { + if (Q_UNLIKELY(error = !request->readHeader(socket))) { + qWarning("OAuth HTTP handler: Invalid header"); + } + } + + if (error) { + socket->disconnectFromHost(); + m_connectedClients.remove(socket); + } + else if (!request->m_url.isEmpty()) { + Q_ASSERT(request->m_state != QHttpRequest::State::ReadingUrl); + + answerClient(socket, request->m_url); + m_connectedClients.remove(socket); + } +} + +bool OAuthHttpHandler::QHttpRequest::readMethod(QTcpSocket* socket) { + bool finished = false; + + while (socket->bytesAvailable() && !finished) { + const auto c = socket->read(1).at(0); + + if (std::isupper(c) && m_fragment.size() < 6) { + m_fragment += c; + } + else { + finished = true; + } + } + + if (finished) { + if (m_fragment == "HEAD") { + m_method = Method::Head; + } + else if (m_fragment == "GET") { + m_method = Method::Get; + } + else if (m_fragment == "PUT") { + m_method = Method::Put; + } + else if (m_fragment == "POST") { + m_method = Method::Post; + } + else if (m_fragment == "DELETE") { + m_method = Method::Delete; + } + else { + qWarning("OAuth HTTP handler: Invalid operation %s", m_fragment.data()); + } + + m_state = State::ReadingUrl; + m_fragment.clear(); + + return m_method != Method::Unknown; + } + + return true; +} + +bool OAuthHttpHandler::QHttpRequest::readUrl(QTcpSocket* socket) { + bool finished = false; + + while (socket->bytesAvailable() && !finished) { + const auto c = socket->read(1).at(0); + + if (std::isspace(c)) { + finished = true; + } + else { + m_fragment += c; + } + } + + if (finished) { + if (!m_fragment.startsWith("/")) { + qWarning("OAuth HTTP handler: Invalid URL path %s", m_fragment.constData()); + return false; + } + + m_url.setUrl(QStringLiteral("http://localhost:") + QString::number(m_port) + QString::fromUtf8(m_fragment)); + m_state = State::ReadingStatus; + + if (!m_url.isValid()) { + qWarning("OAuth HTTP handler: Invalid URL %s", m_fragment.constData()); + return false; + } + + m_fragment.clear(); + return true; + } + + return true; +} + +bool OAuthHttpHandler::QHttpRequest::readStatus(QTcpSocket* socket) { + bool finished = false; + + while (socket->bytesAvailable() && !finished) { + m_fragment += socket->read(1); + + if (m_fragment.endsWith("\r\n")) { + finished = true; + m_fragment.resize(m_fragment.size() - 2); + } + } + + if (finished) { + if (!std::isdigit(m_fragment.at(m_fragment.size() - 3)) || !std::isdigit(m_fragment.at(m_fragment.size() - 1))) { + qWarning("OAuth HTTP handler: Invalid version"); + return false; + } + + m_version = qMakePair(m_fragment.at(m_fragment.size() - 3) - '0', m_fragment.at(m_fragment.size() - 1) - '0'); + m_state = State::ReadingHeader; + m_fragment.clear(); + } + + return true; +} + +bool OAuthHttpHandler::QHttpRequest::readHeader(QTcpSocket* socket) { + while (socket->bytesAvailable()) { + m_fragment += socket->read(1); + + if (m_fragment.endsWith("\r\n")) { + if (m_fragment == "\r\n") { + m_state = State::ReadingBody; + m_fragment.clear(); + return true; + } + else { + m_fragment.chop(2); + const int index = m_fragment.indexOf(':'); + + if (index == -1) { + return false; + } + + const QByteArray key = m_fragment.mid(0, index).trimmed(); + const QByteArray value = m_fragment.mid(index + 1).trimmed(); + + m_headers.insert(key, value); + m_fragment.clear(); + } + } + } + + return false; +} diff --git a/src/network-web/oauthhttphandler.h b/src/network-web/oauthhttphandler.h new file mode 100644 index 000000000..9cdbe0f32 --- /dev/null +++ b/src/network-web/oauthhttphandler.h @@ -0,0 +1,69 @@ +// For license of this file, see /LICENSE.md. + +#ifndef OAUTHHTTPHANDLER_H +#define OAUTHHTTPHANDLER_H + +#include + +#include +#include + +class OAuthHttpHandler : public QObject { + Q_OBJECT + + public: + explicit OAuthHttpHandler(QObject* parent = nullptr); + virtual ~OAuthHttpHandler(); + + signals: + void authRejected(const QString& error_description); + void authGranted(const QString& auth_code); + + private slots: + void clientConnected(); + + private: + void handleRedirection(const QVariantMap& data); + void answerClient(QTcpSocket* socket, const QUrl& url); + void readReceivedData(QTcpSocket* socket); + + private: + struct QHttpRequest { + bool readMethod(QTcpSocket* socket); + bool readUrl(QTcpSocket* socket); + bool readStatus(QTcpSocket* socket); + bool readHeader(QTcpSocket* socket); + + enum class State { + ReadingMethod, + ReadingUrl, + ReadingStatus, + ReadingHeader, + ReadingBody, + AllDone + } m_state = State::ReadingMethod; + + enum class Method { + Unknown, + Head, + Get, + Put, + Post, + Delete, + } m_method = Method::Unknown; + + quint16 m_port = 0; + QByteArray m_fragment; + QUrl m_url; + + QPair m_version; + QMap m_headers; + }; + + QMap m_connectedClients; + QTcpServer m_httpServer; + QHostAddress m_listenAddress = QHostAddress::LocalHost; + QString m_text; +}; + +#endif // OAUTHHTTPHANDLER_H diff --git a/src/services/gmail/gmailentrypoint.cpp b/src/services/gmail/gmailentrypoint.cpp index cbf3e27bf..ac1182c57 100755 --- a/src/services/gmail/gmailentrypoint.cpp +++ b/src/services/gmail/gmailentrypoint.cpp @@ -13,16 +13,9 @@ #include ServiceRoot* GmailEntryPoint::createNewRoot() const { -#if defined(USE_WEBENGINE) FormEditGmailAccount form_acc(qApp->mainFormWidget()); return form_acc.execForCreate(); -#else - QMessageBox::warning(qApp->mainFormWidget(), - QObject::tr("Not supported"), - QObject::tr("This plugin is not supported in NonWebEngine variant of this program.")); - return nullptr; -#endif } QList GmailEntryPoint::initializeSubtree() const { diff --git a/src/services/gmail/gui/formeditgmailaccount.cpp b/src/services/gmail/gui/formeditgmailaccount.cpp index d602d369d..5d48eddff 100755 --- a/src/services/gmail/gui/formeditgmailaccount.cpp +++ b/src/services/gmail/gui/formeditgmailaccount.cpp @@ -10,7 +10,7 @@ #include "services/gmail/gmailserviceroot.h" FormEditGmailAccount::FormEditGmailAccount(QWidget* parent) : QDialog(parent), - m_oauth(new OAuth2Service(GMAIL_OAUTH_AUTH_URL, GMAIL_OAUTH_TOKEN_URL, + m_oauth(new OAuth2Service(QString(), GMAIL_OAUTH_AUTH_URL, GMAIL_OAUTH_TOKEN_URL, QString(), QString(), GMAIL_OAUTH_SCOPE)), m_editableRoot(nullptr) { m_ui.setupUi(this); diff --git a/src/services/gmail/network/gmailnetworkfactory.cpp b/src/services/gmail/network/gmailnetworkfactory.cpp index 4cf49a5c7..faab9a383 100755 --- a/src/services/gmail/network/gmailnetworkfactory.cpp +++ b/src/services/gmail/network/gmailnetworkfactory.cpp @@ -26,7 +26,7 @@ GmailNetworkFactory::GmailNetworkFactory(QObject* parent) : QObject(parent), m_service(nullptr), m_username(QString()), m_batchSize(GMAIL_DEFAULT_BATCH_SIZE), - m_oauth2(new OAuth2Service(GMAIL_OAUTH_AUTH_URL, GMAIL_OAUTH_TOKEN_URL, + m_oauth2(new OAuth2Service(QString(), GMAIL_OAUTH_AUTH_URL, GMAIL_OAUTH_TOKEN_URL, QString(), QString(), GMAIL_OAUTH_SCOPE)) { initializeOauth(); } @@ -328,7 +328,7 @@ void GmailNetworkFactory::markMessagesStarred(RootItem::Importance importance, c void GmailNetworkFactory::onTokensError(const QString& error, const QString& error_description) { Q_UNUSED(error) - qApp->showGuiMessage(tr("Inoreader: authentication error"), + qApp->showGuiMessage(tr("Gmail: authentication error"), tr("Click this to login again. Error is: '%1'").arg(error_description), QSystemTrayIcon::Critical, nullptr, false, @@ -338,7 +338,7 @@ void GmailNetworkFactory::onTokensError(const QString& error, const QString& err } void GmailNetworkFactory::onAuthFailed() { - qApp->showGuiMessage(tr("Inoreader: authorization denied"), + qApp->showGuiMessage(tr("Gmail: authorization denied"), tr("Click this to login again."), QSystemTrayIcon::Critical, nullptr, false, diff --git a/src/services/inoreader/gui/formeditinoreaderaccount.cpp b/src/services/inoreader/gui/formeditinoreaderaccount.cpp index a7f888524..6dd4e9593 100755 --- a/src/services/inoreader/gui/formeditinoreaderaccount.cpp +++ b/src/services/inoreader/gui/formeditinoreaderaccount.cpp @@ -10,7 +10,7 @@ #include "services/inoreader/inoreaderserviceroot.h" FormEditInoreaderAccount::FormEditInoreaderAccount(QWidget* parent) : QDialog(parent), - m_oauth(new OAuth2Service(INOREADER_OAUTH_AUTH_URL, INOREADER_OAUTH_TOKEN_URL, + m_oauth(new OAuth2Service(QString(), INOREADER_OAUTH_AUTH_URL, INOREADER_OAUTH_TOKEN_URL, INOREADER_OAUTH_CLI_ID, INOREADER_OAUTH_CLI_KEY, INOREADER_OAUTH_SCOPE)), m_editableRoot(nullptr) { m_ui.setupUi(this); diff --git a/src/services/inoreader/inoreaderentrypoint.cpp b/src/services/inoreader/inoreaderentrypoint.cpp index 8359c86d7..578e8fb32 100755 --- a/src/services/inoreader/inoreaderentrypoint.cpp +++ b/src/services/inoreader/inoreaderentrypoint.cpp @@ -14,16 +14,9 @@ #include ServiceRoot* InoreaderEntryPoint::createNewRoot() const { -#if defined(USE_WEBENGINE) FormEditInoreaderAccount form_acc(qApp->mainFormWidget()); return form_acc.execForCreate(); -#else - QMessageBox::warning(qApp->mainFormWidget(), - QObject::tr("Not supported"), - QObject::tr("This plugin is not supported in NonWebEngine variant of this program.")); - return nullptr; -#endif } QList InoreaderEntryPoint::initializeSubtree() const { diff --git a/src/services/inoreader/network/inoreadernetworkfactory.cpp b/src/services/inoreader/network/inoreadernetworkfactory.cpp index 61b1e09eb..08e9d4530 100755 --- a/src/services/inoreader/network/inoreadernetworkfactory.cpp +++ b/src/services/inoreader/network/inoreadernetworkfactory.cpp @@ -24,7 +24,7 @@ InoreaderNetworkFactory::InoreaderNetworkFactory(QObject* parent) : QObject(parent), m_service(nullptr), m_username(QString()), m_batchSize(INOREADER_DEFAULT_BATCH_SIZE), - m_oauth2(new OAuth2Service(INOREADER_OAUTH_AUTH_URL, INOREADER_OAUTH_TOKEN_URL, + m_oauth2(new OAuth2Service(QString(), INOREADER_OAUTH_AUTH_URL, INOREADER_OAUTH_TOKEN_URL, INOREADER_OAUTH_CLI_ID, INOREADER_OAUTH_CLI_KEY, INOREADER_OAUTH_SCOPE)) { initializeOauth(); }