summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/oauth/oauth.pro37
-rw-r--r--src/oauth/qabstractoauth.cpp222
-rw-r--r--src/oauth/qabstractoauth.h172
-rw-r--r--src/oauth/qabstractoauth2.cpp273
-rw-r--r--src/oauth/qabstractoauth2.h128
-rw-r--r--src/oauth/qabstractoauth2_p.h118
-rw-r--r--src/oauth/qabstractoauth_p.h104
-rw-r--r--src/oauth/qabstractoauthreplyhandler.cpp59
-rw-r--r--src/oauth/qabstractoauthreplyhandler.h83
-rw-r--r--src/oauth/qoauth1.cpp654
-rw-r--r--src/oauth/qoauth1.h159
-rw-r--r--src/oauth/qoauth1_p.h124
-rw-r--r--src/oauth/qoauth1signature.cpp300
-rw-r--r--src/oauth/qoauth1signature.h120
-rw-r--r--src/oauth/qoauth1signature_p.h89
-rw-r--r--src/oauth/qoauth2authorizationcodeflow.cpp353
-rw-r--r--src/oauth/qoauth2authorizationcodeflow.h112
-rw-r--r--src/oauth/qoauth2authorizationcodeflow_p.h90
-rw-r--r--src/oauth/qoauthglobal.h59
-rw-r--r--src/oauth/qoauthhttpserverreplyhandler.cpp329
-rw-r--r--src/oauth/qoauthhttpserverreplyhandler.h86
-rw-r--r--src/oauth/qoauthhttpserverreplyhandler_p.h122
-rw-r--r--src/oauth/qoauthoobreplyhandler.cpp122
-rw-r--r--src/oauth/qoauthoobreplyhandler.h70
-rw-r--r--src/src.pro4
25 files changed, 3989 insertions, 0 deletions
diff --git a/src/oauth/oauth.pro b/src/oauth/oauth.pro
new file mode 100644
index 0000000..3060605
--- /dev/null
+++ b/src/oauth/oauth.pro
@@ -0,0 +1,37 @@
+TARGET = QtNetworkAuth
+MODULE = networkauth
+
+QT += core core-private network
+
+PUBLIC_HEADERS += \
+ qoauth1.h \
+ qoauthglobal.h \
+ qabstractoauth.h \
+ qabstractoauth2.h \
+ qoauth1signature.h \
+ qoauthoobreplyhandler.h \
+ qabstractoauthreplyhandler.h \
+ qoauth2authorizationcodeflow.h \
+ qoauthhttpserverreplyhandler.h
+
+PRIVATE_HEADERS += \
+ qoauth1_p.h \
+ qabstractoauth_p.h \
+ qabstractoauth2_p.h \
+ qoauth1signature_p.h \
+ qoauth2authorizationcodeflow_p.h \
+ qoauthhttpserverreplyhandler_p.h
+
+SOURCES += \
+ qoauth1.cpp \
+ qabstractoauth.cpp \
+ qabstractoauth2.cpp \
+ qoauth1signature.cpp \
+ qoauthoobreplyhandler.cpp \
+ qabstractoauthreplyhandler.cpp \
+ qoauth2authorizationcodeflow.cpp \
+ qoauthhttpserverreplyhandler.cpp
+
+HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
+
+load(qt_module)
diff --git a/src/oauth/qabstractoauth.cpp b/src/oauth/qabstractoauth.cpp
new file mode 100644
index 0000000..b970d80
--- /dev/null
+++ b/src/oauth/qabstractoauth.cpp
@@ -0,0 +1,222 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_HTTP
+
+#include <qabstractoauth.h>
+#include <qabstractoauthreplyhandler.h>
+
+#include <private/qabstractoauth_p.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qurlquery.h>
+#include <QtCore/qmessageauthenticationcode.h>
+
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+#include <random>
+
+Q_DECLARE_METATYPE(QAbstractOAuth::Error)
+
+QT_BEGIN_NAMESPACE
+
+QAbstractOAuthPrivate::QAbstractOAuthPrivate(QNetworkAccessManager *manager) :
+ QAbstractOAuthPrivate(QUrl(), manager)
+{}
+
+QAbstractOAuthPrivate::QAbstractOAuthPrivate(const QUrl &authorizationUrl,
+ QNetworkAccessManager *manager) :
+ authorizationUrl(authorizationUrl), defaultReplyHandler(new QOAuthOobReplyHandler),
+ networkAccessManagerPointer(manager)
+{}
+
+QAbstractOAuthPrivate::~QAbstractOAuthPrivate()
+{}
+
+QNetworkAccessManager *QAbstractOAuthPrivate::networkAccessManager()
+{
+ Q_Q(QAbstractOAuth);
+ if (!networkAccessManagerPointer)
+ networkAccessManagerPointer = new QNetworkAccessManager(q);
+ return networkAccessManagerPointer.data();
+}
+
+void QAbstractOAuthPrivate::setStatus(QAbstractOAuth::Status newStatus)
+{
+ Q_Q(QAbstractOAuth);
+ if (status != newStatus) {
+ status = newStatus;
+ Q_EMIT q->statusChanged(status);
+ if (status == QAbstractOAuth::Status::Granted)
+ Q_EMIT q->granted();
+ }
+}
+
+QByteArray QAbstractOAuthPrivate::generateRandomString(quint8 length)
+{
+ const char characters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ std::mt19937 randomEngine;
+ std::uniform_int_distribution<int> distribution(0, sizeof(characters) - 2);
+ QByteArray data;
+ data.reserve(length);
+ for (quint8 i = 0; i < length; ++i)
+ data.append(characters[distribution(randomEngine)]);
+ return data;
+}
+
+QUrlQuery QAbstractOAuthPrivate::createQuery(const QVariantMap &parameters)
+{
+ QUrlQuery query;
+ for (auto it = parameters.begin(), end = parameters.end(); it != end; ++it)
+ query.addQueryItem(it.key(), it.value().toString());
+ return query;
+}
+
+QAbstractOAuth::QAbstractOAuth(QAbstractOAuthPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+ qRegisterMetaType<QAbstractOAuth::Error>();
+}
+
+QAbstractOAuth::~QAbstractOAuth()
+{}
+
+QNetworkAccessManager *QAbstractOAuth::networkAccessManager() const
+{
+ Q_D(const QAbstractOAuth);
+ return d->networkAccessManagerPointer.data();
+}
+
+void QAbstractOAuth::setNetworkAccessManager(QNetworkAccessManager *networkAccessManager)
+{
+ Q_D(QAbstractOAuth);
+ if (networkAccessManager != d->networkAccessManagerPointer) {
+ if (d->networkAccessManagerPointer && d->networkAccessManagerPointer->parent() == this)
+ delete d->networkAccessManagerPointer.data();
+ d->networkAccessManagerPointer = networkAccessManager;
+ }
+}
+
+QAbstractOAuth::Status QAbstractOAuth::status() const
+{
+ Q_D(const QAbstractOAuth);
+ return d->status;
+}
+
+QUrl QAbstractOAuth::authorizationUrl() const
+{
+ Q_D(const QAbstractOAuth);
+ return d->authorizationUrl;
+}
+
+void QAbstractOAuth::setAuthorizationUrl(const QUrl &url)
+{
+ Q_D(QAbstractOAuth);
+ if (d->authorizationUrl != url) {
+ d->authorizationUrl = url;
+ Q_EMIT authorizationUrlChanged(url);
+ }
+}
+
+void QAbstractOAuth::setStatus(QAbstractOAuth::Status status)
+{
+ Q_D(QAbstractOAuth);
+ if (status != d->status) {
+ d->status = status;
+ Q_EMIT statusChanged(status);
+ }
+}
+
+QAbstractOAuthReplyHandler *QAbstractOAuth::replyHandler() const
+{
+ Q_D(const QAbstractOAuth);
+ return d->replyHandler ? d->replyHandler.data() : d->defaultReplyHandler.data();
+}
+
+void QAbstractOAuth::setReplyHandler(QAbstractOAuthReplyHandler *handler)
+{
+ Q_D(QAbstractOAuth);
+ d->replyHandler = handler;
+}
+
+QAbstractOAuth::ModifyParametersFunction QAbstractOAuth::modifyParametersFunction() const
+{
+ Q_D(const QAbstractOAuth);
+ return d->modifyParametersFunction;
+}
+
+void QAbstractOAuth::setModifyParametersFunction(
+ const QAbstractOAuth::ModifyParametersFunction &modifyParametersFunction)
+{
+ Q_D(QAbstractOAuth);
+ d->modifyParametersFunction = modifyParametersFunction;
+}
+
+QVariantMap QAbstractOAuth::extraTokens() const
+{
+ Q_D(const QAbstractOAuth);
+ return d->extraTokens;
+}
+
+QString QAbstractOAuth::callback() const
+{
+ Q_D(const QAbstractOAuth);
+ return d->replyHandler ? d->replyHandler->callback()
+ : d->defaultReplyHandler->callback();
+}
+
+void QAbstractOAuth::resourceOwnerAuthorization(const QUrl &url, const QVariantMap &parameters)
+{
+ QUrl u = url;
+ u.setQuery(QAbstractOAuthPrivate::createQuery(parameters));
+ Q_EMIT authorizeWithBrowser(u);
+}
+
+QByteArray QAbstractOAuth::generateRandomString(quint8 length)
+{
+ return QAbstractOAuthPrivate::generateRandomString(length);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
diff --git a/src/oauth/qabstractoauth.h b/src/oauth/qabstractoauth.h
new file mode 100644
index 0000000..d9c5aeb
--- /dev/null
+++ b/src/oauth/qabstractoauth.h
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTOAUTH_H
+#define QABSTRACTOAUTH_H
+
+#ifndef QT_NO_HTTP
+
+#include <QtNetworkAuth/qoauthglobal.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvariant.h>
+
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+class QByteArray;
+class QNetworkReply;
+class QNetworkRequest;
+class QNetworkAccessManager;
+class QAbstractOAuthReplyHandler;
+
+class QAbstractOAuthPrivate;
+class Q_OAUTH_EXPORT QAbstractOAuth : public QObject
+{
+ Q_OBJECT
+
+ Q_ENUMS(Status)
+ Q_ENUMS(Stage)
+ Q_ENUMS(Error)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QVariantMap extraTokens READ extraTokens NOTIFY extraTokensChanged)
+ Q_PROPERTY(QUrl authorizationUrl
+ READ authorizationUrl
+ WRITE setAuthorizationUrl
+ NOTIFY authorizationUrlChanged)
+
+public:
+ enum class Status {
+ NotAuthenticated,
+ TemporaryCredentialsReceived,
+ Granted,
+ RefreshingToken
+ };
+
+ enum class Stage {
+ RequestingTemporaryCredentials,
+ RequestingAuthorization,
+ RequestingAccessToken
+ };
+
+ enum class Error {
+ NoError,
+ NetworkError,
+ ServerError,
+
+ OAuthTokenNotFoundError,
+ OAuthTokenSecretNotFoundError,
+ OAuthCallbackNotVerified
+ };
+
+ typedef std::function<void(Stage, QVariantMap*)> ModifyParametersFunction;
+
+ virtual ~QAbstractOAuth();
+
+ virtual QString clientIdentifier() const = 0;
+ virtual void setClientIdentifier(const QString &clientIdentifier) = 0;
+
+ virtual QString token() const = 0;
+ virtual void setToken(const QString &token) = 0;
+
+ QNetworkAccessManager *networkAccessManager() const;
+ void setNetworkAccessManager(QNetworkAccessManager *networkAccessManager);
+
+ Status status() const;
+
+ QUrl authorizationUrl() const;
+ void setAuthorizationUrl(const QUrl &url);
+
+ QVariantMap extraTokens() const;
+
+ QAbstractOAuthReplyHandler *replyHandler() const;
+ void setReplyHandler(QAbstractOAuthReplyHandler *handler);
+
+ Q_INVOKABLE virtual QNetworkReply *head(const QUrl &url,
+ const QVariantMap &parameters = QVariantMap()) = 0;
+ Q_INVOKABLE virtual QNetworkReply *get(const QUrl &url,
+ const QVariantMap &parameters = QVariantMap()) = 0;
+ Q_INVOKABLE virtual QNetworkReply *post(const QUrl &url,
+ const QVariantMap &parameters = QVariantMap()) = 0;
+ Q_INVOKABLE virtual QNetworkReply *deleteResource(
+ const QUrl &url, const QVariantMap &parameters = QVariantMap()) = 0;
+
+ ModifyParametersFunction modifyParametersFunction() const;
+ void setModifyParametersFunction(const ModifyParametersFunction &modifyParametersFunction);
+
+public Q_SLOTS:
+ virtual void grant() = 0;
+
+Q_SIGNALS:
+ void clientIdentifierChanged(const QString &clientIdentifier);
+ void tokenChanged(const QString &token);
+ void statusChanged(Status status);
+ void authorizationUrlChanged(const QUrl &url);
+ void extraTokensChanged(const QVariantMap &tokens);
+
+ void requestFailed(const Error error);
+ void authorizeWithBrowser(const QUrl &url);
+ void granted();
+ void finished(QNetworkReply *reply);
+ void replyDataReceived(const QByteArray &data);
+
+protected:
+ explicit QAbstractOAuth(QAbstractOAuthPrivate &, QObject *parent = nullptr);
+
+ void setStatus(Status status);
+
+ QString callback() const;
+
+ virtual void resourceOwnerAuthorization(const QUrl &url, const QVariantMap &parameters);
+ static QByteArray generateRandomString(quint8 length);
+
+private:
+ Q_DISABLE_COPY(QAbstractOAuth)
+ Q_DECLARE_PRIVATE(QAbstractOAuth)
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QABSTRACTOAUTH_H
diff --git a/src/oauth/qabstractoauth2.cpp b/src/oauth/qabstractoauth2.cpp
new file mode 100644
index 0000000..5808b97
--- /dev/null
+++ b/src/oauth/qabstractoauth2.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_HTTP
+
+#include <qabstractoauth2.h>
+#include <private/qabstractoauth2_p.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qurlquery.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qmessageauthenticationcode.h>
+
+#include <QtNetwork/qnetworkreply.h>
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+QT_BEGIN_NAMESPACE
+
+using Key = QAbstractOAuth2Private::OAuth2KeyString;
+const QString Key::accessToken = QStringLiteral("access_token");
+const QString Key::apiKey = QStringLiteral("api_key");
+const QString Key::clientIdentifier = QStringLiteral("client_id");
+const QString Key::clientSharedSecret = QStringLiteral("client_secret");
+const QString Key::code = QStringLiteral("code");
+const QString Key::error = QStringLiteral("error");
+const QString Key::errorDescription = QStringLiteral("error_description");
+const QString Key::errorUri = QStringLiteral("error_uri");
+const QString Key::expiresIn = QStringLiteral("expires_in");
+const QString Key::grantType = QStringLiteral("grant_type");
+const QString Key::redirectUri = QStringLiteral("redirect_uri");
+const QString Key::refreshToken = QStringLiteral("refresh_token");
+const QString Key::responseType = QStringLiteral("response_type");
+const QString Key::scope = QStringLiteral("scope");
+const QString Key::state = QStringLiteral("state");
+const QString Key::tokenType = QStringLiteral("token_type");
+
+QAbstractOAuth2Private::QAbstractOAuth2Private(const QPair<QString, QString> &clientCredentials,
+ const QUrl &authorizationUrl,
+ QNetworkAccessManager *manager) :
+ QAbstractOAuthPrivate(authorizationUrl, manager), clientCredentials(clientCredentials)
+{}
+
+QAbstractOAuth2Private::QAbstractOAuth2Private(QNetworkAccessManager *manager) :
+ QAbstractOAuthPrivate(authorizationUrl, manager)
+{}
+
+QAbstractOAuth2Private::~QAbstractOAuth2Private()
+{}
+
+QString QAbstractOAuth2Private::generateRandomState()
+{
+ return QString::fromUtf8(QAbstractOAuthPrivate::generateRandomString(8));
+}
+
+QNetworkRequest QAbstractOAuth2Private::createRequest(const QUrl &url, const QVariantMap &parameters)
+{
+ QUrlQuery query(url.query());
+
+ for (auto it = parameters.begin(), end = parameters.end(); it != end; ++it)
+ query.addQueryItem(it.key(), it.value().toString());
+
+ QUrl u(url);
+ u.setQuery(query);
+
+ QNetworkRequest request(u);
+ request.setHeader(QNetworkRequest::UserAgentHeader, userAgent);
+ const QString bearer = bearerFormat.arg(token);
+ request.setRawHeader("Authorization", bearer.toUtf8());
+ return request;
+}
+
+QAbstractOAuth2::QAbstractOAuth2(QObject *parent) :
+ QAbstractOAuth2(nullptr, parent)
+{}
+
+QAbstractOAuth2::QAbstractOAuth2(QNetworkAccessManager *manager, QObject *parent) :
+ QAbstractOAuth(*new QAbstractOAuth2Private(manager), parent)
+{}
+
+QAbstractOAuth2::QAbstractOAuth2(QAbstractOAuth2Private &dd, QObject *parent) :
+ QAbstractOAuth(dd, parent)
+{}
+
+QAbstractOAuth2::~QAbstractOAuth2()
+{}
+
+QUrl QAbstractOAuth2::createAuthenticatedUrl(const QUrl &url, const QVariantMap &parameters)
+{
+ Q_D(const QAbstractOAuth2);
+ if (Q_UNLIKELY(d->token.isEmpty())) {
+ qWarning("QAbstractOAuth2::createAuthenticatedUrl: Empty access token");
+ return QUrl();
+ }
+ QUrl ret = url;
+ QUrlQuery query(ret.query());
+ query.addQueryItem(Key::accessToken, d->token);
+ for (auto it = parameters.begin(), end = parameters.end(); it != end ;++it)
+ query.addQueryItem(it.key(), it.value().toString());
+ ret.setQuery(query);
+ return ret;
+}
+
+QNetworkReply *QAbstractOAuth2::head(const QUrl &url, const QVariantMap &parameters)
+{
+ Q_D(QAbstractOAuth2);
+ QNetworkReply *reply = d->networkAccessManager()->head(d->createRequest(url, parameters));
+ connect(reply, &QNetworkReply::finished, std::bind(&QAbstractOAuth::finished, this, reply));
+ return reply;
+}
+
+QNetworkReply *QAbstractOAuth2::get(const QUrl &url, const QVariantMap &parameters)
+{
+ Q_D(QAbstractOAuth2);
+ QNetworkReply *reply = d->networkAccessManager()->get(
+ d->createRequest(url, parameters));
+ connect(reply, &QNetworkReply::finished, std::bind(&QAbstractOAuth::finished, this, reply));
+ return reply;
+}
+
+QNetworkReply *QAbstractOAuth2::post(const QUrl &url, const QVariantMap &parameters)
+{
+ Q_D(QAbstractOAuth2);
+ QNetworkReply *reply = d->networkAccessManager()->post(
+ d->createRequest(url, parameters), QByteArray());
+ connect(reply, &QNetworkReply::finished, std::bind(&QAbstractOAuth::finished, this, reply));
+ return reply;
+}
+
+QNetworkReply *QAbstractOAuth2::deleteResource(const QUrl &url, const QVariantMap &parameters)
+{
+ Q_D(QAbstractOAuth2);
+ QNetworkReply *reply = d->networkAccessManager()->deleteResource(
+ d->createRequest(url, parameters));
+ connect(reply, &QNetworkReply::finished, std::bind(&QAbstractOAuth::finished, this, reply));
+ return reply;
+}
+
+QString QAbstractOAuth2::scope() const
+{
+ Q_D(const QAbstractOAuth2);
+ return d->scope;
+}
+
+void QAbstractOAuth2::setScope(const QString &scope)
+{
+ Q_D(QAbstractOAuth2);
+ if (d->scope != scope) {
+ d->scope = scope;
+ Q_EMIT scopeChanged(scope);
+ }
+}
+
+QString QAbstractOAuth2::userAgent() const
+{
+ Q_D(const QAbstractOAuth2);
+ return d->userAgent;
+}
+
+void QAbstractOAuth2::setUserAgent(const QString &userAgent)
+{
+ Q_D(QAbstractOAuth2);
+ if (d->userAgent != userAgent) {
+ d->userAgent = userAgent;
+ Q_EMIT userAgentChanged(userAgent);
+ }
+}
+
+QString QAbstractOAuth2::clientIdentifier() const
+{
+ Q_D(const QAbstractOAuth2);
+ return d->clientCredentials.first;
+}
+
+void QAbstractOAuth2::setClientIdentifier(const QString &clientIdentifier)
+{
+ Q_D(QAbstractOAuth2);
+ if (d->clientCredentials.first != clientIdentifier) {
+ d->clientCredentials.first = clientIdentifier;
+ Q_EMIT clientIdentifierChanged(clientIdentifier);
+ }
+}
+
+QString QAbstractOAuth2::clientIdentifierSharedKey() const
+{
+ Q_D(const QAbstractOAuth2);
+ return d->clientCredentials.second;
+}
+
+void QAbstractOAuth2::setClientIdentifierSharedKey(const QString &clientIdentifierSharedKey)
+{
+ Q_D(QAbstractOAuth2);
+ if (d->clientCredentials.second != clientIdentifierSharedKey) {
+ d->clientCredentials.second = clientIdentifierSharedKey;
+ Q_EMIT clientIdentifierSharedKeyChanged(clientIdentifierSharedKey);
+ }
+}
+
+QString QAbstractOAuth2::token() const
+{
+ Q_D(const QAbstractOAuth2);
+ return d->token;
+}
+
+void QAbstractOAuth2::setToken(const QString &token)
+{
+ Q_D(QAbstractOAuth2);
+ if (d->token != token) {
+ d->token = token;
+ Q_EMIT tokenChanged(token);
+ }
+}
+
+QString QAbstractOAuth2::state() const
+{
+ Q_D(const QAbstractOAuth2);
+ return d->state;
+}
+
+void QAbstractOAuth2::setState(const QString &state)
+{
+ Q_D(QAbstractOAuth2);
+ if (state != d->state) {
+ d->state = state;
+ Q_EMIT stateChanged(state);
+ }
+}
+
+QDateTime QAbstractOAuth2::expirationAt() const
+{
+ Q_D(const QAbstractOAuth2);
+ return d->expiresAt;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
diff --git a/src/oauth/qabstractoauth2.h b/src/oauth/qabstractoauth2.h
new file mode 100644
index 0000000..06f9b3d
--- /dev/null
+++ b/src/oauth/qabstractoauth2.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTOAUTH2_H
+#define QABSTRACTOAUTH2_H
+
+#ifndef QT_NO_HTTP
+
+#include <QtCore/qdatetime.h>
+
+#include <QtNetworkAuth/qoauthglobal.h>
+#include <QtNetworkAuth/qabstractoauth.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractOAuth2Private;
+class Q_OAUTH_EXPORT QAbstractOAuth2 : public QAbstractOAuth
+{
+ Q_OBJECT
+ Q_PROPERTY(QString scope READ scope WRITE setScope NOTIFY scopeChanged)
+ Q_PROPERTY(QString userAgent READ userAgent WRITE setUserAgent NOTIFY userAgentChanged)
+ Q_PROPERTY(QString clientIdentifier
+ READ clientIdentifier
+ WRITE setClientIdentifier
+ NOTIFY clientIdentifierChanged)
+ Q_PROPERTY(QString clientIdentifierSharedKey
+ READ clientIdentifierSharedKey
+ WRITE setClientIdentifierSharedKey
+ NOTIFY clientIdentifierSharedKeyChanged)
+ Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged)
+ Q_PROPERTY(QDateTime expiration READ expirationAt NOTIFY expirationAtChanged)
+
+public:
+ explicit QAbstractOAuth2(QObject *parent = nullptr);
+ explicit QAbstractOAuth2(QNetworkAccessManager *manager, QObject *parent = nullptr);
+ ~QAbstractOAuth2();
+
+ Q_INVOKABLE virtual QUrl createAuthenticatedUrl(const QUrl &url,
+ const QVariantMap &parameters = QVariantMap());
+ Q_INVOKABLE virtual QNetworkReply *head(const QUrl &url,
+ const QVariantMap &parameters = QVariantMap()) override;
+ Q_INVOKABLE virtual QNetworkReply *get(const QUrl &url,
+ const QVariantMap &parameters = QVariantMap()) override;
+ Q_INVOKABLE virtual QNetworkReply *post(const QUrl &url,
+ const QVariantMap &parameters = QVariantMap()) override;
+ Q_INVOKABLE virtual QNetworkReply *deleteResource(const QUrl &url,
+ const QVariantMap &parameters = QVariantMap()) override;
+
+ QString scope() const;
+ void setScope(const QString &scope);
+
+ QString userAgent() const;
+ void setUserAgent(const QString &userAgent);
+
+ virtual QString responseType() const = 0;
+
+ QString clientIdentifier() const override;
+ void setClientIdentifier(const QString &clientIdentifier) override;
+ QString clientIdentifierSharedKey() const;
+ void setClientIdentifierSharedKey(const QString &clientIdentifierSharedKey);
+
+ QString token() const override;
+ void setToken(const QString &token) override;
+
+ QString state() const;
+ void setState(const QString &state);
+
+ QDateTime expirationAt() const;
+
+Q_SIGNALS:
+ void scopeChanged(const QString &scope);
+ void userAgentChanged(const QString &userAgent);
+ void clientIdentifierChanged(const QString &clientIdentifier);
+ void clientIdentifierSharedKeyChanged(const QString &clientIdentifierSharedKey);
+ void stateChanged(const QString &state);
+ void expirationAtChanged(const QDateTime &expiration);
+
+ void error(const QString &error, const QString &errorDescription, const QUrl &uri);
+ void authorizationCallbackReceived(const QVariantMap &data);
+
+protected:
+ explicit QAbstractOAuth2(QAbstractOAuth2Private &, QObject *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QAbstractOAuth2)
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QABSTRACTOAUTH2_H
diff --git a/src/oauth/qabstractoauth2_p.h b/src/oauth/qabstractoauth2_p.h
new file mode 100644
index 0000000..c9a8ec1
--- /dev/null
+++ b/src/oauth/qabstractoauth2_p.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QABSTRACTOAUTH2_P_H
+#define QABSTRACTOAUTH2_P_H
+
+#ifndef QT_NO_HTTP
+
+#include <private/qabstractoauth_p.h>
+
+#include <QtNetworkAuth/qoauthglobal.h>
+#include <QtNetworkAuth/qabstractoauth2.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qpointer.h>
+
+#include <QtNetwork/qnetworkreply.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkAccessManager;
+
+class QAbstractOAuth2Private : public QAbstractOAuthPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractOAuth2)
+
+public:
+ QAbstractOAuth2Private(const QPair<QString, QString> &clientCredentials,
+ const QUrl &authorizationUrl, QNetworkAccessManager *manager = nullptr);
+ QAbstractOAuth2Private(QNetworkAccessManager *manager = nullptr);
+ ~QAbstractOAuth2Private();
+
+ static QString generateRandomState();
+ QNetworkRequest createRequest(const QUrl &url, const QVariantMap &parameters);
+
+ QPair<QString, QString> clientCredentials;
+ QString token;
+ QString scope;
+ QString state = generateRandomState();
+ QString userAgent = QStringLiteral("QtOAuth/1.0 (+https://www.qt.io)");
+ const QString bearerFormat = QStringLiteral("Bearer %1"); // Case sensitive
+ QDateTime expiresAt;
+ QString refreshToken;
+
+ struct OAuth2KeyString
+ {
+ static const QString accessToken;
+ static const QString apiKey;
+ static const QString clientIdentifier;
+ static const QString clientSharedSecret;
+ static const QString code;
+ static const QString error;
+ static const QString errorDescription;
+ static const QString errorUri;
+ static const QString expiresIn;
+ static const QString grantType;
+ static const QString redirectUri;
+ static const QString refreshToken;
+ static const QString responseType;
+ static const QString scope;
+ static const QString state;
+ static const QString tokenType;
+ };
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QABSTRACTOAUTH2_P_H
diff --git a/src/oauth/qabstractoauth_p.h b/src/oauth/qabstractoauth_p.h
new file mode 100644
index 0000000..214108c
--- /dev/null
+++ b/src/oauth/qabstractoauth_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QABSTRACTQOAUTH_P_H
+#define QABSTRACTQOAUTH_P_H
+
+#ifndef QT_NO_HTTP
+
+#include <private/qobject_p.h>
+
+#include <QtNetworkAuth/qoauthglobal.h>
+#include <QtNetworkAuth/qabstractoauth.h>
+#include <QtNetworkAuth/qoauthoobreplyhandler.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qscopedpointer.h>
+
+#include <QtNetwork/qtcpserver.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+QT_BEGIN_NAMESPACE
+
+class QUrlQuery;
+
+class QAbstractOAuthPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractOAuth)
+
+public:
+ QAbstractOAuthPrivate(QNetworkAccessManager *manager);
+ QAbstractOAuthPrivate(const QUrl &authorizationUrl, QNetworkAccessManager *manager);
+ ~QAbstractOAuthPrivate();
+
+ QNetworkAccessManager *networkAccessManager();
+ void setStatus(QAbstractOAuth::Status status);
+ static QByteArray generateRandomString(quint8 length);
+
+ // Resource Owner Authorization: https://tools.ietf.org/html/rfc5849#section-2.2
+ QUrl authorizationUrl;
+ QVariantMap extraTokens;
+ QAbstractOAuth::Status status = QAbstractOAuth::Status::NotAuthenticated;
+ QNetworkAccessManager::Operation operation;
+ QPointer<QAbstractOAuthReplyHandler> replyHandler;
+ QScopedPointer<QOAuthOobReplyHandler> defaultReplyHandler;
+ QPointer<QNetworkAccessManager> networkAccessManagerPointer;
+ QAbstractOAuth::ModifyParametersFunction modifyParametersFunction;
+
+ static QUrlQuery createQuery(const QVariantMap &parameters);
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QABSTRACTQOAUTH_H
diff --git a/src/oauth/qabstractoauthreplyhandler.cpp b/src/oauth/qabstractoauthreplyhandler.cpp
new file mode 100644
index 0000000..6237732
--- /dev/null
+++ b/src/oauth/qabstractoauthreplyhandler.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_HTTP
+
+#include "qabstractoauthreplyhandler.h"
+
+QT_BEGIN_NAMESPACE
+
+QAbstractOAuthReplyHandler::QAbstractOAuthReplyHandler(QObject *parent)
+ : QObject(parent)
+{}
+
+QAbstractOAuthReplyHandler::~QAbstractOAuthReplyHandler()
+{}
+
+QAbstractOAuthReplyHandler::QAbstractOAuthReplyHandler(QObjectPrivate &d, QObject *parent)
+ : QObject(d, parent)
+{}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
diff --git a/src/oauth/qabstractoauthreplyhandler.h b/src/oauth/qabstractoauthreplyhandler.h
new file mode 100644
index 0000000..e5cddb1
--- /dev/null
+++ b/src/oauth/qabstractoauthreplyhandler.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTOAUTHREPLYHANDLER_H
+#define QABSTRACTOAUTHREPLYHANDLER_H
+
+#ifndef QT_NO_HTTP
+
+#include <QtNetworkAuth/qoauthglobal.h>
+#include <QtNetworkAuth/qabstractoauth.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_OAUTH_EXPORT QAbstractOAuthReplyHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QAbstractOAuthReplyHandler(QObject *parent = nullptr);
+ virtual ~QAbstractOAuthReplyHandler();
+
+ virtual QString callback() const = 0;
+
+public Q_SLOTS:
+ virtual void networkReplyFinished(QNetworkReply *reply) = 0;
+
+Q_SIGNALS:
+ void callbackReceived(const QVariantMap &values);
+ void tokensReceived(const QVariantMap &tokens);
+
+ void replyDataReceived(const QByteArray &data);
+ void callbackDataReceived(const QByteArray &data);
+
+protected:
+ QAbstractOAuthReplyHandler(QObjectPrivate &d, QObject *parent = nullptr);
+
+private:
+ Q_DISABLE_COPY(QAbstractOAuthReplyHandler)
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QABSTRACTOAUTHREPLYHANDLER_H
diff --git a/src/oauth/qoauth1.cpp b/src/oauth/qoauth1.cpp
new file mode 100644
index 0000000..cd6133e
--- /dev/null
+++ b/src/oauth/qoauth1.cpp
@@ -0,0 +1,654 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_HTTP
+
+#include "qoauth1.h"
+#include "qoauth1_p.h"
+#include "qoauth1signature.h"
+#include "qoauthoobreplyhandler.h"
+#include "qoauthhttpserverreplyhandler.h"
+
+#include <QtCore/qmap.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qurlquery.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qmessageauthenticationcode.h>
+
+#include <QtNetwork/qnetworkreply.h>
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+QT_BEGIN_NAMESPACE
+
+using Key = QOAuth1Private::OAuth1KeyString;
+const QString Key::oauthCallback = QStringLiteral("oauth_callback");
+const QString Key::oauthCallbackConfirmed = QStringLiteral("oauth_callback_confirmed");
+const QString Key::oauthConsumerKey = QStringLiteral("oauth_consumer_key");
+const QString Key::oauthNonce = QStringLiteral("oauth_nonce");
+const QString Key::oauthSignature = QStringLiteral("oauth_signature");
+const QString Key::oauthSignatureMethod = QStringLiteral("oauth_signature_method");
+const QString Key::oauthTimestamp = QStringLiteral("oauth_timestamp");
+const QString Key::oauthToken = QStringLiteral("oauth_token");
+const QString Key::oauthTokenSecret = QStringLiteral("oauth_token_secret");
+const QString Key::oauthVerifier = QStringLiteral("oauth_verifier");
+const QString Key::oauthVersion = QStringLiteral("oauth_version");
+
+static auto networkReplyErrorFunctionPointer = static_cast<void(QNetworkReply::*)(
+ QNetworkReply::NetworkError)>(&QNetworkReply::error);
+
+QOAuth1Private::QOAuth1Private(QNetworkAccessManager *networkAccessManager)
+ : QAbstractOAuthPrivate(networkAccessManager)
+{
+ qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
+}
+
+void QOAuth1Private::appendCommonHeaders(QVariantMap *headers)
+{
+ const auto currentDateTime = QDateTime::currentDateTimeUtc();
+
+ headers->insert(Key::oauthNonce, QOAuth1::nonce());
+ headers->insert(Key::oauthConsumerKey, clientCredentials.first);
+ headers->insert(Key::oauthTimestamp, QString::number(currentDateTime.toTime_t()));
+ headers->insert(Key::oauthVersion, oauthVersion);
+ headers->insert(Key::oauthSignatureMethod, signatureMethodString().toUtf8());
+}
+
+void QOAuth1Private::appendSignature(QAbstractOAuth::Stage stage,
+ QVariantMap *headers,
+ const QUrl &url,
+ QNetworkAccessManager::Operation operation,
+ const QVariantMap parameters)
+{
+ QByteArray signature;
+ {
+ QVariantMap allParameters = QVariantMap(*headers).unite(parameters);
+ if (modifyParametersFunction)
+ modifyParametersFunction(stage, &allParameters);
+ signature = generateSignature(allParameters, url, operation);
+ }
+ headers->insert(Key::oauthSignature, signature);
+}
+
+QNetworkReply *QOAuth1Private::requestToken(QNetworkAccessManager::Operation operation,
+ const QUrl &url,
+ const QPair<QString, QString> &token,
+ const QVariantMap &parameters)
+{
+ Q_Q(QOAuth1);
+ if (Q_UNLIKELY(!networkAccessManager())) {
+ qWarning("QOAuth1Private::requestToken: QNetworkAccessManager not available");
+ return nullptr;
+ }
+ if (Q_UNLIKELY(url.isEmpty())) {
+ qWarning("QOAuth1Private::requestToken: Request Url not set");
+ return nullptr;
+ }
+ if (Q_UNLIKELY(operation != QNetworkAccessManager::GetOperation &&
+ operation != QNetworkAccessManager::PostOperation)) {
+ qWarning("QOAuth1Private::requestToken: Operation not supported");
+ return nullptr;
+ }
+
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
+
+ QAbstractOAuth::Stage stage = QAbstractOAuth::Stage::RequestingTemporaryCredentials;
+ QVariantMap headers;
+ appendCommonHeaders(&headers);
+ headers.insert(Key::oauthCallback, q->callback());
+ if (!token.first.isEmpty()) {
+ headers.insert(Key::oauthToken, token.first);
+ stage = QAbstractOAuth::Stage::RequestingAccessToken;
+ }
+ appendSignature(stage, &headers, url, operation, parameters);
+
+ request.setRawHeader("Authorization", q->generateAuthorizationHeader(headers));
+
+ QNetworkReply *reply = nullptr;
+ if (operation == QNetworkAccessManager::GetOperation) {
+ if (parameters.size() > 0) {
+ QUrl url = request.url();
+ url.setQuery(QOAuth1Private::createQuery(parameters));
+ request.setUrl(url);
+ }
+ reply = networkAccessManager()->get(request);
+ }
+ else if (operation == QNetworkAccessManager::PostOperation) {
+ QUrlQuery query = QOAuth1Private::createQuery(parameters);
+ const QByteArray data = query.toString(QUrl::FullyEncoded).toUtf8();
+ request.setHeader(QNetworkRequest::ContentTypeHeader,
+ QStringLiteral("application/x-www-form-urlencoded"));
+ reply = networkAccessManager()->post(request, data);
+ }
+
+ connect(reply, networkReplyErrorFunctionPointer, this, &QOAuth1Private::_q_onTokenRequestError);
+
+ QAbstractOAuthReplyHandler *handler = replyHandler ? replyHandler.data()
+ : defaultReplyHandler.data();
+ QObject::connect(reply, &QNetworkReply::finished,
+ std::bind(&QAbstractOAuthReplyHandler::networkReplyFinished, handler, reply));
+ connect(handler, &QAbstractOAuthReplyHandler::tokensReceived, this,
+ &QOAuth1Private::_q_tokensReceived);
+
+ return reply;
+}
+
+QString QOAuth1Private::signatureMethodString() const
+{
+ switch (signatureMethod) { // No default: intended
+ case QOAuth1::SignatureMethod::PlainText:
+ return QStringLiteral("PLAINTEXT");
+ case QOAuth1::SignatureMethod::Hmac_Sha1:
+ return QStringLiteral("HMAC-SHA1");
+ case QOAuth1::SignatureMethod::Rsa_Sha1:
+ qFatal("RSA-SHA1 signature method not supported");
+ return QStringLiteral("RSA-SHA1");
+ }
+ qFatal("Invalid signature method");
+ return QString();
+}
+
+QByteArray QOAuth1Private::generateSignature(const QVariantMap &parameters,
+ const QUrl &url,
+ QNetworkAccessManager::Operation operation) const
+{
+ const QOAuth1Signature signature(url,
+ clientCredentials.second,
+ tokenCredentials.second,
+ static_cast<QOAuth1Signature::HttpRequestMethod>(operation),
+ parameters);
+
+ switch (signatureMethod) {
+ case QOAuth1::SignatureMethod::Hmac_Sha1:
+ return signature.hmacSha1().toBase64();
+ case QOAuth1::SignatureMethod::PlainText:
+ return signature.plainText(clientCredentials.first);
+ default:
+ qFatal("QOAuth1Private::generateSignature: Signature method not supported");
+ return QByteArray();
+ }
+}
+
+void QOAuth1Private::_q_onTokenRequestError(QNetworkReply::NetworkError error)
+{
+ Q_Q(QOAuth1);
+ Q_UNUSED(error);
+ Q_EMIT q->requestFailed(QAbstractOAuth::Error::NetworkError);
+}
+
+void QOAuth1Private::_q_tokensReceived(const QVariantMap &tokens)
+{
+ Q_Q(QOAuth1);
+
+ QPair<QString, QString> credential(tokens.value(Key::oauthToken).toString(),
+ tokens.value(Key::oauthTokenSecret).toString());
+ switch (status) {
+ case QAbstractOAuth::Status::NotAuthenticated:
+ if (tokens.value(Key::oauthCallbackConfirmed, true).toBool()) {
+ q->setTokenCredentials(credential);
+ setStatus(QAbstractOAuth::Status::TemporaryCredentialsReceived);
+ } else {
+ Q_EMIT q->requestFailed(QAbstractOAuth::Error::OAuthCallbackNotVerified);
+ }
+ break;
+ case QAbstractOAuth::Status::TemporaryCredentialsReceived:
+ q->setTokenCredentials(credential);
+ setStatus(QAbstractOAuth::Status::Granted);
+ break;
+ case QAbstractOAuth::Status::Granted:
+ case QAbstractOAuth::Status::RefreshingToken:
+ break;
+ }
+
+}
+
+QOAuth1::QOAuth1(QObject *parent)
+ : QAbstractOAuth(*new QOAuth1Private, parent)
+{}
+
+QOAuth1::QOAuth1(QNetworkAccessManager *manager, QObject *parent)
+ : QAbstractOAuth(*new QOAuth1Private(manager), parent)
+{}
+
+QOAuth1::QOAuth1(const QString &clientIdentifier,
+ const QString &clientSharedSecret,
+ QNetworkAccessManager *manager,
+ QObject *parent)
+ : QAbstractOAuth(*new QOAuth1Private(manager), parent)
+{
+ Q_D(QOAuth1);
+ d->clientCredentials.first = clientIdentifier;
+ d->clientCredentials.second = clientSharedSecret;
+}
+
+QOAuth1::~QOAuth1()
+{}
+
+QString QOAuth1::clientIdentifier() const
+{
+ Q_D(const QOAuth1);
+ return d->clientCredentials.first;
+}
+
+void QOAuth1::setClientIdentifier(const QString &clientIdentifier)
+{
+ Q_D(QOAuth1);
+ if (d->clientCredentials.first != clientIdentifier) {
+ d->clientCredentials.first = clientIdentifier;
+ Q_EMIT clientIdentifierChanged(clientIdentifier);
+ }
+}
+
+QString QOAuth1::clientSharedSecret() const
+{
+ Q_D(const QOAuth1);
+ return d->clientCredentials.second;
+}
+
+void QOAuth1::setClientSharedSecret(const QString &clientSharedSecret)
+{
+ Q_D(QOAuth1);
+ if (d->clientCredentials.second != clientSharedSecret) {
+ d->clientCredentials.second = clientSharedSecret;
+ Q_EMIT clientSharedSecretChanged(clientSharedSecret);
+ }
+}
+
+QPair<QString, QString> QOAuth1::clientCredentials() const
+{
+ Q_D(const QOAuth1);
+ return d->clientCredentials;
+}
+
+void QOAuth1::setClientCredentials(const QPair<QString, QString> &clientCredentials)
+{
+ setClientCredentials(clientCredentials.first, clientCredentials.second);
+}
+
+void QOAuth1::setClientCredentials(const QString &clientIdentifier,
+ const QString &clientSharedSecret)
+{
+ setClientIdentifier(clientIdentifier);
+ setClientSharedSecret(clientSharedSecret);
+}
+
+QString QOAuth1::token() const
+{
+ Q_D(const QOAuth1);
+ return d->tokenCredentials.first;
+}
+
+void QOAuth1::setToken(const QString &token)
+{
+ Q_D(QOAuth1);
+ if (d->tokenCredentials.first != token) {
+ d->tokenCredentials.first = token;
+ Q_EMIT tokenChanged(token);
+ }
+}
+
+QString QOAuth1::tokenSecret() const
+{
+ Q_D(const QOAuth1);
+ return d->tokenCredentials.second;
+}
+
+void QOAuth1::setTokenSecret(const QString &tokenSecret)
+{
+ Q_D(QOAuth1);
+ if (d->tokenCredentials.second != tokenSecret) {
+ d->tokenCredentials.second = tokenSecret;
+ Q_EMIT tokenSecretChanged(tokenSecret);
+ }
+}
+
+QPair<QString, QString> QOAuth1::tokenCredentials() const
+{
+ Q_D(const QOAuth1);
+ return d->tokenCredentials;
+}
+
+void QOAuth1::setTokenCredentials(const QPair<QString, QString> &tokenCredentials)
+{
+ setTokenCredentials(tokenCredentials.first, tokenCredentials.second);
+}
+
+void QOAuth1::setTokenCredentials(const QString &token, const QString &tokenSecret)
+{
+ setToken(token);
+ setTokenSecret(tokenSecret);
+}
+
+QUrl QOAuth1::temporaryCredentialsUrl() const
+{
+ Q_D(const QOAuth1);
+ return d->temporaryCredentialsUrl;
+}
+
+void QOAuth1::setTemporaryCredentialsUrl(const QUrl &url)
+{
+ Q_D(QOAuth1);
+ if (d->temporaryCredentialsUrl != url) {
+ d->temporaryCredentialsUrl = url;
+ Q_EMIT temporaryCredentialsUrlChanged(url);
+ }
+}
+
+QUrl QOAuth1::tokenCredentialsUrl() const
+{
+ Q_D(const QOAuth1);
+ return d->tokenCredentialsUrl;
+}
+
+void QOAuth1::setTokenCredentialsUrl(const QUrl &url)
+{
+ Q_D(QOAuth1);
+ if (d->tokenCredentialsUrl != url) {
+ d->tokenCredentialsUrl = url;
+ Q_EMIT tokenCredentialsUrlChanged(url);
+ }
+}
+
+QOAuth1::SignatureMethod QOAuth1::signatureMethod() const
+{
+ Q_D(const QOAuth1);
+ return d->signatureMethod;
+}
+
+void QOAuth1::setSignatureMethod(QOAuth1::SignatureMethod value)
+{
+ Q_D(QOAuth1);
+ if (d->signatureMethod != value) {
+ d->signatureMethod = value;
+ Q_EMIT signatureMethodChanged(value);
+ }
+}
+
+QNetworkReply *QOAuth1::head(const QUrl &url, const QVariantMap &parameters)
+{
+ Q_D(QOAuth1);
+ if (!d->networkAccessManager()) {
+ qWarning("QOAuth1::head: QNetworkAccessManager not available");
+ return nullptr;
+ }
+ QNetworkRequest request(url);
+ setup(&request, parameters, QNetworkAccessManager::HeadOperation);
+ return d->networkAccessManager()->head(request);
+}
+
+QNetworkReply *QOAuth1::get(const QUrl &url, const QVariantMap &parameters)
+{
+ Q_D(QOAuth1);
+ if (!d->networkAccessManager()) {
+ qWarning("QOAuth1::get: QNetworkAccessManager not available");
+ return nullptr;
+ }
+ QNetworkRequest request(url);
+ setup(&request, parameters, QNetworkAccessManager::GetOperation);
+ QNetworkReply *reply = d->networkAccessManager()->get(request);
+ connect(reply, &QNetworkReply::finished, std::bind(&QAbstractOAuth::finished, this, reply));
+ return reply;
+}
+
+QNetworkReply *QOAuth1::post(const QUrl &url, const QVariantMap &parameters)
+{
+ Q_D(QOAuth1);
+ if (!d->networkAccessManager()) {
+ qWarning("QOAuth1::post: QNetworkAccessManager not available");
+ return nullptr;
+ }
+ QNetworkRequest request(url);
+ setup(&request, parameters, QNetworkAccessManager::PostOperation);
+
+ QUrlQuery query;
+ for (auto it = parameters.begin(), end = parameters.end(); it != end; ++it)
+ query.addQueryItem(it.key(), it.value().toString());
+ QString data = query.toString(QUrl::FullyEncoded);
+ QNetworkReply *reply = d->networkAccessManager()->post(request, data.toUtf8());
+ connect(reply, &QNetworkReply::finished, std::bind(&QAbstractOAuth::finished, this, reply));
+ return reply;
+}
+
+QNetworkReply *QOAuth1::deleteResource(const QUrl &url, const QVariantMap &parameters)
+{
+ Q_D(QOAuth1);
+ if (!d->networkAccessManager()) {
+ qWarning("QOAuth1::deleteResource: QNetworkAccessManager not available");
+ return nullptr;
+ }
+ QNetworkRequest request(url);
+ setup(&request, parameters, QNetworkAccessManager::DeleteOperation);
+ QNetworkReply *reply = d->networkAccessManager()->deleteResource(request);
+ connect(reply, &QNetworkReply::finished, std::bind(&QAbstractOAuth::finished, this, reply));
+ return reply;
+}
+
+QNetworkReply *QOAuth1::requestTemporaryCredentials(QNetworkAccessManager::Operation operation,
+ const QUrl &url,
+ const QVariantMap &parameters)
+{
+ // https://tools.ietf.org/html/rfc5849#section-2.1
+ Q_D(QOAuth1);
+ d->tokenCredentials = QPair<QString, QString>();
+ return d->requestToken(operation, url, d->tokenCredentials, parameters);
+}
+
+QNetworkReply *QOAuth1::requestTokenCredentials(QNetworkAccessManager::Operation operation,
+ const QUrl &url,
+ const QPair<QString, QString> &temporaryToken,
+ const QVariantMap &parameters)
+{
+ Q_D(QOAuth1);
+ return d->requestToken(operation, url, temporaryToken, parameters);
+}
+
+void QOAuth1::setup(QNetworkRequest *request,
+ const QVariantMap &signingParameters,
+ QNetworkAccessManager::Operation operation)
+{
+ Q_D(const QOAuth1);
+
+ QVariantMap oauthParams;
+ QVariantMap otherParams = signingParameters;
+ // Adding parameters located in the query
+ {
+ auto queryItems = QUrlQuery(request->url().query()).queryItems();
+ for (auto it = queryItems.begin(), end = queryItems.end(); it != end; ++it)
+ otherParams.insert(it->first, it->second);
+ }
+
+ const auto currentDateTime = QDateTime::currentDateTimeUtc();
+
+ oauthParams.insert(Key::oauthConsumerKey, d->clientCredentials.first);
+ oauthParams.insert(Key::oauthVersion, QStringLiteral("1.0"));
+ oauthParams.insert(Key::oauthToken, d->tokenCredentials.first);
+ oauthParams.insert(Key::oauthSignatureMethod, d->signatureMethodString());
+ oauthParams.insert(Key::oauthNonce, QOAuth1::nonce());
+ oauthParams.insert(Key::oauthTimestamp, QString::number(currentDateTime.toTime_t()));
+
+ // Add signature parameter
+ {
+ const auto parameters = QVariantMap(oauthParams).unite(signingParameters);
+ const auto signature = d->generateSignature(parameters, request->url(), operation);
+ oauthParams.insert(Key::oauthSignature, signature);
+ }
+
+ if (operation == QNetworkAccessManager::GetOperation) {
+ if (signingParameters.size()) {
+ QUrl url = request->url();
+ QUrlQuery query;
+ for (auto it = signingParameters.begin(), end = signingParameters.end(); it != end;
+ ++it)
+ query.addQueryItem(it.key(), it.value().toString());
+ url.setQuery(query);
+ request->setUrl(url);
+ }
+ }
+
+ request->setRawHeader("Authorization", generateAuthorizationHeader(oauthParams));
+
+ if (operation == QNetworkAccessManager::PostOperation)
+ request->setHeader(QNetworkRequest::ContentTypeHeader,
+ QStringLiteral("application/x-www-form-urlencoded"));
+}
+
+QByteArray QOAuth1::nonce()
+{
+ // https://tools.ietf.org/html/rfc5849#section-3.3
+ return QAbstractOAuth::generateRandomString(8);
+}
+
+QByteArray QOAuth1::signature(const QVariantMap &parameters,
+ const QUrl &url,
+ QNetworkAccessManager::Operation op,
+ const QString &clientSharedSecret,
+ const QString &tokenSecret)
+{
+ auto method = static_cast<QOAuth1Signature::HttpRequestMethod>(op);
+ QOAuth1Signature signature(url, clientSharedSecret, tokenSecret, method, parameters);
+ return signature.hmacSha1().toBase64();
+}
+
+QByteArray QOAuth1::generateAuthorizationHeader(const QVariantMap &oauthParams)
+{
+ // https://tools.ietf.org/html/rfc5849#section-3.5.1
+ // TODO Add realm parameter support
+ bool first = true;
+ QString ret(QStringLiteral("OAuth "));
+ QVariantMap headers(oauthParams);
+ for (auto it = headers.begin(), end = headers.end(); it != end; ++it) {
+ if (first)
+ first = false;
+ else
+ ret += QLatin1String(",");
+ ret += it.key() +
+ QLatin1String("=\"") +
+ QString::fromUtf8(QUrl::toPercentEncoding(it.value().toString())) +
+ QLatin1Char('\"');
+ }
+ return ret.toUtf8();
+}
+
+void QOAuth1::grant()
+{
+ // https://tools.ietf.org/html/rfc5849#section-2
+ Q_D(QOAuth1);
+ using Key = QOAuth1Private::OAuth1KeyString;
+
+ if (d->temporaryCredentialsUrl.isEmpty()) {
+ qWarning("QOAuth1::grant: requestTokenUrl is empty");
+ return;
+ }
+ if (d->tokenCredentialsUrl.isEmpty()) {
+ qWarning("QOAuth1::grant: authorizationGrantUrl is empty");
+ return;
+ }
+ if (!d->tokenCredentials.first.isEmpty()) {
+ qWarning("QOAuth1::grant: Already authenticated");
+ return;
+ }
+
+ QMetaObject::Connection connection;
+ connection = connect(this, &QAbstractOAuth::statusChanged, [&](Status status) {
+ Q_D(QOAuth1);
+
+ if (status == Status::TemporaryCredentialsReceived) {
+ if (d->authorizationUrl.isEmpty()) {
+ // try upgrading token without verifier
+ auto reply = requestTokenCredentials(QNetworkAccessManager::PostOperation,
+ d->tokenCredentialsUrl,
+ d->tokenCredentials);
+ connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
+ } else {
+ QVariantMap parameters;
+ parameters.insert(Key::oauthToken, d->tokenCredentials.first);
+ if (d->modifyParametersFunction)
+ d->modifyParametersFunction(Stage::RequestingAuthorization, &parameters);
+
+ // https://tools.ietf.org/html/rfc5849#section-2.2
+ resourceOwnerAuthorization(d->authorizationUrl, parameters);
+ }
+ } else if (status == Status::Granted) {
+ Q_EMIT granted();
+ } else {
+ // Inherit class called QAbstractOAuth::setStatus(Status::NotAuthenticated);
+ setTokenCredentials(QString(), QString());
+ disconnect(connection);
+ }
+ });
+
+ auto httpReplyHandler = qobject_cast<QOAuthHttpServerReplyHandler*>(replyHandler());
+ if (httpReplyHandler) {
+ connect(httpReplyHandler, &QOAuthHttpServerReplyHandler::callbackReceived, [&](
+ const QVariantMap &values) {
+ QString verifier = values.value(Key::oauthVerifier).toString();
+ if (verifier.isEmpty()) {
+ qWarning("%s not found in the callback", qPrintable(Key::oauthVerifier));
+ return;
+ }
+ continueGrantWithVerifier(verifier);
+ });
+ }
+
+ // requesting temporary credentials
+ auto reply = requestTemporaryCredentials(QNetworkAccessManager::PostOperation,
+ d->temporaryCredentialsUrl);
+ connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
+}
+
+void QOAuth1::continueGrantWithVerifier(const QString &verifier)
+{
+ // https://tools.ietf.org/html/rfc5849#section-2.3
+ Q_D(QOAuth1);
+
+ QVariantMap parameters;
+ parameters.insert(Key::oauthVerifier, verifier);
+ auto reply = requestTokenCredentials(QNetworkAccessManager::PostOperation,
+ d->tokenCredentialsUrl,
+ d->tokenCredentials,
+ parameters);
+ connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
diff --git a/src/oauth/qoauth1.h b/src/oauth/qoauth1.h
new file mode 100644
index 0000000..3d13645
--- /dev/null
+++ b/src/oauth/qoauth1.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOAUTH1_H
+#define QOAUTH1_H
+
+#ifndef QT_NO_HTTP
+
+#include <QtNetworkAuth/qoauthglobal.h>
+#include <QtNetworkAuth/qabstractoauth.h>
+
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOAuth1Private;
+class Q_OAUTH_EXPORT QOAuth1: public QAbstractOAuth
+{
+ Q_OBJECT
+
+public:
+ enum class SignatureMethod {
+ Hmac_Sha1,
+ Rsa_Sha1,
+ PlainText
+ };
+
+ Q_ENUM(SignatureMethod)
+
+ explicit QOAuth1(QObject *parent = nullptr);
+ explicit QOAuth1(QNetworkAccessManager *manager,
+ QObject *parent = nullptr);
+
+ QOAuth1(const QString &clientIdentifier,
+ const QString &clientSharedSecret,
+ QNetworkAccessManager *manager,
+ QObject *parent = nullptr);
+
+ ~QOAuth1();
+
+ // Client credentials
+ QString clientIdentifier() const override;
+ void setClientIdentifier(const QString &clientIdentifier) override;
+ QString clientSharedSecret() const;
+ void setClientSharedSecret(const QString &clientSharedSecret);
+ QPair<QString, QString> clientCredentials() const;
+ void setClientCredentials(const QPair<QString, QString> &clientCredentials);
+ void setClientCredentials(const QString &clientIdentifier, const QString &clientSharedSecret);
+
+ // Token credentials: https://tools.ietf.org/html/rfc5849#section-2.3
+ QString token() const override;
+ void setToken(const QString &token) override;
+ QString tokenSecret() const;
+ void setTokenSecret(const QString &tokenSecret);
+ QPair<QString, QString> tokenCredentials() const;
+ void setTokenCredentials(const QPair<QString, QString> &tokenCredentials);
+ void setTokenCredentials(const QString &token, const QString &tokenSecret);
+
+ // Temporary Credentials: https://tools.ietf.org/html/rfc5849#section-2.1
+ QUrl temporaryCredentialsUrl() const;
+ void setTemporaryCredentialsUrl(const QUrl &url);
+
+ // Token Credentials: https://tools.ietf.org/html/rfc5849#section-2.3
+ QUrl tokenCredentialsUrl() const;
+ void setTokenCredentialsUrl(const QUrl &url);
+
+ // Signature method: https://tools.ietf.org/html/rfc5849#section-3.4
+ SignatureMethod signatureMethod() const;
+ void setSignatureMethod(SignatureMethod value);
+
+public:
+ QNetworkReply *head(const QUrl &url, const QVariantMap &parameters = QVariantMap()) override;
+ QNetworkReply *get(const QUrl &url, const QVariantMap &parameters = QVariantMap()) override;
+
+ QNetworkReply *post(const QUrl &url, const QVariantMap &parameters = QVariantMap()) override;
+ QNetworkReply *deleteResource(const QUrl &url,
+ const QVariantMap &parameters = QVariantMap()) override;
+
+public Q_SLOTS:
+ void grant() override;
+ void continueGrantWithVerifier(const QString &verifier);
+
+Q_SIGNALS:
+ void signatureMethodChanged(SignatureMethod method);
+ void clientSharedSecretChanged(const QString &credential);
+ void tokenSecretChanged(const QString &token);
+ void temporaryCredentialsUrlChanged(const QUrl &url);
+ void tokenCredentialsUrlChanged(const QUrl &url);
+
+protected:
+ QNetworkReply *requestTemporaryCredentials(QNetworkAccessManager::Operation operation,
+ const QUrl &url,
+ const QVariantMap &parameters = QVariantMap());
+
+ QNetworkReply *requestTokenCredentials(QNetworkAccessManager::Operation operation,
+ const QUrl &url,
+ const QPair<QString, QString> &temporaryToken,
+ const QVariantMap &parameters = QVariantMap());
+
+ void setup(QNetworkRequest *request,
+ const QVariantMap &signingParameters,
+ QNetworkAccessManager::Operation operation);
+
+ static QByteArray nonce();
+ static QByteArray generateAuthorizationHeader(const QVariantMap &oauthParams);
+
+ // Signature: https://tools.ietf.org/html/rfc5849#section-3.4
+ static QByteArray signature(const QVariantMap &parameters,
+ const QUrl &url,
+ QNetworkAccessManager::Operation op,
+ const QString &clientSharedSecret,
+ const QString &tokenSecret);
+
+private:
+ Q_DISABLE_COPY(QOAuth1)
+ Q_DECLARE_PRIVATE(QOAuth1)
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QOAUTH1_H
diff --git a/src/oauth/qoauth1_p.h b/src/oauth/qoauth1_p.h
new file mode 100644
index 0000000..167aed2
--- /dev/null
+++ b/src/oauth/qoauth1_p.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QOAUTH1_P_H
+#define QOAUTH1_P_H
+
+#ifndef QT_NO_HTTP
+
+#include <private/qabstractoauth_p.h>
+
+#include <QtNetworkAuth/qoauth1.h>
+#include <QtNetworkAuth/qoauthglobal.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qobject.h>
+
+#include <QtNetwork/qnetworkreply.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOAuth1Private : public QAbstractOAuthPrivate
+{
+ Q_DECLARE_PUBLIC(QOAuth1)
+
+public:
+ QOAuth1Private(QNetworkAccessManager *networkAccessManager = nullptr);
+
+ void appendCommonHeaders(QVariantMap *headers);
+ void appendSignature(QAbstractOAuth::Stage stage,
+ QVariantMap *headers,
+ const QUrl &url,
+ QNetworkAccessManager::Operation operation,
+ const QVariantMap parameters);
+
+ QNetworkReply *requestToken(QNetworkAccessManager::Operation operation,
+ const QUrl &url,
+ const QPair<QString, QString> &token,
+ const QVariantMap &additionalParameters);
+
+ QString signatureMethodString() const;
+ QByteArray generateSignature(const QVariantMap &parameters,
+ const QUrl &url,
+ QNetworkAccessManager::Operation operation) const;
+
+ void _q_onTokenRequestError(QNetworkReply::NetworkError error);
+ void _q_tokensReceived(const QVariantMap &tokens);
+
+ QPair<QString, QString> clientCredentials;
+ QPair<QString, QString> tokenCredentials;
+ QString verifier;
+ QUrl temporaryCredentialsUrl;
+ QUrl tokenCredentialsUrl;
+ QOAuth1::SignatureMethod signatureMethod = QOAuth1::SignatureMethod::Hmac_Sha1;
+ const QString oauthVersion = QStringLiteral("1.0");
+
+ struct OAuth1KeyString
+ {
+ static const QString oauthCallback;
+ static const QString oauthCallbackConfirmed;
+ static const QString oauthConsumerKey;
+ static const QString oauthNonce;
+ static const QString oauthSignature;
+ static const QString oauthSignatureMethod;
+ static const QString oauthTimestamp;
+ static const QString oauthToken;
+ static const QString oauthTokenSecret;
+ static const QString oauthVerifier;
+ static const QString oauthVersion;
+ };
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QOAUTH1_P_H
diff --git a/src/oauth/qoauth1signature.cpp b/src/oauth/qoauth1signature.cpp
new file mode 100644
index 0000000..238cf20
--- /dev/null
+++ b/src/oauth/qoauth1signature.cpp
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoauth1signature.h"
+#include "qoauth1signature_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qurlquery.h>
+#include <QtCore/qmessageauthenticationcode.h>
+
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+#include <functional>
+#include <type_traits>
+
+QT_BEGIN_NAMESPACE
+
+static_assert(static_cast<int>(QOAuth1Signature::HttpRequestMethod::Head) ==
+ static_cast<int>(QNetworkAccessManager::HeadOperation) &&
+ static_cast<int>(QOAuth1Signature::HttpRequestMethod::Get) ==
+ static_cast<int>(QNetworkAccessManager::GetOperation) &&
+ static_cast<int>(QOAuth1Signature::HttpRequestMethod::Put) ==
+ static_cast<int>(QNetworkAccessManager::PutOperation) &&
+ static_cast<int>(QOAuth1Signature::HttpRequestMethod::Post) ==
+ static_cast<int>(QNetworkAccessManager::PostOperation) &&
+ static_cast<int>(QOAuth1Signature::HttpRequestMethod::Delete) ==
+ static_cast<int>(QNetworkAccessManager::DeleteOperation),
+ "Invalid QOAuth1Signature::HttpRequestMethod enumeration values");
+
+QOAuth1SignaturePrivate QOAuth1SignaturePrivate::shared_null;
+
+QOAuth1SignaturePrivate::QOAuth1SignaturePrivate()
+{}
+
+QOAuth1SignaturePrivate::QOAuth1SignaturePrivate(const QUrl &url,
+ QOAuth1Signature::HttpRequestMethod method,
+ const QVariantMap &parameters,
+ const QString &clientSharedKey,
+ const QString &tokenSecret) :
+ method(method), url(url), clientSharedKey(clientSharedKey), tokenSecret(tokenSecret),
+ parameters(parameters)
+{}
+
+QByteArray QOAuth1SignaturePrivate::signatureBaseString() const
+{
+ // https://tools.ietf.org/html/rfc5849#section-3.4.1
+ QByteArray base;
+
+ switch (method) {
+ case QOAuth1Signature::HttpRequestMethod::Head:
+ base.append("HEAD");
+ break;
+ case QOAuth1Signature::HttpRequestMethod::Get:
+ base.append("GET");
+ break;
+ case QOAuth1Signature::HttpRequestMethod::Put:
+ base.append("PUT");
+ break;
+ case QOAuth1Signature::HttpRequestMethod::Post:
+ base.append("POST");
+ break;
+ case QOAuth1Signature::HttpRequestMethod::Delete:
+ base.append("DELETE");
+ break;
+ default:
+ qCritical("QOAuth1Signature: HttpRequestMethod not supported");
+ }
+ base.append('&');
+ base.append(QUrl::toPercentEncoding(url.toString(QUrl::RemoveQuery)) + "&");
+
+ QVariantMap p = parameters;
+ {
+ const auto queryItems = QUrlQuery(url.query()).queryItems();
+ for (auto it = queryItems.begin(), end = queryItems.end(); it != end; ++it)
+ p.insert(it->first, it->second);
+ }
+ base.append(encodeHeaders(p));
+ return base;
+}
+
+QByteArray QOAuth1SignaturePrivate::secret() const
+{
+ QByteArray secret;
+ secret.append(QUrl::toPercentEncoding(clientSharedKey));
+ secret.append('&');
+ secret.append(QUrl::toPercentEncoding(tokenSecret));
+ return secret;
+}
+
+QByteArray QOAuth1SignaturePrivate::parameterString(const QVariantMap &parameters)
+{
+ QByteArray ret;
+ auto previous = parameters.end();
+ for (auto it = parameters.begin(), end = parameters.end(); it != end; previous = it++) {
+ if (previous != parameters.end()) {
+ if (Q_UNLIKELY(previous.key() == it.key()))
+ qWarning("QOAuth: duplicated key %s", qPrintable(it.key()));
+ ret.append("&");
+ }
+ ret.append(QUrl::toPercentEncoding(it.key()));
+ ret.append("=");
+ ret.append(QUrl::toPercentEncoding(it.value().toString()));
+ }
+ return ret;
+}
+
+QByteArray QOAuth1SignaturePrivate::encodeHeaders(const QVariantMap &headers)
+{
+ return QUrl::toPercentEncoding(QString::fromLatin1(parameterString(headers)));
+}
+
+QOAuth1Signature::QOAuth1Signature(const QUrl &url, QOAuth1Signature::HttpRequestMethod method,
+ const QVariantMap &parameters) :
+ d(new QOAuth1SignaturePrivate(url, method, parameters))
+{}
+
+QOAuth1Signature::QOAuth1Signature(const QUrl &url, const QString &clientSharedKey,
+ const QString &tokenSecret, HttpRequestMethod method,
+ const QVariantMap &parameters) :
+ d(new QOAuth1SignaturePrivate(url, method, parameters, clientSharedKey, tokenSecret))
+{}
+
+QOAuth1Signature::QOAuth1Signature(const QOAuth1Signature &other) : d(other.d)
+{}
+
+QOAuth1Signature::QOAuth1Signature(QOAuth1Signature &&other) : d(other.d)
+{
+ other.d = &QOAuth1SignaturePrivate::shared_null;
+}
+
+QOAuth1Signature::~QOAuth1Signature()
+{}
+
+QOAuth1Signature::HttpRequestMethod QOAuth1Signature::httpRequestMethod() const
+{
+ return d->method;
+}
+
+void QOAuth1Signature::setHttpRequestMethod(QOAuth1Signature::HttpRequestMethod method)
+{
+ d->method = method;
+}
+
+QUrl QOAuth1Signature::url() const
+{
+ return d->url;
+}
+
+void QOAuth1Signature::setUrl(const QUrl &url)
+{
+ d->url = url;
+}
+
+QVariantMap QOAuth1Signature::parameters() const
+{
+ return d->parameters;
+}
+
+void QOAuth1Signature::setParameters(const QVariantMap &parameters)
+{
+ d->parameters = parameters;
+}
+
+void QOAuth1Signature::addRequestBody(const QUrlQuery &body)
+{
+ const auto list = body.queryItems();
+ for (auto it = list.begin(), end = list.end(); it != end; ++it)
+ d->parameters.insert(it->first, it->second);
+}
+
+void QOAuth1Signature::insert(const QString &key, const QVariant &value)
+{
+ d->parameters.insert(key, value);
+}
+
+QList<QString> QOAuth1Signature::keys() const
+{
+ return d->parameters.uniqueKeys();
+}
+
+QVariant QOAuth1Signature::take(const QString &key)
+{
+ return d->parameters.take(key);
+}
+
+QVariant QOAuth1Signature::value(const QString &key, const QVariant &defaultValue) const
+{
+ return d->parameters.value(key, defaultValue);
+}
+
+QString QOAuth1Signature::clientSharedKey() const
+{
+ return d->clientSharedKey;
+}
+
+void QOAuth1Signature::setClientSharedKey(const QString &secret)
+{
+ d->clientSharedKey = secret;
+}
+
+QString QOAuth1Signature::tokenSecret() const
+{
+ return d->tokenSecret;
+}
+
+void QOAuth1Signature::setTokenSecret(const QString &secret)
+{
+ d->tokenSecret = secret;
+}
+
+QByteArray QOAuth1Signature::hmacSha1() const
+{
+ QMessageAuthenticationCode code(QCryptographicHash::Sha1);
+ code.setKey(d->secret());
+ code.addData(d->signatureBaseString());
+ return code.result();
+}
+
+QByteArray QOAuth1Signature::rsaSha1() const
+{
+ qCritical("QOAuth1Signature::rsaSha1: RSA-SHA1 signing method not supported");
+ return QByteArray();
+}
+
+QByteArray QOAuth1Signature::plainText(const QString &clientIdentifier) const
+{
+ return plainText(clientIdentifier, d->clientSharedKey);
+}
+
+QByteArray QOAuth1Signature::plainText(const QString &clientIdentifier,
+ const QString clientSharedKey)
+{
+ QByteArray ret;
+ ret += clientIdentifier.toUtf8() + '&' + clientSharedKey.toUtf8();
+ return ret;
+}
+
+QByteArray QOAuth1Signature::plainText(const QPair<QString, QString> &clientCredentials)
+{
+ return plainText(clientCredentials.first, clientCredentials.second);
+}
+
+void QOAuth1Signature::swap(QOAuth1Signature &other)
+{
+ qSwap(d, other.d);
+}
+
+QOAuth1Signature &QOAuth1Signature::operator=(const QOAuth1Signature &other)
+{
+ if (d != other.d) {
+ QOAuth1Signature tmp(other);
+ tmp.swap(*this);
+ }
+ return *this;
+}
+
+QOAuth1Signature &QOAuth1Signature::operator=(QOAuth1Signature &&other)
+{
+ QOAuth1Signature moved(std::move(other));
+ swap(moved);
+ return *this;
+}
+
+QT_END_NAMESPACE
diff --git a/src/oauth/qoauth1signature.h b/src/oauth/qoauth1signature.h
new file mode 100644
index 0000000..c0d5719
--- /dev/null
+++ b/src/oauth/qoauth1signature.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOAUTH1SIGNATURE_H
+#define QOAUTH1SIGNATURE_H
+
+#ifndef QT_NO_HTTP
+
+#include <QtNetworkAuth/qoauthglobal.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QUrlQuery;
+
+class QOAuth1SignaturePrivate;
+class Q_OAUTH_EXPORT QOAuth1Signature
+{
+public:
+ enum class HttpRequestMethod {
+ Head = 1,
+ Get,
+ Put,
+ Post,
+ Delete,
+ Custom,
+
+ Unknown = 0
+ };
+
+ explicit QOAuth1Signature(const QUrl &url = QUrl(),
+ HttpRequestMethod method = HttpRequestMethod::Post,
+ const QVariantMap &parameters = QVariantMap());
+ QOAuth1Signature(const QUrl &url, const QString &clientSharedKey, const QString &tokenSecret,
+ HttpRequestMethod method = HttpRequestMethod::Post,
+ const QVariantMap &parameters = QVariantMap());
+ QOAuth1Signature(const QOAuth1Signature &other);
+ QOAuth1Signature(QOAuth1Signature &&other);
+ ~QOAuth1Signature();
+
+ HttpRequestMethod httpRequestMethod() const;
+ void setHttpRequestMethod(HttpRequestMethod method);
+
+ QUrl url() const;
+ void setUrl(const QUrl &url);
+
+ QVariantMap parameters() const;
+ void setParameters(const QVariantMap &parameters);
+ void addRequestBody(const QUrlQuery &body);
+
+ void insert(const QString &key, const QVariant &value);
+ QList<QString> keys() const;
+ QVariant take(const QString &key);
+ QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
+
+ QString clientSharedKey() const;
+ void setClientSharedKey(const QString &secret);
+
+ QString tokenSecret() const;
+ void setTokenSecret(const QString &secret);
+
+ QByteArray hmacSha1() const;
+ QByteArray rsaSha1() const;
+ QByteArray plainText(const QString &clientIdentifier) const;
+
+ static QByteArray plainText(const QString &clientIdentifier, const QString clientSharedKey);
+ static QByteArray plainText(const QPair<QString, QString> &clientCredentials);
+
+ void swap(QOAuth1Signature &other);
+ QOAuth1Signature &operator=(const QOAuth1Signature &other);
+ QOAuth1Signature &operator=(QOAuth1Signature &&other);
+
+private:
+ QSharedDataPointer<QOAuth1SignaturePrivate> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QOAUTH1SIGNATURE_H
diff --git a/src/oauth/qoauth1signature_p.h b/src/oauth/qoauth1signature_p.h
new file mode 100644
index 0000000..5b68cc2
--- /dev/null
+++ b/src/oauth/qoauth1signature_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QOAUTH1SIGNATURE_P_H
+#define QOAUTH1SIGNATURE_P_H
+
+#include <QtNetworkAuth/qoauth1signature.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOAuth1SignaturePrivate : public QSharedData
+{
+public:
+ QOAuth1SignaturePrivate();
+ QOAuth1SignaturePrivate(const QUrl &url, QOAuth1Signature::HttpRequestMethod method,
+ const QVariantMap &parameters,
+ const QString &clientSharedKey = QString(),
+ const QString &tokenSecret = QString());
+
+ QByteArray signatureBaseString() const;
+ QByteArray secret() const;
+ static QByteArray parameterString(const QVariantMap &parameters);
+ static QByteArray encodeHeaders(const QVariantMap &headers);
+
+
+ QOAuth1Signature::HttpRequestMethod method = QOAuth1Signature::HttpRequestMethod::Post;
+ QUrl url;
+ QString clientSharedKey;
+ QString tokenSecret;
+ QVariantMap parameters;
+
+ static QOAuth1SignaturePrivate shared_null;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOAUTH1SIGNATURE_P_H
diff --git a/src/oauth/qoauth2authorizationcodeflow.cpp b/src/oauth/qoauth2authorizationcodeflow.cpp
new file mode 100644
index 0000000..a41993d
--- /dev/null
+++ b/src/oauth/qoauth2authorizationcodeflow.cpp
@@ -0,0 +1,353 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_HTTP
+
+#include <qoauth2authorizationcodeflow.h>
+#include <private/qoauth2authorizationcodeflow_p.h>
+
+#include <qmap.h>
+#include <qurl.h>
+#include <qvariant.h>
+#include <qurlquery.h>
+#include <qjsonobject.h>
+#include <qjsondocument.h>
+#include <qauthenticator.h>
+#include <qoauthhttpserverreplyhandler.h>
+
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+QOAuth2AuthorizationCodeFlowPrivate::QOAuth2AuthorizationCodeFlowPrivate(
+ const QUrl &authorizationUrl, const QUrl &accessTokenUrl, const QString &clientIdentifier,
+ QNetworkAccessManager *manager) :
+ QAbstractOAuth2Private(qMakePair(clientIdentifier, QString()), authorizationUrl, manager),
+ accessTokenUrl(accessTokenUrl)
+{}
+
+QOAuth2AuthorizationCodeFlowPrivate::QOAuth2AuthorizationCodeFlowPrivate(
+ QNetworkAccessManager *manager) : QAbstractOAuth2Private(manager)
+{}
+
+void QOAuth2AuthorizationCodeFlowPrivate::_q_handleCallback(const QVariantMap &data)
+{
+ Q_Q(QOAuth2AuthorizationCodeFlow);
+ using Key = QAbstractOAuth2Private::OAuth2KeyString;
+
+ if (status != QAbstractOAuth::Status::NotAuthenticated) {
+ qWarning("QOAuth2AuthorizationCodeFlow: Unexpected call");
+ return;
+ }
+
+ Q_ASSERT(!state.isEmpty());
+
+ const QString error = data.value(Key::error).toString();
+ const QString code = data.value(Key::code).toString();
+ const QString receivedState = data.value(Key::state).toString();
+ if (error.size()) {
+ const QString uri = data.value(Key::errorUri).toString();
+ const QString description = data.value(Key::errorDescription).toString();
+ qWarning("QOAuth2AuthorizationCodeFlow: AuthenticationError: %s(%s): %s",
+ qPrintable(error), qPrintable(uri), qPrintable(description));
+ Q_EMIT q->error(error, description, uri);
+ return;
+ }
+ if (code.isEmpty()) {
+ qWarning("QOAuth2AuthorizationCodeFlow: AuthenticationError: Code not received");
+ return;
+ }
+ if (receivedState.isEmpty()) {
+ qWarning("QOAuth2AuthorizationCodeFlow: State not received");
+ return;
+ }
+ if (state != receivedState) {
+ qWarning("QOAuth2AuthorizationCodeFlow: State mismatch");
+ return;
+ }
+
+ setStatus(QAbstractOAuth::Status::TemporaryCredentialsReceived);
+
+ QVariantMap copy(data);
+ copy.remove(Key::code);
+ extraTokens = copy;
+ q->requestAccessToken(code);
+}
+
+void QOAuth2AuthorizationCodeFlowPrivate::_q_accessTokenRequestFinished(const QVariantMap &values)
+{
+ Q_Q(QOAuth2AuthorizationCodeFlow);
+ using Key = QAbstractOAuth2Private::OAuth2KeyString;
+
+ if (values.contains(Key::error)) {
+ const QString error = values.value(Key::error).toString();
+ qWarning("QOAuth2AuthorizationCodeFlow Error: %s", qPrintable(error));
+ return;
+ }
+
+ bool ok;
+ const QString accessToken = values.value(Key::accessToken).toString();
+ tokenType = values.value(Key::tokenType).toString();
+ int expiresIn = values.value(Key::expiresIn).toInt(&ok);
+ if (!ok)
+ expiresIn = -1;
+ refreshToken = values.value(Key::refreshToken).toString();
+ scope = values.value(Key::scope).toString();
+ if (accessToken.isEmpty()) {
+ qWarning("QOAuth2AuthorizationCodeFlow: Access token not received");
+ return;
+ }
+ q->setToken(accessToken);
+
+ const QDateTime currentDateTime = QDateTime::currentDateTime();
+ if (expiresIn > 0 && currentDateTime.secsTo(expiresAt) != expiresIn) {
+ expiresAt = currentDateTime.addSecs(expiresIn);
+ Q_EMIT q->expirationAtChanged(expiresAt);
+ }
+
+ setStatus(QAbstractOAuth::Status::Granted);
+}
+
+void QOAuth2AuthorizationCodeFlowPrivate::_q_authenticate(QNetworkReply *reply,
+ QAuthenticator *authenticator)
+{
+ if (reply == currentReply){
+ const auto url = reply->url();
+ if (url == accessTokenUrl) {
+ authenticator->setUser(clientCredentials.first);
+ authenticator->setPassword(QString());
+ }
+ }
+}
+
+QOAuth2AuthorizationCodeFlow::QOAuth2AuthorizationCodeFlow(QObject *parent) :
+ QAbstractOAuth2(*new QOAuth2AuthorizationCodeFlowPrivate, parent)
+{}
+
+QOAuth2AuthorizationCodeFlow::QOAuth2AuthorizationCodeFlow(QNetworkAccessManager *manager,
+ QObject *parent) :
+ QAbstractOAuth2(*new QOAuth2AuthorizationCodeFlowPrivate(manager), parent)
+{}
+
+QOAuth2AuthorizationCodeFlow::QOAuth2AuthorizationCodeFlow(const QString &clientIdentifier,
+ QNetworkAccessManager *manager,
+ QObject *parent) :
+ QAbstractOAuth2(*new QOAuth2AuthorizationCodeFlowPrivate(QUrl(), QUrl(), clientIdentifier,
+ manager),
+ parent)
+{}
+
+QOAuth2AuthorizationCodeFlow::QOAuth2AuthorizationCodeFlow(const QUrl &authenticateUrl,
+ const QUrl &accessTokenUrl,
+ QNetworkAccessManager *manager,
+ QObject *parent) :
+ QAbstractOAuth2(*new QOAuth2AuthorizationCodeFlowPrivate(authenticateUrl, accessTokenUrl,
+ QString(), manager),
+ parent)
+{}
+
+QOAuth2AuthorizationCodeFlow::QOAuth2AuthorizationCodeFlow(const QString &clientIdentifier,
+ const QUrl &authenticateUrl,
+ const QUrl &accessTokenUrl,
+ QNetworkAccessManager *manager,
+ QObject *parent) :
+ QAbstractOAuth2(*new QOAuth2AuthorizationCodeFlowPrivate(authenticateUrl, accessTokenUrl,
+ clientIdentifier, manager),
+ parent)
+{}
+
+QOAuth2AuthorizationCodeFlow::~QOAuth2AuthorizationCodeFlow()
+{}
+
+QString QOAuth2AuthorizationCodeFlow::responseType() const
+{
+ return QStringLiteral("code");
+}
+
+QUrl QOAuth2AuthorizationCodeFlow::accessTokenUrl() const
+{
+ Q_D(const QOAuth2AuthorizationCodeFlow);
+ return d->accessTokenUrl;
+}
+
+void QOAuth2AuthorizationCodeFlow::setAccessTokenUrl(const QUrl &accessTokenUrl)
+{
+ Q_D(QOAuth2AuthorizationCodeFlow);
+ if (d->accessTokenUrl != accessTokenUrl) {
+ d->accessTokenUrl = accessTokenUrl;
+ Q_EMIT accessTokenUrlChanged(accessTokenUrl);
+ }
+}
+
+void QOAuth2AuthorizationCodeFlow::grant()
+{
+ Q_D(QOAuth2AuthorizationCodeFlow);
+ if (d->authorizationUrl.isEmpty()) {
+ qWarning("QOAuth2AuthorizationCodeFlow::grant: No authenticate Url set");
+ return;
+ }
+ if (d->accessTokenUrl.isEmpty()) {
+ qWarning("QOAuth2AuthorizationCodeFlow::grant: No request access token Url set");
+ return;
+ }
+
+ resourceOwnerAuthorization(d->authorizationUrl);
+}
+
+void QOAuth2AuthorizationCodeFlow::refreshAccessToken()
+{
+ Q_D(QOAuth2AuthorizationCodeFlow);
+
+ if (d->refreshToken.isEmpty()) {
+ qWarning("QOAuth2AuthorizationCodeFlow::refreshAccessToken: Cannot refresh access token. "
+ "Empty refresh token");
+ return;
+ }
+ if (d->status == Status::RefreshingToken) {
+ qWarning("QOAuth2AuthorizationCodeFlow::refreshAccessToken: Cannot refresh access token. "
+ "Refresh Access Token in progress");
+ return;
+ }
+
+ using Key = QAbstractOAuth2Private::OAuth2KeyString;
+
+ QVariantMap parameters;
+ QNetworkRequest request(d->accessTokenUrl);
+ QUrlQuery query;
+ parameters.insert(Key::grantType, QStringLiteral("refresh_token"));
+ parameters.insert(Key::refreshToken, d->refreshToken);
+ parameters.insert(Key::redirectUri, QUrl::toPercentEncoding(callback()));
+ query = QAbstractOAuthPrivate::createQuery(parameters);
+ request.setHeader(QNetworkRequest::ContentTypeHeader,
+ QStringLiteral("application/x-www-form-urlencoded"));
+
+ const QString data = query.toString(QUrl::FullyEncoded);
+ d->currentReply = d->networkAccessManager()->post(request, data.toUtf8());
+ d->status = Status::RefreshingToken;
+
+ connect(d->currentReply.data(), &QNetworkReply::finished,
+ std::bind(&QAbstractOAuthReplyHandler::networkReplyFinished, replyHandler(),
+ d->currentReply.data()));
+ connect(d->currentReply.data(), &QNetworkReply::finished, d->currentReply.data(),
+ &QNetworkReply::deleteLater);
+ QObjectPrivate::connect(d->networkAccessManager(),
+ &QNetworkAccessManager::authenticationRequired,
+ d, &QOAuth2AuthorizationCodeFlowPrivate::_q_authenticate,
+ Qt::UniqueConnection);
+}
+
+QUrl QOAuth2AuthorizationCodeFlow::buildAuthenticateUrl(const QVariantMap &parameters)
+{
+ Q_D(QOAuth2AuthorizationCodeFlow);
+ using Key = QAbstractOAuth2Private::OAuth2KeyString;
+
+ if (d->state.isEmpty())
+ setState(QAbstractOAuth2Private::generateRandomState());
+ Q_ASSERT(!d->state.isEmpty());
+ const QString state = d->state;
+
+ QVariantMap p(parameters);
+ QUrl url(d->authorizationUrl);
+ p.insert(Key::responseType, responseType());
+ p.insert(Key::clientIdentifier, d->clientCredentials.first);
+ p.insert(Key::redirectUri, callback());
+ p.insert(Key::scope, d->scope);
+ p.insert(Key::state, state);
+ if (d->modifyParametersFunction)
+ d->modifyParametersFunction(Stage::RequestingAuthorization, &p);
+ url.setQuery(d->createQuery(p));
+ connect(d->replyHandler.data(), &QAbstractOAuthReplyHandler::callbackReceived, this,
+ &QOAuth2AuthorizationCodeFlow::authorizationCallbackReceived, Qt::UniqueConnection);
+ setStatus(QAbstractOAuth::Status::NotAuthenticated);
+ qDebug("QOAuth2AuthorizationCodeFlow::buildAuthenticateUrl: %s", qPrintable(url.toString()));
+ return url;
+}
+
+void QOAuth2AuthorizationCodeFlow::requestAccessToken(const QString &code)
+{
+ Q_D(QOAuth2AuthorizationCodeFlow);
+ using Key = QAbstractOAuth2Private::OAuth2KeyString;
+
+ QVariantMap parameters;
+ QNetworkRequest request(d->accessTokenUrl);
+ QUrlQuery query;
+ parameters.insert(Key::grantType, QStringLiteral("authorization_code"));
+ parameters.insert(Key::code, QUrl::toPercentEncoding(code));
+ parameters.insert(Key::redirectUri, QUrl::toPercentEncoding(callback()));
+ parameters.insert(Key::clientIdentifier, QUrl::toPercentEncoding(d->clientCredentials.first));
+ if (!d->clientCredentials.second.isEmpty())
+ parameters.insert(Key::clientSharedSecret, d->clientCredentials.second);
+ if (d->modifyParametersFunction)
+ d->modifyParametersFunction(Stage::RequestingAccessToken, &parameters);
+ query = QAbstractOAuthPrivate::createQuery(parameters);
+ request.setHeader(QNetworkRequest::ContentTypeHeader,
+ QStringLiteral("application/x-www-form-urlencoded"));
+
+ const QString data = query.toString(QUrl::FullyEncoded);
+ d->currentReply = d->networkAccessManager()->post(request, data.toUtf8());
+ QObject::connect(d->currentReply.data(), &QNetworkReply::finished,
+ std::bind(&QAbstractOAuthReplyHandler::networkReplyFinished, replyHandler(),
+ d->currentReply.data()));
+ QObjectPrivate::connect(d->replyHandler.data(), &QAbstractOAuthReplyHandler::tokensReceived, d,
+ &QOAuth2AuthorizationCodeFlowPrivate::_q_accessTokenRequestFinished,
+ Qt::UniqueConnection);
+ QObjectPrivate::connect(d->networkAccessManager(),
+ &QNetworkAccessManager::authenticationRequired,
+ d, &QOAuth2AuthorizationCodeFlowPrivate::_q_authenticate,
+ Qt::UniqueConnection);
+}
+
+void QOAuth2AuthorizationCodeFlow::resourceOwnerAuthorization(const QUrl &url,
+ const QVariantMap &parameters)
+{
+ Q_D(QOAuth2AuthorizationCodeFlow);
+ if (Q_UNLIKELY(url != d->authorizationUrl)) {
+ qWarning("Invalid URL: %s", qPrintable(url.toString()));
+ return;
+ }
+ const QUrl u = buildAuthenticateUrl(parameters);
+ QObjectPrivate::connect(this, &QOAuth2AuthorizationCodeFlow::authorizationCallbackReceived, d,
+ &QOAuth2AuthorizationCodeFlowPrivate::_q_handleCallback,
+ Qt::UniqueConnection);
+ Q_EMIT authorizeWithBrowser(u);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
diff --git a/src/oauth/qoauth2authorizationcodeflow.h b/src/oauth/qoauth2authorizationcodeflow.h
new file mode 100644
index 0000000..a67873c
--- /dev/null
+++ b/src/oauth/qoauth2authorizationcodeflow.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOAUTH2AUTHORIZATIONCODEFLOW_H
+#define QOAUTH2AUTHORIZATIONCODEFLOW_H
+
+#ifndef QT_NO_HTTP
+
+#include <QtNetworkAuth/qoauthglobal.h>
+#include <QtNetworkAuth/qabstractoauth2.h>
+
+QT_BEGIN_NAMESPACE
+
+class QUrl;
+class QString;
+class QNetworkAccessManager;
+
+class QOAuth2AuthorizationCodeFlowPrivate;
+class Q_OAUTH_EXPORT QOAuth2AuthorizationCodeFlow : public QAbstractOAuth2
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl accessTokenUrl
+ READ accessTokenUrl
+ WRITE setAccessTokenUrl
+ NOTIFY accessTokenUrlChanged)
+
+public:
+ explicit QOAuth2AuthorizationCodeFlow(QObject *parent = nullptr);
+ explicit QOAuth2AuthorizationCodeFlow(QNetworkAccessManager *manager,
+ QObject *parent = nullptr);
+
+ QOAuth2AuthorizationCodeFlow(const QString &clientIdentifier,
+ QNetworkAccessManager *manager,
+ QObject *parent = nullptr);
+
+ QOAuth2AuthorizationCodeFlow(const QUrl &authorizationUrl,
+ const QUrl &accessTokenUrl,
+ QNetworkAccessManager *manager,
+ QObject *parent = nullptr);
+
+ QOAuth2AuthorizationCodeFlow(const QString &clientIdentifier,
+ const QUrl &authorizationUrl,
+ const QUrl &accessTokenUrl,
+ QNetworkAccessManager *manager,
+ QObject *parent = nullptr);
+
+ ~QOAuth2AuthorizationCodeFlow();
+
+ QString responseType() const override;
+
+ QUrl accessTokenUrl() const;
+ void setAccessTokenUrl(const QUrl &accessTokenUrl);
+
+public Q_SLOTS:
+ void grant() override;
+ void refreshAccessToken();
+
+protected:
+ QUrl buildAuthenticateUrl(const QVariantMap &parameters = QVariantMap());
+ void requestAccessToken(const QString &code);
+ void resourceOwnerAuthorization(const QUrl &url,
+ const QVariantMap &parameters = QVariantMap()) override;
+
+Q_SIGNALS:
+ void accessTokenUrlChanged(const QUrl &accessTokenUrl);
+
+private:
+ Q_DISABLE_COPY(QOAuth2AuthorizationCodeFlow)
+ Q_DECLARE_PRIVATE(QOAuth2AuthorizationCodeFlow)
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QOAUTH2AUTHORIZATIONCODEFLOW_H
diff --git a/src/oauth/qoauth2authorizationcodeflow_p.h b/src/oauth/qoauth2authorizationcodeflow_p.h
new file mode 100644
index 0000000..54a4c8d
--- /dev/null
+++ b/src/oauth/qoauth2authorizationcodeflow_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QOAUTH2AUTHORIZATIONCODEFLOW_P_H
+#define QOAUTH2AUTHORIZATIONCODEFLOW_P_H
+
+#ifndef QT_NO_HTTP
+
+#include <private/qabstractoauth2_p.h>
+
+#include <QtNetworkAuth/qoauthglobal.h>
+#include <QtNetworkAuth/qoauth2authorizationcodeflow.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOAuth2AuthorizationCodeFlowPrivate : public QAbstractOAuth2Private
+{
+ Q_DECLARE_PUBLIC(QOAuth2AuthorizationCodeFlow)
+
+public:
+ QOAuth2AuthorizationCodeFlowPrivate(const QUrl &authorizationUrl,
+ const QUrl &accessTokenUrl,
+ const QString &clientIdentifier,
+ QNetworkAccessManager *manager = nullptr);
+ QOAuth2AuthorizationCodeFlowPrivate(QNetworkAccessManager *manager = nullptr);
+
+ void _q_handleCallback(const QVariantMap &data);
+ void _q_accessTokenRequestFinished(const QVariantMap &values);
+ void _q_authenticate(QNetworkReply *reply, QAuthenticator *authenticator);
+
+ QUrl accessTokenUrl;
+ QString tokenType;
+ QPointer<QNetworkReply> currentReply;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QOAUTH2AUTHORIZATIONCODEFLOW_P_H
diff --git a/src/oauth/qoauthglobal.h b/src/oauth/qoauthglobal.h
new file mode 100644
index 0000000..d84a01e
--- /dev/null
+++ b/src/oauth/qoauthglobal.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtPositioning module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOAUTHGLOBAL_H
+#define QOAUTHGLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+#if defined(QT_SHARED) || !defined(QT_STATIC)
+# if defined(QT_BUILD_NETWORKAUTH_LIB)
+# define Q_OAUTH_EXPORT Q_DECL_EXPORT
+# else
+# define Q_OAUTH_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_OAUTH_EXPORT
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QOAUTHGLOBAL_H
diff --git a/src/oauth/qoauthhttpserverreplyhandler.cpp b/src/oauth/qoauthhttpserverreplyhandler.cpp
new file mode 100644
index 0000000..68fec3e
--- /dev/null
+++ b/src/oauth/qoauthhttpserverreplyhandler.cpp
@@ -0,0 +1,329 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_HTTP
+
+#include <qabstractoauth.h>
+#include <qoauthhttpserverreplyhandler.h>
+
+#include <private/qoauthhttpserverreplyhandler_p.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qurlquery.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <QtNetwork/qtcpsocket.h>
+#include <QtNetwork/qnetworkreply.h>
+
+#include <cctype>
+#include <cstring>
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+QOAuthHttpServerReplyHandlerPrivate::QOAuthHttpServerReplyHandlerPrivate(
+ QOAuthHttpServerReplyHandler *p) :
+ text(QObject::tr("Callback received. Feel free to close this page.")), q_ptr(p)
+{
+ QObject::connect(&httpServer, &QTcpServer::newConnection,
+ std::bind(&QOAuthHttpServerReplyHandlerPrivate::_q_clientConnected, this));
+}
+
+QOAuthHttpServerReplyHandlerPrivate::~QOAuthHttpServerReplyHandlerPrivate()
+{
+ if (httpServer.isListening())
+ httpServer.close();
+}
+
+void QOAuthHttpServerReplyHandlerPrivate::_q_clientConnected()
+{
+ QTcpSocket *socket = httpServer.nextPendingConnection();
+
+ QObject::connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater);
+ QObject::connect(socket, &QTcpSocket::readyRead,
+ std::bind(&QOAuthHttpServerReplyHandlerPrivate::_q_readData, this, socket));
+}
+
+void QOAuthHttpServerReplyHandlerPrivate::_q_readData(QTcpSocket *socket)
+{
+ if (!clients.contains(socket))
+ clients[socket].port = httpServer.serverPort();
+
+ QHttpRequest *request = &clients[socket];
+ bool error;
+
+ if (Q_LIKELY(request->state == QHttpRequest::State::ReadingMethod))
+ if (Q_UNLIKELY(error = !request->readMethod(socket)))
+ qWarning("QOAuthHttpServerReplyHandlerPrivate::_q_readData: Invalid Method");
+
+ if (Q_LIKELY(!error && request->state == QHttpRequest::State::ReadingUrl))
+ if (Q_UNLIKELY(error = !request->readUrl(socket)))
+ qWarning("QOAuthHttpServerReplyHandlerPrivate::_q_readData: Invalid URL");
+
+ if (Q_LIKELY(!error && request->state == QHttpRequest::State::ReadingStatus))
+ if (Q_UNLIKELY(error = !request->readStatus(socket)))
+ qWarning("QOAuthHttpServerReplyHandlerPrivate::_q_readData: Invalid Status");
+
+ if (Q_LIKELY(!error && request->state == QHttpRequest::State::ReadingHeader))
+ if (Q_UNLIKELY(error = !request->readHeader(socket)))
+ qWarning("QOAuthHttpServerReplyHandlerPrivate::_q_readData: Invalid Header");
+
+ if (error) {
+ socket->disconnectFromHost();
+ clients.remove(socket);
+ } else if (!request->url.isEmpty()) {
+ Q_ASSERT(request->state != QHttpRequest::State::ReadingUrl);
+ _q_answerClient(socket, request->url);
+ clients.remove(socket);
+ }
+}
+
+void QOAuthHttpServerReplyHandlerPrivate::_q_answerClient(QTcpSocket *socket, const QUrl &url)
+{
+ Q_Q(QOAuthHttpServerReplyHandler);
+ if (!url.path().startsWith(QStringLiteral("/cb"))) {
+ qWarning("QOAuthHttpServerReplyHandlerPrivate::_q_answerClient: Invalid request: %s",
+ qPrintable(url.toString()));
+ } else {
+ QVariantMap receivedData;
+ const QUrlQuery query(url.query());
+ const auto items = query.queryItems();
+ for (auto it = items.begin(), end = items.end(); it != end; ++it)
+ receivedData.insert(it->first, it->second);
+ Q_EMIT q->callbackReceived(receivedData);
+
+ const QString html = QLatin1String("<html><head><title>") +
+ qApp->applicationName() +
+ QLatin1String("</title></head><body>") +
+ text +
+ QLatin1String("</body></html>");
+
+ const QByteArray htmlSize = QString::number(html.size()).toUtf8();
+ const QByteArray replyMessage = QByteArrayLiteral("HTTP/1.0 200 OK \r\n"
+ "Content-Type: text/html; "
+ "charset=\"utf-8\"\r\n"
+ "Content-Length: ") + htmlSize +
+ QByteArrayLiteral("\r\n\r\n") +
+ html.toUtf8();
+
+ socket->write(replyMessage);
+ }
+ socket->disconnectFromHost();
+}
+
+bool QOAuthHttpServerReplyHandlerPrivate::QHttpRequest::readMethod(QTcpSocket *socket)
+{
+ bool finished = false;
+ while (socket->bytesAvailable() && !finished) {
+ const auto c = socket->read(1).at(0);
+ if (std::isupper(c) && fragment.size() < 6)
+ fragment += c;
+ else
+ finished = true;
+ }
+ if (finished) {
+ if (fragment == "HEAD")
+ method = Method::Head;
+ else if (fragment == "GET")
+ method = Method::Get;
+ else if (fragment == "PUT")
+ method = Method::Put;
+ else if (fragment == "POST")
+ method = Method::Post;
+ else if (fragment == "DELETE")
+ method = Method::Delete;
+ else
+ qWarning("QOAuthHttpServerReplyHandlerPrivate::QHttpRequest::readMethod: Invalid "
+ "operation %s", fragment.data());
+
+ state = State::ReadingUrl;
+ fragment.clear();
+
+ return method != Method::Unknown;
+ }
+ return true;
+}
+
+bool QOAuthHttpServerReplyHandlerPrivate::QHttpRequest::readUrl(QTcpSocket *socket)
+{
+ bool finished = false;
+ while (socket->bytesAvailable() && !finished) {
+ const auto c = socket->read(1).at(0);
+ if (std::isspace(c))
+ finished = true;
+ else
+ fragment += c;
+ }
+ if (finished) {
+ if (!fragment.startsWith("/")) {
+ qWarning("QOAuthHttpServerReplyHandlerPrivate::QHttpRequest::readUrl: Invalid "
+ "URL path %s", fragment.constData());
+ return false;
+ }
+ url.setUrl(QStringLiteral("http://localhost:") + QString::number(port) +
+ QString::fromUtf8(fragment));
+ state = State::ReadingStatus;
+ if (!url.isValid()) {
+ qWarning("QOAuthHttpServerReplyHandlerPrivate::QHttpRequest::readUrl: Invalid "
+ "URL %s", fragment.constData());
+ return false;
+ }
+ fragment.clear();
+ return true;
+ }
+ return true;
+}
+
+bool QOAuthHttpServerReplyHandlerPrivate::QHttpRequest::readStatus(QTcpSocket *socket)
+{
+ bool finished = false;
+ while (socket->bytesAvailable() && !finished) {
+ fragment += socket->read(1);
+ if (fragment.endsWith("\r\n")) {
+ finished = true;
+ fragment.resize(fragment.size() - 2);
+ }
+ }
+ if (finished) {
+ if (!std::isdigit(fragment.at(fragment.size() - 3)) ||
+ !std::isdigit(fragment.at(fragment.size() - 1))) {
+ qWarning("QOAuthHttpServerReplyHandlerPrivate::QHttpRequest::readStatus: Invalid "
+ "version");
+ return false;
+ }
+ version = qMakePair(fragment.at(fragment.size() - 3) - '0',
+ fragment.at(fragment.size() - 1) - '0');
+ state = State::ReadingHeader;
+ fragment.clear();
+ }
+ return true;
+}
+
+bool QOAuthHttpServerReplyHandlerPrivate::QHttpRequest::readHeader(QTcpSocket *socket)
+{
+ while (socket->bytesAvailable()) {
+ fragment += socket->read(1);
+ if (fragment.endsWith("\r\n")) {
+ if (fragment == "\r\n") {
+ state = State::ReadingBody;
+ fragment.clear();
+ return true;
+ } else {
+ fragment.chop(2);
+ const int index = fragment.indexOf(':');
+ if (index == -1)
+ return false;
+
+ const QByteArray key = fragment.mid(0, index).trimmed();
+ const QByteArray value = fragment.mid(index + 1).trimmed();
+ headers.insert(key, value);
+ fragment.clear();
+ }
+ }
+ }
+ return false;
+}
+
+QOAuthHttpServerReplyHandler::QOAuthHttpServerReplyHandler(QObject *parent) :
+ QOAuthHttpServerReplyHandler(QHostAddress::Any, 0, parent)
+{}
+
+QOAuthHttpServerReplyHandler::QOAuthHttpServerReplyHandler(quint16 port, QObject *parent) :
+ QOAuthHttpServerReplyHandler(QHostAddress::Any, port, parent)
+{}
+
+QOAuthHttpServerReplyHandler::QOAuthHttpServerReplyHandler(const QHostAddress &address,
+ quint16 port, QObject *parent) :
+ QOAuthOobReplyHandler(parent),
+ d_ptr(new QOAuthHttpServerReplyHandlerPrivate(this))
+{
+ listen(address, port);
+}
+
+QOAuthHttpServerReplyHandler::~QOAuthHttpServerReplyHandler()
+{}
+
+QString QOAuthHttpServerReplyHandler::callback() const
+{
+ Q_D(const QOAuthHttpServerReplyHandler);
+
+ Q_ASSERT(d->httpServer.isListening());
+ const QUrl url(QString::fromLatin1("http://localhost:%1/cb").arg(d->httpServer.serverPort()));
+ return url.toString(QUrl::EncodeDelimiters);
+}
+
+QString QOAuthHttpServerReplyHandler::callbackText() const
+{
+ Q_D(const QOAuthHttpServerReplyHandler);
+ return d->text;
+}
+
+void QOAuthHttpServerReplyHandler::setCallbackText(const QString &text)
+{
+ Q_D(QOAuthHttpServerReplyHandler);
+ d->text = text;
+}
+
+quint16 QOAuthHttpServerReplyHandler::port() const
+{
+ Q_D(const QOAuthHttpServerReplyHandler);
+ return d->httpServer.serverPort();
+}
+
+bool QOAuthHttpServerReplyHandler::listen(const QHostAddress &address, quint16 port)
+{
+ Q_D(QOAuthHttpServerReplyHandler);
+ return d->httpServer.listen(address, port);
+}
+
+void QOAuthHttpServerReplyHandler::close()
+{
+ Q_D(QOAuthHttpServerReplyHandler);
+ return d->httpServer.close();
+}
+
+bool QOAuthHttpServerReplyHandler::isListening() const
+{
+ Q_D(const QOAuthHttpServerReplyHandler);
+ return d->httpServer.isListening();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
diff --git a/src/oauth/qoauthhttpserverreplyhandler.h b/src/oauth/qoauthhttpserverreplyhandler.h
new file mode 100644
index 0000000..2437e08
--- /dev/null
+++ b/src/oauth/qoauthhttpserverreplyhandler.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOAUTHHTTPSERVERREPLYHANDLER_H
+#define QOAUTHHTTPSERVERREPLYHANDLER_H
+
+#ifndef QT_NO_HTTP
+
+#include <QtNetworkAuth/qoauthglobal.h>
+#include <QtNetworkAuth/qoauthoobreplyhandler.h>
+
+#include <QtNetwork/qhostaddress.h>
+
+QT_BEGIN_NAMESPACE
+
+class QUrlQuery;
+
+class QOAuthHttpServerReplyHandlerPrivate;
+class Q_OAUTH_EXPORT QOAuthHttpServerReplyHandler : public QOAuthOobReplyHandler
+{
+ Q_OBJECT
+
+public:
+ explicit QOAuthHttpServerReplyHandler(QObject *parent = nullptr);
+ explicit QOAuthHttpServerReplyHandler(quint16 port, QObject *parent = nullptr);
+ explicit QOAuthHttpServerReplyHandler(const QHostAddress &address, quint16 port,
+ QObject *parent = nullptr);
+ ~QOAuthHttpServerReplyHandler();
+
+ QString callback() const override;
+
+ QString callbackText() const;
+ void setCallbackText(const QString &text);
+
+ quint16 port() const;
+
+ bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
+ void close();
+ bool isListening() const;
+
+private:
+ Q_DECLARE_PRIVATE(QOAuthHttpServerReplyHandler)
+ QScopedPointer<QOAuthHttpServerReplyHandlerPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QOAUTHHTTPSERVERREPLYHANDLER_H
diff --git a/src/oauth/qoauthhttpserverreplyhandler_p.h b/src/oauth/qoauthhttpserverreplyhandler_p.h
new file mode 100644
index 0000000..7e0be6b
--- /dev/null
+++ b/src/oauth/qoauthhttpserverreplyhandler_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QOAUTHHTTPSERVERREPLYHANDLER_P_H
+#define QOAUTHHTTPSERVERREPLYHANDLER_P_H
+
+#ifndef QT_NO_HTTP
+
+#include <QtNetworkAuth/qoauthglobal.h>
+#include <QtNetworkAuth/qoauthhttpserverreplyhandler.h>
+
+#include <private/qobject_p.h>
+
+#include <QtNetwork/qtcpserver.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOAuthHttpServerReplyHandlerPrivate
+{
+ Q_DECLARE_PUBLIC(QOAuthHttpServerReplyHandler)
+
+public:
+ explicit QOAuthHttpServerReplyHandlerPrivate(QOAuthHttpServerReplyHandler *p);
+ ~QOAuthHttpServerReplyHandlerPrivate();
+
+ QTcpServer httpServer;
+ QString text;
+ QHostAddress listenAddress = QHostAddress::LocalHost;
+
+private:
+ void _q_clientConnected();
+ void _q_readData(QTcpSocket *socket);
+ void _q_answerClient(QTcpSocket *socket, const QUrl &url);
+
+ struct QHttpRequest {
+ quint16 port = 0;
+
+ bool readMethod(QTcpSocket *socket);
+ bool readUrl(QTcpSocket *socket);
+ bool readStatus(QTcpSocket *socket);
+ bool readHeader(QTcpSocket *socket);
+
+ enum class State {
+ ReadingMethod,
+ ReadingUrl,
+ ReadingStatus,
+ ReadingHeader,
+ ReadingBody,
+ AllDone
+ } state = State::ReadingMethod;
+ QByteArray fragment;
+
+ enum class Method {
+ Unknown,
+ Head,
+ Get,
+ Put,
+ Post,
+ Delete,
+ } method = Method::Unknown;
+ QUrl url;
+ QPair<quint8, quint8> version;
+ QMap<QByteArray, QByteArray> headers;
+ };
+
+ QMap<QTcpSocket *, QHttpRequest> clients;
+
+ QOAuthHttpServerReplyHandler *q_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QOAUTHHTTPSERVERREPLYHANDLER_P_H
diff --git a/src/oauth/qoauthoobreplyhandler.cpp b/src/oauth/qoauthoobreplyhandler.cpp
new file mode 100644
index 0000000..c4e0bd8
--- /dev/null
+++ b/src/oauth/qoauthoobreplyhandler.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_HTTP
+
+#include "qoauthoobreplyhandler.h"
+
+#include <QtCore/qurlquery.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsondocument.h>
+
+#include <QtNetwork/qnetworkreply.h>
+
+QT_BEGIN_NAMESPACE
+
+QOAuthOobReplyHandler::QOAuthOobReplyHandler(QObject *parent)
+ : QAbstractOAuthReplyHandler(parent)
+{}
+
+QString QOAuthOobReplyHandler::callback() const
+{
+ return QStringLiteral("oob");
+}
+
+void QOAuthOobReplyHandler::networkReplyFinished(QNetworkReply *reply)
+{
+ if (reply->error() != QNetworkReply::NoError) {
+ qWarning("QOAuthOobReplyHandler::networkReplyFinished: %s",
+ qPrintable(reply->errorString()));
+ return;
+ }
+ if (reply->header(QNetworkRequest::ContentTypeHeader).isNull()) {
+ qWarning("QOAuthOobReplyHandler::networkReplyFinished: Empty Content-type header");
+ return;
+ }
+ const QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).isNull() ?
+ QStringLiteral("text/html") :
+ reply->header(QNetworkRequest::ContentTypeHeader).toString();
+ const QByteArray data = reply->readAll();
+ if (data.isEmpty()) {
+ qWarning("QOAuthOobReplyHandler::networkReplyFinished: No received data");
+ return;
+ }
+
+ Q_EMIT replyDataReceived(data);
+
+ QVariantMap ret;
+
+ if (contentType.startsWith(QStringLiteral("text/html")) ||
+ contentType.startsWith(QStringLiteral("application/x-www-form-urlencoded"))) {
+ ret = parseResponse(data);
+ } else if (contentType.startsWith(QStringLiteral("application/json"))) {
+ const QJsonDocument document = QJsonDocument::fromJson(data);
+ if (!document.isObject()) {
+ qWarning("QOAuthOobReplyHandler::networkReplyFinished: Received data is not a JSON"
+ "object: %s", qPrintable(QString::fromUtf8(data)));
+ return;
+ }
+ const QJsonObject object = document.object();
+ if (object.isEmpty()) {
+ qWarning("QOAuthOobReplyHandler::networkReplyFinished: Received empty JSON object: %s",
+ qPrintable(QString::fromUtf8(data)));
+ }
+ ret = object.toVariantMap();
+ } else {
+ qWarning("QOAuthOobReplyHandler::networkReplyFinished: Unknown Content-type: %s",
+ qPrintable(contentType));
+ return;
+ }
+
+ Q_EMIT tokensReceived(ret);
+}
+
+QVariantMap QOAuthOobReplyHandler::parseResponse(const QByteArray &response)
+{
+ QVariantMap ret;
+ QUrlQuery query(QString::fromUtf8(response));
+ auto queryItems = query.queryItems(QUrl::FullyDecoded);
+ for (auto it = queryItems.begin(), end = queryItems.end(); it != end; ++it)
+ ret.insert(it->first, it->second);
+ return ret;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
diff --git a/src/oauth/qoauthoobreplyhandler.h b/src/oauth/qoauthoobreplyhandler.h
new file mode 100644
index 0000000..1ca246c
--- /dev/null
+++ b/src/oauth/qoauthoobreplyhandler.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOAUTHOOBREPLYHANDLER_H
+#define QOAUTHOOBREPLYHANDLER_H
+
+#ifndef QT_NO_HTTP
+
+#include <QtNetworkAuth/qoauthglobal.h>
+#include <QtNetworkAuth/qabstractoauthreplyhandler.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_OAUTH_EXPORT QOAuthOobReplyHandler : public QAbstractOAuthReplyHandler
+{
+ Q_OBJECT
+
+public:
+ explicit QOAuthOobReplyHandler(QObject *parent = nullptr);
+
+ QString callback() const override;
+
+protected:
+ void networkReplyFinished(QNetworkReply *reply) override;
+
+private:
+ QVariantMap parseResponse(const QByteArray &response);
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_HTTP
+
+#endif // QOAUTHOOBREPLYHANDLER_H
diff --git a/src/src.pro b/src/src.pro
new file mode 100644
index 0000000..10821d5
--- /dev/null
+++ b/src/src.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS += oauth