1
mirror of https://invent.kde.org/network/falkon.git synced 2024-11-11 01:22:10 +01:00

Add method to fetch sync Master Key and upload device name

This commit is contained in:
Prasenjit Kumar Shaw 2019-07-20 23:43:26 +05:30
parent 1460611cce
commit ccbbf2c0fc
10 changed files with 445 additions and 133 deletions

View File

@ -223,6 +223,7 @@ set(SRCS ${SRCS}
sync/synccrypto.cpp sync/synccrypto.cpp
sync/hawk/hawk.cpp sync/hawk/hawk.cpp
sync/syncmanager.cpp sync/syncmanager.cpp
sync/syncutils.cpp
tabwidget/combotabbar.cpp tabwidget/combotabbar.cpp
tabwidget/tabbar.cpp tabwidget/tabbar.cpp
tabwidget/tabicon.cpp tabwidget/tabicon.cpp

View File

@ -34,7 +34,7 @@ SyncOptions::SyncOptions(QWidget* parent)
loginPage = new FxALoginPage(this); loginPage = new FxALoginPage(this);
ui->fxaloginframe->addWidget(loginPage); ui->fxaloginframe->addWidget(loginPage);
connect(ui->btnSyncNow, &QPushButton::clicked, mApp->syncManager(), &SyncManager::sync); connect(ui->btnSyncNow, &QPushButton::clicked, mApp->syncManager(), &SyncManager::startSync);
} }
SyncOptions::~SyncOptions() SyncOptions::~SyncOptions()

View File

@ -100,7 +100,6 @@ void FxALoginPage::parseMessage(QJsonObject *msg)
settings.setValue(QSL("KeyFetchToken"), key_fetch_token); settings.setValue(QSL("KeyFetchToken"), key_fetch_token);
settings.setValue(QSL("UnwrapBKey"), unwrap_kb); settings.setValue(QSL("UnwrapBKey"), unwrap_kb);
settings.endGroup(); settings.endGroup();
// derive the various tokens and save into settings right here and instead of synccreds, create a user_data object
} }
} }

View File

