// This file is part of RSS Guard. // // Copyright (C) 2011-2017 by Martin Rotter // // RSS Guard is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // RSS Guard is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with RSS Guard. If not, see . //////////////////////////////////////////////////////////////////////////////// // // // This file is part of QOAuth2. // // Copyright (c) 2014 Jacob Dawid // // // // QOAuth2 is free software: you can redistribute it and/or modify // // it under the terms of the GNU Affero General Public License as // // published by the Free Software Foundation, either version 3 of the // // License, or (at your option) any later version. // // // // QOAuth2 is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY; without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU Affero General Public License for more details. // // // // You should have received a copy of the GNU Affero General Public // // License along with QOAuth2. // // If not, see . // // // //////////////////////////////////////////////////////////////////////////////// #include "network-web/oauth2service.h" #include "definitions/definitions.h" #include "gui/dialogs/oauthlogin.h" #include "miscellaneous/application.h" #include "services/inoreader/definitions.h" #include #include #include #include #include OAuth2Service::OAuth2Service(QString authUrl, QString tokenUrl, QString clientId, QString clientSecret, QString scope, QObject* parent) : QObject(parent), m_tokensExpireIn(QDateTime()) { m_redirectUri = QSL(INOREADER_OAUTH_CLI_REDIRECT); m_tokenGrantType = QSL("authorization_code"); m_tokenUrl = QUrl(tokenUrl); m_authUrl = authUrl; m_clientId = clientId; m_clientSecret = clientSecret; m_scope = scope; connect(&m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(tokenRequestFinished(QNetworkReply*))); connect(this, &OAuth2Service::authCodeObtained, this, &OAuth2Service::retrieveAccessToken); } QString OAuth2Service::bearer() const { return QString("Bearer %1").arg(m_accessToken); } void OAuth2Service::attachBearerHeader(QNetworkRequest& req) { req.setRawHeader(QString("Authorization").toLocal8Bit(), bearer().toLocal8Bit()); } void OAuth2Service::setOAuthTokenGrantType(QString grant_type) { m_tokenGrantType = grant_type; } QString OAuth2Service::oAuthTokenGrantType() { return m_tokenGrantType; } void OAuth2Service::retrieveAccessToken(QString auth_code) { QNetworkRequest networkRequest; networkRequest.setUrl(m_tokenUrl); networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); QString content = QString("client_id=%1&" "client_secret=%2&" "code=%3&" "redirect_uri=%5&" "grant_type=%4") .arg(m_clientId) .arg(m_clientSecret) .arg(auth_code) .arg(m_tokenGrantType) .arg(m_redirectUri); m_networkManager.post(networkRequest, content.toUtf8()); } void OAuth2Service::refreshAccessToken(QString refresh_token) { if (refresh_token.isEmpty()) { refresh_token = m_refreshToken; } QNetworkRequest networkRequest; networkRequest.setUrl(m_tokenUrl); networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); QString content = QString("client_id=%1&" "client_secret=%2&" "refresh_token=%3&" "grant_type=%4") .arg(m_clientId) .arg(m_clientSecret) .arg(refresh_token) .arg("refresh_token"); m_networkManager.post(networkRequest, content.toUtf8()); } void OAuth2Service::cleanTokens() { m_refreshToken = m_accessToken = QString(); } void OAuth2Service::tokenRequestFinished(QNetworkReply* networkReply) { QJsonDocument jsonDocument = QJsonDocument::fromJson(networkReply->readAll()); QJsonObject rootObject = jsonDocument.object(); qDebug() << "Token response:"; qDebug() << jsonDocument.toJson(); if (rootObject.keys().contains("error")) { QString error = rootObject.value("error").toString(); QString error_description = rootObject.value("error_description").toString(); cleanTokens(); login(); emit tokensRetrieveError(error, error_description); } else { int expires = rootObject.value(QL1S("expires_in")).toInt(); m_accessToken = rootObject.value(QL1S("access_token")).toString(); m_refreshToken = rootObject.value(QL1S("refresh_token")).toString(); m_tokensExpireIn = QDateTime::currentDateTime().addSecs(expires); qDebug() << "Obtained refresh token" << m_refreshToken << "- expires on date/time" << m_tokensExpireIn; // TODO: Start timer to refresh tokens? emit tokensReceived(m_accessToken, m_refreshToken, rootObject.value("expires_in").toInt()); } networkReply->deleteLater(); } QString OAuth2Service::accessToken() const { return m_accessToken; } void OAuth2Service::setAccessToken(const QString& access_token) { m_accessToken = access_token; } QDateTime OAuth2Service::tokensExpireIn() const { return m_tokensExpireIn; } void OAuth2Service::setTokensExpireIn(const QDateTime& tokens_expire_in) { m_tokensExpireIn = tokens_expire_in; } QString OAuth2Service::clientSecret() const { return m_clientSecret; } void OAuth2Service::setClientSecret(const QString& client_secret) { m_clientSecret = client_secret; } QString OAuth2Service::clientId() const { return m_clientId; } void OAuth2Service::setClientId(const QString& client_id) { m_clientId = client_id; } QString OAuth2Service::redirectUri() const { return m_redirectUri; } void OAuth2Service::setRedirectUri(const QString& redirect_uri) { m_redirectUri = redirect_uri; } QString OAuth2Service::refreshToken() const { return m_refreshToken; } void OAuth2Service::setRefreshToken(const QString& refresh_token) { m_refreshToken = refresh_token; } bool OAuth2Service::login() { bool did_token_expire = m_tokensExpireIn.isNull() || m_tokensExpireIn < QDateTime::currentDateTime(); bool does_token_exist = !m_refreshToken.isEmpty(); // We refresh current tokens only if: // 1. We have some existing refresh token. // AND // 2. We do not know its expiration date or it passed. if (does_token_exist && did_token_expire) { refreshAccessToken(); return false; } else if (!does_token_exist) { retrieveAuthCode(); return false; } else { return true; } } void OAuth2Service::logout() { m_refreshToken = m_accessToken = QString(); m_tokensExpireIn = QDateTime(); // TODO: zastavit timer na obnovení refresh tokenu? } void OAuth2Service::retrieveAuthCode() { QString auth_url = m_authUrl + QString("?client_id=%1&scope=%2&" "redirect_uri=%3&response_type=code&state=abcdef").arg(m_clientId, m_scope, m_redirectUri); OAuthLogin login_page(qApp->mainFormWidget()); connect(&login_page, &OAuthLogin::authGranted, this, &OAuth2Service::authCodeObtained); connect(&login_page, &OAuthLogin::authRejected, [this]() { cleanTokens(); emit authFailed(); }); login_page.login(auth_url, m_redirectUri); }