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 ¶ms) 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¬_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"