@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */ * ============================================================ */
#include "synccrypto.h" #include "synccrypto.h"
#include "syncutils.h"
#include <nettle/sha2.h> #include <nettle/sha2.h>
#include <nettle/hkdf.h> #include <nettle/hkdf.h>
@ -26,6 +27,7 @@
#include <QByteArray> #include <QByteArray>
#include <QString> #include <QString>
#include <QDebug> #include <QDebug>
#include <QDateTime>
#include <random> #include <random>
@ -153,3 +155,158 @@ RSAKeyPair *generateRSAKeyPair()
return keyPair; return keyPair;
} }
QByteArray *createBowserIdAssertion(QByteArray *certificate, QByteArray *audience, qint64 seconds, RSAKeyPair *keyPair)
{
QByteArray *assertion = new QByteArray();
mpz_t signature;
QString tempHeader("{\"alg\": \"RS256\"}");
QByteArray header = QByteArray(tempHeader.toUtf8());
header.toBase64();
qint64 expiry = QDateTime::currentMSecsSinceEpoch() + seconds * 1000;
QString tempBody = QString("{\"exp\": %1, \"aud\": \"%2\"}").arg(expiry).arg(audience->data());
QByteArray body = QByteArray(tempBody.toUtf8());
body.toBase64();
QByteArray toSign = QByteArray((QString("%1.%2").arg(header.data()).arg(header.data())).toUtf8());
u_char *digest = new u_char[SHA256_DIGEST_SIZE];
sha256_ctx *ctx = new sha256_ctx;
sha256_init(ctx);
sha256_update(ctx, toSign.size(), (u_char *)(toSign.data()));
sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
delete ctx;
mpz_init(signature);
int success = nettle_rsa_sha256_sign_digest_tr(&(keyPair->m_publicKey), &(keyPair->m_privateKey), nullptr, generateRandomBytes, digest, signature);
Q_ASSERT(success);
size_t expectedSize = (mpz_sizeinbase(signature, 2) + 7) / 8;
size_t count;
u_char *sig = new u_char[expectedSize];
mpz_export(sig, &count, 1, sizeof(quint8), 0, 0, signature);
Q_ASSERT(count == expectedSize);
QByteArray sigBase64 = QByteArray::fromRawData((const char *)sig, count);
sigBase64.toBase64();
assertion->append((QString("%1~%2.%3.%4").arg(certificate->data()).arg(header.data()).arg(body.data()).arg(sigBase64.data())).toUtf8());
mpz_clear(signature);
delete digest;
delete sig;
return assertion;
}
QByteArray *xorQByteArray(QByteArray *a, QByteArray *b, size_t len)
{
QByteArray *xored = new QByteArray();
char *aData = a->data();
char *bData = b->data();
char *xorData = new char[len];
for(int i = 0; i < len; ++i) {
xorData[i] = aData[i] ^ bData[i];
}
xored->append(xorData, len);
return xored;
}
bool deriveMasterKey(QByteArray *bundleHex, QByteArray *respHMACKey, QByteArray *respXORKey, QByteArray *unwrapKb, QByteArray *ka, QByteArray *kb)
{
bool returnVal = true;
QByteArray *bundle = new QByteArray(QByteArray::fromHex(bundleHex->data()));
size_t masterKeyLen = 32;
QByteArray *cipherText = new QByteArray(bundle->data());
cipherText->chop(masterKeyLen);
QByteArray *respHMAC = new QByteArray(bundle->right(masterKeyLen).data());
hmac_sha256_ctx *ctx = new hmac_sha256_ctx;
hmac_sha256_set_key(ctx, respHMACKey->size(), (u_char *)respHMACKey->data());
hmac_sha256_update(ctx, cipherText->length(), (u_char *)cipherText->data());
u_char *out = new u_char[SHA256_DIGEST_SIZE];
hmac_sha256_digest(ctx, SHA256_DIGEST_SIZE, out);
QByteArray *respHMAC2 = new QByteArray(QByteArray::fromRawData((const char *)out, SHA256_DIGEST_SIZE));
QByteArray mac(respHMAC->data());
QByteArray mac2(respHMAC2->data());
qDebug() << "mac: " << mac.toHex().data() << "\ndigest:" << mac2.toHex().data();
if (*respHMAC == *respHMAC2) {
QByteArray *xored = xorQByteArray(cipherText, respXORKey, 2 * masterKeyLen);
ka->append(xored->data());
ka->chop(masterKeyLen);
QByteArray *wrapKb = new QByteArray(xored->right(masterKeyLen));
QByteArray *xored2 = xorQByteArray(unwrapKb, wrapKb, masterKeyLen);
kb->append(xored2->data());
delete xored;
delete wrapKb;
delete xored2;
} else {
returnVal = false;
}
delete bundle;
delete cipherText;
delete respHMAC;
delete ctx;
return returnVal;
}
void testDeriveMasterKey()
{
bool returnVal = true;
QByteArray bundle(QByteArray::fromHex("ee5c58845c7c9412b11bbd20920c2fddd83c33c9cd2c2de2d66b222613364636fc7e59d854d599f10e212801de3a47c34333f3b838ee3471e0f285649c332bbb4c17f42a0b319bbba327d2b326ad23e937219b4de32e3ec7b3e3f740522ad6ef"));
size_t masterKeyLen = 32;
QByteArray cipherText(bundle.data());
cipherText.chop(masterKeyLen);
QByteArray respHMAC(bundle.right(masterKeyLen).data());
QByteArray respHMACKey(QByteArray::fromHex("f824d2953aab9faf51a1cb65ba9e7f9e5bf91c8d8fd1ac1c8c2d31853a8a1210"));
QByteArray respXORKey(QByteArray::fromHex("ce7d7aa77859b2359932970bbe2101f2e80d01faf9191bd5ee52181d2f0b78098281ba8cff3925433a89f7c3095e0c89900a469d60790c833281c4df1a11c763"));
QByteArray unwrapKb(QByteArray::fromHex("de6a2648b78284fcb9ffa81ba95803309cfba7af583c01a8a1a63e567234dd28"));
hmac_sha256_ctx *ctx = new hmac_sha256_ctx;
hmac_sha256_set_key(ctx, respHMACKey.size(), (u_char *)respHMACKey.data());
hmac_sha256_update(ctx, cipherText.length(), (u_char *)cipherText.data());
u_char *out = new u_char[SHA256_DIGEST_SIZE];
hmac_sha256_digest(ctx, SHA256_DIGEST_SIZE, out);
QByteArray respHMAC2(QByteArray::fromRawData((const char *)out, SHA256_DIGEST_SIZE));
QByteArray mac(respHMAC.data());
QByteArray mac2(respHMAC2.data());
qDebug() << "mac: " << mac.toHex().data() << "\ndigest:" << mac2.toHex().data() << "\nequal? " << (respHMAC == respHMAC2);
if (respHMAC == respHMAC2) {
QByteArray *xored = xorQByteArray(&cipherText, &respXORKey, 2 * masterKeyLen);
QByteArray ka(xored->data());
ka.chop(masterKeyLen);
QByteArray *wrapKb = new QByteArray(xored->right(masterKeyLen));
QByteArray *xored2 = xorQByteArray(&unwrapKb, wrapKb, masterKeyLen);
QByteArray kb(xored2->data());
QByteArray expectedKa(QByteArray::fromHex("202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"));
QByteArray expectedKb(("a095c51c1c6e384e8d5777d97e3c487a4fc2128a00ab395a73d57fedf41631f0"));
qDebug() << "ka? " << (ka == expectedKa) << "\nkb? " << (kb == expectedKb);
delete xored;
delete wrapKb;
delete xored2;
} else {
returnVal = false;
}
delete ctx;
delete out;
}

