File indexing completed on 2026-05-17 12:33:23

0001 /*
0002    SPDX-FileCopyrightText: 2023-2024 Laurent Montel <montel.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "githubauthenticationjob.h"
0008 #include "githubauthenticationplugin_debug.h"
0009 #include "githubauthenticationsettings.h"
0010 #include <QDesktopServices>
0011 #include <QOAuth2AuthorizationCodeFlow>
0012 #include <QOAuthHttpServerReplyHandler>
0013 #include <QTimer>
0014 
0015 GitHubAuthenticationJob::GitHubAuthenticationJob(QObject *parent)
0016     : QObject{parent}
0017     , mOAuth2(new QOAuth2AuthorizationCodeFlow(this))
0018 {
0019 }
0020 
0021 GitHubAuthenticationJob::~GitHubAuthenticationJob() = default;
0022 
0023 void GitHubAuthenticationJob::doRequest()
0024 {
0025     // TODO
0026 
0027     deleteLater();
0028 }
0029 
0030 GitHubAuthenticationJob::GitHubInfo GitHubAuthenticationJob::gitHubInfo() const
0031 {
0032     return mGitHubInfo;
0033 }
0034 
0035 void GitHubAuthenticationJob::setGitHubInfo(const GitHubInfo &newGitHubInfo)
0036 {
0037     mGitHubInfo = newGitHubInfo;
0038 }
0039 
0040 void GitHubAuthenticationJob::start()
0041 {
0042     if (!mGitHubInfo.isValid()) {
0043         qCWarning(RUQOLA_GITHUBAUTHENTICATION_PLUGIN_LOG) << "Lab info is invalid";
0044         deleteLater();
0045         return;
0046     }
0047 #if 0
0048     QString clientId = "CLIENT ID FROM API CREDENTIALS";
0049     QString authUri = "https://accounts.google.com/o/oauth2/auth";
0050     QString tokenUri = "https://accounts.google.com/o/oauth2/token";
0051     QStringList redirectUris;
0052     redirectUris << "http://127.0.0.1:54321/"; //ensure this is included in the API credentials under authorized URI
0053     QString redirectUri = redirectUris[0];
0054     QString clientSecret = "YOUR CLIENT SECRET FROM API CREDENTIALS";
0055     auto google = new QOAuth2AuthorizationCodeFlow(this);
0056     google->setScope("email");
0057     google->setAuthorizationUrl(authUri);
0058     google->setClientIdentifier(clientId);
0059     google->setAccessTokenUrl(tokenUri);
0060     google->setClientIdentifierSharedKey(clientSecret);
0061 
0062     // Use the same port number as above
0063     auto replyHandler = new QOAuthHttpServerReplyHandler(54321, this);
0064     google->setReplyHandler(replyHandler);
0065 
0066     // Set up the function to modify AND REPLACE the parameters
0067     google->setModifyParametersFunction([](QAbstractOAuth::Stage stage, QMultiMap<QString, QVariant>* parameters) {
0068         if (stage == QAbstractOAuth::Stage::RequestingAccessToken) {
0069             auto encodedCode = parameters->value("code").toByteArray();
0070             parameters->replace("code", QUrl::fromPercentEncoding(encodedCode));
0071         }
0072     });
0073 
0074     // Connect the signals to retrieve the tokens, if you want to see them
0075     connect(google, &QOAuth2AuthorizationCodeFlow::tokenChanged, [=](const QString &token)
0076     {
0077         qDebug() << "Token changed:" << token;
0078 
0079     });
0080     connect(replyHandler, &QOAuthHttpServerReplyHandler::tokensReceived, [](const QVariantMap &tokens)
0081     {
0082         qDebug() << "Tokens received:" << tokens;
0083     });
0084 
0085     connect(google, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, &QDesktopServices::openUrl);
0086 
0087     // Once you are granted access, make a request via the Google API
0088     connect(google, &QOAuth2AuthorizationCodeFlow::granted, [=]
0089     {
0090         qDebug() << "in the granted block now";
0091         // This block is run once you have logged into the browser successfully
0092 
0093         auto rep = google->get(QUrl("https://www.googleapis.com/oauth2/v1/userinfo?alt=json"));
0094         QEventLoop loop;
0095         connect(rep, &QNetworkReply::finished, &loop, &QEventLoop::quit);
0096         loop.exec();
0097         QString currentByteArray = rep->readAll();
0098         qDebug() << "network reply google api connect step get info" << currentByteArray;
0099 
0100     });
0101 
0102     google->grant();
0103 
0104     0
0105 
0106 #endif
0107 
0108     auto replyHandler = new QOAuthHttpServerReplyHandler(11450, mOAuth2);
0109     mOAuth2->setClientIdentifier(mGitHubInfo.clientId);
0110     mOAuth2->setReplyHandler(replyHandler);
0111     mOAuth2->setAuthorizationUrl(GitHubAuthenticationSettings::authorizeUrl());
0112     mOAuth2->setAccessTokenUrl(GitHubAuthenticationSettings::accessTokenUrl());
0113     mOAuth2->setScope(QStringLiteral("openid"));
0114     mOAuth2->setToken(mGitHubInfo.token);
0115     mOAuth2->setRefreshToken(mGitHubInfo.refreshToken);
0116 
0117     QObject::connect(mOAuth2, &QOAuth2AuthorizationCodeFlow::statusChanged, [this](QAbstractOAuth::Status status) {
0118         qCDebug(RUQOLA_GITHUBAUTHENTICATION_PLUGIN_LOG)
0119             << (int)status << mOAuth2->token() << mOAuth2->refreshToken() << mOAuth2->expirationAt() << mOAuth2->extraTokens();
0120         if (status == QAbstractOAuth::Status::Granted) {
0121             // TODO store info in qtkeychain
0122             qCDebug(RUQOLA_GITHUBAUTHENTICATION_PLUGIN_LOG) << "authorization granted";
0123             doRequest();
0124             QTimer::singleShot(std::max<qint64>(5 * 60 * 1000, QDateTime::currentDateTime().secsTo(mOAuth2->expirationAt()) * 800),
0125                                mOAuth2,
0126                                &QOAuth2AuthorizationCodeFlow::refreshAccessToken);
0127         }
0128     });
0129     QObject::connect(mOAuth2, &QOAuth2AuthorizationCodeFlow::authorizationCallbackReceived, [](const QVariantMap &m) {
0130         qCDebug(RUQOLA_GITHUBAUTHENTICATION_PLUGIN_LOG) << "auth callback received" << m;
0131     });
0132     QObject::connect(mOAuth2, &QOAuth2AuthorizationCodeFlow::error, [](const QString &err, const QString &desc) {
0133         qCDebug(RUQOLA_GITHUBAUTHENTICATION_PLUGIN_LOG) << "error" << err << desc;
0134     });
0135     QObject::connect(mOAuth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, &QDesktopServices::openUrl);
0136 
0137     if (mOAuth2->refreshToken().isEmpty()) {
0138         mOAuth2->grant();
0139     } else if (!mOAuth2->expirationAt().isValid() || mOAuth2->expirationAt() < QDateTime::currentDateTimeUtc()) {
0140         mOAuth2->refreshAccessToken();
0141     }
0142 }
0143 
0144 bool GitHubAuthenticationJob::GitHubInfo::isValid() const
0145 {
0146     return !url.isEmpty() && !clientId.isEmpty();
0147 }
0148 
0149 #include "moc_githubauthenticationjob.cpp"