mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-22 00:06:12 -05:00
Re-sync external o2 library
Keep a few downstream patches: - Oauth2 PKCE initial support (76df15690c5b3e7fd2f97177cd8e743546821f07) - Find QtKeychain by its cmake target (b9e859f0ed1d9d783c0a7b4f28e3d73ac21572f6) - Allow compiling o2 with Qt6 (6fbe9a4fb3a29bbbd32987153303181d3d4362cd) - Hide more debug noise (1f91895b1e8d4ca8dd2bb24b0ea35f5bcb425a96) - If an o2 auth refresh reply contains an error message, then the refresh was NOT successful (9af5a531b1a9c4b452b98c0a10387aefa850edee) - Ensure correct thread locale QgsNetworkAccessManager is used during o2 requests (9cde65457b3717a74e32277c843a2945eb4f1221)
This commit is contained in:
parent
725cb445e7
commit
806bbb2bfb
211
external/o2/README.md
vendored
211
external/o2/README.md
vendored
@ -4,9 +4,11 @@ This library encapsulates the OAuth 1.0 and 2.0 client authentication flows, and
|
||||
|
||||
The primary target is Qt Quick applications on embedded devices.
|
||||
|
||||
Supported Qt versions: 5 and 6.
|
||||
|
||||
Notes to contributors:
|
||||
|
||||
* Please follow the coding style of the existing source
|
||||
* Please follow the coding style of the existing source code
|
||||
* Code contributions are released under Simplified BSD License, as specified in LICENSE. Do not contribute if this license does not suit your code
|
||||
|
||||
## Classes
|
||||
@ -25,17 +27,21 @@ O1Freshbooks | o1freshbooks.h | Freshbooks OAuth specialization
|
||||
O1Requestor | o1requestor.h | Makes authenticated OAuth 1.0 requests: GET, POST or PUT, handles timeouts
|
||||
O1RequestParameter | o1.h | An extra request parameter participating in request signing
|
||||
O1Twitter | o1twitter.h | Twitter OAuth specialization
|
||||
O1SmugMug | o1smugmug.h | SmugMug OAuth specialization
|
||||
O2 | o2.h | Generic OAuth 2.0 authenticator
|
||||
O2Facebook | o2facebook.h | Facebook OAuth specialization
|
||||
O2Gft | o2gft.h | Google Fusion Tables OAuth specialization
|
||||
O2Google | o2google.h | Google Oauth specialization [scopes](https://developers.google.com/identity/protocols/googlescopes)
|
||||
O2GoogleDevice | o2google.h | Google [Sign-In for TVs and Devices](https://developers.google.com/identity/sign-in/devices)
|
||||
O2Hubic | o2hubic.h | Hubic OAuth specialization
|
||||
O2Msgraph | o2msgraph.h | Microsoft Graph OAuth specialization
|
||||
O2Reply | o2reply.h | A network request/reply that can time out
|
||||
O2ReplyServer | o2replyserver.h | HTTP server to process authentication responses
|
||||
O2Requestor | o2requestor.h | Makes authenticated OAuth 2.0 requests (GET, POST or PUT), handles timeouts and token expiry
|
||||
O2Skydrive | o2skydrive.h | OneDrive OAuth specialization
|
||||
O2SurveyMonkey | o2surveymonkey.h | SurveyMonkey OAuth specialization
|
||||
OXTwitter | oxtwitter.h | Twitter XAuth specialization
|
||||
O2Uber | o2uber.h | Uber OAuth specialization
|
||||
|
||||
## Installation
|
||||
|
||||
@ -49,24 +55,28 @@ This example assumes a hypothetical Twitter client that will post tweets. Twitte
|
||||
|
||||
Include the required header files, and have some member variables that will be used for authentication and sending requests:
|
||||
|
||||
#include "o1twitter.h"
|
||||
#include "o1requestor.h"
|
||||
O1Twitter *o1;
|
||||
```c++
|
||||
#include "o1twitter.h"
|
||||
#include "o1requestor.h"
|
||||
O1Twitter *o1;
|
||||
```
|
||||
|
||||
### Initialization
|
||||
|
||||
Instantiate one of the authenticator classes, like O1Twitter, set your application ID and application secret, and install the signal handlers:
|
||||
|
||||
o1 = new O1Twitter(this);
|
||||
o1->setClientId(MY_CLIENT_ID);
|
||||
o1->setClientSecret(MY_CLIENT_SECRET);
|
||||
connect(o1, SIGNAL(linkedChanged()), this, SLOT(onLinkedChanged()));
|
||||
connect(o1, SIGNAL(linkingFailed()), this, SLOT(onLinkingFailed()));
|
||||
connect(o1, SIGNAL(linkingSucceeded()), this, SLOT(onLinkingSucceeded()));
|
||||
connect(o1, SIGNAL(openBrowser(QUrl)), this, SLOT(onOpenBrowser(QUrl)));
|
||||
connect(o1, SIGNAL(closeBrowser()), this, SLOT(onCloseBrowser()));
|
||||
```c++
|
||||
o1 = new O1Twitter(this);
|
||||
o1->setClientId(MY_CLIENT_ID);
|
||||
o1->setClientSecret(MY_CLIENT_SECRET);
|
||||
connect(o1, SIGNAL(linkedChanged()), this, SLOT(onLinkedChanged()));
|
||||
connect(o1, SIGNAL(linkingFailed()), this, SLOT(onLinkingFailed()));
|
||||
connect(o1, SIGNAL(linkingSucceeded()), this, SLOT(onLinkingSucceeded()));
|
||||
connect(o1, SIGNAL(openBrowser(QUrl)), this, SLOT(onOpenBrowser(QUrl)));
|
||||
connect(o1, SIGNAL(closeBrowser()), this, SLOT(onCloseBrowser()));
|
||||
```
|
||||
|
||||
**Note:** For browserless Twitter authentication, you can use the OXTwitter specialized class which can do Twitter XAuth. You will need to additionally provide your Twitter login credentials (username & password) before calling *link()*.
|
||||
**Note:** For browserless Twitter authentication, you can use the OXTwitter specialized class that can do Twitter XAuth. You will need to additionally provide your Twitter login credentials (username & password) before calling *link()*.
|
||||
|
||||
### Handling Signals
|
||||
|
||||
@ -74,35 +84,46 @@ O2 is an asynchronous library. It will send signals at various stages of authent
|
||||
|
||||
To handle these signals, implement the following slots in your code:
|
||||
|
||||
void onLinkedChanged() {
|
||||
// Linking (login) state has changed.
|
||||
// Use o1->linked() to get the actual state
|
||||
}
|
||||
```c++
|
||||
void onLinkedChanged() {
|
||||
// Linking (login) state has changed.
|
||||
// Use o1->linked() to get the actual state
|
||||
}
|
||||
|
||||
void onLinkingFailed() {
|
||||
// Login has failed
|
||||
}
|
||||
void onLinkingFailed() {
|
||||
// Login has failed
|
||||
}
|
||||
|
||||
void onLinkingSucceeded() {
|
||||
// Login has succeeded
|
||||
}
|
||||
void onLinkingSucceeded() {
|
||||
// Login has succeeded
|
||||
}
|
||||
|
||||
void onOpenBrowser(const QUrl *url) {
|
||||
// Open a web browser or a web view with the given URL.
|
||||
// The user will interact with this browser window to
|
||||
// enter login name, password, and authorize your application
|
||||
// to access the Twitter account
|
||||
}
|
||||
void onOpenBrowser(const QUrl *url) {
|
||||
// Open a web browser or a web view with the given URL.
|
||||
// The user will interact with this browser window to
|
||||
// enter login name, password, and authorize your application
|
||||
// to access the Twitter account
|
||||
}
|
||||
|
||||
void onCloseBrowser() {
|
||||
// Close the browser window opened in openBrowser()
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** From _onOpenBrowser_, prefer opening a web view, instead of a full-blown external browser.
|
||||
|
||||
**Note:** If you _must_ use an external browser on Android, change this line in the Qt-generated manifest.xml:
|
||||
|
||||
```meta-data android:name="android.app.background_running" android:value="true"```
|
||||
|
||||
void onCloseBrowser() {
|
||||
// Close the browser window opened in openBrowser()
|
||||
}
|
||||
|
||||
### Logging In
|
||||
|
||||
To log in (e.g. to link your application to the OAuth service), call the link() method:
|
||||
|
||||
o1->link();
|
||||
```c++
|
||||
o1->link();
|
||||
```
|
||||
|
||||
This initiates the authentication sequence. Your signal handlers above will be called at various stages. Lastly, if linking succeeds, onLinkingSucceeded() will be called.
|
||||
|
||||
@ -110,7 +131,9 @@ This initiates the authentication sequence. Your signal handlers above will be c
|
||||
|
||||
To log out, call the unlink() method:
|
||||
|
||||
o1->unlink();
|
||||
```c++
|
||||
o1->unlink();
|
||||
```
|
||||
|
||||
Logging out always succeeds, and requires no user interaction.
|
||||
|
||||
@ -120,86 +143,108 @@ Once linked, you can start sending authenticated requests to the service. We sta
|
||||
|
||||
First we need a Qt network manager and an O1 requestor object:
|
||||
|
||||
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||
O1Requestor *requestor = new O1Requestor(manager, o1, this);
|
||||
```c++
|
||||
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||
O1Requestor *requestor = new O1Requestor(manager, o1, this);
|
||||
```
|
||||
|
||||
Next, create parameters for posting the update:
|
||||
|
||||
QByteArray paramName("status");
|
||||
QByteArray tweetText("My first tweet!");
|
||||
```c++
|
||||
QByteArray paramName("status");
|
||||
QByteArray tweetText("My first tweet!");
|
||||
|
||||
QList<O1RequestParameter> requestParams = QList<O1RequestParameter>();
|
||||
requestParams << O1RequestParameter(paramName, tweetText);
|
||||
QList<O1RequestParameter> requestParams = QList<O1RequestParameter>();
|
||||
requestParams << O1RequestParameter(paramName, tweetText);
|
||||
|
||||
QByteArray postData = O1::createQueryParams(requestParams);
|
||||
QByteArray postData = O1::createQueryParams(requestParams);
|
||||
|
||||
// Using Twitter's REST API ver 1.1
|
||||
QUrl url = QUrl("https://api.twitter.com/1.1/statuses/update.json");
|
||||
// Using Twitter's REST API ver 1.1
|
||||
QUrl url = QUrl("https://api.twitter.com/1.1/statuses/update.json");
|
||||
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, O2_MIME_TYPE_XFORM);
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, O2_MIME_TYPE_XFORM);
|
||||
```
|
||||
|
||||
Finally we authenticate and send the request using the O1 requestor object:
|
||||
|
||||
QNetworkReply *reply = requestor->post(request, reqestParams, postData);
|
||||
```c++
|
||||
QNetworkReply *reply = requestor->post(request, reqestParams, postData);
|
||||
```
|
||||
|
||||
Continuing with the example, we will now send a tweet containing an image as well as a message.
|
||||
|
||||
We create an HTTP request containing the image and the message, in the format specified by Twitter:
|
||||
|
||||
QString imagePath("/tmp/image.jpg");
|
||||
QString message("My tweet with an image!");
|
||||
```c++
|
||||
QString imagePath("/tmp/image.jpg");
|
||||
QString message("My tweet with an image!");
|
||||
|
||||
QFileInfo fileInfo(imagePath);
|
||||
QFile file(imagePath);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QFileInfo fileInfo(imagePath);
|
||||
QFile file(imagePath);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
||||
QString boundary("7d44e178b0439");
|
||||
QByteArray data(QString("--" + boundary + "\r\n").toAscii());
|
||||
data += "Content-Disposition: form-data; name=\"media[]\"; filename=\"" + fileInfo.fileName() + "\"\r\n";
|
||||
data += "Content-Transfer-Encoding: binary\r\n";
|
||||
data += "Content-Type: application/octet-stream\r\n\r\n";
|
||||
data += file.readAll();
|
||||
file.close();
|
||||
data += QString("\r\n--") + boundary + "\r\n";
|
||||
data += "Content-Disposition: form-data; name=\"status\"\r\n";
|
||||
data += "Content-Transfer-Encoding: binary\r\n";
|
||||
data += "Content-Type: text/plain; charset=utf-8\r\n\r\n";
|
||||
data += message.toUtf8();
|
||||
data += QString("\r\n--") + boundary + "--\r\n";
|
||||
QString boundary("7d44e178b0439");
|
||||
QByteArray data(QString("--" + boundary + "\r\n").toAscii());
|
||||
data += "Content-Disposition: form-data; name=\"media[]\"; filename=\"" + fileInfo.fileName() + "\"\r\n";
|
||||
data += "Content-Transfer-Encoding: binary\r\n";
|
||||
data += "Content-Type: application/octet-stream\r\n\r\n";
|
||||
data += file.readAll();
|
||||
file.close();
|
||||
data += QString("\r\n--") + boundary + "\r\n";
|
||||
data += "Content-Disposition: form-data; name=\"status\"\r\n";
|
||||
data += "Content-Transfer-Encoding: binary\r\n";
|
||||
data += "Content-Type: text/plain; charset=utf-8\r\n\r\n";
|
||||
data += message.toUtf8();
|
||||
data += QString("\r\n--") + boundary + "--\r\n";
|
||||
|
||||
QNetworkRequest request;
|
||||
// Using Twitter's REST API ver 1.1
|
||||
request.setUrl(QUrl("https://api.twitter.com/1.1/statuses/update_with_media.json"));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + boundary);
|
||||
request.setHeader(QNetworkRequest::ContentLengthHeader, data.length());
|
||||
QNetworkRequest request;
|
||||
// Using Twitter's REST API ver 1.1
|
||||
request.setUrl(QUrl("https://api.twitter.com/1.1/statuses/update_with_media.json"));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + boundary);
|
||||
request.setHeader(QNetworkRequest::ContentLengthHeader, data.length());
|
||||
|
||||
QNetworkReply *reply = requestor->post(request, QList<O1RequestParameter>(), data);
|
||||
QNetworkReply *reply = requestor->post(request, QList<O1RequestParameter>(), data);
|
||||
```
|
||||
|
||||
That's it. Tweets using the O2 library!
|
||||
|
||||
### Storing OAuth Tokens
|
||||
|
||||
O2 provides simple storage classes for writing OAuth tokens in a persistent location. Currently, a QSettings based backing store **O2SettingsStore** is provided in O2. O2SettingsStore keeps all token values in an encrypted form. You have to specify the encryption key to use while constructing the object:
|
||||
O2 provides simple storage classes for writing OAuth tokens in a peristent location. Currently, a QSettings based backing store **O0SettingsStore** is provided in O2. O2SettingsStore keeps all token values in an encrypted form. You have to specify the encryption key to use while constructing the object:
|
||||
|
||||
O0SettingsStore settings = new O0SettingsStore("myencryptionkey");
|
||||
// Set the store before starting OAuth, i.e before calling link()
|
||||
o1->setStore(settings);
|
||||
...
|
||||
```c++
|
||||
O0SettingsStore *settings = new O0SettingsStore("myencryptionkey");
|
||||
// Set the store before starting OAuth, i.e before calling link()
|
||||
o1->setStore(settings);
|
||||
// ...
|
||||
```
|
||||
|
||||
Once set, the O0BaseAuth takes ownership of the O0SettingsStore object.
|
||||
|
||||
You can also create it with your customized QSettings object. O2SettingsStore will then use that QSettings object for storing the tokens:
|
||||
|
||||
O0SettingsStore settings = new O0SettingsStore(mySettingsObject, "myencryptionkey");
|
||||
```c++
|
||||
O0SettingsStore *settings = new O0SettingsStore(mySettingsObject, "myencryptionkey");
|
||||
```
|
||||
|
||||
Once set, O2SettingsStore takes ownership of the QSettings object.
|
||||
|
||||
**Note:** If you do not specify a storage object to use, O2 will create one by default (which QSettings based), and use it. In such a case, a default encryption key is used for encrypting the data.
|
||||
**Note:** If you do not specify a storage object to use, O2 will create one by default (which QSettings based), and use it. In such a case, a default encryption key is used for encrypting the data. *This is not a secure solution: prefer storing the tokens in a Keychain or Wallet based facility instead*.
|
||||
|
||||
**Note:** If using O2SettingsStore, make sure organization name, domain and application name are set:
|
||||
|
||||
```c++
|
||||
QCoreApplication::setOrganizationName("MySoft");
|
||||
QCoreApplication::setOrganizationDomain("mysoft.com");
|
||||
QCoreApplication::setApplicationName("Star Runner");
|
||||
```
|
||||
|
||||
### Extra OAuth Tokens
|
||||
|
||||
Some OAuth service providers provide additional information in the access token response. Eg: Twitter returns 2 additional tokens in it's access token response - *screen_name* and *user_id*.
|
||||
Some OAuth services provide additional information in the access token response. For example Twitter returns two additional tokens: *screen_name* and *user_id*.
|
||||
|
||||
O2 provides all such tokens via the property - *extraTokens*. You can query this property after a successful OAuth exchange, i.e after the *linkingSucceeded()* signal has been emitted.
|
||||
O2 exposes such tokens via the property *extraTokens*. You can query this property after a successful OAuth exchange, i.e after the *linkingSucceeded()* signal has been emitted.
|
||||
|
||||
## More Examples
|
||||
|
||||
@ -213,11 +258,11 @@ twitterdemo | Command line client for authenticating with Twitter and posting st
|
||||
|
||||
## Change Log
|
||||
|
||||
### 1.0.2
|
||||
|
||||
* Last Qt5-only release
|
||||
|
||||
### 0.1.0
|
||||
|
||||
* Persist the extra tokens, too
|
||||
* Add Qt Quick Twitter client example
|
||||
|
||||
|
||||
|
||||
|
||||
|
4
external/o2/README_QGIS.txt
vendored
4
external/o2/README_QGIS.txt
vendored
@ -1,4 +1,2 @@
|
||||
|
||||
O2 Library from https://github.com/pipacs/o2/archive/31ceafb3f0c3b605110ddd20aeebd3288504ee1f.tar.gz
|
||||
|
||||
Note: current master build of O2 is broken if built with keychain support
|
||||
O2 Library from https://github.com/pipacs/o2/archive/99902cc37e083a8311c1f8eee918e93c93cbc937.tar.gz
|
||||
|
2
external/o2/o2.pc.cmake
vendored
2
external/o2/o2.pc.cmake
vendored
@ -7,4 +7,4 @@ Description: OAuth 2.0 for Qt
|
||||
Version: @PROJECT_VERSION@
|
||||
|
||||
Cflags: -I${includedir} @CMAKE_INCLUDE_PATH@
|
||||
Libs: -L${libdir} @CMAKE_LIBRARY_PATH@
|
||||
Libs: -L${libdir} -lo2
|
||||
|
50
external/o2/src/CMakeLists.txt
vendored
50
external/o2/src/CMakeLists.txt
vendored
@ -20,16 +20,19 @@ endif(NOT o2_WITH_QT5)
|
||||
|
||||
set( o2_SRCS
|
||||
o2.cpp
|
||||
o2pollserver.cpp
|
||||
o2reply.cpp
|
||||
o2replyserver.cpp
|
||||
o2requestor.cpp
|
||||
o2simplecrypt.cpp
|
||||
o0jsonresponse.cpp
|
||||
o0settingsstore.cpp
|
||||
o0baseauth.cpp
|
||||
)
|
||||
|
||||
set( o2_HDRS
|
||||
o2.h
|
||||
o2pollserver.h
|
||||
o2reply.h
|
||||
o2replyserver.h
|
||||
o2requestor.h
|
||||
@ -37,6 +40,7 @@ set( o2_HDRS
|
||||
o0baseauth.h
|
||||
o0export.h
|
||||
o0globals.h
|
||||
o0jsonresponse.h
|
||||
o0requestparameter.h
|
||||
o0settingsstore.h
|
||||
o0simplecrypt.h
|
||||
@ -82,14 +86,27 @@ if(o2_WITH_GOOGLE)
|
||||
${o2_SRCS}
|
||||
o2gft.cpp
|
||||
o2google.cpp
|
||||
o2googledevice.cpp
|
||||
)
|
||||
set( o2_HDRS
|
||||
${o2_HDRS}
|
||||
o2gft.h
|
||||
o2google.h
|
||||
o2googledevice.h
|
||||
)
|
||||
endif(o2_WITH_GOOGLE)
|
||||
|
||||
if(o2_WITH_VIMEO)
|
||||
set( o2_SRCS
|
||||
${o2_SRCS}
|
||||
o2vimeo.cpp
|
||||
)
|
||||
set( o2_HDRS
|
||||
${o2_HDRS}
|
||||
o2vimeo.h
|
||||
)
|
||||
endif(o2_WITH_VIMEO)
|
||||
|
||||
if(o2_WITH_FACEBOOK)
|
||||
set( o2_SRCS
|
||||
${o2_SRCS}
|
||||
@ -152,6 +169,27 @@ if(o2_WITH_SURVEYMONKEY)
|
||||
)
|
||||
endif(o2_WITH_SURVEYMONKEY)
|
||||
|
||||
if(o2_WITH_SMUGMUG)
|
||||
set( o2_SRCS
|
||||
${o2_SRCS}
|
||||
o1smugmug.cpp
|
||||
)
|
||||
set( o2_HDRS
|
||||
${o2_HDRS}
|
||||
o1smugmug.h
|
||||
)
|
||||
endif(o2_WITH_SMUGMUG)
|
||||
|
||||
if(o2_WITH_MSGRAPH)
|
||||
set( o2_SRCS
|
||||
${o2_SRCS}
|
||||
o2msgraph.cpp
|
||||
)
|
||||
set( o2_HDRS
|
||||
${o2_HDRS}
|
||||
o2msgraph.h
|
||||
)
|
||||
endif(o2_WITH_MSGRAPH)
|
||||
|
||||
if(o2_WITH_KEYCHAIN)
|
||||
if (Qt5Core_DIR)
|
||||
@ -160,7 +198,7 @@ if(o2_WITH_KEYCHAIN)
|
||||
find_package(QtKeychain REQUIRED)
|
||||
endif()
|
||||
if(QTKEYCHAIN_FOUND OR QT5KEYCHAIN_FOUND)
|
||||
message("Found QTKeychain")
|
||||
MESSAGE("Found QTKeychain")
|
||||
list(APPEND LINK_TARGETS ${QTKEYCHAIN_LIBRARY})
|
||||
include_directories(${QTKEYCHAIN_INCLUDE_DIR})
|
||||
set( o2_SRCS
|
||||
@ -172,7 +210,7 @@ if(o2_WITH_KEYCHAIN)
|
||||
o0keychainstore.h
|
||||
)
|
||||
else()
|
||||
message("Qt5Keychain or QtKeychain is required")
|
||||
MESSAGE("Qt5Keychain or QtKeychain is required")
|
||||
endif()
|
||||
|
||||
|
||||
@ -229,5 +267,9 @@ install(FILES ${o2_HDRS}
|
||||
)
|
||||
|
||||
message(STATUS "Writing pkg-config file...")
|
||||
configure_file(${CMAKE_SOURCE_DIR}/o2.pc.cmake ${CMAKE_BINARY_DIR}/o2.pc @ONLY)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/o2.pc DESTINATION "${CMAKE_INSTALL_PREFIX}/lib${o2_LIB_SUFFIX}/pkgconfig/")
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/../o2.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/o2.pc @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/o2.pc DESTINATION "${CMAKE_INSTALL_PREFIX}/lib${o2_LIB_SUFFIX}/pkgconfig/")
|
||||
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/../o2-config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/o2-config.h @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/o2-config.h DESTINATION "${CMAKE_INSTALL_PREFIX}/include/o2")
|
||||
|
||||
|
52
external/o2/src/o0baseauth.cpp
vendored
52
external/o2/src/o0baseauth.cpp
vendored
@ -1,16 +1,19 @@
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
#include <QIODevice>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include "o0baseauth.h"
|
||||
#include "o0globals.h"
|
||||
#include "o0settingsstore.h"
|
||||
#include "o2replyserver.h"
|
||||
#include "o2pollserver.h"
|
||||
|
||||
static const quint16 DefaultLocalPort = 1965;
|
||||
|
||||
O0BaseAuth::O0BaseAuth(QObject *parent): QObject(parent) {
|
||||
O0BaseAuth::O0BaseAuth(QObject *parent, O0AbstractStore *store): QObject(parent), store_(0), useExternalWebInterceptor_(false), replyServer_(NULL), pollServer_(NULL) {
|
||||
localPort_ = DefaultLocalPort;
|
||||
store_ = new O0SettingsStore(O2_ENCRYPTION_KEY, this);
|
||||
setStore(store);
|
||||
}
|
||||
|
||||
void O0BaseAuth::setStore(O0AbstractStore *store) {
|
||||
@ -83,6 +86,25 @@ void O0BaseAuth::setClientSecret(const QString &value) {
|
||||
Q_EMIT clientSecretChanged();
|
||||
}
|
||||
|
||||
bool O0BaseAuth::useExternalWebInterceptor() {
|
||||
return useExternalWebInterceptor_;
|
||||
}
|
||||
|
||||
void O0BaseAuth::setUseExternalWebInterceptor(bool useExternalWebInterceptor) {
|
||||
useExternalWebInterceptor_ = useExternalWebInterceptor;
|
||||
}
|
||||
|
||||
QByteArray O0BaseAuth::replyContent() const {
|
||||
return replyContent_;
|
||||
}
|
||||
|
||||
void O0BaseAuth::setReplyContent(const QByteArray &value) {
|
||||
replyContent_ = value;
|
||||
if (replyServer_) {
|
||||
replyServer_->setReplyContent(replyContent_);
|
||||
}
|
||||
}
|
||||
|
||||
int O0BaseAuth::localPort() {
|
||||
return localPort_;
|
||||
}
|
||||
@ -112,6 +134,32 @@ void O0BaseAuth::setExtraTokens(QVariantMap extraTokens) {
|
||||
Q_EMIT extraTokensChanged();
|
||||
}
|
||||
|
||||
void O0BaseAuth::setReplyServer(O2ReplyServer * server)
|
||||
{
|
||||
delete replyServer_;
|
||||
|
||||
replyServer_ = server;
|
||||
replyServer_->setReplyContent(replyContent_);
|
||||
}
|
||||
|
||||
O2ReplyServer * O0BaseAuth::replyServer() const
|
||||
{
|
||||
return replyServer_;
|
||||
}
|
||||
|
||||
void O0BaseAuth::setPollServer(O2PollServer *server)
|
||||
{
|
||||
if (pollServer_)
|
||||
pollServer_->deleteLater();
|
||||
|
||||
pollServer_ = server;
|
||||
}
|
||||
|
||||
O2PollServer *O0BaseAuth::pollServer() const
|
||||
{
|
||||
return pollServer_;
|
||||
}
|
||||
|
||||
QByteArray O0BaseAuth::createQueryParameters(const QList<O0RequestParameter> ¶meters) {
|
||||
QByteArray ret;
|
||||
bool first = true;
|
||||
|
41
external/o2/src/o0baseauth.h
vendored
41
external/o2/src/o0baseauth.h
vendored
@ -12,12 +12,15 @@
|
||||
#include "o0abstractstore.h"
|
||||
#include "o0requestparameter.h"
|
||||
|
||||
/// Base class of OAuth authenticators
|
||||
class O0_EXPORT O0BaseAuth : public QObject {
|
||||
Q_OBJECT
|
||||
class O2ReplyServer;
|
||||
class O2PollServer;
|
||||
|
||||
/// Base class of OAuth authenticators
|
||||
class O0_EXPORT O0BaseAuth : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit O0BaseAuth(QObject *parent = 0);
|
||||
explicit O0BaseAuth(QObject *parent = 0, O0AbstractStore *store = 0);
|
||||
|
||||
public:
|
||||
/// Are we authenticated?
|
||||
@ -48,6 +51,17 @@ public:
|
||||
QString clientSecret();
|
||||
void setClientSecret(const QString &value);
|
||||
|
||||
/// Should we use a reply server (default) or an external web interceptor?
|
||||
Q_PROPERTY(bool useExternalWebInterceptor READ useExternalWebInterceptor WRITE setUseExternalWebInterceptor)
|
||||
bool useExternalWebInterceptor();
|
||||
void setUseExternalWebInterceptor(bool inUseExternalWebInterceptor);
|
||||
|
||||
/// Page content on local host after successful oauth.
|
||||
/// Provide it in case you do not want to close the browser, but display something
|
||||
Q_PROPERTY(QByteArray replyContent READ replyContent WRITE setReplyContent)
|
||||
QByteArray replyContent() const;
|
||||
void setReplyContent(const QByteArray &value);
|
||||
|
||||
/// TCP port number to use in local redirections.
|
||||
/// The OAuth "redirect_uri" will be set to "http://localhost:<localPort>/".
|
||||
/// If localPort is set to 0 (default), O2 will replace it with a free one.
|
||||
@ -75,6 +89,9 @@ Q_SIGNALS:
|
||||
/// 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();
|
||||
|
||||
@ -104,6 +121,16 @@ protected:
|
||||
/// Set extra tokens found in OAuth response
|
||||
void setExtraTokens(QVariantMap extraTokens);
|
||||
|
||||
/// Set local reply server
|
||||
void setReplyServer(O2ReplyServer *server);
|
||||
|
||||
O2ReplyServer * replyServer() const;
|
||||
|
||||
/// Set local poll server
|
||||
void setPollServer(O2PollServer *server);
|
||||
|
||||
O2PollServer * pollServer() const;
|
||||
|
||||
protected:
|
||||
QString clientId_;
|
||||
QString clientSecret_;
|
||||
@ -118,6 +145,12 @@ protected:
|
||||
QVariantMap extraTokens_;
|
||||
QByteArray pkceCodeVerifier_;
|
||||
QString pkceCodeChallenge_;
|
||||
bool useExternalWebInterceptor_;
|
||||
QByteArray replyContent_;
|
||||
|
||||
private:
|
||||
O2ReplyServer *replyServer_;
|
||||
O2PollServer *pollServer_;
|
||||
};
|
||||
|
||||
#endif // O0BASEAUTH
|
||||
|
12
external/o2/src/o0globals.h
vendored
12
external/o2/src/o0globals.h
vendored
@ -24,6 +24,7 @@ const char O2_OAUTH_SIGNATURE[] = "oauth_signature";
|
||||
const char O2_OAUTH_SIGNATURE_METHOD[] = "oauth_signature_method";
|
||||
const char O2_OAUTH_TIMESTAMP[] = "oauth_timestamp";
|
||||
const char O2_OAUTH_VERSION[] = "oauth_version";
|
||||
|
||||
// OAuth 1/1.1 Response Parameters
|
||||
const char O2_OAUTH_TOKEN[] = "oauth_token";
|
||||
const char O2_OAUTH_TOKEN_SECRET[] = "oauth_token_secret";
|
||||
@ -41,22 +42,33 @@ const char O2_OAUTH2_SCOPE[] = "scope";
|
||||
const char O2_OAUTH2_GRANT_TYPE_CODE[] = "code";
|
||||
const char O2_OAUTH2_GRANT_TYPE_TOKEN[] = "token";
|
||||
const char O2_OAUTH2_GRANT_TYPE_PASSWORD[] = "password";
|
||||
const char O2_OAUTH2_GRANT_TYPE_DEVICE[] = "urn:ietf:params:oauth:grant-type:device_code";
|
||||
const char O2_OAUTH2_GRANT_TYPE[] = "grant_type";
|
||||
const char O2_OAUTH2_API_KEY[] = "api_key";
|
||||
const char O2_OAUTH2_STATE[] = "state";
|
||||
const char O2_OAUTH2_CODE[] = "code";
|
||||
|
||||
// OAuth 2 Response Parameters
|
||||
const char O2_OAUTH2_ACCESS_TOKEN[] = "access_token";
|
||||
const char O2_OAUTH2_REFRESH_TOKEN[] = "refresh_token";
|
||||
const char O2_OAUTH2_EXPIRES_IN[] = "expires_in";
|
||||
const char O2_OAUTH2_DEVICE_CODE[] = "device_code";
|
||||
const char O2_OAUTH2_USER_CODE[] = "user_code";
|
||||
const char O2_OAUTH2_VERIFICATION_URI[] = "verification_uri";
|
||||
const char O2_OAUTH2_VERIFICATION_URL[] = "verification_url"; // Google sign-in
|
||||
const char O2_OAUTH2_VERIFICATION_URI_COMPLETE[] = "verification_uri_complete";
|
||||
const char O2_OAUTH2_INTERVAL[] = "interval";
|
||||
|
||||
// OAuth signature types
|
||||
const char O2_SIGNATURE_TYPE_HMAC_SHA1[] = "HMAC-SHA1";
|
||||
const char O2_SIGNATURE_TYPE_HMAC_SHA256[] = "HMAC-SHA256";
|
||||
const char O2_SIGNATURE_TYPE_PLAINTEXT[] = "PLAINTEXT";
|
||||
|
||||
// Parameter values
|
||||
const char O2_AUTHORIZATION_CODE[] = "authorization_code";
|
||||
|
||||
// Standard HTTP headers
|
||||
const char O2_HTTP_HTTP_HEADER[] = "HTTP";
|
||||
const char O2_HTTP_AUTHORIZATION_HEADER[] = "Authorization";
|
||||
|
||||
// PKCE parameters
|
||||
|
41
external/o2/src/o0jsonresponse.cpp
vendored
Normal file
41
external/o2/src/o0jsonresponse.cpp
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
#include "o0jsonresponse.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#else
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptValueIterator>
|
||||
#endif
|
||||
|
||||
QVariantMap parseJsonResponse(const QByteArray &data) {
|
||||
#if QT_VERSION >= 0x050000
|
||||
QJsonParseError err;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data, &err);
|
||||
if (err.error != QJsonParseError::NoError) {
|
||||
qWarning() << "parseTokenResponse: Failed to parse token response due to err:" << err.errorString();
|
||||
return QVariantMap();
|
||||
}
|
||||
|
||||
if (!doc.isObject()) {
|
||||
qWarning() << "parseTokenResponse: Token response is not an object";
|
||||
return QVariantMap();
|
||||
}
|
||||
|
||||
return doc.object().toVariantMap();
|
||||
#else
|
||||
QScriptEngine engine;
|
||||
QScriptValue value = engine.evaluate("(" + QString(data) + ")");
|
||||
QScriptValueIterator it(value);
|
||||
QVariantMap map;
|
||||
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
map.insert(it.name(), it.value().toVariant());
|
||||
}
|
||||
|
||||
return map;
|
||||
#endif
|
||||
}
|
11
external/o2/src/o0jsonresponse.h
vendored
Normal file
11
external/o2/src/o0jsonresponse.h
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef O0JSONRESPONSE_H
|
||||
#define O0JSONRESPONSE_H
|
||||
|
||||
#include <QVariantMap>
|
||||
|
||||
class QByteArray;
|
||||
|
||||
/// Parse JSON data into a QVariantMap
|
||||
QVariantMap parseJsonResponse(const QByteArray &data);
|
||||
|
||||
#endif // O0JSONRESPONSE_H
|
69
external/o2/src/o0keychainstore.cpp
vendored
69
external/o2/src/o0keychainstore.cpp
vendored
@ -21,62 +21,63 @@ o0keyChainStore::o0keyChainStore(const QString& app,const QString& name,QObject
|
||||
}
|
||||
|
||||
QString o0keyChainStore::value(const QString &key, const QString &defaultValue) {
|
||||
Q_UNUSED(defaultValue)
|
||||
return pairs_.value(key);
|
||||
return pairs_.value(key, defaultValue);
|
||||
}
|
||||
|
||||
void o0keyChainStore::setValue(const QString &key, const QString &value) {
|
||||
pairs_.insert(key,value);
|
||||
}
|
||||
|
||||
void o0keyChainStore::persist() {
|
||||
int o0keyChainStore::persist() {
|
||||
WritePasswordJob job(app_);
|
||||
job.setAutoDelete(false);
|
||||
job.setKey(name_);
|
||||
initJob(job);
|
||||
|
||||
QByteArray data;
|
||||
QDataStream ds(&data,QIODevice::ReadWrite);
|
||||
ds << pairs_;
|
||||
job.setBinaryData(data);
|
||||
|
||||
job.setTextData(data);
|
||||
QEventLoop loop;
|
||||
job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) );
|
||||
job.start();
|
||||
loop.exec();
|
||||
if(job.error())
|
||||
{
|
||||
qWarning() << "keychain could not be persisted "<< name_ << ":" << qPrintable(job.errorString());
|
||||
}
|
||||
return executeJob(job, "persist");
|
||||
}
|
||||
|
||||
void o0keyChainStore::fetchFromKeychain() {
|
||||
int o0keyChainStore::fetchFromKeychain() {
|
||||
ReadPasswordJob job(app_);
|
||||
job.setKey(name_);
|
||||
QEventLoop loop;
|
||||
job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) );
|
||||
job.start();
|
||||
loop.exec();
|
||||
|
||||
QByteArray data;
|
||||
// QKeychain::ReadPasswordJob::textData() returns QString::fromUtf8( <password data> )
|
||||
// switch back to UTF-8 to avoid issues when QT_NO_CAST_TO_ASCII is defined
|
||||
data.append(job.textData().toUtf8());
|
||||
QDataStream ds(&data,QIODevice::ReadOnly);
|
||||
ds >> pairs_;
|
||||
|
||||
if(job.error())
|
||||
{
|
||||
qWarning() << "keychain could not be fetched"<< name_ << ":" << qPrintable(job.errorString());
|
||||
initJob(job);
|
||||
const int result = executeJob(job, "fetch");
|
||||
if (result == 0) { // success
|
||||
QByteArray data;
|
||||
data.append(job.binaryData());
|
||||
QDataStream ds(&data, QIODevice::ReadOnly);
|
||||
ds >> pairs_;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void o0keyChainStore::clearFromKeychain() {
|
||||
int o0keyChainStore::clearFromKeychain() {
|
||||
DeletePasswordJob job(app_);
|
||||
initJob(job);
|
||||
return executeJob(job, "clear");
|
||||
}
|
||||
|
||||
bool o0keyChainStore::isEntryNotFoundError(int errorCode) {
|
||||
return errorCode == QKeychain::EntryNotFound;
|
||||
}
|
||||
|
||||
void o0keyChainStore::initJob(QKeychain::Job &job) const {
|
||||
job.setAutoDelete(false);
|
||||
job.setKey(name_);
|
||||
}
|
||||
|
||||
int o0keyChainStore::executeJob(QKeychain::Job &job, const char *actionName) const {
|
||||
QEventLoop loop;
|
||||
job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) );
|
||||
job.start();
|
||||
loop.exec();
|
||||
if ( job.error() ) {
|
||||
qWarning() << "Deleting keychain failed: " << qPrintable(job.errorString());
|
||||
|
||||
const QKeychain::Error errorCode = job.error();
|
||||
if (errorCode != QKeychain::NoError) {
|
||||
qWarning() << "keychain store could not" << actionName << name_ << ":"
|
||||
<< job.errorString() << "(" << errorCode << ").";
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
|
37
external/o2/src/o0keychainstore.h
vendored
37
external/o2/src/o0keychainstore.h
vendored
@ -8,21 +8,48 @@
|
||||
#include "o0abstractstore.h"
|
||||
#include <QString>
|
||||
|
||||
namespace QKeychain {
|
||||
class Job;
|
||||
}
|
||||
|
||||
/// Calling persist(), fetchFromKeychain() and clearFromKeychain() member
|
||||
/// functions is the responsibility of the user of this class.
|
||||
/// This is important to minimize the number of keychain accesses (and
|
||||
/// potentially the number of user password prompts).
|
||||
/// For example: fetchFromKeychain() can be called immediately after
|
||||
/// creating a keychain store; persist() - after a successful authorization;
|
||||
/// clearFromKeychain() - when the user logs out from the service.
|
||||
class O0_EXPORT o0keyChainStore : public O0AbstractStore{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit o0keyChainStore(const QString& app,const QString& name,QObject *parent = 0);
|
||||
|
||||
/// Retrieve a string value by key.
|
||||
virtual QString value(const QString &key, const QString &defaultValue = QString()) = 0;
|
||||
QString value(const QString &key, const QString &defaultValue = QString());
|
||||
|
||||
/// Set a string value for a key.
|
||||
virtual void setValue(const QString &key, const QString &value) = 0;
|
||||
void setValue(const QString &key, const QString &value);
|
||||
|
||||
// The functions below return QKeychain::Error casted to int. They don't
|
||||
// return the enumerator directly because it can not be forward-declared reliably,
|
||||
// and including <keychain.h> into this header may be undesirable.
|
||||
// Note that if 0 is returned, then there was no error.
|
||||
|
||||
int persist();
|
||||
int fetchFromKeychain();
|
||||
int clearFromKeychain();
|
||||
|
||||
/// @return true if @p errorCode is equal to QKeychain::EntryNotFound.
|
||||
/// @note This function can be used to single out one type of an error
|
||||
/// returned from the functions above without including <keychain.h>.
|
||||
/// The EntryNotFound error type is special because it can be considered
|
||||
/// not an error if returned from clearFromKeychain().
|
||||
static bool isEntryNotFoundError(int errorCode);
|
||||
|
||||
void persist();
|
||||
void fetchFromKeychain();
|
||||
void clearFromKeychain();
|
||||
private:
|
||||
void initJob(QKeychain::Job &job) const;
|
||||
int executeJob(QKeychain::Job &job, const char *actionName) const;
|
||||
|
||||
QString app_;
|
||||
QString name_;
|
||||
QMap<QString,QString> pairs_;
|
||||
|
2
external/o2/src/o0requestparameter.h
vendored
2
external/o2/src/o0requestparameter.h
vendored
@ -3,6 +3,8 @@
|
||||
|
||||
#include "o0export.h"
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
/// Request parameter (name-value pair) participating in authentication.
|
||||
struct O0_EXPORT O0RequestParameter {
|
||||
O0RequestParameter(const QByteArray &n, const QByteArray &v): name(n), value(v) {}
|
||||
|
10
external/o2/src/o0settingsstore.cpp
vendored
10
external/o2/src/o0settingsstore.cpp
vendored
@ -1,5 +1,6 @@
|
||||
#include <QCryptographicHash>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
|
||||
#include "o0settingsstore.h"
|
||||
|
||||
@ -41,4 +42,13 @@ QString O0SettingsStore::value(const QString &key, const QString &defaultValue)
|
||||
void O0SettingsStore::setValue(const QString &key, const QString &value) {
|
||||
QString fullKey = groupKey_.isEmpty() ? key : (groupKey_ + '/' + key);
|
||||
settings_->setValue(fullKey, crypt_.encryptToString(value));
|
||||
|
||||
const QSettings::Status status = settings_->status();
|
||||
if (status != QSettings::NoError) {
|
||||
qCritical() << "O0SettingsStore QSettings error:" << status;
|
||||
if (status == QSettings::AccessError) {
|
||||
qCritical() << "Did you forget to set organization name and application name "
|
||||
"in QSettings or QCoreApplication?";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
external/o2/src/o0simplecrypt.h
vendored
17
external/o2/src/o0simplecrypt.h
vendored
@ -30,7 +30,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QFlags>
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
#include <QRandomGenerator>
|
||||
#endif
|
||||
#include "o0baseauth.h"
|
||||
|
||||
/**
|
||||
@ -82,7 +84,7 @@ public:
|
||||
ProtectionHash /*!< A cryptographic hash is used to verify the integrity of the data. This method produces a much stronger, but longer check */
|
||||
};
|
||||
/**
|
||||
Error describes the type of error that occurred.
|
||||
Error describes the type of error that occured.
|
||||
*/
|
||||
enum Error {
|
||||
ErrorNoError, /*!< No error occurred. */
|
||||
@ -175,7 +177,7 @@ public:
|
||||
Decrypts a cyphertext string encrypted with this class with the set key back to the
|
||||
plain text version.
|
||||
|
||||
If an error occurred, such as non-matching keys between encryption and decryption,
|
||||
If an error occured, such as non-matching keys between encryption and decryption,
|
||||
an empty string or a string containing nonsense may be returned.
|
||||
*/
|
||||
QString decryptToString(const QString& cyphertext) ;
|
||||
@ -183,7 +185,7 @@ public:
|
||||
Decrypts a cyphertext string encrypted with this class with the set key back to the
|
||||
plain text version.
|
||||
|
||||
If an error occurred, such as non-matching keys between encryption and decryption,
|
||||
If an error occured, such as non-matching keys between encryption and decryption,
|
||||
an empty string or a string containing nonsense may be returned.
|
||||
*/
|
||||
QByteArray decryptToByteArray(const QString& cyphertext) ;
|
||||
@ -191,7 +193,7 @@ public:
|
||||
Decrypts a cyphertext binary encrypted with this class with the set key back to the
|
||||
plain text version.
|
||||
|
||||
If an error occurred, such as non-matching keys between encryption and decryption,
|
||||
If an error occured, such as non-matching keys between encryption and decryption,
|
||||
an empty string or a string containing nonsense may be returned.
|
||||
*/
|
||||
QString decryptToString(QByteArray cypher) ;
|
||||
@ -199,7 +201,7 @@ public:
|
||||
Decrypts a cyphertext binary encrypted with this class with the set key back to the
|
||||
plain text version.
|
||||
|
||||
If an error occurred, such as non-matching keys between encryption and decryption,
|
||||
If an error occured, such as non-matching keys between encryption and decryption,
|
||||
an empty string or a string containing nonsense may be returned.
|
||||
*/
|
||||
QByteArray decryptToByteArray(QByteArray cypher) ;
|
||||
@ -221,6 +223,9 @@ private:
|
||||
CompressionMode m_compressionMode;
|
||||
IntegrityProtectionMode m_protectionMode;
|
||||
Error m_lastError;
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
QRandomGenerator m_rand;
|
||||
#endif
|
||||
};
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(O0SimpleCrypt::CryptoFlags)
|
||||
|
||||
|
99
external/o2/src/o1.cpp
vendored
99
external/o2/src/o1.cpp
vendored
@ -6,6 +6,7 @@
|
||||
#include <QDebug>
|
||||
#include <QDataStream>
|
||||
#include <QStringList>
|
||||
#include <algorithm>
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QUrlQuery>
|
||||
@ -15,20 +16,32 @@
|
||||
#include <QMessageAuthenticationCode>
|
||||
#endif
|
||||
|
||||
#if QT_VERSION >= 0x051500
|
||||
#include <QRandomGenerator>
|
||||
#endif
|
||||
|
||||
|
||||
#include "o1.h"
|
||||
#include "o2replyserver.h"
|
||||
#include "o0globals.h"
|
||||
#include "o0settingsstore.h"
|
||||
|
||||
O1::O1(QObject *parent, QNetworkAccessManager *manager): O0BaseAuth(parent) {
|
||||
setSignatureMethod(O2_SIGNATURE_TYPE_HMAC_SHA1);
|
||||
O1::O1(QObject *parent, QNetworkAccessManager *manager, O0AbstractStore *store): O0BaseAuth(parent, store) {
|
||||
setSignatureMethod(O2_SIGNATURE_TYPE_HMAC_SHA256);
|
||||
manager_ = manager ? manager : new QNetworkAccessManager(this);
|
||||
replyServer_ = new O2ReplyServer(this);
|
||||
qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
|
||||
connect(replyServer_, SIGNAL(verificationReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>)));
|
||||
|
||||
setCallbackUrl(O2_CALLBACK_URL);
|
||||
}
|
||||
|
||||
QByteArray O1::userAgent() const {
|
||||
return userAgent_;
|
||||
}
|
||||
|
||||
void O1::setUserAgent(const QByteArray &v) {
|
||||
userAgent_ = v;
|
||||
}
|
||||
|
||||
QUrl O1::requestTokenUrl() {
|
||||
return requestTokenUrl_;
|
||||
}
|
||||
@ -141,7 +154,7 @@ QByteArray O1::getRequestBase(const QList<O0RequestParameter> &oauthParams, cons
|
||||
// Append a sorted+encoded list of all request parameters to the base string
|
||||
QList<O0RequestParameter> headers(oauthParams);
|
||||
headers.append(otherParams);
|
||||
qSort(headers);
|
||||
std::sort(headers.begin(), headers.end());
|
||||
base.append(encodeHeaders(headers));
|
||||
|
||||
return base;
|
||||
@ -151,7 +164,7 @@ QByteArray O1::sign(const QList<O0RequestParameter> &oauthParams, const QList<O0
|
||||
QByteArray baseString = getRequestBase(oauthParams, otherParams, url, op);
|
||||
QByteArray secret = QUrl::toPercentEncoding(consumerSecret) + "&" + QUrl::toPercentEncoding(tokenSecret);
|
||||
#if QT_VERSION >= 0x050100
|
||||
return QMessageAuthenticationCode::hash(baseString, secret, QCryptographicHash::Sha1).toBase64();
|
||||
return QMessageAuthenticationCode::hash(baseString, secret, QCryptographicHash::Sha256).toBase64();
|
||||
#else
|
||||
return hmacSha1(secret, baseString);
|
||||
#endif
|
||||
@ -161,7 +174,7 @@ QByteArray O1::buildAuthorizationHeader(const QList<O0RequestParameter> &oauthPa
|
||||
bool first = true;
|
||||
QByteArray ret("OAuth ");
|
||||
QList<O0RequestParameter> headers(oauthParams);
|
||||
qSort(headers);
|
||||
std::sort(headers.begin(), headers.end());
|
||||
foreach (O0RequestParameter h, headers) {
|
||||
if (first) {
|
||||
first = false;
|
||||
@ -176,9 +189,20 @@ QByteArray O1::buildAuthorizationHeader(const QList<O0RequestParameter> &oauthPa
|
||||
return ret;
|
||||
}
|
||||
|
||||
void O1::decorateRequest(QNetworkRequest &req, const QList<O0RequestParameter> &oauthParams) {
|
||||
req.setRawHeader(O2_HTTP_AUTHORIZATION_HEADER, buildAuthorizationHeader(oauthParams));
|
||||
if (!userAgent_.isEmpty()) {
|
||||
#if QT_VERSION >= 0x050000
|
||||
req.setHeader(QNetworkRequest::UserAgentHeader, userAgent_);
|
||||
#else
|
||||
req.setRawHeader("User-Agent", userAgent_);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray O1::generateSignature(const QList<O0RequestParameter> headers, const QNetworkRequest &req, const QList<O0RequestParameter> &signingParameters, QNetworkAccessManager::Operation operation) {
|
||||
QByteArray signature;
|
||||
if (signatureMethod() == O2_SIGNATURE_TYPE_HMAC_SHA1) {
|
||||
if (signatureMethod() == O2_SIGNATURE_TYPE_HMAC_SHA256) {
|
||||
signature = sign(headers, signingParameters, req.url(), operation, clientSecret(), tokenSecret());
|
||||
} else if (signatureMethod() == O2_SIGNATURE_TYPE_PLAINTEXT) {
|
||||
signature = clientSecret().toLatin1() + "&" + tokenSecret().toLatin1();
|
||||
@ -188,6 +212,17 @@ QByteArray O1::generateSignature(const QList<O0RequestParameter> headers, const
|
||||
|
||||
void O1::link() {
|
||||
qDebug() << "O1::link";
|
||||
|
||||
// Create the reply server if it doesn't exist
|
||||
// and we don't use an external web interceptor
|
||||
if(!useExternalWebInterceptor_) {
|
||||
if(replyServer() == NULL) {
|
||||
O2ReplyServer * replyServer = new O2ReplyServer(this);
|
||||
connect(replyServer, SIGNAL(verificationReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>)));
|
||||
setReplyServer(replyServer);
|
||||
}
|
||||
}
|
||||
|
||||
if (linked()) {
|
||||
qDebug() << "O1::link: Linked already";
|
||||
Q_EMIT linkingSucceeded();
|
||||
@ -199,9 +234,11 @@ void O1::link() {
|
||||
setTokenSecret("");
|
||||
setExtraTokens(QVariantMap());
|
||||
|
||||
// Start reply server
|
||||
if (!replyServer_->isListening())
|
||||
replyServer_->listen(QHostAddress::Any, localPort());
|
||||
if (!useExternalWebInterceptor_) {
|
||||
// Start reply server
|
||||
if (!replyServer()->isListening())
|
||||
replyServer()->listen(QHostAddress::Any, localPort());
|
||||
}
|
||||
|
||||
// Get any query parameters for the request
|
||||
#if QT_VERSION >= 0x050000
|
||||
@ -226,23 +263,35 @@ void O1::link() {
|
||||
|
||||
// Create initial token request
|
||||
QList<O0RequestParameter> headers;
|
||||
headers.append(O0RequestParameter(O2_OAUTH_CALLBACK, callbackUrl().arg(replyServer_->serverPort()).toLatin1()));
|
||||
headers.append(O0RequestParameter(O2_OAUTH_CALLBACK, callbackUrl().arg(localPort()).toLatin1()));
|
||||
headers.append(O0RequestParameter(O2_OAUTH_CONSUMER_KEY, clientId().toLatin1()));
|
||||
headers.append(O0RequestParameter(O2_OAUTH_NONCE, nonce()));
|
||||
#if QT_VERSION >= 0x050800
|
||||
headers.append(O0RequestParameter(O2_OAUTH_TIMESTAMP, QString::number(QDateTime::currentSecsSinceEpoch()).toLatin1()));
|
||||
#else
|
||||
headers.append(O0RequestParameter(O2_OAUTH_TIMESTAMP, QString::number(QDateTime::currentDateTimeUtc().toTime_t()).toLatin1()));
|
||||
#endif
|
||||
headers.append(O0RequestParameter(O2_OAUTH_VERSION, "1.0"));
|
||||
headers.append(O0RequestParameter(O2_OAUTH_SIGNATURE_METHOD, signatureMethod().toLatin1()));
|
||||
headers.append(O0RequestParameter(O2_OAUTH_SIGNATURE, generateSignature(headers, request, requestParameters(), QNetworkAccessManager::PostOperation)));
|
||||
// qDebug() << "O1:link: Token request headers:";
|
||||
// foreach(param, headers) {
|
||||
// qDebug() << " " << param.name << "=" << param.value;
|
||||
// }
|
||||
|
||||
// Clear request token
|
||||
requestToken_.clear();
|
||||
requestTokenSecret_.clear();
|
||||
|
||||
// Post request
|
||||
request.setRawHeader(O2_HTTP_AUTHORIZATION_HEADER, buildAuthorizationHeader(headers));
|
||||
decorateRequest(request, headers);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, O2_MIME_TYPE_XFORM);
|
||||
QNetworkReply *reply = manager_->post(request, QByteArray());
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenRequestError(QNetworkReply::NetworkError)));
|
||||
#else
|
||||
connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onTokenRequestError(QNetworkReply::NetworkError)));
|
||||
#endif
|
||||
connect(reply, SIGNAL(finished()), this, SLOT(onTokenRequestFinished()));
|
||||
}
|
||||
|
||||
@ -282,11 +331,11 @@ void O1::onTokenRequestFinished() {
|
||||
QUrl url(authorizeUrl());
|
||||
#if QT_VERSION < 0x050000
|
||||
url.addQueryItem(O2_OAUTH_TOKEN, requestToken_);
|
||||
url.addQueryItem(O2_OAUTH_CALLBACK, callbackUrl().arg(replyServer_->serverPort()).toLatin1());
|
||||
url.addQueryItem(O2_OAUTH_CALLBACK, callbackUrl().arg(localPort()).toLatin1());
|
||||
#else
|
||||
QUrlQuery query(url);
|
||||
query.addQueryItem(O2_OAUTH_TOKEN, requestToken_);
|
||||
query.addQueryItem(O2_OAUTH_CALLBACK, callbackUrl().arg(replyServer_->serverPort()).toLatin1());
|
||||
query.addQueryItem(O2_OAUTH_CALLBACK, callbackUrl().arg(localPort()).toLatin1());
|
||||
url.setQuery(query);
|
||||
#endif
|
||||
Q_EMIT openBrowser(url);
|
||||
@ -313,7 +362,11 @@ void O1::exchangeToken() {
|
||||
QList<O0RequestParameter> oauthParams;
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_CONSUMER_KEY, clientId().toLatin1()));
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_VERSION, "1.0"));
|
||||
#if QT_VERSION >= 0x050800
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_TIMESTAMP, QString::number(QDateTime::currentSecsSinceEpoch()).toLatin1()));
|
||||
#else
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_TIMESTAMP, QString::number(QDateTime::currentDateTimeUtc().toTime_t()).toLatin1()));
|
||||
#endif
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_NONCE, nonce()));
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_TOKEN, requestToken_.toLatin1()));
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_VERFIER, verifier_.toLatin1()));
|
||||
@ -321,10 +374,14 @@ void O1::exchangeToken() {
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_SIGNATURE, generateSignature(oauthParams, request, QList<O0RequestParameter>(), QNetworkAccessManager::PostOperation)));
|
||||
|
||||
// Post request
|
||||
request.setRawHeader(O2_HTTP_AUTHORIZATION_HEADER, buildAuthorizationHeader(oauthParams));
|
||||
decorateRequest(request, oauthParams);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, O2_MIME_TYPE_XFORM);
|
||||
QNetworkReply *reply = manager_->post(request, QByteArray());
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenExchangeError(QNetworkReply::NetworkError)));
|
||||
#else
|
||||
connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onTokenExchangeError(QNetworkReply::NetworkError)));
|
||||
#endif
|
||||
connect(reply, SIGNAL(finished()), this, SLOT(onTokenExchangeFinished()));
|
||||
}
|
||||
|
||||
@ -378,12 +435,20 @@ QMap<QString, QString> O1::parseResponse(const QByteArray &response) {
|
||||
}
|
||||
|
||||
QByteArray O1::nonce() {
|
||||
#if QT_VERSION >= 0x050800
|
||||
QString u = QString::number(QDateTime::currentSecsSinceEpoch()).toLatin1();
|
||||
#else
|
||||
QString u = QString::number(QDateTime::currentDateTimeUtc().toTime_t()).toLatin1();
|
||||
#endif
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
u.append(QString::number(QRandomGenerator::global()->generate()));
|
||||
#else
|
||||
static bool firstTime = true;
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
qsrand(QTime::currentTime().msec());
|
||||
}
|
||||
QString u = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
|
||||
u.append(QString::number(qrand()));
|
||||
#endif
|
||||
return u.toLatin1();
|
||||
}
|
||||
|
22
external/o2/src/o1.h
vendored
22
external/o2/src/o1.h
vendored
@ -8,13 +8,19 @@
|
||||
#include "o0export.h"
|
||||
#include "o0baseauth.h"
|
||||
|
||||
class O2ReplyServer;
|
||||
|
||||
/// Simple OAuth 1.0 authenticator.
|
||||
class O0_EXPORT O1: public O0BaseAuth {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/// HTTP User-Agent header
|
||||
/// Set user agent to a value unique for your application (https://tools.ietf.org/html/rfc7231#section-5.5.3)
|
||||
/// if you see the following error in the application log:
|
||||
/// O1::onTokenRequestError: 201 "Error transferring requestTokenUrl() - server replied: Forbidden" "Bad bot"
|
||||
Q_PROPERTY(QByteArray userAgent READ userAgent WRITE setUserAgent)
|
||||
QByteArray userAgent() const;
|
||||
void setUserAgent(const QByteArray &value);
|
||||
|
||||
/// Signature method
|
||||
Q_PROPERTY(QString signatureMethod READ signatureMethod WRITE setSignatureMethod NOTIFY signatureMethodChanged)
|
||||
QString signatureMethod();
|
||||
@ -26,7 +32,7 @@ public:
|
||||
void setRequestTokenUrl(const QUrl &value);
|
||||
|
||||
/// Parameters to pass with request URL.
|
||||
Q_PROPERTY(QList<O0RequestParameter> requestParameters READ requestParameters WRITE setRequestParameters);
|
||||
Q_PROPERTY(QList<O0RequestParameter> requestParameters READ requestParameters WRITE setRequestParameters)
|
||||
QList<O0RequestParameter> requestParameters();
|
||||
void setRequestParameters(const QList<O0RequestParameter> &value);
|
||||
|
||||
@ -48,7 +54,7 @@ public:
|
||||
void setAccessTokenUrl(const QUrl &value);
|
||||
|
||||
/// Constructor.
|
||||
explicit O1(QObject *parent = 0, QNetworkAccessManager *manager = 0);
|
||||
explicit O1(QObject *parent = 0, QNetworkAccessManager *manager = 0, O0AbstractStore *store = 0);
|
||||
|
||||
/// Parse a URL-encoded response string.
|
||||
static QMap<QString, QString> parseResponse(const QByteArray &response);
|
||||
@ -56,6 +62,9 @@ public:
|
||||
/// Build the value of the "Authorization:" header.
|
||||
static QByteArray buildAuthorizationHeader(const QList<O0RequestParameter> &oauthParams);
|
||||
|
||||
/// Add common configuration (headers) to @p req.
|
||||
void decorateRequest(QNetworkRequest &req, const QList<O0RequestParameter> &oauthParams);
|
||||
|
||||
/// Create unique bytes to prevent replay attacks.
|
||||
static QByteArray nonce();
|
||||
|
||||
@ -91,10 +100,11 @@ Q_SIGNALS:
|
||||
void accessTokenUrlChanged();
|
||||
void signatureMethodChanged();
|
||||
|
||||
protected Q_SLOTS:
|
||||
public Q_SLOTS:
|
||||
/// Handle verification received from the reply server.
|
||||
virtual void onVerificationReceived(QMap<QString,QString> params);
|
||||
|
||||
protected Q_SLOTS:
|
||||
/// Handle token request error.
|
||||
virtual void onTokenRequestError(QNetworkReply::NetworkError error);
|
||||
|
||||
@ -111,6 +121,7 @@ protected:
|
||||
/// Exchange temporary token to authentication token
|
||||
void exchangeToken();
|
||||
|
||||
QByteArray userAgent_;
|
||||
QUrl requestUrl_;
|
||||
QList<O0RequestParameter> requestParameters_;
|
||||
QString callbackUrl_;
|
||||
@ -119,7 +130,6 @@ protected:
|
||||
QString verifier_;
|
||||
QString signatureMethod_;
|
||||
QNetworkAccessManager *manager_;
|
||||
O2ReplyServer *replyServer_;
|
||||
};
|
||||
|
||||
#endif // O1_H
|
||||
|
6
external/o2/src/o1requestor.cpp
vendored
6
external/o2/src/o1requestor.cpp
vendored
@ -45,13 +45,17 @@ QNetworkRequest O1Requestor::setup(const QNetworkRequest &req, const QList<O0Req
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_TOKEN, authenticator_->token().toLatin1()));
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_SIGNATURE_METHOD, authenticator_->signatureMethod().toLatin1()));
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_NONCE, O1::nonce()));
|
||||
#if QT_VERSION >= 0x050800
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_TIMESTAMP, QString::number(QDateTime::currentSecsSinceEpoch()).toLatin1()));
|
||||
#else
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_TIMESTAMP, QString::number(QDateTime::currentDateTimeUtc().toTime_t()).toLatin1()));
|
||||
#endif
|
||||
|
||||
// Add signature parameter
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_SIGNATURE, authenticator_->generateSignature(oauthParams, req, signingParameters, operation)));
|
||||
|
||||
// Return a copy of the original request with authorization header set
|
||||
QNetworkRequest request(req);
|
||||
request.setRawHeader(O2_HTTP_AUTHORIZATION_HEADER, O1::buildAuthorizationHeader(oauthParams));
|
||||
authenticator_->decorateRequest(request, oauthParams);
|
||||
return request;
|
||||
}
|
||||
|
86
external/o2/src/o1smugmug.cpp
vendored
Normal file
86
external/o2/src/o1smugmug.cpp
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
#include <cstddef>
|
||||
|
||||
#include "o1smugmug.h"
|
||||
|
||||
static QString basicAuthorizationUrl() {
|
||||
return "https://secure.smugmug.com/services/oauth/1.0a/authorize";
|
||||
}
|
||||
|
||||
static const char *accessToString(O1SmugMug::Access access) {
|
||||
const char * const strings[] = {
|
||||
"Public",
|
||||
"Full"
|
||||
};
|
||||
const std::size_t stringsSize = sizeof(strings) / sizeof(strings[0]);
|
||||
Q_ASSERT(access >= 0 && static_cast<std::size_t>(access) < stringsSize
|
||||
&& "Unsupported SmugMug authorization access!");
|
||||
Q_UNUSED(stringsSize)
|
||||
|
||||
return strings[access];
|
||||
}
|
||||
|
||||
static const char *permissionsToString(O1SmugMug::Permissions permissions) {
|
||||
const char * const strings[] = {
|
||||
"Read",
|
||||
"Add",
|
||||
"Modify"
|
||||
};
|
||||
const std::size_t stringsSize = sizeof(strings) / sizeof(strings[0]);
|
||||
Q_ASSERT(permissions >= 0 && static_cast<std::size_t>(permissions) < stringsSize
|
||||
&& "Unsupported SmugMug authorization permissions!");
|
||||
Q_UNUSED(stringsSize)
|
||||
|
||||
return strings[permissions];
|
||||
}
|
||||
|
||||
|
||||
void O1SmugMug::initAuthorizationUrl(Access access, Permissions permissions) {
|
||||
setAuthorizeUrl(QUrl(::basicAuthorizationUrl()
|
||||
+ "?Access=" + ::accessToString(access)
|
||||
+ "&Permissions=" + ::permissionsToString(permissions)));
|
||||
}
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
|
||||
void O1SmugMug::AuthorizationUrlBuilder::setAccess(Access value) {
|
||||
query_.addQueryItem("Access", ::accessToString(value));
|
||||
}
|
||||
|
||||
void O1SmugMug::AuthorizationUrlBuilder::setPermissions(Permissions value) {
|
||||
query_.addQueryItem("Permissions", ::permissionsToString(value));
|
||||
}
|
||||
|
||||
void O1SmugMug::AuthorizationUrlBuilder::setAllowThirdPartyLogin(bool value) {
|
||||
query_.addQueryItem("allowThirdPartyLogin", value ? "1" : "0");
|
||||
}
|
||||
|
||||
void O1SmugMug::AuthorizationUrlBuilder::setShowSignUpButton(bool value) {
|
||||
query_.addQueryItem("showSignUpButton", value ? "true" : "false");
|
||||
}
|
||||
|
||||
void O1SmugMug::AuthorizationUrlBuilder::setPrepopulatedUsername(const QString &value) {
|
||||
query_.addQueryItem("username", value);
|
||||
}
|
||||
|
||||
void O1SmugMug::AuthorizationUrlBuilder::setViewportScale(double value) {
|
||||
Q_ASSERT(value >= 0 && value <= 1 && "Invalid SmugMug authorization viewportScale!");
|
||||
query_.addQueryItem("viewportScale", QString::number(value, 'f'));
|
||||
}
|
||||
|
||||
QUrl O1SmugMug::AuthorizationUrlBuilder::url() const {
|
||||
QUrl result(::basicAuthorizationUrl());
|
||||
result.setQuery(query_);
|
||||
return result;
|
||||
}
|
||||
|
||||
void O1SmugMug::initAuthorizationUrl(const AuthorizationUrlBuilder &builder) {
|
||||
setAuthorizeUrl(builder.url());
|
||||
}
|
||||
|
||||
#endif // QT_VERSION >= 0x050000
|
||||
|
||||
O1SmugMug::O1SmugMug(QObject *parent, QNetworkAccessManager *manager, O0AbstractStore *store)
|
||||
: O1(parent, manager, store) {
|
||||
setRequestTokenUrl(QUrl("https://secure.smugmug.com/services/oauth/1.0a/getRequestToken"));
|
||||
setAccessTokenUrl(QUrl("https://secure.smugmug.com/services/oauth/1.0a/getAccessToken"));
|
||||
}
|
69
external/o2/src/o1smugmug.h
vendored
Normal file
69
external/o2/src/o1smugmug.h
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef O1SMUGMUG_H
|
||||
#define O1SMUGMUG_H
|
||||
|
||||
#include "o0export.h"
|
||||
#include "o1.h"
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QUrlQuery>
|
||||
#endif
|
||||
|
||||
/// SmugMug OAuth 1.0 client
|
||||
///
|
||||
/// Simple usage:
|
||||
/// @code
|
||||
/// o1_ = new O1SmugMug(this);
|
||||
/// o1_->initAuthorizationUrl(O1SmugMug::AccessFull, O1SmugMug::PermissionsAdd);
|
||||
/// @endcode
|
||||
///
|
||||
/// Advanced usage (Qt 5.0 or later):
|
||||
/// @code
|
||||
/// o1_ = new O1SmugMug(this, 0, secureStore);
|
||||
/// O1SmugMug::AuthorizationUrlBuilder builder;
|
||||
/// builder.setAccess(O1SmugMug::AccessFull);
|
||||
/// builder.setShowSignUpButton(false);
|
||||
/// builder.setPrepopulatedUsername(lastUsername_);
|
||||
/// o1_->initAuthorizationUrl(builder);
|
||||
/// @endcode
|
||||
class O0_EXPORT O1SmugMug: public O1 {
|
||||
Q_OBJECT
|
||||
Q_ENUMS(Access)
|
||||
Q_ENUMS(Permissions)
|
||||
|
||||
public:
|
||||
enum Access {
|
||||
AccessPublic,
|
||||
AccessFull
|
||||
};
|
||||
|
||||
enum Permissions {
|
||||
PermissionsRead,
|
||||
PermissionsAdd,
|
||||
PermissionsModify
|
||||
};
|
||||
|
||||
Q_INVOKABLE void initAuthorizationUrl(Access access, Permissions permissions);
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
class AuthorizationUrlBuilder {
|
||||
public:
|
||||
void setAccess(Access value);
|
||||
void setPermissions(Permissions value);
|
||||
void setAllowThirdPartyLogin(bool value);
|
||||
void setShowSignUpButton(bool value);
|
||||
void setPrepopulatedUsername(const QString &value);
|
||||
void setViewportScale(double value);
|
||||
|
||||
QUrl url() const;
|
||||
|
||||
private:
|
||||
QUrlQuery query_;
|
||||
};
|
||||
|
||||
void initAuthorizationUrl(const AuthorizationUrlBuilder &builder);
|
||||
#endif // QT_VERSION >= 0x050000
|
||||
|
||||
explicit O1SmugMug(QObject *parent = 0, QNetworkAccessManager *manager = 0, O0AbstractStore *store = 0);
|
||||
};
|
||||
|
||||
#endif // O1SMUGMUG_H
|
18
external/o2/src/o1upwork.h
vendored
Normal file
18
external/o2/src/o1upwork.h
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef O1UPWORK_H
|
||||
#define O1UPWORK_H
|
||||
|
||||
#include "o1.h"
|
||||
|
||||
class O1Upwork: public O1 {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit O1Upwork(QObject *parent = 0) : O1(parent) {
|
||||
setRequestTokenUrl(QUrl("https://www.upwork.com/api/auth/v1/oauth/token/request"));
|
||||
setAuthorizeUrl(QUrl("https://www.upwork.com/services/api/auth"));
|
||||
setAccessTokenUrl(QUrl("https://www.upwork.com/api/auth/v1/oauth/token/access"));
|
||||
}
|
||||
};
|
||||
|
||||
#endif // O1UPWORK_H
|
||||
|
326
external/o2/src/o2.cpp
vendored
326
external/o2/src/o2.cpp
vendored
@ -10,52 +10,25 @@
|
||||
#include <QCryptographicHash>
|
||||
#include <QTimer>
|
||||
#include <QVariantMap>
|
||||
#include <QUuid>
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QUrlQuery>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#endif
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QRegularExpression>
|
||||
#else
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptValueIterator>
|
||||
#include <QRegExp>
|
||||
#endif
|
||||
|
||||
#include "o2.h"
|
||||
#include "o2pollserver.h"
|
||||
#include "o2replyserver.h"
|
||||
#include "o0globals.h"
|
||||
#include "o0jsonresponse.h"
|
||||
#include "o0settingsstore.h"
|
||||
|
||||
/// Parse JSON data into a QVariantMap
|
||||
static QVariantMap parseTokenResponse(const QByteArray &data) {
|
||||
#if QT_VERSION >= 0x050000
|
||||
QJsonParseError err;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data, &err);
|
||||
if (err.error != QJsonParseError::NoError) {
|
||||
qWarning() << "parseTokenResponse: Failed to parse token response due to err:" << err.errorString();
|
||||
return QVariantMap();
|
||||
}
|
||||
|
||||
if (!doc.isObject()) {
|
||||
qWarning() << "parseTokenResponse: Token response is not an object";
|
||||
return QVariantMap();
|
||||
}
|
||||
|
||||
return doc.object().toVariantMap();
|
||||
#else
|
||||
QScriptEngine engine;
|
||||
QScriptValue value = engine.evaluate("(" + QString(data) + ")");
|
||||
QScriptValueIterator it(value);
|
||||
QVariantMap map;
|
||||
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
map.insert(it.name(), it.value().toVariant());
|
||||
}
|
||||
|
||||
return map;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Add query parameters to a query
|
||||
static void addQueryParametersToUrl(QUrl &url, QList<QPair<QString, QString> > parameters) {
|
||||
#if QT_VERSION < 0x050000
|
||||
@ -67,14 +40,30 @@ static void addQueryParametersToUrl(QUrl &url, QList<QPair<QString, QString> >
|
||||
#endif
|
||||
}
|
||||
|
||||
O2::O2(QObject *parent, QNetworkAccessManager *manager): O0BaseAuth(parent) {
|
||||
// ref: https://tools.ietf.org/html/rfc8628#section-3.2
|
||||
// Exception: Google sign-in uses "verification_url" instead of "*_uri" - we'll accept both.
|
||||
static bool hasMandatoryDeviceAuthParams(const QVariantMap& params)
|
||||
{
|
||||
if (!params.contains(O2_OAUTH2_DEVICE_CODE))
|
||||
return false;
|
||||
|
||||
if (!params.contains(O2_OAUTH2_USER_CODE))
|
||||
return false;
|
||||
|
||||
if (!(params.contains(O2_OAUTH2_VERIFICATION_URI) || params.contains(O2_OAUTH2_VERIFICATION_URL)))
|
||||
return false;
|
||||
|
||||
if (!params.contains(O2_OAUTH2_EXPIRES_IN))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
O2::O2(QObject *parent, QNetworkAccessManager *manager, O0AbstractStore *store): O0BaseAuth(parent, store) {
|
||||
manager_ = manager ? manager : new QNetworkAccessManager(this);
|
||||
replyServer_ = new O2ReplyServer(this);
|
||||
grantFlow_ = GrantFlowAuthorizationCode;
|
||||
localhostPolicy_ = QString(O2_CALLBACK_URL);
|
||||
qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
|
||||
connect(replyServer_, SIGNAL(verificationReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>)));
|
||||
connect(replyServer_, SIGNAL(serverClosed(bool)), this, SLOT(serverHasClosed(bool)));
|
||||
}
|
||||
|
||||
O2::GrantFlow O2::grantFlow() {
|
||||
@ -151,9 +140,44 @@ void O2::setRefreshTokenUrl(const QString &value) {
|
||||
Q_EMIT refreshTokenUrlChanged();
|
||||
}
|
||||
|
||||
QString O2::grantType()
|
||||
{
|
||||
if (!grantType_.isEmpty())
|
||||
return grantType_;
|
||||
|
||||
switch (grantFlow_) {
|
||||
case GrantFlowAuthorizationCode:
|
||||
return O2_OAUTH2_GRANT_TYPE_CODE;
|
||||
case GrantFlowImplicit:
|
||||
return O2_OAUTH2_GRANT_TYPE_TOKEN;
|
||||
case GrantFlowResourceOwnerPasswordCredentials:
|
||||
return O2_OAUTH2_GRANT_TYPE_PASSWORD;
|
||||
case GrantFlowDevice:
|
||||
return O2_OAUTH2_GRANT_TYPE_DEVICE;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
void O2::setGrantType(const QString &value)
|
||||
{
|
||||
grantType_ = value;
|
||||
}
|
||||
|
||||
void O2::link() {
|
||||
//qDebug() << "O2::link";
|
||||
|
||||
// Create the reply server if it doesn't exist
|
||||
// and we don't use an external web interceptor
|
||||
if(!useExternalWebInterceptor_) {
|
||||
if(replyServer() == NULL) {
|
||||
O2ReplyServer * replyServer = new O2ReplyServer(this);
|
||||
connect(replyServer, SIGNAL(verificationReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>)));
|
||||
connect(replyServer, SIGNAL(serverClosed(bool)), this, SLOT(serverHasClosed(bool)));
|
||||
setReplyServer(replyServer);
|
||||
}
|
||||
}
|
||||
|
||||
if (linked()) {
|
||||
//qDebug() << "O2::link: Linked already";
|
||||
Q_EMIT linkingSucceeded();
|
||||
@ -168,19 +192,31 @@ void O2::link() {
|
||||
setExpires(0);
|
||||
|
||||
if (grantFlow_ == GrantFlowAuthorizationCode || grantFlow_ == GrantFlowImplicit) {
|
||||
// Start listening to authentication replies
|
||||
if (!replyServer_->isListening()) {
|
||||
if (replyServer_->listen(QHostAddress::Any, localPort_)) {
|
||||
//qDebug() << "O2::link: Reply server listening on port" << localPort();
|
||||
} else {
|
||||
qWarning() << "O2::link: Reply server failed to start listening on port" << localPort();
|
||||
Q_EMIT linkingFailed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Save redirect URI, as we have to reuse it when requesting the access token
|
||||
redirectUri_ = localhostPolicy_.arg(replyServer_->serverPort());
|
||||
#if QT_VERSION >= 0x050000
|
||||
QString uniqueState = QUuid::createUuid().toString().remove(QRegularExpression("([^a-zA-Z0-9]|[-])"));
|
||||
#else
|
||||
QString uniqueState = QUuid::createUuid().toString().remove(QRegExp("([^a-zA-Z0-9]|[-])"));
|
||||
#endif
|
||||
if (useExternalWebInterceptor_) {
|
||||
// Save redirect URI, as we have to reuse it when requesting the access token
|
||||
redirectUri_ = localhostPolicy_.arg(localPort());
|
||||
} else {
|
||||
// Start listening to authentication replies
|
||||
if (!replyServer()->isListening()) {
|
||||
if (replyServer()->listen(QHostAddress::Any, localPort_)) {
|
||||
//qDebug() << "O2::link: Reply server listening on port" << localPort();
|
||||
} else {
|
||||
qWarning() << "O2::link: Reply server failed to start listening on port" << localPort();
|
||||
Q_EMIT linkingFailed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Save redirect URI, as we have to reuse it when requesting the access token
|
||||
redirectUri_ = localhostPolicy_.arg(replyServer()->serverPort());
|
||||
replyServer()->setUniqueState(uniqueState);
|
||||
}
|
||||
|
||||
// Assemble intial authentication URL
|
||||
QList<QPair<QString, QString> > parameters;
|
||||
@ -189,6 +225,7 @@ void O2::link() {
|
||||
parameters.append(qMakePair(QString(O2_OAUTH2_CLIENT_ID), clientId_));
|
||||
parameters.append(qMakePair(QString(O2_OAUTH2_REDIRECT_URI), redirectUri_));
|
||||
parameters.append(qMakePair(QString(O2_OAUTH2_SCOPE), scope_.replace( " ", "+" )));
|
||||
parameters.append(qMakePair(QString(O2_OAUTH2_STATE), uniqueState));
|
||||
if ( !apiKey_.isEmpty() )
|
||||
parameters.append(qMakePair(QString(O2_OAUTH2_API_KEY), apiKey_));
|
||||
foreach (QString key, extraRequestParams().keys()) {
|
||||
@ -222,12 +259,34 @@ void O2::link() {
|
||||
QNetworkReply *tokenReply = getManager()->post(tokenRequest, payload);
|
||||
|
||||
connect(tokenReply, SIGNAL(finished()), this, SLOT(onTokenReplyFinished()), Qt::QueuedConnection);
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(tokenReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(tokenReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
}
|
||||
else if (grantFlow_ == GrantFlowDevice) {
|
||||
QList<O0RequestParameter> parameters;
|
||||
parameters.append(O0RequestParameter(O2_OAUTH2_CLIENT_ID, clientId_.toUtf8()));
|
||||
parameters.append(O0RequestParameter(O2_OAUTH2_SCOPE, scope_.toUtf8()));
|
||||
QByteArray payload = O0BaseAuth::createQueryParameters(parameters);
|
||||
|
||||
QUrl url(requestUrl_);
|
||||
QNetworkRequest deviceRequest(url);
|
||||
deviceRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
QNetworkReply *tokenReply = getManager()->post(deviceRequest, payload);
|
||||
|
||||
connect(tokenReply, SIGNAL(finished()), this, SLOT(onDeviceAuthReplyFinished()), Qt::QueuedConnection);
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(tokenReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(tokenReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void O2::unlink() {
|
||||
//() << "O2::unlink";
|
||||
//qDebug() << "O2::unlink";
|
||||
setLinked(false);
|
||||
setToken(QString());
|
||||
setRefreshToken(QString());
|
||||
@ -237,7 +296,6 @@ void O2::unlink() {
|
||||
}
|
||||
|
||||
void O2::onVerificationReceived(const QMap<QString, QString> response) {
|
||||
//qDebug() << "O2::onVerificationReceived:" << response;
|
||||
//qDebug() << "O2::onVerificationReceived: Emitting closeBrowser()";
|
||||
Q_EMIT closeBrowser();
|
||||
|
||||
@ -271,24 +329,31 @@ void O2::onVerificationReceived(const QMap<QString, QString> response) {
|
||||
QNetworkReply *tokenReply = getManager()->post(tokenRequest, data);
|
||||
timedReplies_.add(tokenReply);
|
||||
connect(tokenReply, SIGNAL(finished()), this, SLOT(onTokenReplyFinished()), Qt::QueuedConnection);
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(tokenReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
} else if (grantFlow_ == GrantFlowImplicit) {
|
||||
#else
|
||||
connect(tokenReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
} else if (grantFlow_ == GrantFlowImplicit || grantFlow_ == GrantFlowDevice) {
|
||||
// Check for mandatory tokens
|
||||
if (response.contains(O2_OAUTH2_ACCESS_TOKEN)) {
|
||||
//qDebug() << "O2::onVerificationReceived: Access token returned for implicit flow";
|
||||
//qDebug() << "O2::onVerificationReceived: Access token returned for implicit or device flow";
|
||||
setToken(response.value(O2_OAUTH2_ACCESS_TOKEN));
|
||||
if (response.contains(O2_OAUTH2_EXPIRES_IN)) {
|
||||
bool ok = false;
|
||||
int expiresIn = response.value(O2_OAUTH2_EXPIRES_IN).toInt(&ok);
|
||||
if (ok) {
|
||||
//qDebug() << "O2::onVerificationReceived: Token expires in" << expiresIn << "seconds";
|
||||
setExpires(QDateTime::currentMSecsSinceEpoch() / 1000 + expiresIn);
|
||||
setExpires((int)(QDateTime::currentMSecsSinceEpoch() / 1000 + expiresIn));
|
||||
}
|
||||
}
|
||||
if (response.contains(O2_OAUTH2_REFRESH_TOKEN)) {
|
||||
setRefreshToken(response.value(O2_OAUTH2_REFRESH_TOKEN));
|
||||
}
|
||||
setLinked(true);
|
||||
Q_EMIT linkingSucceeded();
|
||||
} else {
|
||||
qWarning() << "O2::onVerificationReceived: Access token missing from response for implicit flow";
|
||||
qWarning() << "O2::onVerificationReceived: Access token missing from response for implicit or device flow";
|
||||
Q_EMIT linkingFailed();
|
||||
}
|
||||
} else {
|
||||
@ -323,7 +388,7 @@ void O2::onTokenReplyFinished() {
|
||||
//qDebug() << "O2::onTokenReplyFinished: replyData\n";
|
||||
//qDebug() << QString( replyData );
|
||||
|
||||
QVariantMap tokens = parseTokenResponse(replyData);
|
||||
QVariantMap tokens = parseJsonResponse(replyData);
|
||||
|
||||
// Dump tokens
|
||||
//qDebug() << "O2::onTokenReplyFinished: Tokens returned:\n";
|
||||
@ -340,7 +405,7 @@ void O2::onTokenReplyFinished() {
|
||||
int expiresIn = tokens.take(O2_OAUTH2_EXPIRES_IN).toInt(&ok);
|
||||
if (ok) {
|
||||
// qDebug() << "O2::onTokenReplyFinished: Token expires in" << expiresIn << "seconds";
|
||||
setExpires(QDateTime::currentMSecsSinceEpoch() / 1000 + expiresIn);
|
||||
setExpires((int)(QDateTime::currentMSecsSinceEpoch() / 1000 + expiresIn));
|
||||
}
|
||||
setRefreshToken(tokens.take(O2_OAUTH2_REFRESH_TOKEN).toString());
|
||||
setExtraTokens(tokens);
|
||||
@ -357,11 +422,17 @@ void O2::onTokenReplyFinished() {
|
||||
|
||||
void O2::onTokenReplyError(QNetworkReply::NetworkError error) {
|
||||
QNetworkReply *tokenReply = qobject_cast<QNetworkReply *>(sender());
|
||||
qWarning() << "O2::onTokenReplyError: " << error << ": " << tokenReply->errorString();
|
||||
// qDebug() << "O2::onTokenReplyError: " << tokenReply->readAll();
|
||||
if (!tokenReply)
|
||||
{
|
||||
//qDebug() << "O2::onTokenReplyError: reply is null";
|
||||
} else {
|
||||
qWarning() << "O2::onTokenReplyError: " << error << ": " << tokenReply->errorString();
|
||||
//qDebug() << "O2::onTokenReplyError: " << tokenReply->readAll();
|
||||
timedReplies_.remove(tokenReply);
|
||||
}
|
||||
|
||||
setToken(QString());
|
||||
setRefreshToken(QString());
|
||||
timedReplies_.remove(tokenReply);
|
||||
Q_EMIT linkingFailed();
|
||||
}
|
||||
|
||||
@ -395,6 +466,45 @@ QNetworkAccessManager *O2::getManager()
|
||||
return manager_;
|
||||
}
|
||||
|
||||
void O2::startPollServer(const QVariantMap ¶ms)
|
||||
{
|
||||
bool ok = false;
|
||||
int expiresIn = params[O2_OAUTH2_EXPIRES_IN].toInt(&ok);
|
||||
if (!ok) {
|
||||
qWarning() << "O2::startPollServer: No expired_in parameter";
|
||||
Q_EMIT linkingFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
//qDebug() << "O2::startPollServer: device_ and user_code expires in" << expiresIn << "seconds";
|
||||
|
||||
QUrl url(tokenUrl_);
|
||||
QNetworkRequest authRequest(url);
|
||||
authRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
const QString deviceCode = params[O2_OAUTH2_DEVICE_CODE].toString();
|
||||
const QString grantType = grantType_.isEmpty() ? O2_OAUTH2_GRANT_TYPE_DEVICE : grantType_;
|
||||
|
||||
QList<O0RequestParameter> parameters;
|
||||
parameters.append(O0RequestParameter(O2_OAUTH2_CLIENT_ID, clientId_.toUtf8()));
|
||||
if ( !clientSecret_.isEmpty() )
|
||||
parameters.append(O0RequestParameter(O2_OAUTH2_CLIENT_SECRET, clientSecret_.toUtf8()));
|
||||
parameters.append(O0RequestParameter(O2_OAUTH2_CODE, deviceCode.toUtf8()));
|
||||
parameters.append(O0RequestParameter(O2_OAUTH2_GRANT_TYPE, grantType.toUtf8()));
|
||||
QByteArray payload = O0BaseAuth::createQueryParameters(parameters);
|
||||
|
||||
O2PollServer * pollServer = new O2PollServer(getManager(), authRequest, payload, expiresIn, this);
|
||||
if (params.contains(O2_OAUTH2_INTERVAL)) {
|
||||
int interval = params[O2_OAUTH2_INTERVAL].toInt(&ok);
|
||||
if (ok)
|
||||
pollServer->setInterval(interval);
|
||||
}
|
||||
connect(pollServer, SIGNAL(verificationReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>)));
|
||||
connect(pollServer, SIGNAL(serverClosed(bool)), this, SLOT(serverHasClosed(bool)));
|
||||
setPollServer(pollServer);
|
||||
pollServer->startPolling();
|
||||
}
|
||||
|
||||
QString O2::refreshToken() {
|
||||
QString key = QString(O2_KEY_REFRESH_TOKEN).arg(clientId_);
|
||||
return store_->value(key);
|
||||
@ -432,35 +542,44 @@ void O2::refresh() {
|
||||
QNetworkReply *refreshReply = getManager()->post(refreshRequest, data);
|
||||
timedReplies_.add(refreshReply);
|
||||
connect(refreshReply, SIGNAL(finished()), this, SLOT(onRefreshFinished()), Qt::QueuedConnection);
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(refreshReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRefreshError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(refreshReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRefreshError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
}
|
||||
|
||||
void O2::onRefreshFinished() {
|
||||
QNetworkReply *refreshReply = qobject_cast<QNetworkReply *>(sender());
|
||||
|
||||
if (refreshReply->error() == QNetworkReply::NoError) {
|
||||
QByteArray reply = refreshReply->readAll();
|
||||
QVariantMap tokens = parseTokenResponse(reply);
|
||||
QVariantMap tokens = parseJsonResponse(reply);
|
||||
if ( tokens.contains(QStringLiteral("error")) ) {
|
||||
qDebug() << " Error refreshing token" << tokens.value(QStringLiteral("error")).toMap().value(QStringLiteral("message")).toString().toLocal8Bit().constData();
|
||||
unlink();
|
||||
timedReplies_.remove(refreshReply);
|
||||
Q_EMIT refreshFinished(QNetworkReply::NoError);
|
||||
}
|
||||
else
|
||||
{
|
||||
setToken(tokens.value(O2_OAUTH2_ACCESS_TOKEN).toString());
|
||||
setExpires(QDateTime::currentMSecsSinceEpoch() / 1000 + tokens.value(O2_OAUTH2_EXPIRES_IN).toInt());
|
||||
const QString refreshToken = tokens.value(O2_OAUTH2_REFRESH_TOKEN).toString();
|
||||
if ( !refreshToken.isEmpty() )
|
||||
setRefreshToken(refreshToken);
|
||||
setExpires((int)(QDateTime::currentMSecsSinceEpoch() / 1000 + tokens.value(O2_OAUTH2_EXPIRES_IN).toInt()));
|
||||
QString refreshToken = tokens.value(O2_OAUTH2_REFRESH_TOKEN).toString();
|
||||
if(!refreshToken.isEmpty()) {
|
||||
setRefreshToken(refreshToken);
|
||||
}
|
||||
else {
|
||||
//qDebug() << "No new refresh token. Keep the old one.";
|
||||
}
|
||||
timedReplies_.remove(refreshReply);
|
||||
setLinked(true);
|
||||
//qDebug() << " New token expires in" << expires() << "seconds";
|
||||
Q_EMIT linkingSucceeded();
|
||||
Q_EMIT refreshFinished(QNetworkReply::NoError);
|
||||
//qDebug() << " New token expires in" << expires() << "seconds";
|
||||
}
|
||||
timedReplies_.remove(refreshReply);
|
||||
Q_EMIT refreshFinished(QNetworkReply::NoError);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "O2::onRefreshFinished: Error" << (int)refreshReply->error() << refreshReply->errorString();
|
||||
} else {
|
||||
//qDebug() << "O2::onRefreshFinished: Error" << (int)refreshReply->error() << refreshReply->errorString();
|
||||
}
|
||||
refreshReply->deleteLater();
|
||||
}
|
||||
@ -473,12 +592,63 @@ void O2::onRefreshError(QNetworkReply::NetworkError error) {
|
||||
Q_EMIT refreshFinished(error);
|
||||
}
|
||||
|
||||
void O2::onDeviceAuthReplyFinished()
|
||||
{
|
||||
qDebug() << "O2::onDeviceAuthReplyFinished";
|
||||
QNetworkReply *tokenReply = qobject_cast<QNetworkReply *>(sender());
|
||||
if (!tokenReply)
|
||||
{
|
||||
qDebug() << "O2::onDeviceAuthReplyFinished: reply is null";
|
||||
return;
|
||||
}
|
||||
if (tokenReply->error() == QNetworkReply::NoError) {
|
||||
QByteArray replyData = tokenReply->readAll();
|
||||
|
||||
// Dump replyData
|
||||
// SENSITIVE DATA in RelWithDebInfo or Debug builds
|
||||
//qDebug() << "O2::onDeviceAuthReplyFinished: replyData\n";
|
||||
//qDebug() << QString( replyData );
|
||||
|
||||
QVariantMap params = parseJsonResponse(replyData);
|
||||
|
||||
// Dump tokens
|
||||
qDebug() << "O2::onDeviceAuthReplyFinished: Tokens returned:\n";
|
||||
foreach (QString key, params.keys()) {
|
||||
// SENSITIVE DATA in RelWithDebInfo or Debug builds, so it is truncated first
|
||||
qDebug() << key << ": "<< params.value( key ).toString().left( 3 ) << "...";
|
||||
}
|
||||
|
||||
// Check for mandatory parameters
|
||||
if (hasMandatoryDeviceAuthParams(params)) {
|
||||
qDebug() << "O2::onDeviceAuthReplyFinished: Device auth request response";
|
||||
|
||||
const QString userCode = params.take(O2_OAUTH2_USER_CODE).toString();
|
||||
QUrl uri = params.take(O2_OAUTH2_VERIFICATION_URI).toUrl();
|
||||
if (uri.isEmpty())
|
||||
uri = params.take(O2_OAUTH2_VERIFICATION_URL).toUrl();
|
||||
|
||||
if (params.contains(O2_OAUTH2_VERIFICATION_URI_COMPLETE))
|
||||
Q_EMIT openBrowser(params.take(O2_OAUTH2_VERIFICATION_URI_COMPLETE).toUrl());
|
||||
|
||||
Q_EMIT showVerificationUriAndCode(uri, userCode);
|
||||
|
||||
startPollServer(params);
|
||||
} else {
|
||||
qWarning() << "O2::onDeviceAuthReplyFinished: Mandatory parameters missing from response";
|
||||
Q_EMIT linkingFailed();
|
||||
}
|
||||
}
|
||||
tokenReply->deleteLater();
|
||||
}
|
||||
|
||||
void O2::serverHasClosed(bool paramsfound)
|
||||
{
|
||||
if ( !paramsfound ) {
|
||||
// server has probably timed out after receiving first response
|
||||
Q_EMIT linkingFailed();
|
||||
}
|
||||
// poll server is not re-used for later auth requests
|
||||
setPollServer(NULL);
|
||||
}
|
||||
|
||||
QString O2::localhostPolicy() const {
|
||||
@ -497,14 +667,6 @@ void O2::setApiKey(const QString &value) {
|
||||
apiKey_ = value;
|
||||
}
|
||||
|
||||
QByteArray O2::replyContent() {
|
||||
return replyServer_->replyContent();
|
||||
}
|
||||
|
||||
void O2::setReplyContent(const QByteArray &value) {
|
||||
replyServer_->setReplyContent(value);
|
||||
}
|
||||
|
||||
bool O2::ignoreSslErrors() {
|
||||
return timedReplies_.ignoreSslErrors();
|
||||
}
|
||||
|
30
external/o2/src/o2.h
vendored
30
external/o2/src/o2.h
vendored
@ -11,11 +11,11 @@
|
||||
#include "o2reply.h"
|
||||
#include "o0abstractstore.h"
|
||||
|
||||
class O2ReplyServer;
|
||||
|
||||
/// Simple OAuth2 authenticator.
|
||||
class O0_EXPORT O2: public O0BaseAuth {
|
||||
class O0_EXPORT O2: public O0BaseAuth
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_ENUMS(GrantFlow)
|
||||
|
||||
public:
|
||||
@ -25,6 +25,7 @@ public:
|
||||
GrantFlowImplicit, ///< @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.2
|
||||
GrantFlowResourceOwnerPasswordCredentials,
|
||||
GrantFlowPkce, ///< @see https://www.rfc-editor.org/rfc/rfc7636
|
||||
GrantFlowDevice ///< @see https://tools.ietf.org/html/rfc8628#section-1
|
||||
};
|
||||
|
||||
/// Authorization flow.
|
||||
@ -60,12 +61,6 @@ public:
|
||||
QString apiKey();
|
||||
void setApiKey(const QString &value);
|
||||
|
||||
/// Page content on local host after successful oauth.
|
||||
/// Provide it 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);
|
||||
|
||||
/// Allow ignoring SSL errors?
|
||||
/// E.g. SurveyMonkey fails on Mac due to SSL error. Ignoring the error circumvents the problem
|
||||
Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors)
|
||||
@ -92,10 +87,15 @@ public:
|
||||
QString refreshTokenUrl();
|
||||
void setRefreshTokenUrl(const QString &value);
|
||||
|
||||
/// Grant type (if non-standard)
|
||||
Q_PROPERTY(QString grantType READ grantType WRITE setGrantType)
|
||||
QString grantType();
|
||||
void setGrantType(const QString &value);
|
||||
|
||||
public:
|
||||
/// Constructor.
|
||||
/// @param parent Parent object.
|
||||
explicit O2(QObject *parent = 0, QNetworkAccessManager *manager = 0);
|
||||
explicit O2(QObject *parent = 0, QNetworkAccessManager *manager = 0, O0AbstractStore *store = 0);
|
||||
|
||||
/// Get authentication code.
|
||||
QString code();
|
||||
@ -133,10 +133,11 @@ Q_SIGNALS:
|
||||
void refreshTokenUrlChanged();
|
||||
void tokenUrlChanged();
|
||||
|
||||
protected Q_SLOTS:
|
||||
public Q_SLOTS:
|
||||
/// Handle verification response.
|
||||
virtual void onVerificationReceived(QMap<QString, QString>);
|
||||
|
||||
protected Q_SLOTS:
|
||||
/// Handle completion of a token request.
|
||||
virtual void onTokenReplyFinished();
|
||||
|
||||
@ -149,6 +150,9 @@ protected Q_SLOTS:
|
||||
/// 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> ¶meters);
|
||||
@ -163,6 +167,8 @@ protected:
|
||||
void setExpires(int v);
|
||||
|
||||
virtual QNetworkAccessManager *getManager();
|
||||
/// Start polling authorization server
|
||||
void startPollServer(const QVariantMap ¶ms);
|
||||
|
||||
protected:
|
||||
QString username_;
|
||||
@ -176,9 +182,9 @@ protected:
|
||||
QString localhostPolicy_;
|
||||
QString apiKey_;
|
||||
QNetworkAccessManager *manager_;
|
||||
O2ReplyServer *replyServer_;
|
||||
O2ReplyList timedReplies_;
|
||||
GrantFlow grantFlow_;
|
||||
QString grantType_;
|
||||
};
|
||||
|
||||
#endif // O2_H
|
||||
|
18
external/o2/src/o2facebook.cpp
vendored
18
external/o2/src/o2facebook.cpp
vendored
@ -1,4 +1,6 @@
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QMap>
|
||||
#include <QNetworkReply>
|
||||
#include <QString>
|
||||
@ -13,7 +15,7 @@
|
||||
|
||||
static const char *FbEndpoint = "https://graph.facebook.com/oauth/authorize?display=touch";
|
||||
static const char *FbTokenUrl = "https://graph.facebook.com/oauth/access_token";
|
||||
static const char *FbExpiresKey = "expires";
|
||||
static const char *FbExpiresKey = "expires_in";
|
||||
|
||||
O2Facebook::O2Facebook(QObject *parent): O2(parent) {
|
||||
setRequestUrl(FbEndpoint);
|
||||
@ -58,7 +60,11 @@ void O2Facebook::onVerificationReceived(const QMap<QString, QString> response) {
|
||||
QNetworkReply *tokenReply = manager_->get(tokenRequest);
|
||||
timedReplies_.add(tokenReply);
|
||||
connect(tokenReply, SIGNAL(finished()), this, SLOT(onTokenReplyFinished()), Qt::QueuedConnection);
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(tokenReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(tokenReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
}
|
||||
|
||||
void O2Facebook::onTokenReplyFinished() {
|
||||
@ -68,12 +74,12 @@ void O2Facebook::onTokenReplyFinished() {
|
||||
if (tokenReply->error() == QNetworkReply::NoError) {
|
||||
// Process reply
|
||||
QByteArray replyData = tokenReply->readAll();
|
||||
QJsonDocument doc = QJsonDocument::fromJson(replyData);
|
||||
const QJsonObject rootObject = doc.object();
|
||||
|
||||
QVariantMap reply;
|
||||
foreach (QString pair, QString(replyData).split("&")) {
|
||||
QStringList kv = pair.split("=");
|
||||
if (kv.length() == 2) {
|
||||
reply.insert(kv[0], kv[1]);
|
||||
}
|
||||
for (const QString &key : rootObject.keys()) {
|
||||
reply.insert(key, rootObject[key].toVariant());
|
||||
}
|
||||
|
||||
// Interpret reply
|
||||
|
4
external/o2/src/o2facebook.h
vendored
4
external/o2/src/o2facebook.h
vendored
@ -11,8 +11,10 @@ class O0_EXPORT O2Facebook: public O2 {
|
||||
public:
|
||||
explicit O2Facebook(QObject *parent = 0);
|
||||
|
||||
protected Q_SLOTS:
|
||||
public Q_SLOTS:
|
||||
void onVerificationReceived(QMap<QString, QString>);
|
||||
|
||||
protected Q_SLOTS:
|
||||
virtual void onTokenReplyFinished();
|
||||
};
|
||||
|
||||
|
4
external/o2/src/o2gft.cpp
vendored
4
external/o2/src/o2gft.cpp
vendored
@ -1,9 +1,7 @@
|
||||
#include "o2gft.h"
|
||||
#include "o2google.h"
|
||||
|
||||
static const char *GftScope = "https://www.googleapis.com/auth/fusiontables";
|
||||
static const char *GftEndpoint = "https://accounts.google.com/o/oauth2/auth";
|
||||
static const char *GftTokenUrl = "https://accounts.google.com/o/oauth2/token";
|
||||
static const char *GftRefreshUrl = "https://accounts.google.com/o/oauth2/token";
|
||||
|
||||
O2Gft::O2Gft(QObject *parent): O2Google(parent) {
|
||||
setScope(GftScope);
|
||||
|
1
external/o2/src/o2google.h
vendored
1
external/o2/src/o2google.h
vendored
@ -5,6 +5,7 @@
|
||||
#ifndef O2_O2GOOGLE_H
|
||||
#define O2_O2GOOGLE_H
|
||||
|
||||
#include "o2.h"
|
||||
|
||||
class O2Google : public O2 {
|
||||
Q_OBJECT
|
||||
|
15
external/o2/src/o2googledevice.cpp
vendored
Normal file
15
external/o2/src/o2googledevice.cpp
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
#include "o2googledevice.h"
|
||||
|
||||
static const char *GoogleDeviceTokenUrl = "https://oauth2.googleapis.com/token";
|
||||
static const char *GoogleDeviceRefreshUrl = "https://oauth2.googleapis.com/token";
|
||||
static const char *GoogleDeviceEndpoint = "https://oauth2.googleapis.com/device/code";
|
||||
// Google uses a different grant type value than specified in RFC 8628
|
||||
static const char *GoogleDeviceGrantType = "http://oauth.net/grant_type/device/1.0";
|
||||
|
||||
O2GoogleDevice::O2GoogleDevice(QObject *parent) : O2(parent) {
|
||||
setGrantFlow(GrantFlowDevice);
|
||||
setGrantType(GoogleDeviceGrantType);
|
||||
setRequestUrl(GoogleDeviceEndpoint);
|
||||
setTokenUrl(GoogleDeviceTokenUrl);
|
||||
setRefreshTokenUrl(GoogleDeviceRefreshUrl);
|
||||
}
|
16
external/o2/src/o2googledevice.h
vendored
Normal file
16
external/o2/src/o2googledevice.h
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef O2GOOGLEDEVICE_H
|
||||
#define O2GOOGLEDEVICE_H
|
||||
|
||||
#include "o0export.h"
|
||||
#include "o2.h"
|
||||
|
||||
/// "Google Sign-In for TVs and Devices",
|
||||
/// A dialect of RFC 8628: OAuth 2.0 Device Authorization Grant
|
||||
class O0_EXPORT O2GoogleDevice : public O2 {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit O2GoogleDevice(QObject *parent = 0);
|
||||
};
|
||||
|
||||
#endif // O2GOOGLEDEVICE_H
|
1
external/o2/src/o2hubic.cpp
vendored
1
external/o2/src/o2hubic.cpp
vendored
@ -1,5 +1,4 @@
|
||||
#include "o2hubic.h"
|
||||
#include "o2globals.h"
|
||||
#include "o2replyserver.h"
|
||||
#include <QHostAddress>
|
||||
|
||||
|
10
external/o2/src/o2msgraph.cpp
vendored
Normal file
10
external/o2/src/o2msgraph.cpp
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
#include "o2msgraph.h"
|
||||
|
||||
static const char *MsgraphEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
|
||||
static const char *MsgraphTokenUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
|
||||
|
||||
O2Msgraph::O2Msgraph(QObject *parent): O2(parent) {
|
||||
setRequestUrl(MsgraphEndpoint);
|
||||
setTokenUrl(MsgraphTokenUrl);
|
||||
setRefreshTokenUrl(MsgraphTokenUrl);
|
||||
}
|
15
external/o2/src/o2msgraph.h
vendored
Normal file
15
external/o2/src/o2msgraph.h
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef O2MSGRAPH_H
|
||||
#define O2MSGRAPH_H
|
||||
|
||||
#include "o0export.h"
|
||||
#include "o2.h"
|
||||
|
||||
/// Microsoft Graph's dialect of OAuth 2.0
|
||||
class O0_EXPORT O2Msgraph: public O2 {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit O2Msgraph(QObject *parent = 0);
|
||||
};
|
||||
|
||||
#endif // O2MSGRAPH_H
|
14
external/o2/src/o2outlook.cpp
vendored
Normal file
14
external/o2/src/o2outlook.cpp
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
#include "o2outlook.h"
|
||||
#include "o0globals.h"
|
||||
|
||||
O2Outlook::O2Outlook(QObject *parent): O2Skydrive(parent) {
|
||||
setRequestUrl("https://login.microsoftonline.com/common/oauth2/v2.0/authorize");
|
||||
setTokenUrl("https://login.microsoftonline.com/common/oauth2/v2.0/token");
|
||||
setRefreshTokenUrl("https://login.microsoftonline.com/common/oauth2/v2.0/token");
|
||||
redirectUri_ = QString("https://login.live.com/oauth20_desktop.srf");
|
||||
}
|
||||
|
||||
QUrl O2Outlook::redirectUrl()
|
||||
{
|
||||
return redirectUri_;
|
||||
}
|
17
external/o2/src/o2outlook.h
vendored
Normal file
17
external/o2/src/o2outlook.h
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef O2OUTLOOK_H
|
||||
#define O2OUTLOOK_H
|
||||
|
||||
#include "o2skydrive.h"
|
||||
|
||||
/// Outlook's dialect of OAuth 2.0
|
||||
class O0_EXPORT O2Outlook: public O2Skydrive
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit O2Outlook(QObject *parent = nullptr);
|
||||
|
||||
public:
|
||||
QUrl redirectUrl();
|
||||
};
|
||||
|
||||
#endif // O2OUTLOOK_H
|
117
external/o2/src/o2pollserver.cpp
vendored
Normal file
117
external/o2/src/o2pollserver.cpp
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include "o2pollserver.h"
|
||||
#include "o0jsonresponse.h"
|
||||
|
||||
static QMap<QString, QString> toVerificationParams(const QVariantMap &map)
|
||||
{
|
||||
QMap<QString, QString> params;
|
||||
for (QVariantMap::const_iterator i = map.constBegin();
|
||||
i != map.constEnd(); ++i)
|
||||
{
|
||||
params[i.key()] = i.value().toString();
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
O2PollServer::O2PollServer(QNetworkAccessManager *manager, const QNetworkRequest &request, const QByteArray &payload, int expiresIn, QObject *parent)
|
||||
: QObject(parent)
|
||||
, manager_(manager)
|
||||
, request_(request)
|
||||
, payload_(payload)
|
||||
, expiresIn_(expiresIn)
|
||||
{
|
||||
expirationTimer.setTimerType(Qt::VeryCoarseTimer);
|
||||
expirationTimer.setInterval(expiresIn * 1000);
|
||||
expirationTimer.setSingleShot(true);
|
||||
connect(&expirationTimer, SIGNAL(timeout()), this, SLOT(onExpiration()));
|
||||
expirationTimer.start();
|
||||
|
||||
pollTimer.setTimerType(Qt::VeryCoarseTimer);
|
||||
pollTimer.setInterval(5 * 1000);
|
||||
pollTimer.setSingleShot(true);
|
||||
connect(&pollTimer, SIGNAL(timeout()), this, SLOT(onPollTimeout()));
|
||||
}
|
||||
|
||||
int O2PollServer::interval() const
|
||||
{
|
||||
return pollTimer.interval() / 1000;
|
||||
}
|
||||
|
||||
void O2PollServer::setInterval(int interval)
|
||||
{
|
||||
pollTimer.setInterval(interval * 1000);
|
||||
}
|
||||
|
||||
void O2PollServer::startPolling()
|
||||
{
|
||||
if (expirationTimer.isActive()) {
|
||||
pollTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
void O2PollServer::onPollTimeout()
|
||||
{
|
||||
qDebug() << "O2PollServer::onPollTimeout: retrying";
|
||||
QNetworkReply * reply = manager_->post(request_, payload_);
|
||||
connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished()));
|
||||
}
|
||||
|
||||
void O2PollServer::onExpiration()
|
||||
{
|
||||
pollTimer.stop();
|
||||
Q_EMIT serverClosed(false);
|
||||
}
|
||||
|
||||
void O2PollServer::onReplyFinished()
|
||||
{
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||
|
||||
if (!reply) {
|
||||
qDebug() << "O2PollServer::onReplyFinished: reply is null";
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray replyData = reply->readAll();
|
||||
QMap<QString, QString> params = toVerificationParams(parseJsonResponse(replyData));
|
||||
|
||||
// Dump replyData
|
||||
// SENSITIVE DATA in RelWithDebInfo or Debug builds
|
||||
// qDebug() << "O2PollServer::onReplyFinished: replyData\n";
|
||||
// qDebug() << QString( replyData );
|
||||
|
||||
if (reply->error() == QNetworkReply::TimeoutError) {
|
||||
// rfc8628#section-3.2
|
||||
// "On encountering a connection timeout, clients MUST unilaterally
|
||||
// reduce their polling frequency before retrying. The use of an
|
||||
// exponential backoff algorithm to achieve this, such as doubling the
|
||||
// polling interval on each such connection timeout, is RECOMMENDED."
|
||||
setInterval(interval() * 2);
|
||||
pollTimer.start();
|
||||
}
|
||||
else {
|
||||
QString error = params.value("error");
|
||||
if (error == "slow_down") {
|
||||
// rfc8628#section-3.2
|
||||
// "A variant of 'authorization_pending', the authorization request is
|
||||
// still pending and polling should continue, but the interval MUST
|
||||
// be increased by 5 seconds for this and all subsequent requests."
|
||||
setInterval(interval() + 5);
|
||||
pollTimer.start();
|
||||
}
|
||||
else if (error == "authorization_pending") {
|
||||
// keep trying - rfc8628#section-3.2
|
||||
// "The authorization request is still pending as the end user hasn't
|
||||
// yet completed the user-interaction steps (Section 3.3)."
|
||||
pollTimer.start();
|
||||
}
|
||||
else {
|
||||
expirationTimer.stop();
|
||||
Q_EMIT serverClosed(true);
|
||||
// let O2 handle the other cases
|
||||
Q_EMIT verificationReceived(params);
|
||||
}
|
||||
}
|
||||
reply->deleteLater();
|
||||
}
|
49
external/o2/src/o2pollserver.h
vendored
Normal file
49
external/o2/src/o2pollserver.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef O2POLLSERVER_H
|
||||
#define O2POLLSERVER_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QMap>
|
||||
#include <QNetworkRequest>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
|
||||
#include "o0export.h"
|
||||
|
||||
class QNetworkAccessManager;
|
||||
|
||||
/// Poll an authorization server for token
|
||||
class O0_EXPORT O2PollServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit O2PollServer(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);
|
||||
|
||||
Q_SIGNALS:
|
||||
void verificationReceived(QMap<QString, QString>);
|
||||
void serverClosed(bool); // whether it has found parameters
|
||||
|
||||
public Q_SLOTS:
|
||||
void startPolling();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onPollTimeout();
|
||||
void onExpiration();
|
||||
void onReplyFinished();
|
||||
|
||||
protected:
|
||||
QNetworkAccessManager *manager_;
|
||||
const QNetworkRequest request_;
|
||||
const QByteArray payload_;
|
||||
const int expiresIn_;
|
||||
QTimer expirationTimer;
|
||||
QTimer pollTimer;
|
||||
};
|
||||
|
||||
#endif // O2POLLSERVER_H
|
4
external/o2/src/o2reply.cpp
vendored
4
external/o2/src/o2reply.cpp
vendored
@ -5,7 +5,11 @@
|
||||
|
||||
O2Reply::O2Reply(QNetworkReply *r, int timeOut, QObject *parent): QTimer(parent), reply(r) {
|
||||
setSingleShot(true);
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(this, SIGNAL(error(QNetworkReply::NetworkError)), reply, SIGNAL(error(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(this, SIGNAL(error(QNetworkReply::NetworkError)), reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
connect(this, SIGNAL(timeout()), this, SLOT(onTimeOut()), Qt::QueuedConnection);
|
||||
start(timeOut);
|
||||
}
|
||||
|
2
external/o2/src/o2reply.h
vendored
2
external/o2/src/o2reply.h
vendored
@ -29,7 +29,7 @@ public:
|
||||
};
|
||||
|
||||
/// List of O2Replies.
|
||||
class O2ReplyList {
|
||||
class O0_EXPORT O2ReplyList {
|
||||
public:
|
||||
O2ReplyList() { ignoreSslErrors_ = false; }
|
||||
|
||||
|
16
external/o2/src/o2replyserver.cpp
vendored
16
external/o2/src/o2replyserver.cpp
vendored
@ -12,6 +12,7 @@
|
||||
#include <QUrlQuery>
|
||||
#endif
|
||||
|
||||
#include "o0globals.h"
|
||||
#include "o2replyserver.h"
|
||||
|
||||
O2ReplyServer::O2ReplyServer(QObject *parent): QTcpServer(parent),
|
||||
@ -73,6 +74,11 @@ void O2ReplyServer::onBytesReady() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!uniqueState_.isEmpty() && !queryParams.contains(QString(O2_OAUTH2_STATE))) {
|
||||
//qDebug() << "O2ReplyServer::onBytesReady: Malicious or service request";
|
||||
closeServer(socket, true);
|
||||
return; // Malicious or service (e.g. favicon.ico) request
|
||||
}
|
||||
//qDebug() << "O2ReplyServer::onBytesReady: Query params found, closing server";
|
||||
closeServer(socket, true);
|
||||
Q_EMIT verificationReceived(queryParams);
|
||||
@ -166,3 +172,13 @@ void O2ReplyServer::setCallbackTries(int maxtries)
|
||||
{
|
||||
maxtries_ = maxtries;
|
||||
}
|
||||
|
||||
QString O2ReplyServer::uniqueState()
|
||||
{
|
||||
return uniqueState_;
|
||||
}
|
||||
|
||||
void O2ReplyServer::setUniqueState(const QString &state)
|
||||
{
|
||||
uniqueState_ = state;
|
||||
}
|
||||
|
4
external/o2/src/o2replyserver.h
vendored
4
external/o2/src/o2replyserver.h
vendored
@ -30,6 +30,9 @@ public:
|
||||
int callbackTries();
|
||||
void setCallbackTries(int maxtries);
|
||||
|
||||
QString uniqueState();
|
||||
void setUniqueState(const QString &state);
|
||||
|
||||
Q_SIGNALS:
|
||||
void verificationReceived(QMap<QString, QString>);
|
||||
void serverClosed(bool); // whether it has found parameters
|
||||
@ -45,6 +48,7 @@ protected:
|
||||
int timeout_;
|
||||
int maxtries_;
|
||||
int tries_;
|
||||
QString uniqueState_;
|
||||
};
|
||||
|
||||
#endif // O2REPLYSERVER_H
|
||||
|
220
external/o2/src/o2requestor.cpp
vendored
220
external/o2/src/o2requestor.cpp
vendored
@ -1,5 +1,8 @@
|
||||
#include <cassert>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QBuffer>
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QUrlQuery>
|
||||
#endif
|
||||
@ -8,7 +11,7 @@
|
||||
#include "o2.h"
|
||||
#include "o0globals.h"
|
||||
|
||||
O2Requestor::O2Requestor(QNetworkAccessManager *manager, O2 *authenticator, QObject *parent): QObject(parent), reply_(NULL), status_(Idle) {
|
||||
O2Requestor::O2Requestor(QNetworkAccessManager *manager, O2 *authenticator, QObject *parent): QObject(parent), reply_(NULL), status_(Idle), addAccessTokenInQuery_(true), rawData_(false) {
|
||||
manager_ = manager;
|
||||
authenticator_ = authenticator;
|
||||
if (authenticator) {
|
||||
@ -21,43 +24,162 @@ O2Requestor::O2Requestor(QNetworkAccessManager *manager, O2 *authenticator, QObj
|
||||
O2Requestor::~O2Requestor() {
|
||||
}
|
||||
|
||||
int O2Requestor::get(const QNetworkRequest &req) {
|
||||
void O2Requestor::setAddAccessTokenInQuery(bool value) {
|
||||
addAccessTokenInQuery_ = value;
|
||||
}
|
||||
|
||||
void O2Requestor::setAccessTokenInAuthenticationHTTPHeaderFormat(const QString &value) {
|
||||
accessTokenInAuthenticationHTTPHeaderFormat_ = value;
|
||||
}
|
||||
|
||||
int O2Requestor::get(const QNetworkRequest &req, int timeout/* = 60*1000*/) {
|
||||
if (-1 == setup(req, QNetworkAccessManager::GetOperation)) {
|
||||
return -1;
|
||||
}
|
||||
reply_ = manager_->get(request_);
|
||||
timedReplies_.add(reply_);
|
||||
timedReplies_.add(new O2Reply(reply_, timeout));
|
||||
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
|
||||
return id_;
|
||||
}
|
||||
|
||||
int O2Requestor::post(const QNetworkRequest &req, const QByteArray &data) {
|
||||
int O2Requestor::post(const QNetworkRequest &req, const QByteArray &data, int timeout/* = 60*1000*/) {
|
||||
if (-1 == setup(req, QNetworkAccessManager::PostOperation)) {
|
||||
return -1;
|
||||
}
|
||||
rawData_ = true;
|
||||
data_ = data;
|
||||
reply_ = manager_->post(request_, data_);
|
||||
timedReplies_.add(reply_);
|
||||
timedReplies_.add(new O2Reply(reply_, timeout));
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
|
||||
connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
|
||||
return id_;
|
||||
}
|
||||
|
||||
int O2Requestor::put(const QNetworkRequest &req, const QByteArray &data) {
|
||||
int O2Requestor::post(const QNetworkRequest & req, QHttpMultiPart* data, int timeout/* = 60*1000*/)
|
||||
{
|
||||
if (-1 == setup(req, QNetworkAccessManager::PostOperation)) {
|
||||
return -1;
|
||||
}
|
||||
rawData_ = false;
|
||||
multipartData_ = data;
|
||||
reply_ = manager_->post(request_, multipartData_);
|
||||
multipartData_->setParent(reply_);
|
||||
timedReplies_.add(new O2Reply(reply_, timeout));
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
|
||||
connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
|
||||
return id_;
|
||||
}
|
||||
|
||||
int O2Requestor::put(const QNetworkRequest &req, const QByteArray &data, int timeout/* = 60*1000*/) {
|
||||
if (-1 == setup(req, QNetworkAccessManager::PutOperation)) {
|
||||
return -1;
|
||||
}
|
||||
rawData_ = true;
|
||||
data_ = data;
|
||||
reply_ = manager_->put(request_, data_);
|
||||
timedReplies_.add(reply_);
|
||||
timedReplies_.add(new O2Reply(reply_, timeout));
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
|
||||
connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
|
||||
return id_;
|
||||
}
|
||||
|
||||
int O2Requestor::put(const QNetworkRequest & req, QHttpMultiPart* data, int timeout/* = 60*1000*/)
|
||||
{
|
||||
if (-1 == setup(req, QNetworkAccessManager::PutOperation)) {
|
||||
return -1;
|
||||
}
|
||||
rawData_ = false;
|
||||
multipartData_ = data;
|
||||
reply_ = manager_->put(request_, multipartData_);
|
||||
multipartData_->setParent(reply_);
|
||||
timedReplies_.add(new O2Reply(reply_, timeout));
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
|
||||
connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
|
||||
return id_;
|
||||
}
|
||||
|
||||
int O2Requestor::deleteResource(const QNetworkRequest & req, int timeout/* = 60*1000*/)
|
||||
{
|
||||
if (-1 == setup(req, QNetworkAccessManager::DeleteOperation)) {
|
||||
return -1;
|
||||
}
|
||||
rawData_ = false;
|
||||
reply_ = manager_->deleteResource(request_);
|
||||
timedReplies_.add(new O2Reply(reply_, timeout));
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
|
||||
return id_;
|
||||
}
|
||||
|
||||
int O2Requestor::customRequest(const QNetworkRequest &req, const QByteArray &verb, const QByteArray &data, int timeout/* = 60*1000*/)
|
||||
{
|
||||
(void)timeout;
|
||||
|
||||
if (-1 == setup(req, QNetworkAccessManager::CustomOperation, verb)) {
|
||||
return -1;
|
||||
}
|
||||
data_ = data;
|
||||
QBuffer * buffer = new QBuffer;
|
||||
buffer->setData(data_);
|
||||
reply_ = manager_->sendCustomRequest(request_, verb, buffer);
|
||||
buffer->setParent(reply_);
|
||||
timedReplies_.add(new O2Reply(reply_));
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
|
||||
connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
|
||||
return id_;
|
||||
}
|
||||
|
||||
int O2Requestor::head(const QNetworkRequest &req, int timeout/* = 60*1000*/)
|
||||
{
|
||||
if (-1 == setup(req, QNetworkAccessManager::HeadOperation)) {
|
||||
return -1;
|
||||
}
|
||||
reply_ = manager_->head(request_);
|
||||
timedReplies_.add(new O2Reply(reply_, timeout));
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
|
||||
return id_;
|
||||
}
|
||||
|
||||
void O2Requestor::onRefreshFinished(QNetworkReply::NetworkError error) {
|
||||
if (status_ != Requesting) {
|
||||
qWarning() << "O2Requestor::onRefreshFinished: No pending request";
|
||||
@ -72,15 +194,13 @@ void O2Requestor::onRefreshFinished(QNetworkReply::NetworkError error) {
|
||||
}
|
||||
|
||||
void O2Requestor::onRequestFinished() {
|
||||
QNetworkReply *senderReply = qobject_cast<QNetworkReply *>(sender());
|
||||
QNetworkReply::NetworkError error = senderReply->error();
|
||||
if (status_ == Idle) {
|
||||
return;
|
||||
}
|
||||
if (reply_ != senderReply) {
|
||||
if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
|
||||
return;
|
||||
}
|
||||
if (error == QNetworkReply::NoError) {
|
||||
if (reply_->error() == QNetworkReply::NoError) {
|
||||
QTimer::singleShot(10, this, SLOT(finish()));
|
||||
}
|
||||
}
|
||||
@ -95,7 +215,6 @@ void O2Requestor::onRequestError(QNetworkReply::NetworkError error) {
|
||||
}
|
||||
int httpStatus = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
qWarning() << "O2Requestor::onRequestError: HTTP status" << httpStatus << reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
||||
qDebug() << reply_->readAll();
|
||||
if ((status_ == Requesting) && (httpStatus == 401)) {
|
||||
// Call O2::refresh. Note the O2 instance might live in a different thread
|
||||
if (QMetaObject::invokeMethod(authenticator_, "refresh")) {
|
||||
@ -115,12 +234,15 @@ void O2Requestor::onUploadProgress(qint64 uploaded, qint64 total) {
|
||||
if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
|
||||
return;
|
||||
}
|
||||
// Restart timeout because request in progress
|
||||
O2Reply *o2Reply = timedReplies_.find(reply_);
|
||||
if(o2Reply)
|
||||
o2Reply->start();
|
||||
Q_EMIT uploadProgress(id_, uploaded, total);
|
||||
}
|
||||
|
||||
int O2Requestor::setup(const QNetworkRequest &req, QNetworkAccessManager::Operation operation) {
|
||||
int O2Requestor::setup(const QNetworkRequest &req, QNetworkAccessManager::Operation operation, const QByteArray &verb) {
|
||||
static int currentId;
|
||||
QUrl url;
|
||||
|
||||
if (status_ != Idle) {
|
||||
qWarning() << "O2Requestor::setup: Another request pending";
|
||||
@ -130,15 +252,30 @@ int O2Requestor::setup(const QNetworkRequest &req, QNetworkAccessManager::Operat
|
||||
request_ = req;
|
||||
operation_ = operation;
|
||||
id_ = currentId++;
|
||||
url_ = url = req.url();
|
||||
url_ = req.url();
|
||||
|
||||
QUrl url = url_;
|
||||
if (addAccessTokenInQuery_) {
|
||||
#if QT_VERSION < 0x050000
|
||||
url.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
|
||||
url.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
|
||||
#else
|
||||
QUrlQuery query(url);
|
||||
query.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
|
||||
url.setQuery(query);
|
||||
QUrlQuery query(url);
|
||||
query.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
|
||||
url.setQuery(query);
|
||||
#endif
|
||||
}
|
||||
|
||||
request_.setUrl(url);
|
||||
|
||||
// If the service require the access token to be sent as a Authentication HTTP header, we add the access token.
|
||||
if (!accessTokenInAuthenticationHTTPHeaderFormat_.isEmpty()) {
|
||||
request_.setRawHeader(O2_HTTP_AUTHORIZATION_HEADER, accessTokenInAuthenticationHTTPHeaderFormat_.arg(authenticator_->token()).toLatin1());
|
||||
}
|
||||
|
||||
if (!verb.isEmpty()) {
|
||||
request_.setRawHeader(O2_HTTP_HTTP_HEADER, verb);
|
||||
}
|
||||
|
||||
status_ = Requesting;
|
||||
error_ = QNetworkReply::NoError;
|
||||
return id_;
|
||||
@ -155,7 +292,11 @@ void O2Requestor::finish() {
|
||||
timedReplies_.remove(reply_);
|
||||
reply_->disconnect(this);
|
||||
reply_->deleteLater();
|
||||
QList<QNetworkReply::RawHeaderPair> headers = reply_->rawHeaderPairs();
|
||||
Q_EMIT finished(id_, error_, data);
|
||||
Q_EMIT finished(id_, error_, reply_->errorString(), data);
|
||||
Q_EMIT finished(id_, error_, data, headers);
|
||||
Q_EMIT finished(id_, error_, reply_->errorString(), data, headers);
|
||||
}
|
||||
|
||||
void O2Requestor::retry() {
|
||||
@ -167,27 +308,56 @@ void O2Requestor::retry() {
|
||||
reply_->disconnect(this);
|
||||
reply_->deleteLater();
|
||||
QUrl url = url_;
|
||||
if (addAccessTokenInQuery_) {
|
||||
#if QT_VERSION < 0x050000
|
||||
url.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
|
||||
url.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
|
||||
#else
|
||||
QUrlQuery query(url);
|
||||
query.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
|
||||
url.setQuery(query);
|
||||
QUrlQuery query(url);
|
||||
query.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
|
||||
url.setQuery(query);
|
||||
#endif
|
||||
}
|
||||
request_.setUrl(url);
|
||||
|
||||
// If the service require the access token to be sent as a Authentication HTTP header,
|
||||
// we update the access token when retrying.
|
||||
if(!accessTokenInAuthenticationHTTPHeaderFormat_.isEmpty()) {
|
||||
request_.setRawHeader(O2_HTTP_AUTHORIZATION_HEADER, accessTokenInAuthenticationHTTPHeaderFormat_.arg(authenticator_->token()).toLatin1());
|
||||
}
|
||||
|
||||
status_ = ReRequesting;
|
||||
switch (operation_) {
|
||||
case QNetworkAccessManager::GetOperation:
|
||||
reply_ = manager_->get(request_);
|
||||
break;
|
||||
case QNetworkAccessManager::PostOperation:
|
||||
reply_ = manager_->post(request_, data_);
|
||||
reply_ = rawData_ ? manager_->post(request_, data_) : manager_->post(request_, multipartData_);
|
||||
break;
|
||||
case QNetworkAccessManager::CustomOperation:
|
||||
{
|
||||
QBuffer * buffer = new QBuffer;
|
||||
buffer->setData(data_);
|
||||
reply_ = manager_->sendCustomRequest(request_, request_.rawHeader(O2_HTTP_HTTP_HEADER), buffer);
|
||||
buffer->setParent(reply_);
|
||||
}
|
||||
break;
|
||||
case QNetworkAccessManager::PutOperation:
|
||||
reply_ = rawData_ ? manager_->post(request_, data_) : manager_->put(request_, multipartData_);
|
||||
break;
|
||||
case QNetworkAccessManager::HeadOperation:
|
||||
reply_ = manager_->head(request_);
|
||||
break;
|
||||
default:
|
||||
reply_ = manager_->put(request_, data_);
|
||||
assert(!"Unspecified operation for request");
|
||||
reply_ = manager_->get(request_);
|
||||
break;
|
||||
}
|
||||
timedReplies_.add(reply_);
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
|
||||
connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
|
||||
}
|
||||
|
55
external/o2/src/o2requestor.h
vendored
55
external/o2/src/o2requestor.h
vendored
@ -7,6 +7,7 @@
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QUrl>
|
||||
#include <QByteArray>
|
||||
#include <QHttpMultiPart>
|
||||
|
||||
#include "o0export.h"
|
||||
#include "o2reply.h"
|
||||
@ -20,24 +21,66 @@ class O0_EXPORT O2Requestor: public QObject {
|
||||
public:
|
||||
explicit O2Requestor(QNetworkAccessManager *manager, O2 *authenticator, QObject *parent = 0);
|
||||
~O2Requestor();
|
||||
|
||||
|
||||
/// 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 Q_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 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 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 put(const QNetworkRequest &req, const QByteArray &data, int timeout = 60*1000);
|
||||
int put(const QNetworkRequest &req, QHttpMultiPart* data, int timeout = 60*1000);
|
||||
|
||||
/// Make a DELETE request.
|
||||
/// @return Request ID or -1 if there are too many requests in the queue.
|
||||
int deleteResource(const QNetworkRequest &req, 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.
|
||||
/// @return Request ID or -1 if there are too many requests in the queue.
|
||||
int customRequest(const QNetworkRequest &req, const QByteArray &verb, const QByteArray &data, int timeout = 60*1000);
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
/// Emitted when a request has been completed or failed.
|
||||
void finished(int id, QNetworkReply::NetworkError error, QByteArray data);
|
||||
|
||||
/// Emitted when a request has been completed or failed.
|
||||
void finished(int id, QNetworkReply::NetworkError error, QString errorText, QByteArray data);
|
||||
|
||||
/// Emitted when a request has been completed or failed. Also reply headers will be provided.
|
||||
void finished(int id, QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers);
|
||||
|
||||
/// Emitted when a request has been completed or failed. Also reply headers will be provided.
|
||||
void finished(int id, QNetworkReply::NetworkError error, QString errorText, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers);
|
||||
|
||||
/// Emitted when an upload has progressed.
|
||||
void uploadProgress(int id, qint64 bytesSent, qint64 bytesTotal);
|
||||
|
||||
@ -61,7 +104,7 @@ protected Q_SLOTS:
|
||||
void onUploadProgress(qint64 uploaded, qint64 total);
|
||||
|
||||
protected:
|
||||
int setup(const QNetworkRequest &request, QNetworkAccessManager::Operation operation);
|
||||
int setup(const QNetworkRequest &request, QNetworkAccessManager::Operation operation, const QByteArray &verb = QByteArray());
|
||||
|
||||
enum Status {
|
||||
Idle, Requesting, ReRequesting
|
||||
@ -71,6 +114,7 @@ protected:
|
||||
O2 *authenticator_;
|
||||
QNetworkRequest request_;
|
||||
QByteArray data_;
|
||||
QHttpMultiPart* multipartData_;
|
||||
QNetworkReply *reply_;
|
||||
Status status_;
|
||||
int id_;
|
||||
@ -78,6 +122,9 @@ protected:
|
||||
QUrl url_;
|
||||
O2ReplyList timedReplies_;
|
||||
QNetworkReply::NetworkError error_;
|
||||
bool addAccessTokenInQuery_;
|
||||
QString accessTokenInAuthenticationHTTPHeaderFormat_;
|
||||
bool rawData_;
|
||||
};
|
||||
|
||||
#endif // O2REQUESTOR_H
|
||||
|
25
external/o2/src/o2simplecrypt.cpp
vendored
25
external/o2/src/o2simplecrypt.cpp
vendored
@ -32,7 +32,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <QCryptographicHash>
|
||||
#include <QDataStream>
|
||||
#include <QIODevice>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
O0SimpleCrypt::O0SimpleCrypt():
|
||||
m_key(0),
|
||||
@ -40,6 +39,11 @@ O0SimpleCrypt::O0SimpleCrypt():
|
||||
m_protectionMode(ProtectionChecksum),
|
||||
m_lastError(ErrorNoError)
|
||||
{
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
|
||||
qsrand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
|
||||
#else
|
||||
m_rand.seed(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
|
||||
#endif
|
||||
}
|
||||
|
||||
O0SimpleCrypt::O0SimpleCrypt(quint64 key):
|
||||
@ -48,6 +52,11 @@ O0SimpleCrypt::O0SimpleCrypt(quint64 key):
|
||||
m_protectionMode(ProtectionChecksum),
|
||||
m_lastError(ErrorNoError)
|
||||
{
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
|
||||
qsrand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
|
||||
#else
|
||||
m_rand.seed(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
|
||||
#endif
|
||||
splitKey();
|
||||
}
|
||||
|
||||
@ -103,7 +112,11 @@ QByteArray O0SimpleCrypt::encryptToByteArray(QByteArray plaintext)
|
||||
if (m_protectionMode == ProtectionChecksum) {
|
||||
flags |= CryptoFlagChecksum;
|
||||
QDataStream s(&integrityProtection, QIODevice::WriteOnly);
|
||||
#if QT_VERSION >= 0x060000
|
||||
s << qChecksum(QByteArrayView(ba));
|
||||
#else
|
||||
s << qChecksum(ba.constData(), ba.length());
|
||||
#endif
|
||||
} else if (m_protectionMode == ProtectionHash) {
|
||||
flags |= CryptoFlagHash;
|
||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||
@ -113,7 +126,11 @@ QByteArray O0SimpleCrypt::encryptToByteArray(QByteArray plaintext)
|
||||
}
|
||||
|
||||
//prepend a random char to the string
|
||||
char randomChar = char(QRandomGenerator::global()->generate() & 0xFF);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
|
||||
char randomChar = char(qrand() & 0xFF);
|
||||
#else
|
||||
char randomChar = char(m_rand.generate() & 0xFF);
|
||||
#endif
|
||||
ba = randomChar + integrityProtection + ba;
|
||||
|
||||
int pos(0);
|
||||
@ -227,7 +244,11 @@ QByteArray O0SimpleCrypt::decryptToByteArray(QByteArray cypher)
|
||||
s >> storedChecksum;
|
||||
}
|
||||
ba = ba.mid(2);
|
||||
#if QT_VERSION >= 0x060000
|
||||
quint16 checksum = qChecksum(QByteArrayView(ba));
|
||||
#else
|
||||
quint16 checksum = qChecksum(ba.constData(), ba.length());
|
||||
#endif
|
||||
integrityOk = (checksum == storedChecksum);
|
||||
} else if (flags.testFlag(CryptoFlagHash)) {
|
||||
if (ba.length() < 20) {
|
||||
|
4
external/o2/src/o2skydrive.cpp
vendored
4
external/o2/src/o2skydrive.cpp
vendored
@ -85,7 +85,11 @@ void O2Skydrive::redirected(const QUrl &url) {
|
||||
QNetworkReply *tokenReply = manager_->post(tokenRequest, data);
|
||||
timedReplies_.add(tokenReply);
|
||||
connect(tokenReply, SIGNAL(finished()), this, SLOT(onTokenReplyFinished()), Qt::QueuedConnection);
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(tokenReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(tokenReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
} else {
|
||||
// Get access token
|
||||
QString urlToken = "";
|
||||
|
1
external/o2/src/o2surveymonkey.cpp
vendored
1
external/o2/src/o2surveymonkey.cpp
vendored
@ -7,7 +7,6 @@
|
||||
#endif
|
||||
|
||||
#include "o2surveymonkey.h"
|
||||
#include "o2globals.h"
|
||||
|
||||
static const char *SMEndpoint = "https://api.surveymonkey.net/oauth/authorize";
|
||||
static const char *SMTokenUrl = "https://api.surveymonkey.net/oauth/token";
|
||||
|
102
external/o2/src/o2uber.cpp
vendored
Normal file
102
external/o2/src/o2uber.cpp
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QMap>
|
||||
#include <QNetworkReply>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QUrlQuery>
|
||||
#endif
|
||||
|
||||
#include "o2uber.h"
|
||||
#include "o0globals.h"
|
||||
|
||||
static const char *UberEndpoint = "https://login.uber.com/oauth/v2/authorize";
|
||||
static const char *UberTokenUrl = "https://login.uber.com/oauth/v2/token";
|
||||
static const char *UberExpiresIn = "expires_in";
|
||||
static const char *UberGrantType = "authorization_code";
|
||||
|
||||
O2Uber::O2Uber(QObject *parent): O2(parent)
|
||||
{
|
||||
setRequestUrl(UberEndpoint);
|
||||
setTokenUrl(UberTokenUrl);
|
||||
}
|
||||
|
||||
void O2Uber::onVerificationReceived(const QMap<QString, QString> response){
|
||||
|
||||
qDebug() << "O2Uber::onVerificationReceived: Emitting closeBrowser()";
|
||||
Q_EMIT closeBrowser();
|
||||
|
||||
if (response.contains("error")) {
|
||||
qWarning() << "O2Uber::onVerificationReceived: Verification failed";
|
||||
foreach (QString key, response.keys()) {
|
||||
qWarning() << "O2Uber::onVerificationReceived:" << key << response.value(key);
|
||||
}
|
||||
Q_EMIT linkingFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
// Save access code
|
||||
setCode(response.value(O2_OAUTH2_GRANT_TYPE_CODE));
|
||||
|
||||
// Exchange access code for access/refresh tokens
|
||||
QUrl url(tokenUrl_);
|
||||
#if QT_VERSION < 0x050000
|
||||
url.addQueryItem(O2_OAUTH2_CLIENT_ID, clientId_);
|
||||
url.addQueryItem(O2_OAUTH2_CLIENT_SECRET, clientSecret_);
|
||||
url.addQueryItem(O2_OAUTH2_GRANT_TYPE, UberGrantType);
|
||||
url.addQueryItem(O2_OAUTH2_REDIRECT_URI, redirectUri_);
|
||||
url.addQueryItem(O2_OAUTH2_GRANT_TYPE_CODE, code());
|
||||
url.addQueryItem(O2_OAUTH2_SCOPE, scope_);
|
||||
#else
|
||||
QUrlQuery query(url);
|
||||
query.addQueryItem(O2_OAUTH2_CLIENT_ID, clientId_);
|
||||
query.addQueryItem(O2_OAUTH2_CLIENT_SECRET, clientSecret_);
|
||||
query.addQueryItem(O2_OAUTH2_GRANT_TYPE, UberGrantType);
|
||||
query.addQueryItem(O2_OAUTH2_REDIRECT_URI, redirectUri_);
|
||||
query.addQueryItem(O2_OAUTH2_GRANT_TYPE_CODE, code());
|
||||
query.addQueryItem(O2_OAUTH2_SCOPE, scope_);
|
||||
url.setQuery(query);
|
||||
#endif
|
||||
|
||||
QNetworkRequest tokenRequest(url);
|
||||
tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
QNetworkReply *tokenReply = manager_->post(tokenRequest, QByteArray());
|
||||
timedReplies_.add(tokenReply);
|
||||
connect(tokenReply, SIGNAL(finished()), this, SLOT(onTokenReplyFinished()), Qt::QueuedConnection);
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(tokenReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#else
|
||||
connect(tokenReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
#endif
|
||||
}
|
||||
|
||||
void O2Uber::onTokenReplyFinished(){
|
||||
qDebug() << "O2Uber::onTokenReplyFinished";
|
||||
|
||||
QNetworkReply *tokenReply = qobject_cast<QNetworkReply *>(sender());
|
||||
if (tokenReply->error() == QNetworkReply::NoError) {
|
||||
// Process reply
|
||||
QByteArray replyData = tokenReply->readAll();
|
||||
QJsonDocument doc = QJsonDocument::fromJson(replyData);
|
||||
const QJsonObject rootObject = doc.object();
|
||||
|
||||
QVariantMap reply;
|
||||
for (const QString &key : rootObject.keys()) {
|
||||
reply.insert(key, rootObject[key].toVariant());
|
||||
}
|
||||
|
||||
// Interpret reply
|
||||
setToken(reply.value(O2_OAUTH2_ACCESS_TOKEN, QString()).toString());
|
||||
setExpires(reply.value(UberExpiresIn).toInt());
|
||||
setRefreshToken(reply.value(O2_OAUTH2_REFRESH_TOKEN, QString()).toString());
|
||||
setExtraTokens(reply);
|
||||
timedReplies_.remove(tokenReply);
|
||||
setLinked(true);
|
||||
Q_EMIT linkingSucceeded();
|
||||
} else {
|
||||
qWarning() << "O2Uber::onTokenReplyFinished:" << tokenReply->errorString();
|
||||
}
|
||||
}
|
20
external/o2/src/o2uber.h
vendored
Normal file
20
external/o2/src/o2uber.h
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef O2UBER_H
|
||||
#define O2UBER_H
|
||||
|
||||
#include "o0export.h"
|
||||
#include "o2.h"
|
||||
|
||||
class O0_EXPORT O2Uber: public O2{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
O2Uber(QObject *parent = 0);
|
||||
|
||||
public Q_SLOTS:
|
||||
void onVerificationReceived(QMap<QString, QString>);
|
||||
|
||||
protected Q_SLOTS:
|
||||
virtual void onTokenReplyFinished();
|
||||
};
|
||||
|
||||
#endif // O2UBER_H
|
13
external/o2/src/o2vimeo.cpp
vendored
Normal file
13
external/o2/src/o2vimeo.cpp
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
#include "o2vimeo.h"
|
||||
|
||||
// Vimeo supported scopes: https://developer.vimeo.com/api/authentication#supported-scopes
|
||||
static const char *VimeoScope = "public";
|
||||
static const char *VimeoEndpoint = "https://api.vimeo.com/oauth/authorize";
|
||||
static const char *VimeoTokenUrl = "https://api.vimeo.com/oauth/access_token";
|
||||
|
||||
O2Vimeo::O2Vimeo(QObject *parent): O2(parent) {
|
||||
setRequestUrl(VimeoEndpoint);
|
||||
setTokenUrl(VimeoTokenUrl);
|
||||
setRefreshTokenUrl(VimeoTokenUrl);
|
||||
setScope(VimeoScope);
|
||||
}
|
15
external/o2/src/o2vimeo.h
vendored
Normal file
15
external/o2/src/o2vimeo.h
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef O2VIMEO_H
|
||||
#define O2VIMEO_H
|
||||
|
||||
#include "o0export.h"
|
||||
#include "o2.h"
|
||||
|
||||
/// Vimeo dialect of OAuth 2.0
|
||||
class O0_EXPORT O2Vimeo : public O2 {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit O2Vimeo(QObject *parent = 0);
|
||||
};
|
||||
|
||||
#endif // O2VIMEO_H
|
10
external/o2/src/oxtwitter.cpp
vendored
10
external/o2/src/oxtwitter.cpp
vendored
@ -51,7 +51,11 @@ void OXTwitter::link() {
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_SIGNATURE_METHOD, O2_SIGNATURE_TYPE_HMAC_SHA1));
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_CONSUMER_KEY, clientId().toLatin1()));
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_VERSION, "1.0"));
|
||||
#if QT_VERSION >= 0x050800
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_TIMESTAMP, QString::number(QDateTime::currentSecsSinceEpoch()).toLatin1()));
|
||||
#else
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_TIMESTAMP, QString::number(QDateTime::currentDateTimeUtc().toTime_t()).toLatin1()));
|
||||
#endif
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_NONCE, nonce()));
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_TOKEN, QByteArray("")));
|
||||
oauthParams.append(O0RequestParameter(O2_OAUTH_VERFIER, QByteArray("")));
|
||||
@ -61,9 +65,13 @@ void OXTwitter::link() {
|
||||
|
||||
// Post request
|
||||
QNetworkRequest request(accessTokenUrl());
|
||||
request.setRawHeader(O2_HTTP_AUTHORIZATION_HEADER, buildAuthorizationHeader(oauthParams));
|
||||
decorateRequest(request, oauthParams);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, O2_MIME_TYPE_XFORM);
|
||||
QNetworkReply *reply = manager_->post(request, createQueryParameters(xAuthParams_));
|
||||
#if QT_VERSION < 0x051500
|
||||
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenExchangeError(QNetworkReply::NetworkError)));
|
||||
#else
|
||||
connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onTokenExchangeError(QNetworkReply::NetworkError)));
|
||||
#endif
|
||||
connect(reply, SIGNAL(finished()), this, SLOT(onTokenExchangeFinished()));
|
||||
}
|
||||
|
59
external/o2/src/src.pri
vendored
59
external/o2/src/src.pri
vendored
@ -1,17 +1,19 @@
|
||||
QT *= network
|
||||
|
||||
# script module is deprecated since Qt 5.5 (http://wiki.qt.io/New-Features-in-Qt-5.5)
|
||||
!qtHaveModule(qml): QT *= script
|
||||
qtHaveModule(qml): QT *= qml
|
||||
lessThan(QT_MAJOR_VERSION, 5): QT *= script
|
||||
|
||||
INCLUDEPATH += $$PWD
|
||||
SOURCES += \
|
||||
$$PWD/o0jsonresponse.cpp \
|
||||
$$PWD/o1.cpp \
|
||||
$$PWD/o1requestor.cpp \
|
||||
$$PWD/o1smugmug.cpp \
|
||||
$$PWD/o1timedreply.cpp \
|
||||
$$PWD/o2.cpp \
|
||||
$$PWD/o2facebook.cpp \
|
||||
$$PWD/o2gft.cpp \
|
||||
$$PWD/o2outlook.cpp \
|
||||
$$PWD/o2pollserver.cpp \
|
||||
$$PWD/o2reply.cpp \
|
||||
$$PWD/o2replyserver.cpp \
|
||||
$$PWD/o2requestor.cpp \
|
||||
@ -20,18 +22,28 @@ SOURCES += \
|
||||
$$PWD/o2simplecrypt.cpp \
|
||||
$$PWD/o0baseauth.cpp \
|
||||
$$PWD/o0settingsstore.cpp \
|
||||
$$PWD/o2spotify.cpp
|
||||
$$PWD/o2spotify.cpp \
|
||||
$$PWD/o2google.cpp \
|
||||
$$PWD/o2googledevice.cpp \
|
||||
$$PWD/o2uber.cpp \
|
||||
$$PWD/o2msgraph.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/o0export.h \
|
||||
$$PWD/o0jsonresponse.h \
|
||||
$$PWD/o1.h \
|
||||
$$PWD/o1dropbox.h \
|
||||
$$PWD/o1flickr.h \
|
||||
$$PWD/o1requestor.h \
|
||||
$$PWD/o1smugmug.h \
|
||||
$$PWD/o1twitter.h \
|
||||
$$PWD/o1timedreply.h \
|
||||
$$PWD/o1upwork.h \
|
||||
$$PWD/o2.h \
|
||||
$$PWD/o2facebook.h \
|
||||
$$PWD/o2gft.h \
|
||||
$$PWD/o2outlook.h \
|
||||
$$PWD/o2pollserver.h \
|
||||
$$PWD/o2reply.h \
|
||||
$$PWD/o2replyserver.h \
|
||||
$$PWD/o2requestor.h \
|
||||
@ -44,4 +56,41 @@ HEADERS += \
|
||||
$$PWD/o0requestparameter.h \
|
||||
$$PWD/o0abstractstore.h \
|
||||
$$PWD/o0settingsstore.h \
|
||||
$$PWD/o2spotify.h
|
||||
$$PWD/o2spotify.h \
|
||||
$$PWD/o2google.h \
|
||||
$$PWD/o2googledevice.h \
|
||||
$$PWD/o2uber.h \
|
||||
$$PWD/o2msgraph.h
|
||||
|
||||
headers.files += \
|
||||
$$PWD/o0jsonresponse.h \
|
||||
$$PWD/o1.h \
|
||||
$$PWD/o1dropbox.h \
|
||||
$$PWD/o1flickr.h \
|
||||
$$PWD/o1requestor.h \
|
||||
$$PWD/o1smugmug.h \
|
||||
$$PWD/o1twitter.h \
|
||||
$$PWD/o1timedreply.h \
|
||||
$$PWD/o1upwork.h \
|
||||
$$PWD/o2.h \
|
||||
$$PWD/o2facebook.h \
|
||||
$$PWD/o2gft.h \
|
||||
$$PWD/o2pollserver.h \
|
||||
$$PWD/o2reply.h \
|
||||
$$PWD/o2replyserver.h \
|
||||
$$PWD/o2requestor.h \
|
||||
$$PWD/o2skydrive.h \
|
||||
$$PWD/oxtwitter.h \
|
||||
$$PWD/o1freshbooks.h \
|
||||
$$PWD/o0baseauth.h \
|
||||
$$PWD/o0globals.h \
|
||||
$$PWD/o0simplecrypt.h \
|
||||
$$PWD/o0requestparameter.h \
|
||||
$$PWD/o0abstractstore.h \
|
||||
$$PWD/o0settingsstore.h \
|
||||
$$PWD/o2spotify.h \
|
||||
$$PWD/o2google.h \
|
||||
$$PWD/o2googledevice.h \
|
||||
$$PWD/o2uber.h \
|
||||
$$PWD/o2msgraph.h \
|
||||
$$PWD/o2outlook.h
|
||||
|
@ -18,9 +18,11 @@ endif()
|
||||
if(WITH_INTERNAL_O2)
|
||||
set(O2_SRCS
|
||||
${O2_SOURCE_DIR}/o0baseauth.cpp
|
||||
${O2_SOURCE_DIR}/o0jsonresponse.cpp
|
||||
${O2_SOURCE_DIR}/o0keychainstore.cpp
|
||||
${O2_SOURCE_DIR}/o0settingsstore.cpp
|
||||
${O2_SOURCE_DIR}/o2.cpp
|
||||
${O2_SOURCE_DIR}/o2pollserver.cpp
|
||||
${O2_SOURCE_DIR}/o2reply.cpp
|
||||
${O2_SOURCE_DIR}/o2replyserver.cpp
|
||||
${O2_SOURCE_DIR}/o2requestor.cpp
|
||||
@ -28,10 +30,12 @@ if(WITH_INTERNAL_O2)
|
||||
)
|
||||
set(O2_HDRS
|
||||
${O2_INCLUDE_DIR}/o0abstractstore.h
|
||||
${O2_INCLUDE_DIR}/o0jsonresponse.h
|
||||
${O2_INCLUDE_DIR}/o0baseauth.h
|
||||
${O2_INCLUDE_DIR}/o0export.h
|
||||
${O2_INCLUDE_DIR}/o0globals.h
|
||||
${O2_INCLUDE_DIR}/o0keychainstore.h
|
||||
${O2_INCLUDE_DIR}/o2pollserver.h
|
||||
${O2_INCLUDE_DIR}/o0requestparameter.h
|
||||
${O2_INCLUDE_DIR}/o0settingsstore.h
|
||||
${O2_INCLUDE_DIR}/o0simplecrypt.h
|
||||
|
Loading…
x
Reference in New Issue
Block a user