View File

@ -29,8 +29,17 @@ struct RSAKeyPair {
}; };
void generateRandomBytes(void *randomCtx, size_t numBytes, u_char *out); void generateRandomBytes(void *randomCtx, size_t numBytes, u_char *out);
u_char *syncCryptoHkdf(QByteArray *in, QByteArray *info, size_t out_len); u_char *syncCryptoHkdf(QByteArray *in, QByteArray *info, size_t out_len);
void syncCryptoKW(QByteArray *kw, QString name); void syncCryptoKW(QByteArray *kw, QString name);
void deriveSessionToken(QByteArray *sessionToken, QByteArray *tokenId, QByteArray *reqHMACKey, QByteArray *reqKey); void deriveSessionToken(QByteArray *sessionToken, QByteArray *tokenId, QByteArray *reqHMACKey, QByteArray *reqKey);
void deriveKeyFetchToken(QByteArray *keyFetchToken, QByteArray *tokenId, QByteArray *reqHMACKey, QByteArray *respHMACKey, QByteArray *respXORKey); void deriveKeyFetchToken(QByteArray *keyFetchToken, QByteArray *tokenId, QByteArray *reqHMACKey, QByteArray *respHMACKey, QByteArray *respXORKey);
bool deriveMasterKey(QByteArray *bundleHex, QByteArray *respHMACKey, QByteArray *respXORKey, QByteArray *unwrapKb, QByteArray *ka, QByteArray *kb);
RSAKeyPair *generateRSAKeyPair(); RSAKeyPair *generateRSAKeyPair();
QByteArray *createBowserIdAssertion(QByteArray *certificate, QByteArray *audience, qint64 seconds, RSAKeyPair *keyPair);
QByteArray *xorQByteArray(QByteArray *a, QByteArray *b, size_t len);
void testDeriveMasterKey();

View File

