File indexing completed on 2024-11-24 04:43:51

0001 /*
0002     SPDX-FileCopyrightText: 2018 Krzysztof Nowicki <krissn@op.pl>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "ewsoauth_ut_mock.h"
0008 
0009 #include <QUrlQuery>
0010 Q_LOGGING_CATEGORY(EWSCLI_LOG, "org.kde.pim.ews.client", QtInfoMsg)
0011 
0012 namespace Mock
0013 {
0014 QPointer<QWebEngineView> QWebEngineView::instance;
0015 QPointer<QOAuth2AuthorizationCodeFlow> QOAuth2AuthorizationCodeFlow::instance;
0016 
0017 QUrl QWebEngineUrlRequestJob::requestUrl() const
0018 {
0019     return mUrl;
0020 }
0021 
0022 QUrl QWebEngineUrlRequestInfo::requestUrl() const
0023 {
0024     return mUrl;
0025 }
0026 
0027 void QWebEngineUrlRequestInfo::block(bool)
0028 {
0029     mBlocked = true;
0030 }
0031 
0032 void QWebEngineUrlRequestInfo::redirect(const QUrl &)
0033 {
0034 }
0035 
0036 void QWebEngineUrlRequestInfo::setHttpHeader(const QByteArray &header, const QByteArray &value)
0037 {
0038 }
0039 
0040 QWebEngineUrlRequestInterceptor::QWebEngineUrlRequestInterceptor(QObject *parent)
0041     : QObject(parent)
0042 {
0043 }
0044 
0045 QWebEngineUrlRequestInterceptor::~QWebEngineUrlRequestInterceptor() = default;
0046 
0047 QWebEngineUrlSchemeHandler::QWebEngineUrlSchemeHandler(QObject *parent)
0048     : QObject(parent)
0049 {
0050 }
0051 
0052 QWebEngineUrlSchemeHandler::~QWebEngineUrlSchemeHandler() = default;
0053 
0054 QWebEngineProfile::QWebEngineProfile(QObject *parent)
0055     : QObject(parent)
0056     , mInterceptor(nullptr)
0057     , mHandler(nullptr)
0058 {
0059 }
0060 
0061 QWebEngineProfile::~QWebEngineProfile() = default;
0062 
0063 void QWebEngineProfile::setHttpUserAgent(const QString &ua)
0064 {
0065     mUserAgent = ua;
0066 }
0067 
0068 void QWebEngineProfile::setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor)
0069 {
0070     mInterceptor = interceptor;
0071 }
0072 
0073 void QWebEngineProfile::installUrlSchemeHandler(QByteArray const &scheme, QWebEngineUrlSchemeHandler *handler)
0074 {
0075     mScheme = QString::fromLatin1(scheme);
0076     mHandler = handler;
0077 }
0078 
0079 QWebEnginePage::QWebEnginePage(QWebEngineProfile *profile, QObject *parent)
0080     : QObject(parent)
0081     , mProfile(profile)
0082 {
0083     connect(profile, &QWebEngineProfile::logEvent, this, &QWebEnginePage::logEvent);
0084 }
0085 
0086 QWebEnginePage::~QWebEnginePage() = default;
0087 
0088 QWebEngineView::QWebEngineView(QWidget *parent)
0089     : QWidget(parent)
0090     , mPage(nullptr)
0091 {
0092     if (!instance) {
0093         instance = this;
0094     } else {
0095         qDebug() << "QWebEngineView instance already exists!";
0096     }
0097 }
0098 
0099 QWebEngineView::~QWebEngineView() = default;
0100 
0101 void QWebEngineView::load(const QUrl &url)
0102 {
0103     Q_EMIT logEvent(QStringLiteral("LoadWebPage:") + url.toString());
0104 
0105     simulatePageLoad(url);
0106 
0107     QVariantMap params;
0108     if (mAuthFunction) {
0109         mAuthFunction(url, params);
0110 
0111         simulatePageLoad(QUrl(mRedirectUri + QStringLiteral("?") + QOAuth2AuthorizationCodeFlow::mapToSortedQuery(params).toString()));
0112     } else {
0113         qWarning() << "No authentication callback defined";
0114     }
0115 }
0116 
0117 void QWebEngineView::simulatePageLoad(const QUrl &url)
0118 {
0119     if (mPage && mPage->mProfile && mPage->mProfile->mInterceptor) {
0120         QWebEngineUrlRequestInfo info(url, this);
0121         Q_EMIT logEvent(QStringLiteral("InterceptRequest:") + url.toString());
0122         mPage->mProfile->mInterceptor->interceptRequest(info);
0123         Q_EMIT logEvent(QStringLiteral("InterceptRequestBlocked:%1").arg(info.mBlocked));
0124     } else {
0125         qWarning() << "Cannot reach to request interceptor";
0126     }
0127 }
0128 
0129 void QWebEngineView::setPage(QWebEnginePage *page)
0130 {
0131     mPage = page;
0132 
0133     connect(page, &QWebEnginePage::logEvent, this, &QWebEngineView::logEvent);
0134 }
0135 
0136 void QWebEngineView::stop()
0137 {
0138 }
0139 
0140 void QWebEngineView::setAuthFunction(const AuthFunc &func)
0141 {
0142     mAuthFunction = func;
0143 }
0144 
0145 void QWebEngineView::setRedirectUri(const QString &uri)
0146 {
0147     mRedirectUri = uri;
0148 }
0149 
0150 QNetworkReply::NetworkError QNetworkReply::error() const
0151 {
0152     return NoError;
0153 }
0154 
0155 QVariant QNetworkReply::header(QNetworkRequest::KnownHeaders header) const
0156 {
0157     return mHeaders[header];
0158 }
0159 
0160 QAbstractOAuthReplyHandler::QAbstractOAuthReplyHandler(QObject *parent)
0161     : QObject(parent)
0162 {
0163 }
0164 
0165 QAbstractOAuthReplyHandler::~QAbstractOAuthReplyHandler() = default;
0166 
0167 QAbstractOAuth::QAbstractOAuth(QObject *parent)
0168     : QObject(parent)
0169     , mStatus(Status::NotAuthenticated)
0170 {
0171 }
0172 
0173 void QAbstractOAuth::setReplyHandler(QAbstractOAuthReplyHandler *handler)
0174 {
0175     mReplyHandler = handler;
0176 }
0177 
0178 void QAbstractOAuth::setAuthorizationUrl(const QUrl &url)
0179 {
0180     mAuthUrl = url;
0181 }
0182 
0183 void QAbstractOAuth::setClientIdentifier(const QString &identifier)
0184 {
0185     mClientId = identifier;
0186 }
0187 
0188 void QAbstractOAuth::setModifyParametersFunction(const std::function<void(QAbstractOAuth::Stage, QMap<QString, QVariant> *)> &func)
0189 {
0190     mModifyParamsFunc = func;
0191 }
0192 
0193 QString QAbstractOAuth::token() const
0194 {
0195     return mToken;
0196 }
0197 
0198 void QAbstractOAuth::setToken(const QString &token)
0199 {
0200     mToken = token;
0201 }
0202 
0203 QAbstractOAuth::Status QAbstractOAuth::status() const
0204 {
0205     return mStatus;
0206 }
0207 
0208 QAbstractOAuth2::QAbstractOAuth2(QObject *parent)
0209     : QAbstractOAuth(parent)
0210 {
0211 }
0212 
0213 QString QAbstractOAuth2::refreshToken() const
0214 {
0215     return mRefreshToken;
0216 }
0217 
0218 void QAbstractOAuth2::setRefreshToken(const QString &token)
0219 {
0220     mRefreshToken = token;
0221 }
0222 
0223 QOAuth2AuthorizationCodeFlow::QOAuth2AuthorizationCodeFlow(QObject *parent)
0224     : QAbstractOAuth2(parent)
0225 {
0226     if (!instance) {
0227         instance = this;
0228     } else {
0229         qDebug() << "QOAuth2AuthorizationCodeFlow instance already exists!";
0230     }
0231 }
0232 
0233 QOAuth2AuthorizationCodeFlow::~QOAuth2AuthorizationCodeFlow() = default;
0234 
0235 void QOAuth2AuthorizationCodeFlow::setAccessTokenUrl(const QUrl &url)
0236 {
0237     mTokenUrl = url;
0238 }
0239 
0240 void QOAuth2AuthorizationCodeFlow::grant()
0241 {
0242     QMap<QString, QVariant> map;
0243     map[QStringLiteral("response_type")] = QStringLiteral("code");
0244     map[QStringLiteral("client_id")] = QUrl::toPercentEncoding(mClientId);
0245     map[QStringLiteral("redirect_uri")] = QUrl::toPercentEncoding(mReplyHandler->callback());
0246     map[QStringLiteral("scope")] = QString();
0247     map[QStringLiteral("state")] = mState;
0248 
0249     Q_EMIT logEvent(QStringLiteral("ModifyParams:RequestingAuthorization:") + mapToSortedQuery(map).toString());
0250 
0251     if (mModifyParamsFunc) {
0252         mModifyParamsFunc(Stage::RequestingAuthorization, &map);
0253     }
0254 
0255     mResource = QUrl::fromPercentEncoding(map[QStringLiteral("resource")].toByteArray());
0256 
0257     QUrl url(mAuthUrl);
0258     url.setQuery(mapToSortedQuery(map));
0259 
0260     Q_EMIT logEvent(QStringLiteral("AuthorizeWithBrowser:") + url.toString());
0261 
0262     connect(this, &QAbstractOAuth2::authorizationCallbackReceived, this, &QOAuth2AuthorizationCodeFlow::authCallbackReceived, Qt::UniqueConnection);
0263 
0264     Q_EMIT authorizeWithBrowser(url);
0265 }
0266 
0267 void QOAuth2AuthorizationCodeFlow::refreshAccessToken()
0268 {
0269     mStatus = Status::RefreshingToken;
0270 
0271     doRefreshAccessToken();
0272 }
0273 
0274 void QOAuth2AuthorizationCodeFlow::doRefreshAccessToken()
0275 {
0276     QMap<QString, QVariant> map;
0277     map[QStringLiteral("grant_type")] = QStringLiteral("authorization_code");
0278     map[QStringLiteral("code")] = QUrl::toPercentEncoding(mRefreshToken);
0279     map[QStringLiteral("client_id")] = QUrl::toPercentEncoding(mClientId);
0280     map[QStringLiteral("redirect_uri")] = QUrl::toPercentEncoding(mReplyHandler->callback());
0281 
0282     Q_EMIT logEvent(QStringLiteral("ModifyParams:RequestingAccessToken:") + mapToSortedQuery(map).toString());
0283 
0284     if (mModifyParamsFunc) {
0285         mModifyParamsFunc(Stage::RequestingAccessToken, &map);
0286     }
0287 
0288     connect(mReplyHandler, &QAbstractOAuthReplyHandler::tokensReceived, this, &QOAuth2AuthorizationCodeFlow::tokenCallbackReceived, Qt::UniqueConnection);
0289     connect(mReplyHandler,
0290             &QAbstractOAuthReplyHandler::replyDataReceived,
0291             this,
0292             &QOAuth2AuthorizationCodeFlow::replyDataCallbackReceived,
0293             Qt::UniqueConnection);
0294 
0295     if (mTokenFunc) {
0296         QNetworkReply reply(this);
0297 
0298         QString data;
0299         reply.mError = mTokenFunc(data, reply.mHeaders);
0300 
0301         reply.setData(data.toUtf8());
0302         reply.open(QIODevice::ReadOnly);
0303 
0304         Q_EMIT logEvent(QStringLiteral("NetworkReplyFinished:") + data);
0305 
0306         mReplyHandler->networkReplyFinished(&reply);
0307     } else {
0308         qWarning() << "No token function defined";
0309     }
0310 }
0311 
0312 QUrlQuery QOAuth2AuthorizationCodeFlow::mapToSortedQuery(QMap<QString, QVariant> const &map)
0313 {
0314     QUrlQuery query;
0315     QStringList keys = map.keys();
0316     keys.sort();
0317     for (const auto &key : std::as_const(keys)) {
0318         query.addQueryItem(key, map[key].toString());
0319     }
0320     return query;
0321 }
0322 
0323 void QOAuth2AuthorizationCodeFlow::authCallbackReceived(QMap<QString, QVariant> const &params)
0324 {
0325     Q_EMIT logEvent(QStringLiteral("AuthorizatioCallbackReceived:") + mapToSortedQuery(params).toString());
0326 
0327     mRefreshToken = params[QStringLiteral("code")].toString();
0328     if (!mRefreshToken.isEmpty()) {
0329         mStatus = Status::TemporaryCredentialsReceived;
0330         doRefreshAccessToken();
0331     } else {
0332         Q_EMIT error(QString(), QString(), QUrl());
0333     }
0334 }
0335 
0336 void QOAuth2AuthorizationCodeFlow::tokenCallbackReceived(const QVariantMap &tokens)
0337 {
0338     Q_EMIT logEvent(QStringLiteral("TokenCallback:") + mapToSortedQuery(tokens).toString());
0339 
0340     mToken = tokens[QStringLiteral("access_token")].toString();
0341     mRefreshToken = tokens[QStringLiteral("refresh_token")].toString();
0342 
0343     mStatus = Status::Granted;
0344 
0345     Q_EMIT granted();
0346 }
0347 
0348 void QOAuth2AuthorizationCodeFlow::replyDataCallbackReceived(const QByteArray &data)
0349 {
0350     Q_EMIT logEvent(QStringLiteral("ReplyDataCallback:") + QString::fromLatin1(data));
0351 }
0352 
0353 QString QOAuth2AuthorizationCodeFlow::redirectUri() const
0354 {
0355     return mReplyHandler->callback();
0356 }
0357 
0358 void QOAuth2AuthorizationCodeFlow::setTokenFunction(const TokenFunc &func)
0359 {
0360     mTokenFunc = func;
0361 }
0362 
0363 void QOAuth2AuthorizationCodeFlow::setState(const QString &state)
0364 {
0365     mState = state;
0366 }
0367 
0368 QString browserDisplayRequestString()
0369 {
0370     return QStringLiteral("BrowserDisplayRequest");
0371 }
0372 
0373 QString modifyParamsAuthString(const QString &clientId, const QString &returnUri, const QString &state)
0374 {
0375     return QStringLiteral("ModifyParams:RequestingAuthorization:client_id=%1&redirect_uri=%2&response_type=code&scope&state=%3")
0376         .arg(QString::fromUtf8(QUrl::toPercentEncoding(clientId)),
0377              QString::fromLatin1(QUrl::toPercentEncoding(returnUri)),
0378              QString::fromLatin1(QUrl::toPercentEncoding(state)));
0379 }
0380 
0381 QString
0382 authUrlString(const QString &authUrl, const QString &clientId, const QString &returnUri, const QString &email, const QString &resource, const QString &state)
0383 {
0384     return QStringLiteral("%1?client_id=%2&login_hint=%3&prompt=login&redirect_uri=%4&resource=%5&response_type=code&scope&state=%6")
0385         .arg(authUrl,
0386              QString::fromLatin1(QUrl::toPercentEncoding(clientId)),
0387              email,
0388              QString::fromLatin1(QUrl::toPercentEncoding(returnUri)),
0389              QString::fromLatin1(QUrl::toPercentEncoding(resource)),
0390              QString::fromLatin1(QUrl::toPercentEncoding(state)));
0391 }
0392 
0393 QString authorizeWithBrowserString(const QString &url)
0394 {
0395     return QStringLiteral("AuthorizeWithBrowser:") + url;
0396 }
0397 
0398 QString loadWebPageString(const QString &url)
0399 {
0400     return QStringLiteral("LoadWebPage:") + url;
0401 }
0402 
0403 QString interceptRequestString(const QString &url)
0404 {
0405     return QStringLiteral("InterceptRequest:") + url;
0406 }
0407 
0408 QString interceptRequestBlockedString(bool blocked)
0409 {
0410     return QStringLiteral("InterceptRequestBlocked:%1").arg(blocked);
0411 }
0412 
0413 QString authorizationCallbackReceivedString(const QString &code)
0414 {
0415     return QStringLiteral("AuthorizatioCallbackReceived:code=%1").arg(code);
0416 }
0417 
0418 QString modifyParamsTokenString(const QString &clientId, const QString &returnUri, const QString &code)
0419 {
0420     return QStringLiteral("ModifyParams:RequestingAccessToken:client_id=%1&code=%2&grant_type=authorization_code&redirect_uri=%3")
0421         .arg(QString::fromUtf8(QUrl::toPercentEncoding(clientId)),
0422              QString::fromLatin1(QUrl::toPercentEncoding(code)),
0423              QString::fromLatin1(QUrl::toPercentEncoding(returnUri)));
0424 }
0425 
0426 QString networkReplyFinishedString(const QString &data)
0427 {
0428     return QStringLiteral("NetworkReplyFinished:") + data;
0429 }
0430 
0431 QString replyDataCallbackString(const QString &data)
0432 {
0433     return QStringLiteral("ReplyDataCallback:") + data;
0434 }
0435 
0436 QString tokenCallbackString(const QString &accessToken,
0437                             const QString &refreshToken,
0438                             const QString &idToken,
0439                             quint64 time,
0440                             unsigned int tokenLifetime,
0441                             unsigned int extTokenLifetime,
0442                             const QString &resource)
0443 {
0444     return QStringLiteral(
0445                "TokenCallback:access_token=%1&expires_in=%2&expires_on=%3&ext_expires_in=%4&foci=1&id_token=%5&not_before=%6&refresh_token=%7&resource=%8&"
0446                "scope=ReadWrite.All&token_type=Bearer")
0447         .arg(accessToken)
0448         .arg(tokenLifetime)
0449         .arg(time + tokenLifetime)
0450         .arg(extTokenLifetime)
0451         .arg(idToken)
0452         .arg(time)
0453         .arg(refreshToken, resource);
0454 }
0455 
0456 QString requestWalletMapString()
0457 {
0458     return QStringLiteral("RequestWalletMap");
0459 }
0460 
0461 const QString &KJob::errorString() const
0462 {
0463     static const QString empty;
0464     return empty;
0465 }
0466 
0467 EwsPKeyAuthJob::EwsPKeyAuthJob(const QUrl &pkeyUri, const QString &certFile, const QString &keyFile, const QString &keyPassword, QObject *parent)
0468     : KJob(parent)
0469 {
0470     Q_UNUSED(pkeyUri)
0471     Q_UNUSED(certFile)
0472     Q_UNUSED(keyFile)
0473     Q_UNUSED(keyPassword)
0474 }
0475 
0476 const QUrl &EwsPKeyAuthJob::resultUri() const
0477 {
0478     static const QUrl empty;
0479     return empty;
0480 }
0481 
0482 QString EwsPKeyAuthJob::getAuthHeader()
0483 {
0484     return {};
0485 }
0486 }
0487 
0488 #include "moc_ewsoauth_ut_mock.cpp"