1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:critical reason:authorization-protocol
4
5#include "qoauthoobreplyhandler.h"
6#include "qoauthoobreplyhandler_p.h"
7
8#include <QtCore/qurlquery.h>
9#include <QtCore/qjsonobject.h>
10#include <QtCore/qjsondocument.h>
11#include <QtCore/qloggingcategory.h>
12
13#include <QtNetwork/qnetworkreply.h>
14#include <QtNetwork/qrestreply.h>
15
16QT_BEGIN_NAMESPACE
17
18using namespace Qt::StringLiterals;
19
20QOAuthOobReplyHandler::QOAuthOobReplyHandler(QObject *parent)
21 : QAbstractOAuthReplyHandler(parent)
22{}
23
24/*! \internal */
25QOAuthOobReplyHandler::QOAuthOobReplyHandler(QOAuthOobReplyHandlerPrivate &d, QObject *parent)
26 : QAbstractOAuthReplyHandler(d, parent)
27{}
28
29QOAuthOobReplyHandler::~QOAuthOobReplyHandler()
30 = default; // must be empty until Qt 7 (was inline until Qt 6.8)
31
32QString QOAuthOobReplyHandler::callback() const
33{
34 return QStringLiteral("oob");
35}
36
37void QOAuthOobReplyHandler::networkReplyFinished(QNetworkReply *reply)
38{
39 QRestReply restReply(reply);
40
41 if (restReply.hasError()) {
42 emit tokenRequestErrorOccurred(error: QAbstractOAuth::Error::NetworkError, errorString: reply->errorString());
43 return;
44 }
45 if (!restReply.isHttpStatusSuccess()) {
46 emit tokenRequestErrorOccurred(error: QAbstractOAuth::Error::ServerError, errorString: reply->errorString());
47 return;
48 }
49 if (reply->header(header: QNetworkRequest::ContentTypeHeader).isNull()) {
50 emit tokenRequestErrorOccurred(error: QAbstractOAuth::Error::ServerError,
51 errorString: u"Empty Content-type header"_s);
52 return;
53 }
54 const QString contentType = reply->header(header: QNetworkRequest::ContentTypeHeader).isNull() ?
55 QStringLiteral("text/html") :
56 reply->header(header: QNetworkRequest::ContentTypeHeader).toString();
57 const QByteArray data = reply->readAll();
58 if (data.isEmpty()) {
59 emit tokenRequestErrorOccurred(error: QAbstractOAuth::Error::ServerError, errorString: u"No data received"_s);
60 return;
61 }
62
63 Q_EMIT replyDataReceived(data);
64
65 QVariantMap ret;
66
67 if (contentType.startsWith(QStringLiteral("text/html")) ||
68 contentType.startsWith(QStringLiteral("application/x-www-form-urlencoded"))) {
69 ret = parseResponse(response: data);
70 } else if (contentType.startsWith(QStringLiteral("application/json"))
71 || contentType.startsWith(QStringLiteral("text/javascript"))) {
72 const QJsonDocument document = QJsonDocument::fromJson(json: data);
73 if (!document.isObject()) {
74 emit tokenRequestErrorOccurred(error: QAbstractOAuth::Error::ServerError,
75 errorString: u"Received data is not a JSON object: %1"_s.arg(a: QString::fromUtf8(ba: data)));
76 return;
77 }
78 const QJsonObject object = document.object();
79 if (object.isEmpty()) {
80 emit tokenRequestErrorOccurred(error: QAbstractOAuth::Error::ServerError,
81 errorString: u"Received an empty JSON object"_s);
82 return;
83 }
84 ret = object.toVariantMap();
85 } else {
86 emit tokenRequestErrorOccurred(error: QAbstractOAuth::Error::ServerError,
87 errorString: u"Unknown Content-type %1"_s.arg(a: contentType));
88 return;
89 }
90
91 Q_EMIT tokensReceived(tokens: ret);
92}
93
94QVariantMap QOAuthOobReplyHandler::parseResponse(const QByteArray &response)
95{
96 QVariantMap ret;
97 QUrlQuery query(QString::fromUtf8(ba: response));
98 const auto queryItems = query.queryItems(encoding: QUrl::FullyDecoded);
99 for (auto it = queryItems.begin(), end = queryItems.end(); it != end; ++it)
100 ret.insert(key: it->first, value: it->second);
101 return ret;
102}
103
104QT_END_NAMESPACE
105
106#include "moc_qoauthoobreplyhandler.cpp"
107

source code of qtnetworkauth/src/oauth/qoauthoobreplyhandler.cpp