@ -16,8 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */ * ============================================================ */
#include "syncmanager.h" #include "syncmanager.h"
#include "syncrequest.h"
#include "synccrypto.h" #include "synccrypto.h"
#include "syncutils.h"
#include "settings.h" #include "settings.h"
#include "hawk.h" #include "hawk.h"
#include "mainapplication.h" #include "mainapplication.h"
@ -79,7 +79,7 @@ SyncState::~SyncState()
void SyncState::saveSyncState(bool syncSuccess) void SyncState::saveSyncState(bool syncSuccess)
{ {
if (syncSuccess) { if (syncSuccess) {
*m_lastSyncTime = QDateTime::currentDateTimeUtc(); *m_lastSyncTime = QDateTime::currentDateTime();
m_isInitialSync = false; m_isInitialSync = false;
Settings settings; Settings settings;
settings.beginGroup(QSL("SyncState")); settings.beginGroup(QSL("SyncState"));
@ -107,14 +107,19 @@ SyncManager::SyncManager(QObject *parent)
m_syncState = new SyncState(); m_syncState = new SyncState();
m_networkManager = new QNetworkAccessManager(this); m_networkManager = new QNetworkAccessManager(this);
m_keyPair = generateRSAKeyPair(); m_keyPair = generateRSAKeyPair();
m_browserCertificate = new QByteArray();
testDeriveMasterKey();
} }
SyncManager::~SyncManager() SyncManager::~SyncManager()
{ {
saveSyncState(); saveSyncState();
m_networkManager->deleteLater();
delete m_syncCreds; delete m_syncCreds;
delete m_syncState; delete m_syncState;
delete m_keyPair; delete m_keyPair;
delete m_browserCertificate;
} }
void SyncManager::saveSyncState() void SyncManager::saveSyncState()
@ -124,35 +129,49 @@ void SyncManager::saveSyncState()
void SyncManager::sync() void SyncManager::sync()
{ {
bool error = false; switch(m_syncStep) {
if (m_storageCredentialsExpired) { case enum_ERROR:
error = getBrowserSignedCertificate(); qWarning() << "Error occured in Sync Process.";
if (!error) {
m_storageCredentialsExpired = false;
}
} else {
qDebug() << "Getting Crypto Keys";
getCryptoKeys();
}
if (error) {
m_syncSuccess = false; m_syncSuccess = false;
qDebug() << "Sync Failed";
} else {
m_syncSuccess = true;
}
saveSyncState(); saveSyncState();
break;
case enum_FetchBrowserId:
getBrowserSignedCertificate();
break;
case enum_TradeBrowserIdAssertion:
tradeBrowserIdAssertion();
break;
case enum_FetchAccountKeys:
getCryptoKeys();
break;
case enum_UploadDevice:
uploadDevice();
break;
case enum_NoRequestPending:
qDebug() << "No sync requests pending.";
m_syncSuccess = true;
saveSyncState();
break;
default:
saveSyncState();
break;
}
} }
void SyncManager::startSync() void SyncManager::startSync()
{ {
if(m_syncState->isInitialSync()) {
qDebug() << "is initial sync, going to uploadDevice";
m_syncStep = enum_UploadDevice;
} else {
qDebug() << "not initial sync, going to fetchBrowserId";
m_syncStep = enum_FetchBrowserId;
}
sync(); sync();
} }
bool SyncManager::getBrowserSignedCertificate() void SyncManager::getBrowserSignedCertificate()
{ {
bool error = false;
QString endpoint("certificate/sign"); QString endpoint("certificate/sign");
QByteArray *sessionToken = new QByteArray(QByteArray::fromHex(m_syncCreds->getValue("SessionToken").toUtf8().data())); QByteArray *sessionToken = new QByteArray(QByteArray::fromHex(m_syncCreds->getValue("SessionToken").toUtf8().data()));
@ -182,7 +201,7 @@ bool SyncManager::getBrowserSignedCertificate()
QNetworkRequest request = createHawkPostReqeuest(endpoint, tokenIdHex, requestHMACKey, 32, data); QNetworkRequest request = createHawkPostReqeuest(endpoint, tokenIdHex, requestHMACKey, 32, data);
QNetworkReply *reply = m_networkManager->post(request, *data); QNetworkReply *reply = m_networkManager->post(request, *data);
connect(reply, &QNetworkReply::finished, this, &SyncManager::recievedBrowserSignedCertificate); connect(reply, &QNetworkReply::finished, this, &SyncManager::callback_getBrowserSignedCertificate);
qDebug() << "Hawk POST Request sent to /certificate/sign endpoint."; qDebug() << "Hawk POST Request sent to /certificate/sign endpoint.";
@ -194,25 +213,27 @@ bool SyncManager::getBrowserSignedCertificate()
delete n; delete n;
delete e; delete e;
delete data; delete data;
return error;
} }
void SyncManager::recievedBrowserSignedCertificate() void SyncManager::callback_getBrowserSignedCertificate()
{ {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender()); QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (!reply) { if (!reply) {
m_syncStep = enum_ERROR;
sync();
return; return;
} }
if (reply->error() != QNetworkReply::NoError) { if (reply->error() != QNetworkReply::NoError) {
qWarning() << "Error in recieving Browser Signed Certificate for Firefox Sync."; qWarning() << "Error in receiving Browser Signed Certificate for Firefox Sync.";
reply->close(); reply->close();
reply->deleteLater(); reply->deleteLater();
m_syncStep = enum_ERROR;
sync();
return; return;
} }
QByteArray response = reply->readAll(); QByteArray response(reply->readAll().data());
QJsonDocument doc = QJsonDocument::fromJson(response); QJsonDocument doc = QJsonDocument::fromJson(response);
QJsonObject obj = doc.object(); QJsonObject obj = doc.object();
@ -221,15 +242,24 @@ void SyncManager::recievedBrowserSignedCertificate()
if (verifyBrowserSignedCertificate(&certificate)) { if (verifyBrowserSignedCertificate(&certificate)) {
qDebug() << "Valid Browser Signed Certificate Response."; qDebug() << "Valid Browser Signed Certificate Response.";
m_storageCredentialsExpired = false; m_storageCredentialsExpired = false;
sync(); m_browserCertificate->clear();
m_browserCertificate->append(certificate.data());
if (m_syncState->isInitialSync()) {
m_syncStep = enum_FetchAccountKeys;
} else { } else {
qWarning() << "Invalid Browser ID Assertion Response Recieved."; m_syncStep = enum_TradeBrowserIdAssertion;
} }
} else { } else {
qWarning() << "Invalid Browser ID Assertion Response Recieved."; qWarning() << "Invalid Browser ID Assertion Response Received.";
m_syncStep = enum_ERROR;
}
} else {
qWarning() << "Invalid Browser ID Assertion Response Received.";
m_syncStep = enum_ERROR;
} }
reply->deleteLater(); reply->deleteLater();
sync();
} }
bool SyncManager::verifyBrowserSignedCertificate(QByteArray* certificate) bool SyncManager::verifyBrowserSignedCertificate(QByteArray* certificate)
@ -268,9 +298,16 @@ bool SyncManager::verifyBrowserSignedCertificate(QByteArray* certificate)
return true; return true;
} }
void SyncManager::tradeBrowserIdAssertion()
bool SyncManager::getCryptoKeys()
{ {
m_syncStep = enum_NoRequestPending;
sync();
}
void SyncManager::getCryptoKeys()
{
qDebug() << "getCryptoKeys";
QString endpoint("account/keys"); QString endpoint("account/keys");
QByteArray *keyFetchToken = new QByteArray(QByteArray::fromHex(m_syncCreds->getValue("KeyFetchToken").toUtf8().data())); QByteArray *keyFetchToken = new QByteArray(QByteArray::fromHex(m_syncCreds->getValue("KeyFetchToken").toUtf8().data()));
QByteArray *tokenId = new QByteArray(); QByteArray *tokenId = new QByteArray();
@ -279,21 +316,22 @@ bool SyncManager::getCryptoKeys()
QByteArray *respXorKey = new QByteArray(); QByteArray *respXorKey = new QByteArray();
deriveKeyFetchToken(keyFetchToken, tokenId, reqHMACKey, respHMACKey, respXorKey); deriveKeyFetchToken(keyFetchToken, tokenId, reqHMACKey, respHMACKey, respXorKey);
QByteArray respHMACKeyHex(respHMACKey->toHex().data());
QByteArray reqHMACKeyHex(reqHMACKey->toHex().data());
QByteArray respXorKeyHex(respXorKey->toHex().data());
m_syncCreds->addSyncCredentials(QString("RespHMACKey"), QString(respHMACKeyHex.data()));
m_syncCreds->addSyncCredentials(QString("ReqHMACKey"), QString(reqHMACKeyHex.data()));
m_syncCreds->addSyncCredentials(QString("RespXORKey"), QString(respXorKeyHex.data()));
qDebug() << "derived keyFetchToken";
QByteArray *tokenIdHex = new QByteArray(tokenId->toHex().data()); QByteArray *tokenIdHex = new QByteArray(tokenId->toHex().data());
QNetworkRequest request = createHawkGetRequest(endpoint, tokenIdHex, reqHMACKey, 32); QNetworkRequest request = createHawkGetRequest(endpoint, tokenIdHex, reqHMACKey, 32);
qDebug() << "Request created";
QNetworkReply *reply = m_networkManager->get(request); QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [ = ]() { connect(reply, &QNetworkReply::finished, this, &SyncManager::callback_getCryptoKeys);
if (reply->error() != QNetworkReply::NoError) {
qWarning() << "Reply Error" << reply->error() << reply->errorString(); qDebug() << "Hawk POST Request sent to /account/keys endpoint.";
qDebug() << "Reply: " << reply->readAll();
reply->deleteLater();
return;
}
qDebug() << "Reply: " << reply->readAll();
reply->deleteLater();
});
delete keyFetchToken; delete keyFetchToken;
delete tokenId; delete tokenId;
@ -301,10 +339,139 @@ bool SyncManager::getCryptoKeys()
delete respHMACKey; delete respHMACKey;
delete respXorKey; delete respXorKey;
delete tokenIdHex; delete tokenIdHex;
return false;
} }
void SyncManager::callback_getCryptoKeys()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
qDebug() << "Received reply";
if (!reply) {
qDebug()<< "No reply";
m_syncStep = enum_ERROR;
sync();
return;
}
if (reply->error() != QNetworkReply::NoError) {
qWarning() << "Error in receiving Crypto Keys for Firefox Sync.";
qDebug() << reply->readAll();
reply->close();
reply->deleteLater();
m_syncStep = enum_ERROR;
sync();
return;
}
qDebug() << "received bundle";
QByteArray response(reply->readAll().data());
qDebug() << "account/keys response:\n" << response;
QJsonDocument doc = QJsonDocument::fromJson(response);
QJsonObject obj = doc.object();
if (obj.contains(QString("bundle"))) {
QByteArray *bundle = new QByteArray(obj.value(QString("bundle")).toString().toUtf8());
qDebug() << "bundle: " << bundle->data();
m_syncCreds->addSyncCredentials(QString("Bundle"), QString(bundle->data()));
QByteArray *ka = new QByteArray();
QByteArray *kb = new QByteArray();
QByteArray *unwrapKb = new QByteArray(QByteArray::fromHex(m_syncCreds->getValue(QString("UnwrapBKey")).toUtf8()));
QByteArray *respHMACKey = new QByteArray(QByteArray::fromHex(m_syncCreds->getValue(QString("RespHMACKey")).toUtf8()));
QByteArray *respXorKey = new QByteArray(QByteArray::fromHex(m_syncCreds->getValue(QString("RespXORKey")).toUtf8()));
if(!deriveMasterKey(bundle, respHMACKey, respXorKey, unwrapKb, ka, kb)) {
qWarning() << "Failed to retrieve Sync Key.";
m_syncStep = enum_ERROR;
} else {
m_syncCreds->addSyncCredentials(QString("MasterKey"), QString(kb->toHex().data()));
m_syncStep = enum_TradeBrowserIdAssertion;
}
delete bundle;
delete ka;
delete kb;
delete unwrapKb;
delete respHMACKey;
delete respXorKey;
} else {
qWarning() << "Invalid Crypto Keys Response Recieved.";
m_syncStep = enum_ERROR;
}
reply->deleteLater();
sync();
}
void SyncManager::uploadDevice()
{
QString endpoint("account/device");
QJsonObject obj;
obj.insert(QString("name"), QString("Falkon"));
obj.insert(QString("type"), QString("desktop"));
QJsonDocument doc(obj);
QByteArray *data = new QByteArray(doc.toJson(QJsonDocument::Compact));
QByteArray *sessionToken = new QByteArray(QByteArray::fromHex(m_syncCreds->getValue("SessionToken").toUtf8().data()));
QByteArray *tokenId = new QByteArray();
QByteArray *requestHMACKey = new QByteArray();
QByteArray *requestKey = new QByteArray();
deriveSessionToken(sessionToken, tokenId, requestHMACKey, requestKey);
QByteArray *tokenIdHex = new QByteArray(tokenId->toHex().data());
QNetworkRequest request = createHawkPostReqeuest(endpoint, tokenIdHex, requestHMACKey, 32, data);
QNetworkReply *reply = m_networkManager->post(request, *data);
connect(reply, &QNetworkReply::finished, this, &SyncManager::callback_uploadDevice);
qDebug() << "Hawk POST Request sent to /account/device endpoint.";
delete sessionToken;
delete tokenId;
delete requestHMACKey;
delete requestKey;
delete tokenIdHex;
delete data;
}
void SyncManager::callback_uploadDevice()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
qDebug() << "Received reply";
if (!reply) {
qDebug()<< "No reply";
m_syncStep = enum_ERROR;
sync();
return;
}
if (reply->error() != QNetworkReply::NoError) {
qWarning() << "Error in uploading Device Name to Firefox Sync.";
qDebug() << reply->readAll();
reply->close();
reply->deleteLater();
m_syncStep = enum_ERROR;
sync();
return;
}
QByteArray response(reply->readAll().data());
qDebug() << "account/device response:\n" << response;
QJsonDocument doc = QJsonDocument::fromJson(response);
QJsonObject obj = doc.object();
if (obj.contains(QString("id"))) {
QString id = obj.value(QString("id")).toString();
qDebug() << "id of device:" << id;
m_syncCreds->addSyncCredentials(QString("DeviceId"), id);
m_syncStep = enum_FetchBrowserId;
} else {
qWarning() << "Invalid Upload Device Response Recieved.";
m_syncStep = enum_ERROR;
}
reply->deleteLater();
sync();
}
QNetworkRequest SyncManager::createHawkGetRequest(QString endpoint, QByteArray* id, QByteArray* key, size_t keyLen) QNetworkRequest SyncManager::createHawkGetRequest(QString endpoint, QByteArray* id, QByteArray* key, size_t keyLen)
{ {

View File

@ -58,6 +58,15 @@ class SyncManager : public QObject
Q_OBJECT Q_OBJECT
public: public:
enum SyncStep {
enum_ERROR = 0,
enum_NoRequestPending = 1,
enum_FetchBrowserId = 2,
enum_UploadDevice = 3,
enum_TradeBrowserIdAssertion = 4,
enum_FetchAccountKeys = 5
};
explicit SyncManager(QObject *parent = nullptr); explicit SyncManager(QObject *parent = nullptr);
~SyncManager(); ~SyncManager();
void sync(); void sync();
@ -67,11 +76,15 @@ public Q_SLOTS:
void startSync(); void startSync();
private Q_SLOTS: private Q_SLOTS:
void recievedBrowserSignedCertificate(); void callback_getBrowserSignedCertificate();
void callback_getCryptoKeys();
void callback_uploadDevice();
private: private:
bool getBrowserSignedCertificate(); void getBrowserSignedCertificate();
bool getCryptoKeys(); void tradeBrowserIdAssertion();
void getCryptoKeys();
void uploadDevice();
bool verifyBrowserSignedCertificate(QByteArray *certificate); bool verifyBrowserSignedCertificate(QByteArray *certificate);
@ -88,4 +101,8 @@ private:
SyncCredentials *m_syncCreds; SyncCredentials *m_syncCreds;
SyncState *m_syncState; SyncState *m_syncState;
RSAKeyPair *m_keyPair; RSAKeyPair *m_keyPair;
QByteArray *m_browserCertificate;
uint m_syncStep = enum_FetchBrowserId;
}; };

