From 7029968c47867fcba962f88b00051056915c0242 Mon Sep 17 00:00:00 2001 From: eugenyorbitsoftcom Date: Fri, 29 Jul 2022 10:36:54 +0600 Subject: [PATCH 01/52] SecureFormat AES-GCM --- client/client.pro | 2 + client/main.cpp | 13 ++++ client/secureformat.cpp | 169 ++++++++++++++++++++++++++++++++++++++++ client/secureformat.h | 21 +++++ client/settings.cpp | 7 +- client/settings.h | 8 +- 6 files changed, 213 insertions(+), 7 deletions(-) create mode 100644 client/secureformat.cpp create mode 100644 client/secureformat.h diff --git a/client/client.pro b/client/client.pro index 316730f93..1ec8cf1f8 100644 --- a/client/client.pro +++ b/client/client.pro @@ -40,6 +40,7 @@ HEADERS += \ managementserver.h \ platforms/linux/leakdetector.h \ protocols/protocols_defs.h \ + secureformat.h \ settings.h \ ui/notificationhandler.h \ ui/models/containers_model.h \ @@ -97,6 +98,7 @@ SOURCES += \ managementserver.cpp \ platforms/linux/leakdetector.cpp \ protocols/protocols_defs.cpp \ + secureformat.cpp \ settings.cpp \ ui/notificationhandler.cpp \ ui/models/containers_model.cpp \ diff --git a/client/main.cpp b/client/main.cpp index b1419f183..e3a1674f2 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -136,6 +136,19 @@ int main(int argc, char *argv[]) return 0; } +// QSettings oldSettings(ORGANIZATION_NAME, APPLICATION_NAME); +// if (!oldSettings.allKeys().isEmpty()) { +// QSettings newSettings(QSettings::Format::CustomFormat1, QSettings::UserScope, +// ORGANIZATION_NAME, APPLICATION_NAME); +// QString oldSettingsFileName = oldSettings.fileName(); +// QString newSettingsFileName = newSettings.fileName(); +// qDebug() << "oldSettingsFileName:" << oldSettingsFileName; +// qDebug() << "newSettingsFileName:" << newSettingsFileName; +//// qDebug() << "New config removed:" << QFile::remove(newSettingsFileName); +// qDebug() << "Old config copied:" << QFile::copy(oldSettingsFileName, newSettingsFileName); +//// qDebug() << "Old config removed:" << QFile::remove(oldSettingsFileName); +// } + Settings settings; if (settings.isSaveLogs()) { diff --git a/client/secureformat.cpp b/client/secureformat.cpp new file mode 100644 index 000000000..bd12e907e --- /dev/null +++ b/client/secureformat.cpp @@ -0,0 +1,169 @@ +#include "secureformat.h" + +#include +#include + +#include "openssl/evp.h" + +void handleErrors() { + qDebug() << "handleErrors"; +} + +int gcm_encrypt(unsigned char *plaintext, int plaintext_len, + unsigned char *key, + unsigned char *iv, int iv_len, + unsigned char *ciphertext) +{ + EVP_CIPHER_CTX *ctx; + + int len; + + int ciphertext_len; + + + /* Create and initialise the context */ + if(!(ctx = EVP_CIPHER_CTX_new())) + handleErrors(); + + /* Initialise the encryption operation. */ + if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + handleErrors(); + + /* + * Set IV length if default 12 bytes (96 bits) is not appropriate + */ + if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) + handleErrors(); + + /* Initialise key and IV */ + if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) + handleErrors(); + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) + handleErrors(); + ciphertext_len = len; + + /* + * Finalise the encryption. Normally ciphertext bytes may be written at + * this stage, but this does not occur in GCM mode + */ + if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) + handleErrors(); + ciphertext_len += len; + + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + return ciphertext_len; +} + +int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, + unsigned char *key, + unsigned char *iv, int iv_len, + unsigned char *plaintext) +{ + EVP_CIPHER_CTX *ctx; + int len; + int plaintext_len; + int ret; + + /* Create and initialise the context */ + if(!(ctx = EVP_CIPHER_CTX_new())) + handleErrors(); + + /* Initialise the decryption operation. */ + if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + handleErrors(); + + /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ + if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) + handleErrors(); + + /* Initialise key and IV */ + if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) + handleErrors(); + + /* + * Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary + */ + if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) + handleErrors(); + plaintext_len = len; + + /* + * Finalise the decryption. A positive return value indicates success, + * anything else is a failure - the plaintext is not trustworthy. + */ + ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len); + + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + if(ret > 0) { + /* Success */ + plaintext_len += len; + return plaintext_len; + } else { + /* Verify failed */ + return -1; + } +} + +SecureFormat::SecureFormat() +{ + m_format = QSettings::registerFormat("plist", + readSecureFile, + writeSecureFile); + qDebug() << "SecureFormat" << m_format; + + unsigned char plainText[] = "Hello world!"; + qDebug("%s", plainText); + unsigned char key[] = "12345qwerty"; + unsigned char iv[] = "000000000000"; + unsigned char chipherText[1024]; + unsigned char decryptPlainText[1024]; + gcm_encrypt(plainText, std::strlen((const char *)plainText), + key, + iv, 12, + chipherText); + qDebug("%s", chipherText); + + gcm_decrypt(chipherText, std::strlen((const char *)chipherText), + key, + iv, 12, + decryptPlainText); + qDebug("%s", decryptPlainText); +} + +bool SecureFormat::readSecureFile(QIODevice& device, QSettings::SettingsMap& map) { + if (!device.isOpen()) { + return false; + } + + QTextStream inStream(&device); + while (!inStream.atEnd()) { + QString line = inStream.readLine(); + qDebug() << "SecureFormat::readSecureFile" << line; + } + + return true; +} + +bool SecureFormat::writeSecureFile(QIODevice& device, const QSettings::SettingsMap& map) { + if (!device.isOpen()) { + return false; + } + + QTextStream outStream(&device); + + return true; +} + +const QSettings::Format& SecureFormat::format() const{ + return m_format; +} diff --git a/client/secureformat.h b/client/secureformat.h new file mode 100644 index 000000000..bb93d77e3 --- /dev/null +++ b/client/secureformat.h @@ -0,0 +1,21 @@ +#ifndef SECUREFORMAT_H +#define SECUREFORMAT_H + +#include +#include + +class SecureFormat +{ +public: + SecureFormat(); + + static bool readSecureFile(QIODevice &device, QSettings::SettingsMap &map); + static bool writeSecureFile(QIODevice &device, const QSettings::SettingsMap &map); + + const QSettings::Format& format() const; + +private: + QSettings::Format m_format; +}; + +#endif // SECUREFORMAT_H diff --git a/client/settings.cpp b/client/settings.cpp index 317df7406..e35a14ace 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -8,10 +8,15 @@ const char Settings::cloudFlareNs1[] = "1.1.1.1"; const char Settings::cloudFlareNs2[] = "1.0.0.1"; +SecureFormat Settings::m_secureFormat; + Settings::Settings(QObject* parent) : QObject(parent), - m_settings (ORGANIZATION_NAME, APPLICATION_NAME, this) + m_settings(m_secureFormat.format(), QSettings::UserScope, + ORGANIZATION_NAME, APPLICATION_NAME, this) { + qDebug() << "Settings::Settings()" << this; + qDebug() << "Settings::Settings()" << m_settings.fileName(); // Import old settings if (serversCount() == 0) { QString user = m_settings.value("Server/userName").toString(); diff --git a/client/settings.h b/client/settings.h index d5cb16396..7b0066b90 100644 --- a/client/settings.h +++ b/client/settings.h @@ -11,6 +11,7 @@ #include "core/defs.h" #include "containers/containers_defs.h" +#include "secureformat.h" using namespace amnezia; @@ -110,14 +111,9 @@ public: // static constexpr char openNicNs5[] = "94.103.153.176"; // static constexpr char openNicNs13[] = "144.76.103.143"; - -public: - - - private: + static SecureFormat m_secureFormat; QSettings m_settings; - }; #endif // SETTINGS_H From 3b78c3a9295bbd63b4b294be20064d4e9e85a54c Mon Sep 17 00:00:00 2001 From: eugenyorbitsoftcom Date: Fri, 29 Jul 2022 14:58:22 +0600 Subject: [PATCH 02/52] chiperSettings --- client/main.cpp | 20 ++++++----- client/secureformat.cpp | 76 +++++++++++++++++++++++++++++------------ client/secureformat.h | 2 ++ 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/client/main.cpp b/client/main.cpp index e3a1674f2..aae9a7e3e 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -136,18 +136,22 @@ int main(int argc, char *argv[]) return 0; } -// QSettings oldSettings(ORGANIZATION_NAME, APPLICATION_NAME); -// if (!oldSettings.allKeys().isEmpty()) { -// QSettings newSettings(QSettings::Format::CustomFormat1, QSettings::UserScope, -// ORGANIZATION_NAME, APPLICATION_NAME); -// QString oldSettingsFileName = oldSettings.fileName(); -// QString newSettingsFileName = newSettings.fileName(); + QSettings oldSettings(ORGANIZATION_NAME, APPLICATION_NAME); + if (!oldSettings.allKeys().isEmpty()) { + QSettings newSettingsForPath(QSettings::Format::CustomFormat1, QSettings::UserScope, + ORGANIZATION_NAME, APPLICATION_NAME); + QString oldSettingsFileName = oldSettings.fileName(); + QString newSettingsFileName = newSettingsForPath.fileName(); + + qDebug() << "New config removed:" << QFile::remove(newSettingsFileName); + QSettings newSettings(newSettingsFileName, QSettings::Format::NativeFormat); + SecureFormat::chiperSettings(oldSettings, newSettings); + // qDebug() << "oldSettingsFileName:" << oldSettingsFileName; // qDebug() << "newSettingsFileName:" << newSettingsFileName; -//// qDebug() << "New config removed:" << QFile::remove(newSettingsFileName); // qDebug() << "Old config copied:" << QFile::copy(oldSettingsFileName, newSettingsFileName); //// qDebug() << "Old config removed:" << QFile::remove(oldSettingsFileName); -// } + } Settings settings; diff --git a/client/secureformat.cpp b/client/secureformat.cpp index bd12e907e..db632a0a6 100644 --- a/client/secureformat.cpp +++ b/client/secureformat.cpp @@ -1,6 +1,7 @@ #include "secureformat.h" #include +#include #include #include "openssl/evp.h" @@ -15,12 +16,9 @@ int gcm_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *ciphertext) { EVP_CIPHER_CTX *ctx; - int len; - int ciphertext_len; - /* Create and initialise the context */ if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors(); @@ -120,24 +118,6 @@ SecureFormat::SecureFormat() readSecureFile, writeSecureFile); qDebug() << "SecureFormat" << m_format; - - unsigned char plainText[] = "Hello world!"; - qDebug("%s", plainText); - unsigned char key[] = "12345qwerty"; - unsigned char iv[] = "000000000000"; - unsigned char chipherText[1024]; - unsigned char decryptPlainText[1024]; - gcm_encrypt(plainText, std::strlen((const char *)plainText), - key, - iv, 12, - chipherText); - qDebug("%s", chipherText); - - gcm_decrypt(chipherText, std::strlen((const char *)chipherText), - key, - iv, 12, - decryptPlainText); - qDebug("%s", decryptPlainText); } bool SecureFormat::readSecureFile(QIODevice& device, QSettings::SettingsMap& map) { @@ -148,7 +128,9 @@ bool SecureFormat::readSecureFile(QIODevice& device, QSettings::SettingsMap& map QTextStream inStream(&device); while (!inStream.atEnd()) { QString line = inStream.readLine(); - qDebug() << "SecureFormat::readSecureFile" << line; + qDebug() << "SecureFormat::readSecureFile: " << line; + QStringList keyValue = line.split("<=>"); + map.insert(keyValue.first(), keyValue.last()); } return true; @@ -160,10 +142,60 @@ bool SecureFormat::writeSecureFile(QIODevice& device, const QSettings::SettingsM } QTextStream outStream(&device); + auto keys = map.keys(); + for (auto key : keys) { + outStream << key << "<=>" << map.value(key).toString(); + qDebug() << "SecureFormat::writeSecureFile: " << key << "<=>" << map.value(key).toString(); + } return true; } +void SecureFormat::chiperSettings(const QSettings &oldSetting, QSettings &newSetting) { + QVariantMap keysValuesPairs; + QStringList keys = oldSetting.allKeys(); + QStringListIterator it(keys); + while ( it.hasNext() ) { + QString currentKey = it.next(); + keysValuesPairs.insert(currentKey, oldSetting.value(currentKey)); + } + + unsigned char gcmkey[] = "12345qwerty"; + unsigned char iv[] = "000000000000"; + + for (const QString& key : keys) { + QString value = keysValuesPairs.value(key).toString(); + + int plainTextSize = value.toUtf8().size(); + unsigned char* plainText = new unsigned char[plainTextSize]; + std::memcpy(plainText, value.toUtf8().constData(), plainTextSize); + + unsigned char chipherText[UINT16_MAX]; + int chipherTextSize = gcm_encrypt(plainText, plainTextSize, + gcmkey, + iv, 12, + chipherText); + QByteArray qChipherArray = QByteArray::fromRawData((const char *)chipherText, chipherTextSize); + +// unsigned char decryptPlainText[UINT16_MAX]; +// gcm_decrypt((unsigned char*)qChipherArray.data(), qChipherArray.size(), +// gcmkey, +// iv, 12, +// decryptPlainText); +// QString qDecryptPlainText = QString::fromUtf8((const char *)decryptPlainText); +// qDebug() << "qDecryptPlainText:" << qDecryptPlainText; + + newSetting.setValue(key, qChipherArray); + } + +// newSetting.sync(); +// qDebug() << "newSetting.allKeys(): " << newSetting.allKeys(); +// for (const QString& key : newSetting.allKeys()) { +// QString value = keysValuesPairs.value(key).toString(); +// qDebug() << "newSetting value: " << value; +// } +} + const QSettings::Format& SecureFormat::format() const{ return m_format; } diff --git a/client/secureformat.h b/client/secureformat.h index bb93d77e3..32e6d5991 100644 --- a/client/secureformat.h +++ b/client/secureformat.h @@ -12,6 +12,8 @@ public: static bool readSecureFile(QIODevice &device, QSettings::SettingsMap &map); static bool writeSecureFile(QIODevice &device, const QSettings::SettingsMap &map); + static void chiperSettings(const QSettings &oldSetting, QSettings &newSetting); + const QSettings::Format& format() const; private: From e99aa868630a488b36ae964af66748630d5f4c90 Mon Sep 17 00:00:00 2001 From: eugenyorbitsoftcom Date: Mon, 1 Aug 2022 15:57:16 +0600 Subject: [PATCH 03/52] fix building project --- client/client.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/client.pro b/client/client.pro index dd75d958f..0b6b10347 100644 --- a/client/client.pro +++ b/client/client.pro @@ -319,7 +319,7 @@ ios { platforms/ios/iosglue.mm \ platforms/ios/ipaddress.cpp \ platforms/ios/ipaddressrange.cpp \ - platforms/ios/QRCodeReaderBase.mm + platforms/ios/QRCodeReaderBase.mm \ platforms/ios/QtAppDelegate.mm \ platforms/ios/MobileUtils.mm From 7e5748b3a63080e7d247eefb47f13691c82cd4b3 Mon Sep 17 00:00:00 2001 From: eugenyorbitsoftcom Date: Mon, 1 Aug 2022 16:30:57 +0600 Subject: [PATCH 04/52] fix building project --- client/client.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/client.pro b/client/client.pro index 0b6b10347..84a2d7569 100644 --- a/client/client.pro +++ b/client/client.pro @@ -309,7 +309,7 @@ ios { platforms/ios/QtAppDelegate-C-Interface.h SOURCES -= \ - platforms/ios/QRCodeReader.cpp \ + platforms/ios/QRCodeReaderBase.cpp \ platforms/ios/MobileUtils.cpp SOURCES += \ From e49b468fd530159a11a52c5df5699723a3e578c8 Mon Sep 17 00:00:00 2001 From: eugenyorbitsoftcom Date: Tue, 2 Aug 2022 15:52:03 +0600 Subject: [PATCH 05/52] writeToKeychain, readFromKeychain --- client/main.cpp | 30 +++++++------- client/platforms/ios/MobileUtils.cpp | 10 ++--- client/platforms/ios/MobileUtils.h | 3 ++ client/platforms/ios/MobileUtils.mm | 62 ++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 21 deletions(-) diff --git a/client/main.cpp b/client/main.cpp index 0991144ed..327837df1 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -38,6 +38,7 @@ #include "QZXing.h" #include "platforms/ios/QRCodeReaderBase.h" +#include "platforms/ios/MobileUtils.h" #include "debug.h" #include "defines.h" @@ -143,22 +144,23 @@ int main(int argc, char *argv[]) return 0; } - QSettings oldSettings(ORGANIZATION_NAME, APPLICATION_NAME); - if (!oldSettings.allKeys().isEmpty()) { - QSettings newSettingsForPath(QSettings::Format::CustomFormat1, QSettings::UserScope, - ORGANIZATION_NAME, APPLICATION_NAME); - QString oldSettingsFileName = oldSettings.fileName(); - QString newSettingsFileName = newSettingsForPath.fileName(); - - qDebug() << "New config removed:" << QFile::remove(newSettingsFileName); - QSettings newSettings(newSettingsFileName, QSettings::Format::NativeFormat); - SecureFormat::chiperSettings(oldSettings, newSettings); - +// QSettings oldSettings(ORGANIZATION_NAME, APPLICATION_NAME); +// if (!oldSettings.allKeys().isEmpty()) { +// QSettings newSettings(QSettings::Format::CustomFormat1, QSettings::SystemScope, +// ORGANIZATION_NAME, APPLICATION_NAME); +// QString oldSettingsFileName = oldSettings.fileName(); +// QString newSettingsFileName = newSettings.fileName(); // qDebug() << "oldSettingsFileName:" << oldSettingsFileName; // qDebug() << "newSettingsFileName:" << newSettingsFileName; -// qDebug() << "Old config copied:" << QFile::copy(oldSettingsFileName, newSettingsFileName); -//// qDebug() << "Old config removed:" << QFile::remove(oldSettingsFileName); - } + +// qDebug() << "New config removed:" << QFile::remove(newSettingsFileName); +// SecureFormat::chiperSettings(oldSettings, newSettings); +//// qDebug() << "Old config copied:" << QFile::copy(oldSettingsFileName, newSettingsFileName); +////// qDebug() << "Old config removed:" << QFile::remove(oldSettingsFileName); +// } + + MobileUtils::writeToKeychain("testKey", "12345"); + qDebug() << "MobileUtils::readFromKeychain(\"testKey\"):" << MobileUtils::readFromKeychain("testKey"); Settings settings; diff --git a/client/platforms/ios/MobileUtils.cpp b/client/platforms/ios/MobileUtils.cpp index 31b58c94e..771e78559 100644 --- a/client/platforms/ios/MobileUtils.cpp +++ b/client/platforms/ios/MobileUtils.cpp @@ -1,10 +1,6 @@ #include "MobileUtils.h" -MobileUtils::MobileUtils() -{ +void MobileUtils::shareText(const QStringList&) {} -} - -void MobileUtils::shareText(const QStringList& filesToSend) { - -} +void MobileUtils::writeToKeychain(const QString&, const QString&) {} +QString MobileUtils::readFromKeychain(const QString&) { return {}; } diff --git a/client/platforms/ios/MobileUtils.h b/client/platforms/ios/MobileUtils.h index 42aa4031a..49fcdce0d 100644 --- a/client/platforms/ios/MobileUtils.h +++ b/client/platforms/ios/MobileUtils.h @@ -12,6 +12,9 @@ public: public slots: static void shareText(const QStringList& filesToSend); + + static void writeToKeychain(const QString& tag, const QString& value); + static QString readFromKeychain(const QString& tag); }; #endif // MOBILEUTILS_H diff --git a/client/platforms/ios/MobileUtils.mm b/client/platforms/ios/MobileUtils.mm index 94c7c7751..658309e3c 100644 --- a/client/platforms/ios/MobileUtils.mm +++ b/client/platforms/ios/MobileUtils.mm @@ -1,6 +1,9 @@ #include "MobileUtils.h" #include +#include + +#include static UIViewController* getViewController() { NSArray *windows = [[UIApplication sharedApplication]windows]; @@ -31,3 +34,62 @@ void MobileUtils::shareText(const QStringList& filesToSend) { popController.sourceView = qtController.view; } } + +bool deleteFromKeychain(const QString& tag) { + NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary *deleteQuery = @{ (id)kSecClass: (id)kSecClassKey, + (id)kSecAttrApplicationTag: nsTag, + }; + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)deleteQuery); + if (status != errSecSuccess) { + qDebug() << "Error deleteFromKeychain" << status; + return false; + } else { + qDebug() << "OK deleteFromKeychain"; + return true; + } +} + +void MobileUtils::writeToKeychain(const QString& tag, const QString& value) { + deleteFromKeychain(tag); + + NSData* nsValue = [value.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; + NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary* addQuery = @{ (id)kSecValueData: nsValue, + (id)kSecClass: (id)kSecClassKey, + (id)kSecAttrApplicationTag: nsTag, + }; + + OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL); + if (status != errSecSuccess) { + qDebug() << "Error writeToKeychain" << status; + } else { + qDebug() << "OK writeToKeychain"; + } +} + +QString MobileUtils::readFromKeychain(const QString& tag) { + NSData* nsValue = NULL; + NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary *getQuery = @{ (id)kSecReturnData: @YES, + (id)kSecClass: (id)kSecClassKey, + (id)kSecAttrApplicationTag: nsTag, + }; + + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)getQuery, + (CFTypeRef *)&nsValue); + if (status != errSecSuccess) { + qDebug() << "Error readFromKeychain" << status; + } else { + qDebug() << "OK readFromKeychain" << nsValue; + } + + QString result; + if (nsValue) { + result = QByteArray::fromNSData(nsValue); + CFRelease(nsValue); + } + + return result; +} From 18c0aa5c815861528d68142db4610479e94188fb Mon Sep 17 00:00:00 2001 From: eugenyorbitsoftcom Date: Wed, 3 Aug 2022 10:46:59 +0600 Subject: [PATCH 06/52] kSecClassGenericPassword --- client/platforms/ios/MobileUtils.mm | 32 ++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/client/platforms/ios/MobileUtils.mm b/client/platforms/ios/MobileUtils.mm index 658309e3c..38f06a6c8 100644 --- a/client/platforms/ios/MobileUtils.mm +++ b/client/platforms/ios/MobileUtils.mm @@ -35,10 +35,15 @@ void MobileUtils::shareText(const QStringList& filesToSend) { } } +const QString service = "org.amnezia.AmneziaVPN"; + bool deleteFromKeychain(const QString& tag) { NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary *deleteQuery = @{ (id)kSecClass: (id)kSecClassKey, - (id)kSecAttrApplicationTag: nsTag, + NSData* nsService = [service.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; + + NSDictionary *deleteQuery = @{ (id)kSecAttrService: nsService, + (id)kSecAttrAccount: nsTag, + (id)kSecClass: (id)kSecClassGenericPassword, }; OSStatus status = SecItemDelete((__bridge CFDictionaryRef)deleteQuery); @@ -54,11 +59,14 @@ bool deleteFromKeychain(const QString& tag) { void MobileUtils::writeToKeychain(const QString& tag, const QString& value) { deleteFromKeychain(tag); - NSData* nsValue = [value.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary* addQuery = @{ (id)kSecValueData: nsValue, - (id)kSecClass: (id)kSecClassKey, - (id)kSecAttrApplicationTag: nsTag, + NSData* nsService = [service.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; + NSData* nsValue = [value.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; + + NSDictionary* addQuery = @{ (id)kSecAttrService: nsService, + (id)kSecAttrAccount: nsTag, + (id)kSecClass: (id)kSecClassGenericPassword, + (id)kSecValueData: nsValue, }; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL); @@ -70,11 +78,15 @@ void MobileUtils::writeToKeychain(const QString& tag, const QString& value) { } QString MobileUtils::readFromKeychain(const QString& tag) { - NSData* nsValue = NULL; NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary *getQuery = @{ (id)kSecReturnData: @YES, - (id)kSecClass: (id)kSecClassKey, - (id)kSecAttrApplicationTag: nsTag, + NSData* nsService = [service.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; + NSData* nsValue = NULL; + + NSDictionary *getQuery = @{ (id)kSecAttrService: nsService, + (id)kSecAttrAccount: nsTag, + (id)kSecClass: (id)kSecClassGenericPassword, + (id)kSecMatchLimit: (id)kSecMatchLimitOne, + (id)kSecReturnData: @YES, }; OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)getQuery, From 06682c333f3dd512b3afa3b5340fa79dabf54dc2 Mon Sep 17 00:00:00 2001 From: eugenyorbitsoftcom Date: Wed, 3 Aug 2022 10:52:59 +0600 Subject: [PATCH 07/52] remove kSecAttrService --- client/platforms/ios/MobileUtils.mm | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/client/platforms/ios/MobileUtils.mm b/client/platforms/ios/MobileUtils.mm index 38f06a6c8..4a2e43e6b 100644 --- a/client/platforms/ios/MobileUtils.mm +++ b/client/platforms/ios/MobileUtils.mm @@ -35,14 +35,10 @@ void MobileUtils::shareText(const QStringList& filesToSend) { } } -const QString service = "org.amnezia.AmneziaVPN"; - bool deleteFromKeychain(const QString& tag) { NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - NSData* nsService = [service.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary *deleteQuery = @{ (id)kSecAttrService: nsService, - (id)kSecAttrAccount: nsTag, + NSDictionary *deleteQuery = @{ (id)kSecAttrAccount: nsTag, (id)kSecClass: (id)kSecClassGenericPassword, }; @@ -60,11 +56,9 @@ void MobileUtils::writeToKeychain(const QString& tag, const QString& value) { deleteFromKeychain(tag); NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - NSData* nsService = [service.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; NSData* nsValue = [value.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary* addQuery = @{ (id)kSecAttrService: nsService, - (id)kSecAttrAccount: nsTag, + NSDictionary* addQuery = @{ (id)kSecAttrAccount: nsTag, (id)kSecClass: (id)kSecClassGenericPassword, (id)kSecValueData: nsValue, }; @@ -79,11 +73,9 @@ void MobileUtils::writeToKeychain(const QString& tag, const QString& value) { QString MobileUtils::readFromKeychain(const QString& tag) { NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - NSData* nsService = [service.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; NSData* nsValue = NULL; - NSDictionary *getQuery = @{ (id)kSecAttrService: nsService, - (id)kSecAttrAccount: nsTag, + NSDictionary *getQuery = @{ (id)kSecAttrAccount: nsTag, (id)kSecClass: (id)kSecClassGenericPassword, (id)kSecMatchLimit: (id)kSecMatchLimitOne, (id)kSecReturnData: @YES, From 9a180b098fcd77e99f4da023856a5ebea589df34 Mon Sep 17 00:00:00 2001 From: eugenyorbitsoftcom Date: Thu, 4 Aug 2022 11:49:00 +0600 Subject: [PATCH 08/52] try read and write chipher Settings --- client/main.cpp | 36 ++++++++++-------- client/secureformat.cpp | 84 ++++++++++++++++++++++++----------------- 2 files changed, 70 insertions(+), 50 deletions(-) diff --git a/client/main.cpp b/client/main.cpp index 327837df1..748a5e5ba 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -144,26 +144,30 @@ int main(int argc, char *argv[]) return 0; } -// QSettings oldSettings(ORGANIZATION_NAME, APPLICATION_NAME); -// if (!oldSettings.allKeys().isEmpty()) { -// QSettings newSettings(QSettings::Format::CustomFormat1, QSettings::SystemScope, -// ORGANIZATION_NAME, APPLICATION_NAME); -// QString oldSettingsFileName = oldSettings.fileName(); -// QString newSettingsFileName = newSettings.fileName(); -// qDebug() << "oldSettingsFileName:" << oldSettingsFileName; -// qDebug() << "newSettingsFileName:" << newSettingsFileName; + { + Settings settingsTemp; + } -// qDebug() << "New config removed:" << QFile::remove(newSettingsFileName); -// SecureFormat::chiperSettings(oldSettings, newSettings); -//// qDebug() << "Old config copied:" << QFile::copy(oldSettingsFileName, newSettingsFileName); -////// qDebug() << "Old config removed:" << QFile::remove(oldSettingsFileName); -// } + QSettings oldSettings(ORGANIZATION_NAME, APPLICATION_NAME); + QSettings newSettings(QSettings::Format::CustomFormat1, QSettings::UserScope, + ORGANIZATION_NAME, APPLICATION_NAME); + +// QString newSettingsFileName = newSettings.fileName(); +// QFile::remove(newSettingsFileName); + + if (!oldSettings.allKeys().isEmpty() && newSettings.allKeys().isEmpty()) { + QString oldSettingsFileName = oldSettings.fileName(); + QString newSettingsFileName = newSettings.fileName(); + qDebug() << "oldSettingsFileName:" << oldSettingsFileName << QFile::exists(oldSettingsFileName) << oldSettings.isWritable(); + qDebug() << "newSettingsFileName:" << newSettingsFileName << QFile::exists(newSettingsFileName) << newSettings.isWritable(); - MobileUtils::writeToKeychain("testKey", "12345"); - qDebug() << "MobileUtils::readFromKeychain(\"testKey\"):" << MobileUtils::readFromKeychain("testKey"); + SecureFormat::chiperSettings(oldSettings, newSettings); + } + +// MobileUtils::writeToKeychain("testKey", "12345"); +// qDebug() << "MobileUtils::readFromKeychain(\"testKey\"):" << MobileUtils::readFromKeychain("testKey"); Settings settings; - if (settings.isSaveLogs()) { if (!Debug::init()) { qWarning() << "Initialization of debug subsystem failed"; diff --git a/client/secureformat.cpp b/client/secureformat.cpp index db632a0a6..8b8aaee2e 100644 --- a/client/secureformat.cpp +++ b/client/secureformat.cpp @@ -10,6 +10,15 @@ void handleErrors() { qDebug() << "handleErrors"; } +int generate_key_and_iv(unsigned char *iv, unsigned char *key) { +// unsigned char key[32]; +// unsigned char iv[16]; +// EVP_BytesToKey(EVP_aes_256_gcm(), EVP_md5(), +// NULL, +// key_file_buf, key_size, 1, // const unsigned char *data, int datal, int count, +// key, iv); +} + int gcm_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, int iv_len, @@ -112,9 +121,35 @@ int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, } } +unsigned char gcmkey[] = "12345qwerty"; +unsigned char iv[] = "000000000000"; + +QByteArray encryptText(const QString& value) { + int plainTextSize = value.toUtf8().size(); + unsigned char* plainText = new unsigned char[plainTextSize]; + std::memcpy(plainText, value.toUtf8().constData(), plainTextSize); + + unsigned char chipherText[UINT16_MAX]; + int chipherTextSize = gcm_encrypt(plainText, plainTextSize, + gcmkey, + iv, 12, + chipherText); + delete[] plainText; + return QByteArray::fromRawData((const char *)chipherText, chipherTextSize); +} + +QString decryptText(const QByteArray& qEncryptArray) { + unsigned char decryptPlainText[UINT16_MAX]; + gcm_decrypt((unsigned char*)qEncryptArray.data(), qEncryptArray.size(), + gcmkey, + iv, 12, + decryptPlainText); + return QString::fromUtf8((const char *)decryptPlainText); +} + SecureFormat::SecureFormat() { - m_format = QSettings::registerFormat("plist", + m_format = QSettings::registerFormat("sconf", readSecureFile, writeSecureFile); qDebug() << "SecureFormat" << m_format; @@ -128,9 +163,13 @@ bool SecureFormat::readSecureFile(QIODevice& device, QSettings::SettingsMap& map QTextStream inStream(&device); while (!inStream.atEnd()) { QString line = inStream.readLine(); - qDebug() << "SecureFormat::readSecureFile: " << line; + QStringList keyValue = line.split("<=>"); - map.insert(keyValue.first(), keyValue.last()); + QString key = keyValue.first(); + QString value = decryptText(keyValue.last().toUtf8()); + map.insert(key, value); + + qDebug() << "SecureFormat::readSecureFile: " << key << "<=>" << value; } return true; @@ -144,8 +183,11 @@ bool SecureFormat::writeSecureFile(QIODevice& device, const QSettings::SettingsM QTextStream outStream(&device); auto keys = map.keys(); for (auto key : keys) { - outStream << key << "<=>" << map.value(key).toString(); - qDebug() << "SecureFormat::writeSecureFile: " << key << "<=>" << map.value(key).toString(); + QString value = map.value(key).toString(); + QByteArray qEncryptArray = encryptText(value); + outStream << key << "<=>" << qEncryptArray; + + qDebug() << "SecureFormat::writeSecureFile: " << key << "<=>" << qEncryptArray; } return true; @@ -160,40 +202,14 @@ void SecureFormat::chiperSettings(const QSettings &oldSetting, QSettings &newSet keysValuesPairs.insert(currentKey, oldSetting.value(currentKey)); } - unsigned char gcmkey[] = "12345qwerty"; - unsigned char iv[] = "000000000000"; - for (const QString& key : keys) { QString value = keysValuesPairs.value(key).toString(); + QByteArray qEncryptArray = encryptText(value); - int plainTextSize = value.toUtf8().size(); - unsigned char* plainText = new unsigned char[plainTextSize]; - std::memcpy(plainText, value.toUtf8().constData(), plainTextSize); - - unsigned char chipherText[UINT16_MAX]; - int chipherTextSize = gcm_encrypt(plainText, plainTextSize, - gcmkey, - iv, 12, - chipherText); - QByteArray qChipherArray = QByteArray::fromRawData((const char *)chipherText, chipherTextSize); - -// unsigned char decryptPlainText[UINT16_MAX]; -// gcm_decrypt((unsigned char*)qChipherArray.data(), qChipherArray.size(), -// gcmkey, -// iv, 12, -// decryptPlainText); -// QString qDecryptPlainText = QString::fromUtf8((const char *)decryptPlainText); -// qDebug() << "qDecryptPlainText:" << qDecryptPlainText; - - newSetting.setValue(key, qChipherArray); + newSetting.setValue(key, qEncryptArray); } -// newSetting.sync(); -// qDebug() << "newSetting.allKeys(): " << newSetting.allKeys(); -// for (const QString& key : newSetting.allKeys()) { -// QString value = keysValuesPairs.value(key).toString(); -// qDebug() << "newSetting value: " << value; -// } + newSetting.sync(); } const QSettings::Format& SecureFormat::format() const{ From 870cb26e01a3f622b8f069c529d2edea3320489e Mon Sep 17 00:00:00 2001 From: eugenyorbitsoftcom Date: Fri, 5 Aug 2022 14:15:11 +0600 Subject: [PATCH 09/52] new line --- client/secureformat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/secureformat.cpp b/client/secureformat.cpp index 8b8aaee2e..5112a6015 100644 --- a/client/secureformat.cpp +++ b/client/secureformat.cpp @@ -185,7 +185,7 @@ bool SecureFormat::writeSecureFile(QIODevice& device, const QSettings::SettingsM for (auto key : keys) { QString value = map.value(key).toString(); QByteArray qEncryptArray = encryptText(value); - outStream << key << "<=>" << qEncryptArray; + outStream << key << "<=>" << qEncryptArray << "\n"; qDebug() << "SecureFormat::writeSecureFile: " << key << "<=>" << qEncryptArray; } From 71b57bfed1fbe0cd58b248a6bcc9bb155369726c Mon Sep 17 00:00:00 2001 From: pokamest Date: Fri, 5 Aug 2022 14:31:12 +0300 Subject: [PATCH 10/52] Secure settings 2 --- client/client.pro | 2 ++ client/secure_qsettings.cpp | 47 +++++++++++++++++++++++++++++ client/secure_qsettings.h | 22 ++++++++++++++ client/secureformat.cpp | 59 +++++++++++++++++++------------------ client/secureformat.h | 3 ++ client/settings.cpp | 7 ++--- client/settings.h | 5 ++-- 7 files changed, 110 insertions(+), 35 deletions(-) create mode 100644 client/secure_qsettings.cpp create mode 100644 client/secure_qsettings.h diff --git a/client/client.pro b/client/client.pro index 84a2d7569..0b8cf83af 100644 --- a/client/client.pro +++ b/client/client.pro @@ -41,6 +41,7 @@ HEADERS += \ platforms/ios/MobileUtils.h \ platforms/linux/leakdetector.h \ protocols/protocols_defs.h \ + secure_qsettings.h \ secureformat.h \ settings.h \ ui/notificationhandler.h \ @@ -100,6 +101,7 @@ SOURCES += \ platforms/ios/MobileUtils.cpp \ platforms/linux/leakdetector.cpp \ protocols/protocols_defs.cpp \ + secure_qsettings.cpp \ secureformat.cpp \ settings.cpp \ ui/notificationhandler.cpp \ diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp new file mode 100644 index 000000000..a9beb1128 --- /dev/null +++ b/client/secure_qsettings.cpp @@ -0,0 +1,47 @@ +#include "secure_qsettings.h" +#include "secureformat.h" + +#include + +SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent) + : QObject{parent}, + m_setting(organization, application, parent) +{ + encrypted = m_setting.value("encrypted").toBool(); + + // convert settings to encrypted + if (! encrypted) { + // TODO: convert + // m_setting.sync(); + } +} + +QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue) const +{ + if (encrypted) { + QByteArray encryptedValue = m_setting.value(key, defaultValue).toByteArray(); + QByteArray decryptedValue = decryptText(encryptedValue); + + QDataStream ds(&decryptedValue, QIODevice::ReadOnly); + QVariant v; + ds >> v; + return v; + } + else { + return m_setting.value(key, defaultValue); + } +} + +void SecureQSettings::setValue(const QString &key, const QVariant &value) +{ + QByteArray decryptedValue; + { + QDataStream ds(&decryptedValue, QIODevice::WriteOnly); + ds << value; + } + + QByteArray encryptedValue = encryptText(decryptedValue); + m_setting.setValue(key, encryptedValue); +} + + diff --git a/client/secure_qsettings.h b/client/secure_qsettings.h new file mode 100644 index 000000000..a7f32f64a --- /dev/null +++ b/client/secure_qsettings.h @@ -0,0 +1,22 @@ +#ifndef SECUREQSETTINGS_H +#define SECUREQSETTINGS_H + +#include +#include + +class SecureQSettings : public QObject +{ +public: + explicit SecureQSettings(const QString &organization, const QString &application = QString(), QObject *parent = nullptr); + + QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; + void setValue(const QString &key, const QVariant &value); + void sync() { m_setting.sync(); } + void remove(const QString &key) { m_setting.remove(key); } + +private: + QSettings m_setting; + bool encrypted {false}; +}; + +#endif // SECUREQSETTINGS_H diff --git a/client/secureformat.cpp b/client/secureformat.cpp index 5112a6015..6dfe185cf 100644 --- a/client/secureformat.cpp +++ b/client/secureformat.cpp @@ -17,6 +17,7 @@ int generate_key_and_iv(unsigned char *iv, unsigned char *key) { // NULL, // key_file_buf, key_size, 1, // const unsigned char *data, int datal, int count, // key, iv); + return 0; } int gcm_encrypt(unsigned char *plaintext, int plaintext_len, @@ -124,10 +125,10 @@ int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char gcmkey[] = "12345qwerty"; unsigned char iv[] = "000000000000"; -QByteArray encryptText(const QString& value) { - int plainTextSize = value.toUtf8().size(); +QByteArray encryptText(const QByteArray& value) { + int plainTextSize = value.size(); unsigned char* plainText = new unsigned char[plainTextSize]; - std::memcpy(plainText, value.toUtf8().constData(), plainTextSize); + std::memcpy(plainText, value.constData(), plainTextSize); unsigned char chipherText[UINT16_MAX]; int chipherTextSize = gcm_encrypt(plainText, plainTextSize, @@ -138,13 +139,13 @@ QByteArray encryptText(const QString& value) { return QByteArray::fromRawData((const char *)chipherText, chipherTextSize); } -QString decryptText(const QByteArray& qEncryptArray) { +QByteArray decryptText(const QByteArray& qEncryptArray) { unsigned char decryptPlainText[UINT16_MAX]; gcm_decrypt((unsigned char*)qEncryptArray.data(), qEncryptArray.size(), gcmkey, iv, 12, decryptPlainText); - return QString::fromUtf8((const char *)decryptPlainText); + return QByteArray::fromRawData((const char *)decryptPlainText, qEncryptArray.size()); } SecureFormat::SecureFormat() @@ -176,40 +177,40 @@ bool SecureFormat::readSecureFile(QIODevice& device, QSettings::SettingsMap& map } bool SecureFormat::writeSecureFile(QIODevice& device, const QSettings::SettingsMap& map) { - if (!device.isOpen()) { - return false; - } +// if (!device.isOpen()) { +// return false; +// } - QTextStream outStream(&device); - auto keys = map.keys(); - for (auto key : keys) { - QString value = map.value(key).toString(); - QByteArray qEncryptArray = encryptText(value); - outStream << key << "<=>" << qEncryptArray << "\n"; +// QTextStream outStream(&device); +// auto keys = map.keys(); +// for (auto key : keys) { +// QString value = map.value(key).toString(); +// QByteArray qEncryptArray = encryptText(value); +// outStream << key << "<=>" << qEncryptArray << "\n"; - qDebug() << "SecureFormat::writeSecureFile: " << key << "<=>" << qEncryptArray; - } +// qDebug() << "SecureFormat::writeSecureFile: " << key << "<=>" << qEncryptArray; +// } return true; } void SecureFormat::chiperSettings(const QSettings &oldSetting, QSettings &newSetting) { - QVariantMap keysValuesPairs; - QStringList keys = oldSetting.allKeys(); - QStringListIterator it(keys); - while ( it.hasNext() ) { - QString currentKey = it.next(); - keysValuesPairs.insert(currentKey, oldSetting.value(currentKey)); - } +// QVariantMap keysValuesPairs; +// QStringList keys = oldSetting.allKeys(); +// QStringListIterator it(keys); +// while ( it.hasNext() ) { +// QString currentKey = it.next(); +// keysValuesPairs.insert(currentKey, oldSetting.value(currentKey)); +// } - for (const QString& key : keys) { - QString value = keysValuesPairs.value(key).toString(); - QByteArray qEncryptArray = encryptText(value); +// for (const QString& key : keys) { +// QString value = keysValuesPairs.value(key).toString(); +// QByteArray qEncryptArray = encryptText(value); - newSetting.setValue(key, qEncryptArray); - } +// newSetting.setValue(key, qEncryptArray); +// } - newSetting.sync(); +// newSetting.sync(); } const QSettings::Format& SecureFormat::format() const{ diff --git a/client/secureformat.h b/client/secureformat.h index 32e6d5991..c49ed2148 100644 --- a/client/secureformat.h +++ b/client/secureformat.h @@ -4,6 +4,9 @@ #include #include +QByteArray encryptText(const QByteArray &value); +QByteArray decryptText(const QByteArray& qEncryptArray); + class SecureFormat { public: diff --git a/client/settings.cpp b/client/settings.cpp index e35a14ace..c8069f70f 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -8,15 +8,14 @@ const char Settings::cloudFlareNs1[] = "1.1.1.1"; const char Settings::cloudFlareNs2[] = "1.0.0.1"; -SecureFormat Settings::m_secureFormat; +//SecureFormat Settings::m_secureFormat; Settings::Settings(QObject* parent) : QObject(parent), - m_settings(m_secureFormat.format(), QSettings::UserScope, - ORGANIZATION_NAME, APPLICATION_NAME, this) + m_settings(ORGANIZATION_NAME, APPLICATION_NAME, this) { qDebug() << "Settings::Settings()" << this; - qDebug() << "Settings::Settings()" << m_settings.fileName(); +// qDebug() << "Settings::Settings()" << m_settings.fileName(); // Import old settings if (serversCount() == 0) { QString user = m_settings.value("Server/userName").toString(); diff --git a/client/settings.h b/client/settings.h index 7b0066b90..082db8912 100644 --- a/client/settings.h +++ b/client/settings.h @@ -12,6 +12,7 @@ #include "core/defs.h" #include "containers/containers_defs.h" #include "secureformat.h" +#include "secure_qsettings.h" using namespace amnezia; @@ -112,8 +113,8 @@ public: // static constexpr char openNicNs13[] = "144.76.103.143"; private: - static SecureFormat m_secureFormat; - QSettings m_settings; + //static SecureFormat m_secureFormat; + SecureQSettings m_settings; }; #endif // SETTINGS_H From 1e85b25438ab1b987aacf961cc0c136dc5f7b2ff Mon Sep 17 00:00:00 2001 From: pokamest Date: Fri, 5 Aug 2022 18:59:47 +0300 Subject: [PATCH 11/52] Backup/restore config --- client/main.cpp | 14 ---- client/secure_qsettings.cpp | 87 +++++++++++++++++++--- client/secure_qsettings.h | 11 ++- client/secureformat.cpp | 64 ---------------- client/secureformat.h | 6 -- client/settings.h | 4 +- client/ui/pages_logic/AppSettingsLogic.cpp | 23 ++++++ client/ui/pages_logic/AppSettingsLogic.h | 4 + client/ui/pages_logic/StartPageLogic.cpp | 2 - client/ui/pages_logic/StartPageLogic.h | 1 - client/ui/qml/Pages/PageAppSetting.qml | 29 +++++++- client/ui/qml/Pages/PageStart.qml | 15 +++- 12 files changed, 155 insertions(+), 105 deletions(-) diff --git a/client/main.cpp b/client/main.cpp index 748a5e5ba..196d5cec9 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -148,21 +148,7 @@ int main(int argc, char *argv[]) Settings settingsTemp; } - QSettings oldSettings(ORGANIZATION_NAME, APPLICATION_NAME); - QSettings newSettings(QSettings::Format::CustomFormat1, QSettings::UserScope, - ORGANIZATION_NAME, APPLICATION_NAME); - -// QString newSettingsFileName = newSettings.fileName(); -// QFile::remove(newSettingsFileName); - - if (!oldSettings.allKeys().isEmpty() && newSettings.allKeys().isEmpty()) { - QString oldSettingsFileName = oldSettings.fileName(); - QString newSettingsFileName = newSettings.fileName(); - qDebug() << "oldSettingsFileName:" << oldSettingsFileName << QFile::exists(oldSettingsFileName) << oldSettings.isWritable(); - qDebug() << "newSettingsFileName:" << newSettingsFileName << QFile::exists(newSettingsFileName) << newSettings.isWritable(); - SecureFormat::chiperSettings(oldSettings, newSettings); - } // MobileUtils::writeToKeychain("testKey", "12345"); // qDebug() << "MobileUtils::readFromKeychain(\"testKey\"):" << MobileUtils::readFromKeychain("testKey"); diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index a9beb1128..b2eeecbcd 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -2,34 +2,52 @@ #include "secureformat.h" #include +#include SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent) : QObject{parent}, - m_setting(organization, application, parent) + m_setting(organization, application, parent), + encryptedKeys({"Servers/serversList"}) { - encrypted = m_setting.value("encrypted").toBool(); + encrypted = m_setting.value("Conf/encrypted").toBool(); // convert settings to encrypted if (! encrypted) { - // TODO: convert - // m_setting.sync(); + for (const QString &key : m_setting.allKeys()) { + if (encryptedKeys.contains(key)) { + const QVariant &val = value(key); + setValue(key, val); + } + } + m_setting.setValue("Conf/encrypted", true); + m_setting.sync(); + encrypted = true; } } QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue) const { - if (encrypted) { - QByteArray encryptedValue = m_setting.value(key, defaultValue).toByteArray(); + if (m_cache.contains(key)) { + return m_cache.value(key); + } + + QVariant retVal; + if (encrypted && encryptedKeys.contains(key)) { + if (!m_setting.contains(key)) return defaultValue; + + QByteArray encryptedValue = m_setting.value(key).toByteArray(); QByteArray decryptedValue = decryptText(encryptedValue); QDataStream ds(&decryptedValue, QIODevice::ReadOnly); - QVariant v; - ds >> v; - return v; + ds >> retVal; } else { - return m_setting.value(key, defaultValue); + retVal = m_setting.value(key, defaultValue); } + + m_cache.insert(key, retVal); + + return retVal; } void SecureQSettings::setValue(const QString &key, const QVariant &value) @@ -42,6 +60,55 @@ void SecureQSettings::setValue(const QString &key, const QVariant &value) QByteArray encryptedValue = encryptText(decryptedValue); m_setting.setValue(key, encryptedValue); + m_cache.insert(key, value); + + sync(); +} + +void SecureQSettings::remove(const QString &key) +{ + m_setting.remove(key); + m_cache.remove(key); + + sync(); +} + +void SecureQSettings::sync() +{ + m_setting.sync(); +} + +QByteArray SecureQSettings::backupAppConfig() const +{ + QMap cfg; + for (const QString &key : m_setting.allKeys()) { + cfg.insert(key, value(key)); + } + + QByteArray ba; + { + QDataStream ds(&ba, QIODevice::WriteOnly); + ds << cfg; + } + + return ba.toBase64(); +} + +void SecureQSettings::restoreAppConfig(const QByteArray &base64Cfg) +{ + QByteArray ba = QByteArray::fromBase64(base64Cfg); + QMap cfg; + + { + QDataStream ds(&ba, QIODevice::ReadOnly); + ds >> cfg; + } + + for (const QString &key : cfg.keys()) { + setValue(key, cfg.value(key)); + } + + sync(); } diff --git a/client/secure_qsettings.h b/client/secure_qsettings.h index a7f32f64a..113757a66 100644 --- a/client/secure_qsettings.h +++ b/client/secure_qsettings.h @@ -11,12 +11,19 @@ public: QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; void setValue(const QString &key, const QVariant &value); - void sync() { m_setting.sync(); } - void remove(const QString &key) { m_setting.remove(key); } + void remove(const QString &key); + void sync(); + + QByteArray backupAppConfig() const; + void restoreAppConfig(const QByteArray &base64Cfg); private: QSettings m_setting; bool encrypted {false}; + + mutable QMap m_cache; + + QStringList encryptedKeys; // encode only key listed here }; #endif // SECUREQSETTINGS_H diff --git a/client/secureformat.cpp b/client/secureformat.cpp index 6dfe185cf..1acdeea74 100644 --- a/client/secureformat.cpp +++ b/client/secureformat.cpp @@ -148,71 +148,7 @@ QByteArray decryptText(const QByteArray& qEncryptArray) { return QByteArray::fromRawData((const char *)decryptPlainText, qEncryptArray.size()); } -SecureFormat::SecureFormat() -{ - m_format = QSettings::registerFormat("sconf", - readSecureFile, - writeSecureFile); - qDebug() << "SecureFormat" << m_format; -} -bool SecureFormat::readSecureFile(QIODevice& device, QSettings::SettingsMap& map) { - if (!device.isOpen()) { - return false; - } - QTextStream inStream(&device); - while (!inStream.atEnd()) { - QString line = inStream.readLine(); - QStringList keyValue = line.split("<=>"); - QString key = keyValue.first(); - QString value = decryptText(keyValue.last().toUtf8()); - map.insert(key, value); - qDebug() << "SecureFormat::readSecureFile: " << key << "<=>" << value; - } - - return true; -} - -bool SecureFormat::writeSecureFile(QIODevice& device, const QSettings::SettingsMap& map) { -// if (!device.isOpen()) { -// return false; -// } - -// QTextStream outStream(&device); -// auto keys = map.keys(); -// for (auto key : keys) { -// QString value = map.value(key).toString(); -// QByteArray qEncryptArray = encryptText(value); -// outStream << key << "<=>" << qEncryptArray << "\n"; - -// qDebug() << "SecureFormat::writeSecureFile: " << key << "<=>" << qEncryptArray; -// } - - return true; -} - -void SecureFormat::chiperSettings(const QSettings &oldSetting, QSettings &newSetting) { -// QVariantMap keysValuesPairs; -// QStringList keys = oldSetting.allKeys(); -// QStringListIterator it(keys); -// while ( it.hasNext() ) { -// QString currentKey = it.next(); -// keysValuesPairs.insert(currentKey, oldSetting.value(currentKey)); -// } - -// for (const QString& key : keys) { -// QString value = keysValuesPairs.value(key).toString(); -// QByteArray qEncryptArray = encryptText(value); - -// newSetting.setValue(key, qEncryptArray); -// } - -// newSetting.sync(); -} - -const QSettings::Format& SecureFormat::format() const{ - return m_format; -} diff --git a/client/secureformat.h b/client/secureformat.h index c49ed2148..04a25b64c 100644 --- a/client/secureformat.h +++ b/client/secureformat.h @@ -12,15 +12,9 @@ class SecureFormat public: SecureFormat(); - static bool readSecureFile(QIODevice &device, QSettings::SettingsMap &map); - static bool writeSecureFile(QIODevice &device, const QSettings::SettingsMap &map); - static void chiperSettings(const QSettings &oldSetting, QSettings &newSetting); - const QSettings::Format& format() const; -private: - QSettings::Format m_format; }; #endif // SECUREFORMAT_H diff --git a/client/settings.h b/client/settings.h index 082db8912..4241f1518 100644 --- a/client/settings.h +++ b/client/settings.h @@ -112,8 +112,10 @@ public: // static constexpr char openNicNs5[] = "94.103.153.176"; // static constexpr char openNicNs13[] = "144.76.103.143"; + QByteArray backupAppConfig() const { return m_settings.backupAppConfig(); } + void restoreAppConfig(const QByteArray &cfg) { m_settings.restoreAppConfig(cfg); } + private: - //static SecureFormat m_secureFormat; SecureQSettings m_settings; }; diff --git a/client/ui/pages_logic/AppSettingsLogic.cpp b/client/ui/pages_logic/AppSettingsLogic.cpp index 6429fc960..ccdb5071c 100644 --- a/client/ui/pages_logic/AppSettingsLogic.cpp +++ b/client/ui/pages_logic/AppSettingsLogic.cpp @@ -74,3 +74,26 @@ void AppSettingsLogic::onPushButtonClearLogsClicked() Debug::clearLogs(); Debug::clearServiceLogs(); } + +void AppSettingsLogic::onPushButtonBackupAppConfigClicked() +{ + uiLogic()->saveTextFile("Backup application config", "AmneziaVPN.backup", ".backup", m_settings.backupAppConfig()); +} + +void AppSettingsLogic::onPushButtonRestoreAppConfigClicked() +{ + QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open backup"), + QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.backup"); + + if (fileName.isEmpty()) return; + + QFile file(fileName); + file.open(QIODevice::ReadOnly); + QByteArray data = file.readAll(); + + m_settings.restoreAppConfig(data); + + emit uiLogic()->goToPage(Page::Vpn); + emit uiLogic()->setStartPage(Page::Vpn); +} + diff --git a/client/ui/pages_logic/AppSettingsLogic.h b/client/ui/pages_logic/AppSettingsLogic.h index b597b129b..fc9f0da7e 100644 --- a/client/ui/pages_logic/AppSettingsLogic.h +++ b/client/ui/pages_logic/AppSettingsLogic.h @@ -25,6 +25,10 @@ public: Q_INVOKABLE void onPushButtonExportLogsClicked(); Q_INVOKABLE void onPushButtonClearLogsClicked(); + Q_INVOKABLE void onPushButtonBackupAppConfigClicked(); + Q_INVOKABLE void onPushButtonRestoreAppConfigClicked(); + + public: explicit AppSettingsLogic(UiLogic *uiLogic, QObject *parent = nullptr); ~AppSettingsLogic() = default; diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index e8b3f2698..c21aa6f62 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -24,7 +24,6 @@ StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent): m_labelWaitInfoVisible{true}, m_labelWaitInfoText{}, m_pushButtonBackFromStartVisible{true}, - m_pushButtonConnectVisible{true}, m_ipAddressPortRegex{Utils::ipAddressPortRegExp()} { @@ -41,7 +40,6 @@ void StartPageLogic::onUpdatePage() set_labelWaitInfoVisible(false); set_labelWaitInfoText(""); - set_pushButtonConnectVisible(true); set_pushButtonConnectKeyChecked(false); diff --git a/client/ui/pages_logic/StartPageLogic.h b/client/ui/pages_logic/StartPageLogic.h index f5f132f89..24bdc53fe 100644 --- a/client/ui/pages_logic/StartPageLogic.h +++ b/client/ui/pages_logic/StartPageLogic.h @@ -20,7 +20,6 @@ class StartPageLogic : public PageLogicBase AUTO_PROPERTY(bool, labelWaitInfoVisible) AUTO_PROPERTY(QString, labelWaitInfoText) AUTO_PROPERTY(bool, pushButtonBackFromStartVisible) - AUTO_PROPERTY(bool, pushButtonConnectVisible) READONLY_PROPERTY(QRegExp, ipAddressPortRegex) public: diff --git a/client/ui/qml/Pages/PageAppSetting.qml b/client/ui/qml/Pages/PageAppSetting.qml index b795ceb55..7e8d415ab 100644 --- a/client/ui/qml/Pages/PageAppSetting.qml +++ b/client/ui/qml/Pages/PageAppSetting.qml @@ -107,7 +107,7 @@ PageBase { BlueButtonType { Layout.fillWidth: true - Layout.topMargin: 15 + Layout.topMargin: 10 Layout.preferredHeight: 41 text: qsTr("Export logs") onClicked: { @@ -117,7 +117,7 @@ PageBase { BlueButtonType { Layout.fillWidth: true - Layout.topMargin: 15 + Layout.topMargin: 10 Layout.preferredHeight: 41 property string start_text: qsTr("Clear logs") @@ -135,6 +135,31 @@ PageBase { AppSettingsLogic.onPushButtonClearLogsClicked() } } + + LabelType { + Layout.fillWidth: true + Layout.topMargin: 30 + text: qsTr("Backup and restore configuration") + } + + BlueButtonType { + Layout.fillWidth: true + Layout.topMargin: 10 + Layout.preferredHeight: 41 + text: qsTr("Backup app config") + onClicked: { + AppSettingsLogic.onPushButtonBackupAppConfigClicked() + } + } + BlueButtonType { + Layout.fillWidth: true + Layout.topMargin: 10 + Layout.preferredHeight: 41 + text: qsTr("Restore app config") + onClicked: { + AppSettingsLogic.onPushButtonRestoreAppConfigClicked() + } + } } } diff --git a/client/ui/qml/Pages/PageStart.qml b/client/ui/qml/Pages/PageStart.qml index 3ff11a863..ab53792d2 100644 --- a/client/ui/qml/Pages/PageStart.qml +++ b/client/ui/qml/Pages/PageStart.qml @@ -119,7 +119,6 @@ PageBase { anchors.topMargin: 40 text: qsTr("Open file") - visible: StartPageLogic.pushButtonConnectVisible onClicked: { StartPageLogic.onPushButtonImportOpenFile() } @@ -133,7 +132,6 @@ PageBase { anchors.topMargin: 10 text: qsTr("Scan QR code") - visible: StartPageLogic.pushButtonConnectVisible onClicked: { if (Qt.platform.os == "ios") { UiLogic.goToPage(PageEnum.QrDecoderIos) @@ -144,7 +142,19 @@ PageBase { enabled: StartPageLogic.pushButtonConnectEnabled } + BlueButtonType { + id: btn_restore_cfg + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: qr_code_import.bottom + anchors.topMargin: 30 + visible: UiLogic.pagesStackDepth == 1 + enabled: StartPageLogic.pushButtonConnectEnabled + text: qsTr("Restore app config") + onClicked: { + AppSettingsLogic.onPushButtonRestoreAppConfigClicked() + } + } } @@ -270,7 +280,6 @@ PageBase { anchors.topMargin: 10 text: StartPageLogic.pushButtonConnectText - visible: StartPageLogic.pushButtonConnectVisible onClicked: { StartPageLogic.onPushButtonConnect() } From 585de53148ef9abbcb0817cbbd47b0a96d874617 Mon Sep 17 00:00:00 2001 From: pokamest Date: Sat, 6 Aug 2022 19:47:29 +0300 Subject: [PATCH 12/52] Secure settings refactoring --- client/client.pro | 4 +- ...secureformat.cpp => encryption_helper.cpp} | 63 ++++++++----------- client/encryption_helper.h | 31 +++++++++ client/secure_qsettings.cpp | 62 ++++++++++++++---- client/secure_qsettings.h | 13 +++- client/secureformat.h | 20 ------ client/settings.h | 2 +- 7 files changed, 122 insertions(+), 73 deletions(-) rename client/{secureformat.cpp => encryption_helper.cpp} (70%) create mode 100644 client/encryption_helper.h delete mode 100644 client/secureformat.h diff --git a/client/client.pro b/client/client.pro index 0b8cf83af..9d2180f75 100644 --- a/client/client.pro +++ b/client/client.pro @@ -37,12 +37,12 @@ HEADERS += \ core/servercontroller.h \ debug.h \ defines.h \ + encryption_helper.h \ managementserver.h \ platforms/ios/MobileUtils.h \ platforms/linux/leakdetector.h \ protocols/protocols_defs.h \ secure_qsettings.h \ - secureformat.h \ settings.h \ ui/notificationhandler.h \ ui/models/containers_model.h \ @@ -96,13 +96,13 @@ SOURCES += \ core/server_defs.cpp \ core/servercontroller.cpp \ debug.cpp \ + encryption_helper.cpp \ main.cpp \ managementserver.cpp \ platforms/ios/MobileUtils.cpp \ platforms/linux/leakdetector.cpp \ protocols/protocols_defs.cpp \ secure_qsettings.cpp \ - secureformat.cpp \ settings.cpp \ ui/notificationhandler.cpp \ ui/models/containers_model.cpp \ diff --git a/client/secureformat.cpp b/client/encryption_helper.cpp similarity index 70% rename from client/secureformat.cpp rename to client/encryption_helper.cpp index 1acdeea74..6c1bffda8 100644 --- a/client/secureformat.cpp +++ b/client/encryption_helper.cpp @@ -1,4 +1,4 @@ -#include "secureformat.h" +#include "encryption_helper.h" #include #include @@ -6,6 +6,25 @@ #include "openssl/evp.h" +int gcm_encrypt(const char *plaintext, int plaintext_len, + const char *key, const char *iv, int iv_len, + char *ciphertext) +{ + return gcm_encrypt((uchar*)plaintext, plaintext_len, + (uchar*)key, (uchar*)iv, iv_len, + (uchar*)ciphertext); +} + +int gcm_decrypt(const char *ciphertext, int ciphertext_len, + const char *key, + const char *iv, int iv_len, + char *plaintext) +{ + return gcm_decrypt((uchar*)ciphertext, ciphertext_len, + (uchar*)key, (uchar*)iv, iv_len, + (uchar*)plaintext); +} + void handleErrors() { qDebug() << "handleErrors"; } @@ -20,9 +39,9 @@ int generate_key_and_iv(unsigned char *iv, unsigned char *key) { return 0; } -int gcm_encrypt(unsigned char *plaintext, int plaintext_len, - unsigned char *key, - unsigned char *iv, int iv_len, +int gcm_encrypt(const unsigned char *plaintext, int plaintext_len, + const unsigned char *key, + const unsigned char *iv, int iv_len, unsigned char *ciphertext) { EVP_CIPHER_CTX *ctx; @@ -69,9 +88,9 @@ int gcm_encrypt(unsigned char *plaintext, int plaintext_len, return ciphertext_len; } -int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, - unsigned char *key, - unsigned char *iv, int iv_len, +int gcm_decrypt(const unsigned char *ciphertext, int ciphertext_len, + const unsigned char *key, + const unsigned char *iv, int iv_len, unsigned char *plaintext) { EVP_CIPHER_CTX *ctx; @@ -122,33 +141,3 @@ int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, } } -unsigned char gcmkey[] = "12345qwerty"; -unsigned char iv[] = "000000000000"; - -QByteArray encryptText(const QByteArray& value) { - int plainTextSize = value.size(); - unsigned char* plainText = new unsigned char[plainTextSize]; - std::memcpy(plainText, value.constData(), plainTextSize); - - unsigned char chipherText[UINT16_MAX]; - int chipherTextSize = gcm_encrypt(plainText, plainTextSize, - gcmkey, - iv, 12, - chipherText); - delete[] plainText; - return QByteArray::fromRawData((const char *)chipherText, chipherTextSize); -} - -QByteArray decryptText(const QByteArray& qEncryptArray) { - unsigned char decryptPlainText[UINT16_MAX]; - gcm_decrypt((unsigned char*)qEncryptArray.data(), qEncryptArray.size(), - gcmkey, - iv, 12, - decryptPlainText); - return QByteArray::fromRawData((const char *)decryptPlainText, qEncryptArray.size()); -} - - - - - diff --git a/client/encryption_helper.h b/client/encryption_helper.h new file mode 100644 index 000000000..ba9214087 --- /dev/null +++ b/client/encryption_helper.h @@ -0,0 +1,31 @@ +#ifndef ENCRYPTION_HELPER_H +#define ENCRYPTION_HELPER_H + +#include +#include + + + +int gcm_encrypt(const char *plaintext, int plaintext_len, + const char *key, + const char *iv, int iv_len, + char *ciphertext); + +int gcm_decrypt(const char *ciphertext, int ciphertext_len, + const char *key, + const char *iv, int iv_len, + char *plaintext); + + +int gcm_encrypt(const unsigned char *plaintext, int plaintext_len, + const unsigned char *key, + const unsigned char *iv, int iv_len, + unsigned char *ciphertext); + +int gcm_decrypt(const unsigned char *ciphertext, int ciphertext_len, + const unsigned char *key, + const unsigned char *iv, int iv_len, + unsigned char *plaintext); + + +#endif // ENCRYPTION_HELPER_H diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index b2eeecbcd..8faed6b15 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -1,5 +1,5 @@ #include "secure_qsettings.h" -#include "secureformat.h" +#include "encryption_helper.h" #include #include @@ -9,10 +9,18 @@ SecureQSettings::SecureQSettings(const QString &organization, const QString &app m_setting(organization, application, parent), encryptedKeys({"Servers/serversList"}) { - encrypted = m_setting.value("Conf/encrypted").toBool(); + // load keys from system key storage +#ifdef Q_OS_IOS + key = MobileUtils::readFromKeychain(settingsKeyTag); + iv = MobileUtils::readFromKeychain(settingsIvTag); +#endif + key = "12345qwerty00000"; + iv = "000000000000000"; + + bool encrypted = m_setting.value("Conf/encrypted").toBool(); // convert settings to encrypted - if (! encrypted) { + if (encryptionRequired() && ! encrypted) { for (const QString &key : m_setting.allKeys()) { if (encryptedKeys.contains(key)) { const QVariant &val = value(key); @@ -21,7 +29,6 @@ SecureQSettings::SecureQSettings(const QString &organization, const QString &app } m_setting.setValue("Conf/encrypted", true); m_setting.sync(); - encrypted = true; } } @@ -32,7 +39,7 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue } QVariant retVal; - if (encrypted && encryptedKeys.contains(key)) { + if (encryptionRequired() && encryptedKeys.contains(key)) { if (!m_setting.contains(key)) return defaultValue; QByteArray encryptedValue = m_setting.value(key).toByteArray(); @@ -52,16 +59,21 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue void SecureQSettings::setValue(const QString &key, const QVariant &value) { - QByteArray decryptedValue; - { - QDataStream ds(&decryptedValue, QIODevice::WriteOnly); - ds << value; + if (encryptionRequired() && encryptedKeys.contains(key)) { + QByteArray decryptedValue; + { + QDataStream ds(&decryptedValue, QIODevice::WriteOnly); + ds << value; + } + + QByteArray encryptedValue = encryptText(decryptedValue); + m_setting.setValue(key, encryptedValue); + } + else { + m_setting.setValue(key, value); } - QByteArray encryptedValue = encryptText(decryptedValue); - m_setting.setValue(key, encryptedValue); m_cache.insert(key, value); - sync(); } @@ -112,3 +124,29 @@ void SecureQSettings::restoreAppConfig(const QByteArray &base64Cfg) } +QByteArray SecureQSettings::encryptText(const QByteArray& value) const { + char cipherText[UINT16_MAX]; + int cipherTextSize = gcm_encrypt(value.constData(), value.size(), + key.constData(), iv.constData(), iv_len, cipherText); + + return QByteArray::fromRawData((const char *)cipherText, cipherTextSize); +} + +QByteArray SecureQSettings::decryptText(const QByteArray& ba) const { + char decryptPlainText[UINT16_MAX]; + gcm_decrypt(ba.data(), ba.size(), + key.constData(), iv.constData(), iv_len, decryptPlainText); + + return QByteArray::fromRawData(decryptPlainText, ba.size()); +} + +bool SecureQSettings::encryptionRequired() const +{ +#if defined Q_OS_ANDROID || defined Q_OS_IOS + return true; +#endif + + return false; +} + + diff --git a/client/secure_qsettings.h b/client/secure_qsettings.h index 113757a66..3fcd4ed7c 100644 --- a/client/secure_qsettings.h +++ b/client/secure_qsettings.h @@ -4,6 +4,9 @@ #include #include +constexpr const char* settingsKeyTag = "settingsKeyTag"; +constexpr const char* settingsIvTag = "settingsIvTag"; + class SecureQSettings : public QObject { public: @@ -17,13 +20,21 @@ public: QByteArray backupAppConfig() const; void restoreAppConfig(const QByteArray &base64Cfg); + QByteArray encryptText(const QByteArray &value) const; + QByteArray decryptText(const QByteArray& ba) const; + + bool encryptionRequired() const; + private: QSettings m_setting; - bool encrypted {false}; mutable QMap m_cache; QStringList encryptedKeys; // encode only key listed here + + QByteArray key; + QByteArray iv; + int iv_len {16}; }; #endif // SECUREQSETTINGS_H diff --git a/client/secureformat.h b/client/secureformat.h deleted file mode 100644 index 04a25b64c..000000000 --- a/client/secureformat.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SECUREFORMAT_H -#define SECUREFORMAT_H - -#include -#include - -QByteArray encryptText(const QByteArray &value); -QByteArray decryptText(const QByteArray& qEncryptArray); - -class SecureFormat -{ -public: - SecureFormat(); - - - - -}; - -#endif // SECUREFORMAT_H diff --git a/client/settings.h b/client/settings.h index 4241f1518..39c9919c0 100644 --- a/client/settings.h +++ b/client/settings.h @@ -11,7 +11,7 @@ #include "core/defs.h" #include "containers/containers_defs.h" -#include "secureformat.h" +#include "encryption_helper.h" #include "secure_qsettings.h" using namespace amnezia; From 3bff653bbb83865b6c941fc6a07d628c2d7fa388 Mon Sep 17 00:00:00 2001 From: pokamest Date: Wed, 10 Aug 2022 22:15:00 +0300 Subject: [PATCH 13/52] IpcServerProcess permit list --- client/defines.h | 4 +-- .../protocols/ikev2_vpn_protocol_windows.cpp | 2 +- client/protocols/openvpnprotocol.cpp | 15 ++------- client/protocols/openvpnprotocol.h | 1 - client/protocols/wireguardprotocol.cpp | 19 +++-------- client/protocols/wireguardprotocol.h | 2 -- client/utils.cpp | 32 +++++++++++++++++++ client/utils.h | 5 +++ ipc/ipc.h | 22 +++++++++++++ ipc/ipc_process_interface.rep | 4 +-- ipc/ipcserverprocess.cpp | 20 +++++++----- ipc/ipcserverprocess.h | 4 +-- 12 files changed, 84 insertions(+), 46 deletions(-) diff --git a/client/defines.h b/client/defines.h index 415dc21a1..4334c68fd 100644 --- a/client/defines.h +++ b/client/defines.h @@ -4,7 +4,7 @@ #define APPLICATION_NAME "AmneziaVPN" #define SERVICE_NAME "AmneziaVPN-service" #define ORGANIZATION_NAME "AmneziaVPN.ORG" -#define APP_MAJOR_VERSION "2.0.10" -#define APP_VERSION "2.0.10.0" +#define APP_MAJOR_VERSION "2.1.0" +#define APP_VERSION "2.1.0.0" #endif // DEFINES_H diff --git a/client/protocols/ikev2_vpn_protocol_windows.cpp b/client/protocols/ikev2_vpn_protocol_windows.cpp index 5e4e5b14d..47bc3d0ce 100644 --- a/client/protocols/ikev2_vpn_protocol_windows.cpp +++ b/client/protocols/ikev2_vpn_protocol_windows.cpp @@ -199,7 +199,7 @@ ErrorCode Ikev2Protocol::start() setLastError(ErrorCode::AmneziaServiceConnectionFailed); return ErrorCode::AmneziaServiceConnectionFailed; } - certInstallProcess->setProgram("certutil"); + certInstallProcess->setProgram(PermittedProcess::CertUtil); QStringList arguments({"-f" , "-importpfx", "-p", m_config[config_key::password].toString(), certFile.fileName(), "NoExport" diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index 6adabfb34..209757308 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -132,24 +132,13 @@ void OpenVpnProtocol::updateRouteGateway(QString line) qDebug() << "Set VPN route gateway" << m_routeGateway; } -QString OpenVpnProtocol::openVpnExecPath() const -{ -#ifdef Q_OS_WIN - return Utils::executable("openvpn/openvpn", true); -#elif defined Q_OS_LINUX - return Utils::usrExecutable("openvpn"); -#else - return Utils::executable("/openvpn", true); -#endif -} - ErrorCode OpenVpnProtocol::start() { #ifndef Q_OS_IOS //qDebug() << "Start OpenVPN connection"; OpenVpnProtocol::stop(); - if (!QFileInfo::exists(openVpnExecPath())) { + if (!QFileInfo::exists(Utils::openVpnExecPath())) { setLastError(ErrorCode::OpenVpnExecutableMissing); return lastError(); } @@ -183,7 +172,7 @@ ErrorCode OpenVpnProtocol::start() setLastError(ErrorCode::AmneziaServiceConnectionFailed); return ErrorCode::AmneziaServiceConnectionFailed; } - m_openVpnProcess->setProgram(openVpnExecPath()); + m_openVpnProcess->setProgram(PermittedProcess::OpenVPN); QStringList arguments({"--config" , configPath(), "--management", m_managementHost, QString::number(m_managementPort), "--management-client"/*, "--log", vpnLogFileNamePath */ diff --git a/client/protocols/openvpnprotocol.h b/client/protocols/openvpnprotocol.h index 34cff8f4a..1f3bbd409 100644 --- a/client/protocols/openvpnprotocol.h +++ b/client/protocols/openvpnprotocol.h @@ -30,7 +30,6 @@ protected slots: private: QString configPath() const; - QString openVpnExecPath() const; bool openVpnProcessIsRunning() const; bool sendTermSignal(); void readOpenVpnConfiguration(const QJsonObject &configuration); diff --git a/client/protocols/wireguardprotocol.cpp b/client/protocols/wireguardprotocol.cpp index d650cb3f5..763813c94 100644 --- a/client/protocols/wireguardprotocol.cpp +++ b/client/protocols/wireguardprotocol.cpp @@ -30,7 +30,7 @@ void WireguardProtocol::stop() //qDebug() << "WireguardProtocol::stop() 1"; #ifndef Q_OS_IOS - if (!QFileInfo::exists(wireguardExecPath())) { + if (!QFileInfo::exists(Utils::wireguardExecPath())) { qCritical() << "Wireguard executable missing!"; setLastError(ErrorCode::ExecutableMissing); return; @@ -51,7 +51,7 @@ void WireguardProtocol::stop() return; } - m_wireguardStopProcess->setProgram(wireguardExecPath()); + m_wireguardStopProcess->setProgram(PermittedProcess::Wireguard); QStringList arguments({"--remove", configPath()}); @@ -117,17 +117,6 @@ void WireguardProtocol::updateRouteGateway(QString line) qDebug() << "Set VPN route gateway" << m_routeGateway; } -QString WireguardProtocol::wireguardExecPath() const -{ -#ifdef Q_OS_WIN - return Utils::executable("wireguard/wireguard-service", true); -#elif defined Q_OS_LINUX - return Utils::usrExecutable("wg"); -#else - return Utils::executable("/wireguard", true); -#endif -} - ErrorCode WireguardProtocol::start() { //qDebug() << "WireguardProtocol::start() 1"; @@ -141,7 +130,7 @@ ErrorCode WireguardProtocol::start() //qDebug() << "Start Wireguard connection"; WireguardProtocol::stop(); - if (!QFileInfo::exists(wireguardExecPath())) { + if (!QFileInfo::exists(Utils::wireguardExecPath())) { setLastError(ErrorCode::ExecutableMissing); return lastError(); } @@ -168,7 +157,7 @@ ErrorCode WireguardProtocol::start() return ErrorCode::AmneziaServiceConnectionFailed; } - m_wireguardStartProcess->setProgram(wireguardExecPath()); + m_wireguardStartProcess->setProgram(PermittedProcess::Wireguard); QStringList arguments({"--add", configPath()}); diff --git a/client/protocols/wireguardprotocol.h b/client/protocols/wireguardprotocol.h index 8ed26c7d0..3a091cacf 100644 --- a/client/protocols/wireguardprotocol.h +++ b/client/protocols/wireguardprotocol.h @@ -23,8 +23,6 @@ public: private: QString configPath() const; - QString wireguardExecPath() const; - //bool openVpnProcessIsRunning() const; void readWireguardConfiguration(const QJsonObject &configuration); void updateRouteGateway(QString line); diff --git a/client/utils.cpp b/client/utils.cpp index 046d582cd..576439eed 100644 --- a/client/utils.cpp +++ b/client/utils.cpp @@ -214,6 +214,38 @@ QStringList Utils::summarizeRoutes(const QStringList &ips, const QString cidr) return QStringList(); } +QString Utils::openVpnExecPath() +{ +#ifdef Q_OS_WIN + return Utils::executable("openvpn/openvpn", true); +#elif defined Q_OS_LINUX + return Utils::usrExecutable("openvpn"); +#else + return Utils::executable("/openvpn", true); +#endif +} + +QString Utils::wireguardExecPath() +{ +#ifdef Q_OS_WIN + return Utils::executable("wireguard/wireguard-service", true); +#elif defined Q_OS_LINUX + return Utils::usrExecutable("wg"); +#else + return Utils::executable("/wireguard", true); +#endif +} + +QString Utils::certUtilPath() +{ +#ifdef Q_OS_WIN + QString winPath = QString::fromUtf8(qgetenv("windir")); + return winPath + "system32\\certutil.exe"; +#else + return ""; +#endif +} + #ifdef Q_OS_WIN // Inspired from http://stackoverflow.com/a/15281070/1529139 // and http://stackoverflow.com/q/40059902/1529139 diff --git a/client/utils.h b/client/utils.h index ff5c5e8cb..61981db73 100644 --- a/client/utils.h +++ b/client/utils.h @@ -44,6 +44,11 @@ public: static QStringList summarizeRoutes(const QStringList &ips, const QString cidr); + static QString openVpnExecPath(); + static QString wireguardExecPath(); + static QString certUtilPath(); + + #ifdef Q_OS_WIN static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent); #endif diff --git a/ipc/ipc.h b/ipc/ipc.h index d78a450be..d69f6517f 100644 --- a/ipc/ipc.h +++ b/ipc/ipc.h @@ -4,10 +4,32 @@ #include #include +#include "../client/utils.h" + #define IPC_SERVICE_URL "local:AmneziaVpnIpcInterface" namespace amnezia { +enum PermittedProcess { + OpenVPN, + Wireguard, + CertUtil +}; + +inline QString permittedProcessPath(PermittedProcess pid) +{ + if (pid == PermittedProcess::OpenVPN) { + return Utils::openVpnExecPath(); + } + if (pid == PermittedProcess::Wireguard) { + return Utils::wireguardExecPath(); + } + else if (pid == PermittedProcess::CertUtil) { + return Utils::certUtilPath(); + } +} + + inline QString getIpcServiceUrl() { #ifdef Q_OS_WIN return IPC_SERVICE_URL; diff --git a/ipc/ipc_process_interface.rep b/ipc/ipc_process_interface.rep index fc82c49e7..ba42332c0 100644 --- a/ipc/ipc_process_interface.rep +++ b/ipc/ipc_process_interface.rep @@ -3,7 +3,7 @@ class IpcProcessInterface { - SLOT( start(const QString &program, const QStringList &args) ); + //SLOT( start(const QString &program, const QStringList &args) ); SLOT( start() ); SLOT( close() ); @@ -11,7 +11,7 @@ class IpcProcessInterface SLOT( setInputChannelMode(QProcess::InputChannelMode mode) ); SLOT( setNativeArguments(const QString &arguments) ); SLOT( setProcessChannelMode(QProcess::ProcessChannelMode mode) ); - SLOT( setProgram(const QString &program) ); + SLOT( setProgram(int programId) ); SLOT( setWorkingDirectory(const QString &dir) ); SLOT( QByteArray readAll() ); diff --git a/ipc/ipcserverprocess.cpp b/ipc/ipcserverprocess.cpp index f9cdd20f5..92fdc4936 100644 --- a/ipc/ipcserverprocess.cpp +++ b/ipc/ipcserverprocess.cpp @@ -1,4 +1,5 @@ #include "ipcserverprocess.h" +#include "ipc.h" #include #ifndef Q_OS_IOS @@ -38,16 +39,19 @@ IpcServerProcess::~IpcServerProcess() qDebug() << "IpcServerProcess::~IpcServerProcess"; } -void IpcServerProcess::start(const QString &program, const QStringList &arguments) -{ - m_process->start(program, arguments); - qDebug() << "IpcServerProcess started, " << arguments; +//void IpcServerProcess::start(const QString &program, const QStringList &arguments) +//{ +// m_process->start(program, arguments); +// qDebug() << "IpcServerProcess started, " << arguments; - m_process->waitForStarted(); -} +// m_process->waitForStarted(); +//} void IpcServerProcess::start() { + if (m_process->program().isEmpty()) { + qDebug() << "IpcServerProcess failed to start, program is empty"; + } m_process->start(); qDebug() << "IpcServerProcess started, " << m_process->program() << m_process->arguments(); @@ -81,9 +85,9 @@ void IpcServerProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode) m_process->setProcessChannelMode(mode); } -void IpcServerProcess::setProgram(const QString &program) +void IpcServerProcess::setProgram(int programId) { - m_process->setProgram(program); + m_process->setProgram(amnezia::permittedProcessPath(static_cast(programId))); } void IpcServerProcess::setWorkingDirectory(const QString &dir) diff --git a/ipc/ipcserverprocess.h b/ipc/ipcserverprocess.h index 0ed61ee8e..ff2c9434d 100644 --- a/ipc/ipcserverprocess.h +++ b/ipc/ipcserverprocess.h @@ -13,7 +13,7 @@ public: explicit IpcServerProcess(QObject *parent = nullptr); virtual ~IpcServerProcess(); - void start(const QString &program, const QStringList &arguments) override; + //void start(const QString &program, const QStringList &arguments) override; void start() override; void close() override; @@ -21,7 +21,7 @@ public: void setInputChannelMode(QProcess::InputChannelMode mode) override; void setNativeArguments(const QString &arguments) override; void setProcessChannelMode(QProcess::ProcessChannelMode mode) override; - void setProgram(const QString &program) override; + void setProgram(int programId) override; void setWorkingDirectory(const QString &dir) override; QByteArray readAll() override; From 42398950e42a77acaf1e4a06fa0eb92e59ce0029 Mon Sep 17 00:00:00 2001 From: pokamest Date: Tue, 16 Aug 2022 08:28:41 -0700 Subject: [PATCH 14/52] Fix for iOS --- client/secure_qsettings.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index 8faed6b15..0b2f138ea 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -1,5 +1,6 @@ #include "secure_qsettings.h" #include "encryption_helper.h" +#include "platforms/ios/MobileUtils.h" #include #include @@ -11,8 +12,8 @@ SecureQSettings::SecureQSettings(const QString &organization, const QString &app { // load keys from system key storage #ifdef Q_OS_IOS - key = MobileUtils::readFromKeychain(settingsKeyTag); - iv = MobileUtils::readFromKeychain(settingsIvTag); + key = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsKeyTag).toUtf8()); + iv = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsIvTag).toUtf8()); #endif key = "12345qwerty00000"; iv = "000000000000000"; From b5890340e357124e7b691e59f03323b92b2766ca Mon Sep 17 00:00:00 2001 From: pokamest Date: Tue, 23 Aug 2022 22:47:23 +0300 Subject: [PATCH 15/52] Secure settings rework --- client/3rd/QSimpleCrypto/QSimpleCrypto.pri | 18 + client/3rd/QSimpleCrypto/include/QAead.h | 87 +++++ .../3rd/QSimpleCrypto/include/QBlockCipher.h | 83 ++++ .../3rd/QSimpleCrypto/include/QCryptoError.h | 45 +++ client/3rd/QSimpleCrypto/include/QRsa.h | 104 +++++ .../include/QSimpleCrypto_global.h | 9 + client/3rd/QSimpleCrypto/include/QX509.h | 87 +++++ client/3rd/QSimpleCrypto/include/QX509Store.h | 120 ++++++ client/3rd/QSimpleCrypto/sources/QAead.cpp | 364 ++++++++++++++++++ .../QSimpleCrypto/sources/QBlockCipher.cpp | 184 +++++++++ .../QSimpleCrypto/sources/QCryptoError.cpp | 6 + client/3rd/QSimpleCrypto/sources/QRsa.cpp | 274 +++++++++++++ client/3rd/QSimpleCrypto/sources/QX509.cpp | 234 +++++++++++ .../3rd/QSimpleCrypto/sources/QX509Store.cpp | 176 +++++++++ client/client.pro | 5 +- client/encryption_helper.cpp | 143 ------- client/encryption_helper.h | 31 -- client/secure_qsettings.cpp | 103 +++-- client/secure_qsettings.h | 11 +- client/settings.cpp | 1 - client/settings.h | 1 - 21 files changed, 1863 insertions(+), 223 deletions(-) create mode 100644 client/3rd/QSimpleCrypto/QSimpleCrypto.pri create mode 100644 client/3rd/QSimpleCrypto/include/QAead.h create mode 100644 client/3rd/QSimpleCrypto/include/QBlockCipher.h create mode 100644 client/3rd/QSimpleCrypto/include/QCryptoError.h create mode 100644 client/3rd/QSimpleCrypto/include/QRsa.h create mode 100644 client/3rd/QSimpleCrypto/include/QSimpleCrypto_global.h create mode 100644 client/3rd/QSimpleCrypto/include/QX509.h create mode 100644 client/3rd/QSimpleCrypto/include/QX509Store.h create mode 100644 client/3rd/QSimpleCrypto/sources/QAead.cpp create mode 100644 client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp create mode 100644 client/3rd/QSimpleCrypto/sources/QCryptoError.cpp create mode 100644 client/3rd/QSimpleCrypto/sources/QRsa.cpp create mode 100644 client/3rd/QSimpleCrypto/sources/QX509.cpp create mode 100644 client/3rd/QSimpleCrypto/sources/QX509Store.cpp delete mode 100644 client/encryption_helper.cpp delete mode 100644 client/encryption_helper.h diff --git a/client/3rd/QSimpleCrypto/QSimpleCrypto.pri b/client/3rd/QSimpleCrypto/QSimpleCrypto.pri new file mode 100644 index 000000000..99a1c1293 --- /dev/null +++ b/client/3rd/QSimpleCrypto/QSimpleCrypto.pri @@ -0,0 +1,18 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/include/QAead.h \ + $$PWD/include/QBlockCipher.h \ + $$PWD/include/QCryptoError.h \ + $$PWD/include/QRsa.h \ + $$PWD/include/QSimpleCrypto_global.h \ + $$PWD/include/QX509.h \ + $$PWD/include/QX509Store.h + +SOURCES += \ + $$PWD/sources/QAead.cpp \ + $$PWD/sources/QBlockCipher.cpp \ + $$PWD/sources/QCryptoError.cpp \ + $$PWD/sources/QRsa.cpp \ + $$PWD/sources/QX509.cpp \ + $$PWD/sources/QX509Store.cpp diff --git a/client/3rd/QSimpleCrypto/include/QAead.h b/client/3rd/QSimpleCrypto/include/QAead.h new file mode 100644 index 000000000..11f60b31f --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QAead.h @@ -0,0 +1,87 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#ifndef QAEAD_H +#define QAEAD_H + +#include "QSimpleCrypto_global.h" + +#include + +#include + +#include +#include +#include +#include + +#include "QCryptoError.h" + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QAead { + public: + QAead(); + + /// + /// \brief encryptAesGcm - Function encrypts data with Gcm algorithm. + /// \param data - Data that will be encrypted. + /// \param key - AES key. + /// \param iv - Initialization vector. + /// \param tag - Authorization tag. + /// \param aad - Additional authenticated data. Must be nullptr, if not used. + /// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm(). + /// \return Returns encrypted data or "", if error happened. + /// + QByteArray encryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_gcm()); + + /// + /// \brief decryptAesGcm - Function decrypts data with Gcm algorithm. + /// \param data - Data that will be decrypted + /// \param key - AES key + /// \param iv - Initialization vector + /// \param tag - Authorization tag + /// \param aad - Additional authenticated data. Must be nullptr, if not used + /// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm() + /// \return Returns decrypted data or "", if error happened. + /// + QByteArray decryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_gcm()); + + /// + /// \brief encryptAesCcm - Function encrypts data with Ccm algorithm. + /// \param data - Data that will be encrypted. + /// \param key - AES key. + /// \param iv - Initialization vector. + /// \param tag - Authorization tag. + /// \param aad - Additional authenticated data. Must be nullptr, if not used. + /// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm(). + /// \return Returns encrypted data or "", if error happened. + /// + QByteArray encryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_ccm()); + + /// + /// \brief decryptAesCcm - Function decrypts data with Ccm algorithm. + /// \param data - Data that will be decrypted. + /// \param key - AES key. + /// \param iv - Initialization vector. + /// \param tag - Authorization tag. + /// \param aad - Additional authenticated data. Must be nullptr, if not used. + /// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm(). + /// \return Returns decrypted data or "", if error happened. + /// + QByteArray decryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad = "", const EVP_CIPHER* cipher = EVP_aes_256_ccm()); + + /// + /// \brief error - Error handler class. + /// + QCryptoError error; + }; +} // namespace QSimpleCrypto + +#endif // QAEAD_H diff --git a/client/3rd/QSimpleCrypto/include/QBlockCipher.h b/client/3rd/QSimpleCrypto/include/QBlockCipher.h new file mode 100644 index 000000000..af57b650f --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QBlockCipher.h @@ -0,0 +1,83 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#ifndef QBLOCKCIPHER_H +#define QBLOCKCIPHER_H + +#include "QSimpleCrypto_global.h" + +#include + +#include + +#include +#include +#include +#include + +#include "QCryptoError.h" + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QBlockCipher { + + #define Aes128Rounds 10 + #define Aes192Rounds 12 + #define Aes256Rounds 14 + + public: + QBlockCipher(); + + /// + /// \brief generateRandomBytes - Function generates random bytes by size. + /// \param size - Size of generated bytes. + /// \return Returns random bytes. + /// + QByteArray generateRandomBytes(const int& size); + + /// + /// \brief encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm. + /// \param data - Data that will be encrypted. + /// \param key - AES key. + /// \param iv - Initialization vector. + /// \param password - Encryption password. + /// \param salt - Random delta. + /// \param rounds - Transformation rounds. + /// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). + /// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512(). + /// \return Returns decrypted data or "", if error happened. + /// + QByteArray encryptAesBlockCipher(QByteArray data, QByteArray key, + QByteArray iv = "", const int& rounds = Aes256Rounds, + const EVP_CIPHER* cipher = EVP_aes_256_cbc(), const EVP_MD* md = EVP_sha512()); + + /// + /// \brief decryptAesBlockCipher - Function decrypts data with Aes Block Cipher algorithm. + /// \param data - Data that will be decrypted. + /// \param key - AES key. + /// \param iv - Initialization vector. + /// \param password - Decryption password. + /// \param salt - Random delta. + /// \param rounds - Transformation rounds. + /// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). + /// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512(). + /// \return Returns decrypted data or "", if error happened. + /// + QByteArray decryptAesBlockCipher(QByteArray data, QByteArray key, + QByteArray iv = "", const int& rounds = Aes256Rounds, + const EVP_CIPHER* cipher = EVP_aes_256_cbc(), const EVP_MD* md = EVP_sha512()); + + /// + /// \brief error - Error handler class. + /// + QCryptoError error; + }; +} // namespace QSimpleCrypto + +#endif // QBLOCKCIPHER_H diff --git a/client/3rd/QSimpleCrypto/include/QCryptoError.h b/client/3rd/QSimpleCrypto/include/QCryptoError.h new file mode 100644 index 000000000..fc0596545 --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QCryptoError.h @@ -0,0 +1,45 @@ +#ifndef QCRYPTOERROR_H +#define QCRYPTOERROR_H + +#include + +#include "QSimpleCrypto_global.h" + +/// TODO: Add Special error code for each error. + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QCryptoError : public QObject { + Q_OBJECT + + public: + explicit QCryptoError(QObject* parent = nullptr); + + /// + /// \brief setError - Sets error information + /// \param errorCode - Error code. + /// \param errorSummary - Error summary. + /// + inline void setError(const quint8 errorCode, const QString& errorSummary) + { + m_currentErrorCode = errorCode; + m_errorSummary = errorSummary; + } + + /// + /// \brief lastError - Returns last error. + /// \return Returns eror ID and error Text. + /// + inline QPair lastError() const + { + return QPair(m_currentErrorCode, m_errorSummary); + } + + private: + quint8 m_currentErrorCode; + QString m_errorSummary; + }; +} + +#endif // QCRYPTOERROR_H diff --git a/client/3rd/QSimpleCrypto/include/QRsa.h b/client/3rd/QSimpleCrypto/include/QRsa.h new file mode 100644 index 000000000..45eb31693 --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QRsa.h @@ -0,0 +1,104 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#ifndef QRSA_H +#define QRSA_H + +#include "QSimpleCrypto_global.h" + +#include +#include + +#include + +#include +#include +#include + +#include "QCryptoError.h" + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QRsa { + + #define PublicEncrypt 0 + #define PrivateEncrypt 1 + #define PublicDecrypt 2 + #define PrivateDecrypt 3 + + public: + QRsa(); + + /// + /// \brief generateRsaKeys - Function generate Rsa Keys and returns them in OpenSSL structure. + /// \param bits - RSA key size. + /// \param rsaBigNumber - The exponent is an odd number, typically 3, 17 or 65537. + /// \return Returns 'OpenSSL RSA structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'RSA_free()' to avoid memory leak. + /// + RSA* generateRsaKeys(const int& bits, const int& rsaBigNumber); + + /// + /// \brief savePublicKey - Saves to file RSA public key. + /// \param rsa - OpenSSL RSA structure. + /// \param publicKeyFileName - Public key file name. + /// + void savePublicKey(RSA *rsa, const QByteArray& publicKeyFileName); + + /// + /// \brief savePrivateKey - Saves to file RSA private key. + /// \param rsa - OpenSSL RSA structure. + /// \param privateKeyFileName - Private key file name. + /// \param password - Private key password. + /// \param cipher - Can be used with 'OpenSSL EVP_CIPHER' (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). + /// + void savePrivateKey(RSA* rsa, const QByteArray& privateKeyFileName, QByteArray password = "", const EVP_CIPHER* cipher = nullptr); + + /// + /// \brief getPublicKeyFromFile - Gets RSA public key from a file. + /// \param filePath - File path to public key file. + /// \return Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak. + /// + EVP_PKEY* getPublicKeyFromFile(const QByteArray& filePath); + + /// + /// \brief getPrivateKeyFromFile - Gets RSA private key from a file. + /// \param filePath - File path to private key file. + /// \param password - Private key password. + /// \return - Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak. + /// + EVP_PKEY* getPrivateKeyFromFile(const QByteArray& filePath, const QByteArray& password = ""); + + /// + /// \brief encrypt - Encrypt data with RSA algorithm. + /// \param plaintext - Text that must be encrypted. + /// \param rsa - OpenSSL RSA structure. + /// \param encryptType - Public or private encrypt type. (PUBLIC_ENCRYPT, PRIVATE_ENCRYPT). + /// \param padding - OpenSSL RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc. + /// \return Returns encrypted data or "", if error happened. + /// + QByteArray encrypt(QByteArray plainText, RSA* rsa, const int& encryptType = PublicEncrypt, const int& padding = RSA_PKCS1_PADDING); + + /// + /// \brief decrypt - Decrypt data with RSA algorithm. + /// \param cipherText - Text that must be decrypted. + /// \param rsa - OpenSSL RSA structure. + /// \param decryptType - Public or private type. (PUBLIC_DECRYPT, PRIVATE_DECRYPT). + /// \param padding - RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc. + /// \return - Returns decrypted data or "", if error happened. + /// + QByteArray decrypt(QByteArray cipherText, RSA* rsa, const int& decryptType = PrivateDecrypt, const int& padding = RSA_PKCS1_PADDING); + + /// + /// \brief error - Error handler class. + /// + QCryptoError error; + }; +} // namespace QSimpleCrypto + +#endif // QRSA_H diff --git a/client/3rd/QSimpleCrypto/include/QSimpleCrypto_global.h b/client/3rd/QSimpleCrypto/include/QSimpleCrypto_global.h new file mode 100644 index 000000000..fdd6c020b --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QSimpleCrypto_global.h @@ -0,0 +1,9 @@ +#ifndef QSIMPLECRYPTO_GLOBAL_H +#define QSIMPLECRYPTO_GLOBAL_H + +#include +#include + +#define QSIMPLECRYPTO_EXPORT + +#endif // QSIMPLECRYPTO_GLOBAL_H diff --git a/client/3rd/QSimpleCrypto/include/QX509.h b/client/3rd/QSimpleCrypto/include/QX509.h new file mode 100644 index 000000000..96e0c76cb --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QX509.h @@ -0,0 +1,87 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#ifndef QX509_H +#define QX509_H + +#include "QSimpleCrypto_global.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "QCryptoError.h" + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QX509 { + + #define oneYear 31536000L + #define x509LastVersion 2 + + public: + QX509(); + + /// + /// \brief loadCertificateFromFile - Function load X509 from file and returns OpenSSL structure. + /// \param fileName - File path to certificate. + /// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak. + /// + X509* loadCertificateFromFile(const QByteArray& fileName); + + /// + /// \brief signCertificate - Function signs X509 certificate and returns signed X509 OpenSSL structure. + /// \param endCertificate - Certificate that will be signed + /// \param caCertificate - CA certificate that will sign end certificate + /// \param caPrivateKey - CA certificate private key + /// \param fileName - With that name certificate will be saved. Leave "", if don't need to save it + /// \return Returns OpenSSL X509 structure or nullptr, if error happened. + /// + X509* signCertificate(X509* endCertificate, X509* caCertificate, EVP_PKEY* caPrivateKey, const QByteArray& fileName = ""); + + /// + /// \brief verifyCertificate - Function verifies X509 certificate and returns verified X509 OpenSSL structure. + /// \param x509 - OpenSSL X509. That certificate will be verified. + /// \param store - Trusted certificate must be added to X509_Store with 'addCertificateToStore(X509_STORE* ctx, X509* x509)'. + /// \return Returns OpenSSL X509 structure or nullptr, if error happened + /// + X509* verifyCertificate(X509* x509, X509_STORE* store); + + /// + /// \brief generateSelfSignedCertificate - Function generatesand returns self signed X509. + /// \param rsa - OpenSSL RSA. + /// \param additionalData - Certificate information. + /// \param certificateFileName - With that name certificate will be saved. Leave "", if don't need to save it. + /// \param md - OpenSSL EVP_MD structure. Example: EVP_sha512(). + /// \param serialNumber - X509 certificate serial number. + /// \param version - X509 certificate version. + /// \param notBefore - X509 start date. + /// \param notAfter - X509 end date. + /// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak. + /// + X509* generateSelfSignedCertificate(const RSA* rsa, const QMap& additionalData, + const QByteArray& certificateFileName = "", const EVP_MD* md = EVP_sha512(), + const long& serialNumber = 1, const long& version = x509LastVersion, + const long& notBefore = 0, const long& notAfter = oneYear); + + /// + /// \brief error - Error handler class. + /// + QCryptoError error; + }; +} // namespace QSimpleCrypto + +#endif // QX509_H diff --git a/client/3rd/QSimpleCrypto/include/QX509Store.h b/client/3rd/QSimpleCrypto/include/QX509Store.h new file mode 100644 index 000000000..8cd8ca82b --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QX509Store.h @@ -0,0 +1,120 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#ifndef QX509STORE_H +#define QX509STORE_H + +#include "QSimpleCrypto_global.h" + +#include +#include +#include + +#include + +#include +#include +#include + +#include "QCryptoError.h" + +// clang-format off +namespace QSimpleCrypto +{ + class QSIMPLECRYPTO_EXPORT QX509Store { + public: + QX509Store(); + + /// + /// \brief addCertificateToStore + /// \param store - OpenSSL X509_STORE. + /// \param x509 - OpenSSL X509. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool addCertificateToStore(X509_STORE* store, X509* x509); + + /// + /// \brief addLookup + /// \param store - OpenSSL X509_STORE. + /// \param method - OpenSSL X509_LOOKUP_METHOD. Example: X509_LOOKUP_file. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool addLookup(X509_STORE* store, X509_LOOKUP_METHOD* method); + + /// + /// \brief setCertificateDepth + /// \param store - OpenSSL X509_STORE. + /// \param depth - That is the maximum number of untrusted CA certificates that can appear in a chain. Example: 0. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool setDepth(X509_STORE* store, const int& depth); + + /// + /// \brief setFlag + /// \param store - OpenSSL X509_STORE. + /// \param flag - The verification flags consists of zero or more of the following flags ored together. Example: X509_V_FLAG_CRL_CHECK. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool setFlag(X509_STORE* store, const unsigned long& flag); + + /// + /// \brief setFlag + /// \param store - OpenSSL X509_STORE. + /// \param purpose - Verification purpose in param to purpose. Example: X509_PURPOSE_ANY. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool setPurpose(X509_STORE* store, const int& purpose); + + /// + /// \brief setTrust + /// \param store - OpenSSL X509_STORE. + /// \param trust - Trust Level. Example: X509_TRUST_SSL_SERVER. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool setTrust(X509_STORE* store, const int& trust); + + /// + /// \brief setDefaultPaths + /// \param store - OpenSSL X509_STORE. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool setDefaultPaths(X509_STORE* store); + + /// + /// \brief loadLocations + /// \param store - OpenSSL X509_STORE. + /// \param fileName - File name. Example: "caCertificate.pem". + /// \param dirPath - Path to file. Example: "path/To/File". + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool loadLocations(X509_STORE* store, const QByteArray& fileName, const QByteArray& dirPath); + + /// + /// \brief loadLocations + /// \param store - OpenSSL X509_STORE. + /// \param file - Qt QFile that will be loaded. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool loadLocations(X509_STORE* store, const QFile& file); + + /// + /// \brief loadLocations + /// \param store - OpenSSL X509_STORE. + /// \param fileInfo - Qt QFileInfo. + /// \return Returns 'true' on success and 'false', if error happened. + /// + bool loadLocations(X509_STORE* store, const QFileInfo& fileInfo); + + /// + /// \brief error - Error handler class. + /// + QCryptoError error; + }; +} + +#endif // QX509STORE_H diff --git a/client/3rd/QSimpleCrypto/sources/QAead.cpp b/client/3rd/QSimpleCrypto/sources/QAead.cpp new file mode 100644 index 000000000..968c88417 --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QAead.cpp @@ -0,0 +1,364 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#include "include/QAead.h" + +QSimpleCrypto::QAead::QAead() +{ +} + +/// +/// \brief QSimpleCrypto::QAEAD::encryptAesGcm - Function encrypts data with Gcm algorithm. +/// \param data - Data that will be encrypted. +/// \param key - AES key. +/// \param iv - Initialization vector. +/// \param tag - Authorization tag. +/// \param aad - Additional authenticated data. Must be nullptr, if not used. +/// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm(). +/// \return Returns encrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QAead::encryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr encryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (encryptionCipher == nullptr) { + throw std::runtime_error("Couldn't initialize \'encryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set data length */ + int plainTextLength = data.size(); + int cipherTextLength = 0; + + /* Initialize cipherText. Here encrypted data will be stored */ + std::unique_ptr cipherText { new unsigned char[plainTextLength]() }; + if (cipherText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'ciphertext'."); + } + + /* Initialize encryption operation. */ + if (!EVP_EncryptInit_ex(encryptionCipher.get(), cipher, nullptr, reinterpret_cast(key.data()), reinterpret_cast(iv.data()))) { + throw std::runtime_error("Couldn't initialize encryption operation. EVP_EncryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set IV length if default 12 bytes (96 bits) is not appropriate */ + if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_GCM_SET_IVLEN, iv.length(), nullptr)) { + throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + +// /* Check if aad need to be used */ +// if (aad.length() > 0) { +// /* Provide any AAD data. This can be called zero or more times as required */ +// if (!EVP_EncryptUpdate(encryptionCipher.get(), nullptr, &cipherTextLength, reinterpret_cast(aad.data()), aad.length())) { +// throw std::runtime_error("Couldn't provide aad data. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } +// } + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if (!EVP_EncryptUpdate(encryptionCipher.get(), cipherText.get(), &cipherTextLength, reinterpret_cast(data.data()), plainTextLength)) { + throw std::runtime_error("Couldn't provide message to be encrypted. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Finalize the encryption. Normally cipher text bytes may be written at + * this stage, but this does not occur in GCM mode + */ + if (!EVP_EncryptFinal_ex(encryptionCipher.get(), cipherText.get(), &plainTextLength)) { + throw std::runtime_error("Couldn't finalize encryption. EVP_EncryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + +// /* Get tag */ +// if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_GCM_GET_TAG, tag->length(), reinterpret_cast(tag->data()))) { +// throw std::runtime_error("Couldn't get tag. EVP_CIPHER_CTX_ctrl(. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } + + /* Finilize data to be readable with qt */ + QByteArray encryptedData = QByteArray(reinterpret_cast(cipherText.get()), cipherTextLength); + + return encryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QAead::error.setError(1, exception.what()); + return QByteArray(); + } catch (...) { + QSimpleCrypto::QAead::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} + +/// +/// \brief QSimpleCrypto::QAEAD::decryptAesGcm - Function decrypts data with Gcm algorithm. +/// \param data - Data that will be decrypted +/// \param key - AES key +/// \param iv - Initialization vector +/// \param tag - Authorization tag +/// \param aad - Additional authenticated data. Must be nullptr, if not used +/// \param cipher - Can be used with OpenSSL EVP_CIPHER (gcm) - 128, 192, 256. Example: EVP_aes_256_gcm() +/// \return Returns decrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QAead::decryptAesGcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr decryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (decryptionCipher.get() == nullptr) { + throw std::runtime_error("Couldn't initialize \'decryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set data length */ + int cipherTextLength = data.size(); + int plainTextLength = 0; + + /* Initialize plainText. Here decrypted data will be stored */ + std::unique_ptr plainText { new unsigned char[cipherTextLength]() }; + if (plainText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'plaintext'."); + } + + /* Initialize decryption operation. */ + if (!EVP_DecryptInit_ex(decryptionCipher.get(), cipher, nullptr, reinterpret_cast(key.data()), reinterpret_cast(iv.data()))) { + throw std::runtime_error("Couldn't initialize decryption operation. EVP_DecryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ + if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_GCM_SET_IVLEN, iv.length(), nullptr)) { + throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + +// /* Check if aad need to be used */ +// if (aad.length() > 0) { +// /* Provide any AAD data. This can be called zero or more times as required */ +// if (!EVP_DecryptUpdate(decryptionCipher.get(), nullptr, &plainTextLength, reinterpret_cast(aad.data()), aad.length())) { +// throw std::runtime_error("Couldn't provide aad data. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } +// } + + /* + * Provide the message to be decrypted, and obtain the plain text output. + * EVP_DecryptUpdate can be called multiple times if necessary + */ + if (!EVP_DecryptUpdate(decryptionCipher.get(), plainText.get(), &plainTextLength, reinterpret_cast(data.data()), cipherTextLength)) { + throw std::runtime_error("Couldn't provide message to be decrypted. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + +// /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ +// if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_GCM_SET_TAG, tag->length(), reinterpret_cast(tag->data()))) { +// throw std::runtime_error("Coldn't set tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } + + /* + * Finalize the decryption. A positive return value indicates success, + * anything else is a failure - the plain text is not trustworthy. + */ + if (!EVP_DecryptFinal_ex(decryptionCipher.get(), plainText.get(), &cipherTextLength)) { + throw std::runtime_error("Couldn't finalize decryption. EVP_DecryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finilize data to be readable with qt */ + QByteArray decryptedData = QByteArray(reinterpret_cast(plainText.get()), plainTextLength); + + return decryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QAead::error.setError(1, exception.what()); + return QByteArray(); + } catch (...) { + QSimpleCrypto::QAead::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} + +/// +/// \brief QSimpleCrypto::QAEAD::encryptAesCcm - Function encrypts data with Ccm algorithm. +/// \param data - Data that will be encrypted. +/// \param key - AES key. +/// \param iv - Initialization vector. +/// \param tag - Authorization tag. +/// \param aad - Additional authenticated data. Must be nullptr, if not used. +/// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm(). +/// \return Returns encrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QAead::encryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr encryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (encryptionCipher == nullptr) { + throw std::runtime_error("Couldn't initialize \'encryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set data length */ + int plainTextLength = data.size(); + int cipherTextLength = 0; + + /* Initialize cipherText. Here encrypted data will be stored */ + std::unique_ptr cipherText { new unsigned char[plainTextLength]() }; + if (cipherText.get() == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'ciphertext'."); + } + + /* Initialize encryption operation. */ + if (!EVP_EncryptInit_ex(encryptionCipher.get(), cipher, nullptr, reinterpret_cast(key.data()), reinterpret_cast(iv.data()))) { + throw std::runtime_error("Couldn't initialize encryption operation. EVP_EncryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set IV length if default 12 bytes (96 bits) is not appropriate */ + if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_CCM_SET_IVLEN, iv.length(), nullptr)) { + throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set tag length */ + if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_CCM_SET_TAG, tag->length(), nullptr)) { + throw std::runtime_error("Coldn't set tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Check if aad need to be used */ + if (aad.length() > 0) { + /* Provide the total plain text length */ + if (!EVP_EncryptUpdate(encryptionCipher.get(), nullptr, &cipherTextLength, nullptr, plainTextLength)) { + throw std::runtime_error("Couldn't provide total plaintext length. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Provide any AAD data. This can be called zero or more times as required */ + if (!EVP_EncryptUpdate(encryptionCipher.get(), nullptr, &cipherTextLength, reinterpret_cast(aad.data()), aad.length())) { + throw std::runtime_error("Couldn't provide aad data. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if (!EVP_EncryptUpdate(encryptionCipher.get(), cipherText.get(), &cipherTextLength, reinterpret_cast(data.data()), plainTextLength)) { + throw std::runtime_error("Couldn't provide message to be encrypted. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Finalize the encryption. Normally ciphertext bytes may be written at + * this stage, but this does not occur in GCM mode + */ + if (!EVP_EncryptFinal_ex(encryptionCipher.get(), cipherText.get(), &plainTextLength)) { + throw std::runtime_error("Couldn't finalize encryption. EVP_EncryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Get tag */ + if (!EVP_CIPHER_CTX_ctrl(encryptionCipher.get(), EVP_CTRL_CCM_GET_TAG, tag->length(), reinterpret_cast(tag->data()))) { + throw std::runtime_error("Couldn't get tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finilize data to be readable with qt */ + QByteArray encryptedData = QByteArray(reinterpret_cast(cipherText.get()), cipherTextLength); + + return encryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QAead::error.setError(1, exception.what()); + return QByteArray(); + } catch (...) { + QSimpleCrypto::QAead::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} + +/// +/// \brief QSimpleCrypto::QAEAD::decryptAesCcm - Function decrypts data with Ccm algorithm. +/// \param data - Data that will be decrypted. +/// \param key - AES key. +/// \param iv - Initialization vector. +/// \param tag - Authorization tag. +/// \param aad - Additional authenticated data. Must be nullptr, if not used. +/// \param cipher - Can be used with OpenSSL EVP_CIPHER (ccm) - 128, 192, 256. Example: EVP_aes_256_ccm(). +/// \return Returns decrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QAead::decryptAesCcm(QByteArray data, QByteArray key, QByteArray iv, QByteArray* tag, QByteArray aad, const EVP_CIPHER* cipher) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr decryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (decryptionCipher.get() == nullptr) { + throw std::runtime_error("Couldn't initialize \'decryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set data length */ + int cipherTextLength = data.size(); + int plainTextLength = 0; + + /* Initialize plainText. Here decrypted data will be stored */ + std::unique_ptr plainText { new unsigned char[cipherTextLength]() }; + if (plainText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'plaintext'."); + } + + /* Initialize decryption operation. */ + if (!EVP_DecryptInit_ex(decryptionCipher.get(), cipher, nullptr, reinterpret_cast(key.data()), reinterpret_cast(iv.data()))) { + throw std::runtime_error("Couldn't initialize decryption operation. EVP_DecryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ + if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_CCM_SET_IVLEN, iv.length(), nullptr)) { + throw std::runtime_error("Couldn't set IV length. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ + if (!EVP_CIPHER_CTX_ctrl(decryptionCipher.get(), EVP_CTRL_CCM_SET_TAG, tag->length(), reinterpret_cast(tag->data()))) { + throw std::runtime_error("Coldn't set tag. EVP_CIPHER_CTX_ctrl(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Check if aad need to be used */ + if (aad.length() > 0) { + /* Provide the total ciphertext length */ + if (!EVP_DecryptUpdate(decryptionCipher.get(), nullptr, &plainTextLength, nullptr, cipherTextLength)) { + throw std::runtime_error("Couldn't provide total plaintext length. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Provide any AAD data. This can be called zero or more times as required */ + if (!EVP_DecryptUpdate(decryptionCipher.get(), nullptr, &plainTextLength, reinterpret_cast(aad.data()), aad.length())) { + throw std::runtime_error("Couldn't provide aad data. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } + + /* + * Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary + */ + if (!EVP_DecryptUpdate(decryptionCipher.get(), plainText.get(), &plainTextLength, reinterpret_cast(data.data()), cipherTextLength)) { + throw std::runtime_error("Couldn't provide message to be decrypted. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Finalize the decryption. A positive return value indicates success, + * anything else is a failure - the plaintext is not trustworthy. + */ + if (!EVP_DecryptFinal_ex(decryptionCipher.get(), plainText.get(), &cipherTextLength)) { + throw std::runtime_error("Couldn't finalize decryption. EVP_DecryptFinal_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finilize data to be readable with qt */ + QByteArray decryptedData = QByteArray(reinterpret_cast(plainText.get()), plainTextLength); + + return decryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QAead::error.setError(1, exception.what()); + return QByteArray(); + } catch (...) { + QSimpleCrypto::QAead::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} diff --git a/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp b/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp new file mode 100644 index 000000000..c01b9a2f8 --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp @@ -0,0 +1,184 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#include "include/QBlockCipher.h" + +QSimpleCrypto::QBlockCipher::QBlockCipher() +{ +} + +/// +/// \brief QSimpleCrypto::QBlockCipher::generateRandomBytes - Function generates random bytes by size. +/// \param size - Size of generated bytes. +/// \return Returns random bytes. +/// +QByteArray QSimpleCrypto::QBlockCipher::generateRandomBytes(const int& size) +{ + unsigned char arr[sizeof(size)]; + RAND_bytes(arr, sizeof(size)); + + QByteArray buffer = QByteArray(reinterpret_cast(arr), size); + return buffer; +} + +/// +/// \brief QSimpleCrypto::QBlockCipher::encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm. +/// \param data - Data that will be encrypted. +/// \param key - AES key. +/// \param iv - Initialization vector. +/// \param password - Encryption password. +/// \param salt - Random delta. +/// \param rounds - Transformation rounds. +/// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). +/// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512(). +/// \return Returns decrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QBlockCipher::encryptAesBlockCipher(QByteArray data, QByteArray key, + QByteArray iv, + const int& rounds, const EVP_CIPHER* cipher, const EVP_MD* md) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr encryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (encryptionCipher == nullptr) { + throw std::runtime_error("Couldn't initialize \'encryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Reinterpret values for multi use */ + unsigned char* m_key = reinterpret_cast(key.data()); + unsigned char* m_iv = reinterpret_cast(iv.data()); + + /* Set data length */ + int cipherTextLength(data.size() + AES_BLOCK_SIZE); + int finalLength = 0; + + /* Initialize cipcherText. Here encrypted data will be stored */ + std::unique_ptr cipherText { new unsigned char[cipherTextLength]() }; + if (cipherText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'cipherText'."); + } + + // Bug here +// /* Start encryption with password based encryption routine */ +// if (!EVP_BytesToKey(cipher, md, reinterpret_cast(salt.data()), reinterpret_cast(password.data()), password.length(), rounds, m_key, m_iv)) { +// throw std::runtime_error("Couldn't start encryption routine. EVP_BytesToKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } + + /* Initialize encryption operation. */ + if (!EVP_EncryptInit_ex(encryptionCipher.get(), cipher, nullptr, m_key, m_iv)) { + throw std::runtime_error("Couldn't initialize encryption operation. EVP_EncryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if (!EVP_EncryptUpdate(encryptionCipher.get(), cipherText.get(), &cipherTextLength, reinterpret_cast(data.data()), data.size())) { + throw std::runtime_error("Couldn't provide message to be encrypted. EVP_EncryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finalize the encryption. Normally ciphertext bytes may be written at this stage */ + if (!EVP_EncryptFinal(encryptionCipher.get(), cipherText.get() + cipherTextLength, &finalLength)) { + throw std::runtime_error("Couldn't finalize encryption. EVP_EncryptFinal(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finilize data to be readable with qt */ + QByteArray encryptedData = QByteArray(reinterpret_cast(cipherText.get()), cipherTextLength + finalLength); + + return encryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QBlockCipher::error.setError(1, exception.what()); + return QByteArray(); + } catch (...) { + QSimpleCrypto::QBlockCipher::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} + +/// +/// \brief QSimpleCrypto::QBlockCipher::encryptAesBlockCipher - Function decrypts data with Aes Block Cipher algorithm. +/// \param data - Data that will be decrypted. +/// \param key - AES key. +/// \param iv - Initialization vector. +/// \param password - Decryption password. +/// \param salt - Random delta. +/// \param rounds - Transformation rounds. +/// \param chiper - Can be used with OpenSSL EVP_CIPHER (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). +/// \param md - Hash algroitm (OpenSSL EVP_MD). Example: EVP_sha512(). +/// \return Returns decrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QBlockCipher::decryptAesBlockCipher(QByteArray data, QByteArray key, + QByteArray iv, + const int& rounds, const EVP_CIPHER* cipher, const EVP_MD* md) +{ + try { + /* Initialize EVP_CIPHER_CTX */ + std::unique_ptr decryptionCipher { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free }; + if (decryptionCipher == nullptr) { + throw std::runtime_error("Couldn't initialize \'decryptionCipher\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Reinterpret values for multi use */ + unsigned char* m_key = reinterpret_cast(key.data()); + unsigned char* m_iv = reinterpret_cast(iv.data()); + + /* Set data length */ + int plainTextLength(data.size()); + int finalLength = 0; + + /* Initialize plainText. Here decrypted data will be stored */ + std::unique_ptr plainText { new unsigned char[plainTextLength + AES_BLOCK_SIZE]() }; + if (plainText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for \'plainText\'. EVP_CIPHER_CTX_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + // Bug here +// /* Start encryption with password based encryption routine */ +// if (!EVP_BytesToKey(cipher, md, reinterpret_cast(salt.data()), reinterpret_cast(password.data()), password.length(), rounds, m_key, m_iv)) { +// throw std::runtime_error("Couldn't start decryption routine. EVP_BytesToKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); +// } + + /* Initialize decryption operation. */ + if (!EVP_DecryptInit_ex(decryptionCipher.get(), cipher, nullptr, m_key, m_iv)) { + throw std::runtime_error("Couldn't initialize decryption operation. EVP_DecryptInit_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary + */ + if (!EVP_DecryptUpdate(decryptionCipher.get(), plainText.get(), &plainTextLength, reinterpret_cast(data.data()), data.size())) { + throw std::runtime_error("Couldn't provide message to be decrypted. EVP_DecryptUpdate(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* + * Finalize the decryption. A positive return value indicates success, + * anything else is a failure - the plaintext is not trustworthy. + */ + if (!EVP_DecryptFinal(decryptionCipher.get(), plainText.get() + plainTextLength, &finalLength)) { + throw std::runtime_error("Couldn't finalize decryption. EVP_DecryptFinal. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Finilize data to be readable with qt */ + QByteArray decryptedData = QByteArray(reinterpret_cast(plainText.get()), plainTextLength + finalLength); + + return decryptedData; + + } catch (std::exception& exception) { + QSimpleCrypto::QBlockCipher::error.setError(1, exception.what()); + return QByteArray(exception.what()); + } catch (...) { + QSimpleCrypto::QBlockCipher::error.setError(2, "Unknown error!"); + return QByteArray(); + } + + return QByteArray(); +} diff --git a/client/3rd/QSimpleCrypto/sources/QCryptoError.cpp b/client/3rd/QSimpleCrypto/sources/QCryptoError.cpp new file mode 100644 index 000000000..234f55d73 --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QCryptoError.cpp @@ -0,0 +1,6 @@ +#include "include/QCryptoError.h" + +QSimpleCrypto::QCryptoError::QCryptoError(QObject* parent) + : QObject(parent) +{ +} diff --git a/client/3rd/QSimpleCrypto/sources/QRsa.cpp b/client/3rd/QSimpleCrypto/sources/QRsa.cpp new file mode 100644 index 000000000..544d67464 --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QRsa.cpp @@ -0,0 +1,274 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#include "include/QRsa.h" + +QSimpleCrypto::QRsa::QRsa() +{ +} + +/// +/// \brief QSimpleCrypto::QRSA::generateRsaKeys - Function generate Rsa Keys and returns them in OpenSSL structure. +/// \param bits - RSA key size. +/// \param rsaBigNumber - The exponent is an odd number, typically 3, 17 or 65537. +/// \return Returns 'OpenSSL RSA structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'RSA_free()' to avoid memory leak. +/// +RSA* QSimpleCrypto::QRsa::generateRsaKeys(const int& bits, const int& rsaBigNumber) +{ + try { + /* Initialize big number */ + std::unique_ptr bigNumber { BN_new(), BN_free }; + if (bigNumber == nullptr) { + throw std::runtime_error("Couldn't initialize \'bigNumber\'. BN_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return nullptr; + } + + /* Set big number */ + if (!BN_set_word(bigNumber.get(), rsaBigNumber)) { + throw std::runtime_error("Couldn't set bigNumber. BN_set_word(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize RSA */ + RSA* rsa = nullptr; + if (!(rsa = RSA_new())) { + throw std::runtime_error("Couldn't initialize x509. X509_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Generate key pair and store it in RSA */ + if (!RSA_generate_key_ex(rsa, bits, bigNumber.get(), nullptr)) { + throw std::runtime_error("Couldn't generate RSA. RSA_generate_key_ex(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + return rsa; + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::savePublicKey - Saves to file RSA public key. +/// \param rsa - OpenSSL RSA structure. +/// \param publicKeyFileName - Public key file name. +/// +void QSimpleCrypto::QRsa::savePublicKey(RSA* rsa, const QByteArray& publicKeyFileName) +{ + try { + /* Initialize BIO */ + std::unique_ptr bioPublicKey { BIO_new_file(publicKeyFileName.data(), "w+"), BIO_free_all }; + if (bioPublicKey == nullptr) { + throw std::runtime_error("Couldn't initialize \'bioPublicKey\'. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write public key on file */ + if (!PEM_write_bio_RSA_PUBKEY(bioPublicKey.get(), rsa)) { + throw std::runtime_error("Couldn't save public key. PEM_write_bio_RSAPublicKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::savePrivateKey - Saves to file RSA private key. +/// \param rsa - OpenSSL RSA structure. +/// \param privateKeyFileName - Private key file name. +/// \param password - Private key password. +/// \param cipher - Can be used with 'OpenSSL EVP_CIPHER' (ecb, cbc, cfb, ofb, ctr) - 128, 192, 256. Example: EVP_aes_256_cbc(). +/// +void QSimpleCrypto::QRsa::savePrivateKey(RSA* rsa, const QByteArray& privateKeyFileName, QByteArray password, const EVP_CIPHER* cipher) +{ + try { + /* Initialize BIO */ + std::unique_ptr bioPrivateKey { BIO_new_file(privateKeyFileName.data(), "w+"), BIO_free_all }; + if (bioPrivateKey == nullptr) { + throw std::runtime_error("Couldn't initialize bioPrivateKey. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write private key to file */ + if (!PEM_write_bio_RSAPrivateKey(bioPrivateKey.get(), rsa, cipher, reinterpret_cast(password.data()), password.size(), nullptr, nullptr)) { + throw std::runtime_error("Couldn't save private key. PEM_write_bio_RSAPrivateKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::getPublicKeyFromFile - Gets RSA public key from a file. +/// \param filePath - File path to public key file. +/// \return Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak. +/// +EVP_PKEY* QSimpleCrypto::QRsa::getPublicKeyFromFile(const QByteArray& filePath) +{ + try { + /* Initialize BIO */ + std::unique_ptr bioPublicKey { BIO_new_file(filePath.data(), "r"), BIO_free_all }; + if (bioPublicKey == nullptr) { + throw std::runtime_error("Couldn't initialize bioPublicKey. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize EVP_PKEY */ + EVP_PKEY* keyStore = nullptr; + if (!(keyStore = EVP_PKEY_new())) { + throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write private key to file */ + if (!PEM_read_bio_PUBKEY(bioPublicKey.get(), &keyStore, nullptr, nullptr)) { + throw std::runtime_error("Couldn't read private key. PEM_read_bio_PrivateKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + return keyStore; + + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::getPrivateKeyFromFile - Gets RSA private key from a file. +/// \param filePath - File path to private key file. +/// \param password - Private key password. +/// \return - Returns 'OpenSSL EVP_PKEY structure' or 'nullptr', if error happened. Returned value must be cleaned up with 'EVP_PKEY_free()' to avoid memory leak. +/// +EVP_PKEY* QSimpleCrypto::QRsa::getPrivateKeyFromFile(const QByteArray& filePath, const QByteArray& password) +{ + try { + /* Initialize BIO */ + std::unique_ptr bioPrivateKey { BIO_new_file(filePath.data(), "r"), BIO_free_all }; + if (bioPrivateKey == nullptr) { + throw std::runtime_error("Couldn't initialize bioPrivateKey. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize EVP_PKEY */ + EVP_PKEY* keyStore = nullptr; + if (!(keyStore = EVP_PKEY_new())) { + throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write private key to file */ + if (!PEM_read_bio_PrivateKey(bioPrivateKey.get(), &keyStore, nullptr, (void*)password.data())) { + throw std::runtime_error("Couldn't read private key. PEM_read_bio_PrivateKey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + return keyStore; + + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::encrypt - Encrypt data with RSA algorithm. +/// \param plaintext - Text that must be encrypted. +/// \param rsa - OpenSSL RSA structure. +/// \param encryptType - Public or private encrypt type. (PUBLIC_ENCRYPT, PRIVATE_ENCRYPT). +/// \param padding - OpenSSL RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc. +/// \return Returns encrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QRsa::encrypt(QByteArray plainText, RSA* rsa, const int& encryptType, const int& padding) +{ + try { + /* Initialize array. Here encrypted data will be saved */ + std::unique_ptr cipherText { new unsigned char[RSA_size(rsa)]() }; + if (cipherText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'cipherText'."); + } + + /* Result of encryption operation */ + short int result = 0; + + /* Execute encryption operation */ + if (encryptType == PublicDecrypt) { + result = RSA_public_encrypt(plainText.size(), reinterpret_cast(plainText.data()), cipherText.get(), rsa, padding); + } else if (encryptType == PrivateDecrypt) { + result = RSA_private_encrypt(plainText.size(), reinterpret_cast(plainText.data()), cipherText.get(), rsa, padding); + } + + /* Check for result */ + if (result <= -1) { + throw std::runtime_error("Couldn't encrypt data. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Get encrypted data */ + const QByteArray& encryptedData = QByteArray(reinterpret_cast(cipherText.get()), RSA_size(rsa)); + + return encryptedData; + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return ""; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return ""; + } +} + +/// +/// \brief QSimpleCrypto::QRSA::decrypt - Decrypt data with RSA algorithm. +/// \param cipherText - Text that must be decrypted. +/// \param rsa - OpenSSL RSA structure. +/// \param decryptType - Public or private type. (PUBLIC_DECRYPT, PRIVATE_DECRYPT). +/// \param padding - RSA padding can be used with: 'RSA_PKCS1_PADDING', 'RSA_NO_PADDING' and etc. +/// \return - Returns decrypted data or "", if error happened. +/// +QByteArray QSimpleCrypto::QRsa::decrypt(QByteArray cipherText, RSA* rsa, const int& decryptType, const int& padding) +{ + try { + /* Initialize array. Here decrypted data will be saved */ + std::unique_ptr plainText { new unsigned char[cipherText.size()]() }; + if (plainText == nullptr) { + throw std::runtime_error("Couldn't allocate memory for 'plainText'."); + } + + /* Result of decryption operation */ + short int result = 0; + + /* Execute decryption operation */ + if (decryptType == PublicDecrypt) { + result = RSA_public_decrypt(RSA_size(rsa), reinterpret_cast(cipherText.data()), plainText.get(), rsa, padding); + } else if (decryptType == PrivateDecrypt) { + result = RSA_private_decrypt(RSA_size(rsa), reinterpret_cast(cipherText.data()), plainText.get(), rsa, padding); + } + + /* Check for result */ + if (result <= -1) { + throw std::runtime_error("Couldn't decrypt data. Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Get decrypted data */ + const QByteArray& decryptedData = QByteArray(reinterpret_cast(plainText.get())); + + return decryptedData; + } catch (std::exception& exception) { + QSimpleCrypto::QRsa::error.setError(1, exception.what()); + return ""; + } catch (...) { + QSimpleCrypto::QRsa::error.setError(2, "Unknown error!"); + return ""; + } +} diff --git a/client/3rd/QSimpleCrypto/sources/QX509.cpp b/client/3rd/QSimpleCrypto/sources/QX509.cpp new file mode 100644 index 000000000..8666347db --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QX509.cpp @@ -0,0 +1,234 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#include "include/QX509.h" + +QSimpleCrypto::QX509::QX509() +{ +} + +/// +/// \brief QSimpleCrypto::QX509::loadCertificateFromFile - Function load X509 from file and returns OpenSSL structure. +/// \param fileName - File path to certificate. +/// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak. +/// +X509* QSimpleCrypto::QX509::loadCertificateFromFile(const QByteArray& fileName) +{ + try { + /* Initialize X509 */ + X509* x509 = nullptr; + if (!(x509 = X509_new())) { + throw std::runtime_error("Couldn't initialize X509. X509_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize BIO */ + std::unique_ptr certFile { BIO_new_file(fileName.data(), "r+"), BIO_free_all }; + if (certFile == nullptr) { + throw std::runtime_error("Couldn't initialize certFile. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Read file */ + if (!PEM_read_bio_X509(certFile.get(), &x509, nullptr, nullptr)) { + throw std::runtime_error("Couldn't read certificate file from disk. PEM_read_bio_X509(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + return x509; + } catch (std::exception& exception) { + QSimpleCrypto::QX509::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QX509::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QX509::signCertificate - Function signs X509 certificate and returns signed X509 OpenSSL structure. +/// \param endCertificate - Certificate that will be signed +/// \param caCertificate - CA certificate that will sign end certificate +/// \param caPrivateKey - CA certificate private key +/// \param fileName - With that name certificate will be saved. Leave "", if don't need to save it +/// \return Returns OpenSSL X509 structure or nullptr, if error happened. +/// +X509* QSimpleCrypto::QX509::signCertificate(X509* endCertificate, X509* caCertificate, EVP_PKEY* caPrivateKey, const QByteArray& fileName) +{ + try { + /* Set issuer to CA's subject. */ + if (!X509_set_issuer_name(endCertificate, X509_get_subject_name(caCertificate))) { + throw std::runtime_error("Couldn't set issuer name for X509. X509_set_issuer_name(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Sign the certificate with key. */ + if (!X509_sign(endCertificate, caPrivateKey, EVP_sha256())) { + throw std::runtime_error("Couldn't sign X509. X509_sign(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write certificate file on disk. If needed */ + if (!fileName.isEmpty()) { + /* Initialize BIO */ + std::unique_ptr certFile { BIO_new_file(fileName.data(), "w+"), BIO_free_all }; + if (certFile == nullptr) { + throw std::runtime_error("Couldn't initialize certFile. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write file on disk */ + if (!PEM_write_bio_X509(certFile.get(), endCertificate)) { + throw std::runtime_error("Couldn't write certificate file on disk. PEM_write_bio_X509(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } + + return endCertificate; + } catch (std::exception& exception) { + QSimpleCrypto::QX509::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QX509::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QX509::verifyCertificate - Function verifies X509 certificate and returns verified X509 OpenSSL structure. +/// \param x509 - OpenSSL X509. That certificate will be verified. +/// \param store - Trusted certificate must be added to X509_Store with 'addCertificateToStore(X509_STORE* ctx, X509* x509)'. +/// \return Returns OpenSSL X509 structure or nullptr, if error happened +/// +X509* QSimpleCrypto::QX509::verifyCertificate(X509* x509, X509_STORE* store) +{ + try { + /* Initialize X509_STORE_CTX */ + std::unique_ptr ctx { X509_STORE_CTX_new(), X509_STORE_CTX_free }; + if (ctx == nullptr) { + throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set up CTX for a subsequent verification operation */ + if (!X509_STORE_CTX_init(ctx.get(), store, x509, nullptr)) { + throw std::runtime_error("Couldn't initialize X509_STORE_CTX. X509_STORE_CTX_init(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Verify X509 */ + if (!X509_verify_cert(ctx.get())) { + throw std::runtime_error("Couldn't verify cert. X509_verify_cert(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + return x509; + } catch (std::exception& exception) { + QSimpleCrypto::QX509::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QX509::error.setError(2, "Unknown error!"); + return nullptr; + } +} + +/// +/// \brief QSimpleCrypto::QX509::generateSelfSignedCertificate - Function generatesand returns self signed X509. +/// \param rsa - OpenSSL RSA. +/// \param additionalData - Certificate information. +/// \param certificateFileName - With that name certificate will be saved. Leave "", if don't need to save it. +/// \param md - OpenSSL EVP_MD structure. Example: EVP_sha512(). +/// \param serialNumber - X509 certificate serial number. +/// \param version - X509 certificate version. +/// \param notBefore - X509 start date. +/// \param notAfter - X509 end date. +/// \return Returns OpenSSL X509 structure or nullptr, if error happened. Returned value must be cleaned up with 'X509_free' to avoid memory leak. +/// +X509* QSimpleCrypto::QX509::generateSelfSignedCertificate(const RSA* rsa, const QMap& additionalData, + const QByteArray& certificateFileName, const EVP_MD* md, + const long& serialNumber, const long& version, + const long& notBefore, const long& notAfter) +{ + try { + /* Initialize X509 */ + X509* x509 = nullptr; + if (!(x509 = X509_new())) { + throw std::runtime_error("Couldn't initialize X509. X509_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize EVP_PKEY */ + std::unique_ptr keyStore { EVP_PKEY_new(), EVP_PKEY_free }; + if (keyStore == nullptr) { + throw std::runtime_error("Couldn't initialize keyStore. EVP_PKEY_new(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Sign rsa key */ + if (!EVP_PKEY_assign_RSA(keyStore.get(), rsa)) { + throw std::runtime_error("Couldn't assign rsa. EVP_PKEY_assign_RSA(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set certificate serial number. */ + if (!ASN1_INTEGER_set(X509_get_serialNumber(x509), serialNumber)) { + throw std::runtime_error("Couldn't set serial number. ASN1_INTEGER_set(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set certificate version */ + if (!X509_set_version(x509, version)) { + throw std::runtime_error("Couldn't set version. X509_set_version(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Set certificate creation and expiration date */ + X509_gmtime_adj(X509_get_notBefore(x509), notBefore); + X509_gmtime_adj(X509_get_notAfter(x509), notAfter); + + /* Set certificate public key */ + if (!X509_set_pubkey(x509, keyStore.get())) { + throw std::runtime_error("Couldn't set public key. X509_set_pubkey(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Initialize X509_NAME */ + X509_NAME* x509Name = X509_get_subject_name(x509); + if (x509Name == nullptr) { + throw std::runtime_error("Couldn't initialize X509_NAME. X509_NAME(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Add additional data to certificate */ + QMapIterator certificateInformationList(additionalData); + while (certificateInformationList.hasNext()) { + /* Read next item in list */ + certificateInformationList.next(); + + /* Set additional data */ + if (!X509_NAME_add_entry_by_txt(x509Name, certificateInformationList.key().data(), MBSTRING_UTF8, reinterpret_cast(certificateInformationList.value().data()), -1, -1, 0)) { + throw std::runtime_error("Couldn't set additional information. X509_NAME_add_entry_by_txt(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } + + /* Set certificate info */ + if (!X509_set_issuer_name(x509, x509Name)) { + throw std::runtime_error("Couldn't set issuer name. X509_set_issuer_name(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Sign certificate */ + if (!X509_sign(x509, keyStore.get(), md)) { + throw std::runtime_error("Couldn't sign X509. X509_sign(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write certificate file on disk. If needed */ + if (!certificateFileName.isEmpty()) { + /* Initialize BIO */ + std::unique_ptr certFile { BIO_new_file(certificateFileName.data(), "w+"), BIO_free_all }; + if (certFile == nullptr) { + throw std::runtime_error("Couldn't initialize certFile. BIO_new_file(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + + /* Write file on disk */ + if (!PEM_write_bio_X509(certFile.get(), x509)) { + throw std::runtime_error("Couldn't write certificate file on disk. PEM_write_bio_X509(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + } + } + + return x509; + } catch (std::exception& exception) { + QSimpleCrypto::QX509::error.setError(1, exception.what()); + return nullptr; + } catch (...) { + QSimpleCrypto::QX509::error.setError(2, "Unknown error!"); + return nullptr; + } +} diff --git a/client/3rd/QSimpleCrypto/sources/QX509Store.cpp b/client/3rd/QSimpleCrypto/sources/QX509Store.cpp new file mode 100644 index 000000000..bbbec1a84 --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QX509Store.cpp @@ -0,0 +1,176 @@ +/** + * Copyright 2021 BrutalWizard (https://github.com/bru74lw1z4rd). All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution +**/ + +#include "include/QX509Store.h" + +QSimpleCrypto::QX509Store::QX509Store() +{ +} + +/// +/// \brief QSimpleCrypto::QX509::addCertificateToStore +/// \param store - OpenSSL X509_STORE. +/// \param x509 - OpenSSL X509. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::addCertificateToStore(X509_STORE* store, X509* x509) +{ + if (!X509_STORE_add_cert(store, x509)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't add certificate to X509_STORE. X509_STORE_add_cert(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::addLookup +/// \param store - OpenSSL X509_STORE. +/// \param method - OpenSSL X509_LOOKUP_METHOD. Example: X509_LOOKUP_file. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::addLookup(X509_STORE* store, X509_LOOKUP_METHOD* method) +{ + if (!X509_STORE_add_lookup(store, method)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't add lookup to X509_STORE. X509_STORE_add_lookup(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::setCertificateDepth +/// \param store - OpenSSL X509_STORE. +/// \param depth - That is the maximum number of untrusted CA certificates that can appear in a chain. Example: 0. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::setDepth(X509_STORE* store, const int& depth) +{ + if (!X509_STORE_set_depth(store, depth)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set depth for X509_STORE. X509_STORE_set_depth(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::setFlag +/// \param store - OpenSSL X509_STORE. +/// \param flag - The verification flags consists of zero or more of the following flags ored together. Example: X509_V_FLAG_CRL_CHECK. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::setFlag(X509_STORE* store, const unsigned long& flag) +{ + if (!X509_STORE_set_flags(store, flag)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set flag for X509_STORE. X509_STORE_set_flags(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::setFlag +/// \param store - OpenSSL X509_STORE. +/// \param purpose - Verification purpose in param to purpose. Example: X509_PURPOSE_ANY. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::setPurpose(X509_STORE* store, const int& purpose) +{ + if (!X509_STORE_set_purpose(store, purpose)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set purpose for X509_STORE. X509_STORE_set_purpose(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::setTrust +/// \param store - OpenSSL X509_STORE. +/// \param trust - Trust Level. Example: X509_TRUST_SSL_SERVER. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::setTrust(X509_STORE* store, const int& trust) +{ + if (!X509_STORE_set_trust(store, trust)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set trust for X509_STORE. X509_STORE_set_trust(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::setDefaultPaths +/// \param store - OpenSSL X509_STORE. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::setDefaultPaths(X509_STORE* store) +{ + if (!X509_STORE_set_default_paths(store)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't set default paths for X509_STORE. X509_STORE_set_default_paths(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::loadLocations +/// \param store - OpenSSL X509_STORE. +/// \param fileName - File name. Example: "caCertificate.pem". +/// \param dirPath - Path to file. Example: "path/To/File". +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::loadLocations(X509_STORE* store, const QByteArray& fileName, const QByteArray& dirPath) +{ + if (!X509_STORE_load_locations(store, fileName, dirPath)) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't load locations for X509_STORE. X509_STORE_load_locations(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::loadLocations +/// \param store - OpenSSL X509_STORE. +/// \param file - Qt QFile that will be loaded. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::loadLocations(X509_STORE* store, const QFile& file) +{ + /* Initialize QFileInfo to read information about file */ + QFileInfo info(file); + + if (!X509_STORE_load_locations(store, info.fileName().toLocal8Bit(), info.absoluteDir().path().toLocal8Bit())) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't load locations for X509_STORE. X509_STORE_load_locations(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} + +/// +/// \brief QSimpleCrypto::QX509Store::loadLocations +/// \param store - OpenSSL X509_STORE. +/// \param fileInfo - Qt QFileInfo. +/// \return Returns 'true' on success and 'false', if error happened. +/// +bool QSimpleCrypto::QX509Store::loadLocations(X509_STORE* store, const QFileInfo& fileInfo) +{ + if (!X509_STORE_load_locations(store, fileInfo.fileName().toLocal8Bit(), fileInfo.absoluteDir().path().toLocal8Bit())) { + QSimpleCrypto::QX509Store::error.setError(1, "Couldn't load locations for X509_STORE. X509_STORE_load_locations(). Error: " + QByteArray(ERR_error_string(ERR_get_error(), nullptr))); + return false; + } + + return true; +} diff --git a/client/client.pro b/client/client.pro index 9d2180f75..023f0e184 100644 --- a/client/client.pro +++ b/client/client.pro @@ -16,7 +16,9 @@ include("3rd/QtSsh/src/botan/botan.pri") !android:!ios:include("3rd/SingleApplication/singleapplication.pri") include ("3rd/SortFilterProxyModel/SortFilterProxyModel.pri") include("3rd/qzxing/src/QZXing-components.pri") +include("3rd/QSimpleCrypto/QSimpleCrypto.pri") +INCLUDEPATH += $$PWD/3rd/QSimpleCrypto/include INCLUDEPATH += $$PWD/3rd/OpenSSL/include DEPENDPATH += $$PWD/3rd/OpenSSL/include @@ -37,7 +39,6 @@ HEADERS += \ core/servercontroller.h \ debug.h \ defines.h \ - encryption_helper.h \ managementserver.h \ platforms/ios/MobileUtils.h \ platforms/linux/leakdetector.h \ @@ -96,7 +97,6 @@ SOURCES += \ core/server_defs.cpp \ core/servercontroller.cpp \ debug.cpp \ - encryption_helper.cpp \ main.cpp \ managementserver.cpp \ platforms/ios/MobileUtils.cpp \ @@ -169,7 +169,6 @@ win32 { -lshlwapi \ -liphlpapi \ -lws2_32 \ - -liphlpapi \ -lgdi32 diff --git a/client/encryption_helper.cpp b/client/encryption_helper.cpp deleted file mode 100644 index 6c1bffda8..000000000 --- a/client/encryption_helper.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "encryption_helper.h" - -#include -#include -#include - -#include "openssl/evp.h" - -int gcm_encrypt(const char *plaintext, int plaintext_len, - const char *key, const char *iv, int iv_len, - char *ciphertext) -{ - return gcm_encrypt((uchar*)plaintext, plaintext_len, - (uchar*)key, (uchar*)iv, iv_len, - (uchar*)ciphertext); -} - -int gcm_decrypt(const char *ciphertext, int ciphertext_len, - const char *key, - const char *iv, int iv_len, - char *plaintext) -{ - return gcm_decrypt((uchar*)ciphertext, ciphertext_len, - (uchar*)key, (uchar*)iv, iv_len, - (uchar*)plaintext); -} - -void handleErrors() { - qDebug() << "handleErrors"; -} - -int generate_key_and_iv(unsigned char *iv, unsigned char *key) { -// unsigned char key[32]; -// unsigned char iv[16]; -// EVP_BytesToKey(EVP_aes_256_gcm(), EVP_md5(), -// NULL, -// key_file_buf, key_size, 1, // const unsigned char *data, int datal, int count, -// key, iv); - return 0; -} - -int gcm_encrypt(const unsigned char *plaintext, int plaintext_len, - const unsigned char *key, - const unsigned char *iv, int iv_len, - unsigned char *ciphertext) -{ - EVP_CIPHER_CTX *ctx; - int len; - int ciphertext_len; - - /* Create and initialise the context */ - if(!(ctx = EVP_CIPHER_CTX_new())) - handleErrors(); - - /* Initialise the encryption operation. */ - if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) - handleErrors(); - - /* - * Set IV length if default 12 bytes (96 bits) is not appropriate - */ - if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) - handleErrors(); - - /* Initialise key and IV */ - if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) - handleErrors(); - - /* - * Provide the message to be encrypted, and obtain the encrypted output. - * EVP_EncryptUpdate can be called multiple times if necessary - */ - if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) - handleErrors(); - ciphertext_len = len; - - /* - * Finalise the encryption. Normally ciphertext bytes may be written at - * this stage, but this does not occur in GCM mode - */ - if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) - handleErrors(); - ciphertext_len += len; - - /* Clean up */ - EVP_CIPHER_CTX_free(ctx); - - return ciphertext_len; -} - -int gcm_decrypt(const unsigned char *ciphertext, int ciphertext_len, - const unsigned char *key, - const unsigned char *iv, int iv_len, - unsigned char *plaintext) -{ - EVP_CIPHER_CTX *ctx; - int len; - int plaintext_len; - int ret; - - /* Create and initialise the context */ - if(!(ctx = EVP_CIPHER_CTX_new())) - handleErrors(); - - /* Initialise the decryption operation. */ - if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) - handleErrors(); - - /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ - if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) - handleErrors(); - - /* Initialise key and IV */ - if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) - handleErrors(); - - /* - * Provide the message to be decrypted, and obtain the plaintext output. - * EVP_DecryptUpdate can be called multiple times if necessary - */ - if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) - handleErrors(); - plaintext_len = len; - - /* - * Finalise the decryption. A positive return value indicates success, - * anything else is a failure - the plaintext is not trustworthy. - */ - ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len); - - /* Clean up */ - EVP_CIPHER_CTX_free(ctx); - - if(ret > 0) { - /* Success */ - plaintext_len += len; - return plaintext_len; - } else { - /* Verify failed */ - return -1; - } -} - diff --git a/client/encryption_helper.h b/client/encryption_helper.h deleted file mode 100644 index ba9214087..000000000 --- a/client/encryption_helper.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef ENCRYPTION_HELPER_H -#define ENCRYPTION_HELPER_H - -#include -#include - - - -int gcm_encrypt(const char *plaintext, int plaintext_len, - const char *key, - const char *iv, int iv_len, - char *ciphertext); - -int gcm_decrypt(const char *ciphertext, int ciphertext_len, - const char *key, - const char *iv, int iv_len, - char *plaintext); - - -int gcm_encrypt(const unsigned char *plaintext, int plaintext_len, - const unsigned char *key, - const unsigned char *iv, int iv_len, - unsigned char *ciphertext); - -int gcm_decrypt(const unsigned char *ciphertext, int ciphertext_len, - const unsigned char *key, - const unsigned char *iv, int iv_len, - unsigned char *plaintext); - - -#endif // ENCRYPTION_HELPER_H diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index 0b2f138ea..46d490adc 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -1,35 +1,37 @@ #include "secure_qsettings.h" -#include "encryption_helper.h" #include "platforms/ios/MobileUtils.h" #include #include +#include "utils.h" +#include +#include "QAead.h" +#include "QBlockCipher.h" SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent) : QObject{parent}, - m_setting(organization, application, parent), + m_settings(organization, application, parent), encryptedKeys({"Servers/serversList"}) { + qDebug() << "SecureQSettings::SecureQSettings CTOR"; // load keys from system key storage #ifdef Q_OS_IOS - key = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsKeyTag).toUtf8()); - iv = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsIvTag).toUtf8()); + m_key = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsKeyTag).toUtf8()); + m_iv = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsIvTag).toUtf8()); #endif - key = "12345qwerty00000"; - iv = "000000000000000"; - bool encrypted = m_setting.value("Conf/encrypted").toBool(); + bool encrypted = m_settings.value("Conf/encrypted").toBool(); - // convert settings to encrypted + // convert settings to encrypted for if updated to >= 2.1.0 if (encryptionRequired() && ! encrypted) { - for (const QString &key : m_setting.allKeys()) { + for (const QString &key : m_settings.allKeys()) { if (encryptedKeys.contains(key)) { const QVariant &val = value(key); setValue(key, val); } } - m_setting.setValue("Conf/encrypted", true); - m_setting.sync(); + m_settings.setValue("Conf/encrypted", true); + m_settings.sync(); } } @@ -39,18 +41,36 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue return m_cache.value(key); } + if (!m_settings.contains(key)) return defaultValue; + QVariant retVal; - if (encryptionRequired() && encryptedKeys.contains(key)) { - if (!m_setting.contains(key)) return defaultValue; - QByteArray encryptedValue = m_setting.value(key).toByteArray(); - QByteArray decryptedValue = decryptText(encryptedValue); + // check if value is not encrypted, v. < 2.0.x + retVal = m_settings.value(key); + if (retVal.isValid()) { + if (retVal.userType() == QVariant::ByteArray && + retVal.toByteArray().mid(0, magicString.size()) == magicString) { - QDataStream ds(&decryptedValue, QIODevice::ReadOnly); - ds >> retVal; + if (m_key.isEmpty() || m_iv.isEmpty()) { + qCritical() << "SecureQSettings::setValue Decryption requested, but key is empty"; + return {}; + } + + QByteArray encryptedValue = retVal.toByteArray().mid(magicString.size()); + + QByteArray decryptedValue = decryptText(encryptedValue); + QDataStream ds(&decryptedValue, QIODevice::ReadOnly); + + ds >> retVal; + + if (!retVal.isValid()) { + qWarning() << "SecureQSettings::value settings decryption failed"; + } + } } else { - retVal = m_setting.value(key, defaultValue); + qWarning() << "SecureQSettings::value invalid QVariant value"; + retVal = QVariant(); } m_cache.insert(key, retVal); @@ -61,17 +81,24 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue void SecureQSettings::setValue(const QString &key, const QVariant &value) { if (encryptionRequired() && encryptedKeys.contains(key)) { - QByteArray decryptedValue; - { - QDataStream ds(&decryptedValue, QIODevice::WriteOnly); - ds << value; + if (!m_key.isEmpty() && !m_iv.isEmpty()) { + QByteArray decryptedValue; + { + QDataStream ds(&decryptedValue, QIODevice::WriteOnly); + ds << value; + } + + QByteArray encryptedValue = encryptText(decryptedValue); + m_settings.setValue(key, magicString + encryptedValue); + } + else { + qCritical() << "SecureQSettings::setValue Encryption required, but key is empty"; + return; } - QByteArray encryptedValue = encryptText(decryptedValue); - m_setting.setValue(key, encryptedValue); } else { - m_setting.setValue(key, value); + m_settings.setValue(key, value); } m_cache.insert(key, value); @@ -80,7 +107,7 @@ void SecureQSettings::setValue(const QString &key, const QVariant &value) void SecureQSettings::remove(const QString &key) { - m_setting.remove(key); + m_settings.remove(key); m_cache.remove(key); sync(); @@ -88,13 +115,13 @@ void SecureQSettings::remove(const QString &key) void SecureQSettings::sync() { - m_setting.sync(); + m_settings.sync(); } QByteArray SecureQSettings::backupAppConfig() const { QMap cfg; - for (const QString &key : m_setting.allKeys()) { + for (const QString &key : m_settings.allKeys()) { cfg.insert(key, value(key)); } @@ -125,20 +152,16 @@ void SecureQSettings::restoreAppConfig(const QByteArray &base64Cfg) } -QByteArray SecureQSettings::encryptText(const QByteArray& value) const { - char cipherText[UINT16_MAX]; - int cipherTextSize = gcm_encrypt(value.constData(), value.size(), - key.constData(), iv.constData(), iv_len, cipherText); - - return QByteArray::fromRawData((const char *)cipherText, cipherTextSize); +QByteArray SecureQSettings::encryptText(const QByteArray& value) const +{ + QSimpleCrypto::QBlockCipher cipher; + return cipher.encryptAesBlockCipher(value, m_key, m_iv); } -QByteArray SecureQSettings::decryptText(const QByteArray& ba) const { - char decryptPlainText[UINT16_MAX]; - gcm_decrypt(ba.data(), ba.size(), - key.constData(), iv.constData(), iv_len, decryptPlainText); - - return QByteArray::fromRawData(decryptPlainText, ba.size()); +QByteArray SecureQSettings::decryptText(const QByteArray& ba) const +{ + QSimpleCrypto::QBlockCipher cipher; + return cipher.decryptAesBlockCipher(ba, m_key, m_iv); } bool SecureQSettings::encryptionRequired() const diff --git a/client/secure_qsettings.h b/client/secure_qsettings.h index 3fcd4ed7c..ae2a19b72 100644 --- a/client/secure_qsettings.h +++ b/client/secure_qsettings.h @@ -7,6 +7,7 @@ constexpr const char* settingsKeyTag = "settingsKeyTag"; constexpr const char* settingsIvTag = "settingsIvTag"; + class SecureQSettings : public QObject { public: @@ -26,15 +27,17 @@ public: bool encryptionRequired() const; private: - QSettings m_setting; + QSettings m_settings; mutable QMap m_cache; QStringList encryptedKeys; // encode only key listed here - QByteArray key; - QByteArray iv; - int iv_len {16}; + QByteArray m_key; + QByteArray m_iv; + + const QByteArray magicString { "EncData" }; // Magic keyword used for mark encrypted QByteArray + }; #endif // SECUREQSETTINGS_H diff --git a/client/settings.cpp b/client/settings.cpp index c8069f70f..21deb0bd1 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -8,7 +8,6 @@ const char Settings::cloudFlareNs1[] = "1.1.1.1"; const char Settings::cloudFlareNs2[] = "1.0.0.1"; -//SecureFormat Settings::m_secureFormat; Settings::Settings(QObject* parent) : QObject(parent), diff --git a/client/settings.h b/client/settings.h index 39c9919c0..18337f0d7 100644 --- a/client/settings.h +++ b/client/settings.h @@ -11,7 +11,6 @@ #include "core/defs.h" #include "containers/containers_defs.h" -#include "encryption_helper.h" #include "secure_qsettings.h" using namespace amnezia; From b3d54ce57eb3b36eab879d397be1e47b9f85e4d9 Mon Sep 17 00:00:00 2001 From: pokamest Date: Wed, 24 Aug 2022 16:58:00 +0300 Subject: [PATCH 16/52] PageServerContainers animation fixed [ci skip] --- client/ui/qml/Pages/PageServerContainers.qml | 901 +++++++++---------- 1 file changed, 439 insertions(+), 462 deletions(-) diff --git a/client/ui/qml/Pages/PageServerContainers.qml b/client/ui/qml/Pages/PageServerContainers.qml index fb5dd97e6..4b05568a3 100644 --- a/client/ui/qml/Pages/PageServerContainers.qml +++ b/client/ui/qml/Pages/PageServerContainers.qml @@ -1,462 +1,439 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Dialogs 1.1 -import QtQuick.Layouts 1.15 -import SortFilterProxyModel 0.2 -import ContainerProps 1.0 -import ProtocolProps 1.0 -import PageEnum 1.0 -import ProtocolEnum 1.0 -import "./" -import "../Controls" -import "../Config" -import "InstallSettings" - -PageBase { - id: root - page: PageEnum.ServerContainers - logic: ServerContainersLogic - - enabled: ServerContainersLogic.pageEnabled - - function resetPage() { - container_selector.selectedIndex = -1 - } - - Connections { - target: logic - function onUpdatePage() { - root.resetPage() - } - } - - BackButton { - id: back - } - Caption { - id: caption - text: container_selector.selectedIndex > 0 ? qsTr("Install new service") : qsTr("Installed services") - } - - SelectContainer { - id: container_selector - - onAboutToHide: { - pageLoader.focus = true - } - - onContainerSelected: { - var containerProto = ContainerProps.defaultProtocol(c_index) - - - if (ProtocolProps.defaultPort(containerProto) < 0) { - tf_port_num.enabled = false - tf_port_num.text = qsTr("Default") - } - else tf_port_num.text = ProtocolProps.defaultPort(containerProto) - - cb_port_proto.currentIndex = ProtocolProps.defaultTransportProto(containerProto) - - tf_port_num.enabled = ProtocolProps.defaultPortChangeable(containerProto) - cb_port_proto.enabled = ProtocolProps.defaultTransportProtoChangeable(containerProto) - } - } - - Column { - id: c1 - visible: container_selector.selectedIndex > 0 - width: parent.width - anchors.top: caption.bottom - anchors.topMargin: 10 - - Caption { - font.pixelSize: 22 - text: UiLogic.containerName(container_selector.selectedIndex) - } - - Text { - width: parent.width - anchors.topMargin: 10 - padding: 10 - - font.family: "Lato" - font.styleName: "normal" - font.pixelSize: 16 - color: "#181922" - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - wrapMode: Text.Wrap - - text: UiLogic.containerDesc(container_selector.selectedIndex) - } - } - - Rectangle { - id: frame_settings - visible: container_selector.selectedIndex > 0 - width: parent.width - anchors.top: c1.bottom - anchors.topMargin: 10 - - border.width: 1 - border.color: "lightgray" - anchors.bottomMargin: 5 - anchors.horizontalCenter: parent.horizontalCenter - radius: 2 - Grid { - id: grid - visible: container_selector.selectedIndex > 0 - anchors.fill: parent - columns: 2 - horizontalItemAlignment: Grid.AlignHCenter - verticalItemAlignment: Grid.AlignVCenter - topPadding: 5 - leftPadding: 10 - spacing: 5 - - - LabelType { - width: 130 - text: qsTr("Port") - } - TextFieldType { - id: tf_port_num - width: parent.width - 130 - parent.spacing - parent.leftPadding * 2 - } - LabelType { - width: 130 - text: qsTr("Network Protocol") - } - ComboBoxType { - id: cb_port_proto - width: parent.width - 130 - parent.spacing - parent.leftPadding * 2 - model: [ - qsTr("udp"), - qsTr("tcp"), - ] - } - } - } - - BlueButtonType { - id: pb_cancel_add - visible: container_selector.selectedIndex > 0 - - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: pb_continue_add.top - anchors.bottomMargin: 20 - - width: parent.width - 40 - height: 40 - text: qsTr("Cancel") - font.pixelSize: 16 - onClicked: container_selector.selectedIndex = -1 - - } - - BlueButtonType { - id: pb_continue_add - visible: container_selector.selectedIndex > 0 - - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.bottomMargin: 20 - - width: parent.width - 40 - height: 40 - text: qsTr("Continue") - font.pixelSize: 16 - onClicked: { - let cont = container_selector.selectedIndex - let tp = ProtocolProps.transportProtoFromString(cb_port_proto.currentText) - let port = tf_port_num.text - ServerContainersLogic.onPushButtonContinueClicked(cont, port, tp) - } - } - - - - - - Flickable { - visible: container_selector.selectedIndex <= 0 - clip: true - width: parent.width - anchors.top: caption.bottom - anchors.bottom: pb_add_container.top - contentHeight: col.height - - Column { - visible: container_selector.selectedIndex <= 0 - id: col - anchors { - left: parent.left; - right: parent.right; - } - topPadding: 20 - spacing: 10 - - Caption { - id: cap1 - text: qsTr("Installed Protocols and Services") - font.pixelSize: 20 - - } - - SortFilterProxyModel { - id: proxyContainersModel - sourceModel: UiLogic.containersModel - filters: ValueFilter { - roleName: "is_installed_role" - value: true - } - } - - SortFilterProxyModel { - id: proxyProtocolsModel - sourceModel: UiLogic.protocolsModel - filters: ValueFilter { - roleName: "is_installed_role" - value: true - } - } - - - ListView { - id: tb_c - x: 10 - width: parent.width - 10 - height: tb_c.contentItem.height - currentIndex: -1 - spacing: 5 - clip: true - interactive: false - model: proxyContainersModel - - delegate: Item { - implicitWidth: tb_c.width - 10 - implicitHeight: c_item.height - Item { - id: c_item - width: parent.width - height: row_container.height + tb_p.height - anchors.left: parent.left - Rectangle { - anchors.top: parent.top - width: parent.width - height: 1 - color: "lightgray" - visible: index !== tb_c.currentIndex - } - Rectangle { - anchors.top: row_container.top - anchors.bottom: row_container.bottom - anchors.left: parent.left - anchors.right: parent.right - - color: "#63B4FB" - visible: index === tb_c.currentIndex - } - - RowLayout { - id: row_container - //width: parent.width - anchors.left: parent.left - anchors.right: parent.right - -// anchors.top: lb_container_name.top -// anchors.bottom: lb_container_name.bottom - - Text { - id: lb_container_name - text: name_role - font.pixelSize: 17 - //font.bold: true - color: "#100A44" - topPadding: 5 - bottomPadding: 5 - leftPadding: 10 - verticalAlignment: Text.AlignVCenter - wrapMode: Text.WordWrap - Layout.fillWidth: true - - MouseArea { - enabled: col.visible - anchors.top: lb_container_name.top - anchors.bottom: lb_container_name.bottom - anchors.left: parent.left - anchors.right: parent.right - propagateComposedEvents: true - onClicked: { - if (tb_c.currentIndex === index) tb_c.currentIndex = -1 - else tb_c.currentIndex = index - - UiLogic.protocolsModel.setSelectedDockerContainer(proxyContainersModel.mapToSource(index)) - } - } - } - - ImageButtonType { - id: button_remove - visible: index === tb_c.currentIndex - Layout.alignment: Qt.AlignRight - checkable: true - icon.source: "qrc:/images/delete.png" - implicitWidth: 30 - implicitHeight: 30 - - checked: default_role - - MessageDialog { - id: dialogRemove - standardButtons: StandardButton.Yes | StandardButton.Cancel - title: "AmneziaVPN" - text: qsTr("Remove container") + " " + name_role + "?" + "\n" + qsTr("This action will erase all data of this container on the server.") - onAccepted: { - tb_c.currentIndex = -1 - ServerContainersLogic.onPushButtonRemoveClicked(proxyContainersModel.mapToSource(index)) - } - } - - onClicked: dialogRemove.open() - - VisibleBehavior on visible { } - } - - ImageButtonType { - id: button_share - visible: index === tb_c.currentIndex - Layout.alignment: Qt.AlignRight - icon.source: "qrc:/images/share.png" - implicitWidth: 30 - implicitHeight: 30 - onClicked: { - ServerContainersLogic.onPushButtonShareClicked(proxyContainersModel.mapToSource(index)) - } - - VisibleBehavior on visible { } - } - - ImageButtonType { - id: button_default - visible: service_type_role == ProtocolEnum.Vpn - - Layout.alignment: Qt.AlignRight - checkable: true - img.source: checked ? "qrc:/images/check.png" : "qrc:/images/uncheck.png" - implicitWidth: 30 - implicitHeight: 30 - - checked: default_role - onClicked: { - ServerContainersLogic.onPushButtonDefaultClicked(proxyContainersModel.mapToSource(index)) - } - } - } - - - ListView { - id: tb_p - currentIndex: -1 - visible: index === tb_c.currentIndex - x: 10 - anchors.top: row_container.bottom - - width: parent.width - 40 - height: visible ? tb_p.contentItem.height : 0 - - spacing: 0 - clip: true - interactive: false - model: proxyProtocolsModel - - VisibleBehavior on visible { } - - - delegate: Item { - id: dp_item - - implicitWidth: tb_p.width - 10 - implicitHeight: p_item.height - Item { - id: p_item - width: parent.width - height: lb_protocol_name.height - anchors.left: parent.left - Rectangle { - anchors.top: parent.top - width: parent.width - height: 1 - color: "lightgray" - visible: index !== tb_p.currentIndex - } -// Rectangle { -// anchors.top: lb_protocol_name.top -// anchors.bottom: lb_protocol_name.bottom -// width: parent.width - -// color: "#63B4FB" -// visible: index === tb_p.currentIndex -// } - -// Text { -// id: lb_protocol_name -// text: name_role -// font.pixelSize: 16 -// topPadding: 5 -// bottomPadding: 5 -// leftPadding: 10 -// verticalAlignment: Text.AlignVCenter -// wrapMode: Text.WordWrap -// } - - SettingButtonType { - id: lb_protocol_name - -// anchors.top: lb_protocol_name.top -// anchors.bottom: lb_protocol_name.bottom - topPadding: 10 - bottomPadding: 10 - leftPadding: 10 - - anchors.left: parent.left - - width: parent.width - height: 30 - text: qsTr(name_role + " settings") - textItem.font.pixelSize: 16 - icon.source: "qrc:/images/settings.png" - onClicked: { - tb_p.currentIndex = index - ServerContainersLogic.onPushButtonProtoSettingsClicked( - proxyContainersModel.mapToSource(tb_c.currentIndex), - proxyProtocolsModel.mapToSource(tb_p.currentIndex)) - } - } - } - } - } - } - } - } - } - } - - - BlueButtonType { - id: pb_add_container - visible: container_selector.selectedIndex < 0 - - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.topMargin: 10 - anchors.bottomMargin: 20 - - width: parent.width - 40 - height: 40 - text: qsTr("Install new protocols container") - font.pixelSize: 16 - onClicked: container_selector.visible ? container_selector.close() : container_selector.open() - - } -} +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Dialogs 1.1 +import QtQuick.Layouts 1.15 +import SortFilterProxyModel 0.2 +import ContainerProps 1.0 +import ProtocolProps 1.0 +import PageEnum 1.0 +import ProtocolEnum 1.0 +import "./" +import "../Controls" +import "../Config" +import "InstallSettings" + +PageBase { + id: root + page: PageEnum.ServerContainers + logic: ServerContainersLogic + + enabled: ServerContainersLogic.pageEnabled + + function resetPage() { + container_selector.selectedIndex = -1 + } + + Connections { + target: logic + function onUpdatePage() { + root.resetPage() + } + } + + BackButton { + id: back + } + Caption { + id: caption + text: container_selector.selectedIndex > 0 ? qsTr("Install new service") : qsTr("Installed services") + } + + SelectContainer { + id: container_selector + + onAboutToHide: { + pageLoader.focus = true + } + + onContainerSelected: { + var containerProto = ContainerProps.defaultProtocol(c_index) + + + if (ProtocolProps.defaultPort(containerProto) < 0) { + tf_port_num.enabled = false + tf_port_num.text = qsTr("Default") + } + else tf_port_num.text = ProtocolProps.defaultPort(containerProto) + + cb_port_proto.currentIndex = ProtocolProps.defaultTransportProto(containerProto) + + tf_port_num.enabled = ProtocolProps.defaultPortChangeable(containerProto) + cb_port_proto.enabled = ProtocolProps.defaultTransportProtoChangeable(containerProto) + } + } + + Column { + id: c1 + visible: container_selector.selectedIndex > 0 + width: parent.width + anchors.top: caption.bottom + anchors.topMargin: 10 + + Caption { + font.pixelSize: 22 + text: UiLogic.containerName(container_selector.selectedIndex) + } + + Text { + width: parent.width + anchors.topMargin: 10 + padding: 10 + + font.family: "Lato" + font.styleName: "normal" + font.pixelSize: 16 + color: "#181922" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + wrapMode: Text.Wrap + + text: UiLogic.containerDesc(container_selector.selectedIndex) + } + } + + Rectangle { + id: frame_settings + visible: container_selector.selectedIndex > 0 + width: parent.width + anchors.top: c1.bottom + anchors.topMargin: 10 + + border.width: 1 + border.color: "lightgray" + anchors.bottomMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + radius: 2 + Grid { + id: grid + visible: container_selector.selectedIndex > 0 + anchors.fill: parent + columns: 2 + horizontalItemAlignment: Grid.AlignHCenter + verticalItemAlignment: Grid.AlignVCenter + topPadding: 5 + leftPadding: 10 + spacing: 5 + + + LabelType { + width: 130 + text: qsTr("Port") + } + TextFieldType { + id: tf_port_num + width: parent.width - 130 - parent.spacing - parent.leftPadding * 2 + } + LabelType { + width: 130 + text: qsTr("Network Protocol") + } + ComboBoxType { + id: cb_port_proto + width: parent.width - 130 - parent.spacing - parent.leftPadding * 2 + model: [ + qsTr("udp"), + qsTr("tcp"), + ] + } + } + } + + BlueButtonType { + id: pb_cancel_add + visible: container_selector.selectedIndex > 0 + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: pb_continue_add.top + anchors.bottomMargin: 20 + + width: parent.width - 40 + height: 40 + text: qsTr("Cancel") + font.pixelSize: 16 + onClicked: container_selector.selectedIndex = -1 + + } + + BlueButtonType { + id: pb_continue_add + visible: container_selector.selectedIndex > 0 + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + + width: parent.width - 40 + height: 40 + text: qsTr("Continue") + font.pixelSize: 16 + onClicked: { + let cont = container_selector.selectedIndex + let tp = ProtocolProps.transportProtoFromString(cb_port_proto.currentText) + let port = tf_port_num.text + ServerContainersLogic.onPushButtonContinueClicked(cont, port, tp) + } + } + + + + + + Flickable { + visible: container_selector.selectedIndex <= 0 + clip: true + width: parent.width + anchors.top: caption.bottom + anchors.bottom: pb_add_container.top + contentHeight: col.height + + Column { + visible: container_selector.selectedIndex <= 0 + id: col + anchors { + left: parent.left; + right: parent.right; + } + topPadding: 20 + spacing: 10 + + Caption { + id: cap1 + text: qsTr("Installed Protocols and Services") + font.pixelSize: 20 + + } + + SortFilterProxyModel { + id: proxyContainersModel + sourceModel: UiLogic.containersModel + filters: ValueFilter { + roleName: "is_installed_role" + value: true + } + } + + SortFilterProxyModel { + id: proxyProtocolsModel + sourceModel: UiLogic.protocolsModel + filters: ValueFilter { + roleName: "is_installed_role" + value: true + } + } + + + ListView { + id: tb_c + x: 10 + width: parent.width - 10 + height: tb_c.contentItem.height + currentIndex: -1 + spacing: 5 + clip: true + interactive: false + model: proxyContainersModel + + delegate: Item { + implicitWidth: tb_c.width - 10 + implicitHeight: c_item.height + Item { + id: c_item + width: parent.width + height: row_container.height + tb_p.height + anchors.left: parent.left + Rectangle { + anchors.top: parent.top + width: parent.width + height: 1 + color: "lightgray" + visible: index !== tb_c.currentIndex + } + Rectangle { + anchors.top: row_container.top + anchors.bottom: row_container.bottom + anchors.left: parent.left + anchors.right: parent.right + + color: "#63B4FB" + visible: index === tb_c.currentIndex + } + + RowLayout { + id: row_container + anchors.left: parent.left + anchors.right: parent.right + + Text { + id: lb_container_name + text: name_role + font.pixelSize: 17 + color: "#100A44" + topPadding: 16 + bottomPadding: 12 + leftPadding: 10 + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + Layout.fillWidth: true + + MouseArea { + enabled: col.visible + anchors.top: lb_container_name.top + anchors.bottom: lb_container_name.bottom + anchors.left: parent.left + anchors.right: parent.right + propagateComposedEvents: true + onClicked: { + if (tb_c.currentIndex === index) tb_c.currentIndex = -1 + else tb_c.currentIndex = index + + UiLogic.protocolsModel.setSelectedDockerContainer(proxyContainersModel.mapToSource(index)) + } + } + } + + ImageButtonType { + id: button_remove + visible: index === tb_c.currentIndex + Layout.alignment: Qt.AlignRight + checkable: true + icon.source: "qrc:/images/delete.png" + implicitWidth: 30 + implicitHeight: 30 + + checked: default_role + + MessageDialog { + id: dialogRemove + standardButtons: StandardButton.Yes | StandardButton.Cancel + title: "AmneziaVPN" + text: qsTr("Remove container") + " " + name_role + "?" + "\n" + qsTr("This action will erase all data of this container on the server.") + onAccepted: { + tb_c.currentIndex = -1 + ServerContainersLogic.onPushButtonRemoveClicked(proxyContainersModel.mapToSource(index)) + } + } + + onClicked: dialogRemove.open() + + VisibleBehavior on visible { } + } + + ImageButtonType { + id: button_share + visible: index === tb_c.currentIndex + Layout.alignment: Qt.AlignRight + icon.source: "qrc:/images/share.png" + implicitWidth: 30 + implicitHeight: 30 + onClicked: { + ServerContainersLogic.onPushButtonShareClicked(proxyContainersModel.mapToSource(index)) + } + + VisibleBehavior on visible { } + } + + ImageButtonType { + id: button_default + visible: service_type_role == ProtocolEnum.Vpn + + Layout.alignment: Qt.AlignRight + checkable: true + img.source: checked ? "qrc:/images/check.png" : "qrc:/images/uncheck.png" + implicitWidth: 30 + implicitHeight: 30 + + checked: default_role + onClicked: { + ServerContainersLogic.onPushButtonDefaultClicked(proxyContainersModel.mapToSource(index)) + } + } + } + + + ListView { + id: tb_p + currentIndex: -1 + x: 10 + anchors.top: row_container.bottom + + width: parent.width - 40 + height: index === tb_c.currentIndex ? tb_p.contentItem.height : 0 + implicitHeight: height + + spacing: 0 + clip: true + interactive: false + model: proxyProtocolsModel + + + Behavior on height { + NumberAnimation { + duration: 200 + } + } + + delegate: Item { + id: dp_item + + implicitWidth: tb_p.width - 10 + implicitHeight: p_item.height + Item { + id: p_item + width: parent.width + height: lb_protocol_name.height + anchors.left: parent.left + Rectangle { + anchors.top: parent.top + width: parent.width + height: 1 + color: "lightgray" + visible: index > 0 + } + + SettingButtonType { + id: lb_protocol_name + topPadding: 10 + bottomPadding: 10 + + anchors.left: parent.left + anchors.leftMargin: 10 + + width: parent.width + height: 45 + text: qsTr(name_role + " settings") + textItem.font.pixelSize: 16 + icon.source: "qrc:/images/settings.png" + onClicked: { + tb_p.currentIndex = index + ServerContainersLogic.onPushButtonProtoSettingsClicked( + proxyContainersModel.mapToSource(tb_c.currentIndex), + proxyProtocolsModel.mapToSource(tb_p.currentIndex)) + } + } + } + } + } + } + } + } + } + } + + + BlueButtonType { + id: pb_add_container + visible: container_selector.selectedIndex < 0 + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.topMargin: 10 + anchors.bottomMargin: 20 + + width: parent.width - 40 + height: 40 + text: qsTr("Install new protocols container") + font.pixelSize: 16 + onClicked: container_selector.visible ? container_selector.close() : container_selector.open() + + } +} From 14384131f41960b0fc9343470f2b5ee4166dc0b3 Mon Sep 17 00:00:00 2001 From: pokamest Date: Wed, 24 Aug 2022 07:38:13 -0700 Subject: [PATCH 17/52] Secure config WIP --- .../3rd/QSimpleCrypto/include/QBlockCipher.h | 1 + .../QSimpleCrypto/sources/QBlockCipher.cpp | 9 +++ client/platforms/ios/MobileUtils.cpp | 4 +- client/platforms/ios/MobileUtils.h | 5 +- client/platforms/ios/MobileUtils.mm | 17 ++--- client/secure_qsettings.cpp | 69 ++++++++++++++++--- client/secure_qsettings.h | 6 +- 7 files changed, 83 insertions(+), 28 deletions(-) diff --git a/client/3rd/QSimpleCrypto/include/QBlockCipher.h b/client/3rd/QSimpleCrypto/include/QBlockCipher.h index af57b650f..e7b83a885 100644 --- a/client/3rd/QSimpleCrypto/include/QBlockCipher.h +++ b/client/3rd/QSimpleCrypto/include/QBlockCipher.h @@ -40,6 +40,7 @@ namespace QSimpleCrypto /// \return Returns random bytes. /// QByteArray generateRandomBytes(const int& size); + QByteArray generateSecureRandomBytes(const int& size); /// /// \brief encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm. diff --git a/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp b/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp index c01b9a2f8..8b86ab98c 100644 --- a/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp +++ b/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp @@ -26,6 +26,15 @@ QByteArray QSimpleCrypto::QBlockCipher::generateRandomBytes(const int& size) return buffer; } +QByteArray QSimpleCrypto::QBlockCipher::generateSecureRandomBytes(const int &size) +{ + unsigned char arr[sizeof(size)]; + RAND_priv_bytes(arr, sizeof(size)); + + QByteArray buffer = QByteArray(reinterpret_cast(arr), size); + return buffer; +} + /// /// \brief QSimpleCrypto::QBlockCipher::encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm. /// \param data - Data that will be encrypted. diff --git a/client/platforms/ios/MobileUtils.cpp b/client/platforms/ios/MobileUtils.cpp index 771e78559..3e82bb8c8 100644 --- a/client/platforms/ios/MobileUtils.cpp +++ b/client/platforms/ios/MobileUtils.cpp @@ -2,5 +2,5 @@ void MobileUtils::shareText(const QStringList&) {} -void MobileUtils::writeToKeychain(const QString&, const QString&) {} -QString MobileUtils::readFromKeychain(const QString&) { return {}; } +void MobileUtils::writeToKeychain(const QString&, const QByteArray &) {} +QByteArray MobileUtils::readFromKeychain(const QString&) { return {}; } diff --git a/client/platforms/ios/MobileUtils.h b/client/platforms/ios/MobileUtils.h index 49fcdce0d..045ababb6 100644 --- a/client/platforms/ios/MobileUtils.h +++ b/client/platforms/ios/MobileUtils.h @@ -13,8 +13,9 @@ public: public slots: static void shareText(const QStringList& filesToSend); - static void writeToKeychain(const QString& tag, const QString& value); - static QString readFromKeychain(const QString& tag); + static void writeToKeychain(const QString& tag, const QByteArray& value); + static bool deleteFromKeychain(const QString& tag); + static QByteArray readFromKeychain(const QString& tag); }; #endif // MOBILEUTILS_H diff --git a/client/platforms/ios/MobileUtils.mm b/client/platforms/ios/MobileUtils.mm index 4a2e43e6b..bfe82a6a0 100644 --- a/client/platforms/ios/MobileUtils.mm +++ b/client/platforms/ios/MobileUtils.mm @@ -35,7 +35,7 @@ void MobileUtils::shareText(const QStringList& filesToSend) { } } -bool deleteFromKeychain(const QString& tag) { +bool MobileUtils::deleteFromKeychain(const QString& tag) { NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *deleteQuery = @{ (id)kSecAttrAccount: nsTag, @@ -46,17 +46,14 @@ bool deleteFromKeychain(const QString& tag) { if (status != errSecSuccess) { qDebug() << "Error deleteFromKeychain" << status; return false; - } else { - qDebug() << "OK deleteFromKeychain"; - return true; } } -void MobileUtils::writeToKeychain(const QString& tag, const QString& value) { +void MobileUtils::writeToKeychain(const QString& tag, const QByteArray& value) { deleteFromKeychain(tag); NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - NSData* nsValue = [value.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; + NSData* nsValue = value.toNSData(); NSDictionary* addQuery = @{ (id)kSecAttrAccount: nsTag, (id)kSecClass: (id)kSecClassGenericPassword, @@ -66,12 +63,10 @@ void MobileUtils::writeToKeychain(const QString& tag, const QString& value) { OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL); if (status != errSecSuccess) { qDebug() << "Error writeToKeychain" << status; - } else { - qDebug() << "OK writeToKeychain"; } } -QString MobileUtils::readFromKeychain(const QString& tag) { +QByteArray MobileUtils::readFromKeychain(const QString& tag) { NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; NSData* nsValue = NULL; @@ -85,11 +80,9 @@ QString MobileUtils::readFromKeychain(const QString& tag) { (CFTypeRef *)&nsValue); if (status != errSecSuccess) { qDebug() << "Error readFromKeychain" << status; - } else { - qDebug() << "OK readFromKeychain" << nsValue; } - QString result; + QByteArray result; if (nsValue) { result = QByteArray::fromNSData(nsValue); CFRelease(nsValue); diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index 46d490adc..d77224307 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -14,11 +14,6 @@ SecureQSettings::SecureQSettings(const QString &organization, const QString &app encryptedKeys({"Servers/serversList"}) { qDebug() << "SecureQSettings::SecureQSettings CTOR"; - // load keys from system key storage -#ifdef Q_OS_IOS - m_key = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsKeyTag).toUtf8()); - m_iv = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsIvTag).toUtf8()); -#endif bool encrypted = m_settings.value("Conf/encrypted").toBool(); @@ -51,7 +46,7 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue if (retVal.userType() == QVariant::ByteArray && retVal.toByteArray().mid(0, magicString.size()) == magicString) { - if (m_key.isEmpty() || m_iv.isEmpty()) { + if (getEncKey().isEmpty() || getEncIv().isEmpty()) { qCritical() << "SecureQSettings::setValue Decryption requested, but key is empty"; return {}; } @@ -65,6 +60,7 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue if (!retVal.isValid()) { qWarning() << "SecureQSettings::value settings decryption failed"; + retVal = QVariant(); } } } @@ -81,7 +77,7 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue void SecureQSettings::setValue(const QString &key, const QVariant &value) { if (encryptionRequired() && encryptedKeys.contains(key)) { - if (!m_key.isEmpty() && !m_iv.isEmpty()) { + if (!getEncKey().isEmpty() && !getEncIv().isEmpty()) { QByteArray decryptedValue; { QDataStream ds(&decryptedValue, QIODevice::WriteOnly); @@ -155,22 +151,75 @@ void SecureQSettings::restoreAppConfig(const QByteArray &base64Cfg) QByteArray SecureQSettings::encryptText(const QByteArray& value) const { QSimpleCrypto::QBlockCipher cipher; - return cipher.encryptAesBlockCipher(value, m_key, m_iv); + return cipher.encryptAesBlockCipher(value, getEncKey(), getEncIv()); } QByteArray SecureQSettings::decryptText(const QByteArray& ba) const { QSimpleCrypto::QBlockCipher cipher; - return cipher.decryptAesBlockCipher(ba, m_key, m_iv); + return cipher.decryptAesBlockCipher(ba, getEncKey(), getEncIv()); } bool SecureQSettings::encryptionRequired() const { -#if defined Q_OS_ANDROID || defined Q_OS_IOS +#if defined Q_OS_IOS // || defined Q_OS_ANDROID return true; #endif return false; } +QByteArray SecureQSettings::getEncKey() const +{ + // load keys from system key storage + m_key = MobileUtils::readFromKeychain(settingsKeyTag); + + if (m_key.isEmpty()) { + // Create new key + QSimpleCrypto::QBlockCipher cipher; + QByteArray key = cipher.generateSecureRandomBytes(32); + if (key.isEmpty()) { + qCritical() << "SecureQSettings::getEncKey Unable to generate new enc key"; + } + + MobileUtils::writeToKeychain(settingsKeyTag, key); + + // check + m_key = MobileUtils::readFromKeychain(settingsKeyTag); + if (key != m_key) { + qCritical() << "SecureQSettings::getEncKey Unable to store key in keychain" << key.size() << m_key.size(); + return {}; + } + } + //qDebug() << "SecureQSettings::getEncKey() key" << m_key.size(); + + return m_key; +} + +QByteArray SecureQSettings::getEncIv() const +{ + // load keys from system key storage + m_iv = MobileUtils::readFromKeychain(settingsIvTag); + + if (m_iv.isEmpty()) { + // Create new IV + QSimpleCrypto::QBlockCipher cipher; + QByteArray iv = cipher.generateSecureRandomBytes(32); + if (iv.isEmpty()) { + qCritical() << "SecureQSettings::getEncIv Unable to generate new enc IV"; + } + MobileUtils::writeToKeychain(settingsIvTag, iv); + + // check + m_iv = MobileUtils::readFromKeychain(settingsIvTag); + if (iv != m_iv) { + qCritical() << "SecureQSettings::getEncIv Unable to store IV in keychain" << iv.size() << m_iv.size(); + return {}; + } + } + //qDebug() << "SecureQSettings::getEncIv() iv" << m_iv.size(); + + return m_iv; +} + diff --git a/client/secure_qsettings.h b/client/secure_qsettings.h index ae2a19b72..b36de1eb1 100644 --- a/client/secure_qsettings.h +++ b/client/secure_qsettings.h @@ -26,6 +26,8 @@ public: bool encryptionRequired() const; + QByteArray getEncKey() const; + QByteArray getEncIv() const; private: QSettings m_settings; @@ -33,8 +35,8 @@ private: QStringList encryptedKeys; // encode only key listed here - QByteArray m_key; - QByteArray m_iv; + mutable QByteArray m_key; + mutable QByteArray m_iv; const QByteArray magicString { "EncData" }; // Magic keyword used for mark encrypted QByteArray From 415d18338eab1c62d070b2cc0dae807ce068eee0 Mon Sep 17 00:00:00 2001 From: pokamest Date: Wed, 24 Aug 2022 18:51:35 +0300 Subject: [PATCH 18/52] Secure config WIP --- client/platforms/ios/MobileUtils.cpp | 1 + client/secure_qsettings.cpp | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/client/platforms/ios/MobileUtils.cpp b/client/platforms/ios/MobileUtils.cpp index 3e82bb8c8..4667cc25a 100644 --- a/client/platforms/ios/MobileUtils.cpp +++ b/client/platforms/ios/MobileUtils.cpp @@ -3,4 +3,5 @@ void MobileUtils::shareText(const QStringList&) {} void MobileUtils::writeToKeychain(const QString&, const QByteArray &) {} +bool MobileUtils::deleteFromKeychain(const QString& tag) { return false; } QByteArray MobileUtils::readFromKeychain(const QString&) { return {}; } diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index d77224307..488feb490 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -191,7 +191,6 @@ QByteArray SecureQSettings::getEncKey() const return {}; } } - //qDebug() << "SecureQSettings::getEncKey() key" << m_key.size(); return m_key; } @@ -217,7 +216,6 @@ QByteArray SecureQSettings::getEncIv() const return {}; } } - //qDebug() << "SecureQSettings::getEncIv() iv" << m_iv.size(); return m_iv; } From 510a564797d6f3b268dea20b8b14323f6d71466c Mon Sep 17 00:00:00 2001 From: pokamest Date: Thu, 25 Aug 2022 12:47:02 +0300 Subject: [PATCH 19/52] App refactoring --- client/amnezia_application.cpp | 212 +++++++++++++++++ client/amnezia_application.h | 52 +++++ client/client.pro | 106 ++++----- client/main.cpp | 214 ++---------------- client/settings.h | 2 + client/ui/models/containers_model.cpp | 7 +- client/ui/models/containers_model.h | 4 +- client/ui/models/protocols_model.cpp | 3 +- client/ui/models/protocols_model.h | 4 +- client/ui/models/sites_model.cpp | 5 +- client/ui/models/sites_model.h | 4 +- client/ui/pages_logic/AppSettingsLogic.cpp | 16 +- .../ui/pages_logic/GeneralSettingsLogic.cpp | 14 +- .../ui/pages_logic/NetworkSettingsLogic.cpp | 16 +- client/ui/pages_logic/PageLogicBase.cpp | 4 +- client/ui/pages_logic/PageLogicBase.h | 2 +- .../ui/pages_logic/ServerContainersLogic.cpp | 28 +-- client/ui/pages_logic/ServerListLogic.cpp | 6 +- client/ui/pages_logic/ServerSettingsLogic.cpp | 46 ++-- .../ui/pages_logic/ShareConnectionLogic.cpp | 34 +-- client/ui/pages_logic/SitesLogic.cpp | 24 +- client/ui/pages_logic/StartPageLogic.cpp | 8 +- client/ui/pages_logic/VpnLogic.cpp | 28 +-- client/ui/pages_logic/WizardLogic.cpp | 4 +- .../ui/pages_logic/protocols/CloakLogic.cpp | 10 +- client/ui/pages_logic/protocols/CloakLogic.h | 1 - .../ui/pages_logic/protocols/OpenVpnLogic.cpp | 10 +- .../ui/pages_logic/protocols/OpenVpnLogic.h | 1 - .../protocols/OtherProtocolsLogic.cpp | 2 +- .../protocols/OtherProtocolsLogic.h | 1 - .../protocols/ShadowSocksLogic.cpp | 10 +- .../pages_logic/protocols/ShadowSocksLogic.h | 1 - client/ui/uilogic.cpp | 45 ++-- client/ui/uilogic.h | 6 +- client/vpnconnection.cpp | 35 ++- client/vpnconnection.h | 4 +- 36 files changed, 526 insertions(+), 443 deletions(-) create mode 100644 client/amnezia_application.cpp create mode 100644 client/amnezia_application.h diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp new file mode 100644 index 000000000..85762a078 --- /dev/null +++ b/client/amnezia_application.cpp @@ -0,0 +1,212 @@ +#include "amnezia_application.h" + +#include +#include +#include + + +#include "QZXing.h" + +#include "debug.h" +#include "defines.h" + + +#include "platforms/ios/QRCodeReaderBase.h" +//#include "platforms/ios/MobileUtils.h" + +#include "ui/pages.h" + +#include "ui/pages_logic/AppSettingsLogic.h" +#include "ui/pages_logic/GeneralSettingsLogic.h" +#include "ui/pages_logic/NetworkSettingsLogic.h" +#include "ui/pages_logic/NewServerProtocolsLogic.h" +#include "ui/pages_logic/QrDecoderLogic.h" +#include "ui/pages_logic/ServerConfiguringProgressLogic.h" +#include "ui/pages_logic/ServerContainersLogic.h" +#include "ui/pages_logic/ServerListLogic.h" +#include "ui/pages_logic/ServerSettingsLogic.h" +#include "ui/pages_logic/ServerContainersLogic.h" +#include "ui/pages_logic/ShareConnectionLogic.h" +#include "ui/pages_logic/SitesLogic.h" +#include "ui/pages_logic/StartPageLogic.h" +#include "ui/pages_logic/VpnLogic.h" +#include "ui/pages_logic/WizardLogic.h" + +#include "ui/pages_logic/protocols/CloakLogic.h" +#include "ui/pages_logic/protocols/OpenVpnLogic.h" +#include "ui/pages_logic/protocols/ShadowSocksLogic.h" + + +AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecondary, + SingleApplication::Options options, int timeout, const QString &userData): + #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + QAPPLICATION_CLASS(argc, argv); + #else + SingleApplication(argc, argv, allowSecondary, options, timeout, userData) + #endif + + +{ + setQuitOnLastWindowClosed(false); + m_settings = std::shared_ptr(new Settings); + +// QObject::connect(&app, &QCoreApplication::aboutToQuit, uiLogic, [&engine, uiLogic](){ +// QObject::disconnect(engine, 0,0,0); +// delete engine; + +// QObject::disconnect(uiLogic, 0,0,0); +// delete uiLogic; + // }); +} + +AmneziaApplication::~AmneziaApplication() +{ + QObject::disconnect(m_engine, 0,0,0); + delete m_engine; + + QObject::disconnect(m_uiLogic, 0,0,0); + delete m_uiLogic; +} + +void AmneziaApplication::init() +{ + m_engine = new QQmlApplicationEngine; + m_uiLogic = new UiLogic(m_settings); + + const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml")); + QObject::connect(m_engine, &QQmlApplicationEngine::objectCreated, + this, [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) + QCoreApplication::exit(-1); + }, Qt::QueuedConnection); + + m_engine->rootContext()->setContextProperty("Debug", &Debug::Instance()); + + m_engine->rootContext()->setContextProperty("UiLogic", m_uiLogic); + + m_engine->rootContext()->setContextProperty("AppSettingsLogic", m_uiLogic->appSettingsLogic()); + m_engine->rootContext()->setContextProperty("GeneralSettingsLogic", m_uiLogic->generalSettingsLogic()); + m_engine->rootContext()->setContextProperty("NetworkSettingsLogic", m_uiLogic->networkSettingsLogic()); + m_engine->rootContext()->setContextProperty("NewServerProtocolsLogic", m_uiLogic->newServerProtocolsLogic()); + m_engine->rootContext()->setContextProperty("QrDecoderLogic", m_uiLogic->qrDecoderLogic()); + m_engine->rootContext()->setContextProperty("ServerConfiguringProgressLogic", m_uiLogic->serverConfiguringProgressLogic()); + m_engine->rootContext()->setContextProperty("ServerListLogic", m_uiLogic->serverListLogic()); + m_engine->rootContext()->setContextProperty("ServerSettingsLogic", m_uiLogic->serverSettingsLogic()); + m_engine->rootContext()->setContextProperty("ServerContainersLogic", m_uiLogic->serverprotocolsLogic()); + m_engine->rootContext()->setContextProperty("ShareConnectionLogic", m_uiLogic->shareConnectionLogic()); + m_engine->rootContext()->setContextProperty("SitesLogic", m_uiLogic->sitesLogic()); + m_engine->rootContext()->setContextProperty("StartPageLogic", m_uiLogic->startPageLogic()); + m_engine->rootContext()->setContextProperty("VpnLogic", m_uiLogic->vpnLogic()); + m_engine->rootContext()->setContextProperty("WizardLogic", m_uiLogic->wizardLogic()); + +#if defined(Q_OS_IOS) + setStartPageLogic(uiLogic->startPageLogic()); +#endif + + m_engine->load(url); + + if (m_engine->rootObjects().size() > 0) { + m_uiLogic->setQmlRoot(m_engine->rootObjects().at(0)); + } + + if (m_settings->isSaveLogs()) { + if (!Debug::init()) { + qWarning() << "Initialization of debug subsystem failed"; + } + } + +#ifdef Q_OS_WIN + if (m_parser.isSet("a")) m_uiLogic->showOnStartup(); + else emit m_uiLogic->show(); +#else + uiLogic->showOnStartup(); +#endif + + // TODO - fix +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) + if (isPrimary()) { + QObject::connect(this, &SingleApplication::instanceStarted, m_uiLogic, [this](){ + qDebug() << "Secondary instance started, showing this window instead"; + emit m_uiLogic->show(); + emit m_uiLogic->raise(); + }); + } +#endif +} + +void AmneziaApplication::registerTypes() +{ + QZXing::registerQMLTypes(); + + qRegisterMetaType("VpnProtocol::VpnConnectionState"); + qRegisterMetaType("ServerCredentials"); + + qRegisterMetaType("DockerContainer"); + qRegisterMetaType("TransportProto"); + qRegisterMetaType("Proto"); + qRegisterMetaType("ServiceType"); + qRegisterMetaType("Page"); + qRegisterMetaType("ConnectionState"); + + qRegisterMetaType("PageProtocolLogicBase *"); + + + + declareQmlPageEnum(); + declareQmlProtocolEnum(); + declareQmlContainerEnum(); + + qmlRegisterType("PageType", 1, 0, "PageType"); + qmlRegisterType("QRCodeReader", 1, 0, "QRCodeReader"); + + QScopedPointer containerProps(new ContainerProps); + qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", containerProps.get()); + + QScopedPointer protocolProps(new ProtocolProps); + qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", protocolProps.get()); +} + +void AmneziaApplication::loadFonts() +{ + QFontDatabase::addApplicationFont(":/fonts/Lato-Black.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-BlackItalic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Bold.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-BoldItalic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Italic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Light.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-LightItalic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Regular.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Thin.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-ThinItalic.ttf"); +} + +void AmneziaApplication::loadTranslator() +{ + m_translator = new QTranslator; + if (m_translator->load(QLocale(), QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/translations"))) { + installTranslator(m_translator); + } +} + +void AmneziaApplication::parseCommands() +{ + m_parser.setApplicationDescription(APPLICATION_NAME); + m_parser.addHelpOption(); + m_parser.addVersionOption(); + + QCommandLineOption c_autostart {{"a", "autostart"}, "System autostart"}; + m_parser.addOption(c_autostart); + + QCommandLineOption c_cleanup {{"c", "cleanup"}, "Cleanup logs"}; + m_parser.addOption(c_cleanup); + + m_parser.process(*this); + + if (m_parser.isSet(c_cleanup)) { + Debug::cleanUp(); + QTimer::singleShot(100,[this]{ + quit(); + }); + exec(); + } +} diff --git a/client/amnezia_application.h b/client/amnezia_application.h new file mode 100644 index 000000000..d7a768338 --- /dev/null +++ b/client/amnezia_application.h @@ -0,0 +1,52 @@ +#ifndef AMNEZIA_APPLICATION_H +#define AMNEZIA_APPLICATION_H + +#include +#include + +#include +#include +#include + +#include "settings.h" + +#include "ui/uilogic.h" + +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) + #define AMNEZIA_BASE_CLASS SingleApplication + #define QAPPLICATION_CLASS QGuiApplication + #include "singleapplication.h" + //#undef QAPPLICATION_CLASS +#else + #define AMNEZIA_BASE_CLASS QApplication +#endif + +class AmneziaApplication : public AMNEZIA_BASE_CLASS +{ + Q_OBJECT +public: +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + AmneziaApplication(int &argc, char *argv[]); +#else + AmneziaApplication(int &argc, char *argv[], bool allowSecondary = false, + SingleApplication::Options options = SingleApplication::User, int timeout = 1000, const QString &userData = {} ); +#endif + virtual ~AmneziaApplication(); + + void init(); + void registerTypes(); + void loadFonts(); + void loadTranslator(); + void parseCommands(); + +private: + QQmlApplicationEngine *m_engine; + UiLogic *m_uiLogic; + std::shared_ptr m_settings; + + QTranslator* m_translator; + QCommandLineParser m_parser; + +}; + +#endif // AMNEZIA_APPLICATION_H diff --git a/client/client.pro b/client/client.pro index 023f0e184..5d9ab1ea7 100644 --- a/client/client.pro +++ b/client/client.pro @@ -24,25 +24,26 @@ DEPENDPATH += $$PWD/3rd/OpenSSL/include HEADERS += \ ../ipc/ipc.h \ - configurators/cloak_configurator.h \ - configurators/ikev2_configurator.h \ - configurators/shadowsocks_configurator.h \ - configurators/ssh_configurator.h \ - configurators/vpn_configurator.h \ - configurators/wireguard_configurator.h \ + amnezia_application.h \ + configurators/cloak_configurator.h \ + configurators/ikev2_configurator.h \ + configurators/shadowsocks_configurator.h \ + configurators/ssh_configurator.h \ + configurators/vpn_configurator.h \ + configurators/wireguard_configurator.h \ containers/containers_defs.h \ core/defs.h \ core/errorstrings.h \ configurators/openvpn_configurator.h \ - core/scripts_registry.h \ - core/server_defs.h \ + core/scripts_registry.h \ + core/server_defs.h \ core/servercontroller.h \ debug.h \ defines.h \ managementserver.h \ platforms/ios/MobileUtils.h \ platforms/linux/leakdetector.h \ - protocols/protocols_defs.h \ + protocols/protocols_defs.h \ secure_qsettings.h \ settings.h \ ui/notificationhandler.h \ @@ -52,10 +53,10 @@ HEADERS += \ ui/pages_logic/AppSettingsLogic.h \ ui/pages_logic/GeneralSettingsLogic.h \ ui/pages_logic/NetworkSettingsLogic.h \ - ui/pages_logic/NewServerProtocolsLogic.h \ + ui/pages_logic/NewServerProtocolsLogic.h \ ui/pages_logic/PageLogicBase.h \ - ui/pages_logic/QrDecoderLogic.h \ - ui/pages_logic/ServerConfiguringProgressLogic.h \ + ui/pages_logic/QrDecoderLogic.h \ + ui/pages_logic/ServerConfiguringProgressLogic.h \ ui/pages_logic/ServerContainersLogic.h \ ui/pages_logic/ServerListLogic.h \ ui/pages_logic/ServerSettingsLogic.h \ @@ -64,16 +65,16 @@ HEADERS += \ ui/pages_logic/StartPageLogic.h \ ui/pages_logic/VpnLogic.h \ ui/pages_logic/WizardLogic.h \ - ui/pages_logic/protocols/CloakLogic.h \ - ui/pages_logic/protocols/OpenVpnLogic.h \ - ui/pages_logic/protocols/OtherProtocolsLogic.h \ - ui/pages_logic/protocols/PageProtocolLogicBase.h \ - ui/pages_logic/protocols/ShadowSocksLogic.h \ + ui/pages_logic/protocols/CloakLogic.h \ + ui/pages_logic/protocols/OpenVpnLogic.h \ + ui/pages_logic/protocols/OtherProtocolsLogic.h \ + ui/pages_logic/protocols/PageProtocolLogicBase.h \ + ui/pages_logic/protocols/ShadowSocksLogic.h \ ui/property_helper.h \ ui/models/servers_model.h \ ui/uilogic.h \ - ui/qautostart.h \ - ui/models/sites_model.h \ + ui/qautostart.h \ + ui/models/sites_model.h \ utils.h \ vpnconnection.h \ protocols/vpnprotocol.h \ @@ -84,24 +85,25 @@ HEADERS += \ platforms/ios/QRCodeReaderBase.h SOURCES += \ - configurators/cloak_configurator.cpp \ - configurators/ikev2_configurator.cpp \ - configurators/shadowsocks_configurator.cpp \ - configurators/ssh_configurator.cpp \ - configurators/vpn_configurator.cpp \ - configurators/wireguard_configurator.cpp \ + amnezia_application.cpp \ + configurators/cloak_configurator.cpp \ + configurators/ikev2_configurator.cpp \ + configurators/shadowsocks_configurator.cpp \ + configurators/ssh_configurator.cpp \ + configurators/vpn_configurator.cpp \ + configurators/wireguard_configurator.cpp \ containers/containers_defs.cpp \ - core/errorstrings.cpp \ + core/errorstrings.cpp \ configurators/openvpn_configurator.cpp \ - core/scripts_registry.cpp \ - core/server_defs.cpp \ + core/scripts_registry.cpp \ + core/server_defs.cpp \ core/servercontroller.cpp \ debug.cpp \ main.cpp \ managementserver.cpp \ platforms/ios/MobileUtils.cpp \ platforms/linux/leakdetector.cpp \ - protocols/protocols_defs.cpp \ + protocols/protocols_defs.cpp \ secure_qsettings.cpp \ settings.cpp \ ui/notificationhandler.cpp \ @@ -110,10 +112,10 @@ SOURCES += \ ui/pages_logic/AppSettingsLogic.cpp \ ui/pages_logic/GeneralSettingsLogic.cpp \ ui/pages_logic/NetworkSettingsLogic.cpp \ - ui/pages_logic/NewServerProtocolsLogic.cpp \ + ui/pages_logic/NewServerProtocolsLogic.cpp \ ui/pages_logic/PageLogicBase.cpp \ - ui/pages_logic/QrDecoderLogic.cpp \ - ui/pages_logic/ServerConfiguringProgressLogic.cpp \ + ui/pages_logic/QrDecoderLogic.cpp \ + ui/pages_logic/ServerConfiguringProgressLogic.cpp \ ui/pages_logic/ServerContainersLogic.cpp \ ui/pages_logic/ServerListLogic.cpp \ ui/pages_logic/ServerSettingsLogic.cpp \ @@ -122,15 +124,15 @@ SOURCES += \ ui/pages_logic/StartPageLogic.cpp \ ui/pages_logic/VpnLogic.cpp \ ui/pages_logic/WizardLogic.cpp \ - ui/pages_logic/protocols/CloakLogic.cpp \ - ui/pages_logic/protocols/OpenVpnLogic.cpp \ - ui/pages_logic/protocols/OtherProtocolsLogic.cpp \ - ui/pages_logic/protocols/PageProtocolLogicBase.cpp \ - ui/pages_logic/protocols/ShadowSocksLogic.cpp \ + ui/pages_logic/protocols/CloakLogic.cpp \ + ui/pages_logic/protocols/OpenVpnLogic.cpp \ + ui/pages_logic/protocols/OtherProtocolsLogic.cpp \ + ui/pages_logic/protocols/PageProtocolLogicBase.cpp \ + ui/pages_logic/protocols/ShadowSocksLogic.cpp \ ui/models/servers_model.cpp \ ui/uilogic.cpp \ - ui/qautostart.cpp \ - ui/models/sites_model.cpp \ + ui/qautostart.cpp \ + ui/models/sites_model.cpp \ utils.cpp \ vpnconnection.cpp \ protocols/vpnprotocol.cpp \ @@ -249,20 +251,20 @@ android { DISTFILES += \ - android/AndroidManifest.xml \ - android/build.gradle \ - android/gradle/wrapper/gradle-wrapper.jar \ - android/gradle/wrapper/gradle-wrapper.properties \ - android/gradlew \ - android/gradlew.bat \ - android/gradle.properties \ - android/res/values/libs.xml \ - android/src/org/amnezia/vpn/OpenVPNThreadv3.kt \ - android/src/org/amnezia/vpn/VpnService.kt \ - android/src/org/amnezia/vpn/VpnServiceBinder.kt \ - android/src/org/amnezia/vpn/qt/VPNPermissionHelper.kt + android/AndroidManifest.xml \ + android/build.gradle \ + android/gradle/wrapper/gradle-wrapper.jar \ + android/gradle/wrapper/gradle-wrapper.properties \ + android/gradlew \ + android/gradlew.bat \ + android/gradle.properties \ + android/res/values/libs.xml \ + android/src/org/amnezia/vpn/OpenVPNThreadv3.kt \ + android/src/org/amnezia/vpn/VpnService.kt \ + android/src/org/amnezia/vpn/VpnServiceBinder.kt \ + android/src/org/amnezia/vpn/qt/VPNPermissionHelper.kt - ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android + ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android for (abi, ANDROID_ABIS): { equals(ANDROID_TARGET_ARCH,$$abi) { diff --git a/client/main.cpp b/client/main.cpp index 196d5cec9..904569417 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -1,54 +1,10 @@ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include "ui/uilogic.h" #include +#include -#include "ui/pages.h" - -#include "ui/pages_logic/AppSettingsLogic.h" -#include "ui/pages_logic/GeneralSettingsLogic.h" -#include "ui/pages_logic/NetworkSettingsLogic.h" -#include "ui/pages_logic/NewServerProtocolsLogic.h" -#include "ui/pages_logic/QrDecoderLogic.h" -#include "ui/pages_logic/ServerConfiguringProgressLogic.h" -#include "ui/pages_logic/ServerContainersLogic.h" -#include "ui/pages_logic/ServerListLogic.h" -#include "ui/pages_logic/ServerSettingsLogic.h" -#include "ui/pages_logic/ServerContainersLogic.h" -#include "ui/pages_logic/ShareConnectionLogic.h" -#include "ui/pages_logic/SitesLogic.h" -#include "ui/pages_logic/StartPageLogic.h" -#include "ui/pages_logic/VpnLogic.h" -#include "ui/pages_logic/WizardLogic.h" - -#include "ui/pages_logic/protocols/CloakLogic.h" -#include "ui/pages_logic/protocols/OpenVpnLogic.h" -#include "ui/pages_logic/protocols/ShadowSocksLogic.h" - -#include "ui/uilogic.h" - -#include "QZXing.h" - -#include "platforms/ios/QRCodeReaderBase.h" -#include "platforms/ios/MobileUtils.h" - -#include "debug.h" +#include "amnezia_application.h" #include "defines.h" -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) -#define QAPPLICATION_CLASS QGuiApplication -#include "singleapplication.h" -#undef QAPPLICATION_CLASS -#endif - #ifdef Q_OS_WIN #include "Windows.h" @@ -62,26 +18,21 @@ #include "QtAppDelegate-C-Interface.h" #endif -static void loadTranslator() -{ - QTranslator* translator = new QTranslator; - if (translator->load(QLocale(), QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/translations"))) { - qApp->installTranslator(translator); - } -} int main(int argc, char *argv[]) { QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false")); - QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); #ifdef Q_OS_WIN AllowSetForegroundWindow(ASFW_ANY); #endif -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - SingleApplication app(argc, argv, true, SingleApplication::Mode::User | SingleApplication::Mode::SecondaryNotification); + +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + AmneziaApplication app(argc, argv); +#else + AmneziaApplication app(argc, argv, true, SingleApplication::Mode::User | SingleApplication::Mode::SecondaryNotification); if (!app.isPrimary()) { QTimer::singleShot(1000, &app, [&](){ @@ -89,10 +40,9 @@ int main(int argc, char *argv[]) }); return app.exec(); } -#else - QApplication app(argc, argv); #endif +// Allow to raise app window if secondary instance launched #ifdef Q_OS_WIN AllowSetForegroundWindow(0); #endif @@ -105,155 +55,17 @@ int main(int argc, char *argv[]) QtAppDelegateInitialize(); #endif - loadTranslator(); - - QFontDatabase::addApplicationFont(":/fonts/Lato-Black.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Lato-BlackItalic.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Lato-Bold.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Lato-BoldItalic.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Lato-Italic.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Lato-Light.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Lato-LightItalic.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Lato-Regular.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Lato-Thin.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Lato-ThinItalic.ttf"); + app.registerTypes(); app.setApplicationName(APPLICATION_NAME); app.setOrganizationName(ORGANIZATION_NAME); app.setApplicationDisplayName(APPLICATION_NAME); - QCommandLineParser parser; - parser.setApplicationDescription(APPLICATION_NAME); - parser.addHelpOption(); - parser.addVersionOption(); + app.loadTranslator(); + app.loadFonts(); - QCommandLineOption c_autostart {{"a", "autostart"}, "System autostart"}; - parser.addOption(c_autostart); - - QCommandLineOption c_cleanup {{"c", "cleanup"}, "Cleanup logs"}; - parser.addOption(c_cleanup); - - parser.process(app); - - if (parser.isSet(c_cleanup)) { - Debug::cleanUp(); - QTimer::singleShot(100,[&app]{ - app.quit(); - }); - app.exec(); - return 0; - } - - { - Settings settingsTemp; - } - - - -// MobileUtils::writeToKeychain("testKey", "12345"); -// qDebug() << "MobileUtils::readFromKeychain(\"testKey\"):" << MobileUtils::readFromKeychain("testKey"); - - Settings settings; - if (settings.isSaveLogs()) { - if (!Debug::init()) { - qWarning() << "Initialization of debug subsystem failed"; - } - } - - app.setQuitOnLastWindowClosed(false); - - QZXing::registerQMLTypes(); - - qRegisterMetaType("VpnProtocol::VpnConnectionState"); - qRegisterMetaType("ServerCredentials"); - - qRegisterMetaType("DockerContainer"); - qRegisterMetaType("TransportProto"); - qRegisterMetaType("Proto"); - qRegisterMetaType("ServiceType"); - qRegisterMetaType("Page"); - qRegisterMetaType("ConnectionState"); - - qRegisterMetaType("PageProtocolLogicBase *"); - - UiLogic *uiLogic = new UiLogic; - - QQmlApplicationEngine *engine = new QQmlApplicationEngine; - - declareQmlPageEnum(); - declareQmlProtocolEnum(); - declareQmlContainerEnum(); - - qmlRegisterType("PageType", 1, 0, "PageType"); - qmlRegisterType("QRCodeReader", 1, 0, "QRCodeReader"); - - QScopedPointer containerProps(new ContainerProps); - qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", containerProps.get()); - - QScopedPointer protocolProps(new ProtocolProps); - qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", protocolProps.get()); - - const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml")); - QObject::connect(engine, &QQmlApplicationEngine::objectCreated, - &app, [url](QObject *obj, const QUrl &objUrl) { - if (!obj && url == objUrl) - QCoreApplication::exit(-1); - }, Qt::QueuedConnection); - - engine->rootContext()->setContextProperty("Debug", &Debug::Instance()); - - engine->rootContext()->setContextProperty("UiLogic", uiLogic); - - engine->rootContext()->setContextProperty("AppSettingsLogic", uiLogic->appSettingsLogic()); - engine->rootContext()->setContextProperty("GeneralSettingsLogic", uiLogic->generalSettingsLogic()); - engine->rootContext()->setContextProperty("NetworkSettingsLogic", uiLogic->networkSettingsLogic()); - engine->rootContext()->setContextProperty("NewServerProtocolsLogic", uiLogic->newServerProtocolsLogic()); - engine->rootContext()->setContextProperty("QrDecoderLogic", uiLogic->qrDecoderLogic()); - engine->rootContext()->setContextProperty("ServerConfiguringProgressLogic", uiLogic->serverConfiguringProgressLogic()); - engine->rootContext()->setContextProperty("ServerListLogic", uiLogic->serverListLogic()); - engine->rootContext()->setContextProperty("ServerSettingsLogic", uiLogic->serverSettingsLogic()); - engine->rootContext()->setContextProperty("ServerContainersLogic", uiLogic->serverprotocolsLogic()); - engine->rootContext()->setContextProperty("ShareConnectionLogic", uiLogic->shareConnectionLogic()); - engine->rootContext()->setContextProperty("SitesLogic", uiLogic->sitesLogic()); - engine->rootContext()->setContextProperty("StartPageLogic", uiLogic->startPageLogic()); - engine->rootContext()->setContextProperty("VpnLogic", uiLogic->vpnLogic()); - engine->rootContext()->setContextProperty("WizardLogic", uiLogic->wizardLogic()); - -#if defined(Q_OS_IOS) - setStartPageLogic(uiLogic->startPageLogic()); -#endif - - engine->load(url); - - QObject::connect(&app, &QCoreApplication::aboutToQuit, uiLogic, [&engine, uiLogic](){ - QObject::disconnect(engine, 0,0,0); - delete engine; - - QObject::disconnect(uiLogic, 0,0,0); - delete uiLogic; - }); - - if (engine->rootObjects().size() > 0) { - uiLogic->setQmlRoot(engine->rootObjects().at(0)); - } - -#ifdef Q_OS_WIN - if (parser.isSet("a")) uiLogic->showOnStartup(); - else emit uiLogic->show(); -#else - uiLogic->showOnStartup(); -#endif - - // TODO - fix -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - if (app.isPrimary()) { - QObject::connect(&app, &SingleApplication::instanceStarted, uiLogic, [&](){ - qDebug() << "Secondary instance started, showing this window instead"; - emit uiLogic->show(); - emit uiLogic->raise(); - }); - } -#endif + app.parseCommands(); + app.init(); return app.exec(); } diff --git a/client/settings.h b/client/settings.h index 18337f0d7..fc5753297 100644 --- a/client/settings.h +++ b/client/settings.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "core/defs.h" #include "containers/containers_defs.h" @@ -116,6 +117,7 @@ public: private: SecureQSettings m_settings; + QMutex m_mutex; }; #endif // SETTINGS_H diff --git a/client/ui/models/containers_model.cpp b/client/ui/models/containers_model.cpp index 15fc8f8d9..5468452ee 100644 --- a/client/ui/models/containers_model.cpp +++ b/client/ui/models/containers_model.cpp @@ -1,6 +1,7 @@ #include "containers_model.h" -ContainersModel::ContainersModel(QObject *parent) : +ContainersModel::ContainersModel(std::shared_ptr settings, QObject *parent) : + m_settings(settings), QAbstractListModel(parent) { @@ -37,13 +38,13 @@ QVariant ContainersModel::data(const QModelIndex &index, int role) const return ContainerProps::containerDescriptions().value(c); } if (role == DefaultRole) { - return c == m_settings.defaultContainer(m_selectedServerIndex); + return c == m_settings->defaultContainer(m_selectedServerIndex); } if (role == ServiceTypeRole) { return ContainerProps::containerService(c); } if (role == IsInstalledRole) { - return m_settings.containers(m_selectedServerIndex).contains(c); + return m_settings->containers(m_selectedServerIndex).contains(c); } return QVariant(); } diff --git a/client/ui/models/containers_model.h b/client/ui/models/containers_model.h index 479690b0a..362068557 100644 --- a/client/ui/models/containers_model.h +++ b/client/ui/models/containers_model.h @@ -13,7 +13,7 @@ class ContainersModel : public QAbstractListModel { Q_OBJECT public: - ContainersModel(QObject *parent = nullptr); + ContainersModel(std::shared_ptr settings, QObject *parent = nullptr); public: enum SiteRoles { NameRole = Qt::UserRole + 1, @@ -33,7 +33,7 @@ protected: private: int m_selectedServerIndex; - Settings m_settings; + std::shared_ptr m_settings; }; #endif // CONTAINERS_MODEL_H diff --git a/client/ui/models/protocols_model.cpp b/client/ui/models/protocols_model.cpp index 76e5c6234..7359bb364 100644 --- a/client/ui/models/protocols_model.cpp +++ b/client/ui/models/protocols_model.cpp @@ -1,6 +1,7 @@ #include "protocols_model.h" -ProtocolsModel::ProtocolsModel(QObject *parent) : +ProtocolsModel::ProtocolsModel(std::shared_ptr settings, QObject *parent) : + m_settings(settings), QAbstractListModel(parent) { diff --git a/client/ui/models/protocols_model.h b/client/ui/models/protocols_model.h index bd2715587..48b6eeb64 100644 --- a/client/ui/models/protocols_model.h +++ b/client/ui/models/protocols_model.h @@ -13,7 +13,7 @@ class ProtocolsModel : public QAbstractListModel { Q_OBJECT public: - ProtocolsModel(QObject *parent = nullptr); + ProtocolsModel(std::shared_ptr settings, QObject *parent = nullptr); public: enum SiteRoles { NameRole = Qt::UserRole + 1, @@ -34,7 +34,7 @@ protected: private: int m_selectedServerIndex; DockerContainer m_selectedDockerContainer; - Settings m_settings; + std::shared_ptr m_settings; }; #endif // PROTOCOLS_MODEL_H diff --git a/client/ui/models/sites_model.cpp b/client/ui/models/sites_model.cpp index 9fc5452d4..fe0f4ccf3 100644 --- a/client/ui/models/sites_model.cpp +++ b/client/ui/models/sites_model.cpp @@ -1,7 +1,8 @@ #include "sites_model.h" -SitesModel::SitesModel(Settings::RouteMode mode, QObject *parent) +SitesModel::SitesModel(std::shared_ptr settings, Settings::RouteMode mode, QObject *parent) : QAbstractListModel(parent), + m_settings(settings), m_mode(mode) { } @@ -68,7 +69,7 @@ void SitesModel::genCache() const qDebug() << "SitesModel::genCache"; m_ipsCache.clear(); - const QVariantMap &sites = m_settings.vpnSites(m_mode); + const QVariantMap &sites = m_settings->vpnSites(m_mode); auto i = sites.constBegin(); while (i != sites.constEnd()) { m_ipsCache.append(qMakePair(i.key(), i.value().toString())); diff --git a/client/ui/models/sites_model.h b/client/ui/models/sites_model.h index 5e4feb0f5..7bf04b508 100644 --- a/client/ui/models/sites_model.h +++ b/client/ui/models/sites_model.h @@ -15,7 +15,7 @@ public: IpRole }; - explicit SitesModel(Settings::RouteMode mode, QObject *parent = nullptr); + explicit SitesModel(std::shared_ptr settings, Settings::RouteMode mode, QObject *parent = nullptr); void resetCache(); // Basic functionality: @@ -32,7 +32,7 @@ private: private: Settings::RouteMode m_mode; - Settings m_settings; + std::shared_ptr m_settings; mutable QVector> m_ipsCache; mutable bool m_cacheReady = false; diff --git a/client/ui/pages_logic/AppSettingsLogic.cpp b/client/ui/pages_logic/AppSettingsLogic.cpp index ccdb5071c..e9c614aad 100644 --- a/client/ui/pages_logic/AppSettingsLogic.cpp +++ b/client/ui/pages_logic/AppSettingsLogic.cpp @@ -25,9 +25,9 @@ AppSettingsLogic::AppSettingsLogic(UiLogic *logic, QObject *parent): void AppSettingsLogic::onUpdatePage() { set_checkBoxAutostartChecked(Autostart::isAutostart()); - set_checkBoxAutoConnectChecked(m_settings.isAutoConnect()); - set_checkBoxStartMinimizedChecked(m_settings.isStartMinimized()); - set_checkBoxSaveLogsChecked(m_settings.isSaveLogs()); + set_checkBoxAutoConnectChecked(m_settings->isAutoConnect()); + set_checkBoxStartMinimizedChecked(m_settings->isStartMinimized()); + set_checkBoxSaveLogsChecked(m_settings->isSaveLogs()); QString ver = QString("%1: %2 (%3)") .arg(tr("Software version")) @@ -46,17 +46,17 @@ void AppSettingsLogic::onCheckBoxAutostartToggled(bool checked) void AppSettingsLogic::onCheckBoxAutoconnectToggled(bool checked) { - m_settings.setAutoConnect(checked); + m_settings->setAutoConnect(checked); } void AppSettingsLogic::onCheckBoxStartMinimizedToggled(bool checked) { - m_settings.setStartMinimized(checked); + m_settings->setStartMinimized(checked); } void AppSettingsLogic::onCheckBoxSaveLogsCheckedToggled(bool checked) { - m_settings.setSaveLogs(checked); + m_settings->setSaveLogs(checked); } void AppSettingsLogic::onPushButtonOpenLogsClicked() @@ -77,7 +77,7 @@ void AppSettingsLogic::onPushButtonClearLogsClicked() void AppSettingsLogic::onPushButtonBackupAppConfigClicked() { - uiLogic()->saveTextFile("Backup application config", "AmneziaVPN.backup", ".backup", m_settings.backupAppConfig()); + uiLogic()->saveTextFile("Backup application config", "AmneziaVPN.backup", ".backup", m_settings->backupAppConfig()); } void AppSettingsLogic::onPushButtonRestoreAppConfigClicked() @@ -91,7 +91,7 @@ void AppSettingsLogic::onPushButtonRestoreAppConfigClicked() file.open(QIODevice::ReadOnly); QByteArray data = file.readAll(); - m_settings.restoreAppConfig(data); + m_settings->restoreAppConfig(data); emit uiLogic()->goToPage(Page::Vpn); emit uiLogic()->setStartPage(Page::Vpn); diff --git a/client/ui/pages_logic/GeneralSettingsLogic.cpp b/client/ui/pages_logic/GeneralSettingsLogic.cpp index 92696afaa..344fd5fad 100644 --- a/client/ui/pages_logic/GeneralSettingsLogic.cpp +++ b/client/ui/pages_logic/GeneralSettingsLogic.cpp @@ -12,24 +12,24 @@ GeneralSettingsLogic::GeneralSettingsLogic(UiLogic *logic, QObject *parent): void GeneralSettingsLogic::onUpdatePage() { - uiLogic()->selectedServerIndex = m_settings.defaultServerIndex(); - uiLogic()->selectedDockerContainer = m_settings.defaultContainer(m_settings.defaultServerIndex()); + uiLogic()->selectedServerIndex = m_settings->defaultServerIndex(); + uiLogic()->selectedDockerContainer = m_settings->defaultContainer(m_settings->defaultServerIndex()); - set_pushButtonGeneralSettingsShareConnectionEnable(m_settings.haveAuthData(m_settings.defaultServerIndex())); + set_pushButtonGeneralSettingsShareConnectionEnable(m_settings->haveAuthData(m_settings->defaultServerIndex())); } void GeneralSettingsLogic::onPushButtonGeneralSettingsServerSettingsClicked() { - uiLogic()->selectedServerIndex = m_settings.defaultServerIndex(); - uiLogic()->selectedDockerContainer = m_settings.defaultContainer(m_settings.defaultServerIndex()); + uiLogic()->selectedServerIndex = m_settings->defaultServerIndex(); + uiLogic()->selectedDockerContainer = m_settings->defaultContainer(m_settings->defaultServerIndex()); emit uiLogic()->goToPage(Page::ServerSettings); } void GeneralSettingsLogic::onPushButtonGeneralSettingsShareConnectionClicked() { - uiLogic()->selectedServerIndex = m_settings.defaultServerIndex(); - uiLogic()->selectedDockerContainer = m_settings.defaultContainer(uiLogic()->selectedServerIndex); + uiLogic()->selectedServerIndex = m_settings->defaultServerIndex(); + uiLogic()->selectedDockerContainer = m_settings->defaultContainer(uiLogic()->selectedServerIndex); qobject_cast(uiLogic()->protocolsModel())->setSelectedServerIndex(uiLogic()->selectedServerIndex); qobject_cast(uiLogic()->protocolsModel())->setSelectedDockerContainer(uiLogic()->selectedDockerContainer); diff --git a/client/ui/pages_logic/NetworkSettingsLogic.cpp b/client/ui/pages_logic/NetworkSettingsLogic.cpp index bd593e3a9..f7e77378e 100644 --- a/client/ui/pages_logic/NetworkSettingsLogic.cpp +++ b/client/ui/pages_logic/NetworkSettingsLogic.cpp @@ -13,39 +13,39 @@ NetworkSettingsLogic::NetworkSettingsLogic(UiLogic *logic, QObject *parent): void NetworkSettingsLogic::onUpdatePage() { - set_checkBoxUseAmneziaDnsChecked(m_settings.useAmneziaDns()); + set_checkBoxUseAmneziaDnsChecked(m_settings->useAmneziaDns()); - set_lineEditDns1Text(m_settings.primaryDns()); - set_lineEditDns2Text(m_settings.secondaryDns()); + set_lineEditDns1Text(m_settings->primaryDns()); + set_lineEditDns2Text(m_settings->secondaryDns()); } void NetworkSettingsLogic::onLineEditDns1EditFinished(const QString &text) { if (ipAddressRegex().exactMatch(text)) { - m_settings.setPrimaryDns(text); + m_settings->setPrimaryDns(text); } } void NetworkSettingsLogic::onLineEditDns2EditFinished(const QString &text) { if (ipAddressRegex().exactMatch(text)) { - m_settings.setSecondaryDns(text); + m_settings->setSecondaryDns(text); } } void NetworkSettingsLogic::onPushButtonResetDns1Clicked() { - m_settings.setPrimaryDns(m_settings.cloudFlareNs1); + m_settings->setPrimaryDns(m_settings->cloudFlareNs1); onUpdatePage(); } void NetworkSettingsLogic::onPushButtonResetDns2Clicked() { - m_settings.setSecondaryDns(m_settings.cloudFlareNs2); + m_settings->setSecondaryDns(m_settings->cloudFlareNs2); onUpdatePage(); } void NetworkSettingsLogic::onCheckBoxUseAmneziaDnsToggled(bool checked) { - m_settings.setUseAmneziaDns(checked); + m_settings->setUseAmneziaDns(checked); } diff --git a/client/ui/pages_logic/PageLogicBase.cpp b/client/ui/pages_logic/PageLogicBase.cpp index f06382136..78fd15d78 100644 --- a/client/ui/pages_logic/PageLogicBase.cpp +++ b/client/ui/pages_logic/PageLogicBase.cpp @@ -1,4 +1,5 @@ #include "PageLogicBase.h" +#include "ui/uilogic.h" PageLogicBase::PageLogicBase(UiLogic *logic, QObject *parent): @@ -6,6 +7,7 @@ PageLogicBase::PageLogicBase(UiLogic *logic, QObject *parent): m_pageEnabled{true}, m_uiLogic(logic) { - + m_settings = logic->m_settings; } + diff --git a/client/ui/pages_logic/PageLogicBase.h b/client/ui/pages_logic/PageLogicBase.h index 26858ee09..22df01349 100644 --- a/client/ui/pages_logic/PageLogicBase.h +++ b/client/ui/pages_logic/PageLogicBase.h @@ -23,8 +23,8 @@ public: protected: UiLogic *uiLogic() const { return m_uiLogic; } + std::shared_ptr m_settings; - Settings m_settings; UiLogic *m_uiLogic; signals: diff --git a/client/ui/pages_logic/ServerContainersLogic.cpp b/client/ui/pages_logic/ServerContainersLogic.cpp index e01e1bac9..8822ed922 100644 --- a/client/ui/pages_logic/ServerContainersLogic.cpp +++ b/client/ui/pages_logic/ServerContainersLogic.cpp @@ -36,21 +36,21 @@ void ServerContainersLogic::onPushButtonProtoSettingsClicked(DockerContainer c, { qDebug()<< "ServerContainersLogic::onPushButtonProtoSettingsClicked" << c << p; uiLogic()->selectedDockerContainer = c; - uiLogic()->protocolLogic(p)->updateProtocolPage(m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, p), + uiLogic()->protocolLogic(p)->updateProtocolPage(m_settings->protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, p), uiLogic()->selectedDockerContainer, - m_settings.haveAuthData(uiLogic()->selectedServerIndex)); + m_settings->haveAuthData(uiLogic()->selectedServerIndex)); emit uiLogic()->goToProtocolPage(p); } void ServerContainersLogic::onPushButtonDefaultClicked(DockerContainer c) { - if (m_settings.defaultContainer(uiLogic()->selectedServerIndex) == c) return; + if (m_settings->defaultContainer(uiLogic()->selectedServerIndex) == c) return; - m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c); + m_settings->setDefaultContainer(uiLogic()->selectedServerIndex, c); uiLogic()->onUpdateAllPages(); - if (uiLogic()->selectedServerIndex != m_settings.defaultServerIndex()) return; + if (uiLogic()->selectedServerIndex != m_settings->defaultServerIndex()) return; if (!uiLogic()->m_vpnConnection) return; if (!uiLogic()->m_vpnConnection->isConnected()) return; @@ -67,14 +67,14 @@ void ServerContainersLogic::onPushButtonShareClicked(DockerContainer c) void ServerContainersLogic::onPushButtonRemoveClicked(DockerContainer container) { //buttonSetEnabledFunc(false); - ErrorCode e = ServerController::removeContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), container); - m_settings.removeContainerConfig(uiLogic()->selectedServerIndex, container); + ErrorCode e = ServerController::removeContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), container); + m_settings->removeContainerConfig(uiLogic()->selectedServerIndex, container); //buttonSetEnabledFunc(true); - if (m_settings.defaultContainer(uiLogic()->selectedServerIndex) == container) { - const auto &c = m_settings.containers(uiLogic()->selectedServerIndex); - if (c.isEmpty()) m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None); - else m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c.keys().first()); + if (m_settings->defaultContainer(uiLogic()->selectedServerIndex) == container) { + const auto &c = m_settings->containers(uiLogic()->selectedServerIndex); + if (c.isEmpty()) m_settings->setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None); + else m_settings->setDefaultContainer(uiLogic()->selectedServerIndex, c.keys().first()); } uiLogic()->onUpdateAllPages(); } @@ -87,13 +87,13 @@ void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int p qApp->processEvents(); ErrorCode e = uiLogic()->serverConfiguringProgressLogic()->doInstallAction([this, c, &config](){ - return ServerController::setupContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), c, config); + return ServerController::setupContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), c, config); }); if (!e) { - m_settings.setContainerConfig(uiLogic()->selectedServerIndex, c, config); + m_settings->setContainerConfig(uiLogic()->selectedServerIndex, c, config); if (ContainerProps::containerService(c) == ServiceType::Vpn) { - m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c); + m_settings->setDefaultContainer(uiLogic()->selectedServerIndex, c); } } diff --git a/client/ui/pages_logic/ServerListLogic.cpp b/client/ui/pages_logic/ServerListLogic.cpp index 05cac928a..fe3f6512f 100644 --- a/client/ui/pages_logic/ServerListLogic.cpp +++ b/client/ui/pages_logic/ServerListLogic.cpp @@ -13,7 +13,7 @@ ServerListLogic::ServerListLogic(UiLogic *logic, QObject *parent): void ServerListLogic::onServerListPushbuttonDefaultClicked(int index) { - m_settings.setDefaultServer(index); + m_settings->setDefaultServer(index); uiLogic()->onUpdateAllPages(); } @@ -25,8 +25,8 @@ void ServerListLogic::onServerListPushbuttonSettingsClicked(int index) void ServerListLogic::onUpdatePage() { - const QJsonArray &servers = m_settings.serversArray(); - int defaultServer = m_settings.defaultServerIndex(); + const QJsonArray &servers = m_settings->serversArray(); + int defaultServer = m_settings->defaultServerIndex(); std::vector serverListContent; for(int i = 0; i < servers.size(); i++) { ServerModelContent c; diff --git a/client/ui/pages_logic/ServerSettingsLogic.cpp b/client/ui/pages_logic/ServerSettingsLogic.cpp index e15207b74..e23660fae 100644 --- a/client/ui/pages_logic/ServerSettingsLogic.cpp +++ b/client/ui/pages_logic/ServerSettingsLogic.cpp @@ -26,10 +26,10 @@ void ServerSettingsLogic::onUpdatePage() { set_labelWaitInfoVisible(false); set_labelWaitInfoText(""); - set_pushButtonClearVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex)); - set_pushButtonClearClientCacheVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex)); - set_pushButtonShareFullVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex)); - const QJsonObject &server = m_settings.server(uiLogic()->selectedServerIndex); + set_pushButtonClearVisible(m_settings->haveAuthData(uiLogic()->selectedServerIndex)); + set_pushButtonClearClientCacheVisible(m_settings->haveAuthData(uiLogic()->selectedServerIndex)); + set_pushButtonShareFullVisible(m_settings->haveAuthData(uiLogic()->selectedServerIndex)); + const QJsonObject &server = m_settings->server(uiLogic()->selectedServerIndex); const QString &port = server.value(config_key::port).toString(); set_labelServerText(QString("%1@%2%3%4") .arg(server.value(config_key::userName).toString()) @@ -38,7 +38,7 @@ void ServerSettingsLogic::onUpdatePage() .arg(port)); set_lineEditDescriptionText(server.value(config_key::description).toString()); - DockerContainer selectedContainer = m_settings.defaultContainer(uiLogic()->selectedServerIndex); + DockerContainer selectedContainer = m_settings->defaultContainer(uiLogic()->selectedServerIndex); QString selectedContainerName = ContainerProps::containerHumanNames().value(selectedContainer); set_labelCurrentVpnProtocolText(tr("Service: ") + selectedContainerName); } @@ -48,12 +48,12 @@ void ServerSettingsLogic::onPushButtonClearServer() set_pageEnabled(false); set_pushButtonClearText(tr("Uninstalling Amnezia software...")); - if (m_settings.defaultServerIndex() == uiLogic()->selectedServerIndex) { + if (m_settings->defaultServerIndex() == uiLogic()->selectedServerIndex) { uiLogic()->vpnLogic()->onDisconnect(); } - ErrorCode e = ServerController::removeAllContainers(m_settings.serverCredentials(uiLogic()->selectedServerIndex)); - ServerController::disconnectFromHost(m_settings.serverCredentials(uiLogic()->selectedServerIndex)); + ErrorCode e = ServerController::removeAllContainers(m_settings->serverCredentials(uiLogic()->selectedServerIndex)); + ServerController::disconnectFromHost(m_settings->serverCredentials(uiLogic()->selectedServerIndex)); if (e) { uiLogic()->setDialogConnectErrorText( tr("Error occurred while configuring server.") + "\n" + @@ -66,8 +66,8 @@ void ServerSettingsLogic::onPushButtonClearServer() set_labelWaitInfoText(tr("Amnezia server successfully uninstalled")); } - m_settings.setContainers(uiLogic()->selectedServerIndex, {}); - m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None); + m_settings->setContainers(uiLogic()->selectedServerIndex, {}); + m_settings->setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None); set_pageEnabled(true); set_pushButtonClearText(tr("Clear server from Amnezia software")); @@ -75,27 +75,27 @@ void ServerSettingsLogic::onPushButtonClearServer() void ServerSettingsLogic::onPushButtonForgetServer() { - if (m_settings.defaultServerIndex() == uiLogic()->selectedServerIndex && uiLogic()->m_vpnConnection->isConnected()) { + if (m_settings->defaultServerIndex() == uiLogic()->selectedServerIndex && uiLogic()->m_vpnConnection->isConnected()) { uiLogic()->vpnLogic()->onDisconnect(); } - m_settings.removeServer(uiLogic()->selectedServerIndex); + m_settings->removeServer(uiLogic()->selectedServerIndex); - if (m_settings.defaultServerIndex() == uiLogic()->selectedServerIndex) { - m_settings.setDefaultServer(0); + if (m_settings->defaultServerIndex() == uiLogic()->selectedServerIndex) { + m_settings->setDefaultServer(0); } - else if (m_settings.defaultServerIndex() > uiLogic()->selectedServerIndex) { - m_settings.setDefaultServer(m_settings.defaultServerIndex() - 1); + else if (m_settings->defaultServerIndex() > uiLogic()->selectedServerIndex) { + m_settings->setDefaultServer(m_settings->defaultServerIndex() - 1); } - if (m_settings.serversCount() == 0) { - m_settings.setDefaultServer(-1); + if (m_settings->serversCount() == 0) { + m_settings->setDefaultServer(-1); } uiLogic()->selectedServerIndex = -1; uiLogic()->onUpdateAllPages(); - if (m_settings.serversCount() == 0) { + if (m_settings->serversCount() == 0) { uiLogic()->setStartPage(Page::Start); } else { @@ -107,9 +107,9 @@ void ServerSettingsLogic::onPushButtonClearClientCacheClicked() { set_pushButtonClearClientCacheText(tr("Cache cleared")); - const auto &containers = m_settings.containers(uiLogic()->selectedServerIndex); + const auto &containers = m_settings->containers(uiLogic()->selectedServerIndex); for (DockerContainer container: containers.keys()) { - m_settings.clearLastConnectionConfig(uiLogic()->selectedServerIndex, container); + m_settings->clearLastConnectionConfig(uiLogic()->selectedServerIndex, container); } QTimer::singleShot(3000, this, [this]() { @@ -120,9 +120,9 @@ void ServerSettingsLogic::onPushButtonClearClientCacheClicked() void ServerSettingsLogic::onLineEditDescriptionEditingFinished() { const QString &newText = lineEditDescriptionText(); - QJsonObject server = m_settings.server(uiLogic()->selectedServerIndex); + QJsonObject server = m_settings->server(uiLogic()->selectedServerIndex); server.insert(config_key::description, newText); - m_settings.editServer(uiLogic()->selectedServerIndex, server); + m_settings->editServer(uiLogic()->selectedServerIndex, server); uiLogic()->onUpdateAllPages(); } diff --git a/client/ui/pages_logic/ShareConnectionLogic.cpp b/client/ui/pages_logic/ShareConnectionLogic.cpp index 038b38919..1b042a295 100644 --- a/client/ui/pages_logic/ShareConnectionLogic.cpp +++ b/client/ui/pages_logic/ShareConnectionLogic.cpp @@ -73,17 +73,17 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked() // Full access if (shareFullAccess()) { - serverConfig = m_settings.server(serverIndex); + serverConfig = m_settings->server(serverIndex); } // Container share else { - ServerCredentials credentials = m_settings.serverCredentials(serverIndex); - QJsonObject containerConfig = m_settings.containerConfig(serverIndex, container); + ServerCredentials credentials = m_settings->serverCredentials(serverIndex); + QJsonObject containerConfig = m_settings->containerConfig(serverIndex, container); containerConfig.insert(config_key::container, ContainerProps::containerToString(container)); ErrorCode e = ErrorCode::NoError; for (Proto p: ContainerProps::protocolsForContainer(container)) { - QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, p); + QJsonObject protoConfig = m_settings->protocolConfig(serverIndex, container, p); QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, container, containerConfig, p, &e); if (e) { @@ -96,7 +96,7 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked() QByteArray ba; if (!e) { - serverConfig = m_settings.server(serverIndex); + serverConfig = m_settings->server(serverIndex); serverConfig.remove(config_key::userName); serverConfig.remove(config_key::password); serverConfig.remove(config_key::port); @@ -129,9 +129,9 @@ void ShareConnectionLogic::onPushButtonShareOpenVpnGenerateClicked() { int serverIndex = uiLogic()->selectedServerIndex; DockerContainer container = uiLogic()->selectedDockerContainer; - ServerCredentials credentials = m_settings.serverCredentials(serverIndex); + ServerCredentials credentials = m_settings->serverCredentials(serverIndex); - const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container); + const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); ErrorCode e = ErrorCode::NoError; QString cfg = OpenVpnConfigurator::genOpenVpnConfig(credentials, container, containerConfig, &e); @@ -144,13 +144,13 @@ void ShareConnectionLogic::onPushButtonShareShadowSocksGenerateClicked() { int serverIndex = uiLogic()->selectedServerIndex; DockerContainer container = uiLogic()->selectedDockerContainer; - ServerCredentials credentials = m_settings.serverCredentials(serverIndex); + ServerCredentials credentials = m_settings->serverCredentials(serverIndex); - QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Proto::ShadowSocks); + QJsonObject protoConfig = m_settings->protocolConfig(serverIndex, container, Proto::ShadowSocks); QString cfg = protoConfig.value(config_key::last_config).toString(); if (cfg.isEmpty()) { - const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container); + const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); ErrorCode e = ErrorCode::NoError; cfg = ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, &e); @@ -186,13 +186,13 @@ void ShareConnectionLogic::onPushButtonShareCloakGenerateClicked() { int serverIndex = uiLogic()->selectedServerIndex; DockerContainer container = uiLogic()->selectedDockerContainer; - ServerCredentials credentials = m_settings.serverCredentials(serverIndex); + ServerCredentials credentials = m_settings->serverCredentials(serverIndex); - QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Proto::Cloak); + QJsonObject protoConfig = m_settings->protocolConfig(serverIndex, container, Proto::Cloak); QString cfg = protoConfig.value(config_key::last_config).toString(); if (cfg.isEmpty()) { - const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container); + const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); ErrorCode e = ErrorCode::NoError; cfg = CloakConfigurator::genCloakConfig(credentials, container, containerConfig, &e); @@ -209,9 +209,9 @@ void ShareConnectionLogic::onPushButtonShareWireGuardGenerateClicked() { int serverIndex = uiLogic()->selectedServerIndex; DockerContainer container = uiLogic()->selectedDockerContainer; - ServerCredentials credentials = m_settings.serverCredentials(serverIndex); + ServerCredentials credentials = m_settings->serverCredentials(serverIndex); - const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container); + const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); ErrorCode e = ErrorCode::NoError; QString cfg = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, &e); @@ -235,9 +235,9 @@ void ShareConnectionLogic::onPushButtonShareIkev2GenerateClicked() { int serverIndex = uiLogic()->selectedServerIndex; DockerContainer container = uiLogic()->selectedDockerContainer; - ServerCredentials credentials = m_settings.serverCredentials(serverIndex); + ServerCredentials credentials = m_settings->serverCredentials(serverIndex); - //const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container); + //const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); Ikev2Configurator::ConnectionData connData = Ikev2Configurator::prepareIkev2Config(credentials, container); diff --git a/client/ui/pages_logic/SitesLogic.cpp b/client/ui/pages_logic/SitesLogic.cpp index 8b94155f4..e9966bfaf 100644 --- a/client/ui/pages_logic/SitesLogic.cpp +++ b/client/ui/pages_logic/SitesLogic.cpp @@ -18,13 +18,13 @@ SitesLogic::SitesLogic(UiLogic *logic, QObject *parent): m_tableViewSitesModel{nullptr}, m_lineEditSitesAddCustomText{} { - sitesModels.insert(Settings::VpnOnlyForwardSites, new SitesModel(Settings::VpnOnlyForwardSites)); - sitesModels.insert(Settings::VpnAllExceptSites, new SitesModel(Settings::VpnAllExceptSites)); + sitesModels.insert(Settings::VpnOnlyForwardSites, new SitesModel(m_settings, Settings::VpnOnlyForwardSites)); + sitesModels.insert(Settings::VpnAllExceptSites, new SitesModel(m_settings, Settings::VpnAllExceptSites)); } void SitesLogic::onUpdatePage() { - Settings::RouteMode m = m_settings.routeMode(); + Settings::RouteMode m = m_settings->routeMode(); if (m == Settings::VpnAllSites) return; if (m == Settings::VpnOnlyForwardSites) { @@ -43,7 +43,7 @@ void SitesLogic::onPushButtonAddCustomSitesClicked() if (uiLogic()->vpnLogic()->radioButtonVpnModeAllSitesChecked()) { return; } - Settings::RouteMode mode = m_settings.routeMode(); + Settings::RouteMode mode = m_settings->routeMode(); QString newSite = lineEditSitesAddCustomText(); @@ -60,7 +60,7 @@ void SitesLogic::onPushButtonAddCustomSitesClicked() } const auto &cbProcess = [this, mode](const QString &newSite, const QString &ip) { - m_settings.addVpnSite(mode, newSite, ip); + m_settings->addVpnSite(mode, newSite, ip); if (!ip.isEmpty()) { uiLogic()->m_vpnConnection->addRoutes(QStringList() << ip); @@ -100,7 +100,7 @@ void SitesLogic::onPushButtonAddCustomSitesClicked() void SitesLogic::onPushButtonSitesDeleteClicked(QStringList items) { - Settings::RouteMode mode = m_settings.routeMode(); + Settings::RouteMode mode = m_settings->routeMode(); auto siteModel = qobject_cast (tableViewSitesModel()); if (!siteModel || items.isEmpty()) { @@ -121,7 +121,7 @@ void SitesLogic::onPushButtonSitesDeleteClicked(QStringList items) } } - m_settings.removeVpnSites(mode, sites); + m_settings->removeVpnSites(mode, sites); if (uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) { uiLogic()->m_vpnConnection->deleteRoutes(ips); @@ -139,7 +139,7 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName) return; } - Settings::RouteMode mode = m_settings.routeMode(); + Settings::RouteMode mode = m_settings->routeMode(); QStringList ips; QMap sites; @@ -187,8 +187,8 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName) } - m_settings.addVpnIps(mode, ips); - m_settings.addVpnSites(mode, sites); + m_settings->addVpnIps(mode, ips); + m_settings->addVpnSites(mode, sites); uiLogic()->m_vpnConnection->addRoutes(QStringList() << ips); uiLogic()->m_vpnConnection->flushDns(); @@ -198,9 +198,9 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName) void SitesLogic::onPushButtonSitesExportClicked() { - Settings::RouteMode mode = m_settings.routeMode(); + Settings::RouteMode mode = m_settings->routeMode(); - QVariantMap sites = m_settings.vpnSites(mode); + QVariantMap sites = m_settings->vpnSites(mode); QString data; for (auto s : sites.keys()) { diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index c21aa6f62..2dd8ef626 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -159,8 +159,8 @@ bool StartPageLogic::importConnection(const QJsonObject &profile) //qDebug() << QString("Password") << credentials.password; if (credentials.isValid() || profile.contains(config_key::containers)) { - m_settings.addServer(profile); - m_settings.setDefaultServer(m_settings.serversCount() - 1); + m_settings->addServer(profile); + m_settings->setDefaultServer(m_settings->serversCount() - 1); emit uiLogic()->goToPage(Page::Vpn); emit uiLogic()->setStartPage(Page::Vpn); @@ -172,8 +172,8 @@ bool StartPageLogic::importConnection(const QJsonObject &profile) } if (!profile.contains(config_key::containers)) { - uiLogic()->selectedServerIndex = m_settings.defaultServerIndex(); - uiLogic()->selectedDockerContainer = m_settings.defaultContainer(uiLogic()->selectedServerIndex); + uiLogic()->selectedServerIndex = m_settings->defaultServerIndex(); + uiLogic()->selectedDockerContainer = m_settings->defaultContainer(uiLogic()->selectedServerIndex); uiLogic()->onUpdateAllPages(); emit uiLogic()->goToPage(Page::ServerContainers); diff --git a/client/ui/pages_logic/VpnLogic.cpp b/client/ui/pages_logic/VpnLogic.cpp index 5812441e8..1bfd230ca 100644 --- a/client/ui/pages_logic/VpnLogic.cpp +++ b/client/ui/pages_logic/VpnLogic.cpp @@ -33,7 +33,7 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent): connect(this, &VpnLogic::connectToVpn, uiLogic()->m_vpnConnection, &VpnConnection::connectToVpn, Qt::QueuedConnection); connect(this, &VpnLogic::disconnectFromVpn, uiLogic()->m_vpnConnection, &VpnConnection::disconnectFromVpn, Qt::QueuedConnection); - if (m_settings.isAutoConnect() && m_settings.defaultServerIndex() >= 0) { + if (m_settings->isAutoConnect() && m_settings->defaultServerIndex() >= 0) { QTimer::singleShot(1000, this, [this](){ set_pushButtonConnectEnabled(false); onConnect(); @@ -47,20 +47,20 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent): void VpnLogic::onUpdatePage() { - Settings::RouteMode mode = m_settings.routeMode(); - DockerContainer selectedContainer = m_settings.defaultContainer(m_settings.defaultServerIndex()); + Settings::RouteMode mode = m_settings->routeMode(); + DockerContainer selectedContainer = m_settings->defaultContainer(m_settings->defaultServerIndex()); set_isCustomRoutesSupported (selectedContainer == DockerContainer::OpenVpn || selectedContainer == DockerContainer::ShadowSocks|| selectedContainer == DockerContainer::Cloak); - set_isContainerHaveAuthData(m_settings.haveAuthData(m_settings.defaultServerIndex())); + set_isContainerHaveAuthData(m_settings->haveAuthData(m_settings->defaultServerIndex())); set_radioButtonVpnModeAllSitesChecked(mode == Settings::VpnAllSites || !isCustomRoutesSupported()); set_radioButtonVpnModeForwardSitesChecked(mode == Settings::VpnOnlyForwardSites && isCustomRoutesSupported()); set_radioButtonVpnModeExceptSitesChecked(mode == Settings::VpnAllExceptSites && isCustomRoutesSupported()); - const QJsonObject &server = uiLogic()->m_settings.defaultServer(); + const QJsonObject &server = uiLogic()->m_settings->defaultServer(); QString serverString = QString("%2 (%3)") .arg(server.value(config_key::description).toString()) .arg(server.value(config_key::hostName).toString()); @@ -69,7 +69,7 @@ void VpnLogic::onUpdatePage() QString selectedContainerName = ContainerProps::containerHumanNames().value(selectedContainer); set_labelCurrentService(selectedContainerName); - auto dns = VpnConfigurator::getDnsForConfig(m_settings.defaultServerIndex()); + auto dns = VpnConfigurator::getDnsForConfig(m_settings->defaultServerIndex()); set_amneziaDnsEnabled(dns.first == protocols::dns::amneziaDnsIp); if (dns.first == protocols::dns::amneziaDnsIp) { set_labelCurrentDns("On your server"); @@ -93,19 +93,19 @@ void VpnLogic::onUpdatePage() void VpnLogic::onRadioButtonVpnModeAllSitesClicked() { - m_settings.setRouteMode(Settings::VpnAllSites); + m_settings->setRouteMode(Settings::VpnAllSites); onUpdatePage(); } void VpnLogic::onRadioButtonVpnModeForwardSitesClicked() { - m_settings.setRouteMode(Settings::VpnOnlyForwardSites); + m_settings->setRouteMode(Settings::VpnOnlyForwardSites); onUpdatePage(); } void VpnLogic::onRadioButtonVpnModeExceptSitesClicked() { - m_settings.setRouteMode(Settings::VpnAllExceptSites); + m_settings->setRouteMode(Settings::VpnAllExceptSites); onUpdatePage(); } @@ -203,11 +203,11 @@ void VpnLogic::onPushButtonConnectClicked() void VpnLogic::onConnect() { - int serverIndex = m_settings.defaultServerIndex(); - ServerCredentials credentials = m_settings.serverCredentials(serverIndex); - DockerContainer container = m_settings.defaultContainer(serverIndex); + int serverIndex = m_settings->defaultServerIndex(); + ServerCredentials credentials = m_settings->serverCredentials(serverIndex); + DockerContainer container = m_settings->defaultContainer(serverIndex); - if (m_settings.containers(serverIndex).isEmpty()) { + if (m_settings->containers(serverIndex).isEmpty()) { set_labelErrorText(tr("VPN Protocols is not installed.\n Please install VPN container at first")); set_pushButtonConnectChecked(false); return; @@ -220,7 +220,7 @@ void VpnLogic::onConnect() } - const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container); + const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); onConnectWorker(serverIndex, credentials, container, containerConfig); } diff --git a/client/ui/pages_logic/WizardLogic.cpp b/client/ui/pages_logic/WizardLogic.cpp index 7936524da..5fe820f1f 100644 --- a/client/ui/pages_logic/WizardLogic.cpp +++ b/client/ui/pages_logic/WizardLogic.cpp @@ -55,9 +55,9 @@ void WizardLogic::onPushButtonVpnModeFinishClicked() auto containers = getInstallConfigsFromWizardPage(); uiLogic()->installServer(containers); if (checkBoxVpnModeChecked()) { - m_settings.setRouteMode(Settings::VpnOnlyForwardSites); + m_settings->setRouteMode(Settings::VpnOnlyForwardSites); } else { - m_settings.setRouteMode(Settings::VpnAllSites); + m_settings->setRouteMode(Settings::VpnAllSites); } } diff --git a/client/ui/pages_logic/protocols/CloakLogic.cpp b/client/ui/pages_logic/protocols/CloakLogic.cpp index 2e341383b..227f2e5cc 100644 --- a/client/ui/pages_logic/protocols/CloakLogic.cpp +++ b/client/ui/pages_logic/protocols/CloakLogic.cpp @@ -52,10 +52,10 @@ QJsonObject CloakLogic::getProtocolConfigFromPage(QJsonObject oldConfig) void CloakLogic::onPushButtonSaveClicked() { - QJsonObject protocolConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::Cloak); + QJsonObject protocolConfig = m_settings->protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::Cloak); protocolConfig = getProtocolConfigFromPage(protocolConfig); - QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); + QJsonObject containerConfig = m_settings->containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); QJsonObject newContainerConfig = containerConfig; newContainerConfig.insert(ProtocolProps::protoToString(Proto::Cloak), protocolConfig); @@ -89,14 +89,14 @@ void CloakLogic::onPushButtonSaveClicked() }; ErrorCode e = uiLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ - return ServerController::updateContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); + return ServerController::updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); }, page_func, progressBar_reset, pushButton_save_func, label_info_func); if (!e) { - m_settings.setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig); - m_settings.clearLastConnectionConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); + m_settings->setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig); + m_settings->clearLastConnectionConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); } qDebug() << "Protocol saved with code:" << e << "for" << uiLogic()->selectedServerIndex << uiLogic()->selectedDockerContainer; diff --git a/client/ui/pages_logic/protocols/CloakLogic.h b/client/ui/pages_logic/protocols/CloakLogic.h index e110c4658..d88252c8f 100644 --- a/client/ui/pages_logic/protocols/CloakLogic.h +++ b/client/ui/pages_logic/protocols/CloakLogic.h @@ -32,7 +32,6 @@ public: QJsonObject getProtocolConfigFromPage(QJsonObject oldConfig) override; private: - Settings m_settings; UiLogic *m_uiLogic; }; diff --git a/client/ui/pages_logic/protocols/OpenVpnLogic.cpp b/client/ui/pages_logic/protocols/OpenVpnLogic.cpp index 98115f29b..e784dac9b 100644 --- a/client/ui/pages_logic/protocols/OpenVpnLogic.cpp +++ b/client/ui/pages_logic/protocols/OpenVpnLogic.cpp @@ -81,10 +81,10 @@ void OpenVpnLogic::updateProtocolPage(const QJsonObject &openvpnConfig, DockerCo void OpenVpnLogic::onPushButtonProtoOpenVpnSaveClicked() { - QJsonObject protocolConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::OpenVpn); + QJsonObject protocolConfig = m_settings->protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::OpenVpn); protocolConfig = getProtocolConfigFromPage(protocolConfig); - QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); + QJsonObject containerConfig = m_settings->containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); QJsonObject newContainerConfig = containerConfig; newContainerConfig.insert(ProtocolProps::protoToString(Proto::OpenVpn), protocolConfig); @@ -118,14 +118,14 @@ void OpenVpnLogic::onPushButtonProtoOpenVpnSaveClicked() }; ErrorCode e = uiLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ - return ServerController::updateContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); + return ServerController::updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); }, page_proto_openvpn, progressBar_proto_openvpn_reset, pushButton_proto_openvpn_save, label_proto_openvpn_info); if (!e) { - m_settings.setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig); - m_settings.clearLastConnectionConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); + m_settings->setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig); + m_settings->clearLastConnectionConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); } qDebug() << "Protocol saved with code:" << e << "for" << uiLogic()->selectedServerIndex << uiLogic()->selectedDockerContainer; } diff --git a/client/ui/pages_logic/protocols/OpenVpnLogic.h b/client/ui/pages_logic/protocols/OpenVpnLogic.h index 1d5c7f780..45141050e 100644 --- a/client/ui/pages_logic/protocols/OpenVpnLogic.h +++ b/client/ui/pages_logic/protocols/OpenVpnLogic.h @@ -44,7 +44,6 @@ public: QJsonObject getProtocolConfigFromPage(QJsonObject oldConfig) override; private: - Settings m_settings; UiLogic *m_uiLogic; }; diff --git a/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp b/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp index 8cf3949f1..329ca4dfe 100644 --- a/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp +++ b/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp @@ -82,7 +82,7 @@ void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked() { QString mountPath; QString cmd; - QString host = m_settings.serverCredentials(uiLogic()->selectedServerIndex).hostName; + QString host = m_settings->serverCredentials(uiLogic()->selectedServerIndex).hostName; #ifdef Q_OS_WINDOWS diff --git a/client/ui/pages_logic/protocols/OtherProtocolsLogic.h b/client/ui/pages_logic/protocols/OtherProtocolsLogic.h index 8639ba543..508c29141 100644 --- a/client/ui/pages_logic/protocols/OtherProtocolsLogic.h +++ b/client/ui/pages_logic/protocols/OtherProtocolsLogic.h @@ -31,7 +31,6 @@ public: //QJsonObject getProtocolConfigFromPage(QJsonObject oldConfig) override; private: - Settings m_settings; UiLogic *m_uiLogic; #ifdef AMNEZIA_DESKTOP diff --git a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp index 9aa8d0f3b..9f00d6884 100644 --- a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp +++ b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp @@ -46,10 +46,10 @@ QJsonObject ShadowSocksLogic::getProtocolConfigFromPage(QJsonObject oldConfig) void ShadowSocksLogic::onPushButtonSaveClicked() { - QJsonObject protocolConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::ShadowSocks); + QJsonObject protocolConfig = m_settings->protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::ShadowSocks); //protocolConfig = getShadowSocksConfigFromPage(protocolConfig); - QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); + QJsonObject containerConfig = m_settings->containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); QJsonObject newContainerConfig = containerConfig; newContainerConfig.insert(ProtocolProps::protoToString(Proto::ShadowSocks), protocolConfig); UiLogic::PageFunc page_proto_shadowsocks; @@ -82,14 +82,14 @@ void ShadowSocksLogic::onPushButtonSaveClicked() }; ErrorCode e = uiLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ - return ServerController::updateContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); + return ServerController::updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); }, page_proto_shadowsocks, progressBar_reset, pushButton_proto_shadowsocks_save, label_proto_shadowsocks_info); if (!e) { - m_settings.setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig); - m_settings.clearLastConnectionConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); + m_settings->setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig); + m_settings->clearLastConnectionConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); } qDebug() << "Protocol saved with code:" << e << "for" << uiLogic()->selectedServerIndex << uiLogic()->selectedDockerContainer; } diff --git a/client/ui/pages_logic/protocols/ShadowSocksLogic.h b/client/ui/pages_logic/protocols/ShadowSocksLogic.h index b7c2c9ee7..4e5668254 100644 --- a/client/ui/pages_logic/protocols/ShadowSocksLogic.h +++ b/client/ui/pages_logic/protocols/ShadowSocksLogic.h @@ -30,7 +30,6 @@ public: QJsonObject getProtocolConfigFromPage(QJsonObject oldConfig) override; private: - Settings m_settings; UiLogic *m_uiLogic; }; diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index fe2d541d5..7cd4f7a00 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -74,13 +74,14 @@ using namespace amnezia; using namespace PageEnumNS; -UiLogic::UiLogic(QObject *parent) : +UiLogic::UiLogic(std::shared_ptr settings, QObject *parent) : QObject(parent), + m_settings(settings), m_dialogConnectErrorText{} { - m_containersModel = new ContainersModel(this); - m_protocolsModel = new ProtocolsModel(this); - m_vpnConnection = new VpnConnection(); + m_containersModel = new ContainersModel(settings, this); + m_protocolsModel = new ProtocolsModel(settings, this); + m_vpnConnection = new VpnConnection(settings); m_vpnConnection->moveToThread(&m_vpnConnectionThread); m_vpnConnectionThread.start(); @@ -158,15 +159,15 @@ void UiLogic::initalizeUiLogic() connect(m_notificationHandler, &NotificationHandler::connectRequested, vpnLogic(), &VpnLogic::onConnect); connect(m_notificationHandler, &NotificationHandler::disconnectRequested, vpnLogic(), &VpnLogic::onDisconnect); - if (m_settings.serversCount() > 0) { - if (m_settings.defaultServerIndex() < 0) m_settings.setDefaultServer(0); + if (m_settings->serversCount() > 0) { + if (m_settings->defaultServerIndex() < 0) m_settings->setDefaultServer(0); emit goToPage(Page::Vpn, true, false); } else { emit goToPage(Page::Start, true, false); } - selectedServerIndex = m_settings.defaultServerIndex(); + selectedServerIndex = m_settings->defaultServerIndex(); qInfo().noquote() << QString("Started %1 version %2").arg(APPLICATION_NAME).arg(APP_VERSION); qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName()).arg(QSysInfo::currentCpuArchitecture()); @@ -187,7 +188,7 @@ void UiLogic::setDialogConnectErrorText(const QString &dialogConnectErrorText) void UiLogic::showOnStartup() { - if (! m_settings.isStartMinimized()) { + if (! m_settings->isStartMinimized()) { emit show(); } else { @@ -235,30 +236,30 @@ void UiLogic::keyPressEvent(Qt::Key key) qApp->quit(); break; case Qt::Key_H: - selectedServerIndex = m_settings.defaultServerIndex(); - selectedDockerContainer = m_settings.defaultContainer(selectedServerIndex); + selectedServerIndex = m_settings->defaultServerIndex(); + selectedDockerContainer = m_settings->defaultContainer(selectedServerIndex); - //updateSharingPage(selectedServerIndex, m_settings.serverCredentials(selectedServerIndex), selectedDockerContainer); + //updateSharingPage(selectedServerIndex, m_settings->serverCredentials(selectedServerIndex), selectedDockerContainer); emit goToPage(Page::ShareConnection); break; #endif case Qt::Key_C: - qDebug().noquote() << "Def server" << m_settings.defaultServerIndex() << m_settings.defaultContainerName(m_settings.defaultServerIndex()); - //qDebug().noquote() << QJsonDocument(m_settings.containerConfig(m_settings.defaultServerIndex(), m_settings.defaultContainer(m_settings.defaultServerIndex()))).toJson(); - qDebug().noquote() << QJsonDocument(m_settings.defaultServer()).toJson(); + qDebug().noquote() << "Def server" << m_settings->defaultServerIndex() << m_settings->defaultContainerName(m_settings->defaultServerIndex()); + //qDebug().noquote() << QJsonDocument(m_settings->containerConfig(m_settings->defaultServerIndex(), m_settings->defaultContainer(m_settings->defaultServerIndex()))).toJson(); + qDebug().noquote() << QJsonDocument(m_settings->defaultServer()).toJson(); break; case Qt::Key_A: emit goToPage(Page::Start); break; case Qt::Key_S: - selectedServerIndex = m_settings.defaultServerIndex(); + selectedServerIndex = m_settings->defaultServerIndex(); emit goToPage(Page::ServerSettings); break; case Qt::Key_P: onGotoCurrentProtocolsPage(); break; case Qt::Key_T: - SshConfigurator::openSshTerminal(m_settings.serverCredentials(m_settings.defaultServerIndex())); + SshConfigurator::openSshTerminal(m_settings->serverCredentials(m_settings->defaultServerIndex())); break; case Qt::Key_Escape: case Qt::Key_Back: @@ -280,7 +281,7 @@ void UiLogic::keyPressEvent(Qt::Key key) void UiLogic::onCloseWindow() { - if (m_settings.serversCount() == 0) qApp->quit(); + if (m_settings->serversCount() == 0) qApp->quit(); else { hide(); } @@ -299,8 +300,8 @@ QString UiLogic::containerDesc(int container) void UiLogic::onGotoCurrentProtocolsPage() { - selectedServerIndex = m_settings.defaultServerIndex(); - selectedDockerContainer = m_settings.defaultContainer(selectedServerIndex); + selectedServerIndex = m_settings->defaultServerIndex(); + selectedDockerContainer = m_settings->defaultContainer(selectedServerIndex); emit goToPage(Page::ServerContainers); } @@ -385,7 +386,7 @@ void UiLogic::installServer(QMap &containers) server.insert(config_key::userName, installCredentials.userName); server.insert(config_key::password, installCredentials.password); server.insert(config_key::port, installCredentials.port); - server.insert(config_key::description, m_settings.nextAvailableServerName()); + server.insert(config_key::description, m_settings->nextAvailableServerName()); QJsonArray containerConfigs; for (const QJsonObject &cfg : containers) { @@ -394,8 +395,8 @@ void UiLogic::installServer(QMap &containers) server.insert(config_key::containers, containerConfigs); server.insert(config_key::defaultContainer, ContainerProps::containerToString(containers.firstKey())); - m_settings.addServer(server); - m_settings.setDefaultServer(m_settings.serversCount() - 1); + m_settings->addServer(server); + m_settings->setDefaultServer(m_settings->serversCount() - 1); onUpdateAllPages(); emit setStartPage(Page::Vpn); diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index 4e818bcc0..bbec24510 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -58,10 +58,12 @@ class UiLogic : public QObject Q_PROPERTY(QString dialogConnectErrorText READ getDialogConnectErrorText WRITE setDialogConnectErrorText NOTIFY dialogConnectErrorTextChanged) public: - explicit UiLogic(QObject *parent = nullptr); + explicit UiLogic(std::shared_ptr settings, QObject *parent = nullptr); ~UiLogic(); void showOnStartup(); + friend class PageLogicBase; + friend class AppSettingsLogic; friend class GeneralSettingsLogic; friend class NetworkSettingsLogic; @@ -212,7 +214,7 @@ private: VpnConnection* m_vpnConnection; QThread m_vpnConnectionThread; - Settings m_settings; + std::shared_ptr m_settings; NotificationHandler* m_notificationHandler; diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index d2461b073..baee8933a 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -29,9 +29,8 @@ #include "utils.h" #include "vpnconnection.h" -VpnConnection::VpnConnection(QObject* parent) : QObject(parent), - m_settings(this) - +VpnConnection::VpnConnection(std::shared_ptr settings, QObject* parent) : QObject(parent), + m_settings(settings) { } @@ -56,7 +55,7 @@ void VpnConnection::onConnectionStateChanged(VpnProtocol::VpnConnectionState sta IpcClient::Interface()->resetIpStack(); IpcClient::Interface()->flushDns(); - if (m_settings.routeMode() != Settings::VpnAllSites) { + if (m_settings->routeMode() != Settings::VpnAllSites) { IpcClient::Interface()->routeDeleteList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0"); //qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << forwardIps.size(); } @@ -67,17 +66,17 @@ void VpnConnection::onConnectionStateChanged(VpnProtocol::VpnConnectionState sta QStringList() << dns1 << dns2); - if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) { + if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { QTimer::singleShot(1000, m_vpnProtocol.data(), [this](){ - addSitesRoutes(m_vpnProtocol->vpnGateway(), m_settings.routeMode()); + addSitesRoutes(m_vpnProtocol->vpnGateway(), m_settings->routeMode()); }); } - else if (m_settings.routeMode() == Settings::VpnAllExceptSites) { + else if (m_settings->routeMode() == Settings::VpnAllExceptSites) { IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0/1"); IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "128.0.0.0/1"); IpcClient::Interface()->routeAddList(m_vpnProtocol->routeGateway(), QStringList() << remoteAddress()); - addSitesRoutes(m_vpnProtocol->routeGateway(), m_settings.routeMode()); + addSitesRoutes(m_vpnProtocol->routeGateway(), m_settings->routeMode()); } @@ -85,7 +84,7 @@ void VpnConnection::onConnectionStateChanged(VpnProtocol::VpnConnectionState sta else if (state == VpnProtocol::Error) { IpcClient::Interface()->flushDns(); - if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) { + if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { IpcClient::Interface()->clearSavedRoutes(); } } @@ -104,7 +103,7 @@ void VpnConnection::addSitesRoutes(const QString &gw, Settings::RouteMode mode) #ifdef AMNEZIA_DESKTOP QStringList ips; QStringList sites; - const QVariantMap &m = m_settings.vpnSites(mode); + const QVariantMap &m = m_settings->vpnSites(mode); for (auto i = m.constBegin(); i != m.constEnd(); ++i) { if (Utils::checkIpSubnetFormat(i.key())) { ips.append(i.key()); @@ -132,7 +131,7 @@ void VpnConnection::addSitesRoutes(const QString &gw, Settings::RouteMode mode) //qDebug() << "VpnConnection::addSitesRoutes updating site" << site << ip; if (!ips.contains(ip)) { IpcClient::Interface()->routeAddList(gw, QStringList() << ip); - m_settings.addVpnSite(mode, site, ip); + m_settings->addVpnSite(mode, site, ip); } flushDns(); break; @@ -153,10 +152,10 @@ void VpnConnection::addRoutes(const QStringList &ips) { #ifdef AMNEZIA_DESKTOP if (connectionState() == VpnProtocol::Connected && IpcClient::Interface()) { - if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) { + if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), ips); } - else if (m_settings.routeMode() == Settings::VpnAllExceptSites) { + else if (m_settings->routeMode() == Settings::VpnAllExceptSites) { IpcClient::Interface()->routeAddList(m_vpnProtocol->routeGateway(), ips); } } @@ -167,10 +166,10 @@ void VpnConnection::deleteRoutes(const QStringList &ips) { #ifdef AMNEZIA_DESKTOP if (connectionState() == VpnProtocol::Connected && IpcClient::Interface()) { - if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) { + if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { IpcClient::Interface()->routeDeleteList(vpnProtocol()->vpnGateway(), ips); } - else if (m_settings.routeMode() == Settings::VpnAllExceptSites) { + else if (m_settings->routeMode() == Settings::VpnAllExceptSites) { IpcClient::Interface()->routeDeleteList(m_vpnProtocol->routeGateway(), ips); } } @@ -237,9 +236,9 @@ QString VpnConnection::createVpnConfigurationForProto(int serverIndex, if (serverIndex >= 0) { qDebug() << "VpnConnection::createVpnConfiguration: saving config for server #" << serverIndex << container << proto; - QJsonObject protoObject = m_settings.protocolConfig(serverIndex, container, proto); + QJsonObject protoObject = m_settings->protocolConfig(serverIndex, container, proto); protoObject.insert(config_key::last_config, configDataBeforeLocalProcessing); - m_settings.setProtocolConfig(serverIndex, container, proto, protoObject); + m_settings->setProtocolConfig(serverIndex, container, proto, protoObject); } } @@ -284,7 +283,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig) { qDebug() << QString("СonnectToVpn, Server index is %1, container is %2, route mode is") - .arg(serverIndex).arg(ContainerProps::containerToString(container)) << m_settings.routeMode(); + .arg(serverIndex).arg(ContainerProps::containerToString(container)) << m_settings->routeMode(); #if !defined (Q_OS_ANDROID) && !defined (Q_OS_IOS) if (!m_IpcClient) { diff --git a/client/vpnconnection.h b/client/vpnconnection.h index d0dc21359..86d096b6a 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -21,7 +21,7 @@ class VpnConnection : public QObject Q_OBJECT public: - explicit VpnConnection(QObject* parent = nullptr); + explicit VpnConnection(std::shared_ptr settings, QObject* parent = nullptr); ~VpnConnection() override; static QString bytesPerSecToText(quint64 bytes); @@ -73,7 +73,7 @@ protected: QSharedPointer m_vpnProtocol; private: - Settings m_settings; + std::shared_ptr m_settings; QJsonObject m_vpnConfiguration; QJsonObject m_routeMode; QString m_remoteAddress; From 3ce1ec708ddc0d4c9f4d5a80cf0122853f7468c9 Mon Sep 17 00:00:00 2001 From: pokamest Date: Thu, 25 Aug 2022 17:35:28 +0300 Subject: [PATCH 20/52] App refactoring finished --- client/amnezia_application.cpp | 15 ++--- client/amnezia_application.h | 3 + client/client.pro | 2 + client/configurators/cloak_configurator.cpp | 15 +++-- client/configurators/cloak_configurator.h | 13 ++-- client/configurators/configurator_base.cpp | 10 +++ client/configurators/configurator_base.h | 25 ++++++++ client/configurators/ikev2_configurator.cpp | 19 +++--- client/configurators/ikev2_configurator.h | 17 ++--- client/configurators/openvpn_configurator.cpp | 35 ++++++----- client/configurators/openvpn_configurator.h | 21 ++++--- .../shadowsocks_configurator.cpp | 13 +++- .../configurators/shadowsocks_configurator.h | 10 +-- client/configurators/ssh_configurator.cpp | 7 +++ client/configurators/ssh_configurator.h | 15 +++-- client/configurators/vpn_configurator.cpp | 38 ++++++----- client/configurators/vpn_configurator.h | 37 ++++++++--- .../configurators/wireguard_configurator.cpp | 45 ++++++------- client/configurators/wireguard_configurator.h | 20 +++--- client/core/servercontroller.cpp | 14 ++--- client/core/servercontroller.h | 63 ++++++++++--------- client/protocols/openvpnovercloakprotocol.cpp | 1 - client/protocols/shadowsocksvpnprotocol.cpp | 1 - .../ui/pages_logic/NetworkSettingsLogic.cpp | 1 + .../ui/pages_logic/NewServerProtocolsLogic.h | 1 + client/ui/pages_logic/PageLogicBase.cpp | 6 +- client/ui/pages_logic/PageLogicBase.h | 13 ++-- .../ServerConfiguringProgressLogic.h | 3 + .../ui/pages_logic/ServerContainersLogic.cpp | 6 +- client/ui/pages_logic/ServerContainersLogic.h | 1 + client/ui/pages_logic/ServerSettingsLogic.cpp | 6 +- .../ui/pages_logic/ShareConnectionLogic.cpp | 27 ++++---- client/ui/pages_logic/ShareConnectionLogic.h | 1 + client/ui/pages_logic/SitesLogic.h | 1 + client/ui/pages_logic/StartPageLogic.cpp | 5 +- client/ui/pages_logic/VpnLogic.cpp | 10 +-- client/ui/pages_logic/WizardLogic.h | 1 + .../ui/pages_logic/protocols/CloakLogic.cpp | 2 +- .../ui/pages_logic/protocols/OpenVpnLogic.cpp | 2 +- .../protocols/OtherProtocolsLogic.cpp | 1 - .../protocols/ShadowSocksLogic.cpp | 2 +- client/ui/property_helper.h | 4 +- client/ui/uilogic.cpp | 28 +++------ client/ui/uilogic.h | 21 +++---- client/vpnconnection.cpp | 18 +++--- client/vpnconnection.h | 10 ++- 46 files changed, 362 insertions(+), 247 deletions(-) create mode 100644 client/configurators/configurator_base.cpp create mode 100644 client/configurators/configurator_base.h diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index 85762a078..a0776c309 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -7,12 +7,11 @@ #include "QZXing.h" +#include "core/servercontroller.h" #include "debug.h" #include "defines.h" - #include "platforms/ios/QRCodeReaderBase.h" -//#include "platforms/ios/MobileUtils.h" #include "ui/pages.h" @@ -49,14 +48,8 @@ AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecond { setQuitOnLastWindowClosed(false); m_settings = std::shared_ptr(new Settings); - -// QObject::connect(&app, &QCoreApplication::aboutToQuit, uiLogic, [&engine, uiLogic](){ -// QObject::disconnect(engine, 0,0,0); -// delete engine; - -// QObject::disconnect(uiLogic, 0,0,0); -// delete uiLogic; - // }); + m_serverController = std::shared_ptr(new ServerController(m_settings, this)); + m_configurator = std::shared_ptr(new VpnConfigurator(m_settings, m_serverController, this)); } AmneziaApplication::~AmneziaApplication() @@ -71,7 +64,7 @@ AmneziaApplication::~AmneziaApplication() void AmneziaApplication::init() { m_engine = new QQmlApplicationEngine; - m_uiLogic = new UiLogic(m_settings); + m_uiLogic = new UiLogic(m_settings, m_configurator, m_serverController); const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml")); QObject::connect(m_engine, &QQmlApplicationEngine::objectCreated, diff --git a/client/amnezia_application.h b/client/amnezia_application.h index d7a768338..e0dfbc3a4 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -11,6 +11,7 @@ #include "settings.h" #include "ui/uilogic.h" +#include "configurators/vpn_configurator.h" #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) #define AMNEZIA_BASE_CLASS SingleApplication @@ -43,6 +44,8 @@ private: QQmlApplicationEngine *m_engine; UiLogic *m_uiLogic; std::shared_ptr m_settings; + std::shared_ptr m_configurator; + std::shared_ptr m_serverController; QTranslator* m_translator; QCommandLineParser m_parser; diff --git a/client/client.pro b/client/client.pro index 5d9ab1ea7..996521d1d 100644 --- a/client/client.pro +++ b/client/client.pro @@ -26,6 +26,7 @@ HEADERS += \ ../ipc/ipc.h \ amnezia_application.h \ configurators/cloak_configurator.h \ + configurators/configurator_base.h \ configurators/ikev2_configurator.h \ configurators/shadowsocks_configurator.h \ configurators/ssh_configurator.h \ @@ -87,6 +88,7 @@ HEADERS += \ SOURCES += \ amnezia_application.cpp \ configurators/cloak_configurator.cpp \ + configurators/configurator_base.cpp \ configurators/ikev2_configurator.cpp \ configurators/shadowsocks_configurator.cpp \ configurators/ssh_configurator.cpp \ diff --git a/client/configurators/cloak_configurator.cpp b/client/configurators/cloak_configurator.cpp index 211ddc79f..50f554dc4 100644 --- a/client/configurators/cloak_configurator.cpp +++ b/client/configurators/cloak_configurator.cpp @@ -4,18 +4,25 @@ #include #include +#include "core/servercontroller.h" #include "containers/containers_defs.h" +CloakConfigurator::CloakConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): + ConfiguratorBase(settings, serverController, parent) +{ + +} + QString CloakConfigurator::genCloakConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) { ErrorCode e = ErrorCode::NoError; - QString cloakPublicKey = ServerController::getTextFileFromContainer(container, credentials, + QString cloakPublicKey = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::cloak::ckPublicKeyPath, &e); cloakPublicKey.replace("\n", ""); - QString cloakBypassUid = ServerController::getTextFileFromContainer(container, credentials, + QString cloakBypassUid = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::cloak::ckBypassUidKeyPath, &e); cloakBypassUid.replace("\n", ""); @@ -40,8 +47,8 @@ QString CloakConfigurator::genCloakConfig(const ServerCredentials &credentials, config.insert(config_key::remote, credentials.hostName); config.insert(config_key::port, "$CLOAK_SERVER_PORT"); - QString textCfg = ServerController::replaceVars(QJsonDocument(config).toJson(), - ServerController::genVarsForScript(credentials, container, containerConfig)); + QString textCfg = m_serverController->replaceVars(QJsonDocument(config).toJson(), + m_serverController->genVarsForScript(credentials, container, containerConfig)); // qDebug().noquote() << textCfg; return textCfg; diff --git a/client/configurators/cloak_configurator.h b/client/configurators/cloak_configurator.h index 562b99176..c61848052 100644 --- a/client/configurators/cloak_configurator.h +++ b/client/configurators/cloak_configurator.h @@ -3,15 +3,18 @@ #include -#include "core/defs.h" -#include "settings.h" -#include "core/servercontroller.h" +#include "configurator_base.h" -class CloakConfigurator +using namespace amnezia; + +class CloakConfigurator : ConfiguratorBase { + Q_OBJECT public: + CloakConfigurator(std::shared_ptr settings, + std::shared_ptr serverController, QObject *parent = nullptr); - static QString genCloakConfig(const ServerCredentials &credentials, DockerContainer container, + QString genCloakConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); }; diff --git a/client/configurators/configurator_base.cpp b/client/configurators/configurator_base.cpp new file mode 100644 index 000000000..443774010 --- /dev/null +++ b/client/configurators/configurator_base.cpp @@ -0,0 +1,10 @@ +#include "configurator_base.h" + +ConfiguratorBase::ConfiguratorBase(std::shared_ptr settings, + std::shared_ptr serverController, QObject *parent) + : QObject{parent}, + m_settings(settings), + m_serverController(serverController) +{ + +} diff --git a/client/configurators/configurator_base.h b/client/configurators/configurator_base.h new file mode 100644 index 000000000..8c0614d9c --- /dev/null +++ b/client/configurators/configurator_base.h @@ -0,0 +1,25 @@ +#ifndef CONFIGURATORBASE_H +#define CONFIGURATORBASE_H + +#include + +class Settings; +class ServerController; + +#include "containers/containers_defs.h" +#include "core/defs.h" + +class ConfiguratorBase : public QObject +{ + Q_OBJECT +public: + explicit ConfiguratorBase(std::shared_ptr settings, + std::shared_ptr serverController, QObject *parent = nullptr); + +protected: + std::shared_ptr m_settings; + std::shared_ptr m_serverController; + +}; + +#endif // CONFIGURATORBASE_H diff --git a/client/configurators/ikev2_configurator.cpp b/client/configurators/ikev2_configurator.cpp index de9f0e827..db6b53a21 100644 --- a/client/configurators/ikev2_configurator.cpp +++ b/client/configurators/ikev2_configurator.cpp @@ -8,13 +8,18 @@ #include #include -#include "sftpdefs.h" - -#include "core/server_defs.h" #include "containers/containers_defs.h" +#include "core/server_defs.h" #include "core/scripts_registry.h" +#include "core/servercontroller.h" #include "utils.h" +Ikev2Configurator::Ikev2Configurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): + ConfiguratorBase(settings, serverController, parent) +{ + +} + Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const ServerCredentials &credentials, DockerContainer container, ErrorCode *errorCode) { @@ -35,16 +40,16 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se "--extKeyUsage serverAuth,clientAuth -8 \"%1\"") .arg(connData.clientId); - ErrorCode e = ServerController::runContainerScript(credentials, container, scriptCreateCert); + ErrorCode e = m_serverController->runContainerScript(credentials, container, scriptCreateCert); QString scriptExportCert = QString("pk12util -W \"%1\" -d sql:/etc/ipsec.d -n \"%2\" -o \"%3\"") .arg(connData.password) .arg(connData.clientId) .arg(certFileName); - e = ServerController::runContainerScript(credentials, container, scriptExportCert); + e = m_serverController->runContainerScript(credentials, container, scriptExportCert); - connData.clientCert = ServerController::getTextFileFromContainer(container, credentials, certFileName, &e); - connData.caCert = ServerController::getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e); + connData.clientCert = m_serverController->getTextFileFromContainer(container, credentials, certFileName, &e); + connData.caCert = m_serverController->getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e); qDebug() << "Ikev2Configurator::ConnectionData client cert size:" << connData.clientCert.size(); qDebug() << "Ikev2Configurator::ConnectionData ca cert size:" << connData.caCert.size(); diff --git a/client/configurators/ikev2_configurator.h b/client/configurators/ikev2_configurator.h index 9061a47c7..35c03b193 100644 --- a/client/configurators/ikev2_configurator.h +++ b/client/configurators/ikev2_configurator.h @@ -4,12 +4,15 @@ #include #include +#include "configurator_base.h" #include "core/defs.h" -#include "core/servercontroller.h" -class Ikev2Configurator +class Ikev2Configurator : ConfiguratorBase { + Q_OBJECT public: + Ikev2Configurator(std::shared_ptr settings, + std::shared_ptr serverController, QObject *parent = nullptr); struct ConnectionData { QByteArray clientCert; // p12 client cert @@ -19,14 +22,14 @@ public: QString host; // host ip }; - static QString genIkev2Config(const ServerCredentials &credentials, DockerContainer container, + QString genIkev2Config(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); - static QString genIkev2Config(const ConnectionData &connData); - static QString genMobileConfig(const ConnectionData &connData); - static QString genStrongSwanConfig(const ConnectionData &connData); + QString genIkev2Config(const ConnectionData &connData); + QString genMobileConfig(const ConnectionData &connData); + QString genStrongSwanConfig(const ConnectionData &connData); - static ConnectionData prepareIkev2Config(const ServerCredentials &credentials, + ConnectionData prepareIkev2Config(const ServerCredentials &credentials, DockerContainer container, ErrorCode *errorCode = nullptr); }; diff --git a/client/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp index 3ebfefccf..a7719108a 100644 --- a/client/configurators/openvpn_configurator.cpp +++ b/client/configurators/openvpn_configurator.cpp @@ -6,16 +6,25 @@ #include #include #include +#include -#include "core/server_defs.h" #include "containers/containers_defs.h" +#include "core/server_defs.h" +#include "core/servercontroller.h" #include "core/scripts_registry.h" +#include "settings.h" #include "utils.h" #include #include #include +OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): + ConfiguratorBase(settings, serverController, parent) +{ + +} + OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container, ErrorCode *errorCode) { @@ -31,7 +40,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co arg(amnezia::protocols::openvpn::clientsDirPath). arg(connData.clientId); - ErrorCode e = ServerController::uploadTextFileToContainer(container, credentials, connData.request, reqFileName); + ErrorCode e = m_serverController->uploadTextFileToContainer(container, credentials, connData.request, reqFileName); if (e) { if (errorCode) *errorCode = e; return connData; @@ -43,8 +52,8 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co return connData; } - connData.caCert = ServerController::getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::caCertPath, &e); - connData.clientCert = ServerController::getTextFileFromContainer(container, credentials, + connData.caCert = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::caCertPath, &e); + connData.clientCert = m_serverController->getTextFileFromContainer(container, credentials, QString("%1/%2.crt").arg(amnezia::protocols::openvpn::clientCertPath).arg(connData.clientId), &e); if (e) { @@ -52,7 +61,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co return connData; } - connData.taKey = ServerController::getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::taKeyPath, &e); + connData.taKey = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::taKeyPath, &e); if (connData.caCert.isEmpty() || connData.clientCert.isEmpty() || connData.taKey.isEmpty()) { if (errorCode) *errorCode = ErrorCode::RemoteProcessCrashError; @@ -61,17 +70,11 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co return connData; } -Settings &OpenVpnConfigurator::m_settings() -{ - static Settings s; - return s; -} - QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) { - QString config = ServerController::replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container), - ServerController::genVarsForScript(credentials, container, containerConfig)); + QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container), + m_serverController->genVarsForScript(credentials, container, containerConfig)); ConnectionData connData = prepareOpenVpnConfig(credentials, container, errorCode); if (errorCode && *errorCode) { @@ -105,7 +108,7 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig) QJsonObject json = QJsonDocument::fromJson(jsonConfig.toUtf8()).object(); QString config = json[config_key::config].toString(); - if (m_settings().routeMode() != Settings::VpnAllSites) { + if (m_settings->routeMode() != Settings::VpnAllSites) { config.replace("redirect-gateway def1 bypass-dhcp", ""); } else { @@ -161,9 +164,9 @@ ErrorCode OpenVpnConfigurator::signCert(DockerContainer container, .arg(clientId); QStringList scriptList {script_import, script_sign}; - QString script = ServerController::replaceVars(scriptList.join("\n"), ServerController::genVarsForScript(credentials, container)); + QString script = m_serverController->replaceVars(scriptList.join("\n"), m_serverController->genVarsForScript(credentials, container)); - return ServerController::runScript(credentials, script); + return m_serverController->runScript(credentials, script); } OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest() diff --git a/client/configurators/openvpn_configurator.h b/client/configurators/openvpn_configurator.h index 99c4efa6c..252304997 100644 --- a/client/configurators/openvpn_configurator.h +++ b/client/configurators/openvpn_configurator.h @@ -4,13 +4,15 @@ #include #include +#include "configurator_base.h" #include "core/defs.h" -#include "settings.h" -#include "core/servercontroller.h" -class OpenVpnConfigurator +class OpenVpnConfigurator : ConfiguratorBase { + Q_OBJECT public: + OpenVpnConfigurator(std::shared_ptr settings, + std::shared_ptr serverController, QObject *parent = nullptr); struct ConnectionData { QString clientId; @@ -22,22 +24,21 @@ public: QString host; // host ip }; - static QString genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container, + QString genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); - static QString processConfigWithLocalSettings(QString jsonConfig); - static QString processConfigWithExportSettings(QString jsonConfig); + QString processConfigWithLocalSettings(QString jsonConfig); + QString processConfigWithExportSettings(QString jsonConfig); - static ErrorCode signCert(DockerContainer container, + ErrorCode signCert(DockerContainer container, const ServerCredentials &credentials, QString clientId); private: - static ConnectionData createCertRequest(); + ConnectionData createCertRequest(); - static ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials, + ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container, ErrorCode *errorCode = nullptr); - static Settings &m_settings(); }; #endif // OPENVPN_CONFIGURATOR_H diff --git a/client/configurators/shadowsocks_configurator.cpp b/client/configurators/shadowsocks_configurator.cpp index 6f63ba797..97503ac4a 100644 --- a/client/configurators/shadowsocks_configurator.cpp +++ b/client/configurators/shadowsocks_configurator.cpp @@ -5,13 +5,20 @@ #include #include "containers/containers_defs.h" +#include "core/servercontroller.h" + +ShadowSocksConfigurator::ShadowSocksConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): + ConfiguratorBase(settings, serverController, parent) +{ + +} QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) { ErrorCode e = ErrorCode::NoError; - QString ssKey = ServerController::getTextFileFromContainer(container, credentials, + QString ssKey = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::shadowsocks::ssKeyPath, &e); ssKey.replace("\n", ""); @@ -29,8 +36,8 @@ QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &c config.insert("method", "$SHADOWSOCKS_CIPHER"); - QString textCfg = ServerController::replaceVars(QJsonDocument(config).toJson(), - ServerController::genVarsForScript(credentials, container, containerConfig)); + QString textCfg = m_serverController->replaceVars(QJsonDocument(config).toJson(), + m_serverController->genVarsForScript(credentials, container, containerConfig)); //qDebug().noquote() << textCfg; return textCfg; diff --git a/client/configurators/shadowsocks_configurator.h b/client/configurators/shadowsocks_configurator.h index 4445b074f..be80f1690 100644 --- a/client/configurators/shadowsocks_configurator.h +++ b/client/configurators/shadowsocks_configurator.h @@ -3,15 +3,17 @@ #include +#include "configurator_base.h" #include "core/defs.h" -#include "settings.h" -#include "core/servercontroller.h" -class ShadowSocksConfigurator +class ShadowSocksConfigurator : ConfiguratorBase { + Q_OBJECT public: + ShadowSocksConfigurator(std::shared_ptr settings, + std::shared_ptr serverController, QObject *parent = nullptr); - static QString genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container, + QString genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); }; diff --git a/client/configurators/ssh_configurator.cpp b/client/configurators/ssh_configurator.cpp index fdece1d6e..ac867c708 100644 --- a/client/configurators/ssh_configurator.cpp +++ b/client/configurators/ssh_configurator.cpp @@ -14,8 +14,15 @@ #include "core/server_defs.h" #include "utils.h" +#include "sftpdefs.h" + using namespace QSsh; +SshConfigurator::SshConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): + ConfiguratorBase(settings, serverController, parent) +{ + +} QString SshConfigurator::convertOpenSShKey(const QString &key) { diff --git a/client/configurators/ssh_configurator.h b/client/configurators/ssh_configurator.h index 71146a1ca..d7a177c38 100644 --- a/client/configurators/ssh_configurator.h +++ b/client/configurators/ssh_configurator.h @@ -4,16 +4,19 @@ #include #include +#include "configurator_base.h" #include "core/defs.h" -#include "settings.h" -#include "core/servercontroller.h" -class SshConfigurator +class SshConfigurator : ConfiguratorBase { + Q_OBJECT public: - static QProcessEnvironment prepareEnv(); - static QString convertOpenSShKey(const QString &key); - static void openSshTerminal(const ServerCredentials &credentials); + SshConfigurator(std::shared_ptr settings, + std::shared_ptr serverController, QObject *parent = nullptr); + + QProcessEnvironment prepareEnv(); + QString convertOpenSShKey(const QString &key); + void openSshTerminal(const ServerCredentials &credentials); }; diff --git a/client/configurators/vpn_configurator.cpp b/client/configurators/vpn_configurator.cpp index c2b128f09..42d3063ea 100644 --- a/client/configurators/vpn_configurator.cpp +++ b/client/configurators/vpn_configurator.cpp @@ -4,18 +4,26 @@ #include "shadowsocks_configurator.h" #include "wireguard_configurator.h" #include "ikev2_configurator.h" +#include "ssh_configurator.h" #include #include #include #include "containers/containers_defs.h" +#include "settings.h" #include "utils.h" -Settings &VpnConfigurator::m_settings() +VpnConfigurator::VpnConfigurator(std::shared_ptr settings, + std::shared_ptr serverController, QObject *parent): + ConfiguratorBase(settings, serverController, parent) { - static Settings s; - return s; + openVpnConfigurator = std::shared_ptr(new OpenVpnConfigurator(settings, serverController, this)); + shadowSocksConfigurator = std::shared_ptr(new ShadowSocksConfigurator(settings, serverController, this)); + cloakConfigurator = std::shared_ptr(new CloakConfigurator(settings, serverController, this)); + wireguardConfigurator = std::shared_ptr(new WireguardConfigurator(settings, serverController, this)); + ikev2Configurator = std::shared_ptr(new Ikev2Configurator(settings, serverController, this)); + sshConfigurator = std::shared_ptr(new SshConfigurator(settings, serverController, this)); } QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials, @@ -23,19 +31,19 @@ QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentia { switch (proto) { case Proto::OpenVpn: - return OpenVpnConfigurator::genOpenVpnConfig(credentials, container, containerConfig, errorCode); + return openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, errorCode); case Proto::ShadowSocks: - return ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, errorCode); + return shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, errorCode); case Proto::Cloak: - return CloakConfigurator::genCloakConfig(credentials, container, containerConfig, errorCode); + return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode); case Proto::WireGuard: - return WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, errorCode); + return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, errorCode); case Proto::Ikev2: - return Ikev2Configurator::genIkev2Config(credentials, container, containerConfig, errorCode); + return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode); default: return ""; @@ -46,20 +54,20 @@ QPair VpnConfigurator::getDnsForConfig(int serverIndex) { QPair dns; - bool useAmneziaDns = m_settings().useAmneziaDns(); - const QJsonObject &server = m_settings().server(serverIndex); + bool useAmneziaDns = m_settings->useAmneziaDns(); + const QJsonObject &server = m_settings->server(serverIndex); dns.first = server.value(config_key::dns1).toString(); dns.second = server.value(config_key::dns2).toString(); if (dns.first.isEmpty() || !Utils::checkIPv4Format(dns.first)) { - if (useAmneziaDns && m_settings().containers(serverIndex).contains(DockerContainer::Dns)) { + if (useAmneziaDns && m_settings->containers(serverIndex).contains(DockerContainer::Dns)) { dns.first = protocols::dns::amneziaDnsIp; } - else dns.first = m_settings().primaryDns(); + else dns.first = m_settings->primaryDns(); } if (dns.second.isEmpty() || !Utils::checkIPv4Format(dns.second)) { - dns.second = m_settings().secondaryDns(); + dns.second = m_settings->secondaryDns(); } qDebug() << "VpnConfigurator::getDnsForConfig" << dns.first << dns.second; @@ -83,7 +91,7 @@ QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, Docker processConfigWithDnsSettings(serverIndex, container, proto, config); if (proto == Proto::OpenVpn) { - config = OpenVpnConfigurator::processConfigWithLocalSettings(config); + config = openVpnConfigurator->processConfigWithLocalSettings(config); } return config; } @@ -94,7 +102,7 @@ QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, Docke processConfigWithDnsSettings(serverIndex, container, proto, config); if (proto == Proto::OpenVpn) { - config = OpenVpnConfigurator::processConfigWithExportSettings(config); + config = openVpnConfigurator->processConfigWithExportSettings(config); } return config; } diff --git a/client/configurators/vpn_configurator.h b/client/configurators/vpn_configurator.h index 702fc9d40..47bdc1fd5 100644 --- a/client/configurators/vpn_configurator.h +++ b/client/configurators/vpn_configurator.h @@ -3,29 +3,46 @@ #include +#include "configurator_base.h" #include "core/defs.h" -#include "settings.h" -#include "core/servercontroller.h" + + +class OpenVpnConfigurator; +class ShadowSocksConfigurator; +class CloakConfigurator; +class WireguardConfigurator; +class Ikev2Configurator; +class SshConfigurator; // Retrieve connection settings from server -class VpnConfigurator +class VpnConfigurator : ConfiguratorBase { + Q_OBJECT public: + VpnConfigurator(std::shared_ptr settings, + std::shared_ptr serverController, QObject *parent = nullptr); - static QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container, + QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr); - static QPair getDnsForConfig(int serverIndex); - static QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config); + QPair getDnsForConfig(int serverIndex); + QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config); - static QString &processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto, QString &config); - static QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config); + QString &processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto, QString &config); + QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config); // workaround for containers which is not support normal configaration - static void updateContainerConfigAfterInstallation(DockerContainer container, + void updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig, const QString &stdOut); - static Settings &m_settings(); + std::shared_ptr m_serverController; + + std::shared_ptr openVpnConfigurator; + std::shared_ptr shadowSocksConfigurator; + std::shared_ptr cloakConfigurator; + std::shared_ptr wireguardConfigurator; + std::shared_ptr ikev2Configurator; + std::shared_ptr sshConfigurator; }; #endif // VPN_CONFIGURATOR_H diff --git a/client/configurators/wireguard_configurator.cpp b/client/configurators/wireguard_configurator.cpp index c7b29ef56..08e6c40a4 100644 --- a/client/configurators/wireguard_configurator.cpp +++ b/client/configurators/wireguard_configurator.cpp @@ -5,19 +5,28 @@ #include #include #include +#include + #include #include #include #include -#include "sftpdefs.h" -#include "core/server_defs.h" #include "containers/containers_defs.h" +#include "core/server_defs.h" #include "core/scripts_registry.h" +#include "core/servercontroller.h" +#include "settings.h" #include "utils.h" +WireguardConfigurator::WireguardConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): + ConfiguratorBase(settings, serverController, parent) +{ + +} + WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys() { // TODO review @@ -71,7 +80,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon stdOut += data + "\n"; }; - ServerController::runContainerScript(credentials, container, script, cbReadStdOut); + m_serverController->runContainerScript(credentials, container, script, cbReadStdOut); stdOut.replace("AllowedIPs = ", ""); stdOut.replace("/32", ""); QStringList ips = stdOut.split("\n", Qt::SkipEmptyParts); @@ -104,14 +113,14 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon } // Get keys - connData.serverPubKey = ServerController::getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPublicKeyPath, &e); + connData.serverPubKey = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPublicKeyPath, &e); connData.serverPubKey.replace("\n", ""); if (e) { if (errorCode) *errorCode = e; return connData; } - connData.pskKey = ServerController::getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPskKeyPath, &e); + connData.pskKey = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPskKeyPath, &e); connData.pskKey.replace("\n", ""); if (e) { @@ -129,7 +138,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon arg(connData.pskKey). arg(connData.clientIP); - e = ServerController::uploadTextFileToContainer(container, credentials, configPart, + e = m_serverController->uploadTextFileToContainer(container, credentials, configPart, protocols::wireguard::serverConfigPath, QSsh::SftpOverwriteMode::SftpAppendToExisting); if (e) { @@ -137,24 +146,18 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon return connData; } - e = ServerController::runScript(credentials, - ServerController::replaceVars("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip /opt/amnezia/wireguard/wg0.conf)'", - ServerController::genVarsForScript(credentials, container))); + e = m_serverController->runScript(credentials, + m_serverController->replaceVars("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip /opt/amnezia/wireguard/wg0.conf)'", + m_serverController->genVarsForScript(credentials, container))); return connData; } -Settings &WireguardConfigurator::m_settings() -{ - static Settings s; - return s; -} - QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) { - QString config = ServerController::replaceVars(amnezia::scriptData(ProtocolScriptType::wireguard_template, container), - ServerController::genVarsForScript(credentials, container, containerConfig)); + QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::wireguard_template, container), + m_serverController->genVarsForScript(credentials, container, containerConfig)); ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode); if (errorCode && *errorCode) { @@ -182,8 +185,8 @@ QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &crede QString WireguardConfigurator::processConfigWithLocalSettings(QString config) { // TODO replace DNS if it already set - config.replace("$PRIMARY_DNS", m_settings().primaryDns()); - config.replace("$SECONDARY_DNS", m_settings().secondaryDns()); + config.replace("$PRIMARY_DNS", m_settings->primaryDns()); + config.replace("$SECONDARY_DNS", m_settings->secondaryDns()); QJsonObject jConfig; jConfig[config_key::config] = config; @@ -193,8 +196,8 @@ QString WireguardConfigurator::processConfigWithLocalSettings(QString config) QString WireguardConfigurator::processConfigWithExportSettings(QString config) { - config.replace("$PRIMARY_DNS", m_settings().primaryDns()); - config.replace("$SECONDARY_DNS", m_settings().secondaryDns()); + config.replace("$PRIMARY_DNS", m_settings->primaryDns()); + config.replace("$SECONDARY_DNS", m_settings->secondaryDns()); return config; } diff --git a/client/configurators/wireguard_configurator.h b/client/configurators/wireguard_configurator.h index 635c8dce6..76790d74b 100644 --- a/client/configurators/wireguard_configurator.h +++ b/client/configurators/wireguard_configurator.h @@ -4,13 +4,15 @@ #include #include +#include "configurator_base.h" #include "core/defs.h" -#include "settings.h" -#include "core/servercontroller.h" -class WireguardConfigurator +class WireguardConfigurator : ConfiguratorBase { + Q_OBJECT public: + WireguardConfigurator(std::shared_ptr settings, + std::shared_ptr serverController, QObject *parent = nullptr); struct ConnectionData { QString clientPrivKey; // client private key @@ -21,20 +23,18 @@ public: QString host; // host ip }; - static QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container, + QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); - static QString processConfigWithLocalSettings(QString config); - static QString processConfigWithExportSettings(QString config); + QString processConfigWithLocalSettings(QString config); + QString processConfigWithExportSettings(QString config); private: - static ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, + ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); - static ConnectionData genClientKeys(); - - static Settings &m_settings(); + ConnectionData genClientKeys(); }; #endif // WIREGUARD_CONFIGURATOR_H diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index 638e12535..1ea36011d 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -18,18 +18,18 @@ #include "containers/containers_defs.h" #include "server_defs.h" +#include "settings.h" #include "scripts_registry.h" #include "utils.h" #include - using namespace QSsh; -Settings &ServerController::m_settings() +ServerController::ServerController(std::shared_ptr settings, QObject *parent) : + m_settings(settings) { - static Settings s; - return s; + } ErrorCode ServerController::runScript(const ServerCredentials &credentials, QString script, @@ -605,7 +605,7 @@ ErrorCode ServerController::configureContainerWorker(const ServerCredentials &cr cbReadStdOut, cbReadStdErr); - VpnConfigurator::updateContainerConfigAfterInstallation(container, config, stdOut); + m_configurator->updateContainerConfigAfterInstallation(container, config, stdOut); return e; } @@ -698,8 +698,8 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential vars.append({{"$IPSEC_VPN_C2C_TRAFFIC", "no"}}); - vars.append({{"$PRIMARY_SERVER_DNS", m_settings().primaryDns()}}); - vars.append({{"$SECONDARY_SERVER_DNS", m_settings().secondaryDns()}}); + vars.append({{"$PRIMARY_SERVER_DNS", m_settings->primaryDns()}}); + vars.append({{"$SECONDARY_SERVER_DNS", m_settings->secondaryDns()}}); // Sftp vars diff --git a/client/core/servercontroller.h b/client/core/servercontroller.h index 0f1e6cbf6..091eaa524 100644 --- a/client/core/servercontroller.h +++ b/client/core/servercontroller.h @@ -7,78 +7,83 @@ #include "sshremoteprocess.h" #include "debug.h" #include "defs.h" -#include "settings.h" #include "containers/containers_defs.h" #include "sftpdefs.h" +class Settings; +class VpnConfigurator; + using namespace amnezia; class ServerController : public QObject { Q_OBJECT public: + ServerController(std::shared_ptr settings, QObject *parent = nullptr); + typedef QList> Vars; - static ErrorCode fromSshConnectionErrorCode(QSsh::SshError error); + ErrorCode fromSshConnectionErrorCode(QSsh::SshError error); // QSsh exitCode and exitStatus are different things - static ErrorCode fromSshProcessExitStatus(int exitStatus); + ErrorCode fromSshProcessExitStatus(int exitStatus); - static QSsh::SshConnectionParameters sshParams(const ServerCredentials &credentials); - static void disconnectFromHost(const ServerCredentials &credentials); + QSsh::SshConnectionParameters sshParams(const ServerCredentials &credentials); + void disconnectFromHost(const ServerCredentials &credentials); - static ErrorCode removeAllContainers(const ServerCredentials &credentials); - static ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container); - static ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config); - static ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container, + ErrorCode removeAllContainers(const ServerCredentials &credentials); + ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container); + ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config); + ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &oldConfig, QJsonObject &newConfig); // create initial config - generate passwords, etc - static QJsonObject createContainerInitialConfig(DockerContainer container, int port, TransportProto tp); + QJsonObject createContainerInitialConfig(DockerContainer container, int port, TransportProto tp); - static bool isReinstallContainerRequred(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig); + bool isReinstallContainerRequred(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig); - static ErrorCode checkOpenVpnServer(DockerContainer container, const ServerCredentials &credentials); + ErrorCode checkOpenVpnServer(DockerContainer container, const ServerCredentials &credentials); - static ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, + ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath, QSsh::SftpOverwriteMode overwriteMode = QSsh::SftpOverwriteMode::SftpOverwriteExisting); - static ErrorCode uploadTextFileToContainer(DockerContainer container, + ErrorCode uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials, const QString &file, const QString &path, QSsh::SftpOverwriteMode overwriteMode = QSsh::SftpOverwriteMode::SftpOverwriteExisting); - static QByteArray getTextFileFromContainer(DockerContainer container, + QByteArray getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode = nullptr); - static ErrorCode setupServerFirewall(const ServerCredentials &credentials); + ErrorCode setupServerFirewall(const ServerCredentials &credentials); - static QString replaceVars(const QString &script, const Vars &vars); + QString replaceVars(const QString &script, const Vars &vars); - static ErrorCode runScript(const ServerCredentials &credentials, QString script, + ErrorCode runScript(const ServerCredentials &credentials, QString script, const std::function)> &cbReadStdOut = nullptr, const std::function)> &cbReadStdErr = nullptr); - static ErrorCode runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script, + ErrorCode runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script, const std::function)> &cbReadStdOut = nullptr, const std::function)> &cbReadStdErr = nullptr); - static Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject()); + Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject()); - static QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr); - static QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams); + QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr); + QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams); private: - static ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container); - static ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); - static ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); - static ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config); - static ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config); - static ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); + ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container); + ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); + ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); + ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config); + ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config); + ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); - static Settings &m_settings(); + std::shared_ptr m_settings; + std::shared_ptr m_configurator; }; #endif // SERVERCONTROLLER_H diff --git a/client/protocols/openvpnovercloakprotocol.cpp b/client/protocols/openvpnovercloakprotocol.cpp index 2e9d77e85..5695b3dcf 100644 --- a/client/protocols/openvpnovercloakprotocol.cpp +++ b/client/protocols/openvpnovercloakprotocol.cpp @@ -1,5 +1,4 @@ #include "openvpnovercloakprotocol.h" -#include "core/servercontroller.h" #include "utils.h" #include "containers/containers_defs.h" diff --git a/client/protocols/shadowsocksvpnprotocol.cpp b/client/protocols/shadowsocksvpnprotocol.cpp index bc4947776..3de0bfe8e 100644 --- a/client/protocols/shadowsocksvpnprotocol.cpp +++ b/client/protocols/shadowsocksvpnprotocol.cpp @@ -1,5 +1,4 @@ #include "shadowsocksvpnprotocol.h" -#include "core/servercontroller.h" #include "debug.h" #include "utils.h" diff --git a/client/ui/pages_logic/NetworkSettingsLogic.cpp b/client/ui/pages_logic/NetworkSettingsLogic.cpp index f7e77378e..4038d089d 100644 --- a/client/ui/pages_logic/NetworkSettingsLogic.cpp +++ b/client/ui/pages_logic/NetworkSettingsLogic.cpp @@ -1,6 +1,7 @@ #include "NetworkSettingsLogic.h" #include "defines.h" +#include "settings.h" #include "utils.h" NetworkSettingsLogic::NetworkSettingsLogic(UiLogic *logic, QObject *parent): diff --git a/client/ui/pages_logic/NewServerProtocolsLogic.h b/client/ui/pages_logic/NewServerProtocolsLogic.h index a06e65907..abf3d1029 100644 --- a/client/ui/pages_logic/NewServerProtocolsLogic.h +++ b/client/ui/pages_logic/NewServerProtocolsLogic.h @@ -2,6 +2,7 @@ #define NEW_SERVER_PROTOCOLS_LOGIC_H #include "PageLogicBase.h" +#include "containers/containers_defs.h" class UiLogic; diff --git a/client/ui/pages_logic/PageLogicBase.cpp b/client/ui/pages_logic/PageLogicBase.cpp index 78fd15d78..9274ef49b 100644 --- a/client/ui/pages_logic/PageLogicBase.cpp +++ b/client/ui/pages_logic/PageLogicBase.cpp @@ -1,6 +1,8 @@ #include "PageLogicBase.h" -#include "ui/uilogic.h" +#include "ui/uilogic.h" +#include "settings.h" +#include "configurators/vpn_configurator.h" PageLogicBase::PageLogicBase(UiLogic *logic, QObject *parent): QObject(parent), @@ -8,6 +10,8 @@ PageLogicBase::PageLogicBase(UiLogic *logic, QObject *parent): m_uiLogic(logic) { m_settings = logic->m_settings; + m_configurator = logic->m_configurator; + m_serverController = logic->m_serverController; } diff --git a/client/ui/pages_logic/PageLogicBase.h b/client/ui/pages_logic/PageLogicBase.h index 22df01349..887b0ec7c 100644 --- a/client/ui/pages_logic/PageLogicBase.h +++ b/client/ui/pages_logic/PageLogicBase.h @@ -1,14 +1,15 @@ #ifndef PAGE_LOGIC_BASE_H #define PAGE_LOGIC_BASE_H -#include "settings.h" #include "../pages.h" #include "../property_helper.h" -using namespace amnezia; using namespace PageEnumNS; class UiLogic; +class Settings; +class VpnConfigurator; +class ServerController; class PageLogicBase : public QObject { @@ -22,10 +23,12 @@ public: Q_INVOKABLE virtual void onUpdatePage() {} protected: - UiLogic *uiLogic() const { return m_uiLogic; } - std::shared_ptr m_settings; - UiLogic *m_uiLogic; + UiLogic *uiLogic() const { return m_uiLogic; } + + std::shared_ptr m_settings; + std::shared_ptr m_configurator; + std::shared_ptr m_serverController; signals: void updatePage(); diff --git a/client/ui/pages_logic/ServerConfiguringProgressLogic.h b/client/ui/pages_logic/ServerConfiguringProgressLogic.h index 9620d4c36..3ca948784 100644 --- a/client/ui/pages_logic/ServerConfiguringProgressLogic.h +++ b/client/ui/pages_logic/ServerConfiguringProgressLogic.h @@ -3,6 +3,9 @@ #include #include "PageLogicBase.h" +#include "core/defs.h" + +using namespace amnezia; class UiLogic; diff --git a/client/ui/pages_logic/ServerContainersLogic.cpp b/client/ui/pages_logic/ServerContainersLogic.cpp index 8822ed922..6e021a45c 100644 --- a/client/ui/pages_logic/ServerContainersLogic.cpp +++ b/client/ui/pages_logic/ServerContainersLogic.cpp @@ -67,7 +67,7 @@ void ServerContainersLogic::onPushButtonShareClicked(DockerContainer c) void ServerContainersLogic::onPushButtonRemoveClicked(DockerContainer container) { //buttonSetEnabledFunc(false); - ErrorCode e = ServerController::removeContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), container); + ErrorCode e = m_serverController->removeContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), container); m_settings->removeContainerConfig(uiLogic()->selectedServerIndex, container); //buttonSetEnabledFunc(true); @@ -81,13 +81,13 @@ void ServerContainersLogic::onPushButtonRemoveClicked(DockerContainer container) void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int port, TransportProto tp) { - QJsonObject config = ServerController::createContainerInitialConfig(c, port, tp); + QJsonObject config = m_serverController->createContainerInitialConfig(c, port, tp); emit uiLogic()->goToPage(Page::ServerConfiguringProgress); qApp->processEvents(); ErrorCode e = uiLogic()->serverConfiguringProgressLogic()->doInstallAction([this, c, &config](){ - return ServerController::setupContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), c, config); + return m_serverController->setupContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), c, config); }); if (!e) { diff --git a/client/ui/pages_logic/ServerContainersLogic.h b/client/ui/pages_logic/ServerContainersLogic.h index a49882fa9..3f2a26cd0 100644 --- a/client/ui/pages_logic/ServerContainersLogic.h +++ b/client/ui/pages_logic/ServerContainersLogic.h @@ -2,6 +2,7 @@ #define SERVER_CONTAINERS_LOGIC_H #include "PageLogicBase.h" +#include "containers/containers_defs.h" class UiLogic; diff --git a/client/ui/pages_logic/ServerSettingsLogic.cpp b/client/ui/pages_logic/ServerSettingsLogic.cpp index e23660fae..ddf9504e8 100644 --- a/client/ui/pages_logic/ServerSettingsLogic.cpp +++ b/client/ui/pages_logic/ServerSettingsLogic.cpp @@ -52,10 +52,10 @@ void ServerSettingsLogic::onPushButtonClearServer() uiLogic()->vpnLogic()->onDisconnect(); } - ErrorCode e = ServerController::removeAllContainers(m_settings->serverCredentials(uiLogic()->selectedServerIndex)); - ServerController::disconnectFromHost(m_settings->serverCredentials(uiLogic()->selectedServerIndex)); + ErrorCode e = m_serverController->removeAllContainers(m_settings->serverCredentials(uiLogic()->selectedServerIndex)); + m_serverController->disconnectFromHost(m_settings->serverCredentials(uiLogic()->selectedServerIndex)); if (e) { - uiLogic()->setDialogConnectErrorText( + uiLogic()->set_dialogConnectErrorText( tr("Error occurred while configuring server.") + "\n" + errorString(e) + "\n" + tr("See logs for details.")); diff --git a/client/ui/pages_logic/ShareConnectionLogic.cpp b/client/ui/pages_logic/ShareConnectionLogic.cpp index 1b042a295..2e4404984 100644 --- a/client/ui/pages_logic/ShareConnectionLogic.cpp +++ b/client/ui/pages_logic/ShareConnectionLogic.cpp @@ -21,6 +21,7 @@ #include "defines.h" #include "core/defs.h" #include "core/errorstrings.h" +#include "core/servercontroller.h" #include #include "../uilogic.h" @@ -85,7 +86,7 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked() for (Proto p: ContainerProps::protocolsForContainer(container)) { QJsonObject protoConfig = m_settings->protocolConfig(serverIndex, container, p); - QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, container, containerConfig, p, &e); + QString cfg = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, p, &e); if (e) { cfg = "Error generating config"; break; @@ -103,7 +104,7 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked() serverConfig.insert(config_key::containers, QJsonArray {containerConfig}); serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(container)); - auto dns = VpnConfigurator::getDnsForConfig(serverIndex); + auto dns = m_configurator->getDnsForConfig(serverIndex); serverConfig.insert(config_key::dns1, dns.first); serverConfig.insert(config_key::dns2, dns.second); @@ -134,8 +135,8 @@ void ShareConnectionLogic::onPushButtonShareOpenVpnGenerateClicked() const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); ErrorCode e = ErrorCode::NoError; - QString cfg = OpenVpnConfigurator::genOpenVpnConfig(credentials, container, containerConfig, &e); - cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, cfg); + QString cfg = m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, &e); + cfg = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, cfg); set_textEditShareOpenVpnCodeText(QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString()); } @@ -153,7 +154,7 @@ void ShareConnectionLogic::onPushButtonShareShadowSocksGenerateClicked() const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); ErrorCode e = ErrorCode::NoError; - cfg = ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, &e); + cfg = m_configurator->shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, &e); } QJsonObject ssConfig = QJsonDocument::fromJson(cfg.toUtf8()).object(); @@ -195,7 +196,7 @@ void ShareConnectionLogic::onPushButtonShareCloakGenerateClicked() const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); ErrorCode e = ErrorCode::NoError; - cfg = CloakConfigurator::genCloakConfig(credentials, container, containerConfig, &e); + cfg = m_configurator->cloakConfigurator->genCloakConfig(credentials, container, containerConfig, &e); } QJsonObject cloakConfig = QJsonDocument::fromJson(cfg.toUtf8()).object(); @@ -214,14 +215,14 @@ void ShareConnectionLogic::onPushButtonShareWireGuardGenerateClicked() const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); ErrorCode e = ErrorCode::NoError; - QString cfg = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, &e); + QString cfg = m_configurator->wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, &e); if (e) { QMessageBox::warning(nullptr, APPLICATION_NAME, tr("Error occurred while configuring server.") + "\n" + errorString(e)); return; } - cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, cfg); + cfg = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, cfg); cfg = QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString(); set_textEditShareWireGuardCodeText(cfg); @@ -239,18 +240,18 @@ void ShareConnectionLogic::onPushButtonShareIkev2GenerateClicked() //const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); - Ikev2Configurator::ConnectionData connData = Ikev2Configurator::prepareIkev2Config(credentials, container); + Ikev2Configurator::ConnectionData connData = m_configurator->ikev2Configurator->prepareIkev2Config(credentials, container); - QString cfg = Ikev2Configurator::genIkev2Config(connData); - cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::Ikev2, cfg); + QString cfg = m_configurator->ikev2Configurator->genIkev2Config(connData); + cfg = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::Ikev2, cfg); cfg = QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::cert].toString(); set_textEditShareIkev2CertText(cfg); - QString mobileCfg = Ikev2Configurator::genMobileConfig(connData); + QString mobileCfg = m_configurator->ikev2Configurator->genMobileConfig(connData); set_textEditShareIkev2MobileConfigText(mobileCfg); - QString strongSwanCfg = Ikev2Configurator::genStrongSwanConfig(connData); + QString strongSwanCfg = m_configurator->ikev2Configurator->genStrongSwanConfig(connData); set_textEditShareIkev2StrongSwanConfigText(strongSwanCfg); } diff --git a/client/ui/pages_logic/ShareConnectionLogic.h b/client/ui/pages_logic/ShareConnectionLogic.h index c3c2ad6df..a167b43e2 100644 --- a/client/ui/pages_logic/ShareConnectionLogic.h +++ b/client/ui/pages_logic/ShareConnectionLogic.h @@ -2,6 +2,7 @@ #define SHARE_CONNECTION_LOGIC_H #include "PageLogicBase.h" +#include "containers/containers_defs.h" class UiLogic; diff --git a/client/ui/pages_logic/SitesLogic.h b/client/ui/pages_logic/SitesLogic.h index 2afb3805c..35bf1f90c 100644 --- a/client/ui/pages_logic/SitesLogic.h +++ b/client/ui/pages_logic/SitesLogic.h @@ -2,6 +2,7 @@ #define SITES_LOGIC_H #include "PageLogicBase.h" +#include "settings.h" class UiLogic; class SitesModel; diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index 2dd8ef626..b7b5907e0 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -1,6 +1,7 @@ #include "StartPageLogic.h" #include "core/errorstrings.h" #include "configurators/ssh_configurator.h" +#include "configurators/vpn_configurator.h" #include "../uilogic.h" #include "utils.h" @@ -83,7 +84,7 @@ void StartPageLogic::onPushButtonConnect() } if (key.contains("OPENSSH") && key.contains("BEGIN") && key.contains("PRIVATE KEY")) { - key = SshConfigurator::convertOpenSShKey(key); + key = m_configurator->sshConfigurator->convertOpenSShKey(key); } serverCredentials.password = key; @@ -97,7 +98,7 @@ void StartPageLogic::onPushButtonConnect() ErrorCode e = ErrorCode::NoError; #ifdef Q_DEBUG - //QString output = ServerController::checkSshConnection(serverCredentials, &e); + //QString output = m_serverController->checkSshConnection(serverCredentials, &e); #else QString output; #endif diff --git a/client/ui/pages_logic/VpnLogic.cpp b/client/ui/pages_logic/VpnLogic.cpp index 1bfd230ca..44a37a5ce 100644 --- a/client/ui/pages_logic/VpnLogic.cpp +++ b/client/ui/pages_logic/VpnLogic.cpp @@ -69,7 +69,7 @@ void VpnLogic::onUpdatePage() QString selectedContainerName = ContainerProps::containerHumanNames().value(selectedContainer); set_labelCurrentService(selectedContainerName); - auto dns = VpnConfigurator::getDnsForConfig(m_settings->defaultServerIndex()); + auto dns = m_configurator->getDnsForConfig(m_settings->defaultServerIndex()); set_amneziaDnsEnabled(dns.first == protocols::dns::amneziaDnsIp); if (dns.first == protocols::dns::amneziaDnsIp) { set_labelCurrentDns("On your server"); @@ -233,14 +233,6 @@ void VpnLogic::onConnectWorker(int serverIndex, const ServerCredentials &credent qApp->processEvents(); emit connectToVpn(serverIndex, credentials, container, containerConfig); - -// if (errorCode) { -// //ui->pushButton_connect->setChecked(false); -// uiLogic()->setDialogConnectErrorText(errorString(errorCode)); -// emit uiLogic()->showConnectErrorDialog(); -// return; -// } - } void VpnLogic::onDisconnect() diff --git a/client/ui/pages_logic/WizardLogic.h b/client/ui/pages_logic/WizardLogic.h index cfba5d2d6..3827c86e2 100644 --- a/client/ui/pages_logic/WizardLogic.h +++ b/client/ui/pages_logic/WizardLogic.h @@ -2,6 +2,7 @@ #define WIZARD_LOGIC_H #include "PageLogicBase.h" +#include "containers/containers_defs.h" class UiLogic; diff --git a/client/ui/pages_logic/protocols/CloakLogic.cpp b/client/ui/pages_logic/protocols/CloakLogic.cpp index 227f2e5cc..590199901 100644 --- a/client/ui/pages_logic/protocols/CloakLogic.cpp +++ b/client/ui/pages_logic/protocols/CloakLogic.cpp @@ -89,7 +89,7 @@ void CloakLogic::onPushButtonSaveClicked() }; ErrorCode e = uiLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ - return ServerController::updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); + return m_serverController->updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); }, page_func, progressBar_reset, pushButton_save_func, label_info_func); diff --git a/client/ui/pages_logic/protocols/OpenVpnLogic.cpp b/client/ui/pages_logic/protocols/OpenVpnLogic.cpp index e784dac9b..3b672747e 100644 --- a/client/ui/pages_logic/protocols/OpenVpnLogic.cpp +++ b/client/ui/pages_logic/protocols/OpenVpnLogic.cpp @@ -118,7 +118,7 @@ void OpenVpnLogic::onPushButtonProtoOpenVpnSaveClicked() }; ErrorCode e = uiLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ - return ServerController::updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); + return m_serverController->updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); }, page_proto_openvpn, progressBar_proto_openvpn_reset, pushButton_proto_openvpn_save, label_proto_openvpn_info); diff --git a/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp b/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp index 329ca4dfe..50b17a464 100644 --- a/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp +++ b/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp @@ -5,7 +5,6 @@ #include #include "OtherProtocolsLogic.h" -#include "core/servercontroller.h" #include #include "../../uilogic.h" #include "utils.h" diff --git a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp index 9f00d6884..e26efac1e 100644 --- a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp +++ b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp @@ -82,7 +82,7 @@ void ShadowSocksLogic::onPushButtonSaveClicked() }; ErrorCode e = uiLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ - return ServerController::updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); + return m_serverController->updateContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); }, page_proto_shadowsocks, progressBar_reset, pushButton_proto_shadowsocks_save, label_proto_shadowsocks_info); diff --git a/client/ui/property_helper.h b/client/ui/property_helper.h index 3d254c717..927105b3b 100644 --- a/client/ui/property_helper.h +++ b/client/ui/property_helper.h @@ -14,7 +14,7 @@ } \ Q_SIGNAL void NAME ## Changed(TYPE value);\ private: \ - TYPE m_ ## NAME; + TYPE m_ ## NAME{}; #define READONLY_PROPERTY(TYPE, NAME) \ Q_PROPERTY(TYPE NAME READ NAME CONSTANT ) \ @@ -22,6 +22,6 @@ TYPE NAME() const { return m_ ## NAME ; } \ private: \ void NAME(TYPE value) {m_ ## NAME = value; } \ - TYPE m_ ## NAME; + TYPE m_ ## NAME{}; #endif // PROPERTY_HELPER_H diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 7cd4f7a00..555c6bdc1 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -74,14 +74,17 @@ using namespace amnezia; using namespace PageEnumNS; -UiLogic::UiLogic(std::shared_ptr settings, QObject *parent) : +UiLogic::UiLogic(std::shared_ptr settings, std::shared_ptr configurator, + std::shared_ptr serverController, + QObject *parent) : QObject(parent), m_settings(settings), - m_dialogConnectErrorText{} + m_configurator(configurator), + m_serverController(serverController) { m_containersModel = new ContainersModel(settings, this); m_protocolsModel = new ProtocolsModel(settings, this); - m_vpnConnection = new VpnConnection(settings); + m_vpnConnection = new VpnConnection(settings, configurator, serverController); m_vpnConnection->moveToThread(&m_vpnConnectionThread); m_vpnConnectionThread.start(); @@ -173,19 +176,6 @@ void UiLogic::initalizeUiLogic() qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName()).arg(QSysInfo::currentCpuArchitecture()); } -QString UiLogic::getDialogConnectErrorText() const -{ - return m_dialogConnectErrorText; -} - -void UiLogic::setDialogConnectErrorText(const QString &dialogConnectErrorText) -{ - if (m_dialogConnectErrorText != dialogConnectErrorText) { - m_dialogConnectErrorText = dialogConnectErrorText; - emit dialogConnectErrorTextChanged(); - } -} - void UiLogic::showOnStartup() { if (! m_settings->isStartMinimized()) { @@ -259,7 +249,7 @@ void UiLogic::keyPressEvent(Qt::Key key) onGotoCurrentProtocolsPage(); break; case Qt::Key_T: - SshConfigurator::openSshTerminal(m_settings->serverCredentials(m_settings->defaultServerIndex())); + m_configurator->sshConfigurator->openSshTerminal(m_settings->serverCredentials(m_settings->defaultServerIndex())); break; case Qt::Key_Escape: case Qt::Key_Back: @@ -443,9 +433,9 @@ bool UiLogic::installContainers(ServerCredentials credentials, progress.setTextVisibleFunc(true); progress.setTextFunc(QString("Installing %1 %2 %3").arg(cnt+1).arg(tr("of")).arg(containers.size())); - ErrorCode e = ServerController::setupContainer(credentials, i.key(), i.value()); + ErrorCode e = m_serverController->setupContainer(credentials, i.key(), i.value()); qDebug() << "Setup server finished with code" << e; - ServerController::disconnectFromHost(credentials); + m_serverController->disconnectFromHost(credentials); if (e) { if (page.setEnabledFunc) { diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index bbec24510..ecf244212 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -16,7 +16,10 @@ #include "models/protocols_model.h" #include "notificationhandler.h" -#include "settings.h" + +class Settings; +class VpnConfigurator; +class ServerController; class AppSettingsLogic; class GeneralSettingsLogic; @@ -50,15 +53,14 @@ class UiLogic : public QObject AUTO_PROPERTY(bool, pageEnabled) AUTO_PROPERTY(int, pagesStackDepth) AUTO_PROPERTY(int, currentPageValue) + AUTO_PROPERTY(QString, dialogConnectErrorText) READONLY_PROPERTY(QObject *, containersModel) READONLY_PROPERTY(QObject *, protocolsModel) - // TODO: review - Q_PROPERTY(QString dialogConnectErrorText READ getDialogConnectErrorText WRITE setDialogConnectErrorText NOTIFY dialogConnectErrorTextChanged) - public: - explicit UiLogic(std::shared_ptr settings, QObject *parent = nullptr); + explicit UiLogic(std::shared_ptr settings, std::shared_ptr configurator, + std::shared_ptr serverController, QObject *parent = nullptr); ~UiLogic(); void showOnStartup(); @@ -108,9 +110,6 @@ public: void shareTempFile(const QString &suggestedName, QString ext, const QString& data); - QString getDialogConnectErrorText() const; - void setDialogConnectErrorText(const QString &dialogConnectErrorText); - signals: void dialogConnectErrorTextChanged(); @@ -127,9 +126,6 @@ signals: void raise(); void toggleLogPanel(); -private: - QString m_dialogConnectErrorText; - private slots: // containers - INOUT arg void installServer(QMap &containers); @@ -214,7 +210,10 @@ private: VpnConnection* m_vpnConnection; QThread m_vpnConnectionThread; + std::shared_ptr m_settings; + std::shared_ptr m_configurator; + std::shared_ptr m_serverController; NotificationHandler* m_notificationHandler; diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index baee8933a..d3b7faacf 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -29,8 +29,12 @@ #include "utils.h" #include "vpnconnection.h" -VpnConnection::VpnConnection(std::shared_ptr settings, QObject* parent) : QObject(parent), - m_settings(settings) +VpnConnection::VpnConnection(std::shared_ptr settings, + std::shared_ptr configurator, + std::shared_ptr serverController, QObject* parent) : QObject(parent), + m_settings(settings), + m_configurator(configurator), + m_serverController(serverController) { } @@ -214,18 +218,18 @@ QString VpnConnection::createVpnConfigurationForProto(int serverIndex, QString configData; if (lastVpnConfig.contains(proto)) { configData = lastVpnConfig.value(proto); - configData = VpnConfigurator::processConfigWithLocalSettings(serverIndex, container, proto, configData); + configData = m_configurator->processConfigWithLocalSettings(serverIndex, container, proto, configData); qDebug() << "VpnConnection::createVpnConfiguration: using saved config for" << ProtocolProps::protoToString(proto); } else { qDebug() << "VpnConnection::createVpnConfiguration: gen new config for" << ProtocolProps::protoToString(proto); - configData = VpnConfigurator::genVpnProtocolConfig(credentials, + configData = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, proto, &e); QString configDataBeforeLocalProcessing = configData; - configData = VpnConfigurator::processConfigWithLocalSettings(serverIndex, container, proto, configData); + configData = m_configurator->processConfigWithLocalSettings(serverIndex, container, proto, configData); if (errorCode && e) { @@ -271,7 +275,7 @@ QJsonObject VpnConnection::createVpnConfiguration(int serverIndex, Proto proto = ContainerProps::defaultProtocol(container); vpnConfiguration[config_key::vpnproto] = ProtocolProps::protoToString(proto); - auto dns = VpnConfigurator::getDnsForConfig(serverIndex); + auto dns = m_configurator->getDnsForConfig(serverIndex); vpnConfiguration[config_key::dns1] = dns.first; vpnConfiguration[config_key::dns2] = dns.second; @@ -345,7 +349,7 @@ void VpnConnection::connectToVpn(int serverIndex, connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(VpnProtocol::VpnConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::VpnConnectionState))); connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64))); - ServerController::disconnectFromHost(credentials); + m_serverController->disconnectFromHost(credentials); e = m_vpnProtocol.data()->start(); if (e) emit VpnProtocol::Error; diff --git a/client/vpnconnection.h b/client/vpnconnection.h index 86d096b6a..18446e744 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -14,6 +14,9 @@ #include "core/ipcclient.h" #endif +class VpnConfigurator; +class ServerController; + using namespace amnezia; class VpnConnection : public QObject @@ -21,7 +24,9 @@ class VpnConnection : public QObject Q_OBJECT public: - explicit VpnConnection(std::shared_ptr settings, QObject* parent = nullptr); + explicit VpnConnection(std::shared_ptr settings, + std::shared_ptr configurator, + std::shared_ptr serverController, QObject* parent = nullptr); ~VpnConnection() override; static QString bytesPerSecToText(quint64 bytes); @@ -74,6 +79,9 @@ protected: private: std::shared_ptr m_settings; + std::shared_ptr m_configurator; + std::shared_ptr m_serverController; + QJsonObject m_vpnConfiguration; QJsonObject m_routeMode; QString m_remoteAddress; From aed688224b1bd29547091a8068553588220f5c28 Mon Sep 17 00:00:00 2001 From: pokamest Date: Fri, 26 Aug 2022 00:35:03 +0300 Subject: [PATCH 21/52] App refactoring finished --- client/amnezia_application.cpp | 31 +++++++++++---------- client/amnezia_application.h | 14 ++++++---- client/client.pro | 3 +- client/secure_qsettings.cpp | 6 ++++ client/secure_qsettings.h | 4 +++ client/settings.cpp | 50 ---------------------------------- client/settings.h | 4 +-- 7 files changed, 36 insertions(+), 76 deletions(-) diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index a0776c309..585050e23 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -36,15 +36,14 @@ #include "ui/pages_logic/protocols/ShadowSocksLogic.h" -AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecondary, - SingleApplication::Options options, int timeout, const QString &userData): - #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - QAPPLICATION_CLASS(argc, argv); - #else - SingleApplication(argc, argv, allowSecondary, options, timeout, userData) - #endif - - +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + AmneziaApplication::AmneziaApplication(int &argc, char *argv[]): + AMNEZIA_BASE_CLASS(argc, argv) +#else + AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecondary, + SingleApplication::Options options, int timeout, const QString &userData): + SingleApplication(argc, argv, allowSecondary, options, timeout, userData) +#endif { setQuitOnLastWindowClosed(false); m_settings = std::shared_ptr(new Settings); @@ -59,6 +58,9 @@ AmneziaApplication::~AmneziaApplication() QObject::disconnect(m_uiLogic, 0,0,0); delete m_uiLogic; + + delete m_protocolProps; + delete m_containerProps; } void AmneziaApplication::init() @@ -112,7 +114,7 @@ void AmneziaApplication::init() if (m_parser.isSet("a")) m_uiLogic->showOnStartup(); else emit m_uiLogic->show(); #else - uiLogic->showOnStartup(); + m_uiLogic->showOnStartup(); #endif // TODO - fix @@ -144,7 +146,6 @@ void AmneziaApplication::registerTypes() qRegisterMetaType("PageProtocolLogicBase *"); - declareQmlPageEnum(); declareQmlProtocolEnum(); declareQmlContainerEnum(); @@ -152,11 +153,11 @@ void AmneziaApplication::registerTypes() qmlRegisterType("PageType", 1, 0, "PageType"); qmlRegisterType("QRCodeReader", 1, 0, "QRCodeReader"); - QScopedPointer containerProps(new ContainerProps); - qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", containerProps.get()); + m_containerProps = new ContainerProps; + qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", m_containerProps); - QScopedPointer protocolProps(new ProtocolProps); - qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", protocolProps.get()); + m_protocolProps = new ProtocolProps; + qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", m_protocolProps); } void AmneziaApplication::loadFonts() diff --git a/client/amnezia_application.h b/client/amnezia_application.h index e0dfbc3a4..c665ffef8 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -13,13 +13,12 @@ #include "ui/uilogic.h" #include "configurators/vpn_configurator.h" -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - #define AMNEZIA_BASE_CLASS SingleApplication - #define QAPPLICATION_CLASS QGuiApplication - #include "singleapplication.h" - //#undef QAPPLICATION_CLASS +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + #define AMNEZIA_BASE_CLASS QGuiApplication #else - #define AMNEZIA_BASE_CLASS QApplication + #define AMNEZIA_BASE_CLASS SingleApplication + #define QAPPLICATION_CLASS QApplication + #include "singleapplication.h" #endif class AmneziaApplication : public AMNEZIA_BASE_CLASS @@ -47,6 +46,9 @@ private: std::shared_ptr m_configurator; std::shared_ptr m_serverController; + ContainerProps* m_containerProps; + ProtocolProps* m_protocolProps; + QTranslator* m_translator; QCommandLineParser m_parser; diff --git a/client/client.pro b/client/client.pro index 996521d1d..157027554 100644 --- a/client/client.pro +++ b/client/client.pro @@ -2,7 +2,6 @@ QT += widgets core gui network xml remoteobjects quick svg TARGET = AmneziaVPN TEMPLATE = app -#CONFIG += console CONFIG += qtquickcompiler CONFIG += qzxing_multimedia \ @@ -287,7 +286,7 @@ android { } ios { - message("Client ios build") + message("Client iOS build") CONFIG += static CONFIG += file_copies diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index 488feb490..547326df1 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -32,6 +32,8 @@ SecureQSettings::SecureQSettings(const QString &organization, const QString &app QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue) const { + QMutexLocker locker(&mutex); + if (m_cache.contains(key)) { return m_cache.value(key); } @@ -76,6 +78,8 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue void SecureQSettings::setValue(const QString &key, const QVariant &value) { + QMutexLocker locker(&mutex); + if (encryptionRequired() && encryptedKeys.contains(key)) { if (!getEncKey().isEmpty() && !getEncIv().isEmpty()) { QByteArray decryptedValue; @@ -103,6 +107,8 @@ void SecureQSettings::setValue(const QString &key, const QVariant &value) void SecureQSettings::remove(const QString &key) { + QMutexLocker locker(&mutex); + m_settings.remove(key); m_cache.remove(key); diff --git a/client/secure_qsettings.h b/client/secure_qsettings.h index b36de1eb1..ea6da1060 100644 --- a/client/secure_qsettings.h +++ b/client/secure_qsettings.h @@ -3,6 +3,9 @@ #include #include +#include +#include + constexpr const char* settingsKeyTag = "settingsKeyTag"; constexpr const char* settingsIvTag = "settingsIvTag"; @@ -40,6 +43,7 @@ private: const QByteArray magicString { "EncData" }; // Magic keyword used for mark encrypted QByteArray + mutable QMutex mutex; }; #endif // SECUREQSETTINGS_H diff --git a/client/settings.cpp b/client/settings.cpp index 21deb0bd1..58695f60f 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -295,60 +295,10 @@ void Settings::removeVpnSites(RouteMode mode, const QStringList &sites) setVpnSites(mode, sitesMap); } -//void Settings::addVpnForwardSite(const QString &site, const QString &ip) -//{ -// auto sites = vpnForwardSites(); -// QStringList l = sites.value(site).toStringList(); -// if (!l.contains(ip)) { -// l.append(ip); -// setVpnForwardSites(sites); -// } -//} - -//QStringList Settings::getVpnForwardIps() const -//{ -// QStringList ips; -// const QVariantMap &m = vpnForwardSites(); -// for (const QVariant &v : m) { -// ips.append(v.toStringList()); -// } -// ips.removeDuplicates(); -// return ips; -//} - -//void Settings::addVpnExceptSite(const QString &site, const QString &ip) -//{ -// auto sites = vpnExceptSites(); -// QStringList l = sites.value(site).toStringList(); -// if (!l.contains(ip)) { -// l.append(ip); -// setVpnExceptSites(sites); -// } -//} - -//QStringList Settings::getVpnExceptIps() const -//{ -// QStringList ips; -// const QVariantMap &m = vpnExceptSites(); -// for (const QVariant &v : m) { -// ips.append(v.toStringList()); -// } -// ips.removeDuplicates(); -// return ips; -//} - QString Settings::primaryDns() const { return m_settings.value("Conf/primaryDns", cloudFlareNs1).toString(); } QString Settings::secondaryDns() const { return m_settings.value("Conf/secondaryDns", cloudFlareNs2).toString(); } -//void Settings::setServerCredentials(const ServerCredentials &credentials) -//{ -// setServerName(credentials.hostName); -// setServerPort(credentials.port); -// setUserName(credentials.userName); -// setPassword(credentials.password); -//} - ServerCredentials Settings::defaultServerCredentials() const { return serverCredentials(defaultServerIndex()); diff --git a/client/settings.h b/client/settings.h index fc5753297..aa32cb0eb 100644 --- a/client/settings.h +++ b/client/settings.h @@ -8,7 +8,6 @@ #include #include #include -#include #include "core/defs.h" #include "containers/containers_defs.h" @@ -27,7 +26,6 @@ public: ServerCredentials defaultServerCredentials() const; ServerCredentials serverCredentials(int index) const; - //void setServerCredentials(const ServerCredentials &credentials); QJsonArray serversArray() const { return QJsonDocument::fromJson(m_settings.value("Servers/serversList").toByteArray()).array(); } void setServersArray(const QJsonArray &servers) { m_settings.setValue("Servers/serversList", QJsonDocument(servers).toJson()); } @@ -117,7 +115,7 @@ public: private: SecureQSettings m_settings; - QMutex m_mutex; + }; #endif // SETTINGS_H From aae1da3aa81a1207f27e6fc6a96dbb75b5b2fd2f Mon Sep 17 00:00:00 2001 From: pokamest Date: Fri, 26 Aug 2022 00:58:24 +0300 Subject: [PATCH 22/52] Cleanup code --- client/amnezia_application.h | 2 +- client/secure_qsettings.cpp | 2 -- client/settings.cpp | 4 ---- client/ui/pages_logic/ShareConnectionLogic.cpp | 2 -- client/ui/pages_logic/StartPageLogic.cpp | 11 ----------- client/ui/pages_logic/protocols/ShadowSocksLogic.cpp | 1 - client/ui/systemtray_notificationhandler.cpp | 1 - client/ui/uilogic.cpp | 10 ++-------- client/utils.cpp | 1 - client/vpnconnection.cpp | 6 ------ 10 files changed, 3 insertions(+), 37 deletions(-) diff --git a/client/amnezia_application.h b/client/amnezia_application.h index c665ffef8..6d0ef5d2d 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -14,7 +14,7 @@ #include "configurators/vpn_configurator.h" #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - #define AMNEZIA_BASE_CLASS QGuiApplication + #define AMNEZIA_BASE_CLASS QApplication #else #define AMNEZIA_BASE_CLASS SingleApplication #define QAPPLICATION_CLASS QApplication diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index 547326df1..828369796 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -13,8 +13,6 @@ SecureQSettings::SecureQSettings(const QString &organization, const QString &app m_settings(organization, application, parent), encryptedKeys({"Servers/serversList"}) { - qDebug() << "SecureQSettings::SecureQSettings CTOR"; - bool encrypted = m_settings.value("Conf/encrypted").toBool(); // convert settings to encrypted for if updated to >= 2.1.0 diff --git a/client/settings.cpp b/client/settings.cpp index 58695f60f..6e470a338 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -2,7 +2,6 @@ #include "settings.h" #include "utils.h" -#include #include "containers/containers_defs.h" const char Settings::cloudFlareNs1[] = "1.1.1.1"; @@ -13,8 +12,6 @@ Settings::Settings(QObject* parent) : QObject(parent), m_settings(ORGANIZATION_NAME, APPLICATION_NAME, this) { - qDebug() << "Settings::Settings()" << this; -// qDebug() << "Settings::Settings()" << m_settings.fileName(); // Import old settings if (serversCount() == 0) { QString user = m_settings.value("Server/userName").toString(); @@ -181,7 +178,6 @@ void Settings::clearLastConnectionConfig(int serverIndex, DockerContainer contai QJsonObject c = protocolConfig(serverIndex, container, proto); c.remove(config_key::last_config); setProtocolConfig(serverIndex, container, proto, c); - qDebug() << "Settings::clearLastConnectionConfig for" << serverIndex << container << proto; } bool Settings::haveAuthData(int serverIndex) const diff --git a/client/ui/pages_logic/ShareConnectionLogic.cpp b/client/ui/pages_logic/ShareConnectionLogic.cpp index 2e4404984..6367722ac 100644 --- a/client/ui/pages_logic/ShareConnectionLogic.cpp +++ b/client/ui/pages_logic/ShareConnectionLogic.cpp @@ -238,8 +238,6 @@ void ShareConnectionLogic::onPushButtonShareIkev2GenerateClicked() DockerContainer container = uiLogic()->selectedDockerContainer; ServerCredentials credentials = m_settings->serverCredentials(serverIndex); - //const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); - Ikev2Configurator::ConnectionData connData = m_configurator->ikev2Configurator->prepareIkev2Config(credentials, container); QString cfg = m_configurator->ikev2Configurator->genIkev2Config(connData); diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index b7b5907e0..4fb00f6f6 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -49,8 +49,6 @@ void StartPageLogic::onUpdatePage() void StartPageLogic::onPushButtonConnect() { -// uiLogic()->goToPage(Page::NewServer); -// return; if (pushButtonConnectKeyChecked()){ if (lineEditIpText().isEmpty() || lineEditLoginText().isEmpty() || @@ -67,7 +65,6 @@ void StartPageLogic::onPushButtonConnect() return; } } - qDebug() << "UiLogic::onPushButtonConnect checking new server"; ServerCredentials serverCredentials; serverCredentials.hostName = lineEditIpText(); @@ -152,13 +149,6 @@ bool StartPageLogic::importConnection(const QJsonObject &profile) credentials.userName = profile.value(config_key::userName).toString(); credentials.password = profile.value(config_key::password).toString(); -// qDebug() << QString("Added server %3@%1:%2"). -// arg(credentials.hostName). -// arg(credentials.port). -// arg(credentials.userName); - - //qDebug() << QString("Password") << credentials.password; - if (credentials.isValid() || profile.contains(config_key::containers)) { m_settings->addServer(profile); m_settings->setDefaultServer(m_settings->serversCount() - 1); @@ -208,7 +198,6 @@ bool StartPageLogic::importConnectionFromCode(QString code) bool StartPageLogic::importConnectionFromQr(const QByteArray &data) { - qDebug() << "StartPageLogic::importConnectionFromQr" << data; QJsonObject dataObj = QJsonDocument::fromJson(data).object(); if (!dataObj.isEmpty()) { return importConnection(dataObj); diff --git a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp index e26efac1e..1d5da9366 100644 --- a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp +++ b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp @@ -47,7 +47,6 @@ QJsonObject ShadowSocksLogic::getProtocolConfigFromPage(QJsonObject oldConfig) void ShadowSocksLogic::onPushButtonSaveClicked() { QJsonObject protocolConfig = m_settings->protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::ShadowSocks); - //protocolConfig = getShadowSocksConfigFromPage(protocolConfig); QJsonObject containerConfig = m_settings->containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); QJsonObject newContainerConfig = containerConfig; diff --git a/client/ui/systemtray_notificationhandler.cpp b/client/ui/systemtray_notificationhandler.cpp index 21e24ac19..e142caf54 100644 --- a/client/ui/systemtray_notificationhandler.cpp +++ b/client/ui/systemtray_notificationhandler.cpp @@ -75,7 +75,6 @@ void SystemTrayNotificationHandler::onTrayActivated(QSystemTrayIcon::ActivationR void SystemTrayNotificationHandler::setTrayState(VpnProtocol::VpnConnectionState state) { - qDebug() << "SystemTrayNotificationHandler::setTrayState" << state; QString resourcesPath = ":/images/tray/%1"; switch (state) { diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 555c6bdc1..f3d45577a 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -147,14 +147,12 @@ void UiLogic::initalizeUiLogic() } }); if (!AndroidController::instance()->initialize()) { - qDebug() << QString("Init failed") ; + qCritical() << QString("Init failed") ; emit VpnProtocol::Error; return; } #endif - qDebug() << "UiLogic::initalizeUiLogic()"; - m_notificationHandler = NotificationHandler::create(qmlRoot()); connect(m_vpnConnection, &VpnConnection::connectionStateChanged, m_notificationHandler, &NotificationHandler::setConnectionState); @@ -235,7 +233,6 @@ void UiLogic::keyPressEvent(Qt::Key key) #endif case Qt::Key_C: qDebug().noquote() << "Def server" << m_settings->defaultServerIndex() << m_settings->defaultContainerName(m_settings->defaultServerIndex()); - //qDebug().noquote() << QJsonDocument(m_settings->containerConfig(m_settings->defaultServerIndex(), m_settings->defaultContainer(m_settings->defaultServerIndex()))).toJson(); qDebug().noquote() << QJsonDocument(m_settings->defaultServer()).toJson(); break; case Qt::Key_A: @@ -578,7 +575,7 @@ PageProtocolLogicBase *UiLogic::protocolLogic(Proto p) PageProtocolLogicBase *logic = m_protocolLogicMap.value(p); if (logic) return logic; else { - qDebug() << "UiLogic::protocolLogic Warning: logic missing for" << p; + qCritical() << "UiLogic::protocolLogic Warning: logic missing for" << p; return new PageProtocolLogicBase(this); } } @@ -623,13 +620,11 @@ void UiLogic::saveTextFile(const QString& desc, const QString& suggestedName, QS QUrl::fromLocalFile(docDir), "*" + ext); #endif - qDebug() << "UiLogic::saveTextFile" << fileName; if (fileName.isEmpty()) return; #ifdef AMNEZIA_DESKTOP QFile save(fileName.toLocalFile()); #else - qDebug() << "UiLogic::saveTextFile" << QQmlFile::urlToLocalFileOrQrc(fileName); QFile save(QQmlFile::urlToLocalFileOrQrc(fileName)); #endif @@ -672,7 +667,6 @@ void UiLogic::shareTempFile(const QString &suggestedName, QString ext, const QSt if (!fileName.endsWith(ext)) fileName.append(ext); QFile::remove(fileName); - qDebug() << "UiLogic::shareTempFile" << fileName; QFile save(fileName); save.open(QIODevice::WriteOnly); diff --git a/client/utils.cpp b/client/utils.cpp index 046d582cd..0e4c14037 100644 --- a/client/utils.cpp +++ b/client/utils.cpp @@ -121,7 +121,6 @@ QString Utils::getIPAddress(const QString& host) QList adresses = QHostInfo::fromName(host).addresses(); if (!adresses.isEmpty()) { - qDebug() << "Resolved address for" << host << adresses.first().toString(); return adresses.first().toString(); } qDebug() << "Unable to resolve address for " << host; diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index d3b7faacf..6e117ce43 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -219,11 +219,8 @@ QString VpnConnection::createVpnConfigurationForProto(int serverIndex, if (lastVpnConfig.contains(proto)) { configData = lastVpnConfig.value(proto); configData = m_configurator->processConfigWithLocalSettings(serverIndex, container, proto, configData); - - qDebug() << "VpnConnection::createVpnConfiguration: using saved config for" << ProtocolProps::protoToString(proto); } else { - qDebug() << "VpnConnection::createVpnConfiguration: gen new config for" << ProtocolProps::protoToString(proto); configData = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, proto, &e); @@ -363,8 +360,6 @@ QString VpnConnection::bytesPerSecToText(quint64 bytes) void VpnConnection::disconnectFromVpn() { - // qDebug() << "Disconnect from VPN 1"; - #ifdef AMNEZIA_DESKTOP if (IpcClient::Interface()) { IpcClient::Interface()->flushDns(); @@ -385,7 +380,6 @@ void VpnConnection::disconnectFromVpn() return; } m_vpnProtocol.data()->stop(); - // qDebug() << "Disconnect from VPN 2"; } VpnProtocol::VpnConnectionState VpnConnection::connectionState() From 266859af19cd21dd059cc6fb27ad9b4453b09224 Mon Sep 17 00:00:00 2001 From: pokamest Date: Fri, 26 Aug 2022 03:19:34 -0700 Subject: [PATCH 23/52] Build fix for iOS --- client/amnezia_application.cpp | 5 ++++- client/main.cpp | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index 585050e23..8ceff142c 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -35,6 +35,9 @@ #include "ui/pages_logic/protocols/OpenVpnLogic.h" #include "ui/pages_logic/protocols/ShadowSocksLogic.h" +#if defined(Q_OS_IOS) +#include "platforms/ios/QtAppDelegate-C-Interface.h" +#endif #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) AmneziaApplication::AmneziaApplication(int &argc, char *argv[]): @@ -95,7 +98,7 @@ void AmneziaApplication::init() m_engine->rootContext()->setContextProperty("WizardLogic", m_uiLogic->wizardLogic()); #if defined(Q_OS_IOS) - setStartPageLogic(uiLogic->startPageLogic()); + setStartPageLogic(m_uiLogic->startPageLogic()); #endif m_engine->load(url); diff --git a/client/main.cpp b/client/main.cpp index 904569417..e30bd8c85 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -5,7 +5,6 @@ #include "amnezia_application.h" #include "defines.h" - #ifdef Q_OS_WIN #include "Windows.h" #endif @@ -15,7 +14,7 @@ #endif #if defined(Q_OS_IOS) -#include "QtAppDelegate-C-Interface.h" +#include "platforms/ios/QtAppDelegate-C-Interface.h" #endif From 789902b79a32ba1cb7113bb046044342df37defd Mon Sep 17 00:00:00 2001 From: pokamest Date: Sat, 27 Aug 2022 17:35:43 +0300 Subject: [PATCH 24/52] Secure settings rework --- .gitmodules | 3 + client/3rd/qtkeychain | 1 + client/client.pro | 1 + client/platforms/ios/MobileUtils.cpp | 3 - client/platforms/ios/MobileUtils.h | 3 - client/platforms/ios/MobileUtils.mm | 55 -------------- client/secure_qsettings.cpp | 85 ++++++++++++++-------- client/secure_qsettings.h | 8 +- client/settings.h | 2 +- client/ui/pages_logic/AppSettingsLogic.cpp | 13 +++- 10 files changed, 79 insertions(+), 95 deletions(-) create mode 160000 client/3rd/qtkeychain diff --git a/.gitmodules b/.gitmodules index 008ebf892..328bfe764 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule "client/3rd/CocoaLumberjack"] path = client/3rd/CocoaLumberjack url = https://github.com/CocoaLumberjack/CocoaLumberjack.git +[submodule "client/3rd/qtkeychain"] + path = client/3rd/qtkeychain + url = https://github.com/frankosterfeld/qtkeychain.git diff --git a/client/3rd/qtkeychain b/client/3rd/qtkeychain new file mode 160000 index 000000000..f197cdb93 --- /dev/null +++ b/client/3rd/qtkeychain @@ -0,0 +1 @@ +Subproject commit f197cdb935b0cfd9881fdc6860874cb8379d1238 diff --git a/client/client.pro b/client/client.pro index 157027554..3ea957995 100644 --- a/client/client.pro +++ b/client/client.pro @@ -16,6 +16,7 @@ include("3rd/QtSsh/src/botan/botan.pri") include ("3rd/SortFilterProxyModel/SortFilterProxyModel.pri") include("3rd/qzxing/src/QZXing-components.pri") include("3rd/QSimpleCrypto/QSimpleCrypto.pri") +include("3rd/qtkeychain/qtkeychain.pri") INCLUDEPATH += $$PWD/3rd/QSimpleCrypto/include INCLUDEPATH += $$PWD/3rd/OpenSSL/include diff --git a/client/platforms/ios/MobileUtils.cpp b/client/platforms/ios/MobileUtils.cpp index 427cf3343..3923d2910 100644 --- a/client/platforms/ios/MobileUtils.cpp +++ b/client/platforms/ios/MobileUtils.cpp @@ -2,7 +2,4 @@ void MobileUtils::shareText(const QStringList&) {} -void MobileUtils::writeToKeychain(const QString&, const QByteArray &) {} -bool MobileUtils::deleteFromKeychain(const QString& tag) { return false; } -QByteArray MobileUtils::readFromKeychain(const QString&) { return {}; } diff --git a/client/platforms/ios/MobileUtils.h b/client/platforms/ios/MobileUtils.h index 045ababb6..a7967fdf6 100644 --- a/client/platforms/ios/MobileUtils.h +++ b/client/platforms/ios/MobileUtils.h @@ -13,9 +13,6 @@ public: public slots: static void shareText(const QStringList& filesToSend); - static void writeToKeychain(const QString& tag, const QByteArray& value); - static bool deleteFromKeychain(const QString& tag); - static QByteArray readFromKeychain(const QString& tag); }; #endif // MOBILEUTILS_H diff --git a/client/platforms/ios/MobileUtils.mm b/client/platforms/ios/MobileUtils.mm index bfe82a6a0..a9ad52b5d 100644 --- a/client/platforms/ios/MobileUtils.mm +++ b/client/platforms/ios/MobileUtils.mm @@ -35,58 +35,3 @@ void MobileUtils::shareText(const QStringList& filesToSend) { } } -bool MobileUtils::deleteFromKeychain(const QString& tag) { - NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - - NSDictionary *deleteQuery = @{ (id)kSecAttrAccount: nsTag, - (id)kSecClass: (id)kSecClassGenericPassword, - }; - - OSStatus status = SecItemDelete((__bridge CFDictionaryRef)deleteQuery); - if (status != errSecSuccess) { - qDebug() << "Error deleteFromKeychain" << status; - return false; - } -} - -void MobileUtils::writeToKeychain(const QString& tag, const QByteArray& value) { - deleteFromKeychain(tag); - - NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - NSData* nsValue = value.toNSData(); - - NSDictionary* addQuery = @{ (id)kSecAttrAccount: nsTag, - (id)kSecClass: (id)kSecClassGenericPassword, - (id)kSecValueData: nsValue, - }; - - OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL); - if (status != errSecSuccess) { - qDebug() << "Error writeToKeychain" << status; - } -} - -QByteArray MobileUtils::readFromKeychain(const QString& tag) { - NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding]; - NSData* nsValue = NULL; - - NSDictionary *getQuery = @{ (id)kSecAttrAccount: nsTag, - (id)kSecClass: (id)kSecClassGenericPassword, - (id)kSecMatchLimit: (id)kSecMatchLimitOne, - (id)kSecReturnData: @YES, - }; - - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)getQuery, - (CFTypeRef *)&nsValue); - if (status != errSecSuccess) { - qDebug() << "Error readFromKeychain" << status; - } - - QByteArray result; - if (nsValue) { - result = QByteArray::fromNSData(nsValue); - CFRelease(nsValue); - } - - return result; -} diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index 828369796..cbb8468db 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -3,11 +3,17 @@ #include #include +#include +#include +#include +#include #include "utils.h" #include #include "QAead.h" #include "QBlockCipher.h" +using namespace QKeychain; + SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent) : QObject{parent}, m_settings(organization, application, parent), @@ -70,7 +76,6 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue } m_cache.insert(key, retVal); - return retVal; } @@ -120,35 +125,26 @@ void SecureQSettings::sync() QByteArray SecureQSettings::backupAppConfig() const { - QMap cfg; + QJsonObject cfg; + for (const QString &key : m_settings.allKeys()) { - cfg.insert(key, value(key)); + cfg.insert(key, QJsonValue::fromVariant(value(key))); } - QByteArray ba; - { - QDataStream ds(&ba, QIODevice::WriteOnly); - ds << cfg; - } - - return ba.toBase64(); + return QJsonDocument(cfg).toJson(); } -void SecureQSettings::restoreAppConfig(const QByteArray &base64Cfg) +bool SecureQSettings::restoreAppConfig(const QByteArray &json) { - QByteArray ba = QByteArray::fromBase64(base64Cfg); - QMap cfg; - - { - QDataStream ds(&ba, QIODevice::ReadOnly); - ds >> cfg; - } + QJsonObject cfg = QJsonDocument::fromJson(json).object(); + if (cfg.isEmpty()) return false; for (const QString &key : cfg.keys()) { - setValue(key, cfg.value(key)); + setValue(key, cfg.value(key).toVariant()); } sync(); + return true; } @@ -166,17 +162,14 @@ QByteArray SecureQSettings::decryptText(const QByteArray& ba) const bool SecureQSettings::encryptionRequired() const { -#if defined Q_OS_IOS // || defined Q_OS_ANDROID + // TODO: review on linux return true; -#endif - - return false; } QByteArray SecureQSettings::getEncKey() const { // load keys from system key storage - m_key = MobileUtils::readFromKeychain(settingsKeyTag); + m_key = getSecTag(settingsKeyTag); if (m_key.isEmpty()) { // Create new key @@ -186,10 +179,10 @@ QByteArray SecureQSettings::getEncKey() const qCritical() << "SecureQSettings::getEncKey Unable to generate new enc key"; } - MobileUtils::writeToKeychain(settingsKeyTag, key); + setSecTag(settingsKeyTag, key); // check - m_key = MobileUtils::readFromKeychain(settingsKeyTag); + m_key = getSecTag(settingsKeyTag); if (key != m_key) { qCritical() << "SecureQSettings::getEncKey Unable to store key in keychain" << key.size() << m_key.size(); return {}; @@ -202,7 +195,7 @@ QByteArray SecureQSettings::getEncKey() const QByteArray SecureQSettings::getEncIv() const { // load keys from system key storage - m_iv = MobileUtils::readFromKeychain(settingsIvTag); + m_iv = getSecTag(settingsIvTag); if (m_iv.isEmpty()) { // Create new IV @@ -211,10 +204,10 @@ QByteArray SecureQSettings::getEncIv() const if (iv.isEmpty()) { qCritical() << "SecureQSettings::getEncIv Unable to generate new enc IV"; } - MobileUtils::writeToKeychain(settingsIvTag, iv); + setSecTag(settingsIvTag, iv); // check - m_iv = MobileUtils::readFromKeychain(settingsIvTag); + m_iv = getSecTag(settingsIvTag); if (iv != m_iv) { qCritical() << "SecureQSettings::getEncIv Unable to store IV in keychain" << iv.size() << m_iv.size(); return {}; @@ -224,4 +217,38 @@ QByteArray SecureQSettings::getEncIv() const return m_iv; } +QByteArray SecureQSettings::getSecTag(const QString &tag) +{ + ReadPasswordJob job("get-" + tag); + job.setAutoDelete(false); + job.setKey(tag); + QEventLoop loop; + job.connect(&job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit())); + job.start(); + loop.exec(); + + if ( job.error() ) { + qCritical() << "SecureQSettings::getSecTag Error:" << job.errorString(); + } + + return job.binaryData(); +} + +void SecureQSettings::setSecTag(const QString &tag, const QByteArray &data) +{ + WritePasswordJob job("set-" + tag); + job.setAutoDelete(false); + job.setKey(tag); + job.setBinaryData(data); + QEventLoop loop; + QTimer::singleShot(1000, &loop, SLOT(quit())); + job.connect(&job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit())); + job.start(); + loop.exec(); + + if (job.error()) { + qCritical() << "SecureQSettings::setSecTag Error:" << job.errorString(); + } +} + diff --git a/client/secure_qsettings.h b/client/secure_qsettings.h index ea6da1060..e0be9bfa0 100644 --- a/client/secure_qsettings.h +++ b/client/secure_qsettings.h @@ -6,6 +6,8 @@ #include #include +#include "keychain.h" + constexpr const char* settingsKeyTag = "settingsKeyTag"; constexpr const char* settingsIvTag = "settingsIvTag"; @@ -22,7 +24,7 @@ public: void sync(); QByteArray backupAppConfig() const; - void restoreAppConfig(const QByteArray &base64Cfg); + bool restoreAppConfig(const QByteArray &json); QByteArray encryptText(const QByteArray &value) const; QByteArray decryptText(const QByteArray& ba) const; @@ -31,6 +33,10 @@ public: QByteArray getEncKey() const; QByteArray getEncIv() const; + + static QByteArray getSecTag(const QString &tag); + static void setSecTag(const QString &tag, const QByteArray &data); + private: QSettings m_settings; diff --git a/client/settings.h b/client/settings.h index aa32cb0eb..c78b9a791 100644 --- a/client/settings.h +++ b/client/settings.h @@ -111,7 +111,7 @@ public: // static constexpr char openNicNs13[] = "144.76.103.143"; QByteArray backupAppConfig() const { return m_settings.backupAppConfig(); } - void restoreAppConfig(const QByteArray &cfg) { m_settings.restoreAppConfig(cfg); } + bool restoreAppConfig(const QByteArray &cfg) { return m_settings.restoreAppConfig(cfg); } private: SecureQSettings m_settings; diff --git a/client/ui/pages_logic/AppSettingsLogic.cpp b/client/ui/pages_logic/AppSettingsLogic.cpp index e9c614aad..b2907c3de 100644 --- a/client/ui/pages_logic/AppSettingsLogic.cpp +++ b/client/ui/pages_logic/AppSettingsLogic.cpp @@ -7,6 +7,7 @@ #include #include +#include #include using namespace amnezia; @@ -91,9 +92,15 @@ void AppSettingsLogic::onPushButtonRestoreAppConfigClicked() file.open(QIODevice::ReadOnly); QByteArray data = file.readAll(); - m_settings->restoreAppConfig(data); + bool ok = m_settings->restoreAppConfig(data); + if (ok) { + emit uiLogic()->goToPage(Page::Vpn); + emit uiLogic()->setStartPage(Page::Vpn); + } + else { + QMessageBox::warning(nullptr, APPLICATION_NAME, + tr("Can't import config, file is corrupted.")); + } - emit uiLogic()->goToPage(Page::Vpn); - emit uiLogic()->setStartPage(Page::Vpn); } From 997c8c87d0e0290d5c5b63e10e3e9b9014f39a29 Mon Sep 17 00:00:00 2001 From: pokamest Date: Sat, 27 Aug 2022 18:41:44 +0300 Subject: [PATCH 25/52] Cleanup --- client/protocols/wireguardprotocol.cpp | 17 ----------------- ipc/ipcserverprocess.cpp | 20 -------------------- ipc/ipcserverprocess.h | 1 - 3 files changed, 38 deletions(-) diff --git a/client/protocols/wireguardprotocol.cpp b/client/protocols/wireguardprotocol.cpp index 763813c94..456998ff7 100644 --- a/client/protocols/wireguardprotocol.cpp +++ b/client/protocols/wireguardprotocol.cpp @@ -12,23 +12,18 @@ WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject* parent) : VpnProtocol(configuration, parent) { - //m_configFile.setFileTemplate(QDir::tempPath() + QDir::separator() + serviceName() + ".conf"); m_configFile.setFileName(QDir::tempPath() + QDir::separator() + serviceName() + ".conf"); readWireguardConfiguration(configuration); } WireguardProtocol::~WireguardProtocol() { - //qDebug() << "WireguardProtocol::~WireguardProtocol() 1"; WireguardProtocol::stop(); QThread::msleep(200); - //qDebug() << "WireguardProtocol::~WireguardProtocol() 2"; } void WireguardProtocol::stop() { - //qDebug() << "WireguardProtocol::stop() 1"; - #ifndef Q_OS_IOS if (!QFileInfo::exists(Utils::wireguardExecPath())) { qCritical() << "Wireguard executable missing!"; @@ -74,7 +69,6 @@ void WireguardProtocol::stop() setConnectionState(VpnProtocol::Disconnected); #endif - //qDebug() << "WireguardProtocol::stop() 2"; } void WireguardProtocol::readWireguardConfiguration(const QJsonObject &configuration) @@ -97,11 +91,6 @@ void WireguardProtocol::readWireguardConfiguration(const QJsonObject &configurat } -//bool WireguardProtocol::openVpnProcessIsRunning() const -//{ -// return Utils::processIsRunning("openvpn"); -//} - QString WireguardProtocol::configPath() const { return m_configFileName; @@ -119,15 +108,12 @@ void WireguardProtocol::updateRouteGateway(QString line) ErrorCode WireguardProtocol::start() { - //qDebug() << "WireguardProtocol::start() 1"; - #ifndef Q_OS_IOS if (!m_isConfigLoaded) { setLastError(ErrorCode::ConfigMissing); return lastError(); } - //qDebug() << "Start Wireguard connection"; WireguardProtocol::stop(); if (!QFileInfo::exists(Utils::wireguardExecPath())) { @@ -145,7 +131,6 @@ ErrorCode WireguardProtocol::start() m_wireguardStartProcess = IpcClient::CreatePrivilegedProcess(); if (!m_wireguardStartProcess) { - //qWarning() << "IpcProcess replica is not created!"; setLastError(ErrorCode::AmneziaServiceConnectionFailed); return ErrorCode::AmneziaServiceConnectionFailed; } @@ -199,8 +184,6 @@ ErrorCode WireguardProtocol::start() m_wireguardStartProcess->start(); m_wireguardStartProcess->waitForFinished(10000); - //qDebug() << "WireguardProtocol::start() 2"; - return ErrorCode::NoError; #else return ErrorCode::NotImplementedError; diff --git a/ipc/ipcserverprocess.cpp b/ipc/ipcserverprocess.cpp index 92fdc4936..b8f085c30 100644 --- a/ipc/ipcserverprocess.cpp +++ b/ipc/ipcserverprocess.cpp @@ -20,18 +20,6 @@ IpcServerProcess::IpcServerProcess(QObject *parent) : qDebug() << "IpcServerProcess errorOccurred " << error; }); -// connect(m_process.data(), &QProcess::readyReadStandardError, this, [this](){ -// qDebug() << "IpcServerProcess StandardError " << m_process->readAllStandardError(); - -// }); -// connect(m_process.data(), &QProcess::readyReadStandardOutput, this, [this](){ -// qDebug() << "IpcServerProcess StandardOutput " << m_process->readAllStandardOutput(); -// }); - -// connect(m_process.data(), &QProcess::readyRead, this, [this](){ -// qDebug() << "IpcServerProcess StandardOutput " << m_process->readAll(); -// }); - } IpcServerProcess::~IpcServerProcess() @@ -39,14 +27,6 @@ IpcServerProcess::~IpcServerProcess() qDebug() << "IpcServerProcess::~IpcServerProcess"; } -//void IpcServerProcess::start(const QString &program, const QStringList &arguments) -//{ -// m_process->start(program, arguments); -// qDebug() << "IpcServerProcess started, " << arguments; - -// m_process->waitForStarted(); -//} - void IpcServerProcess::start() { if (m_process->program().isEmpty()) { diff --git a/ipc/ipcserverprocess.h b/ipc/ipcserverprocess.h index ff2c9434d..b427d639d 100644 --- a/ipc/ipcserverprocess.h +++ b/ipc/ipcserverprocess.h @@ -13,7 +13,6 @@ public: explicit IpcServerProcess(QObject *parent = nullptr); virtual ~IpcServerProcess(); - //void start(const QString &program, const QStringList &arguments) override; void start() override; void close() override; From 3a5a7bf674bd723fd788353d8bcb28e6125a8bcb Mon Sep 17 00:00:00 2001 From: pokamest Date: Mon, 29 Aug 2022 01:32:42 +0300 Subject: [PATCH 26/52] Check openvpn config for scripts QML refactoring --- client/amnezia_application.cpp | 27 ++-- client/amnezia_application.h | 5 + client/client.pro | 2 + client/protocols/openvpnprotocol.cpp | 1 - client/protocols/wireguardprotocol.cpp | 1 - client/resources.qrc | 1 + client/ui/pages.h | 2 +- .../ui/pages_logic/GeneralSettingsLogic.cpp | 2 +- client/ui/pages_logic/QrDecoderLogic.cpp | 4 +- .../ui/pages_logic/ServerContainersLogic.cpp | 8 +- client/ui/pages_logic/ServerSettingsLogic.cpp | 6 +- client/ui/pages_logic/SitesLogic.cpp | 2 +- client/ui/pages_logic/StartPageLogic.cpp | 16 +- client/ui/pages_logic/ViewConfigLogic.cpp | 67 ++++++++ client/ui/pages_logic/ViewConfigLogic.h | 47 ++++++ client/ui/qml/Pages/PageShareConnection.qml | 4 +- client/ui/qml/Pages/PageViewConfig.qml | 148 ++++++++++++++++++ client/ui/uilogic.cpp | 86 +++++----- client/ui/uilogic.h | 59 +++---- 19 files changed, 367 insertions(+), 121 deletions(-) create mode 100644 client/ui/pages_logic/ViewConfigLogic.cpp create mode 100644 client/ui/pages_logic/ViewConfigLogic.h create mode 100644 client/ui/qml/Pages/PageViewConfig.qml diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index 8ceff142c..4b8c7a4ea 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -79,26 +79,10 @@ void AmneziaApplication::init() }, Qt::QueuedConnection); m_engine->rootContext()->setContextProperty("Debug", &Debug::Instance()); - - m_engine->rootContext()->setContextProperty("UiLogic", m_uiLogic); - - m_engine->rootContext()->setContextProperty("AppSettingsLogic", m_uiLogic->appSettingsLogic()); - m_engine->rootContext()->setContextProperty("GeneralSettingsLogic", m_uiLogic->generalSettingsLogic()); - m_engine->rootContext()->setContextProperty("NetworkSettingsLogic", m_uiLogic->networkSettingsLogic()); - m_engine->rootContext()->setContextProperty("NewServerProtocolsLogic", m_uiLogic->newServerProtocolsLogic()); - m_engine->rootContext()->setContextProperty("QrDecoderLogic", m_uiLogic->qrDecoderLogic()); - m_engine->rootContext()->setContextProperty("ServerConfiguringProgressLogic", m_uiLogic->serverConfiguringProgressLogic()); - m_engine->rootContext()->setContextProperty("ServerListLogic", m_uiLogic->serverListLogic()); - m_engine->rootContext()->setContextProperty("ServerSettingsLogic", m_uiLogic->serverSettingsLogic()); - m_engine->rootContext()->setContextProperty("ServerContainersLogic", m_uiLogic->serverprotocolsLogic()); - m_engine->rootContext()->setContextProperty("ShareConnectionLogic", m_uiLogic->shareConnectionLogic()); - m_engine->rootContext()->setContextProperty("SitesLogic", m_uiLogic->sitesLogic()); - m_engine->rootContext()->setContextProperty("StartPageLogic", m_uiLogic->startPageLogic()); - m_engine->rootContext()->setContextProperty("VpnLogic", m_uiLogic->vpnLogic()); - m_engine->rootContext()->setContextProperty("WizardLogic", m_uiLogic->wizardLogic()); + m_uiLogic->registerPagesLogic(); #if defined(Q_OS_IOS) - setStartPageLogic(m_uiLogic->startPageLogic()); + setStartPageLogic(m_uiLogic->pageLogic()); #endif m_engine->load(url); @@ -130,6 +114,7 @@ void AmneziaApplication::init() }); } #endif + } void AmneziaApplication::registerTypes() @@ -207,3 +192,9 @@ void AmneziaApplication::parseCommands() exec(); } } + +QQmlApplicationEngine *AmneziaApplication::qmlEngine() const +{ + return m_engine; +} + diff --git a/client/amnezia_application.h b/client/amnezia_application.h index 6d0ef5d2d..c5531aa14 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -13,6 +13,9 @@ #include "ui/uilogic.h" #include "configurators/vpn_configurator.h" +#define amnApp (static_cast(QCoreApplication::instance())) + + #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) #define AMNEZIA_BASE_CLASS QApplication #else @@ -39,6 +42,8 @@ public: void loadTranslator(); void parseCommands(); + QQmlApplicationEngine *qmlEngine() const; + private: QQmlApplicationEngine *m_engine; UiLogic *m_uiLogic; diff --git a/client/client.pro b/client/client.pro index 3ea957995..5b6d3f8f0 100644 --- a/client/client.pro +++ b/client/client.pro @@ -64,6 +64,7 @@ HEADERS += \ ui/pages_logic/ShareConnectionLogic.h \ ui/pages_logic/SitesLogic.h \ ui/pages_logic/StartPageLogic.h \ + ui/pages_logic/ViewConfigLogic.h \ ui/pages_logic/VpnLogic.h \ ui/pages_logic/WizardLogic.h \ ui/pages_logic/protocols/CloakLogic.h \ @@ -124,6 +125,7 @@ SOURCES += \ ui/pages_logic/ShareConnectionLogic.cpp \ ui/pages_logic/SitesLogic.cpp \ ui/pages_logic/StartPageLogic.cpp \ + ui/pages_logic/ViewConfigLogic.cpp \ ui/pages_logic/VpnLogic.cpp \ ui/pages_logic/WizardLogic.cpp \ ui/pages_logic/protocols/CloakLogic.cpp \ diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index 209757308..a62b599cd 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include "debug.h" diff --git a/client/protocols/wireguardprotocol.cpp b/client/protocols/wireguardprotocol.cpp index 456998ff7..e6ccef6c8 100644 --- a/client/protocols/wireguardprotocol.cpp +++ b/client/protocols/wireguardprotocol.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include diff --git a/client/resources.qrc b/client/resources.qrc index a48a98f78..a7e67e398 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -159,5 +159,6 @@ ui/qml/Controls/SvgButtonType.qml ui/qml/Pages/PageQrDecoderIos.qml server_scripts/website_tor/Dockerfile + ui/qml/Pages/PageViewConfig.qml diff --git a/client/ui/pages.h b/client/ui/pages.h index d74c64a68..69f417fac 100644 --- a/client/ui/pages.h +++ b/client/ui/pages.h @@ -24,7 +24,7 @@ enum class Page {Start = 0, NewServer, NewServerProtocols, Vpn, Wizard, WizardLow, WizardMedium, WizardHigh, WizardVpnMode, ServerConfiguringProgress, GeneralSettings, AppSettings, NetworkSettings, ServerSettings, ServerContainers, ServersList, ShareConnection, Sites, - ProtocolSettings, ProtocolShare, QrDecoder, QrDecoderIos, About}; + ProtocolSettings, ProtocolShare, QrDecoder, QrDecoderIos, About, ViewConfig}; Q_ENUM_NS(Page) static void declareQmlPageEnum() { diff --git a/client/ui/pages_logic/GeneralSettingsLogic.cpp b/client/ui/pages_logic/GeneralSettingsLogic.cpp index 344fd5fad..a71a7f91b 100644 --- a/client/ui/pages_logic/GeneralSettingsLogic.cpp +++ b/client/ui/pages_logic/GeneralSettingsLogic.cpp @@ -34,6 +34,6 @@ void GeneralSettingsLogic::onPushButtonGeneralSettingsShareConnectionClicked() qobject_cast(uiLogic()->protocolsModel())->setSelectedServerIndex(uiLogic()->selectedServerIndex); qobject_cast(uiLogic()->protocolsModel())->setSelectedDockerContainer(uiLogic()->selectedDockerContainer); - uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); + uiLogic()->pageLogic()->updateSharingPage(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); emit uiLogic()->goToPage(Page::ShareConnection); } diff --git a/client/ui/pages_logic/QrDecoderLogic.cpp b/client/ui/pages_logic/QrDecoderLogic.cpp index 01c607f71..0c24ca1cc 100644 --- a/client/ui/pages_logic/QrDecoderLogic.cpp +++ b/client/ui/pages_logic/QrDecoderLogic.cpp @@ -54,7 +54,7 @@ void QrDecoderLogic::onDetectedQrCode(const QString &code) data.append(m_chunks.value(i)); } - bool ok = uiLogic()->startPageLogic()->importConnectionFromQr(data); + bool ok = uiLogic()->pageLogic()->importConnectionFromQr(data); if (ok) { set_detectingEnabled(false); emit stopDecode(); @@ -67,7 +67,7 @@ void QrDecoderLogic::onDetectedQrCode(const QString &code) } } else { - bool ok = uiLogic()->startPageLogic()->importConnectionFromQr(ba); + bool ok = uiLogic()->pageLogic()->importConnectionFromQr(ba); if (ok) { set_detectingEnabled(false); emit stopDecode(); diff --git a/client/ui/pages_logic/ServerContainersLogic.cpp b/client/ui/pages_logic/ServerContainersLogic.cpp index 6e021a45c..27f865b5d 100644 --- a/client/ui/pages_logic/ServerContainersLogic.cpp +++ b/client/ui/pages_logic/ServerContainersLogic.cpp @@ -54,13 +54,13 @@ void ServerContainersLogic::onPushButtonDefaultClicked(DockerContainer c) if (!uiLogic()->m_vpnConnection) return; if (!uiLogic()->m_vpnConnection->isConnected()) return; - uiLogic()->vpnLogic()->onDisconnect(); - uiLogic()->vpnLogic()->onConnect(); + uiLogic()->pageLogic()->onDisconnect(); + uiLogic()->pageLogic()->onConnect(); } void ServerContainersLogic::onPushButtonShareClicked(DockerContainer c) { - uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, c); + uiLogic()->pageLogic()->updateSharingPage(uiLogic()->selectedServerIndex, c); emit uiLogic()->goToPage(Page::ShareConnection); } @@ -86,7 +86,7 @@ void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int p emit uiLogic()->goToPage(Page::ServerConfiguringProgress); qApp->processEvents(); - ErrorCode e = uiLogic()->serverConfiguringProgressLogic()->doInstallAction([this, c, &config](){ + ErrorCode e = uiLogic()->pageLogic()->doInstallAction([this, c, &config](){ return m_serverController->setupContainer(m_settings->serverCredentials(uiLogic()->selectedServerIndex), c, config); }); diff --git a/client/ui/pages_logic/ServerSettingsLogic.cpp b/client/ui/pages_logic/ServerSettingsLogic.cpp index ddf9504e8..bd954c882 100644 --- a/client/ui/pages_logic/ServerSettingsLogic.cpp +++ b/client/ui/pages_logic/ServerSettingsLogic.cpp @@ -49,7 +49,7 @@ void ServerSettingsLogic::onPushButtonClearServer() set_pushButtonClearText(tr("Uninstalling Amnezia software...")); if (m_settings->defaultServerIndex() == uiLogic()->selectedServerIndex) { - uiLogic()->vpnLogic()->onDisconnect(); + uiLogic()->pageLogic()->onDisconnect(); } ErrorCode e = m_serverController->removeAllContainers(m_settings->serverCredentials(uiLogic()->selectedServerIndex)); @@ -76,7 +76,7 @@ void ServerSettingsLogic::onPushButtonClearServer() void ServerSettingsLogic::onPushButtonForgetServer() { if (m_settings->defaultServerIndex() == uiLogic()->selectedServerIndex && uiLogic()->m_vpnConnection->isConnected()) { - uiLogic()->vpnLogic()->onDisconnect(); + uiLogic()->pageLogic()->onDisconnect(); } m_settings->removeServer(uiLogic()->selectedServerIndex); @@ -128,6 +128,6 @@ void ServerSettingsLogic::onLineEditDescriptionEditingFinished() void ServerSettingsLogic::onPushButtonShareFullClicked() { - uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, DockerContainer::None); + uiLogic()->pageLogic()->updateSharingPage(uiLogic()->selectedServerIndex, DockerContainer::None); emit uiLogic()->goToShareProtocolPage(Proto::Any); } diff --git a/client/ui/pages_logic/SitesLogic.cpp b/client/ui/pages_logic/SitesLogic.cpp index e9966bfaf..b31018c01 100644 --- a/client/ui/pages_logic/SitesLogic.cpp +++ b/client/ui/pages_logic/SitesLogic.cpp @@ -40,7 +40,7 @@ void SitesLogic::onUpdatePage() void SitesLogic::onPushButtonAddCustomSitesClicked() { - if (uiLogic()->vpnLogic()->radioButtonVpnModeAllSitesChecked()) { + if (uiLogic()->pageLogic()->radioButtonVpnModeAllSitesChecked()) { return; } Settings::RouteMode mode = m_settings->routeMode(); diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index 4fb00f6f6..de3173b59 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -1,4 +1,6 @@ #include "StartPageLogic.h" +#include "ViewConfigLogic.h" + #include "core/errorstrings.h" #include "configurators/ssh_configurator.h" #include "configurators/vpn_configurator.h" @@ -17,13 +19,7 @@ StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent): m_pushButtonConnectEnabled{true}, m_pushButtonConnectText{tr("Connect")}, m_pushButtonConnectKeyChecked{false}, - m_lineEditStartExistingCodeText{}, - m_textEditSshKeyText{}, - m_lineEditIpText{}, - m_lineEditPasswordText{}, - m_lineEditLoginText{}, m_labelWaitInfoVisible{true}, - m_labelWaitInfoText{}, m_pushButtonBackFromStartVisible{true}, m_ipAddressPortRegex{Utils::ipAddressPortRegExp()} { @@ -150,11 +146,9 @@ bool StartPageLogic::importConnection(const QJsonObject &profile) credentials.password = profile.value(config_key::password).toString(); if (credentials.isValid() || profile.contains(config_key::containers)) { - m_settings->addServer(profile); - m_settings->setDefaultServer(m_settings->serversCount() - 1); - - emit uiLogic()->goToPage(Page::Vpn); - emit uiLogic()->setStartPage(Page::Vpn); + // check config + uiLogic()->pageLogic()->set_configJson(profile); + emit uiLogic()->goToPage(Page::ViewConfig); } else { qDebug() << "Failed to import profile"; diff --git a/client/ui/pages_logic/ViewConfigLogic.cpp b/client/ui/pages_logic/ViewConfigLogic.cpp new file mode 100644 index 000000000..17d8814ef --- /dev/null +++ b/client/ui/pages_logic/ViewConfigLogic.cpp @@ -0,0 +1,67 @@ +#include "ViewConfigLogic.h" +#include "core/errorstrings.h" +#include "../uilogic.h" + + +ViewConfigLogic::ViewConfigLogic(UiLogic *logic, QObject *parent): + PageLogicBase(logic, parent) +{ + +} + +void ViewConfigLogic::onUpdatePage() +{ + set_configText(QJsonDocument(configJson()).toJson()); + + m_openVpnLastConfigs = m_openVpnMalStrings = + "
"; + + m_warningStringNumber = 3; + m_warningActive = false; + + const QJsonArray &containers = configJson()[config_key::containers].toArray(); + int i = 0; + for (const QJsonValue &v: containers) { + QString cfg_json = v.toObject()[ProtocolProps::protoToString(Proto::OpenVpn)] + .toObject()[config_key::last_config].toString(); + + QString openvpn_cfg = QJsonDocument::fromJson(cfg_json.toUtf8()).object()[config_key::config] + .toString(); + + openvpn_cfg.replace("\r", ""); + + QStringList lines = openvpn_cfg.split("\n"); + for (const QString &l: lines) { + i++; + QRegularExpressionMatch match = m_re.match(l); + if (dangerousTags.contains(match.captured(0))) { + QString t = QString("

%1").arg(l); + m_openVpnLastConfigs.append(t + "\n"); + m_openVpnMalStrings.append(t); + if (m_warningStringNumber == 3) m_warningStringNumber = i - 3; + m_warningActive = true; + qDebug() << "ViewConfigLogic : malicious scripts warning:" << l; + } + else { + m_openVpnLastConfigs.append("

" + l + " \n"); + } + } + } + + emit openVpnLastConfigsChanged(m_openVpnLastConfigs); + emit openVpnMalStringsChanged(m_openVpnMalStrings); + emit warningStringNumberChanged(m_warningStringNumber); + emit warningActiveChanged(m_warningActive); +} + +void ViewConfigLogic::importConfig() +{ + m_settings->addServer(configJson()); + m_settings->setDefaultServer(m_settings->serversCount() - 1); + + emit uiLogic()->goToPage(Page::Vpn); + emit uiLogic()->setStartPage(Page::Vpn); +} + diff --git a/client/ui/pages_logic/ViewConfigLogic.h b/client/ui/pages_logic/ViewConfigLogic.h new file mode 100644 index 000000000..4713158ec --- /dev/null +++ b/client/ui/pages_logic/ViewConfigLogic.h @@ -0,0 +1,47 @@ +#ifndef VIEW_CONFIG_LOGIC_H +#define VIEW_CONFIG_LOGIC_H + +#include "PageLogicBase.h" + +#include + +class UiLogic; + +class ViewConfigLogic : public PageLogicBase +{ + Q_OBJECT + + AUTO_PROPERTY(QString, configText) + AUTO_PROPERTY(QString, openVpnLastConfigs) + AUTO_PROPERTY(QString, openVpnMalStrings) + AUTO_PROPERTY(QJsonObject, configJson) + AUTO_PROPERTY(int, warningStringNumber) + AUTO_PROPERTY(bool, warningActive) + +public: + Q_INVOKABLE void onUpdatePage() override; + Q_INVOKABLE void importConfig(); + + +public: + explicit ViewConfigLogic(UiLogic *uiLogic, QObject *parent = nullptr); + ~ViewConfigLogic() = default; + +private: + QRegularExpression m_re {"(\\w+-\\w+|\\w+)"}; + + // https://github.com/OpenVPN/openvpn/blob/master/doc/man-sections/script-options.rst + QStringList dangerousTags { + "up", + "tls-verify", + "ipchange", + "client-connect", + "route-up", + "route-pre-down", + "client-disconnect", + "down", + "learn-address", + "auth-user-pass-verify" + }; +}; +#endif // VIEW_CONFIG_LOGIC_H diff --git a/client/ui/qml/Pages/PageShareConnection.qml b/client/ui/qml/Pages/PageShareConnection.qml index c124c9699..9bd84bdd7 100644 --- a/client/ui/qml/Pages/PageShareConnection.qml +++ b/client/ui/qml/Pages/PageShareConnection.qml @@ -59,7 +59,7 @@ PageBase { text: qsTr("Share for Amnezia") height: 40 width: tb_c.width - 10 - onClicked: UiLogic.onGotoShareProtocolPage(ProtocolEnum.Any) + onClicked: UiLogic.goToShareProtocolPage(ProtocolEnum.Any) } ListView { @@ -82,7 +82,7 @@ PageBase { text: qsTr("Share for ") + name_role height: 40 width: tb_c.width - 10 - onClicked: UiLogic.onGotoShareProtocolPage(proxyProtocolsModel.mapToSource(index)) + onClicked: UiLogic.goToShareProtocolPage(proxyProtocolsModel.mapToSource(index)) } } } diff --git a/client/ui/qml/Pages/PageViewConfig.qml b/client/ui/qml/Pages/PageViewConfig.qml new file mode 100644 index 000000000..acefb9b3b --- /dev/null +++ b/client/ui/qml/Pages/PageViewConfig.qml @@ -0,0 +1,148 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.15 +import PageEnum 1.0 +import "./" +import "../Controls" +import "../Config" + +PageBase { + id: root + page: PageEnum.ViewConfig + logic: ViewConfigLogic + + readonly property double rowHeight: ta_last_config.contentHeight / ta_last_config.textArea.lineCount + + BackButton {} + + Caption { + id: caption + text: qsTr("Check config") + } + + Flickable { + id: fl + width: root.width + anchors.top: caption.bottom + anchors.topMargin: 20 + anchors.bottom: root.bottom + anchors.bottomMargin: 20 + anchors.left: root.left + anchors.leftMargin: 30 + anchors.right: root.right + anchors.rightMargin: 30 + + contentHeight: content.height + clip: true + + ColumnLayout { + id: content + enabled: logic.pageEnabled + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + TextAreaType { + id: ta_config + + Layout.topMargin: 5 + Layout.bottomMargin: 20 + Layout.fillWidth: true + Layout.leftMargin: 1 + Layout.rightMargin: 1 + Layout.preferredHeight: ViewConfigLogic.warningActive ? 250 : fl.height - 70 + flickableDirection: Flickable.AutoFlickIfNeeded + + textArea.readOnly: true + textArea.text: logic.configText + } + + LabelType { + id: lb_att + visible: ViewConfigLogic.warningActive + text: qsTr("Attention! +The config above contains cached OpenVPN connection profile. +AmneziaVPN detected this profile may contain malicious scripts. Please, carefully review the config and import this config only if you completely trust it.") + Layout.fillWidth: true + } + + LabelType { + visible: ViewConfigLogic.warningActive + text: qsTr("Suspicious string:") + Layout.fillWidth: true + } + + TextAreaType { + id: ta_mal + visible: ViewConfigLogic.warningActive + + Layout.topMargin: 5 + Layout.bottomMargin: 20 + Layout.fillWidth: true + Layout.leftMargin: 1 + Layout.rightMargin: 1 + Layout.preferredHeight: 60 + flickableDirection: Flickable.AutoFlickIfNeeded + + textArea.readOnly: true + textArea.text: logic.openVpnMalStrings + textArea.textFormat: TextEdit.RichText + } + + LabelType { + visible: ViewConfigLogic.warningActive + text: qsTr("Cached connection profile:") + Layout.fillWidth: true + } + + TextAreaType { + id: ta_last_config + visible: ViewConfigLogic.warningActive + + Layout.topMargin: 5 + Layout.bottomMargin: 20 + Layout.fillWidth: true + Layout.leftMargin: 1 + Layout.rightMargin: 1 + Layout.preferredHeight: 350 + flickableDirection: Flickable.AutoFlickIfNeeded + + textArea.readOnly: true + textArea.text: logic.openVpnLastConfigs + textArea.textFormat: TextEdit.RichText + + Connections { + target: logic + function onWarningStringNumberChanged(n) { + ta_last_config.contentY = rowHeight * n - ta_last_config.height / 2 + } + } + } + + RowLayout { + id: btns_row + + BasicButtonType { + Layout.preferredWidth: (content.width - parent.spacing) /2 + Layout.preferredHeight: 41 + font.pixelSize: btn_import.font.pixelSize + text: qsTr("Cancel") + onClicked: { + UiLogic.closePage() + } + } + + BlueButtonType { + id: btn_import + Layout.preferredWidth: (content.width - parent.spacing) /2 + Layout.preferredHeight: 41 + text: qsTr("Import config") + onClicked: { + logic.importConfig() + } + } + } + } + } + + } diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index f3d45577a..e1468da76 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -16,8 +15,10 @@ #include #include #include -#include #include +#include + +#include "amnezia_application.h" #include "configurators/cloak_configurator.h" #include "configurators/vpn_configurator.h" @@ -62,6 +63,7 @@ #include "pages_logic/ShareConnectionLogic.h" #include "pages_logic/SitesLogic.h" #include "pages_logic/StartPageLogic.h" +#include "pages_logic/ViewConfigLogic.h" #include "pages_logic/VpnLogic.h" #include "pages_logic/WizardLogic.h" @@ -88,20 +90,6 @@ UiLogic::UiLogic(std::shared_ptr settings, std::shared_ptrmoveToThread(&m_vpnConnectionThread); m_vpnConnectionThread.start(); - m_appSettingsLogic = new AppSettingsLogic(this); - m_generalSettingsLogic = new GeneralSettingsLogic(this); - m_networkSettingsLogic = new NetworkSettingsLogic(this); - m_newServerProtocolsLogic = new NewServerProtocolsLogic(this); - m_qrDecoderLogic = new QrDecoderLogic(this); - m_serverConfiguringProgressLogic = new ServerConfiguringProgressLogic(this); - m_serverListLogic = new ServerListLogic(this); - m_serverSettingsLogic = new ServerSettingsLogic(this); - m_serverprotocolsLogic = new ServerContainersLogic(this); - m_shareConnectionLogic = new ShareConnectionLogic(this); - m_sitesLogic = new SitesLogic(this); - m_startPageLogic = new StartPageLogic(this); - m_vpnLogic = new VpnLogic(this); - m_wizardLogic = new WizardLogic(this); m_protocolLogicMap.insert(Proto::OpenVpn, new OpenVpnLogic(this)); m_protocolLogicMap.insert(Proto::ShadowSocks, new ShadowSocksLogic(this)); @@ -143,7 +131,7 @@ void UiLogic::initalizeUiLogic() #ifdef Q_OS_ANDROID connect(AndroidController::instance(), &AndroidController::initialized, [this](bool status, bool connected, const QDateTime& connectionDate) { if (connected) { - vpnLogic()->onConnectionStateChanged(VpnProtocol::Connected); + pageLogic()->onConnectionStateChanged(VpnProtocol::Connected); } }); if (!AndroidController::instance()->initialize()) { @@ -157,8 +145,8 @@ void UiLogic::initalizeUiLogic() connect(m_vpnConnection, &VpnConnection::connectionStateChanged, m_notificationHandler, &NotificationHandler::setConnectionState); connect(m_notificationHandler, &NotificationHandler::raiseRequested, this, &UiLogic::raise); - connect(m_notificationHandler, &NotificationHandler::connectRequested, vpnLogic(), &VpnLogic::onConnect); - connect(m_notificationHandler, &NotificationHandler::disconnectRequested, vpnLogic(), &VpnLogic::onDisconnect); + connect(m_notificationHandler, &NotificationHandler::connectRequested, pageLogic(), &VpnLogic::onConnect); + connect(m_notificationHandler, &NotificationHandler::disconnectRequested, pageLogic(), &VpnLogic::onDisconnect); if (m_settings->serversCount() > 0) { if (m_settings->defaultServerIndex() < 0) m_settings->setDefaultServer(0); @@ -190,21 +178,7 @@ void UiLogic::showOnStartup() void UiLogic::onUpdateAllPages() { - for (PageLogicBase *logic : { - (PageLogicBase *) m_appSettingsLogic, - (PageLogicBase *) m_generalSettingsLogic, - (PageLogicBase *) m_networkSettingsLogic, - (PageLogicBase *) m_serverConfiguringProgressLogic, - (PageLogicBase *) m_newServerProtocolsLogic, - (PageLogicBase *) m_serverListLogic, - (PageLogicBase *) m_serverSettingsLogic, - (PageLogicBase *) m_serverprotocolsLogic, - (PageLogicBase *) m_shareConnectionLogic, - (PageLogicBase *) m_sitesLogic, - (PageLogicBase *) m_startPageLogic, - (PageLogicBase *) m_vpnLogic, - (PageLogicBase *) m_wizardLogic - }) { + for (auto logic : m_logicMap) { logic->onUpdatePage(); } } @@ -332,34 +306,34 @@ void UiLogic::installServer(QMap &containers) PageFunc page_new_server_configuring; page_new_server_configuring.setEnabledFunc = [this] (bool enabled) -> void { - serverConfiguringProgressLogic()->set_pageEnabled(enabled); + pageLogic()->set_pageEnabled(enabled); }; ButtonFunc no_button; LabelFunc label_new_server_configuring_wait_info; label_new_server_configuring_wait_info.setTextFunc = [this] (const QString& text) -> void { - serverConfiguringProgressLogic()->set_labelWaitInfoText(text); + pageLogic()->set_labelWaitInfoText(text); }; label_new_server_configuring_wait_info.setVisibleFunc = [this] (bool visible) ->void { - serverConfiguringProgressLogic()->set_labelWaitInfoVisible(visible); + pageLogic()->set_labelWaitInfoVisible(visible); }; ProgressFunc progressBar_new_server_configuring; progressBar_new_server_configuring.setVisibleFunc = [this] (bool visible) ->void { - serverConfiguringProgressLogic()->set_progressBarVisible(visible); + pageLogic()->set_progressBarVisible(visible); }; progressBar_new_server_configuring.setValueFunc = [this] (int value) ->void { - serverConfiguringProgressLogic()->set_progressBarValue(value); + pageLogic()->set_progressBarValue(value); }; progressBar_new_server_configuring.getValueFunc = [this] (void) -> int { - return serverConfiguringProgressLogic()->progressBarValue(); + return pageLogic()->progressBarValue(); }; progressBar_new_server_configuring.getMaximiumFunc = [this] (void) -> int { - return serverConfiguringProgressLogic()->progressBarMaximium(); + return pageLogic()->progressBarMaximium(); }; progressBar_new_server_configuring.setTextVisibleFunc = [this] (bool visible) ->void { - serverConfiguringProgressLogic()->set_progressBarTextVisible(visible); + pageLogic()->set_progressBarTextVisible(visible); }; progressBar_new_server_configuring.setTextFunc = [this] (const QString& text) ->void { - serverConfiguringProgressLogic()->set_progressBarText(text); + pageLogic()->set_progressBarText(text); }; bool ok = installContainers(installCredentials, containers, page_new_server_configuring, @@ -595,6 +569,11 @@ NotificationHandler *UiLogic::notificationHandler() const return m_notificationHandler; } +void UiLogic::setQmlContextProperty(PageLogicBase *logic) +{ + amnApp->qmlEngine()->rootContext()->setContextProperty(logic->metaObject()->className(), logic); +} + PageEnumNS::Page UiLogic::currentPage() { return static_cast(currentPageValue()); @@ -677,3 +656,24 @@ void UiLogic::shareTempFile(const QString &suggestedName, QString ext, const QSt filesToSend.append(fileName); MobileUtils::shareText(filesToSend); } + +void UiLogic::registerPagesLogic() +{ + amnApp->qmlEngine()->rootContext()->setContextProperty("UiLogic", this); + + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); + registerPageLogic(); +} diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index ecf244212..b5b6092b7 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -7,6 +7,10 @@ #include #include +#include +#include +#include + #include "property_helper.h" #include "pages.h" #include "protocols/vpnprotocol.h" @@ -21,6 +25,8 @@ class Settings; class VpnConfigurator; class ServerController; +class PageLogicBase; + class AppSettingsLogic; class GeneralSettingsLogic; class NetworkSettingsLogic; @@ -33,6 +39,7 @@ class ServerContainersLogic; class ShareConnectionLogic; class SitesLogic; class StartPageLogic; +class ViewConfigLogic; class VpnLogic; class WizardLogic; @@ -77,6 +84,7 @@ public: friend class ShareConnectionLogic; friend class SitesLogic; friend class StartPageLogic; + friend class ViewConfigLogic; friend class VpnLogic; friend class WizardLogic; @@ -96,10 +104,6 @@ public: Q_INVOKABLE QString containerName(int container); Q_INVOKABLE QString containerDesc(int container); - Q_INVOKABLE void onGotoPage(PageEnumNS::Page p, bool reset = true, bool slide = true) { emit goToPage(p, reset, slide); } - Q_INVOKABLE void onGotoProtocolPage(Proto p, bool reset = true, bool slide = true) { emit goToProtocolPage(p, reset, slide); } - Q_INVOKABLE void onGotoShareProtocolPage(Proto p, bool reset = true, bool slide = true) { emit goToShareProtocolPage(p, reset, slide); } - Q_INVOKABLE void onGotoCurrentProtocolsPage(); Q_INVOKABLE void keyPressEvent(Qt::Key key); @@ -166,21 +170,6 @@ private: public: - AppSettingsLogic *appSettingsLogic() { return m_appSettingsLogic; } - GeneralSettingsLogic *generalSettingsLogic() { return m_generalSettingsLogic; } - NetworkSettingsLogic *networkSettingsLogic() { return m_networkSettingsLogic; } - NewServerProtocolsLogic *newServerProtocolsLogic() { return m_newServerProtocolsLogic; } - QrDecoderLogic *qrDecoderLogic() { return m_qrDecoderLogic; } - ServerConfiguringProgressLogic *serverConfiguringProgressLogic() { return m_serverConfiguringProgressLogic; } - ServerListLogic *serverListLogic() { return m_serverListLogic; } - ServerSettingsLogic *serverSettingsLogic() { return m_serverSettingsLogic; } - ServerContainersLogic *serverprotocolsLogic() { return m_serverprotocolsLogic; } - ShareConnectionLogic *shareConnectionLogic() { return m_shareConnectionLogic; } - SitesLogic *sitesLogic() { return m_sitesLogic; } - StartPageLogic *startPageLogic() { return m_startPageLogic; } - VpnLogic *vpnLogic() { return m_vpnLogic; } - WizardLogic *wizardLogic() { return m_wizardLogic; } - Q_INVOKABLE PageProtocolLogicBase *protocolLogic(Proto p); QObject *qmlRoot() const; @@ -188,23 +177,27 @@ public: NotificationHandler *notificationHandler() const; + void setQmlContextProperty(PageLogicBase *logic); + void registerPagesLogic(); + + template + void registerPageLogic() + { + T* logic = new T(this); + m_logicMap[std::type_index(typeid(T))] = logic; + setQmlContextProperty(logic); + } + + template + T* pageLogic() + { + return static_cast(m_logicMap.value(std::type_index(typeid(T)))); + } + private: QObject *m_qmlRoot{nullptr}; - AppSettingsLogic *m_appSettingsLogic; - GeneralSettingsLogic *m_generalSettingsLogic; - NetworkSettingsLogic *m_networkSettingsLogic; - NewServerProtocolsLogic *m_newServerProtocolsLogic; - QrDecoderLogic *m_qrDecoderLogic; - ServerConfiguringProgressLogic *m_serverConfiguringProgressLogic; - ServerListLogic *m_serverListLogic; - ServerSettingsLogic *m_serverSettingsLogic; - ServerContainersLogic *m_serverprotocolsLogic; - ShareConnectionLogic *m_shareConnectionLogic; - SitesLogic *m_sitesLogic; - StartPageLogic *m_startPageLogic; - VpnLogic *m_vpnLogic; - WizardLogic *m_wizardLogic; + QMap m_logicMap; QMap m_protocolLogicMap; From 3316b73ab62a237d8761d9fdd9eeca7514958eb7 Mon Sep 17 00:00:00 2001 From: pokamest Date: Mon, 29 Aug 2022 02:58:23 +0300 Subject: [PATCH 27/52] Select random management port --- client/protocols/openvpnprotocol.cpp | 24 ++++++++++++++++++++++-- client/protocols/openvpnprotocol.h | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index a62b599cd..cfd13a7e3 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include "debug.h" #include "defines.h" @@ -121,6 +123,21 @@ void OpenVpnProtocol::sendManagementCommand(const QString& command) } } +uint OpenVpnProtocol::selectMgmtPort() +{ + + for (int i = 0; i < 100; ++i) { + quint32 port = QRandomGenerator::global()->generate(); + port = (double)(65000-15001) * port / UINT32_MAX + 15001; + + QTcpServer s; + bool ok = s.listen(QHostAddress::LocalHost, port); + if (ok) return port; + } + + return m_managementPort; +} + void OpenVpnProtocol::updateRouteGateway(QString line) { // TODO: fix for macos @@ -150,7 +167,10 @@ ErrorCode OpenVpnProtocol::start() // QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log"; // Utils::createEmptyFile(vpnLogFileNamePath); - if (!m_managementServer.start(m_managementHost, m_managementPort)) { + uint mgmtPort = selectMgmtPort(); + qDebug() << "OpenVpnProtocol::start mgmt port selected:" << mgmtPort; + + if (!m_managementServer.start(m_managementHost, mgmtPort)) { setLastError(ErrorCode::OpenVpnManagementServerError); return lastError(); } @@ -173,7 +193,7 @@ ErrorCode OpenVpnProtocol::start() } m_openVpnProcess->setProgram(PermittedProcess::OpenVPN); QStringList arguments({"--config" , configPath(), - "--management", m_managementHost, QString::number(m_managementPort), + "--management", m_managementHost, QString::number(mgmtPort), "--management-client"/*, "--log", vpnLogFileNamePath */ }); m_openVpnProcess->setArguments(arguments); diff --git a/client/protocols/openvpnprotocol.h b/client/protocols/openvpnprotocol.h index 1f3bbd409..ad80fe50e 100644 --- a/client/protocols/openvpnprotocol.h +++ b/client/protocols/openvpnprotocol.h @@ -46,6 +46,8 @@ private: QString m_configFileName; QTemporaryFile m_configFile; + uint selectMgmtPort(); + private: void updateRouteGateway(QString line); void updateVpnGateway(const QString &line); From a56fbeb6117a0eaa0226c241a94e14005c6288a2 Mon Sep 17 00:00:00 2001 From: Steve Tchatchouang <38782190+karolsteve@users.noreply.github.com> Date: Tue, 30 Aug 2022 13:58:03 +0100 Subject: [PATCH 28/52] Fix android build script Using correct qt binaries folder (gcc64 -> Android) --- deploy/build_android.sh | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/deploy/build_android.sh b/deploy/build_android.sh index 9afe49d3c..2b46b5fb5 100644 --- a/deploy/build_android.sh +++ b/deploy/build_android.sh @@ -3,7 +3,6 @@ echo "Build script started ..." set -o errexit -o nounset - # Hold on to current directory PROJECT_DIR=$(pwd) DEPLOY_DIR=$PROJECT_DIR/deploy @@ -30,7 +29,8 @@ QMAKE_STASH_FILE=$PROJECT_DIR/.qmake_stash # Seacrh Qt if [ -z "${QT_VERSION+x}" ]; then QT_VERSION=5.15.2; -QT_BIN_DIR=$HOME/Qt/$QT_VERSION/gcc_64/bin +QT_BIN_DIR=$HOME/Qt/$QT_VERSION/android/bin +#QT_BIN_DIR=$HOME/Qt/$QT_VERSION/gcc_64/bin fi echo "Using Qt in $QT_BIN_DIR" @@ -46,22 +46,23 @@ echo "Building App..." cd $BUILD_DIR $QT_BIN_DIR/qmake -r -spec android-clang CONFIG+=qtquickcompiler ANDROID_ABIS="armeabi-v7a arm64-v8a x86 x86_64" $PROJECT_DIR/AmneziaVPN.pro -$ANDROID_NDK_HOME/prebuilt/linux-x86_64/bin/make -j2 -$ANDROID_NDK_HOME/prebuilt/linux-x86_64/bin/make install INSTALL_ROOT=android - - - +echo "Executing make... may take long time" +$ANDROID_NDK_HOME/prebuilt/linux-x86_64/bin/make -j2 > /dev/null 2>/dev/null +echo "Make install..." +$ANDROID_NDK_HOME/prebuilt/linux-x86_64/bin/make install INSTALL_ROOT=android > /dev/null 2>/dev/null +echo "Build OK" # Build and run tests here -#echo "............Deploy.................." - -# TODO possible solution: https://github.com/mhoeher/opentodolist/blob/b8981852e500589851132a02c5a62af9b0ed592c/ci/android-cmake-build.sh -#$QT_BIN_DIR/androiddeployqt \ -# --output $OUT_APP_DIR \ -# --gradle \ -# --release \ -# --deployment bundled - -#cp $OUT_APP_DIR/build/outputs/apk/release/android-build-release-unsigned.apk \ -# OpenTodoList-${ANDROID_ABIS}-${OTL_VERSION}.apk +echo "............Deploy.................." +cd $OUT_APP_DIR +#--verbose removed +$QT_BIN_DIR/androiddeployqt \ + --output $OUT_APP_DIR/android \ + --gradle \ + --release \ + --input android-AmneziaVPN-deployment-settings.json + +echo "............Copy apk.................." +cp $OUT_APP_DIR/android/build/outputs/apk/release/android-release-unsigned.apk \ + $PROJECT_DIR/AmneziaVPN-release-unsigned.apk From f6d329ac48ac3db6504eeab0c60ced6084cce240 Mon Sep 17 00:00:00 2001 From: Steve Tchatchouang <38782190+karolsteve@users.noreply.github.com> Date: Tue, 30 Aug 2022 14:00:40 +0100 Subject: [PATCH 29/52] Fix Android job CI --- .travis.yml | 75 +++++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 43 deletions(-) diff --git a/.travis.yml b/.travis.yml index c5022b121..7113efad5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -209,65 +209,54 @@ jobs: # ------------------------------------------------------ - name: Android os: linux - language: android - dist: xenial - - addons: - apt: - packages: - - p7zip - - python3 - - python3-pip - - android: - components: - # Uncomment the lines below if you want to - # use the latest revision of Android SDK Tools - # - tools - # - platform-tools - - # The BuildTools version used by your project - - build-tools-30.0.2 - - # The SDK version used to compile your project - - android-30 - - # Additional components - - extra - - extra-google-google_play_services - - extra-google-m2repository - - extra-android-m2repository - + language: cpp + dist: focal env: - QT_VERSION=5.15.2 - QT_BIN_DIR=$HOME/Qt/$QT_VERSION/android/bin - USE_ANDROID_NDK_VERSION=21d - ANDROID_NDK_HOME=$HOME/NDK + - PROJ_ROOT=$(pwd) + - JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 install: - - | - if [ ! -f $QT_BIN_DIR/qmake ]; then \ - export PATH=$HOME/.local/bin:$PATH && \ - python3 -m pip install -U aqtinstall requests py7zr && \ - python3 -m pip show aqtinstall && \ - python3 -m aqt install-qt linux android $QT_VERSION android_armv7 -m all -O $HOME/Qt && \ - python3 -m aqt install-qt linux android $QT_VERSION android_arm64_v8a -m all -O $HOME/Qt && \ - python3 -m aqt install-qt linux android $QT_VERSION android_x86_64 -m all -O $HOME/Qt && \ - python3 -m aqt install-qt linux android $QT_VERSION android_x86 -m all -O $HOME/Qt ; \ + - echo "Installing Java 8" + - sudo apt-get install openjdk-8-jdk > /dev/null + - echo "QT bin install" && pwd + - if [ ! -f $QT_BIN_DIR/qmake ]; then + wget https://ondjoss.com/qt15_2_android_linux_x86_64.zip > /dev/null && + mkdir -p $HOME/Qt/$QT_VERSION && \ + unzip ./qt15_2_android_linux_x86_64.zip -d $HOME/Qt/$QT_VERSION > /dev/null ; fi - - | - export TERM=dumb && - curl -L https://dl.google.com/android/repository/android-ndk-r${USE_ANDROID_NDK_VERSION}-linux-x86_64.zip -O && + - echo "Download SDK" && pwd + - export ANDROID_HOME=`pwd`/sdk + - export LOCAL_ANDROID_HOME=`pwd`/sdk + - export ANDROID_SDK_ROOT=`pwd`/sdk + - export LOCAL_ANDROID_SDK_ROOT=`pwd`/sdk + - export ANDROID_API_VERSION=android-21 + - mkdir -p sdk && cd sdk && + wget https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip -qO sdk.zip > /dev/null || exit 1 + - ls -ll && unzip -q sdk.zip || exit 1 + - echo "Download all needed tools" && pwd && ls -ll && + yes | ./tools/bin/sdkmanager --licenses > /dev/null 2>/dev/null + - ./tools/bin/sdkmanager --install "cmdline-tools;latest" "platform-tools" "platforms;android-30" "build-tools;30.0.2" > /dev/null 2>/dev/null + - cd $PROJ_ROOT && echo "Download NDK" && pwd + - export TERM=dumb && + curl -L https://dl.google.com/android/repository/android-ndk-r${USE_ANDROID_NDK_VERSION}-linux-x86_64.zip -O && unzip ./android-ndk-r${USE_ANDROID_NDK_VERSION}-linux-x86_64.zip > /dev/null && - rm android-ndk-r${USE_ANDROID_NDK_VERSION}-linux-x86_64.zip && + rm android-ndk-r${USE_ANDROID_NDK_VERSION}-linux-x86_64.zip && export ANDROID_NDK_HOME=`pwd`/android-ndk-r${USE_ANDROID_NDK_VERSION} && + export ANDROID_NDK_ROOT=`pwd`/android-ndk-r${USE_ANDROID_NDK_VERSION} && export LOCAL_ANDROID_NDK_HOME="$ANDROID_NDK_HOME" && export LOCAL_ANDROID_NDK_HOST_PLATFORM="linux-x86_64" && export PATH=$PATH:${ANDROID_NDK_HOME} && + export ANDROID_NDK_HOST=linux-x86_64 && + export ANDROID_NDK_PLATFORM=android-21 && env + - echo "Check env vars" && echo $ANDROID_SDK_ROOT && echo $ANDROID_NDK_ROOT && echo $QT_BIN_DIR script: - - bash deploy/build_android.sh + - travis_wait 60 bash deploy/build_android.sh after_script: - ccache --show-stats From 0ca4f3b1049d5b1b836e7b627470236b4e9ed7ce Mon Sep 17 00:00:00 2001 From: pokamest Date: Wed, 31 Aug 2022 16:54:46 +0300 Subject: [PATCH 30/52] Fix for CommandLineParser --- client/amnezia_application.cpp | 23 ++++++++++++++--------- client/amnezia_application.h | 10 +++++----- client/main.cpp | 9 ++++++--- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index 4b8c7a4ea..43f352a2f 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -56,14 +56,17 @@ AmneziaApplication::~AmneziaApplication() { - QObject::disconnect(m_engine, 0,0,0); - delete m_engine; + if (m_engine) { + QObject::disconnect(m_engine, 0,0,0); + delete m_engine; + } + if (m_uiLogic) { + QObject::disconnect(m_uiLogic, 0,0,0); + delete m_uiLogic; + } - QObject::disconnect(m_uiLogic, 0,0,0); - delete m_uiLogic; - - delete m_protocolProps; - delete m_containerProps; + if (m_protocolProps) delete m_protocolProps; + if (m_containerProps) delete m_containerProps; } void AmneziaApplication::init() @@ -170,7 +173,7 @@ void AmneziaApplication::loadTranslator() } } -void AmneziaApplication::parseCommands() +bool AmneziaApplication::parseCommands() { m_parser.setApplicationDescription(APPLICATION_NAME); m_parser.addHelpOption(); @@ -186,11 +189,13 @@ void AmneziaApplication::parseCommands() if (m_parser.isSet(c_cleanup)) { Debug::cleanUp(); - QTimer::singleShot(100,[this]{ + QTimer::singleShot(100, this, [this]{ quit(); }); exec(); + return false; } + return true; } QQmlApplicationEngine *AmneziaApplication::qmlEngine() const diff --git a/client/amnezia_application.h b/client/amnezia_application.h index c5531aa14..f0f8f5294 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -40,19 +40,19 @@ public: void registerTypes(); void loadFonts(); void loadTranslator(); - void parseCommands(); + bool parseCommands(); QQmlApplicationEngine *qmlEngine() const; private: - QQmlApplicationEngine *m_engine; - UiLogic *m_uiLogic; + QQmlApplicationEngine *m_engine {}; + UiLogic *m_uiLogic {}; std::shared_ptr m_settings; std::shared_ptr m_configurator; std::shared_ptr m_serverController; - ContainerProps* m_containerProps; - ProtocolProps* m_protocolProps; + ContainerProps* m_containerProps {}; + ProtocolProps* m_protocolProps {}; QTranslator* m_translator; QCommandLineParser m_parser; diff --git a/client/main.cpp b/client/main.cpp index e30bd8c85..a5751979e 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -63,8 +63,11 @@ int main(int argc, char *argv[]) app.loadTranslator(); app.loadFonts(); - app.parseCommands(); - app.init(); + bool doExec = app.parseCommands(); - return app.exec(); + if (doExec) { + app.init(); + return app.exec(); + } + return 0; } From 294b75ce2d9090a50dd0446551819455fa0382c4 Mon Sep 17 00:00:00 2001 From: pokamest Date: Wed, 31 Aug 2022 13:29:28 -0700 Subject: [PATCH 31/52] QtKeyChain usage fix --- client/secure_qsettings.cpp | 4 ++-- client/secure_qsettings.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index cbb8468db..b78863bab 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -219,7 +219,7 @@ QByteArray SecureQSettings::getEncIv() const QByteArray SecureQSettings::getSecTag(const QString &tag) { - ReadPasswordJob job("get-" + tag); + ReadPasswordJob job(keyChainName); job.setAutoDelete(false); job.setKey(tag); QEventLoop loop; @@ -236,7 +236,7 @@ QByteArray SecureQSettings::getSecTag(const QString &tag) void SecureQSettings::setSecTag(const QString &tag, const QByteArray &data) { - WritePasswordJob job("set-" + tag); + WritePasswordJob job(keyChainName); job.setAutoDelete(false); job.setKey(tag); job.setBinaryData(data); diff --git a/client/secure_qsettings.h b/client/secure_qsettings.h index e0be9bfa0..9b1f6167e 100644 --- a/client/secure_qsettings.h +++ b/client/secure_qsettings.h @@ -11,6 +11,7 @@ constexpr const char* settingsKeyTag = "settingsKeyTag"; constexpr const char* settingsIvTag = "settingsIvTag"; +constexpr const char* keyChainName = "AmneziaVPN-Keychain"; class SecureQSettings : public QObject From 64513372749db3eec8571c313346298dbcc42ae7 Mon Sep 17 00:00:00 2001 From: leetthewire Date: Thu, 1 Sep 2022 17:45:15 +0400 Subject: [PATCH 32/52] fixed service lib path --- deploy/data/linux/AmneziaVPN.service | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/data/linux/AmneziaVPN.service b/deploy/data/linux/AmneziaVPN.service index 5e7753e08..4f8293120 100755 --- a/deploy/data/linux/AmneziaVPN.service +++ b/deploy/data/linux/AmneziaVPN.service @@ -8,6 +8,7 @@ Type=simple Restart=always RestartSec=1 ExecStart=/opt/AmneziaVPN/service/AmneziaVPN-service.sh +Environment=LD_LIBRARY_PATH=/opt/AmneziaVPN/client/lib [Install] WantedBy=multi-user.target From cdb1a4c288e86c5cef31ce08f326ad1435dfd201 Mon Sep 17 00:00:00 2001 From: pokamest Date: Fri, 2 Sep 2022 12:39:46 -0700 Subject: [PATCH 33/52] Fix for AVP-01-006 - inscure app config permissions --- client/amnezia_application.cpp | 19 +++++++++++++++++++ client/secure_qsettings.cpp | 5 ++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index 43f352a2f..4420f7dc3 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -1,6 +1,7 @@ #include "amnezia_application.h" #include +#include #include #include @@ -49,6 +50,24 @@ #endif { setQuitOnLastWindowClosed(false); + + // Fix config file permissions +#ifdef Q_OS_LINUX + { + QSettings s(ORGANIZATION_NAME, APPLICATION_NAME); + s.setValue("permFixed", true); + } + + QString configLoc1 = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).first() + "/" + + ORGANIZATION_NAME + "/" + APPLICATION_NAME + ".conf"; + QFile::setPermissions(configLoc1, QFileDevice::ReadOwner | QFileDevice::WriteOwner); + + QString configLoc2 = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).first() + "/" + + ORGANIZATION_NAME + "/" + APPLICATION_NAME + "/" + APPLICATION_NAME + ".conf"; + QFile::setPermissions(configLoc2, QFileDevice::ReadOwner | QFileDevice::WriteOwner); + +#endif + m_settings = std::shared_ptr(new Settings); m_serverController = std::shared_ptr(new ServerController(m_settings, this)); m_configurator = std::shared_ptr(new VpnConfigurator(m_settings, m_serverController, this)); diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index b78863bab..a58ae7c47 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -162,7 +162,10 @@ QByteArray SecureQSettings::decryptText(const QByteArray& ba) const bool SecureQSettings::encryptionRequired() const { - // TODO: review on linux +#ifdef Q_OS_LINUX + // QtKeyChain failing on Linux + return false; +#endif return true; } From 5cbe7600a66cbe621f57e4ba779a2a19c6c62c3b Mon Sep 17 00:00:00 2001 From: leetthewire Date: Sat, 3 Sep 2022 06:19:48 +0400 Subject: [PATCH 34/52] updated gitignore --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 26ce16e42..1b4e16b20 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,12 @@ client/3rd/ShadowSocks/build/ # QtCtreator CMake CMakeLists.txt.user* +# Linux files +*.7z +deploy/AppDir +deploy/Tools +deploy/AmneziaVPN*Installer* + # MACOS files .DS_Store client/.DS_Store From 279f866bf569c461e549f67b94ccbfd1f55eba9f Mon Sep 17 00:00:00 2001 From: leetthewire Date: Sat, 3 Sep 2022 06:19:25 +0400 Subject: [PATCH 35/52] completed build linux script --- deploy/build_linux.sh | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) mode change 100644 => 100755 deploy/build_linux.sh diff --git a/deploy/build_linux.sh b/deploy/build_linux.sh old mode 100644 new mode 100755 index 996c758af..945066255 --- a/deploy/build_linux.sh +++ b/deploy/build_linux.sh @@ -11,6 +11,15 @@ DEPLOY_DIR=$PROJECT_DIR/deploy mkdir -p $DEPLOY_DIR/build BUILD_DIR=$DEPLOY_DIR/build +APP_DIR=$DEPLOY_DIR/AppDir +mkdir -p $APP_DIR + +TOOLS_DIR=$DEPLOY_DIR/Tools +mkdir -p $TOOLS_DIR + +CQTDEPLOYER_DIR=$TOOLS_DIR/cqtdeployer +mkdir -p $CQTDEPLOYER_DIR + echo "Project dir: ${PROJECT_DIR}" echo "Build dir: ${BUILD_DIR}" @@ -18,12 +27,8 @@ APP_NAME=AmneziaVPN APP_FILENAME=$APP_NAME.app APP_DOMAIN=org.amneziavpn.package -OUT_APP_DIR=$BUILD_DIR/client -BUNDLE_DIR=$OUT_APP_DIR/$APP_FILENAME - DEPLOY_DATA_DIR=$PROJECT_DIR/deploy/data/linux -INSTALLER_DATA_DIR=$BUILD_DIR/installer/packages/$APP_DOMAIN/data -INSTALLER_BUNDLE_DIR=$BUILD_DIR/installer/$APP_FILENAME +INSTALLER_DATA_DIR=$PROJECT_DIR/deploy/installer/packages/$APP_DOMAIN/data PRO_FILE_PATH=$PROJECT_DIR/$APP_NAME.pro QMAKE_STASH_FILE=$PROJECT_DIR/.qmake_stash @@ -31,13 +36,10 @@ QMAKE_STASH_FILE=$PROJECT_DIR/.qmake_stash # Seacrh Qt if [ -z "${QT_VERSION+x}" ]; then QT_VERSION=5.15.2; -QIF_VERSION=4.1 -QT_BIN_DIR=$HOME/Qt/$QT_VERSION/gcc_64/bin -QIF_BIN_DIR=$QT_BIN_DIR/../../../Tools/QtInstallerFramework/$QIF_VERSION/bin +QT_BIN_DIR=/opt/Qt/$QT_VERSION/gcc_64/bin fi echo "Using Qt in $QT_BIN_DIR" -echo "Using QIF in $QIF_BIN_DIR" # Checking env @@ -56,4 +58,23 @@ make #echo "............Deploy.................." +cp -r $DEPLOY_DATA_DIR/* $APP_DIR + +wget -O $TOOLS_DIR/CQtDeployer.zip https://github.com/QuasarApp/CQtDeployer/releases/download/v1.5.4.17/CQtDeployer_1.5.4.17_Linux_x86_64.zip + +unzip -o $TOOLS_DIR/CQtDeployer.zip -d $CQTDEPLOYER_DIR/ + +chmod +x -R $CQTDEPLOYER_DIR +#chmod +x $CQTDEPLOYER_DIR/binarycreator.sh + +$CQTDEPLOYER_DIR/cqtdeployer.sh -bin $BUILD_DIR/client/AmneziaVPN -qmake $QT_BIN_DIR/qmake -qmlDir $PROJECT_DIR/client/ui/qml/ -targetDir $APP_DIR/client/ + +$CQTDEPLOYER_DIR/cqtdeployer.sh -bin $BUILD_DIR/service/server/AmneziaVPN-service -qmake $QT_BIN_DIR/qmake -targetDir $APP_DIR/service/ + +rm -f $INSTALLER_DATA_DIR/data.7z + +7z a $INSTALLER_DATA_DIR/data.7z $APP_DIR/* + +$CQTDEPLOYER_DIR/binarycreator.sh --offline-only -v -c $PROJECT_DIR/deploy/installer/config/linux.xml -p $PROJECT_DIR/deploy/installer/packages/ -f $PROJECT_DIR/deploy/AmneziaVPN_Linux_Installer + From 3cb14ad3bcc57921143cfb4dcd2ebac530e48dad Mon Sep 17 00:00:00 2001 From: pokamest Date: Sat, 3 Sep 2022 06:31:59 -0700 Subject: [PATCH 36/52] Tiny Linux build scripts fixes --- .travis.yml | 1 + deploy/build_linux.sh | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index c5022b121..0430d5295 100644 --- a/.travis.yml +++ b/.travis.yml @@ -162,6 +162,7 @@ jobs: apt: packages: - p7zip + - p7zip-full - python3 - python3-pip - libgl-dev diff --git a/deploy/build_linux.sh b/deploy/build_linux.sh index 945066255..754b5e6dc 100755 --- a/deploy/build_linux.sh +++ b/deploy/build_linux.sh @@ -35,8 +35,12 @@ QMAKE_STASH_FILE=$PROJECT_DIR/.qmake_stash # Seacrh Qt if [ -z "${QT_VERSION+x}" ]; then -QT_VERSION=5.15.2; -QT_BIN_DIR=/opt/Qt/$QT_VERSION/gcc_64/bin + QT_VERSION=5.15.2 + if [ -f /opt/Qt/$QT_VERSION/gcc_64/bin/qmake ]; then + QT_BIN_DIR=/opt/Qt/$QT_VERSION/gcc_64/bin + elif [ -f $HOME/Qt/$QT_VERSION/gcc_64/bin/qmake ]; then + QT_BIN_DIR=$HOME/Qt/$QT_VERSION/gcc_64/bin + fi fi echo "Using Qt in $QT_BIN_DIR" @@ -60,15 +64,14 @@ make cp -r $DEPLOY_DATA_DIR/* $APP_DIR -wget -O $TOOLS_DIR/CQtDeployer.zip https://github.com/QuasarApp/CQtDeployer/releases/download/v1.5.4.17/CQtDeployer_1.5.4.17_Linux_x86_64.zip +if [ ! -f $CQTDEPLOYER_DIR/cqtdeployer.sh ]; then + wget -O $TOOLS_DIR/CQtDeployer.zip https://github.com/QuasarApp/CQtDeployer/releases/download/v1.5.4.17/CQtDeployer_1.5.4.17_Linux_x86_64.zip + unzip -o $TOOLS_DIR/CQtDeployer.zip -d $CQTDEPLOYER_DIR/ + chmod +x -R $CQTDEPLOYER_DIR +fi -unzip -o $TOOLS_DIR/CQtDeployer.zip -d $CQTDEPLOYER_DIR/ - -chmod +x -R $CQTDEPLOYER_DIR -#chmod +x $CQTDEPLOYER_DIR/binarycreator.sh $CQTDEPLOYER_DIR/cqtdeployer.sh -bin $BUILD_DIR/client/AmneziaVPN -qmake $QT_BIN_DIR/qmake -qmlDir $PROJECT_DIR/client/ui/qml/ -targetDir $APP_DIR/client/ - $CQTDEPLOYER_DIR/cqtdeployer.sh -bin $BUILD_DIR/service/server/AmneziaVPN-service -qmake $QT_BIN_DIR/qmake -targetDir $APP_DIR/service/ rm -f $INSTALLER_DATA_DIR/data.7z From 448c01ca99e26f3512c4dec4a911d0cd6abbc755 Mon Sep 17 00:00:00 2001 From: pokamest Date: Sun, 4 Sep 2022 14:49:33 +0300 Subject: [PATCH 37/52] Travis build fix --- .gitlab-ci.yml | 27 --------------------------- .travis.yml | 22 ++++++++++++++-------- deploy/build_android.sh | 12 +++++------- 3 files changed, 19 insertions(+), 42 deletions(-) delete mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 6c8fa28b5..000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,27 +0,0 @@ -variables: - GIT_STRATEGY: clone - -stages: - - build - -build-windows: - stage: build - tags: - - windows - script: - - cmd.exe /k "deploy\windows-env.bat && cd deploy && windows.bat" - artifacts: - name: artifacts-windows - paths: - - AmneziaVPN.exe - -build-macos: - stage: build - tags: - - macos - script: - - cd deploy && ./macos.sh - artifacts: - name: artifacts-macos - paths: - - AmneziaVPN.dmg diff --git a/.travis.yml b/.travis.yml index 70d9b6ecf..a3d7eacdf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -220,14 +220,20 @@ jobs: - PROJ_ROOT=$(pwd) - JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 + addons: + apt: + packages: + - p7zip + - python3 + - python3-pip + - openjdk-8-jdk + install: - - echo "Installing Java 8" - - sudo apt-get install openjdk-8-jdk > /dev/null - - echo "QT bin install" && pwd - - if [ ! -f $QT_BIN_DIR/qmake ]; then - wget https://ondjoss.com/qt15_2_android_linux_x86_64.zip > /dev/null && - mkdir -p $HOME/Qt/$QT_VERSION && \ - unzip ./qt15_2_android_linux_x86_64.zip -d $HOME/Qt/$QT_VERSION > /dev/null ; + - | + if [ ! -f $QT_BIN_DIR/qmake ]; then \ + python3 -m pip install -U aqtinstall requests py7zr && \ + python3 -m pip show aqtinstall && \ + python3 -m aqt install-qt linux android $QT_VERSION -m all -O $HOME/Qt ; \ fi - echo "Download SDK" && pwd - export ANDROID_HOME=`pwd`/sdk @@ -257,7 +263,7 @@ jobs: - echo "Check env vars" && echo $ANDROID_SDK_ROOT && echo $ANDROID_NDK_ROOT && echo $QT_BIN_DIR script: - - travis_wait 60 bash deploy/build_android.sh + - deploy/build_android.sh after_script: - ccache --show-stats diff --git a/deploy/build_android.sh b/deploy/build_android.sh index 2b46b5fb5..75e8c46c7 100644 --- a/deploy/build_android.sh +++ b/deploy/build_android.sh @@ -30,16 +30,16 @@ QMAKE_STASH_FILE=$PROJECT_DIR/.qmake_stash if [ -z "${QT_VERSION+x}" ]; then QT_VERSION=5.15.2; QT_BIN_DIR=$HOME/Qt/$QT_VERSION/android/bin -#QT_BIN_DIR=$HOME/Qt/$QT_VERSION/gcc_64/bin fi echo "Using Qt in $QT_BIN_DIR" +echo "Using Android SDK in $ANDROID_SDK_ROOT" +echo "Using Android NDK in $ANDROID_NDK_ROOT" # Checking env $QT_BIN_DIR/qmake -v -make -v -gcc -v +$ANDROID_NDK_HOME/prebuilt/linux-x86_64/bin/make -v # Build App echo "Building App..." @@ -47,16 +47,14 @@ cd $BUILD_DIR $QT_BIN_DIR/qmake -r -spec android-clang CONFIG+=qtquickcompiler ANDROID_ABIS="armeabi-v7a arm64-v8a x86 x86_64" $PROJECT_DIR/AmneziaVPN.pro echo "Executing make... may take long time" -$ANDROID_NDK_HOME/prebuilt/linux-x86_64/bin/make -j2 > /dev/null 2>/dev/null +$ANDROID_NDK_HOME/prebuilt/linux-x86_64/bin/make -j2 echo "Make install..." -$ANDROID_NDK_HOME/prebuilt/linux-x86_64/bin/make install INSTALL_ROOT=android > /dev/null 2>/dev/null +$ANDROID_NDK_HOME/prebuilt/linux-x86_64/bin/make install INSTALL_ROOT=android echo "Build OK" -# Build and run tests here echo "............Deploy.................." cd $OUT_APP_DIR -#--verbose removed $QT_BIN_DIR/androiddeployqt \ --output $OUT_APP_DIR/android \ --gradle \ From df26f492a787eebfea5a604d754d8faa0c98d920 Mon Sep 17 00:00:00 2001 From: pokamest Date: Sun, 4 Sep 2022 23:27:00 +0300 Subject: [PATCH 38/52] Travis build fix --- .travis.yml | 61 +++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/.travis.yml b/.travis.yml index a3d7eacdf..72795dd60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -168,6 +168,7 @@ jobs: - libgl-dev - mesa-common-dev - libpulse-dev + - libxcb-icccm4 env: - QT_VERSION=5.15.2 @@ -215,10 +216,20 @@ jobs: env: - QT_VERSION=5.15.2 - QT_BIN_DIR=$HOME/Qt/$QT_VERSION/android/bin - - USE_ANDROID_NDK_VERSION=21d - - ANDROID_NDK_HOME=$HOME/NDK - - PROJ_ROOT=$(pwd) + - ANDROID_API_VERSION=android-21 + - ANDROID_HOME=$HOME/sdk + - ANDROID_SDK_ROOT=$ANDROID_HOME + - LOCAL_ANDROID_HOME=$ANDROID_HOME + - LOCAL_ANDROID_SDK_ROOT=$ANDROID_HOME + - NDK_VERSION=21d + - ANDROID_NDK_PLATFORM=android-21 + - ANDROID_NDK_HOME=$HOME/android-ndk-r${NDK_VERSION} + - ANDROID_NDK_ROOT=$ANDROID_NDK_HOME + - ANDROID_NDK_HOST=linux-x86_64 + - LOCAL_ANDROID_NDK_HOME=$ANDROID_NDK_HOME + - LOCAL_ANDROID_NDK_HOST_PLATFORM=$ANDROID_NDK_HOST - JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 + - TERM=dumb addons: apt: @@ -235,35 +246,24 @@ jobs: python3 -m pip show aqtinstall && \ python3 -m aqt install-qt linux android $QT_VERSION -m all -O $HOME/Qt ; \ fi - - echo "Download SDK" && pwd - - export ANDROID_HOME=`pwd`/sdk - - export LOCAL_ANDROID_HOME=`pwd`/sdk - - export ANDROID_SDK_ROOT=`pwd`/sdk - - export LOCAL_ANDROID_SDK_ROOT=`pwd`/sdk - - export ANDROID_API_VERSION=android-21 - - mkdir -p sdk && cd sdk && - wget https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip -qO sdk.zip > /dev/null || exit 1 - - ls -ll && unzip -q sdk.zip || exit 1 - - echo "Download all needed tools" && pwd && ls -ll && - yes | ./tools/bin/sdkmanager --licenses > /dev/null 2>/dev/null - - ./tools/bin/sdkmanager --install "cmdline-tools;latest" "platform-tools" "platforms;android-30" "build-tools;30.0.2" > /dev/null 2>/dev/null - - cd $PROJ_ROOT && echo "Download NDK" && pwd - - export TERM=dumb && - curl -L https://dl.google.com/android/repository/android-ndk-r${USE_ANDROID_NDK_VERSION}-linux-x86_64.zip -O && - unzip ./android-ndk-r${USE_ANDROID_NDK_VERSION}-linux-x86_64.zip > /dev/null && - rm android-ndk-r${USE_ANDROID_NDK_VERSION}-linux-x86_64.zip && - export ANDROID_NDK_HOME=`pwd`/android-ndk-r${USE_ANDROID_NDK_VERSION} && - export ANDROID_NDK_ROOT=`pwd`/android-ndk-r${USE_ANDROID_NDK_VERSION} && - export LOCAL_ANDROID_NDK_HOME="$ANDROID_NDK_HOME" && - export LOCAL_ANDROID_NDK_HOST_PLATFORM="linux-x86_64" && - export PATH=$PATH:${ANDROID_NDK_HOME} && - export ANDROID_NDK_HOST=linux-x86_64 && - export ANDROID_NDK_PLATFORM=android-21 && - env - - echo "Check env vars" && echo $ANDROID_SDK_ROOT && echo $ANDROID_NDK_ROOT && echo $QT_BIN_DIR + + - | + if [ ! -f $ANDROID_SDK_ROOT/tools/bin/sdkmanager ]; then \ + echo "Download Android SDK" && \ + wget https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip -qO $HOME/sdk.zip > /dev/null && \ + unzip -q -d $ANDROID_SDK_ROOT $HOME/sdk.zip && \ + echo "Download tools" && \ + yes | ./tools/bin/sdkmanager --licenses && \ + $ANDROID_SDK_ROOT/tools/bin/sdkmanager --install "cmdline-tools;latest" "platform-tools" "platforms;android-30" "build-tools;30.0.2" || exit 1 ; \ + fi + - | + if [ ! -f $ANDROID_NDK_ROOT/ndk-build ]; then \ + wget https://dl.google.com/android/repository/android-ndk-r${NDK_VERSION}-linux-x86_64.zip -qO $HOME/ndk.zip && + unzip -q -d $HOME $HOME/ndk.zip ; \ + fi script: - - deploy/build_android.sh + - bash deploy/build_android.sh after_script: - ccache --show-stats @@ -286,6 +286,7 @@ jobs: - $HOME/.gradle/wrapper/ - $HOME/.android/build-cache - $ANDROID_NDK_HOME + - $ANDROID_SDK_ROOT # ------------------------------------------------------ - name: iOS From ac7d2246454601c10b909da44715ebb292c0493e Mon Sep 17 00:00:00 2001 From: pokamest Date: Mon, 5 Sep 2022 00:11:55 +0300 Subject: [PATCH 39/52] Travis build fix --- .travis.yml | 18 +++++++++++++++++- deploy/build_linux.sh | 2 ++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 72795dd60..9f0a9a8af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -168,7 +168,23 @@ jobs: - libgl-dev - mesa-common-dev - libpulse-dev + - libxcb-* - libxcb-icccm4 + - libxcb-image0 + - libxcb-shm0 + - libxcb-util1 + - libxcb-keysyms1 + - libxcb-randr0 + - libxcb-render-util0 + - libxcb-render0 + - libxcb-shape0 + - libxcb-sync1 + - libxcb-xfixes0 + - libxcb-randr0-dev + - libxcb-xtest0-dev + - libxcb-xinerama0-dev + - libxcb-shape0-dev + - libxcb-xkb-dev env: - QT_VERSION=5.15.2 @@ -253,7 +269,7 @@ jobs: wget https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip -qO $HOME/sdk.zip > /dev/null && \ unzip -q -d $ANDROID_SDK_ROOT $HOME/sdk.zip && \ echo "Download tools" && \ - yes | ./tools/bin/sdkmanager --licenses && \ + yes | $ANDROID_SDK_ROOT/tools/bin/sdkmanager --licenses && \ $ANDROID_SDK_ROOT/tools/bin/sdkmanager --install "cmdline-tools;latest" "platform-tools" "platforms;android-30" "build-tools;30.0.2" || exit 1 ; \ fi - | diff --git a/deploy/build_linux.sh b/deploy/build_linux.sh index 754b5e6dc..f72f1a0cc 100755 --- a/deploy/build_linux.sh +++ b/deploy/build_linux.sh @@ -78,6 +78,8 @@ rm -f $INSTALLER_DATA_DIR/data.7z 7z a $INSTALLER_DATA_DIR/data.7z $APP_DIR/* +ldd $CQTDEPLOYER_DIR/bin/binarycreator + $CQTDEPLOYER_DIR/binarycreator.sh --offline-only -v -c $PROJECT_DIR/deploy/installer/config/linux.xml -p $PROJECT_DIR/deploy/installer/packages/ -f $PROJECT_DIR/deploy/AmneziaVPN_Linux_Installer From ce27af6083abc6229b7d10d6e0c43c83c516dae2 Mon Sep 17 00:00:00 2001 From: pokamest Date: Mon, 5 Sep 2022 00:33:27 +0300 Subject: [PATCH 40/52] Travis build fix --- .travis.yml | 21 +++------------------ client/client.pro | 2 -- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f0a9a8af..0edc541e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -169,22 +169,7 @@ jobs: - mesa-common-dev - libpulse-dev - libxcb-* - - libxcb-icccm4 - - libxcb-image0 - - libxcb-shm0 - - libxcb-util1 - - libxcb-keysyms1 - - libxcb-randr0 - - libxcb-render-util0 - - libxcb-render0 - - libxcb-shape0 - - libxcb-sync1 - - libxcb-xfixes0 - - libxcb-randr0-dev - - libxcb-xtest0-dev - - libxcb-xinerama0-dev - - libxcb-shape0-dev - - libxcb-xkb-dev + - libxkbcommon-x11-0 env: - QT_VERSION=5.15.2 @@ -269,8 +254,8 @@ jobs: wget https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip -qO $HOME/sdk.zip > /dev/null && \ unzip -q -d $ANDROID_SDK_ROOT $HOME/sdk.zip && \ echo "Download tools" && \ - yes | $ANDROID_SDK_ROOT/tools/bin/sdkmanager --licenses && \ - $ANDROID_SDK_ROOT/tools/bin/sdkmanager --install "cmdline-tools;latest" "platform-tools" "platforms;android-30" "build-tools;30.0.2" || exit 1 ; \ + yes | $ANDROID_SDK_ROOT/tools/bin/sdkmanager --licenses > /dev/null 2>&1 && \ + $ANDROID_SDK_ROOT/tools/bin/sdkmanager --install "cmdline-tools;latest" "platform-tools" "platforms;android-30" "build-tools;30.0.2" > /dev/null 2>&1 || exit 1 ; \ fi - | if [ ! -f $ANDROID_NDK_ROOT/ndk-build ]; then \ diff --git a/client/client.pro b/client/client.pro index 5b6d3f8f0..fc05dd0fc 100644 --- a/client/client.pro +++ b/client/client.pro @@ -8,8 +8,6 @@ CONFIG += qzxing_multimedia \ enable_decoder_qr_code \ enable_encoder_qr_code -DEFINES += QT_DEPRECATED_WARNINGS - include("3rd/QtSsh/src/ssh/qssh.pri") include("3rd/QtSsh/src/botan/botan.pri") !android:!ios:include("3rd/SingleApplication/singleapplication.pri") From e1c529ab9164833e455a3f0805f9030606542629 Mon Sep 17 00:00:00 2001 From: pokamest Date: Mon, 5 Sep 2022 01:38:29 +0300 Subject: [PATCH 41/52] Travis ccache --- .travis.yml | 10 +++++++++- client/client.pro | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0edc541e6..60c954c74 100644 --- a/.travis.yml +++ b/.travis.yml @@ -77,6 +77,7 @@ jobs: aqt install-qt windows desktop $QT_VERSION win64_msvc2019_64 -m all -O /C/Qt && \ aqt install-tool windows desktop tools_ifw -O /C/Qt ; \ fi + - choco install ccache script: - echo set BUILD_ARCH=$BUILD_ARCH > winbuild.bat @@ -86,7 +87,10 @@ jobs: - echo call \""%MSVC_PATH_WIN%\\Common7\\Tools\\VsDevCmd.bat\" -arch=amd64" >> winbuild.bat - echo call deploy\\build_windows.bat >> winbuild.bat - cmd //c winbuild.bat - + + after_script: + - ccache --show-stats + deploy: provider: releases token: $GH_TOKEN @@ -128,6 +132,7 @@ jobs: aqt install-qt windows desktop $QT_VERSION win32_msvc2019 -m all -O /C/Qt && \ aqt install-tool windows desktop tools_ifw -O /C/Qt ; \ fi + - choco install ccache script: - echo set BUILD_ARCH=$BUILD_ARCH > winbuild.bat @@ -138,6 +143,9 @@ jobs: - echo call deploy\\build_windows.bat >> winbuild.bat - cmd //c winbuild.bat + after_script: + - ccache --show-stats + deploy: provider: releases token: $GH_TOKEN diff --git a/client/client.pro b/client/client.pro index fc05dd0fc..42132edcb 100644 --- a/client/client.pro +++ b/client/client.pro @@ -3,6 +3,12 @@ QT += widgets core gui network xml remoteobjects quick svg TARGET = AmneziaVPN TEMPLATE = app +# silent builds on CI env +contains(DEFINES,CI){ + message("Detected CI env") + CONFIG += silent ccache +} + CONFIG += qtquickcompiler CONFIG += qzxing_multimedia \ enable_decoder_qr_code \ From 9ceadd44c9bcdc69ba1a3f5df1262a7498dbd8ec Mon Sep 17 00:00:00 2001 From: pokamest Date: Mon, 5 Sep 2022 01:56:39 +0300 Subject: [PATCH 42/52] Travis fix --- client/client.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/client.pro b/client/client.pro index 42132edcb..803c5daf5 100644 --- a/client/client.pro +++ b/client/client.pro @@ -4,7 +4,7 @@ TARGET = AmneziaVPN TEMPLATE = app # silent builds on CI env -contains(DEFINES,CI){ +contains(DEFINES,$$(CI)){ message("Detected CI env") CONFIG += silent ccache } From fb07adf7c15aa22d89d512eaa23ca6ed93b1c59c Mon Sep 17 00:00:00 2001 From: pokamest Date: Mon, 5 Sep 2022 02:06:58 +0300 Subject: [PATCH 43/52] Travis fix --- client/client.pro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/client.pro b/client/client.pro index 803c5daf5..9a89842d4 100644 --- a/client/client.pro +++ b/client/client.pro @@ -4,7 +4,8 @@ TARGET = AmneziaVPN TEMPLATE = app # silent builds on CI env -contains(DEFINES,$$(CI)){ +IS_CI=$$(CI) +!isEmpty(IS_CI){ message("Detected CI env") CONFIG += silent ccache } From 7a6c1de5d5c0fd21a18a2b242667e6be3bbd163f Mon Sep 17 00:00:00 2001 From: pokamest Date: Wed, 7 Sep 2022 09:51:03 +0300 Subject: [PATCH 44/52] QrCoreGen --- .gitmodules | 3 - client/3rd/qrcodegen/qrcodegen.cpp | 856 ++++++++++++++++++ client/3rd/qrcodegen/qrcodegen.hpp | 551 +++++++++++ client/3rd/qrcodegen/qrcodegen.pri | 5 + client/3rd/qzxing | 1 - client/amnezia_application.cpp | 4 - client/client.pro | 2 +- .../ui/pages_logic/ShareConnectionLogic.cpp | 33 +- client/ui/pages_logic/ShareConnectionLogic.h | 3 +- 9 files changed, 1430 insertions(+), 28 deletions(-) create mode 100644 client/3rd/qrcodegen/qrcodegen.cpp create mode 100644 client/3rd/qrcodegen/qrcodegen.hpp create mode 100644 client/3rd/qrcodegen/qrcodegen.pri delete mode 160000 client/3rd/qzxing diff --git a/.gitmodules b/.gitmodules index 328bfe764..a8295ac7d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,9 +16,6 @@ [submodule "client/3rd/outline-go-tun2socks"] path = client/3rd/outline-go-tun2socks url = https://github.com/Jigsaw-Code/outline-go-tun2socks.git -[submodule "client/3rd/qzxing"] - path = client/3rd/qzxing - url = https://github.com/ftylitak/qzxing.git [submodule "client/3rd/CocoaAsyncSocket"] path = client/3rd/CocoaAsyncSocket url = https://github.com/robbiehanson/CocoaAsyncSocket.git diff --git a/client/3rd/qrcodegen/qrcodegen.cpp b/client/3rd/qrcodegen/qrcodegen.cpp new file mode 100644 index 000000000..21fffba96 --- /dev/null +++ b/client/3rd/qrcodegen/qrcodegen.cpp @@ -0,0 +1,856 @@ +/* + * QR Code generator library (C++) + * + * Copyright (c) Project Nayuki. (MIT License) + * https://www.nayuki.io/page/qr-code-generator-library + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * - The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * - The Software is provided "as is", without warranty of any kind, express or + * implied, including but not limited to the warranties of merchantability, + * fitness for a particular purpose and noninfringement. In no event shall the + * authors or copyright holders be liable for any claim, damages or other + * liability, whether in an action of contract, tort or otherwise, arising from, + * out of or in connection with the Software or the use or other dealings in the + * Software. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "qrcodegen.hpp" + +using std::int8_t; +using std::uint8_t; +using std::size_t; +using std::vector; + + +namespace qrcodegen { + +/*---- Class QrSegment ----*/ + +QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) : + modeBits(mode) { + numBitsCharCount[0] = cc0; + numBitsCharCount[1] = cc1; + numBitsCharCount[2] = cc2; +} + + +int QrSegment::Mode::getModeBits() const { + return modeBits; +} + + +int QrSegment::Mode::numCharCountBits(int ver) const { + return numBitsCharCount[(ver + 7) / 17]; +} + + +const QrSegment::Mode QrSegment::Mode::NUMERIC (0x1, 10, 12, 14); +const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13); +const QrSegment::Mode QrSegment::Mode::BYTE (0x4, 8, 16, 16); +const QrSegment::Mode QrSegment::Mode::KANJI (0x8, 8, 10, 12); +const QrSegment::Mode QrSegment::Mode::ECI (0x7, 0, 0, 0); + + +QrSegment QrSegment::makeBytes(const vector &data) { + if (data.size() > static_cast(INT_MAX)) + throw std::length_error("Data too long"); + BitBuffer bb; + for (uint8_t b : data) + bb.appendBits(b, 8); + return QrSegment(Mode::BYTE, static_cast(data.size()), std::move(bb)); +} + + +QrSegment QrSegment::makeNumeric(const char *digits) { + BitBuffer bb; + int accumData = 0; + int accumCount = 0; + int charCount = 0; + for (; *digits != '\0'; digits++, charCount++) { + char c = *digits; + if (c < '0' || c > '9') + throw std::domain_error("String contains non-numeric characters"); + accumData = accumData * 10 + (c - '0'); + accumCount++; + if (accumCount == 3) { + bb.appendBits(static_cast(accumData), 10); + accumData = 0; + accumCount = 0; + } + } + if (accumCount > 0) // 1 or 2 digits remaining + bb.appendBits(static_cast(accumData), accumCount * 3 + 1); + return QrSegment(Mode::NUMERIC, charCount, std::move(bb)); +} + + +QrSegment QrSegment::makeAlphanumeric(const char *text) { + BitBuffer bb; + int accumData = 0; + int accumCount = 0; + int charCount = 0; + for (; *text != '\0'; text++, charCount++) { + const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text); + if (temp == nullptr) + throw std::domain_error("String contains unencodable characters in alphanumeric mode"); + accumData = accumData * 45 + static_cast(temp - ALPHANUMERIC_CHARSET); + accumCount++; + if (accumCount == 2) { + bb.appendBits(static_cast(accumData), 11); + accumData = 0; + accumCount = 0; + } + } + if (accumCount > 0) // 1 character remaining + bb.appendBits(static_cast(accumData), 6); + return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb)); +} + + +vector QrSegment::makeSegments(const char *text) { + // Select the most efficient segment encoding automatically + vector result; + if (*text == '\0'); // Leave result empty + else if (isNumeric(text)) + result.push_back(makeNumeric(text)); + else if (isAlphanumeric(text)) + result.push_back(makeAlphanumeric(text)); + else { + vector bytes; + for (; *text != '\0'; text++) + bytes.push_back(static_cast(*text)); + result.push_back(makeBytes(bytes)); + } + return result; +} + + +QrSegment QrSegment::makeEci(long assignVal) { + BitBuffer bb; + if (assignVal < 0) + throw std::domain_error("ECI assignment value out of range"); + else if (assignVal < (1 << 7)) + bb.appendBits(static_cast(assignVal), 8); + else if (assignVal < (1 << 14)) { + bb.appendBits(2, 2); + bb.appendBits(static_cast(assignVal), 14); + } else if (assignVal < 1000000L) { + bb.appendBits(6, 3); + bb.appendBits(static_cast(assignVal), 21); + } else + throw std::domain_error("ECI assignment value out of range"); + return QrSegment(Mode::ECI, 0, std::move(bb)); +} + + +QrSegment::QrSegment(const Mode &md, int numCh, const std::vector &dt) : + mode(&md), + numChars(numCh), + data(dt) { + if (numCh < 0) + throw std::domain_error("Invalid value"); +} + + +QrSegment::QrSegment(const Mode &md, int numCh, std::vector &&dt) : + mode(&md), + numChars(numCh), + data(std::move(dt)) { + if (numCh < 0) + throw std::domain_error("Invalid value"); +} + + +int QrSegment::getTotalBits(const vector &segs, int version) { + int result = 0; + for (const QrSegment &seg : segs) { + int ccbits = seg.mode->numCharCountBits(version); + if (seg.numChars >= (1L << ccbits)) + return -1; // The segment's length doesn't fit the field's bit width + if (4 + ccbits > INT_MAX - result) + return -1; // The sum will overflow an int type + result += 4 + ccbits; + if (seg.data.size() > static_cast(INT_MAX - result)) + return -1; // The sum will overflow an int type + result += static_cast(seg.data.size()); + } + return result; +} + + +bool QrSegment::isNumeric(const char *text) { + for (; *text != '\0'; text++) { + char c = *text; + if (c < '0' || c > '9') + return false; + } + return true; +} + + +bool QrSegment::isAlphanumeric(const char *text) { + for (; *text != '\0'; text++) { + if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr) + return false; + } + return true; +} + + +const QrSegment::Mode &QrSegment::getMode() const { + return *mode; +} + + +int QrSegment::getNumChars() const { + return numChars; +} + + +const std::vector &QrSegment::getData() const { + return data; +} + + +const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; + + + +/*---- Class QrCode ----*/ + +int QrCode::getFormatBits(Ecc ecl) { + switch (ecl) { + case Ecc::LOW : return 1; + case Ecc::MEDIUM : return 0; + case Ecc::QUARTILE: return 3; + case Ecc::HIGH : return 2; + default: throw std::logic_error("Unreachable"); + } +} + + +QrCode QrCode::encodeText(const char *text, Ecc ecl) { + vector segs = QrSegment::makeSegments(text); + return encodeSegments(segs, ecl); +} + + +QrCode QrCode::encodeBinary(const vector &data, Ecc ecl) { + vector segs{QrSegment::makeBytes(data)}; + return encodeSegments(segs, ecl); +} + + +QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, + int minVersion, int maxVersion, int mask, bool boostEcl) { + if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7) + throw std::invalid_argument("Invalid value"); + + // Find the minimal version number to use + int version, dataUsedBits; + for (version = minVersion; ; version++) { + int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available + dataUsedBits = QrSegment::getTotalBits(segs, version); + if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) + break; // This version number is found to be suitable + if (version >= maxVersion) { // All versions in the range could not fit the given data + std::ostringstream sb; + if (dataUsedBits == -1) + sb << "Segment too long"; + else { + sb << "Data length = " << dataUsedBits << " bits, "; + sb << "Max capacity = " << dataCapacityBits << " bits"; + } + throw data_too_long(sb.str()); + } + } + assert(dataUsedBits != -1); + + // Increase the error correction level while the data still fits in the current version number + for (Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high + if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8) + ecl = newEcl; + } + + // Concatenate all segments to create the data bit string + BitBuffer bb; + for (const QrSegment &seg : segs) { + bb.appendBits(static_cast(seg.getMode().getModeBits()), 4); + bb.appendBits(static_cast(seg.getNumChars()), seg.getMode().numCharCountBits(version)); + bb.insert(bb.end(), seg.getData().begin(), seg.getData().end()); + } + assert(bb.size() == static_cast(dataUsedBits)); + + // Add terminator and pad up to a byte if applicable + size_t dataCapacityBits = static_cast(getNumDataCodewords(version, ecl)) * 8; + assert(bb.size() <= dataCapacityBits); + bb.appendBits(0, std::min(4, static_cast(dataCapacityBits - bb.size()))); + bb.appendBits(0, (8 - static_cast(bb.size() % 8)) % 8); + assert(bb.size() % 8 == 0); + + // Pad with alternating bytes until data capacity is reached + for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11) + bb.appendBits(padByte, 8); + + // Pack bits into bytes in big endian + vector dataCodewords(bb.size() / 8); + for (size_t i = 0; i < bb.size(); i++) + dataCodewords.at(i >> 3) |= (bb.at(i) ? 1 : 0) << (7 - (i & 7)); + + // Create the QR Code object + return QrCode(version, ecl, dataCodewords, mask); +} + + +QrCode::QrCode(int ver, Ecc ecl, const vector &dataCodewords, int msk) : + // Initialize fields and check arguments + version(ver), + errorCorrectionLevel(ecl) { + if (ver < MIN_VERSION || ver > MAX_VERSION) + throw std::domain_error("Version value out of range"); + if (msk < -1 || msk > 7) + throw std::domain_error("Mask value out of range"); + size = ver * 4 + 17; + size_t sz = static_cast(size); + modules = vector >(sz, vector(sz)); // Initially all light + isFunction = vector >(sz, vector(sz)); + + // Compute ECC, draw modules + drawFunctionPatterns(); + const vector allCodewords = addEccAndInterleave(dataCodewords); + drawCodewords(allCodewords); + + // Do masking + if (msk == -1) { // Automatically choose best mask + long minPenalty = LONG_MAX; + for (int i = 0; i < 8; i++) { + applyMask(i); + drawFormatBits(i); + long penalty = getPenaltyScore(); + if (penalty < minPenalty) { + msk = i; + minPenalty = penalty; + } + applyMask(i); // Undoes the mask due to XOR + } + } + assert(0 <= msk && msk <= 7); + mask = msk; + applyMask(msk); // Apply the final choice of mask + drawFormatBits(msk); // Overwrite old format bits + + isFunction.clear(); + isFunction.shrink_to_fit(); +} + + +int QrCode::getVersion() const { + return version; +} + + +int QrCode::getSize() const { + return size; +} + + +QrCode::Ecc QrCode::getErrorCorrectionLevel() const { + return errorCorrectionLevel; +} + + +int QrCode::getMask() const { + return mask; +} + + +bool QrCode::getModule(int x, int y) const { + return 0 <= x && x < size && 0 <= y && y < size && module(x, y); +} + + +void QrCode::drawFunctionPatterns() { + // Draw horizontal and vertical timing patterns + for (int i = 0; i < size; i++) { + setFunctionModule(6, i, i % 2 == 0); + setFunctionModule(i, 6, i % 2 == 0); + } + + // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) + drawFinderPattern(3, 3); + drawFinderPattern(size - 4, 3); + drawFinderPattern(3, size - 4); + + // Draw numerous alignment patterns + const vector alignPatPos = getAlignmentPatternPositions(); + size_t numAlign = alignPatPos.size(); + for (size_t i = 0; i < numAlign; i++) { + for (size_t j = 0; j < numAlign; j++) { + // Don't draw on the three finder corners + if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))) + drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j)); + } + } + + // Draw configuration data + drawFormatBits(0); // Dummy mask value; overwritten later in the constructor + drawVersion(); +} + + +void QrCode::drawFormatBits(int msk) { + // Calculate error correction code and pack bits + int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3 + int rem = data; + for (int i = 0; i < 10; i++) + rem = (rem << 1) ^ ((rem >> 9) * 0x537); + int bits = (data << 10 | rem) ^ 0x5412; // uint15 + assert(bits >> 15 == 0); + + // Draw first copy + for (int i = 0; i <= 5; i++) + setFunctionModule(8, i, getBit(bits, i)); + setFunctionModule(8, 7, getBit(bits, 6)); + setFunctionModule(8, 8, getBit(bits, 7)); + setFunctionModule(7, 8, getBit(bits, 8)); + for (int i = 9; i < 15; i++) + setFunctionModule(14 - i, 8, getBit(bits, i)); + + // Draw second copy + for (int i = 0; i < 8; i++) + setFunctionModule(size - 1 - i, 8, getBit(bits, i)); + for (int i = 8; i < 15; i++) + setFunctionModule(8, size - 15 + i, getBit(bits, i)); + setFunctionModule(8, size - 8, true); // Always dark +} + + +void QrCode::drawVersion() { + if (version < 7) + return; + + // Calculate error correction code and pack bits + int rem = version; // version is uint6, in the range [7, 40] + for (int i = 0; i < 12; i++) + rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); + long bits = static_cast(version) << 12 | rem; // uint18 + assert(bits >> 18 == 0); + + // Draw two copies + for (int i = 0; i < 18; i++) { + bool bit = getBit(bits, i); + int a = size - 11 + i % 3; + int b = i / 3; + setFunctionModule(a, b, bit); + setFunctionModule(b, a, bit); + } +} + + +void QrCode::drawFinderPattern(int x, int y) { + for (int dy = -4; dy <= 4; dy++) { + for (int dx = -4; dx <= 4; dx++) { + int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm + int xx = x + dx, yy = y + dy; + if (0 <= xx && xx < size && 0 <= yy && yy < size) + setFunctionModule(xx, yy, dist != 2 && dist != 4); + } + } +} + + +void QrCode::drawAlignmentPattern(int x, int y) { + for (int dy = -2; dy <= 2; dy++) { + for (int dx = -2; dx <= 2; dx++) + setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1); + } +} + + +void QrCode::setFunctionModule(int x, int y, bool isDark) { + size_t ux = static_cast(x); + size_t uy = static_cast(y); + modules .at(uy).at(ux) = isDark; + isFunction.at(uy).at(ux) = true; +} + + +bool QrCode::module(int x, int y) const { + return modules.at(static_cast(y)).at(static_cast(x)); +} + + +vector QrCode::addEccAndInterleave(const vector &data) const { + if (data.size() != static_cast(getNumDataCodewords(version, errorCorrectionLevel))) + throw std::invalid_argument("Invalid argument"); + + // Calculate parameter numbers + int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast(errorCorrectionLevel)][version]; + int blockEccLen = ECC_CODEWORDS_PER_BLOCK [static_cast(errorCorrectionLevel)][version]; + int rawCodewords = getNumRawDataModules(version) / 8; + int numShortBlocks = numBlocks - rawCodewords % numBlocks; + int shortBlockLen = rawCodewords / numBlocks; + + // Split data into blocks and append ECC to each block + vector > blocks; + const vector rsDiv = reedSolomonComputeDivisor(blockEccLen); + for (int i = 0, k = 0; i < numBlocks; i++) { + vector dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1))); + k += static_cast(dat.size()); + const vector ecc = reedSolomonComputeRemainder(dat, rsDiv); + if (i < numShortBlocks) + dat.push_back(0); + dat.insert(dat.end(), ecc.cbegin(), ecc.cend()); + blocks.push_back(std::move(dat)); + } + + // Interleave (not concatenate) the bytes from every block into a single sequence + vector result; + for (size_t i = 0; i < blocks.at(0).size(); i++) { + for (size_t j = 0; j < blocks.size(); j++) { + // Skip the padding byte in short blocks + if (i != static_cast(shortBlockLen - blockEccLen) || j >= static_cast(numShortBlocks)) + result.push_back(blocks.at(j).at(i)); + } + } + assert(result.size() == static_cast(rawCodewords)); + return result; +} + + +void QrCode::drawCodewords(const vector &data) { + if (data.size() != static_cast(getNumRawDataModules(version) / 8)) + throw std::invalid_argument("Invalid argument"); + + size_t i = 0; // Bit index into the data + // Do the funny zigzag scan + for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair + if (right == 6) + right = 5; + for (int vert = 0; vert < size; vert++) { // Vertical counter + for (int j = 0; j < 2; j++) { + size_t x = static_cast(right - j); // Actual x coordinate + bool upward = ((right + 1) & 2) == 0; + size_t y = static_cast(upward ? size - 1 - vert : vert); // Actual y coordinate + if (!isFunction.at(y).at(x) && i < data.size() * 8) { + modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast(i & 7)); + i++; + } + // If this QR Code has any remainder bits (0 to 7), they were assigned as + // 0/false/light by the constructor and are left unchanged by this method + } + } + } + assert(i == data.size() * 8); +} + + +void QrCode::applyMask(int msk) { + if (msk < 0 || msk > 7) + throw std::domain_error("Mask value out of range"); + size_t sz = static_cast(size); + for (size_t y = 0; y < sz; y++) { + for (size_t x = 0; x < sz; x++) { + bool invert; + switch (msk) { + case 0: invert = (x + y) % 2 == 0; break; + case 1: invert = y % 2 == 0; break; + case 2: invert = x % 3 == 0; break; + case 3: invert = (x + y) % 3 == 0; break; + case 4: invert = (x / 3 + y / 2) % 2 == 0; break; + case 5: invert = x * y % 2 + x * y % 3 == 0; break; + case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break; + case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break; + default: throw std::logic_error("Unreachable"); + } + modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x)); + } + } +} + + +long QrCode::getPenaltyScore() const { + long result = 0; + + // Adjacent modules in row having same color, and finder-like patterns + for (int y = 0; y < size; y++) { + bool runColor = false; + int runX = 0; + std::array runHistory = {}; + for (int x = 0; x < size; x++) { + if (module(x, y) == runColor) { + runX++; + if (runX == 5) + result += PENALTY_N1; + else if (runX > 5) + result++; + } else { + finderPenaltyAddHistory(runX, runHistory); + if (!runColor) + result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; + runColor = module(x, y); + runX = 1; + } + } + result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3; + } + // Adjacent modules in column having same color, and finder-like patterns + for (int x = 0; x < size; x++) { + bool runColor = false; + int runY = 0; + std::array runHistory = {}; + for (int y = 0; y < size; y++) { + if (module(x, y) == runColor) { + runY++; + if (runY == 5) + result += PENALTY_N1; + else if (runY > 5) + result++; + } else { + finderPenaltyAddHistory(runY, runHistory); + if (!runColor) + result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; + runColor = module(x, y); + runY = 1; + } + } + result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3; + } + + // 2*2 blocks of modules having same color + for (int y = 0; y < size - 1; y++) { + for (int x = 0; x < size - 1; x++) { + bool color = module(x, y); + if ( color == module(x + 1, y) && + color == module(x, y + 1) && + color == module(x + 1, y + 1)) + result += PENALTY_N2; + } + } + + // Balance of dark and light modules + int dark = 0; + for (const vector &row : modules) { + for (bool color : row) { + if (color) + dark++; + } + } + int total = size * size; // Note that size is odd, so dark/total != 1/2 + // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)% + int k = static_cast((std::abs(dark * 20L - total * 10L) + total - 1) / total) - 1; + assert(0 <= k && k <= 9); + result += k * PENALTY_N4; + assert(0 <= result && result <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4 + return result; +} + + +vector QrCode::getAlignmentPatternPositions() const { + if (version == 1) + return vector(); + else { + int numAlign = version / 7 + 2; + int step = (version == 32) ? 26 : + (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2; + vector result; + for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step) + result.insert(result.begin(), pos); + result.insert(result.begin(), 6); + return result; + } +} + + +int QrCode::getNumRawDataModules(int ver) { + if (ver < MIN_VERSION || ver > MAX_VERSION) + throw std::domain_error("Version number out of range"); + int result = (16 * ver + 128) * ver + 64; + if (ver >= 2) { + int numAlign = ver / 7 + 2; + result -= (25 * numAlign - 10) * numAlign - 55; + if (ver >= 7) + result -= 36; + } + assert(208 <= result && result <= 29648); + return result; +} + + +int QrCode::getNumDataCodewords(int ver, Ecc ecl) { + return getNumRawDataModules(ver) / 8 + - ECC_CODEWORDS_PER_BLOCK [static_cast(ecl)][ver] + * NUM_ERROR_CORRECTION_BLOCKS[static_cast(ecl)][ver]; +} + + +vector QrCode::reedSolomonComputeDivisor(int degree) { + if (degree < 1 || degree > 255) + throw std::domain_error("Degree out of range"); + // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. + // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}. + vector result(static_cast(degree)); + result.at(result.size() - 1) = 1; // Start off with the monomial x^0 + + // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), + // and drop the highest monomial term which is always 1x^degree. + // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). + uint8_t root = 1; + for (int i = 0; i < degree; i++) { + // Multiply the current product by (x - r^i) + for (size_t j = 0; j < result.size(); j++) { + result.at(j) = reedSolomonMultiply(result.at(j), root); + if (j + 1 < result.size()) + result.at(j) ^= result.at(j + 1); + } + root = reedSolomonMultiply(root, 0x02); + } + return result; +} + + +vector QrCode::reedSolomonComputeRemainder(const vector &data, const vector &divisor) { + vector result(divisor.size()); + for (uint8_t b : data) { // Polynomial division + uint8_t factor = b ^ result.at(0); + result.erase(result.begin()); + result.push_back(0); + for (size_t i = 0; i < result.size(); i++) + result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor); + } + return result; +} + + +uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) { + // Russian peasant multiplication + int z = 0; + for (int i = 7; i >= 0; i--) { + z = (z << 1) ^ ((z >> 7) * 0x11D); + z ^= ((y >> i) & 1) * x; + } + assert(z >> 8 == 0); + return static_cast(z); +} + + +int QrCode::finderPenaltyCountPatterns(const std::array &runHistory) const { + int n = runHistory.at(1); + assert(n <= size * 3); + bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n; + return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0) + + (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0); +} + + +int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array &runHistory) const { + if (currentRunColor) { // Terminate dark run + finderPenaltyAddHistory(currentRunLength, runHistory); + currentRunLength = 0; + } + currentRunLength += size; // Add light border to final run + finderPenaltyAddHistory(currentRunLength, runHistory); + return finderPenaltyCountPatterns(runHistory); +} + + +void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const { + if (runHistory.at(0) == 0) + currentRunLength += size; // Add light border to initial run + std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end()); + runHistory.at(0) = currentRunLength; +} + + +bool QrCode::getBit(long x, int i) { + return ((x >> i) & 1) != 0; +} + + +/*---- Tables of constants ----*/ + +const int QrCode::PENALTY_N1 = 3; +const int QrCode::PENALTY_N2 = 3; +const int QrCode::PENALTY_N3 = 40; +const int QrCode::PENALTY_N4 = 10; + + +const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = { + // Version: (note that index 0 is for padding, and is set to an illegal value) + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low + {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium + {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile + {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High +}; + +const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = { + // Version: (note that index 0 is for padding, and is set to an illegal value) + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low + {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium + {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile + {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High +}; + + +data_too_long::data_too_long(const std::string &msg) : + std::length_error(msg) {} + + + +/*---- Class BitBuffer ----*/ + +BitBuffer::BitBuffer() + : std::vector() {} + + +void BitBuffer::appendBits(std::uint32_t val, int len) { + if (len < 0 || len > 31 || val >> len != 0) + throw std::domain_error("Value out of range"); + for (int i = len - 1; i >= 0; i--) // Append bit by bit + this->push_back(((val >> i) & 1) != 0); +} + +std::string toSvgString(const QrCode &qr, int border) { + if (border < 0) + throw std::domain_error("Border must be non-negative"); + if (border > INT_MAX / 2 || border * 2 > INT_MAX - qr.getSize()) + throw std::overflow_error("Border too large"); + + std::ostringstream sb; + sb << "\n"; + sb << "\n"; + sb << "\n"; + sb << "\t\n"; + sb << "\t\n"; + sb << "\n"; + return sb.str(); +} +} diff --git a/client/3rd/qrcodegen/qrcodegen.hpp b/client/3rd/qrcodegen/qrcodegen.hpp new file mode 100644 index 000000000..f355edc75 --- /dev/null +++ b/client/3rd/qrcodegen/qrcodegen.hpp @@ -0,0 +1,551 @@ +/* + * QR Code generator library (C++) + * + * Copyright (c) Project Nayuki. (MIT License) + * https://www.nayuki.io/page/qr-code-generator-library + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * - The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * - The Software is provided "as is", without warranty of any kind, express or + * implied, including but not limited to the warranties of merchantability, + * fitness for a particular purpose and noninfringement. In no event shall the + * authors or copyright holders be liable for any claim, damages or other + * liability, whether in an action of contract, tort or otherwise, arising from, + * out of or in connection with the Software or the use or other dealings in the + * Software. + */ + +#pragma once + +#include +#include +#include +#include +#include + + +namespace qrcodegen { + +/* + * A segment of character/binary/control data in a QR Code symbol. + * Instances of this class are immutable. + * The mid-level way to create a segment is to take the payload data + * and call a static factory function such as QrSegment::makeNumeric(). + * The low-level way to create a segment is to custom-make the bit buffer + * and call the QrSegment() constructor with appropriate values. + * This segment class imposes no length restrictions, but QR Codes have restrictions. + * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. + * Any segment longer than this is meaningless for the purpose of generating QR Codes. + */ +class QrSegment final { + + /*---- Public helper enumeration ----*/ + + /* + * Describes how a segment's data bits are interpreted. Immutable. + */ + public: class Mode final { + + /*-- Constants --*/ + + public: static const Mode NUMERIC; + public: static const Mode ALPHANUMERIC; + public: static const Mode BYTE; + public: static const Mode KANJI; + public: static const Mode ECI; + + + /*-- Fields --*/ + + // The mode indicator bits, which is a uint4 value (range 0 to 15). + private: int modeBits; + + // Number of character count bits for three different version ranges. + private: int numBitsCharCount[3]; + + + /*-- Constructor --*/ + + private: Mode(int mode, int cc0, int cc1, int cc2); + + + /*-- Methods --*/ + + /* + * (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 to 15). + */ + public: int getModeBits() const; + + /* + * (Package-private) Returns the bit width of the character count field for a segment in + * this mode in a QR Code at the given version number. The result is in the range [0, 16]. + */ + public: int numCharCountBits(int ver) const; + + }; + + + + /*---- Static factory functions (mid level) ----*/ + + /* + * Returns a segment representing the given binary data encoded in + * byte mode. All input byte vectors are acceptable. Any text string + * can be converted to UTF-8 bytes and encoded as a byte mode segment. + */ + public: static QrSegment makeBytes(const std::vector &data); + + + /* + * Returns a segment representing the given string of decimal digits encoded in numeric mode. + */ + public: static QrSegment makeNumeric(const char *digits); + + + /* + * Returns a segment representing the given text string encoded in alphanumeric mode. + * The characters allowed are: 0 to 9, A to Z (uppercase only), space, + * dollar, percent, asterisk, plus, hyphen, period, slash, colon. + */ + public: static QrSegment makeAlphanumeric(const char *text); + + + /* + * Returns a list of zero or more segments to represent the given text string. The result + * may use various segment modes and switch modes to optimize the length of the bit stream. + */ + public: static std::vector makeSegments(const char *text); + + + /* + * Returns a segment representing an Extended Channel Interpretation + * (ECI) designator with the given assignment value. + */ + public: static QrSegment makeEci(long assignVal); + + + /*---- Public static helper functions ----*/ + + /* + * Tests whether the given string can be encoded as a segment in numeric mode. + * A string is encodable iff each character is in the range 0 to 9. + */ + public: static bool isNumeric(const char *text); + + + /* + * Tests whether the given string can be encoded as a segment in alphanumeric mode. + * A string is encodable iff each character is in the following set: 0 to 9, A to Z + * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. + */ + public: static bool isAlphanumeric(const char *text); + + + + /*---- Instance fields ----*/ + + /* The mode indicator of this segment. Accessed through getMode(). */ + private: const Mode *mode; + + /* The length of this segment's unencoded data. Measured in characters for + * numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. + * Always zero or positive. Not the same as the data's bit length. + * Accessed through getNumChars(). */ + private: int numChars; + + /* The data bits of this segment. Accessed through getData(). */ + private: std::vector data; + + + /*---- Constructors (low level) ----*/ + + /* + * Creates a new QR Code segment with the given attributes and data. + * The character count (numCh) must agree with the mode and the bit buffer length, + * but the constraint isn't checked. The given bit buffer is copied and stored. + */ + public: QrSegment(const Mode &md, int numCh, const std::vector &dt); + + + /* + * Creates a new QR Code segment with the given parameters and data. + * The character count (numCh) must agree with the mode and the bit buffer length, + * but the constraint isn't checked. The given bit buffer is moved and stored. + */ + public: QrSegment(const Mode &md, int numCh, std::vector &&dt); + + + /*---- Methods ----*/ + + /* + * Returns the mode field of this segment. + */ + public: const Mode &getMode() const; + + + /* + * Returns the character count field of this segment. + */ + public: int getNumChars() const; + + + /* + * Returns the data bits of this segment. + */ + public: const std::vector &getData() const; + + + // (Package-private) Calculates the number of bits needed to encode the given segments at + // the given version. Returns a non-negative number if successful. Otherwise returns -1 if a + // segment has too many characters to fit its length field, or the total bits exceeds INT_MAX. + public: static int getTotalBits(const std::vector &segs, int version); + + + /*---- Private constant ----*/ + + /* The set of all legal characters in alphanumeric mode, where + * each character value maps to the index in the string. */ + private: static const char *ALPHANUMERIC_CHARSET; + +}; + + + +/* + * A QR Code symbol, which is a type of two-dimension barcode. + * Invented by Denso Wave and described in the ISO/IEC 18004 standard. + * Instances of this class represent an immutable square grid of dark and light cells. + * The class provides static factory functions to create a QR Code from text or binary data. + * The class covers the QR Code Model 2 specification, supporting all versions (sizes) + * from 1 to 40, all 4 error correction levels, and 4 character encoding modes. + * + * Ways to create a QR Code object: + * - High level: Take the payload data and call QrCode::encodeText() or QrCode::encodeBinary(). + * - Mid level: Custom-make the list of segments and call QrCode::encodeSegments(). + * - Low level: Custom-make the array of data codeword bytes (including + * segment headers and final padding, excluding error correction codewords), + * supply the appropriate version number, and call the QrCode() constructor. + * (Note that all ways require supplying the desired error correction level.) + */ +class QrCode final { + + /*---- Public helper enumeration ----*/ + + /* + * The error correction level in a QR Code symbol. + */ + public: enum class Ecc { + LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords + MEDIUM , // The QR Code can tolerate about 15% erroneous codewords + QUARTILE, // The QR Code can tolerate about 25% erroneous codewords + HIGH , // The QR Code can tolerate about 30% erroneous codewords + }; + + + // Returns a value in the range 0 to 3 (unsigned 2-bit integer). + private: static int getFormatBits(Ecc ecl); + + + + /*---- Static factory functions (high level) ----*/ + + /* + * Returns a QR Code representing the given Unicode text string at the given error correction level. + * As a conservative upper bound, this function is guaranteed to succeed for strings that have 2953 or fewer + * UTF-8 code units (not Unicode code points) if the low error correction level is used. The smallest possible + * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than + * the ecl argument if it can be done without increasing the version. + */ + public: static QrCode encodeText(const char *text, Ecc ecl); + + + /* + * Returns a QR Code representing the given binary data at the given error correction level. + * This function always encodes using the binary segment mode, not any text mode. The maximum number of + * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output. + * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version. + */ + public: static QrCode encodeBinary(const std::vector &data, Ecc ecl); + + + /*---- Static factory functions (mid level) ----*/ + + /* + * Returns a QR Code representing the given segments with the given encoding parameters. + * The smallest possible QR Code version within the given range is automatically + * chosen for the output. Iff boostEcl is true, then the ECC level of the result + * may be higher than the ecl argument if it can be done without increasing the + * version. The mask number is either between 0 to 7 (inclusive) to force that + * mask, or -1 to automatically choose an appropriate mask (which may be slow). + * This function allows the user to create a custom sequence of segments that switches + * between modes (such as alphanumeric and byte) to encode text in less space. + * This is a mid-level API; the high-level API is encodeText() and encodeBinary(). + */ + public: static QrCode encodeSegments(const std::vector &segs, Ecc ecl, + int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters + + + + /*---- Instance fields ----*/ + + // Immutable scalar parameters: + + /* The version number of this QR Code, which is between 1 and 40 (inclusive). + * This determines the size of this barcode. */ + private: int version; + + /* The width and height of this QR Code, measured in modules, between + * 21 and 177 (inclusive). This is equal to version * 4 + 17. */ + private: int size; + + /* The error correction level used in this QR Code. */ + private: Ecc errorCorrectionLevel; + + /* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive). + * Even if a QR Code is created with automatic masking requested (mask = -1), + * the resulting object still has a mask value between 0 and 7. */ + private: int mask; + + // Private grids of modules/pixels, with dimensions of size*size: + + // The modules of this QR Code (false = light, true = dark). + // Immutable after constructor finishes. Accessed through getModule(). + private: std::vector > modules; + + // Indicates function modules that are not subjected to masking. Discarded when constructor finishes. + private: std::vector > isFunction; + + + + /*---- Constructor (low level) ----*/ + + /* + * Creates a new QR Code with the given version number, + * error correction level, data codeword bytes, and mask number. + * This is a low-level API that most users should not use directly. + * A mid-level API is the encodeSegments() function. + */ + public: QrCode(int ver, Ecc ecl, const std::vector &dataCodewords, int msk); + + + + /*---- Public instance methods ----*/ + + /* + * Returns this QR Code's version, in the range [1, 40]. + */ + public: int getVersion() const; + + + /* + * Returns this QR Code's size, in the range [21, 177]. + */ + public: int getSize() const; + + + /* + * Returns this QR Code's error correction level. + */ + public: Ecc getErrorCorrectionLevel() const; + + + /* + * Returns this QR Code's mask, in the range [0, 7]. + */ + public: int getMask() const; + + + /* + * Returns the color of the module (pixel) at the given coordinates, which is false + * for light or true for dark. The top left corner has the coordinates (x=0, y=0). + * If the given coordinates are out of bounds, then false (light) is returned. + */ + public: bool getModule(int x, int y) const; + + + + /*---- Private helper methods for constructor: Drawing function modules ----*/ + + // Reads this object's version field, and draws and marks all function modules. + private: void drawFunctionPatterns(); + + + // Draws two copies of the format bits (with its own error correction code) + // based on the given mask and this object's error correction level field. + private: void drawFormatBits(int msk); + + + // Draws two copies of the version bits (with its own error correction code), + // based on this object's version field, iff 7 <= version <= 40. + private: void drawVersion(); + + + // Draws a 9*9 finder pattern including the border separator, + // with the center module at (x, y). Modules can be out of bounds. + private: void drawFinderPattern(int x, int y); + + + // Draws a 5*5 alignment pattern, with the center module + // at (x, y). All modules must be in bounds. + private: void drawAlignmentPattern(int x, int y); + + + // Sets the color of a module and marks it as a function module. + // Only used by the constructor. Coordinates must be in bounds. + private: void setFunctionModule(int x, int y, bool isDark); + + + // Returns the color of the module at the given coordinates, which must be in range. + private: bool module(int x, int y) const; + + + /*---- Private helper methods for constructor: Codewords and masking ----*/ + + // Returns a new byte string representing the given data with the appropriate error correction + // codewords appended to it, based on this object's version and error correction level. + private: std::vector addEccAndInterleave(const std::vector &data) const; + + + // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire + // data area of this QR Code. Function modules need to be marked off before this is called. + private: void drawCodewords(const std::vector &data); + + + // XORs the codeword modules in this QR Code with the given mask pattern. + // The function modules must be marked and the codeword bits must be drawn + // before masking. Due to the arithmetic of XOR, calling applyMask() with + // the same mask value a second time will undo the mask. A final well-formed + // QR Code needs exactly one (not zero, two, etc.) mask applied. + private: void applyMask(int msk); + + + // Calculates and returns the penalty score based on state of this QR Code's current modules. + // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. + private: long getPenaltyScore() const; + + + + /*---- Private helper functions ----*/ + + // Returns an ascending list of positions of alignment patterns for this version number. + // Each position is in the range [0,177), and are used on both the x and y axes. + // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. + private: std::vector getAlignmentPatternPositions() const; + + + // Returns the number of data bits that can be stored in a QR Code of the given version number, after + // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. + // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. + private: static int getNumRawDataModules(int ver); + + + // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any + // QR Code of the given version number and error correction level, with remainder bits discarded. + // This stateless pure function could be implemented as a (40*4)-cell lookup table. + private: static int getNumDataCodewords(int ver, Ecc ecl); + + + // Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be + // implemented as a lookup table over all possible parameter values, instead of as an algorithm. + private: static std::vector reedSolomonComputeDivisor(int degree); + + + // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials. + private: static std::vector reedSolomonComputeRemainder(const std::vector &data, const std::vector &divisor); + + + // Returns the product of the two given field elements modulo GF(2^8/0x11D). + // All inputs are valid. This could be implemented as a 256*256 lookup table. + private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y); + + + // Can only be called immediately after a light run is added, and + // returns either 0, 1, or 2. A helper function for getPenaltyScore(). + private: int finderPenaltyCountPatterns(const std::array &runHistory) const; + + + // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). + private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array &runHistory) const; + + + // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). + private: void finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const; + + + // Returns true iff the i'th bit of x is set to 1. + private: static bool getBit(long x, int i); + + + /*---- Constants and tables ----*/ + + // The minimum version number supported in the QR Code Model 2 standard. + public: static constexpr int MIN_VERSION = 1; + + // The maximum version number supported in the QR Code Model 2 standard. + public: static constexpr int MAX_VERSION = 40; + + + // For use in getPenaltyScore(), when evaluating which mask is best. + private: static const int PENALTY_N1; + private: static const int PENALTY_N2; + private: static const int PENALTY_N3; + private: static const int PENALTY_N4; + + + private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41]; + private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41]; + +}; + + + +/*---- Public exception class ----*/ + +/* + * Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception include: + * - Decrease the error correction level if it was greater than Ecc::LOW. + * - If the encodeSegments() function was called with a maxVersion argument, then increase + * it if it was less than QrCode::MAX_VERSION. (This advice does not apply to the other + * factory functions because they search all versions up to QrCode::MAX_VERSION.) + * - Split the text data into better or optimal segments in order to reduce the number of bits required. + * - Change the text or binary data to be shorter. + * - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric). + * - Propagate the error upward to the caller/user. + */ +class data_too_long : public std::length_error { + + public: explicit data_too_long(const std::string &msg); + +}; + + + +/* + * An appendable sequence of bits (0s and 1s). Mainly used by QrSegment. + */ +class BitBuffer final : public std::vector { + + /*---- Constructor ----*/ + + // Creates an empty bit buffer (length 0). + public: BitBuffer(); + + + + /*---- Method ----*/ + + // Appends the given number of low-order bits of the given value + // to this buffer. Requires 0 <= len <= 31 and val < 2^len. + public: void appendBits(std::uint32_t val, int len); + +}; + +std::string toSvgString(const QrCode &qr, int border); + +} diff --git a/client/3rd/qrcodegen/qrcodegen.pri b/client/3rd/qrcodegen/qrcodegen.pri new file mode 100644 index 000000000..da50cb98d --- /dev/null +++ b/client/3rd/qrcodegen/qrcodegen.pri @@ -0,0 +1,5 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD + +HEADERS += $$PWD/qrcodegen.hpp +SOURCES += $$PWD/qrcodegen.cpp diff --git a/client/3rd/qzxing b/client/3rd/qzxing deleted file mode 160000 index 2fd4dd60c..000000000 --- a/client/3rd/qzxing +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2fd4dd60c04a29c6d1271fdd9ae25378b8f61ec8 diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index 4420f7dc3..334582cb5 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -6,8 +6,6 @@ #include -#include "QZXing.h" - #include "core/servercontroller.h" #include "debug.h" #include "defines.h" @@ -141,8 +139,6 @@ void AmneziaApplication::init() void AmneziaApplication::registerTypes() { - QZXing::registerQMLTypes(); - qRegisterMetaType("VpnProtocol::VpnConnectionState"); qRegisterMetaType("ServerCredentials"); diff --git a/client/client.pro b/client/client.pro index 9a89842d4..14a78e166 100644 --- a/client/client.pro +++ b/client/client.pro @@ -19,7 +19,7 @@ include("3rd/QtSsh/src/ssh/qssh.pri") include("3rd/QtSsh/src/botan/botan.pri") !android:!ios:include("3rd/SingleApplication/singleapplication.pri") include ("3rd/SortFilterProxyModel/SortFilterProxyModel.pri") -include("3rd/qzxing/src/QZXing-components.pri") +include("3rd/qrcodegen/qrcodegen.pri") include("3rd/QSimpleCrypto/QSimpleCrypto.pri") include("3rd/qtkeychain/qtkeychain.pri") diff --git a/client/ui/pages_logic/ShareConnectionLogic.cpp b/client/ui/pages_logic/ShareConnectionLogic.cpp index 6367722ac..85849391d 100644 --- a/client/ui/pages_logic/ShareConnectionLogic.cpp +++ b/client/ui/pages_logic/ShareConnectionLogic.cpp @@ -1,12 +1,9 @@ #include #include #include -//#include #include -#include "QZXing.h" -#include "QZXingImageProvider.h" -#include "QZXingFilter.h" +#include "qrcodegen.hpp" #include "ShareConnectionLogic.h" @@ -30,6 +27,8 @@ #include #endif +using namespace qrcodegen; + ShareConnectionLogic::ShareConnectionLogic(UiLogic *logic, QObject *parent): PageLogicBase(logic, parent), m_textEditShareOpenVpnCodeText{}, @@ -168,8 +167,10 @@ void ShareConnectionLogic::onPushButtonShareShadowSocksGenerateClicked() ssString = "ss://" + ssString.toUtf8().toBase64(); set_lineEditShareShadowSocksStringText(ssString); - QImage qr = QZXing::encodeData(ssString.toUtf8(), QZXing::EncoderFormat_QR_CODE, QSize(512,512), QZXing::EncodeErrorCorrectionLevel_L); - set_shareShadowSocksQrCodeText(imageToBase64(qr)); + QrCode qr = QrCode::encodeText(ssString.toUtf8(), QrCode::Ecc::LOW); + QString svg = QString::fromStdString(toSvgString(qr, 0)); + + set_shareShadowSocksQrCodeText(svgToBase64(svg)); QString humanString = QString("Server: %3\n" "Port: %4\n" @@ -227,9 +228,10 @@ void ShareConnectionLogic::onPushButtonShareWireGuardGenerateClicked() set_textEditShareWireGuardCodeText(cfg); - QImage qr = QZXing::encodeData(cfg.toUtf8(), QZXing::EncoderFormat_QR_CODE, QSize(512,512), QZXing::EncodeErrorCorrectionLevel_L); + QrCode qr = QrCode::encodeText(cfg.toUtf8(), QrCode::Ecc::LOW); + QString svg = QString::fromStdString(toSvgString(qr, 0)); - set_shareWireGuardQrCodeText(imageToBase64(qr)); + set_shareWireGuardQrCodeText(svgToBase64(svg)); } void ShareConnectionLogic::onPushButtonShareIkev2GenerateClicked() @@ -267,7 +269,7 @@ void ShareConnectionLogic::updateSharingPage(int serverIndex, DockerContainer co QList ShareConnectionLogic::genQrCodeImageSeries(const QByteArray &data) { - double k = 1500; + double k = 850; quint8 chunksCount = std::ceil(data.size() / k); QList chunks; @@ -278,18 +280,15 @@ QList ShareConnectionLogic::genQrCodeImageSeries(const QByteArray &data QByteArray ba = chunk.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); - QImage qr = QZXing::encodeData(ba, QZXing::EncoderFormat_QR_CODE, QSize(512,512), QZXing::EncodeErrorCorrectionLevel_L); - chunks.append(imageToBase64(qr)); + QrCode qr = QrCode::encodeText(ba, QrCode::Ecc::LOW); + QString svg = QString::fromStdString(toSvgString(qr, 0)); + chunks.append(svgToBase64(svg)); } return chunks; } -QString ShareConnectionLogic::imageToBase64(const QImage &image) +QString ShareConnectionLogic::svgToBase64(const QString &image) { - QByteArray ba; - QBuffer bu(&ba); - bu.open(QIODevice::WriteOnly); - image.save(&bu, "PNG"); - return "data:image/png;base64," + QString::fromLatin1(ba.toBase64().data()); + return "data:image/svg;base64," + QString::fromLatin1(image.toUtf8().toBase64().data()); } diff --git a/client/ui/pages_logic/ShareConnectionLogic.h b/client/ui/pages_logic/ShareConnectionLogic.h index a167b43e2..5d46be974 100644 --- a/client/ui/pages_logic/ShareConnectionLogic.h +++ b/client/ui/pages_logic/ShareConnectionLogic.h @@ -49,8 +49,7 @@ public: void updateSharingPage(int serverIndex, DockerContainer container); QList genQrCodeImageSeries(const QByteArray &data); - QString imageToBase64(const QImage &image); - + QString svgToBase64(const QString &image); }; #endif // SHARE_CONNECTION_LOGIC_H From b356522f94c8064be20749cbe30c732cd711ffd2 Mon Sep 17 00:00:00 2001 From: pokamest Date: Fri, 9 Sep 2022 15:01:11 +0300 Subject: [PATCH 45/52] Secure settings crash fix --- client/secure_qsettings.cpp | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index a58ae7c47..d038be6b2 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "utils.h" #include @@ -222,35 +223,39 @@ QByteArray SecureQSettings::getEncIv() const QByteArray SecureQSettings::getSecTag(const QString &tag) { - ReadPasswordJob job(keyChainName); - job.setAutoDelete(false); - job.setKey(tag); + auto job = QSharedPointer(new ReadPasswordJob(keyChainName), &QObject::deleteLater); + job->setAutoDelete(false); + job->setKey(tag); QEventLoop loop; - job.connect(&job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit())); - job.start(); + job->connect(job.data(), &ReadPasswordJob::finished, job.data(), [&loop](){ + loop.quit(); + }); + job->start(); loop.exec(); - if ( job.error() ) { - qCritical() << "SecureQSettings::getSecTag Error:" << job.errorString(); + if ( job->error() ) { + qCritical() << "SecureQSettings::getSecTag Error:" << job->errorString(); } - return job.binaryData(); + return job->binaryData(); } void SecureQSettings::setSecTag(const QString &tag, const QByteArray &data) { - WritePasswordJob job(keyChainName); - job.setAutoDelete(false); - job.setKey(tag); - job.setBinaryData(data); + auto job = QSharedPointer(new WritePasswordJob(keyChainName), &QObject::deleteLater); + job->setAutoDelete(false); + job->setKey(tag); + job->setBinaryData(data); QEventLoop loop; QTimer::singleShot(1000, &loop, SLOT(quit())); - job.connect(&job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit())); - job.start(); + job->connect(job.data(), &WritePasswordJob::finished, job.data(), [&loop](){ + loop.quit(); + }); + job->start(); loop.exec(); - if (job.error()) { - qCritical() << "SecureQSettings::setSecTag Error:" << job.errorString(); + if (job->error()) { + qCritical() << "SecureQSettings::setSecTag Error:" << job->errorString(); } } From 8cea93de94b20e9b47671e3f7e49825f8e049518 Mon Sep 17 00:00:00 2001 From: pokamest Date: Fri, 9 Sep 2022 15:34:09 +0300 Subject: [PATCH 46/52] Travis build fix --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 60c954c74..1f1affd6f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,10 +23,10 @@ jobs: if [ ! -f $QT_BIN_DIR/qmake ]; then \ brew install p7zip ccache && \ python3 -m pip install --upgrade pip && \ - pip install -U aqtinstall requests py7zr && \ - pip show aqtinstall && \ - aqt install-qt mac desktop $QT_VERSION clang_64 -m all -O $HOME/Qt && \ - aqt install-tool mac desktop tools_ifw -O $HOME/Qt ; \ + python3 -m pip install -U aqtinstall requests py7zr && \ + python3 -m pip show aqtinstall && \ + python3 -m aqt install-qt mac desktop $QT_VERSION clang_64 -m all -O $HOME/Qt && \ + python3 -m aqt install-tool mac desktop tools_ifw -O $HOME/Qt ; \ fi script: @@ -314,9 +314,9 @@ jobs: if [ ! -f $QT_BIN_DIR/qmake ]; then \ brew install p7zip ccache && \ python3 -m pip install --upgrade pip && \ - pip install -U aqtinstall requests py7zr && \ - pip show aqtinstall && \ - aqt install-qt mac ios $QT_VERSION -m all -O $HOME/Qt ; \ + python3 -m pip install -U aqtinstall requests py7zr && \ + python3 -m pip show aqtinstall && \ + python3 -m aqt install-qt mac ios $QT_VERSION -m all -O $HOME/Qt ; \ fi - brew install golang - go install golang.org/x/mobile/cmd/gomobile@latest From c5ba89b05425154af8b4943a098c825d587df9b9 Mon Sep 17 00:00:00 2001 From: pokamest Date: Sat, 10 Sep 2022 19:57:44 +0300 Subject: [PATCH 47/52] Code cleanup --- .travis.yml | 1 + client/client.pro | 5 -- client/main.cpp | 8 ---- client/platforms/android/native.cpp | 54 ---------------------- client/platforms/android/native.h | 20 -------- client/ui/qml/Pages/PageNetworkSetting.qml | 2 +- client/ui/qml/Pages/PageStart.qml | 1 + 7 files changed, 3 insertions(+), 88 deletions(-) delete mode 100644 client/platforms/android/native.cpp delete mode 100644 client/platforms/android/native.h diff --git a/.travis.yml b/.travis.yml index 1f1affd6f..35c941084 100644 --- a/.travis.yml +++ b/.travis.yml @@ -164,6 +164,7 @@ jobs: # ------------------------------------------------------ - name: Linux os: linux + language: cpp dist: focal addons: diff --git a/client/client.pro b/client/client.pro index 14a78e166..bf9db7ed2 100644 --- a/client/client.pro +++ b/client/client.pro @@ -11,9 +11,6 @@ IS_CI=$$(CI) } CONFIG += qtquickcompiler -CONFIG += qzxing_multimedia \ - enable_decoder_qr_code \ - enable_encoder_qr_code include("3rd/QtSsh/src/ssh/qssh.pri") include("3rd/QtSsh/src/botan/botan.pri") @@ -247,13 +244,11 @@ android { INCLUDEPATH += platforms/android HEADERS += \ - platforms/android/native.h \ platforms/android/android_controller.h \ platforms/android/android_notificationhandler.h \ protocols/android_vpnprotocol.h SOURCES += \ - platforms/android/native.cpp \ platforms/android/android_controller.cpp \ platforms/android/android_notificationhandler.cpp \ protocols/android_vpnprotocol.cpp diff --git a/client/main.cpp b/client/main.cpp index a5751979e..62685953b 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -9,10 +9,6 @@ #include "Windows.h" #endif -#if defined(Q_OS_ANDROID) -#include "native.h" -#endif - #if defined(Q_OS_IOS) #include "platforms/ios/QtAppDelegate-C-Interface.h" #endif @@ -46,10 +42,6 @@ int main(int argc, char *argv[]) AllowSetForegroundWindow(0); #endif -#if defined(Q_OS_ANDROID) - NativeHelpers::registerApplicationInstance(&app); -#endif - #if defined(Q_OS_IOS) QtAppDelegateInitialize(); #endif diff --git a/client/platforms/android/native.cpp b/client/platforms/android/native.cpp deleted file mode 100644 index 60ff2d8b7..000000000 --- a/client/platforms/android/native.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "native.h" -#include -#if defined(Q_OS_ANDROID) - #include -#endif // Q_OS_ANDROID - - -QObject *NativeHelpers::application_p_ = 0; - -#if defined(Q_OS_ANDROID) - -// define our native static functions -// these are the functions that Java part will call directly from Android UI thread -static void onPermissionsGranted(JNIEnv * /*env*/, jobject /*obj*/) -{ - QMetaObject::invokeMethod(NativeHelpers::getApplicationInstance(), "onPermissionsGranted" - , Qt::QueuedConnection); -} - -static void onPermissionsDenied(JNIEnv * /*env*/, jobject /*obj*/) -{ - QMetaObject::invokeMethod(NativeHelpers::getApplicationInstance(), "onPermissionsDenied" - , Qt::QueuedConnection); -} - -//create a vector with all our JNINativeMethod(s) -static JNINativeMethod methods[] = { - {"onPermissionsGranted", "()V", (void *)onPermissionsGranted}, - {"onPermissionsDenied", "()V", (void *)onPermissionsDenied}, -}; - -// this method is called automatically by Java after the .so file is loaded -JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) -{ - JNIEnv* env; - // get the JNIEnv pointer. - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) - return JNI_ERR; - - // search for Java class which declares the native methods - jclass javaClass = env->FindClass("org/ftylitak/qzxing/NativeFunctions"); - if (!javaClass) - return JNI_ERR; - - // register our native methods - if (env->RegisterNatives(javaClass, methods, - sizeof(methods) / sizeof(methods[0])) < 0) { - return JNI_ERR; - } - - return JNI_VERSION_1_6; -} - -#endif // Q_OS_ANDROID diff --git a/client/platforms/android/native.h b/client/platforms/android/native.h deleted file mode 100644 index db187a737..000000000 --- a/client/platforms/android/native.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef NATIVE_H -#define NATIVE_H - -#include - -class NativeHelpers { -public: - static void registerApplicationInstance(QObject *app_p) { - application_p_ = app_p; - } - - static QObject* getApplicationInstance() { - return application_p_; - } - -private: - static QObject *application_p_; -}; - -#endif // NATIVE_H diff --git a/client/ui/qml/Pages/PageNetworkSetting.qml b/client/ui/qml/Pages/PageNetworkSetting.qml index 924b32dde..0e8904468 100644 --- a/client/ui/qml/Pages/PageNetworkSetting.qml +++ b/client/ui/qml/Pages/PageNetworkSetting.qml @@ -87,7 +87,7 @@ If AmneziaDNS service is not installed on the same server, or this option is unc anchors.topMargin: 20 width: parent.width - 60 height: 21 - text: qsTr("Secondray DNS server") + text: qsTr("Secondary DNS server") } TextFieldType { id: dns2 diff --git a/client/ui/qml/Pages/PageStart.qml b/client/ui/qml/Pages/PageStart.qml index ab53792d2..d7f2a49ce 100644 --- a/client/ui/qml/Pages/PageStart.qml +++ b/client/ui/qml/Pages/PageStart.qml @@ -127,6 +127,7 @@ PageBase { BlueButtonType { id: qr_code_import + visible: GC.isMobile() anchors.horizontalCenter: parent.horizontalCenter anchors.top: qr_code_import_open.bottom anchors.topMargin: 10 From 9cfc65eeda920b0e467e849501b059129407d1b7 Mon Sep 17 00:00:00 2001 From: pokamest Date: Sun, 11 Sep 2022 00:24:43 +0300 Subject: [PATCH 48/52] Version bump --- client/defines.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/defines.h b/client/defines.h index 4334c68fd..c64eb4584 100644 --- a/client/defines.h +++ b/client/defines.h @@ -4,7 +4,7 @@ #define APPLICATION_NAME "AmneziaVPN" #define SERVICE_NAME "AmneziaVPN-service" #define ORGANIZATION_NAME "AmneziaVPN.ORG" -#define APP_MAJOR_VERSION "2.1.0" -#define APP_VERSION "2.1.0.0" +#define APP_MAJOR_VERSION "2.1.2" +#define APP_VERSION "2.1.2.0" #endif // DEFINES_H From 53e240add72904c586d02ae706398c72dd233c12 Mon Sep 17 00:00:00 2001 From: pokamest Date: Mon, 12 Sep 2022 14:57:00 +0300 Subject: [PATCH 49/52] Android manifest fix --- client/android/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/android/AndroidManifest.xml b/client/android/AndroidManifest.xml index 1c112d2f2..cb70759dc 100644 --- a/client/android/AndroidManifest.xml +++ b/client/android/AndroidManifest.xml @@ -19,7 +19,7 @@ - + From 5fff65db5ae6f90f6e197b77a96f82f8a046de76 Mon Sep 17 00:00:00 2001 From: pokamest Date: Mon, 19 Sep 2022 00:44:00 +0300 Subject: [PATCH 50/52] Tiny fixes --- .travis.yml | 1 + client/configurators/wireguard_configurator.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 35c941084..9e16ef5f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -217,6 +217,7 @@ jobs: - ccache - directories: - $HOME/Qt + - $HOME/.ccache # ------------------------------------------------------ - name: Android diff --git a/client/configurators/wireguard_configurator.cpp b/client/configurators/wireguard_configurator.cpp index 08e6c40a4..913299c75 100644 --- a/client/configurators/wireguard_configurator.cpp +++ b/client/configurators/wireguard_configurator.cpp @@ -80,7 +80,12 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon stdOut += data + "\n"; }; - m_serverController->runContainerScript(credentials, container, script, cbReadStdOut); + e = m_serverController->runContainerScript(credentials, container, script, cbReadStdOut); + if (errorCode && e) { + *errorCode = e; + return connData; + } + stdOut.replace("AllowedIPs = ", ""); stdOut.replace("/32", ""); QStringList ips = stdOut.split("\n", Qt::SkipEmptyParts); From d93be76505b5ae2d7d1aefa90f40829066dc27a3 Mon Sep 17 00:00:00 2001 From: Mykola Baibuz Date: Mon, 19 Sep 2022 12:27:33 +0300 Subject: [PATCH 51/52] Add auth protection for ssh key export We use a builtin keyguard for ssh key export protection on Android. This protection works only if some protection is set on the phone. https://developer.android.com/reference/android/app/KeyguardManager#isDeviceSecure() --- .../src/org/amnezia/vpn/AuthHelper.java | 24 ++++++++++++ client/ui/pages_logic/ServerSettingsLogic.cpp | 39 +++++++++++++++++++ client/ui/pages_logic/ServerSettingsLogic.h | 25 ++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 client/android/src/org/amnezia/vpn/AuthHelper.java diff --git a/client/android/src/org/amnezia/vpn/AuthHelper.java b/client/android/src/org/amnezia/vpn/AuthHelper.java new file mode 100644 index 000000000..b30aa8f50 --- /dev/null +++ b/client/android/src/org/amnezia/vpn/AuthHelper.java @@ -0,0 +1,24 @@ +package org.amnezia.vpn; + +import android.content.Context; +import android.app.KeyguardManager; +import android.content.Intent; +import org.qtproject.qt5.android.bindings.QtActivity; + + +import static android.content.Context.KEYGUARD_SERVICE; + +public class AuthHelper extends QtActivity { + + static final String TAG = "AuthHelper"; + + public static Intent getAuthIntent(Context context) { + KeyguardManager mKeyguardManager = (KeyguardManager)context.getSystemService(KEYGUARD_SERVICE); + if (mKeyguardManager.isDeviceSecure()) { + return mKeyguardManager.createConfirmDeviceCredentialIntent(null, null); + } else { + return null; + } + } + +} diff --git a/client/ui/pages_logic/ServerSettingsLogic.cpp b/client/ui/pages_logic/ServerSettingsLogic.cpp index bd954c882..3b123174a 100644 --- a/client/ui/pages_logic/ServerSettingsLogic.cpp +++ b/client/ui/pages_logic/ServerSettingsLogic.cpp @@ -10,6 +10,12 @@ #include #include +#if defined(Q_OS_ANDROID) +#include +#include +#include +#endif + ServerSettingsLogic::ServerSettingsLogic(UiLogic *logic, QObject *parent): PageLogicBase(logic, parent), m_labelWaitInfoVisible{true}, @@ -126,8 +132,41 @@ void ServerSettingsLogic::onLineEditDescriptionEditingFinished() uiLogic()->onUpdateAllPages(); } +#if defined(Q_OS_ANDROID) +/* Auth result handler for Android */ +void authResultReceiver::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) +{ + qDebug() << "receiverRequestCode" << receiverRequestCode << "resultCode" << resultCode; + + if (resultCode == -1) { //ResultOK + uiLogic()->pageLogic()->updateSharingPage(m_serverIndex, DockerContainer::None); + emit uiLogic()->goToShareProtocolPage(Proto::Any); + } +} +#endif + void ServerSettingsLogic::onPushButtonShareFullClicked() { +#if defined(Q_OS_ANDROID) +/* We use builtin keyguard for ssh key export protection on Android */ + auto appContext = QtAndroid::androidActivity().callObjectMethod( + "getApplicationContext", "()Landroid/content/Context;"); + if (appContext.isValid()) { + QAndroidActivityResultReceiver *receiver = new authResultReceiver(uiLogic(), uiLogic()->selectedServerIndex); + auto intent = QAndroidJniObject::callStaticObjectMethod( + "org/amnezia/vpn/AuthHelper", "getAuthIntent", + "(Landroid/content/Context;)Landroid/content/Intent;", appContext.object()); + if (intent.isValid()) { + if (intent.object() != nullptr) { + QtAndroid::startActivity(intent.object(), 1, receiver); + } + } else { + uiLogic()->pageLogic()->updateSharingPage(uiLogic()->selectedServerIndex, DockerContainer::None); + emit uiLogic()->goToShareProtocolPage(Proto::Any); + } + } +#else uiLogic()->pageLogic()->updateSharingPage(uiLogic()->selectedServerIndex, DockerContainer::None); emit uiLogic()->goToShareProtocolPage(Proto::Any); +#endif } diff --git a/client/ui/pages_logic/ServerSettingsLogic.h b/client/ui/pages_logic/ServerSettingsLogic.h index 282b90ea0..e2d574224 100644 --- a/client/ui/pages_logic/ServerSettingsLogic.h +++ b/client/ui/pages_logic/ServerSettingsLogic.h @@ -3,6 +3,10 @@ #include "PageLogicBase.h" +#if defined(Q_OS_ANDROID) +#include +#endif + class UiLogic; class ServerSettingsLogic : public PageLogicBase @@ -34,4 +38,25 @@ public: ~ServerSettingsLogic() = default; }; + +#if defined(Q_OS_ANDROID) +/* Auth result handler for Android */ +class authResultReceiver final : public PageLogicBase, public QAndroidActivityResultReceiver +{ +Q_OBJECT + +public: + authResultReceiver(UiLogic *uiLogic, int serverIndex , QObject *parent = nullptr) : PageLogicBase(uiLogic, parent) { + m_serverIndex = serverIndex; + } + ~authResultReceiver() {} + +public: + void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) override; + +private: + int m_serverIndex; +}; +#endif + #endif // SERVER_SETTINGS_LOGIC_H From f2d7a45b74e42a69070d08d65052b293af3ea4ef Mon Sep 17 00:00:00 2001 From: Mykola Baibuz Date: Fri, 23 Sep 2022 21:50:25 +0300 Subject: [PATCH 52/52] Set security screen for Android app This will guarantee that even apps running with root privileges are unable to directly capture information displayed by the app on the screen. --- client/ui/pages_logic/StartPageLogic.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index de3173b59..1e28d6cde 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -11,6 +11,7 @@ #include #ifdef Q_OS_ANDROID +#include #include "platforms/android/android_controller.h" #endif @@ -23,7 +24,16 @@ StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent): m_pushButtonBackFromStartVisible{true}, m_ipAddressPortRegex{Utils::ipAddressPortRegExp()} { - +#ifdef Q_OS_ANDROID + // Set security screen for Android app + QtAndroid::runOnAndroidThread([]() { + QAndroidJniObject window = QtAndroid::androidActivity().callObjectMethod("getWindow", "()Landroid/view/Window;"); + if (window.isValid()){ + const int FLAG_SECURE = 8192; + window.callMethod("addFlags", "(I)V", FLAG_SECURE); + } + }); +#endif } void StartPageLogic::onUpdatePage()