File indexing completed on 2025-01-26 04:38:18

0001 /*
0002  * SPDX-FileCopyrightText: 2016 Riccardo Iaconelli <riccardo@kde.org>
0003  * SPDX-FileCopyrightText: 2018 Veluri Mithun <velurimithun38@gmail.com>
0004  *
0005  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006  *
0007  *
0008  */
0009 
0010 #include "googlejob.h"
0011 #include "googleauthenticationplugin_debug.h"
0012 #include "ruqola_debug.h"
0013 
0014 #include <QDesktopServices>
0015 #include <QFile>
0016 #include <QJsonDocument>
0017 #include <QJsonObject>
0018 #include <QNetworkAccessManager>
0019 #include <QNetworkReply>
0020 #include <QNetworkRequest>
0021 
0022 #include <o2/o0globals.h>
0023 #include <o2/o0settingsstore.h>
0024 #include <o2/o2google.h>
0025 
0026 GoogleJob::GoogleJob(QObject *parent)
0027     : QObject(parent)
0028 {
0029     mO2Google = new O2Google(this);
0030 
0031     getDataFromJson();
0032 
0033     mO2Google->setClientId(m_clientID);
0034     mO2Google->setClientSecret(m_clientSecret);
0035     mO2Google->setLocalPort(8888); // it is from redirect url(http://127.0.0.1:8888/)
0036     mO2Google->setRequestUrl(m_authUri); // Use the desktop login UI
0037     mO2Google->setScope(QStringLiteral("email"));
0038 
0039     // Create a store object for writing the received tokens
0040     O0SettingsStore *store = new O0SettingsStore(QLatin1String(O2_ENCRYPTION_KEY), this);
0041     store->setGroupKey(QStringLiteral("Google"));
0042     mO2Google->setStore(store);
0043 
0044     connect(mO2Google, &O2Google::linkedChanged, this, &GoogleJob::onLinkedChanged);
0045     connect(mO2Google, &O2Google::linkingFailed, this, [this]() {
0046         Q_EMIT linkingFailed();
0047     });
0048     connect(mO2Google, &O2Google::linkingSucceeded, this, &GoogleJob::onLinkingSucceeded);
0049     connect(mO2Google, &O2Google::openBrowser, this, &GoogleJob::onOpenBrowser);
0050     connect(mO2Google, &O2Google::closeBrowser, this, &GoogleJob::onCloseBrowser);
0051     connect(mO2Google, &O2Google::linkingSucceeded, this, &GoogleJob::OAuthLoginMethodParameter);
0052 }
0053 
0054 GoogleJob::~GoogleJob()
0055 {
0056 }
0057 
0058 void GoogleJob::getDataFromJson()
0059 {
0060     QFile f(QStringLiteral(":/client_secret.json"));
0061 
0062     QString val;
0063     if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
0064         val = QString::fromLatin1(f.readAll());
0065     } else {
0066         qCWarning(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG) << "Impossible to read client_secret.json";
0067         // TODO exit ?
0068         return;
0069     }
0070 
0071     //******github*******
0072     // 38a607244195a0d7af8 > clientID
0073     // bb617841568d7c1e0c0888f292cf69b7b11d327e3 > clientSecret
0074     // https://github.com/login/oauth/authorize
0075     // https://github.com/login/oauth/access_token
0076     const QJsonDocument document = QJsonDocument::fromJson(val.toUtf8());
0077     const QJsonObject object = document.object();
0078     const auto settingsObject = object[QStringLiteral("web")].toObject();
0079     const auto authUri(settingsObject[QStringLiteral("auth_uri")].toString());
0080     const auto clientID = settingsObject[QStringLiteral("client_id")].toString();
0081     const auto clientSecret(settingsObject[QStringLiteral("client_secret")].toString());
0082 
0083     m_clientID = clientID;
0084     m_clientSecret = clientSecret;
0085     m_authUri = authUri;
0086     m_tokenUri = QStringLiteral("https://accounts.google.com/o/oauth2/token");
0087 }
0088 
0089 void GoogleJob::doOAuth(O2::GrantFlow grantFlowType)
0090 {
0091     qCDebug(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG) << "Starting OAuth 2 with grant flow type: Authorization Grant Flow...";
0092     mO2Google->setGrantFlow(grantFlowType);
0093     mO2Google->unlink();
0094 
0095     // TODO: refresh the token if it is expired(not valid)
0096     validateToken();
0097     if (m_isValidToken) {
0098         OAuthLoginMethodParameter();
0099     } else {
0100         mO2Google->link();
0101     }
0102 }
0103 
0104 // currently not used
0105 void GoogleJob::validateToken()
0106 {
0107     if (!mO2Google->linked()) {
0108         qCWarning(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG) << "ERROR: Application is not linked!";
0109         Q_EMIT linkingFailed(QString());
0110         return;
0111     }
0112 
0113     const QString accessToken = mO2Google->token();
0114     QString debugUrlStr = QString(m_tokenUri).arg(accessToken);
0115     QNetworkRequest request = QNetworkRequest(QUrl(debugUrlStr));
0116     QNetworkAccessManager *mgr = new QNetworkAccessManager(this);
0117     QNetworkReply *reply = mgr->get(request);
0118     connect(reply, &QNetworkReply::finished, this, &GoogleJob::onFinished);
0119     qCDebug(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG) << QStringLiteral("Validating user token. Please wait...");
0120 }
0121 
0122 void GoogleJob::onOpenBrowser(const QUrl &url)
0123 {
0124     QDesktopServices::openUrl(url);
0125 }
0126 
0127 void GoogleJob::onCloseBrowser()
0128 {
0129     // TODO: close the browser
0130 }
0131 
0132 void GoogleJob::onLinkedChanged()
0133 {
0134     qCDebug(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG) << QStringLiteral("Link changed!");
0135 }
0136 
0137 void GoogleJob::onLinkingSucceeded()
0138 {
0139     O2Google *o1t = qobject_cast<O2Google *>(sender());
0140     if (!o1t || !o1t->linked()) {
0141         return;
0142     }
0143     m_accessToken = o1t->token();
0144     const QVariantMap extraTokens = o1t->extraTokens();
0145     if (!extraTokens.isEmpty()) {
0146         Q_EMIT extraTokensReady(extraTokens);
0147         qCDebug(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG) << QStringLiteral("Extra tokens in response:");
0148         foreach (const QString &key, extraTokens.keys()) {
0149             qCDebug(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG)
0150                 << key << QStringLiteral(":") << (extraTokens.value(key).toString().left(3) + QStringLiteral("..."));
0151         }
0152     }
0153 }
0154 
0155 // currently not used
0156 void GoogleJob::onFinished()
0157 {
0158     QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
0159     if (!reply) {
0160         qCWarning(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG) << "NULL reply!";
0161         Q_EMIT linkingFailed(QString());
0162         return;
0163     }
0164 
0165     reply->deleteLater();
0166     if (reply->error() != QNetworkReply::NoError) {
0167         qCWarning(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG) << QStringLiteral("Reply error:") << reply->error();
0168         qCWarning(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG) << QStringLiteral("Reason:") << reply->errorString();
0169         Q_EMIT linkingFailed(QString());
0170         return;
0171     }
0172 
0173     const QByteArray replyData = reply->readAll();
0174     bool valid = !replyData.contains("error");
0175     if (valid) {
0176         qCDebug(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG) << QStringLiteral("Token is valid");
0177         Q_EMIT linkingSucceeded();
0178         m_isValidToken = true;
0179     } else {
0180         qCDebug(RUQOLA_GOOGLEAUTHENTICATION_PLUGIN_LOG) << QStringLiteral("Token is invalid");
0181         // TODO
0182         Q_EMIT linkingFailed(QString());
0183     }
0184 }
0185 
0186 void GoogleJob::OAuthLoginMethodParameter()
0187 {
0188     Q_EMIT loginMethodCalled(m_accessToken, m_clientSecret);
0189 }
0190 
0191 #include "moc_googlejob.cpp"