View File

@ -1,56 +0,0 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2019 Prasenjit Kumar Shaw <shawprasenjit07@gmail.com>
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "syncrequest.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QQueue>
#include <QObject>
SyncRequestManager::SyncRequestManager(QObject* parent)
: QObject(parent)
{
m_requestManager = new QNetworkAccessManager(this);
m_requestQueue = new QQueue<RequestPair>();
startRequests = false;
}
void SyncRequestManager::addRequest(QNetworkRequest *request, bool post)
{
RequestPair temp = {*request, post};
m_requestQueue->enqueue(temp);
}
void SyncRequestManager::startSync(bool start)
{
startRequests = start;
if (startRequests) {
if (!m_requestQueue->isEmpty()) {
RequestPair req = m_requestQueue->dequeue();
QNetworkRequest request = req.request;
QNetworkReply *reply = nullptr;
if (req.post) {
reply = m_requestManager->get(request);
} else {
reply = m_requestManager->get(request);
}
}
}
}

View File

@ -0,0 +1,40 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2019 Prasenjit Kumar Shaw <shawprasenjit07@gmail.com>
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "syncutils.h"
#include <QString>
#include <QUrl>
#include <qzcommon.h>
QString getAudience(QUrl url)
{
QString host = url.host();
QString scheme = url.scheme();
qint64 port = url.port(0);
QString audience;
if(port == 0) {
audience = QSL("%s://%s").arg(scheme).arg(host);
}
else {
audience = QSL("%s://%s:%s").arg(scheme).arg(host).arg(port);
}
return audience;
}

View File

@ -15,31 +15,9 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */ * ============================================================ */
#pragma once #pragma once
#include <QNetworkAccessManager> #include <QString>
#include <QNetworkReply> #include <QUrl>
#include <QNetworkRequest>
#include <QQueue>
#include <QObject>
class SyncRequestManager : public QObject QString getAudience(QUrl url);
{
Q_OBJECT
public:
explicit SyncRequestManager(QObject *parent = nullptr);
void addRequest(QNetworkRequest *request, bool post);
void startSync(bool start);
private:
struct RequestPair {
QNetworkRequest request;
bool post;
};
QNetworkAccessManager *m_requestManager;
QQueue<RequestPair> *m_requestQueue;
bool startRequests;
};