mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-13 17:43:59 +02:00
Pull a bunch of code out of HatchetAccount and into HatchetHelpers; make some things more modular; prepare for the Kiva/Dreamcatcher split
This commit is contained in:
@@ -37,11 +37,13 @@ tomahawk_add_plugin(hatchet
|
||||
TYPE account
|
||||
EXPORT_MACRO ACCOUNTDLLEXPORT_PRO
|
||||
SOURCES
|
||||
HatchetHelpers.cpp
|
||||
account/HatchetAccount.cpp
|
||||
account/HatchetAccountConfig.cpp
|
||||
sip/WebSocket.cpp
|
||||
sip/WebSocketThreadController.cpp
|
||||
sip/HatchetSip.cpp
|
||||
#sip/HatchetCredentialFetcher.cpp
|
||||
UI
|
||||
account/HatchetAccountConfig.ui
|
||||
LINK_LIBRARIES
|
||||
|
233
src/accounts/hatchet/HatchetHelpers.cpp
Normal file
233
src/accounts/hatchet/HatchetHelpers.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2014, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "HatchetHelpers.h"
|
||||
|
||||
#include "utils/Closure.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/NetworkAccessManager.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
|
||||
#include <qjson/parser.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QNetworkReply>
|
||||
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
namespace Accounts
|
||||
{
|
||||
namespace Hatchet
|
||||
{
|
||||
namespace HatchetHelpers
|
||||
{
|
||||
|
||||
|
||||
QVariantMap
|
||||
parseReply( QNetworkReply* reply, bool& okRet )
|
||||
{
|
||||
QVariantMap resp;
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
bool ok;
|
||||
int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt( &ok );
|
||||
if ( reply->error() != QNetworkReply::NoError && statusCode < 400 )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Network error in command:" << reply->error() << reply->errorString();
|
||||
okRet = false;
|
||||
return resp;
|
||||
}
|
||||
|
||||
QJson::Parser p;
|
||||
QByteArray replyData = reply->readAll();
|
||||
resp = p.parse( replyData, &ok ).toMap();
|
||||
|
||||
if ( !ok )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error parsing JSON from server" << replyData;
|
||||
okRet = false;
|
||||
return resp;
|
||||
}
|
||||
|
||||
if ( statusCode >= 400 )
|
||||
{
|
||||
tDebug() << "Error from tomahawk server response, or in parsing from json:" << resp.value( "error" ).toString() << resp;
|
||||
}
|
||||
|
||||
tDebug() << Q_FUNC_INFO << "Got keys" << resp.keys();
|
||||
tDebug() << Q_FUNC_INFO << "Got values" << resp.values();
|
||||
okRet = true;
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
HatchetCredentialFetcher::HatchetCredentialFetcher( QObject* parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HatchetCredentialFetcher::~HatchetCredentialFetcher()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HatchetCredentialFetcher::fetchAccessToken( const QString& type, const MandellaInformation& mandellaInformation )
|
||||
{
|
||||
if ( mandellaInformation.bearerToken.isEmpty() ||
|
||||
(mandellaInformation.bearerTokenExpiration < QDateTime::currentDateTime().toTime_t() &&
|
||||
(mandellaInformation.refreshToken.isEmpty() ||
|
||||
(mandellaInformation.refreshTokenExpiration != 0 && mandellaInformation.refreshTokenExpiration < QDateTime::currentDateTime().toTime_t()))) )
|
||||
{
|
||||
tLog() << "No valid combination of access/refresh tokens, not logging in";
|
||||
tLog() << "Mandella access token expiration:" << mandellaInformation.bearerTokenExpiration << ", refresh token expiration:" << mandellaInformation.refreshTokenExpiration;
|
||||
emit authError( "No valid credentials are stored locally, please log in again.", 401, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
|
||||
bool interceptionNeeded = mandellaInformation.bearerTokenExpiration < QDateTime::currentDateTime().toTime_t();
|
||||
|
||||
QNetworkRequest req( QUrl( "https://auth.hatchet.is/v1/tokens/" + (interceptionNeeded ? "refresh/" + QString::fromUtf8(mandellaInformation.bearerTokenType).toLower() : "fetch/" + type) ) );
|
||||
QNetworkReply* reply;
|
||||
|
||||
if ( interceptionNeeded )
|
||||
{
|
||||
tLog() << "Intercepting; new mandella access token needed";
|
||||
req.setHeader( QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded" );
|
||||
QUrl params;
|
||||
TomahawkUtils::urlAddQueryItem( params, "grant_type", "refresh_token" );
|
||||
TomahawkUtils::urlAddQueryItem( params, "refresh_token", mandellaInformation.refreshToken );
|
||||
QByteArray data = TomahawkUtils::encodedQuery( params );
|
||||
reply = Tomahawk::Utils::nam()->post( req, data );
|
||||
reply->setProperty( "originalType", type );
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog() << "Fetching token of type" << type;
|
||||
req.setRawHeader( "Authorization", QString( mandellaInformation.bearerTokenType + " " + mandellaInformation.bearerToken).toUtf8() );
|
||||
reply = Tomahawk::Utils::nam()->get( req );
|
||||
}
|
||||
|
||||
NewClosure( reply, SIGNAL( finished() ), this, SLOT( onFetchAccessTokenFinished( QNetworkReply*, const QString& ) ), reply, type );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HatchetCredentialFetcher::onFetchAccessTokenFinished( QNetworkReply* reply, const QString& type )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
Q_ASSERT( reply );
|
||||
|
||||
QString originalType;
|
||||
if ( reply->property( "originalType" ).isValid() )
|
||||
{
|
||||
originalType = reply->property( "originalType" ).toString();
|
||||
}
|
||||
|
||||
bool ok;
|
||||
int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt( &ok );
|
||||
if ( !ok )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error finding status code from auth server";
|
||||
emit authError( "An error occurred getting the status code from the server", 0, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
const QVariantMap resp = parseReply( reply, ok );
|
||||
if ( !ok )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error getting parsed reply from auth server";
|
||||
emit authError( "An error occurred reading the reply from the authentication server", statusCode, resp );
|
||||
return;
|
||||
}
|
||||
if ( statusCode >= 500 )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Encountered internal error from auth server, cannot continue";
|
||||
emit authError( "The authentication server reported an internal error, please try again later", statusCode, resp );
|
||||
return;
|
||||
}
|
||||
if ( statusCode >= 400 )
|
||||
{
|
||||
QString errString = resp.value( "error_description" ).toString();
|
||||
tLog() << Q_FUNC_INFO << "An error was returned from the authentication server: " << errString;
|
||||
emit authError( errString, statusCode, resp );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !originalType.isEmpty() )
|
||||
{
|
||||
const QByteArray bearerTokenBytes = resp.value( "access_token" ).toByteArray();
|
||||
uint bearerTokenExpiration = resp.value( "expires_in" ).toUInt( &ok );
|
||||
if ( bearerTokenBytes.isEmpty() || !ok )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error reading access token or its expiration";
|
||||
emit authError( "An error encountered parsing the authentication server's response", 0, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
const QByteArray bearerTokenTypeBytes = resp.value( "token_type" ).toByteArray();
|
||||
if ( bearerTokenTypeBytes.isEmpty() )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error reading access token type";
|
||||
emit authError( "An error encountered parsing the authentication server's response", 0, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
|
||||
MandellaInformation newMandellaInformation;
|
||||
newMandellaInformation.bearerTokenType = bearerTokenTypeBytes;
|
||||
newMandellaInformation.bearerToken = bearerTokenBytes;
|
||||
newMandellaInformation.bearerTokenExpiration = QDateTime::currentDateTime().toTime_t() + bearerTokenExpiration;
|
||||
emit mandellaInformationUpdated( newMandellaInformation );
|
||||
|
||||
fetchAccessToken( originalType, newMandellaInformation );
|
||||
return;
|
||||
}
|
||||
|
||||
const QByteArray accessTokenBytes = resp.value( "access_token" ).toByteArray();
|
||||
uint accessTokenExpiration = resp.value( "expires_in" ).toUInt( &ok );
|
||||
if ( accessTokenBytes.isEmpty() || !ok )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error reading access token or its expiration";
|
||||
emit authError( "An error encountered parsing the authentication server's response", 0, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
const QByteArray tokenTypeBytes = resp.value( "token_type" ).toByteArray();
|
||||
if ( tokenTypeBytes.isEmpty() )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error reading access token type";
|
||||
emit authError( "An error encountered parsing the authentication server's response", 0, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
|
||||
tLog() << Q_FUNC_INFO << "Access tokens fetched successfully";
|
||||
|
||||
AccessTokenInformation accessTokenInformation;
|
||||
accessTokenInformation.type = tokenTypeBytes;
|
||||
accessTokenInformation.token = accessTokenBytes;
|
||||
accessTokenInformation.expiration = accessTokenExpiration;
|
||||
|
||||
emit accessTokenFetched( accessTokenInformation );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
80
src/accounts/hatchet/HatchetHelpers.h
Normal file
80
src/accounts/hatchet/HatchetHelpers.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2014, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HATCHET_HELPERS_H
|
||||
#define HATCHET_HELPERS_H
|
||||
|
||||
#include <QVariantMap>
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
namespace Accounts
|
||||
{
|
||||
namespace Hatchet
|
||||
{
|
||||
namespace HatchetHelpers
|
||||
{
|
||||
|
||||
|
||||
QVariantMap parseReply( QNetworkReply* reply, bool& ok );
|
||||
|
||||
|
||||
struct MandellaInformation {
|
||||
QByteArray bearerTokenType;
|
||||
QByteArray bearerToken;
|
||||
uint bearerTokenExpiration;
|
||||
QByteArray refreshToken;
|
||||
uint refreshTokenExpiration;
|
||||
};
|
||||
|
||||
struct AccessTokenInformation {
|
||||
QByteArray type;
|
||||
QByteArray token;
|
||||
uint expiration;
|
||||
};
|
||||
|
||||
|
||||
class HatchetCredentialFetcher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HatchetCredentialFetcher( QObject* parent );
|
||||
virtual ~HatchetCredentialFetcher();
|
||||
|
||||
signals:
|
||||
void accessTokenFetched( const HatchetHelpers::AccessTokenInformation& accessInfo );
|
||||
void mandellaInformationUpdated( const HatchetHelpers::MandellaInformation& updatedInfo );
|
||||
void authError( const QString& error, int statusCode, const QVariantMap& resp );
|
||||
|
||||
public slots:
|
||||
void fetchAccessToken( const QString& type, const HatchetHelpers::MandellaInformation& mandellaInformation );
|
||||
|
||||
private slots:
|
||||
void onFetchAccessTokenFinished( QNetworkReply*, const QString& type );
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -17,8 +17,8 @@
|
||||
*/
|
||||
|
||||
#include "HatchetAccount.h"
|
||||
#include <QHostInfo>
|
||||
|
||||
#include "HatchetHelpers.h"
|
||||
#include "HatchetAccountConfig.h"
|
||||
#include "sip/HatchetSip.h"
|
||||
#include "utils/Closure.h"
|
||||
@@ -27,16 +27,24 @@
|
||||
#include "utils/Json.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
|
||||
#include <QtPlugin>
|
||||
#include <QHostInfo>
|
||||
#include <QFile>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QUrl>
|
||||
#include <QUuid>
|
||||
#include <QtPlugin>
|
||||
|
||||
using namespace Tomahawk;
|
||||
using namespace Accounts;
|
||||
#include <qjson/parser.h>
|
||||
#include <qjson/serializer.h>
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
namespace Accounts
|
||||
{
|
||||
namespace Hatchet
|
||||
{
|
||||
|
||||
static QPixmap* s_icon = 0;
|
||||
HatchetAccount* HatchetAccount::s_instance = 0;
|
||||
@@ -53,7 +61,6 @@ HatchetAccountFactory::HatchetAccountFactory()
|
||||
|
||||
HatchetAccountFactory::~HatchetAccountFactory()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -223,14 +230,14 @@ HatchetAccount::refreshTokenExpiration() const
|
||||
|
||||
|
||||
QByteArray
|
||||
HatchetAccount::mandellaAccessToken() const
|
||||
HatchetAccount::bearerToken() const
|
||||
{
|
||||
return credentials().value( "mandella_access_token" ).toByteArray();
|
||||
}
|
||||
|
||||
|
||||
uint
|
||||
HatchetAccount::mandellaAccessTokenExpiration() const
|
||||
HatchetAccount::bearerTokenExpiration() const
|
||||
{
|
||||
bool ok;
|
||||
return credentials().value( "mandella_access_token_expiration" ).toUInt( &ok );
|
||||
@@ -238,7 +245,7 @@ HatchetAccount::mandellaAccessTokenExpiration() const
|
||||
|
||||
|
||||
QByteArray
|
||||
HatchetAccount::mandellaTokenType() const
|
||||
HatchetAccount::bearerTokenType() const
|
||||
{
|
||||
return credentials().value( "mandella_token_type" ).toByteArray();
|
||||
}
|
||||
@@ -279,68 +286,14 @@ HatchetAccount::loginWithPassword( const QString& username, const QString& passw
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HatchetAccount::fetchAccessToken( const QString& type )
|
||||
{
|
||||
if ( username().isEmpty() )
|
||||
{
|
||||
tLog() << "No username, not logging in";
|
||||
return;
|
||||
}
|
||||
if ( mandellaAccessToken().isEmpty() ||
|
||||
(mandellaAccessTokenExpiration() < QDateTime::currentDateTime().toTime_t() &&
|
||||
(refreshToken().isEmpty() ||
|
||||
(refreshTokenExpiration() != 0 && refreshTokenExpiration() < QDateTime::currentDateTime().toTime_t()))) )
|
||||
{
|
||||
tLog() << "No valid combination of access/refresh tokens, not logging in";
|
||||
tLog() << "Mandella access token expiration:" << mandellaAccessTokenExpiration() << ", refresh token expiration:" << refreshTokenExpiration();
|
||||
emit authError( "No valid credentials are stored locally, please log in again.", 401, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
|
||||
uint matExpiration = mandellaAccessTokenExpiration();
|
||||
bool interceptionNeeded = false;
|
||||
|
||||
if ( matExpiration < QDateTime::currentDateTime().toTime_t() )
|
||||
{
|
||||
interceptionNeeded = true;
|
||||
tLog() << "Mandella access token has expired, fetching new ones first";
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog() << "Fetching access tokens of type" << type;
|
||||
}
|
||||
|
||||
QNetworkRequest req( QUrl( c_accessTokenServer + "/tokens/" + (interceptionNeeded ? "refresh/" + QString::fromUtf8(mandellaTokenType()).toLower() : "fetch/" + type) ) );
|
||||
QNetworkReply* reply;
|
||||
|
||||
if ( interceptionNeeded )
|
||||
{
|
||||
tLog() << "Intercepting; new mandella access token needed";
|
||||
req.setHeader( QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded" );
|
||||
QUrl params;
|
||||
TomahawkUtils::urlAddQueryItem( params, "grant_type", "refresh_token" );
|
||||
TomahawkUtils::urlAddQueryItem( params, "refresh_token", refreshToken() );
|
||||
QByteArray data = TomahawkUtils::encodedQuery( params );
|
||||
reply = Tomahawk::Utils::nam()->post( req, data );
|
||||
reply->setProperty( "originalType", type );
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog() << "Fetching token of type" << type;
|
||||
req.setRawHeader( "Authorization", QString( mandellaTokenType() + " " + mandellaAccessToken()).toUtf8() );
|
||||
reply = Tomahawk::Utils::nam()->get( req );
|
||||
}
|
||||
|
||||
NewClosure( reply, SIGNAL( finished() ), this, SLOT( onFetchAccessTokenFinished( QNetworkReply*, const QString& ) ), reply, type );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HatchetAccount::onPasswordLoginFinished( QNetworkReply* reply, const QString& username )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
Q_ASSERT( reply );
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
bool ok;
|
||||
int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt( &ok );
|
||||
if ( !ok )
|
||||
@@ -349,7 +302,7 @@ HatchetAccount::onPasswordLoginFinished( QNetworkReply* reply, const QString& us
|
||||
emit authError( "An error occurred getting the status code from the server", 0, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
const QVariantMap resp = parseReply( reply, ok );
|
||||
const QVariantMap resp = HatchetHelpers::parseReply( reply, ok );
|
||||
if ( !ok )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error getting parsed reply from auth server";
|
||||
@@ -420,139 +373,64 @@ HatchetAccount::onPasswordLoginFinished( QNetworkReply* reply, const QString& us
|
||||
|
||||
|
||||
void
|
||||
HatchetAccount::onFetchAccessTokenFinished( QNetworkReply* reply, const QString& type )
|
||||
HatchetAccount::fetchAccessToken( const QString& type )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
Q_ASSERT( reply );
|
||||
QVariantHash creds = credentials();
|
||||
HatchetHelpers::MandellaInformation mandellaInfo;
|
||||
mandellaInfo.bearerToken = bearerToken();
|
||||
mandellaInfo.bearerTokenExpiration = bearerTokenExpiration();
|
||||
mandellaInfo.bearerTokenType = bearerTokenType();
|
||||
mandellaInfo.refreshToken = refreshToken();
|
||||
mandellaInfo.refreshTokenExpiration = refreshTokenExpiration();
|
||||
|
||||
QString originalType;
|
||||
if ( reply->property( "originalType" ).isValid() )
|
||||
{
|
||||
originalType = reply->property( "originalType" ).toString();
|
||||
}
|
||||
HatchetHelpers::HatchetCredentialFetcher* fetcher = new HatchetHelpers::HatchetCredentialFetcher( this );
|
||||
connect( fetcher,
|
||||
SIGNAL( mandellaInformationUpdated( const HatchetHelpers::MandellaInformation& ) ),
|
||||
SLOT( onFetcherMandellaInformationUpdated( const HatchetHelpers::MandellaInformation& ) ) );
|
||||
connect( fetcher,
|
||||
SIGNAL( authError( const QString&, int, const QVariantMap& ) ),
|
||||
SLOT( onFetcherAuthError( const QString&, int, const QVariantMap& ) ) );
|
||||
connect( fetcher,
|
||||
SIGNAL( accessTokenFetched( const HatchetHelpers::AccessTokenInformation& ) ),
|
||||
SLOT( onFetcherAccessTokenFetched( const HatchetHelpers::AccessTokenInformation& ) ) );
|
||||
|
||||
bool ok;
|
||||
int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt( &ok );
|
||||
if ( !ok )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error finding status code from auth server";
|
||||
emit authError( "An error occurred getting the status code from the server", 0, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
const QVariantMap resp = parseReply( reply, ok );
|
||||
if ( !ok )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error getting parsed reply from auth server";
|
||||
emit authError( "An error occurred reading the reply from the authentication server", statusCode, resp );
|
||||
return;
|
||||
}
|
||||
if ( statusCode >= 500 )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Encountered internal error from auth server, cannot continue";
|
||||
emit authError( "The authentication server reported an internal error, please try again later", statusCode, resp );
|
||||
return;
|
||||
}
|
||||
if ( statusCode >= 400 )
|
||||
{
|
||||
QString errString = resp.value( "error_description" ).toString();
|
||||
tLog() << Q_FUNC_INFO << "An error was returned from the authentication server: " << errString;
|
||||
emit authError( errString, statusCode, resp );
|
||||
return;
|
||||
}
|
||||
fetcher->fetchAccessToken( type, mandellaInfo );
|
||||
}
|
||||
|
||||
QVariantMap creds = credentials();
|
||||
|
||||
if ( !originalType.isEmpty() )
|
||||
{
|
||||
const QByteArray accessTokenBytes = resp.value( "access_token" ).toByteArray();
|
||||
uint accessTokenExpiration = resp.value( "expires_in" ).toUInt( &ok );
|
||||
if ( accessTokenBytes.isEmpty() || !ok )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error reading access token or its expiration";
|
||||
emit authError( "An error encountered parsing the authentication server's response", 0, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
const QByteArray tokenTypeBytes = resp.value( "token_type" ).toByteArray();
|
||||
if ( tokenTypeBytes.isEmpty() )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error reading access token type";
|
||||
emit authError( "An error encountered parsing the authentication server's response", 0, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
creds[ "mandella_access_token" ] = accessTokenBytes;
|
||||
creds[ "mandella_access_token_expiration" ] = QDateTime::currentDateTime().toTime_t() + accessTokenExpiration;
|
||||
creds[ "mandella_token_type" ] = tokenTypeBytes;
|
||||
setCredentials( creds );
|
||||
syncConfig();
|
||||
|
||||
fetchAccessToken( originalType );
|
||||
return;
|
||||
}
|
||||
|
||||
const QByteArray accessTokenBytes = resp.value( "access_token" ).toByteArray();
|
||||
uint accessTokenExpiration = resp.value( "expires_in" ).toUInt( &ok );
|
||||
if ( accessTokenBytes.isEmpty() || !ok )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error reading access token or its expiration";
|
||||
emit authError( "An error encountered parsing the authentication server's response", 0, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
const QByteArray tokenTypeBytes = resp.value( "token_type" ).toByteArray();
|
||||
if ( tokenTypeBytes.isEmpty() )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error reading access token type";
|
||||
emit authError( "An error encountered parsing the authentication server's response", 0, QVariantMap() );
|
||||
return;
|
||||
}
|
||||
|
||||
creds[ type + "_access_token" ] = accessTokenBytes;
|
||||
|
||||
tDebug() << Q_FUNC_INFO << "Creds: " << creds;
|
||||
|
||||
void
|
||||
HatchetAccount::onFetcherMandellaInformationUpdated( const HatchetHelpers::MandellaInformation& mandellaInformation )
|
||||
{
|
||||
QVariantHash creds = credentials();
|
||||
creds[ "mandella_access_token" ] = mandellaInformation.bearerToken;
|
||||
creds[ "mandella_access_token_expiration" ] = QDateTime::currentDateTime().toTime_t() + mandellaInformation.bearerTokenExpiration;
|
||||
creds[ "mandella_token_type" ] = mandellaInformation.bearerTokenType;
|
||||
setCredentials( creds );
|
||||
syncConfig();
|
||||
|
||||
tLog() << Q_FUNC_INFO << "Access tokens fetched successfully";
|
||||
|
||||
emit accessTokenFetched();
|
||||
}
|
||||
|
||||
|
||||
QVariantMap
|
||||
HatchetAccount::parseReply( QNetworkReply* reply, bool& okRet ) const
|
||||
void
|
||||
HatchetAccount::onFetcherAuthError( const QString& error, int code, const QVariantMap& resp )
|
||||
{
|
||||
QVariantMap resp;
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
bool ok;
|
||||
int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt( &ok );
|
||||
if ( reply->error() != QNetworkReply::NoError && statusCode < 400 )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Network error in command:" << reply->error() << reply->errorString();
|
||||
okRet = false;
|
||||
return resp;
|
||||
}
|
||||
|
||||
QByteArray replyData = reply->readAll();
|
||||
resp = TomahawkUtils::parseJson( replyData, &ok ).toMap();
|
||||
|
||||
if ( !ok )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Error parsing JSON from server" << replyData;
|
||||
okRet = false;
|
||||
return resp;
|
||||
}
|
||||
|
||||
if ( statusCode >= 400 )
|
||||
{
|
||||
tDebug() << "Error from tomahawk server response, or in parsing from json:" << resp.value( "error" ).toString() << resp;
|
||||
}
|
||||
|
||||
tDebug() << Q_FUNC_INFO << "Got keys" << resp.keys();
|
||||
tDebug() << Q_FUNC_INFO << "Got values" << resp.values();
|
||||
okRet = true;
|
||||
return resp;
|
||||
if ( sender() )
|
||||
sender()->deleteLater();
|
||||
emit authError( error, code, resp );
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN2( Tomahawk::Accounts::AccountFactory, Tomahawk::Accounts::HatchetAccountFactory )
|
||||
|
||||
void
|
||||
HatchetAccount::onFetcherAccessTokenFetched( const HatchetHelpers::AccessTokenInformation& accessTokenInfo )
|
||||
{
|
||||
if ( sender() )
|
||||
sender()->deleteLater();
|
||||
emit accessTokenFetched( accessTokenInfo );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Q_EXPORT_PLUGIN2( Tomahawk::Accounts::AccountFactory, Tomahawk::Accounts::Hatchet::HatchetAccountFactory )
|
||||
|
@@ -20,6 +20,8 @@
|
||||
#define HATCHET_ACCOUNT_H
|
||||
|
||||
#include "TomahawkPlugin.h"
|
||||
#include "HatchetHelpers.h"
|
||||
|
||||
#include <accounts/Account.h>
|
||||
#include <accounts/AccountDllMacro.h>
|
||||
|
||||
@@ -27,14 +29,15 @@
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
class HatchetSipPlugin;
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
namespace Accounts
|
||||
{
|
||||
namespace Hatchet
|
||||
{
|
||||
|
||||
class HatchetAccountConfig;
|
||||
class HatchetSipPlugin;
|
||||
|
||||
class ACCOUNTDLLEXPORT HatchetAccountFactory : public AccountFactory
|
||||
{
|
||||
@@ -87,30 +90,31 @@ public:
|
||||
|
||||
QString username() const;
|
||||
|
||||
void fetchAccessToken( const QString& type = "dreamcatcher" );
|
||||
|
||||
signals:
|
||||
void authError( QString error, int statusCode, const QVariantMap );
|
||||
void authError( const QString&, int, const QVariantMap&);
|
||||
void deauthenticated();
|
||||
void accessTokenFetched();
|
||||
void accessTokenFetched( const HatchetHelpers::AccessTokenInformation& );
|
||||
|
||||
public slots:
|
||||
void fetchAccessToken( const QString& type );
|
||||
|
||||
private slots:
|
||||
void onPasswordLoginFinished( QNetworkReply*, const QString& username );
|
||||
void onFetchAccessTokenFinished( QNetworkReply*, const QString& type );
|
||||
void onPasswordLoginFinished( QNetworkReply*, const QString& );
|
||||
void onFetcherMandellaInformationUpdated( const HatchetHelpers::MandellaInformation& );
|
||||
void onFetcherAccessTokenFetched( const HatchetHelpers::AccessTokenInformation& );
|
||||
void onFetcherAuthError( const QString&, int, const QVariantMap& );
|
||||
|
||||
private:
|
||||
QByteArray refreshToken() const;
|
||||
uint refreshTokenExpiration() const;
|
||||
|
||||
QByteArray mandellaAccessToken() const;
|
||||
uint mandellaAccessTokenExpiration() const;
|
||||
QByteArray bearerToken() const;
|
||||
uint bearerTokenExpiration() const;
|
||||
|
||||
QByteArray mandellaTokenType() const;
|
||||
QByteArray bearerTokenType() const;
|
||||
|
||||
void loginWithPassword( const QString& username, const QString& password, const QString &otp );
|
||||
|
||||
QVariantMap parseReply( QNetworkReply* reply, bool& ok ) const;
|
||||
|
||||
QPointer<HatchetAccountConfig> m_configWidget;
|
||||
|
||||
Account::ConnectionState m_state;
|
||||
@@ -126,6 +130,7 @@ private:
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
using namespace Tomahawk;
|
||||
using namespace Accounts;
|
||||
using namespace Hatchet;
|
||||
|
||||
namespace {
|
||||
enum ButtonAction {
|
||||
|
@@ -32,6 +32,7 @@ namespace Ui {
|
||||
|
||||
namespace Tomahawk {
|
||||
namespace Accounts {
|
||||
namespace Hatchet {
|
||||
|
||||
class HatchetAccount;
|
||||
|
||||
@@ -63,6 +64,7 @@ private:
|
||||
HatchetAccount* m_account;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -37,6 +37,14 @@
|
||||
#include <QHostInfo>
|
||||
#include <QUuid>
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
namespace Accounts
|
||||
{
|
||||
namespace Hatchet
|
||||
{
|
||||
|
||||
|
||||
HatchetSipPlugin::HatchetSipPlugin( Tomahawk::Accounts::Account *account )
|
||||
: SipPlugin( account )
|
||||
, m_sipState( Closed )
|
||||
@@ -46,7 +54,9 @@ HatchetSipPlugin::HatchetSipPlugin( Tomahawk::Accounts::Account *account )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
|
||||
connect( m_account, SIGNAL( accessTokenFetched() ), this, SLOT( connectWebSocket() ) );
|
||||
connect( m_account,
|
||||
SIGNAL( accessTokenFetched( const HatchetHelpers::AccessTokenInformation& ) ),
|
||||
SLOT( connectWebSocket( const HatchetHelpers::AccessTokenInformation& ) ) );
|
||||
connect( Servent::instance(), SIGNAL( dbSyncTriggered() ), this, SLOT( dbSyncTriggered() ));
|
||||
|
||||
/*
|
||||
@@ -95,10 +105,10 @@ HatchetSipPlugin::isValid() const
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::Accounts::HatchetAccount*
|
||||
HatchetAccount*
|
||||
HatchetSipPlugin::hatchetAccount() const
|
||||
{
|
||||
return qobject_cast< Tomahawk::Accounts::HatchetAccount* >( m_account );
|
||||
return qobject_cast< HatchetAccount* >( m_account );
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +143,7 @@ HatchetSipPlugin::disconnectPlugin()
|
||||
|
||||
|
||||
void
|
||||
HatchetSipPlugin::connectWebSocket()
|
||||
HatchetSipPlugin::connectWebSocket( const HatchetHelpers::AccessTokenInformation& accessTokenInformation )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
if ( m_webSocketThreadController )
|
||||
@@ -157,8 +167,7 @@ HatchetSipPlugin::connectWebSocket()
|
||||
return;
|
||||
}
|
||||
|
||||
m_token = m_account->credentials()[ "dreamcatcher_access_token" ].toString();
|
||||
|
||||
m_token = accessTokenInformation.token;
|
||||
|
||||
if ( m_token.isEmpty() )
|
||||
{
|
||||
@@ -585,3 +594,6 @@ HatchetSipPlugin::oplogFetched( const QString& sinceguid, const QString& /* last
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -32,6 +32,13 @@ class WebSocketThreadController;
|
||||
|
||||
const int VERSION = 1;
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
namespace Accounts
|
||||
{
|
||||
namespace Hatchet
|
||||
{
|
||||
|
||||
class ACCOUNTDLLEXPORT HatchetSipPlugin : public SipPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -63,14 +70,14 @@ public slots:
|
||||
void webSocketDisconnected();
|
||||
|
||||
signals:
|
||||
void connectWebSocket() const;
|
||||
void connectWebSocket( const HatchetHelpers::AccessTokenInformation& ) const;
|
||||
void disconnectWebSocket() const;
|
||||
void rawBytes( QByteArray bytes ) const;
|
||||
|
||||
private slots:
|
||||
void dbSyncTriggered();
|
||||
void messageReceived( const QByteArray& msg );
|
||||
void connectWebSocket();
|
||||
void connectWebSocket( const HatchetHelpers::AccessTokenInformation& );
|
||||
void oplogFetched( const QString& sinceguid, const QString& lastguid, const QList< dbop_ptr > ops );
|
||||
|
||||
private:
|
||||
@@ -79,7 +86,7 @@ private:
|
||||
void newPeer( const QVariantMap& valMap );
|
||||
void peerAuthorization( const QVariantMap& valMap );
|
||||
void sendOplog( const QVariantMap& valMap ) const;
|
||||
Tomahawk::Accounts::HatchetAccount* hatchetAccount() const;
|
||||
HatchetAccount* hatchetAccount() const;
|
||||
|
||||
QPointer< WebSocketThreadController > m_webSocketThreadController;
|
||||
QString m_token;
|
||||
@@ -91,4 +98,8 @@ private:
|
||||
QHash< QString, QList< SipInfo > > m_sipInfoHash;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -68,7 +68,6 @@ WebSocketThreadController::run()
|
||||
if ( m_webSocket && m_sip )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Have a valid websocket and parent";
|
||||
connect( m_sip, SIGNAL( connectWebSocket() ), m_webSocket, SLOT( connectWs() ), Qt::QueuedConnection );
|
||||
connect( m_sip, SIGNAL( disconnectWebSocket() ), m_webSocket, SLOT( disconnectWs() ), Qt::QueuedConnection );
|
||||
connect( m_sip, SIGNAL( rawBytes( QByteArray ) ), m_webSocket, SLOT( encodeMessage( QByteArray ) ), Qt::QueuedConnection );
|
||||
connect( m_webSocket, SIGNAL( connected() ), m_sip, SLOT( webSocketConnected() ), Qt::QueuedConnection );
|
||||
|
Reference in New Issue
Block a user