mirror of
https://invent.kde.org/network/falkon.git
synced 2024-12-19 18:26:34 +01:00
Add method to fetch sync Master Key and upload device name
This commit is contained in:
parent
1460611cce
commit
ccbbf2c0fc
@ -223,6 +223,7 @@ set(SRCS ${SRCS}
|
||||
sync/synccrypto.cpp
|
||||
sync/hawk/hawk.cpp
|
||||
sync/syncmanager.cpp
|
||||
sync/syncutils.cpp
|
||||
tabwidget/combotabbar.cpp
|
||||
tabwidget/tabbar.cpp
|
||||
tabwidget/tabicon.cpp
|
||||
|
@ -34,7 +34,7 @@ SyncOptions::SyncOptions(QWidget* parent)
|
||||
loginPage = new FxALoginPage(this);
|
||||
ui->fxaloginframe->addWidget(loginPage);
|
||||
|
||||
connect(ui->btnSyncNow, &QPushButton::clicked, mApp->syncManager(), &SyncManager::sync);
|
||||
connect(ui->btnSyncNow, &QPushButton::clicked, mApp->syncManager(), &SyncManager::startSync);
|
||||
}
|
||||
|
||||
SyncOptions::~SyncOptions()
|
||||
|
@ -100,7 +100,6 @@ void FxALoginPage::parseMessage(QJsonObject *msg)
|
||||
settings.setValue(QSL("KeyFetchToken"), key_fetch_token);
|
||||
settings.setValue(QSL("UnwrapBKey"), unwrap_kb);
|
||||
settings.endGroup();
|
||||
// derive the various tokens and save into settings right here and instead of synccreds, create a user_data object
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */
|
||||
#include "synccrypto.h"
|
||||
#include "syncutils.h"
|
||||
|
||||
#include <nettle/sha2.h>
|
||||
#include <nettle/hkdf.h>
|
||||
@ -26,6 +27,7 @@
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
#include <QDateTime>
|
||||
|
||||
#include <random>
|
||||
|
||||
@ -153,3 +155,158 @@ RSAKeyPair *generateRSAKeyPair()
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -29,8 +29,17 @@ struct RSAKeyPair {
|
||||
};
|
||||
|
||||
void generateRandomBytes(void *randomCtx, size_t numBytes, u_char *out);
|
||||
|
||||
u_char *syncCryptoHkdf(QByteArray *in, QByteArray *info, size_t out_len);
|
||||
void syncCryptoKW(QByteArray *kw, QString name);
|
||||
|
||||
void deriveSessionToken(QByteArray *sessionToken, QByteArray *tokenId, QByteArray *reqHMACKey, QByteArray *reqKey);
|
||||
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();
|
||||
|
||||
QByteArray *createBowserIdAssertion(QByteArray *certificate, QByteArray *audience, qint64 seconds, RSAKeyPair *keyPair);
|
||||
|
||||
QByteArray *xorQByteArray(QByteArray *a, QByteArray *b, size_t len);
|
||||
void testDeriveMasterKey();
|
||||
|
@ -16,8 +16,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */
|
||||
#include "syncmanager.h"
|
||||
#include "syncrequest.h"
|
||||
#include "synccrypto.h"
|
||||
#include "syncutils.h"
|
||||
#include "settings.h"
|
||||
#include "hawk.h"
|
||||
#include "mainapplication.h"
|
||||
@ -79,7 +79,7 @@ SyncState::~SyncState()
|
||||
void SyncState::saveSyncState(bool syncSuccess)
|
||||
{
|
||||
if (syncSuccess) {
|
||||
*m_lastSyncTime = QDateTime::currentDateTimeUtc();
|
||||
*m_lastSyncTime = QDateTime::currentDateTime();
|
||||
m_isInitialSync = false;
|
||||
Settings settings;
|
||||
settings.beginGroup(QSL("SyncState"));
|
||||
@ -107,14 +107,19 @@ SyncManager::SyncManager(QObject *parent)
|
||||
m_syncState = new SyncState();
|
||||
m_networkManager = new QNetworkAccessManager(this);
|
||||
m_keyPair = generateRSAKeyPair();
|
||||
m_browserCertificate = new QByteArray();
|
||||
|
||||
testDeriveMasterKey();
|
||||
}
|
||||
|
||||
SyncManager::~SyncManager()
|
||||
{
|
||||
saveSyncState();
|
||||
m_networkManager->deleteLater();
|
||||
delete m_syncCreds;
|
||||
delete m_syncState;
|
||||
delete m_keyPair;
|
||||
delete m_browserCertificate;
|
||||
}
|
||||
|
||||
void SyncManager::saveSyncState()
|
||||
@ -124,35 +129,49 @@ void SyncManager::saveSyncState()
|
||||
|
||||
void SyncManager::sync()
|
||||
{
|
||||
bool error = false;
|
||||
if (m_storageCredentialsExpired) {
|
||||
error = getBrowserSignedCertificate();
|
||||
if (!error) {
|
||||
m_storageCredentialsExpired = false;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Getting Crypto Keys";
|
||||
getCryptoKeys();
|
||||
switch(m_syncStep) {
|
||||
case enum_ERROR:
|
||||
qWarning() << "Error occured in Sync Process.";
|
||||
m_syncSuccess = false;
|
||||
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;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
m_syncSuccess = false;
|
||||
qDebug() << "Sync Failed";
|
||||
} else {
|
||||
m_syncSuccess = true;
|
||||
}
|
||||
saveSyncState();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
bool SyncManager::getBrowserSignedCertificate()
|
||||
void SyncManager::getBrowserSignedCertificate()
|
||||
{
|
||||
bool error = false;
|
||||
|
||||
QString endpoint("certificate/sign");
|
||||
|
||||
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);
|
||||
|
||||
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.";
|
||||
|
||||
@ -194,25 +213,27 @@ bool SyncManager::getBrowserSignedCertificate()
|
||||
delete n;
|
||||
delete e;
|
||||
delete data;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void SyncManager::recievedBrowserSignedCertificate()
|
||||
void SyncManager::callback_getBrowserSignedCertificate()
|
||||
{
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||
if (!reply) {
|
||||
m_syncStep = enum_ERROR;
|
||||
sync();
|
||||
return;
|
||||
}
|
||||
|
||||
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->deleteLater();
|
||||
m_syncStep = enum_ERROR;
|
||||
sync();
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray response = reply->readAll();
|
||||
QByteArray response(reply->readAll().data());
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response);
|
||||
QJsonObject obj = doc.object();
|
||||
|
||||
@ -221,15 +242,24 @@ void SyncManager::recievedBrowserSignedCertificate()
|
||||
if (verifyBrowserSignedCertificate(&certificate)) {
|
||||
qDebug() << "Valid Browser Signed Certificate Response.";
|
||||
m_storageCredentialsExpired = false;
|
||||
sync();
|
||||
m_browserCertificate->clear();
|
||||
m_browserCertificate->append(certificate.data());
|
||||
if (m_syncState->isInitialSync()) {
|
||||
m_syncStep = enum_FetchAccountKeys;
|
||||
} else {
|
||||
m_syncStep = enum_TradeBrowserIdAssertion;
|
||||
}
|
||||
} 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 Recieved.";
|
||||
qWarning() << "Invalid Browser ID Assertion Response Received.";
|
||||
m_syncStep = enum_ERROR;
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
sync();
|
||||
}
|
||||
|
||||
bool SyncManager::verifyBrowserSignedCertificate(QByteArray* certificate)
|
||||
@ -268,9 +298,16 @@ bool SyncManager::verifyBrowserSignedCertificate(QByteArray* certificate)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SyncManager::getCryptoKeys()
|
||||
void SyncManager::tradeBrowserIdAssertion()
|
||||
{
|
||||
|
||||
m_syncStep = enum_NoRequestPending;
|
||||
sync();
|
||||
}
|
||||
|
||||
void SyncManager::getCryptoKeys()
|
||||
{
|
||||
qDebug() << "getCryptoKeys";
|
||||
QString endpoint("account/keys");
|
||||
QByteArray *keyFetchToken = new QByteArray(QByteArray::fromHex(m_syncCreds->getValue("KeyFetchToken").toUtf8().data()));
|
||||
QByteArray *tokenId = new QByteArray();
|
||||
@ -278,33 +315,163 @@ bool SyncManager::getCryptoKeys()
|
||||
QByteArray *respHMACKey = new QByteArray();
|
||||
QByteArray *respXorKey = new QByteArray();
|
||||
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());
|
||||
|
||||
QNetworkRequest request = createHawkGetRequest(endpoint, tokenIdHex, reqHMACKey, 32);
|
||||
|
||||
qDebug() << "Request created";
|
||||
QNetworkReply *reply = m_networkManager->get(request);
|
||||
connect(reply, &QNetworkReply::finished, this, [ = ]() {
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qWarning() << "Reply Error" << reply->error() << reply->errorString();
|
||||
qDebug() << "Reply: " << reply->readAll();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
qDebug() << "Reply: " << reply->readAll();
|
||||
reply->deleteLater();
|
||||
});
|
||||
connect(reply, &QNetworkReply::finished, this, &SyncManager::callback_getCryptoKeys);
|
||||
|
||||
qDebug() << "Hawk POST Request sent to /account/keys endpoint.";
|
||||
|
||||
delete keyFetchToken;
|
||||
delete tokenId;
|
||||
delete reqHMACKey;
|
||||
delete respHMACKey;
|
||||
delete respXorKey;
|
||||
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)
|
||||
{
|
||||
|
@ -58,6 +58,15 @@ class SyncManager : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
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);
|
||||
~SyncManager();
|
||||
void sync();
|
||||
@ -67,11 +76,15 @@ public Q_SLOTS:
|
||||
void startSync();
|
||||
|
||||
private Q_SLOTS:
|
||||
void recievedBrowserSignedCertificate();
|
||||
void callback_getBrowserSignedCertificate();
|
||||
void callback_getCryptoKeys();
|
||||
void callback_uploadDevice();
|
||||
|
||||
private:
|
||||
bool getBrowserSignedCertificate();
|
||||
bool getCryptoKeys();
|
||||
void getBrowserSignedCertificate();
|
||||
void tradeBrowserIdAssertion();
|
||||
void getCryptoKeys();
|
||||
void uploadDevice();
|
||||
|
||||
bool verifyBrowserSignedCertificate(QByteArray *certificate);
|
||||
|
||||
@ -88,4 +101,8 @@ private:
|
||||
SyncCredentials *m_syncCreds;
|
||||
SyncState *m_syncState;
|
||||
RSAKeyPair *m_keyPair;
|
||||
|
||||
QByteArray *m_browserCertificate;
|
||||
|
||||
uint m_syncStep = enum_FetchBrowserId;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
40
src/lib/sync/syncutils.cpp
Normal file
40
src/lib/sync/syncutils.cpp
Normal 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;
|
||||
}
|
@ -15,31 +15,9 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QQueue>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
class SyncRequestManager : public QObject
|
||||
{
|
||||
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;
|
||||
};
|
||||
QString getAudience(QUrl url);
|
Loading…
Reference in New Issue
Block a user