aboutsummaryrefslogtreecommitdiff
path: root/libraries/katabasis
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2021-07-22 20:15:20 +0200
committerPetr Mrázek <peterix@gmail.com>2021-07-25 19:50:44 +0200
commitdd133680858351e3e07690e286882327a4f42ba5 (patch)
tree42ac11eb0d6cc58d3785c57f8571046cafe4b769 /libraries/katabasis
parent2568752af57258a33f27f4c2d0b8fc486fb3d100 (diff)
downloadPrismLauncher-dd133680858351e3e07690e286882327a4f42ba5.tar.gz
PrismLauncher-dd133680858351e3e07690e286882327a4f42ba5.tar.bz2
PrismLauncher-dd133680858351e3e07690e286882327a4f42ba5.zip
NOISSUE bulk addition of code from Katabasis
Diffstat (limited to 'libraries/katabasis')
-rw-r--r--libraries/katabasis/.gitignore2
-rw-r--r--libraries/katabasis/CMakeLists.txt60
-rw-r--r--libraries/katabasis/LICENSE23
-rw-r--r--libraries/katabasis/README.md36
-rw-r--r--libraries/katabasis/acknowledgements.md110
-rw-r--r--libraries/katabasis/include/katabasis/Bits.h33
-rw-r--r--libraries/katabasis/include/katabasis/Globals.h59
-rw-r--r--libraries/katabasis/include/katabasis/OAuth2.h233
-rw-r--r--libraries/katabasis/include/katabasis/PollServer.h48
-rw-r--r--libraries/katabasis/include/katabasis/Reply.h60
-rw-r--r--libraries/katabasis/include/katabasis/ReplyServer.h53
-rw-r--r--libraries/katabasis/include/katabasis/RequestParameter.h15
-rw-r--r--libraries/katabasis/include/katabasis/Requestor.h116
-rw-r--r--libraries/katabasis/src/JsonResponse.cpp26
-rw-r--r--libraries/katabasis/src/JsonResponse.h12
-rw-r--r--libraries/katabasis/src/OAuth2.cpp668
-rw-r--r--libraries/katabasis/src/PollServer.cpp123
-rw-r--r--libraries/katabasis/src/Reply.cpp62
-rwxr-xr-xlibraries/katabasis/src/ReplyServer.cpp182
-rw-r--r--libraries/katabasis/src/Requestor.cpp304
20 files changed, 2225 insertions, 0 deletions
diff --git a/libraries/katabasis/.gitignore b/libraries/katabasis/.gitignore
new file mode 100644
index 00000000..35e189c5
--- /dev/null
+++ b/libraries/katabasis/.gitignore
@@ -0,0 +1,2 @@
+build/
+*.kdev4
diff --git a/libraries/katabasis/CMakeLists.txt b/libraries/katabasis/CMakeLists.txt
new file mode 100644
index 00000000..7bbe1a8b
--- /dev/null
+++ b/libraries/katabasis/CMakeLists.txt
@@ -0,0 +1,60 @@
+cmake_minimum_required(VERSION 3.20)
+
+string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
+if(IS_IN_SOURCE_BUILD)
+ message(FATAL_ERROR "You are building Katabasis in-source. Please separate the build tree from the source tree.")
+endif()
+
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ if(CMAKE_HOST_SYSTEM_VERSION MATCHES ".*[Mm]icrosoft.*" OR
+ CMAKE_HOST_SYSTEM_VERSION MATCHES ".*WSL.*"
+ )
+ message(FATAL_ERROR "Building Katabasis is not supported in Linux-on-Windows distributions. Use a real Linux machine, not a fraudulent one.")
+ endif()
+endif()
+
+project(Katabasis)
+enable_testing()
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_CXX_STANDARD_REQUIRED true)
+set(CMAKE_C_STANDARD_REQUIRED true)
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_C_STANDARD 11)
+
+find_package(Qt5 COMPONENTS Core Network REQUIRED)
+
+set( katabasis_PRIVATE
+ src/OAuth2.cpp
+
+ src/JsonResponse.cpp
+ src/JsonResponse.h
+ src/PollServer.cpp
+ src/Reply.cpp
+ src/ReplyServer.cpp
+ src/Requestor.cpp
+)
+
+set( katabasis_PUBLIC
+ include/katabasis/OAuth2.h
+
+ include/katabasis/Globals.h
+ include/katabasis/PollServer.h
+ include/katabasis/Reply.h
+ include/katabasis/ReplyServer.h
+
+ include/katabasis/Requestor.h
+ include/katabasis/RequestParameter.h
+)
+
+add_library( Katabasis STATIC ${katabasis_PRIVATE} ${katabasis_PUBLIC} )
+target_link_libraries(Katabasis Qt5::Core Qt5::Network)
+
+# needed for statically linked Katabasis in shared libs on x86_64
+set_target_properties(Katabasis
+ PROPERTIES POSITION_INDEPENDENT_CODE TRUE
+)
+
+target_include_directories(Katabasis PUBLIC include PRIVATE src include/katabasis)
diff --git a/libraries/katabasis/LICENSE b/libraries/katabasis/LICENSE
new file mode 100644
index 00000000..9ac8d42f
--- /dev/null
+++ b/libraries/katabasis/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2012, Akos Polster
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/libraries/katabasis/README.md b/libraries/katabasis/README.md
new file mode 100644
index 00000000..a4dc0994
--- /dev/null
+++ b/libraries/katabasis/README.md
@@ -0,0 +1,36 @@
+# Katabasis - MS-flavoerd OAuth for Qt, derived from the O2 library
+
+This library's sole purpose is to make interacting with MSA and various MSA and XBox authenticated services less painful.
+
+It may be possible to backport some of the changes to O2 in the future, but for the sake of going fast, all compatibility concerns have been ignored.
+
+[You can find the original library's git repository here.](https://github.com/pipacs/o2)
+
+Notes to contributors:
+
+ * Please follow the coding style of the existing source, where reasonable
+ * Code contributions are released under Simplified BSD License, as specified in LICENSE. Do not contribute if this license does not suit your code
+ * If you are interested in working on this, come to the MultiMC Discord server and talk first
+
+## Installation
+
+Clone the Github repository, integrate the it into your CMake build system.
+
+The library is static only, dynamic linking and system-wide installation are out of scope and undesirable.
+
+## Usage
+
+At this stage, don't, unless you want to help with the library itself.
+
+This is an experimental fork of the O2 library and is undergoing a big design/architecture shift in order to support different features:
+
+* Multiple accounts
+* Multi-stage authentication/authorization schemes
+* Tighter control over token chains and their storage
+* Talking to complex APIs and individually authorized microservices
+* Token lifetime management, 'offline mode' and resilience in face of network failures
+* Token and claims/entitlements validation
+* Caching of some API results
+* XBox magic
+* Mojang magic
+* Generally, magic that you would spend weeks on researching while getting confused by contradictory/incomplete documentation (if any is available)
diff --git a/libraries/katabasis/acknowledgements.md b/libraries/katabasis/acknowledgements.md
new file mode 100644
index 00000000..c1c8a3d4
--- /dev/null
+++ b/libraries/katabasis/acknowledgements.md
@@ -0,0 +1,110 @@
+# O2 library by Akos Polster and contributors
+
+[The origin of this fork.](https://github.com/pipacs/o2)
+
+> Copyright (c) 2012, Akos Polster
+> All rights reserved.
+>
+> Redistribution and use in source and binary forms, with or without
+> modification, are permitted provided that the following conditions are met:
+>
+> * Redistributions of source code must retain the above copyright notice, this
+> list of conditions and the following disclaimer.
+>
+> * Redistributions in binary form must reproduce the above copyright notice,
+> this list of conditions and the following disclaimer in the documentation
+> and/or other materials provided with the distribution.
+>
+> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+# SimpleCrypt by Andre Somers
+
+Cryptographic methods for Qt.
+
+> Copyright (c) 2011, Andre Somers
+> All rights reserved.
+>
+> Redistribution and use in source and binary forms, with or without
+> modification, are permitted provided that the following conditions are met:
+>
+> * Redistributions of source code must retain the above copyright
+> notice, this list of conditions and the following disclaimer.
+> * Redistributions in binary form must reproduce the above copyright
+> notice, this list of conditions and the following disclaimer in the
+> documentation and/or other materials provided with the distribution.
+> * Neither the name of the Rathenau Instituut, Andre Somers nor the
+> names of its contributors may be used to endorse or promote products
+> derived from this software without specific prior written permission.
+>
+> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+> ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+> WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+> DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY
+> DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+> (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+> ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+> (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+> SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Mandeep Sandhu <mandeepsandhu.chd@gmail.com>
+
+Configurable settings storage, Twitter XAuth specialization, new demos, cleanups.
+
+> "Hi Akos,
+>
+> I'm writing this mail to confirm that my contributions to the O2 library, available here https://github.com/pipacs/o2, can be freely distributed according to the project's license (as shown in the LICENSE file).
+>
+> Regards,
+> -mandeep"
+
+# Sergey Gavrushkin <https://github.com/ncux>
+
+FreshBooks specialization
+
+# Theofilos Intzoglou <https://github.com/parapente>
+
+Hubic specialization
+
+# Dimitar
+
+SurveyMonkey specialization
+
+# David Brooks <https://github.com/dbrnz>
+
+CMake related fixes and improvements.
+
+# Lukas Vogel <https://github.com/lukedirtwalker>
+
+Spotify support
+
+# Alan Garny <https://github.com/agarny>
+
+Windows DLL build support
+
+# MartinMikita <https://github.com/MartinMikita>
+
+Bug fixes
+
+# Larry Shaffer <https://github.com/dakcarto>
+
+Versioning, shared lib, install target and header support
+
+# Gilmanov Ildar <https://github.com/gilmanov-ildar>
+
+Bug fixes, support for ```qml``` module
+
+# Fabian Vogt <https://github.com/Vogtinator>
+
+Bug fixes, support for building without Qt keywords enabled
+
diff --git a/libraries/katabasis/include/katabasis/Bits.h b/libraries/katabasis/include/katabasis/Bits.h
new file mode 100644
index 00000000..3fd2f530
--- /dev/null
+++ b/libraries/katabasis/include/katabasis/Bits.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <QString>
+#include <QDateTime>
+#include <QMap>
+#include <QVariantMap>
+
+namespace Katabasis {
+enum class Activity {
+ Idle,
+ LoggingIn,
+ LoggingOut,
+ Refreshing
+};
+
+enum class Validity {
+ None,
+ Assumed,
+ Certain
+};
+
+struct Token {
+ QDateTime issueInstant;
+ QDateTime notAfter;
+ QString token;
+ QString refresh_token;
+ QVariantMap extra;
+
+ Validity validity = Validity::None;
+ bool persistent = true;
+};
+
+}
diff --git a/libraries/katabasis/include/katabasis/Globals.h b/libraries/katabasis/include/katabasis/Globals.h
new file mode 100644
index 00000000..512745d3
--- /dev/null
+++ b/libraries/katabasis/include/katabasis/Globals.h
@@ -0,0 +1,59 @@
+#pragma once
+
+namespace Katabasis {
+
+// Common constants
+const char ENCRYPTION_KEY[] = "12345678";
+const char MIME_TYPE_XFORM[] = "application/x-www-form-urlencoded";
+const char MIME_TYPE_JSON[] = "application/json";
+
+// OAuth 1/1.1 Request Parameters
+const char OAUTH_CALLBACK[] = "oauth_callback";
+const char OAUTH_CONSUMER_KEY[] = "oauth_consumer_key";
+const char OAUTH_NONCE[] = "oauth_nonce";
+const char OAUTH_SIGNATURE[] = "oauth_signature";
+const char OAUTH_SIGNATURE_METHOD[] = "oauth_signature_method";
+const char OAUTH_TIMESTAMP[] = "oauth_timestamp";
+const char OAUTH_VERSION[] = "oauth_version";
+// OAuth 1/1.1 Response Parameters
+const char OAUTH_TOKEN[] = "oauth_token";
+const char OAUTH_TOKEN_SECRET[] = "oauth_token_secret";
+const char OAUTH_CALLBACK_CONFIRMED[] = "oauth_callback_confirmed";
+const char OAUTH_VERFIER[] = "oauth_verifier";
+
+// OAuth 2 Request Parameters
+const char OAUTH2_RESPONSE_TYPE[] = "response_type";
+const char OAUTH2_CLIENT_ID[] = "client_id";
+const char OAUTH2_CLIENT_SECRET[] = "client_secret";
+const char OAUTH2_USERNAME[] = "username";
+const char OAUTH2_PASSWORD[] = "password";
+const char OAUTH2_REDIRECT_URI[] = "redirect_uri";
+const char OAUTH2_SCOPE[] = "scope";
+const char OAUTH2_GRANT_TYPE_CODE[] = "code";
+const char OAUTH2_GRANT_TYPE_TOKEN[] = "token";
+const char OAUTH2_GRANT_TYPE_PASSWORD[] = "password";
+const char OAUTH2_GRANT_TYPE_DEVICE[] = "urn:ietf:params:oauth:grant-type:device_code";
+const char OAUTH2_GRANT_TYPE[] = "grant_type";
+const char OAUTH2_API_KEY[] = "api_key";
+const char OAUTH2_STATE[] = "state";
+const char OAUTH2_CODE[] = "code";
+
+// OAuth 2 Response Parameters
+const char OAUTH2_ACCESS_TOKEN[] = "access_token";
+const char OAUTH2_REFRESH_TOKEN[] = "refresh_token";
+const char OAUTH2_EXPIRES_IN[] = "expires_in";
+const char OAUTH2_DEVICE_CODE[] = "device_code";
+const char OAUTH2_USER_CODE[] = "user_code";
+const char OAUTH2_VERIFICATION_URI[] = "verification_uri";
+const char OAUTH2_VERIFICATION_URL[] = "verification_url"; // Google sign-in
+const char OAUTH2_VERIFICATION_URI_COMPLETE[] = "verification_uri_complete";
+const char OAUTH2_INTERVAL[] = "interval";
+
+// Parameter values
+const char AUTHORIZATION_CODE[] = "authorization_code";
+
+// Standard HTTP headers
+const char HTTP_HTTP_HEADER[] = "HTTP";
+const char HTTP_AUTHORIZATION_HEADER[] = "Authorization";
+
+}
diff --git a/libraries/katabasis/include/katabasis/OAuth2.h b/libraries/katabasis/include/katabasis/OAuth2.h
new file mode 100644
index 00000000..4361691c
--- /dev/null
+++ b/libraries/katabasis/include/katabasis/OAuth2.h
@@ -0,0 +1,233 @@
+#pragma once
+
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QPair>
+
+#include "Reply.h"
+#include "RequestParameter.h"
+#include "Bits.h"
+
+namespace Katabasis {
+
+class ReplyServer;
+class PollServer;
+
+
+/*
+ * FIXME: this is not as simple as it should be. it squishes 4 different grant flows into one big ball of mud
+ * This serves no practical purpose and simply makes the code less readable / maintainable.
+ *
+ * Therefore: Split this into the 4 different OAuth2 flows that people can use as authentication steps. Write tests/examples for all of them.
+ */
+
+/// Simple OAuth2 authenticator.
+class OAuth2: public QObject
+{
+ Q_OBJECT
+public:
+ Q_ENUMS(GrantFlow)
+
+public:
+
+ struct Options {
+ QString userAgent = QStringLiteral("Katabasis/1.0");
+ QString redirectionUrl = QStringLiteral("http://localhost:%1");
+ QString responseType = QStringLiteral("code");
+ QString scope;
+ QString clientIdentifier;
+ QString clientSecret;
+ QUrl authorizationUrl;
+ QUrl accessTokenUrl;
+ QVector<quint16> listenerPorts = { 0 };
+ };
+
+ /// Authorization flow types.
+ enum GrantFlow {
+ GrantFlowAuthorizationCode, ///< @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.1
+ GrantFlowImplicit, ///< @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.2
+ GrantFlowResourceOwnerPasswordCredentials,
+ GrantFlowDevice ///< @see https://tools.ietf.org/html/rfc8628#section-1
+ };
+
+ /// Authorization flow.
+ GrantFlow grantFlow();
+ void setGrantFlow(GrantFlow value);
+
+public:
+ /// Are we authenticated?
+ bool linked();
+
+ /// Authentication token.
+ QString token();
+
+ /// Provider-specific extra tokens, available after a successful authentication
+ QVariantMap extraTokens();
+
+ /// Page content on local host after successful oauth.
+ /// Provide it in case you do not want to close the browser, but display something
+ QByteArray replyContent() const;
+ void setReplyContent(const QByteArray &value);
+
+public:
+
+ // TODO: remove
+ /// Resource owner username.
+ /// instances with the same (username, password) share the same "linked" and "token" properties.
+ QString username();
+ void setUsername(const QString &value);
+
+ // TODO: remove
+ /// Resource owner password.
+ /// instances with the same (username, password) share the same "linked" and "token" properties.
+ QString password();
+ void setPassword(const QString &value);
+
+ // TODO: remove
+ /// API key.
+ QString apiKey();
+ void setApiKey(const QString &value);
+
+ // TODO: remove
+ /// Allow ignoring SSL errors?
+ /// E.g. SurveyMonkey fails on Mac due to SSL error. Ignoring the error circumvents the problem
+ bool ignoreSslErrors();
+ void setIgnoreSslErrors(bool ignoreSslErrors);
+
+ // TODO: put in `Options`
+ /// User-defined extra parameters to append to request URL
+ QVariantMap extraRequestParams();
+ void setExtraRequestParams(const QVariantMap &value);
+
+ // TODO: split up the class into multiple, each implementing one OAuth2 flow
+ /// Grant type (if non-standard)
+ QString grantType();
+ void setGrantType(const QString &value);
+
+public:
+ /// Constructor.
+ /// @param parent Parent object.
+ explicit OAuth2(Options & opts, Token & token, QObject *parent = 0, QNetworkAccessManager *manager = 0);
+
+ /// Get refresh token.
+ QString refreshToken();
+
+ /// Get token expiration time
+ QDateTime expires();
+
+public slots:
+ /// Authenticate.
+ virtual void link();
+
+ /// De-authenticate.
+ virtual void unlink();
+
+ /// Refresh token.
+ bool refresh();
+
+ /// Handle situation where reply server has opted to close its connection
+ void serverHasClosed(bool paramsfound = false);
+
+signals:
+ /// Emitted when a token refresh has been completed or failed.
+ void refreshFinished(QNetworkReply::NetworkError error);
+
+ /// Emitted when client needs to open a web browser window, with the given URL.
+ void openBrowser(const QUrl &url);
+
+ /// Emitted when client can close the browser window.
+ void closeBrowser();
+
+ /// Emitted when client needs to show a verification uri and user code
+ void showVerificationUriAndCode(const QUrl &uri, const QString &code);
+
+ /// Emitted when authentication/deauthentication succeeded.
+ void linkingSucceeded();
+
+ /// Emitted when authentication/deauthentication failed.
+ void linkingFailed();
+
+ void activityChanged(Activity activity);
+
+public slots:
+ /// Handle verification response.
+ virtual void onVerificationReceived(QMap<QString, QString>);
+
+protected slots:
+ /// Handle completion of a token request.
+ virtual void onTokenReplyFinished();
+
+ /// Handle failure of a token request.
+ virtual void onTokenReplyError(QNetworkReply::NetworkError error);
+
+ /// Handle completion of a refresh request.
+ virtual void onRefreshFinished();
+
+ /// Handle failure of a refresh request.
+ virtual void onRefreshError(QNetworkReply::NetworkError error);
+
+ /// Handle completion of a Device Authorization Request
+ virtual void onDeviceAuthReplyFinished();
+
+protected:
+ /// Build HTTP request body.
+ QByteArray buildRequestBody(const QMap<QString, QString> &parameters);
+
+ /// Set refresh token.
+ void setRefreshToken(const QString &v);
+
+ /// Set token expiration time.
+ void setExpires(QDateTime v);
+
+ /// Start polling authorization server
+ void startPollServer(const QVariantMap &params);
+
+ /// Set authentication token.
+ void setToken(const QString &v);
+
+ /// Set the linked state
+ void setLinked(bool v);
+
+ /// Set extra tokens found in OAuth response
+ void setExtraTokens(QVariantMap extraTokens);
+
+ /// Set local reply server
+ void setReplyServer(ReplyServer *server);
+
+ ReplyServer * replyServer() const;
+
+ /// Set local poll server
+ void setPollServer(PollServer *server);
+
+ PollServer * pollServer() const;
+
+ void updateActivity(Activity activity);
+
+protected:
+ QString username_;
+ QString password_;
+
+ Options options_;
+
+ QVariantMap extraReqParams_;
+ QString apiKey_;
+ QNetworkAccessManager *manager_ = nullptr;
+ ReplyList timedReplies_;
+ GrantFlow grantFlow_;
+ QString grantType_;
+
+protected:
+ QString redirectUri_;
+ Token &token_;
+
+ // this should be part of the reply server impl
+ QByteArray replyContent_;
+
+private:
+ ReplyServer *replyServer_ = nullptr;
+ PollServer *pollServer_ = nullptr;
+ Activity activity_ = Activity::Idle;
+};
+
+}
diff --git a/libraries/katabasis/include/katabasis/PollServer.h b/libraries/katabasis/include/katabasis/PollServer.h
new file mode 100644
index 00000000..77103867
--- /dev/null
+++ b/libraries/katabasis/include/katabasis/PollServer.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <QByteArray>
+#include <QMap>
+#include <QNetworkRequest>
+#include <QObject>
+#include <QString>
+#include <QTimer>
+
+class QNetworkAccessManager;
+
+namespace Katabasis {
+
+/// Poll an authorization server for token
+class PollServer : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit PollServer(QNetworkAccessManager * manager, const QNetworkRequest &request, const QByteArray & payload, int expiresIn, QObject *parent = 0);
+
+ /// Seconds to wait between polling requests
+ Q_PROPERTY(int interval READ interval WRITE setInterval)
+ int interval() const;
+ void setInterval(int interval);
+
+signals:
+ void verificationReceived(QMap<QString, QString>);
+ void serverClosed(bool); // whether it has found parameters
+
+public slots:
+ void startPolling();
+
+protected slots:
+ void onPollTimeout();
+ void onExpiration();
+ void onReplyFinished();
+
+protected:
+ QNetworkAccessManager *manager_;
+ const QNetworkRequest request_;
+ const QByteArray payload_;
+ const int expiresIn_;
+ QTimer expirationTimer;
+ QTimer pollTimer;
+};
+
+}
diff --git a/libraries/katabasis/include/katabasis/Reply.h b/libraries/katabasis/include/katabasis/Reply.h
new file mode 100644
index 00000000..3af1d49f
--- /dev/null
+++ b/libraries/katabasis/include/katabasis/Reply.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include <QList>
+#include <QTimer>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QNetworkAccessManager>
+#include <QByteArray>
+
+namespace Katabasis {
+
+/// A network request/reply pair that can time out.
+class Reply: public QTimer {
+ Q_OBJECT
+
+public:
+ Reply(QNetworkReply *reply, int timeOut = 60 * 1000, QObject *parent = 0);
+
+signals:
+ void error(QNetworkReply::NetworkError);
+
+public slots:
+ /// When time out occurs, the QNetworkReply's error() signal is triggered.
+ void onTimeOut();
+
+public:
+ QNetworkReply *reply;
+};
+
+/// List of O2Replies.
+class ReplyList {
+public:
+ ReplyList() { ignoreSslErrors_ = false; }
+
+ /// Destructor.
+ /// Deletes all O2Reply instances in the list.
+ virtual ~ReplyList();
+
+ /// Create a new O2Reply from a QNetworkReply, and add it to this list.
+ void add(QNetworkReply *reply);
+
+ /// Add an O2Reply to the list, while taking ownership of it.
+ void add(Reply *reply);
+
+ /// Remove item from the list that corresponds to a QNetworkReply.
+ void remove(QNetworkReply *reply);
+
+ /// Find an O2Reply in the list, corresponding to a QNetworkReply.
+ /// @return Matching O2Reply or NULL.
+ Reply *find(QNetworkReply *reply);
+
+ bool ignoreSslErrors();
+ void setIgnoreSslErrors(bool ignoreSslErrors);
+
+protected:
+ QList<Reply *> replies_;
+ bool ignoreSslErrors_;
+};
+
+}
diff --git a/libraries/katabasis/include/katabasis/ReplyServer.h b/libraries/katabasis/include/katabasis/ReplyServer.h
new file mode 100644
index 00000000..bf47df69
--- /dev/null
+++ b/libraries/katabasis/include/katabasis/ReplyServer.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <QTcpServer>
+#include <QMap>
+#include <QByteArray>
+#include <QString>
+
+namespace Katabasis {
+
+/// HTTP server to process authentication response.
+class ReplyServer: public QTcpServer {
+ Q_OBJECT
+
+public:
+ explicit ReplyServer(QObject *parent = 0);
+
+ /// Page content on local host after successful oauth - in case you do not want to close the browser, but display something
+ Q_PROPERTY(QByteArray replyContent READ replyContent WRITE setReplyContent)
+ QByteArray replyContent();
+ void setReplyContent(const QByteArray &value);
+
+ /// Seconds to keep listening *after* first response for a callback with token content
+ Q_PROPERTY(int timeout READ timeout WRITE setTimeout)
+ int timeout();
+ void setTimeout(int timeout);
+
+ /// Maximum number of callback tries to accept, in case some don't have token content (favicons, etc.)
+ Q_PROPERTY(int callbackTries READ callbackTries WRITE setCallbackTries)
+ int callbackTries();
+ void setCallbackTries(int maxtries);
+
+ QString uniqueState();
+ void setUniqueState(const QString &state);
+
+signals:
+ void verificationReceived(QMap<QString, QString>);
+ void serverClosed(bool); // whether it has found parameters
+
+public slots:
+ void onIncomingConnection();
+ void onBytesReady();
+ QMap<QString, QString> parseQueryParams(QByteArray *data);
+ void closeServer(QTcpSocket *socket = 0, bool hasparameters = false);
+
+protected:
+ QByteArray replyContent_;
+ int timeout_;
+ int maxtries_;
+ int tries_;
+ QString uniqueState_;
+};
+
+}
diff --git a/libraries/katabasis/include/katabasis/RequestParameter.h b/libraries/katabasis/include/katabasis/RequestParameter.h
new file mode 100644
index 00000000..ca36934a
--- /dev/null
+++ b/libraries/katabasis/include/katabasis/RequestParameter.h
@@ -0,0 +1,15 @@
+#pragma once
+
+namespace Katabasis {
+
+/// Request parameter (name-value pair) participating in authentication.
+struct RequestParameter {
+ RequestParameter(const QByteArray &n, const QByteArray &v): name(n), value(v) {}
+ bool operator <(const RequestParameter &other) const {
+ return (name == other.name)? (value < other.value): (name < other.name);
+ }
+ QByteArray name;
+ QByteArray value;
+};
+
+}
diff --git a/libraries/katabasis/include/katabasis/Requestor.h b/libraries/katabasis/include/katabasis/Requestor.h
new file mode 100644
index 00000000..61437f76
--- /dev/null
+++ b/libraries/katabasis/include/katabasis/Requestor.h
@@ -0,0 +1,116 @@
+#pragma once
+#include <QObject>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QNetworkAccessManager>
+#include <QUrl>
+#include <QByteArray>
+#include <QHttpMultiPart>
+
+#include "Reply.h"
+
+namespace Katabasis {
+
+class OAuth2;
+
+/// Makes authenticated requests.
+class Requestor: public QObject {
+ Q_OBJECT
+
+public:
+ explicit Requestor(QNetworkAccessManager *manager, OAuth2 *authenticator, QObject *parent = 0);
+ ~Requestor();
+
+
+ /// Some services require the access token to be sent as a Authentication HTTP header
+ /// and refuse requests with the access token in the query.
+ /// This function allows to use or ignore the access token in the query.
+ /// The default value of `true` means that the query will contain the access token.
+ /// By setting the value to false, the query will not contain the access token.
+ /// See:
+ /// https://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-16#section-4.3
+ /// https://tools.ietf.org/html/rfc6750#section-2.3
+
+ void setAddAccessTokenInQuery(bool value);
+
+ /// Some services require the access token to be sent as a Authentication HTTP header.
+ /// This is the case for Twitch and Mixer.
+ /// When the access token expires and is refreshed, O2Requestor::retry() needs to update the Authentication HTTP header.
+ /// In order to do so, O2Requestor needs to know the format of the Authentication HTTP header.
+ void setAccessTokenInAuthenticationHTTPHeaderFormat(const QString &value);
+
+public slots:
+ /// Make a GET request.
+ /// @return Request ID or -1 if there are too many requests in the queue.
+ int get(const QNetworkRequest &req, int timeout = 60*1000);
+
+ /// Make a POST request.
+ /// @return Request ID or -1 if there are too many requests in the queue.
+ int post(const QNetworkRequest &req, const QByteArray &data, int timeout = 60*1000);
+ int post(const QNetworkRequest &req, QHttpMultiPart* data, int timeout = 60*1000);
+
+ /// Make a PUT request.
+ /// @return Request ID or -1 if there are too many requests in the queue.
+ int put(const QNetworkRequest &req, const QByteArray &data, int timeout = 60*1000);
+ int put(const QNetworkRequest &req, QHttpMultiPart* data, int timeout = 60*1000);
+
+ /// Make a HEAD request.
+ /// @return Request ID or -1 if there are too many requests in the queue.
+ int head(const QNetworkRequest &req, int timeout = 60*1000);
+
+ /// Make a custom request.
+ /