diff --git a/.gitmodules b/.gitmodules index 008ebf89..328bfe76 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/.travis.yml b/.travis.yml index b7f08e04..c5022b12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,9 @@ jobs: os: osx osx_image: xcode13.4 language: cpp - + env: + - PATH=/usr/local/opt/ccache/libexec:$PATH - QT_VERSION=5.15.2 - QIF_VERSION=4.4 - QT_BIN_DIR=$HOME/Qt/$QT_VERSION/clang_64/bin @@ -19,8 +20,8 @@ jobs: install: - | - if [ ! -f $HOME/Qt/$QT_VERSION/clang_64/bin/qmake ]; then \ - brew install p7zip && \ + 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 && \ @@ -31,6 +32,9 @@ jobs: script: - bash deploy/build_macos.sh + after_script: + - ccache --show-stats + deploy: provider: releases token: $GH_TOKEN @@ -41,6 +45,12 @@ jobs: tags: true branch: master + cache: + - ccache + - directories: + - $HOME/Qt + - $HOME/Library/Caches/Homebrew + # ------------------------------------------------------ - name: Windows_x64 os: windows @@ -87,6 +97,11 @@ jobs: tags: true branch: master + cache: + directories: + - /C/Qt + - $MSVC_PATH + # ------------------------------------------------------ - name: Windows_x32 os: windows @@ -133,9 +148,25 @@ jobs: tags: true branch: master + cache: + directories: + - /C/Qt + - $MSVC_PATH + # ------------------------------------------------------ - name: Linux os: linux + dist: focal + + addons: + apt: + packages: + - p7zip + - python3 + - python3-pip + - libgl-dev + - mesa-common-dev + - libpulse-dev env: - QT_VERSION=5.15.2 @@ -145,19 +176,21 @@ jobs: install: - | - if [ ! -f $HOME/Qt/$QT_VERSION/gcc_64/bin/qmake ]; then \ - sudo apt-get update && \ - sudo apt install -yy p7zip python3 python3-pip && \ - python3 -m pip install --upgrade pip && \ - pip install -U aqtinstall requests py7zr && \ - pip show aqtinstall && \ - python3 -m aqt install-qt linux desktop $QT_VERSION clang_64 -m all -O $HOME/Qt && \ + if [ ! -f $QT_BIN_DIR/qmake ]; then \ + python3 -m pip install --user $(whoami) --upgrade pip && \ + 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 desktop $QT_VERSION gcc_64 -m all -O $HOME/Qt && \ python3 -m aqt install-tool linux desktop tools_ifw -O $HOME/Qt ; \ fi script: - bash deploy/build_linux.sh + after_script: + - ccache --show-stats + deploy: provider: releases token: $GH_TOKEN @@ -168,28 +201,42 @@ jobs: tags: true branch: master + cache: + - ccache + - directories: + - $HOME/Qt + # ------------------------------------------------------ - name: Android os: linux language: android + dist: xenial - components: - # Uncomment the lines below if you want to - # use the latest revision of Android SDK Tools - # - tools - # - platform-tools + addons: + apt: + packages: + - p7zip + - python3 + - python3-pip - # The BuildTools version used by your project - - build-tools-30.0.2 + android: + components: + # Uncomment the lines below if you want to + # use the latest revision of Android SDK Tools + # - tools + # - platform-tools - # The SDK version used to compile your project - - android-30 + # The BuildTools version used by your project + - build-tools-30.0.2 - # Additional components - - extra - - extra-google-google_play_services - - extra-google-m2repository - - extra-android-m2repository + # The SDK version used to compile your project + - android-30 + + # Additional components + - extra + - extra-google-google_play_services + - extra-google-m2repository + - extra-android-m2repository env: - QT_VERSION=5.15.2 @@ -199,12 +246,10 @@ jobs: install: - | - if [ ! -f $HOME/Qt/$QT_VERSION/android/bin/qmake ]; then \ - sudo apt-get update && \ - sudo apt install -yy p7zip python3 python3-pip && \ - python3 -m pip install --upgrade pip && \ - pip install -U aqtinstall requests py7zr && \ - pip show aqtinstall && \ + 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 && \ @@ -224,6 +269,9 @@ jobs: script: - bash deploy/build_android.sh + after_script: + - ccache --show-stats + deploy: provider: releases token: $GH_TOKEN @@ -234,20 +282,54 @@ jobs: tags: true branch: master + cache: + - ccache + - directories: + - $HOME/Qt + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ + - $HOME/.android/build-cache + - $ANDROID_NDK_HOME +# ------------------------------------------------------ + - name: iOS + os: osx + osx_image: xcode13.4 + language: cpp + + env: + - PATH=/usr/local/opt/ccache/libexec:~/go/bin:$PATH + - QT_VERSION=5.15.2 + - QT_BIN_DIR=$HOME/Qt/$QT_VERSION/ios/bin + - QT_IOS_BIN=$QT_BIN_DIR + + install: + - | + 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 ; \ + fi + - brew install golang + - go install golang.org/x/mobile/cmd/gomobile@latest + - gomobile init + + script: + - bash deploy/build_ios.sh + + after_script: + - ccache --show-stats + + cache: + - ccache + - directories: + - $HOME/Qt + - $HOME/Library/Caches/Homebrew before_cache: - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew cleanup; fi # Cache only .git files under "/usr/local/Homebrew" so "brew update" does not take 5min every build - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then find /usr/local/Homebrew \! -regex ".+\.git.+" -delete; fi -cache: - directories: - - $HOME/Qt - - /C/Qt - - $HOME/Library/Caches/Homebrew - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - - $HOME/.android/build-cache - - $ANDROID_NDK_HOME - - $MSVC_PATH diff --git a/client/3rd/QSimpleCrypto/QSimpleCrypto.pri b/client/3rd/QSimpleCrypto/QSimpleCrypto.pri new file mode 100644 index 00000000..99a1c129 --- /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 00000000..11f60b31 --- /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 00000000..e7b83a88 --- /dev/null +++ b/client/3rd/QSimpleCrypto/include/QBlockCipher.h @@ -0,0 +1,84 @@ +/** + * 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); + QByteArray generateSecureRandomBytes(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 00000000..fc059654 --- /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 00000000..45eb3169 --- /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 00000000..fdd6c020 --- /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 00000000..96e0c76c --- /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 00000000..8cd8ca82 --- /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 00000000..968c8841 --- /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 00000000..8b86ab98 --- /dev/null +++ b/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp @@ -0,0 +1,193 @@ +/** + * 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; +} + +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. +/// \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 00000000..234f55d7 --- /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 00000000..544d6746 --- /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 00000000..8666347d --- /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 00000000..bbbec1a8 --- /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/3rd/qtkeychain b/client/3rd/qtkeychain new file mode 160000 index 00000000..f197cdb9 --- /dev/null +++ b/client/3rd/qtkeychain @@ -0,0 +1 @@ +Subproject commit f197cdb935b0cfd9881fdc6860874cb8379d1238 diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp new file mode 100644 index 00000000..43f352a2 --- /dev/null +++ b/client/amnezia_application.cpp @@ -0,0 +1,205 @@ +#include "amnezia_application.h" + +#include +#include +#include + + +#include "QZXing.h" + +#include "core/servercontroller.h" +#include "debug.h" +#include "defines.h" + +#include "platforms/ios/QRCodeReaderBase.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" + +#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[]): + 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); + m_serverController = std::shared_ptr(new ServerController(m_settings, this)); + m_configurator = std::shared_ptr(new VpnConfigurator(m_settings, m_serverController, this)); +} + +AmneziaApplication::~AmneziaApplication() +{ + 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; + } + + if (m_protocolProps) delete m_protocolProps; + if (m_containerProps) delete m_containerProps; +} + +void AmneziaApplication::init() +{ + m_engine = new QQmlApplicationEngine; + 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, + this, [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) + QCoreApplication::exit(-1); + }, Qt::QueuedConnection); + + m_engine->rootContext()->setContextProperty("Debug", &Debug::Instance()); + m_uiLogic->registerPagesLogic(); + +#if defined(Q_OS_IOS) + setStartPageLogic(m_uiLogic->pageLogic()); +#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 + m_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"); + + m_containerProps = new ContainerProps; + qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", m_containerProps); + + m_protocolProps = new ProtocolProps; + qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", m_protocolProps); +} + +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); + } +} + +bool 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, [this]{ + quit(); + }); + exec(); + return false; + } + return true; +} + +QQmlApplicationEngine *AmneziaApplication::qmlEngine() const +{ + return m_engine; +} + diff --git a/client/amnezia_application.h b/client/amnezia_application.h new file mode 100644 index 00000000..f0f8f529 --- /dev/null +++ b/client/amnezia_application.h @@ -0,0 +1,62 @@ +#ifndef AMNEZIA_APPLICATION_H +#define AMNEZIA_APPLICATION_H + +#include +#include + +#include +#include +#include + +#include "settings.h" + +#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 + #define AMNEZIA_BASE_CLASS SingleApplication + #define QAPPLICATION_CLASS QApplication + #include "singleapplication.h" +#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(); + bool parseCommands(); + + QQmlApplicationEngine *qmlEngine() const; + +private: + 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 {}; + + QTranslator* m_translator; + QCommandLineParser m_parser; + +}; + +#endif // AMNEZIA_APPLICATION_H diff --git a/client/client.pro b/client/client.pro index a39ec755..5b6d3f8f 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 \ @@ -16,31 +15,37 @@ 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") +include("3rd/qtkeychain/qtkeychain.pri") +INCLUDEPATH += $$PWD/3rd/QSimpleCrypto/include INCLUDEPATH += $$PWD/3rd/OpenSSL/include 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/configurator_base.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 \ ui/models/containers_model.h \ @@ -49,28 +54,29 @@ 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 \ 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 \ - 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 \ @@ -81,24 +87,27 @@ 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/configurator_base.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 \ ui/models/containers_model.cpp \ @@ -106,27 +115,28 @@ 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 \ 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 \ - 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 \ @@ -165,7 +175,6 @@ win32 { -lshlwapi \ -liphlpapi \ -lws2_32 \ - -liphlpapi \ -lgdi32 @@ -246,20 +255,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) { @@ -280,7 +289,7 @@ android { } ios { - message("Client ios build") + message("Client iOS build") CONFIG += static CONFIG += file_copies @@ -307,7 +316,7 @@ ios { platforms/ios/QtAppDelegate-C-Interface.h SOURCES -= \ - platforms/ios/QRCodeReader.cpp \ + platforms/ios/QRCodeReaderBase.cpp \ platforms/ios/MobileUtils.cpp SOURCES += \ diff --git a/client/configurators/cloak_configurator.cpp b/client/configurators/cloak_configurator.cpp index 211ddc79..50f554dc 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 562b9917..c6184805 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 00000000..44377401 --- /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 00000000..8c0614d9 --- /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 de9f0e82..db6b53a2 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 9061a47c..35c03b19 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 3ebfefcc..a7719108 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 99c4efa6..25230499 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 6f63ba79..97503ac4 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 4445b074..be80f169 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 fdece1d6..ac867c70 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 71146a1c..d7a177c3 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 c2b128f0..42d3063e 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 702fc9d4..47bdc1fd 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 c7b29ef5..08e6c40a 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 635c8dce..76790d74 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 638e1253..1ea36011 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 0f1e6cbf..091eaa52 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/defines.h b/client/defines.h index 415dc21a..4334c68f 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/main.cpp b/client/main.cpp index 1283e839..a5751979 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 "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" #endif @@ -58,29 +14,24 @@ #endif #if defined(Q_OS_IOS) -#include "QtAppDelegate-C-Interface.h" +#include "platforms/ios/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, [&](){ @@ -88,10 +39,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 @@ -104,147 +54,20 @@ 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); + bool doExec = app.parseCommands(); - 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; + if (doExec) { + app.init(); + return app.exec(); } - - 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 - - return app.exec(); + return 0; } diff --git a/client/platforms/ios/MobileUtils.cpp b/client/platforms/ios/MobileUtils.cpp index eea504ce..3923d291 100644 --- a/client/platforms/ios/MobileUtils.cpp +++ b/client/platforms/ios/MobileUtils.cpp @@ -1,5 +1,5 @@ #include "MobileUtils.h" -void MobileUtils::shareText(const QStringList& filesToSend) { +void MobileUtils::shareText(const QStringList&) {} + -} diff --git a/client/platforms/ios/MobileUtils.h b/client/platforms/ios/MobileUtils.h index 42aa4031..a7967fdf 100644 --- a/client/platforms/ios/MobileUtils.h +++ b/client/platforms/ios/MobileUtils.h @@ -12,6 +12,7 @@ public: public slots: static void shareText(const QStringList& filesToSend); + }; #endif // MOBILEUTILS_H diff --git a/client/platforms/ios/MobileUtils.mm b/client/platforms/ios/MobileUtils.mm index 94c7c775..a9ad52b5 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,4 @@ void MobileUtils::shareText(const QStringList& filesToSend) { popController.sourceView = qtController.view; } } + diff --git a/client/protocols/ikev2_vpn_protocol_windows.cpp b/client/protocols/ikev2_vpn_protocol_windows.cpp index 5e4e5b14..47bc3d0c 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/openvpnovercloakprotocol.cpp b/client/protocols/openvpnovercloakprotocol.cpp index 2e9d77e8..5695b3dc 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/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index 6adabfb3..cfd13a7e 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -1,8 +1,9 @@ #include #include #include -#include #include +#include +#include #include "debug.h" #include "defines.h" @@ -122,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 @@ -132,24 +148,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(); } @@ -162,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(); } @@ -183,9 +191,9 @@ 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", 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 34cff8f4..ad80fe50 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); @@ -47,6 +46,8 @@ private: QString m_configFileName; QTemporaryFile m_configFile; + uint selectMgmtPort(); + private: void updateRouteGateway(QString line); void updateVpnGateway(const QString &line); diff --git a/client/protocols/shadowsocksvpnprotocol.cpp b/client/protocols/shadowsocksvpnprotocol.cpp index bc494777..3de0bfe8 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/protocols/wireguardprotocol.cpp b/client/protocols/wireguardprotocol.cpp index d650cb3f..e6ccef6c 100644 --- a/client/protocols/wireguardprotocol.cpp +++ b/client/protocols/wireguardprotocol.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include @@ -12,25 +11,20 @@ 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(wireguardExecPath())) { + if (!QFileInfo::exists(Utils::wireguardExecPath())) { qCritical() << "Wireguard executable missing!"; setLastError(ErrorCode::ExecutableMissing); return; @@ -51,7 +45,7 @@ void WireguardProtocol::stop() return; } - m_wireguardStopProcess->setProgram(wireguardExecPath()); + m_wireguardStopProcess->setProgram(PermittedProcess::Wireguard); QStringList arguments({"--remove", configPath()}); @@ -74,7 +68,6 @@ void WireguardProtocol::stop() setConnectionState(VpnProtocol::Disconnected); #endif - //qDebug() << "WireguardProtocol::stop() 2"; } void WireguardProtocol::readWireguardConfiguration(const QJsonObject &configuration) @@ -97,11 +90,6 @@ void WireguardProtocol::readWireguardConfiguration(const QJsonObject &configurat } -//bool WireguardProtocol::openVpnProcessIsRunning() const -//{ -// return Utils::processIsRunning("openvpn"); -//} - QString WireguardProtocol::configPath() const { return m_configFileName; @@ -117,31 +105,17 @@ 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"; - #ifndef Q_OS_IOS if (!m_isConfigLoaded) { setLastError(ErrorCode::ConfigMissing); return lastError(); } - //qDebug() << "Start Wireguard connection"; WireguardProtocol::stop(); - if (!QFileInfo::exists(wireguardExecPath())) { + if (!QFileInfo::exists(Utils::wireguardExecPath())) { setLastError(ErrorCode::ExecutableMissing); return lastError(); } @@ -156,7 +130,6 @@ ErrorCode WireguardProtocol::start() m_wireguardStartProcess = IpcClient::CreatePrivilegedProcess(); if (!m_wireguardStartProcess) { - //qWarning() << "IpcProcess replica is not created!"; setLastError(ErrorCode::AmneziaServiceConnectionFailed); return ErrorCode::AmneziaServiceConnectionFailed; } @@ -168,7 +141,7 @@ ErrorCode WireguardProtocol::start() return ErrorCode::AmneziaServiceConnectionFailed; } - m_wireguardStartProcess->setProgram(wireguardExecPath()); + m_wireguardStartProcess->setProgram(PermittedProcess::Wireguard); QStringList arguments({"--add", configPath()}); @@ -210,8 +183,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/client/protocols/wireguardprotocol.h b/client/protocols/wireguardprotocol.h index 8ed26c7d..3a091cac 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/resources.qrc b/client/resources.qrc index a48a98f7..a7e67e39 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/scripts/apple_compile.sh b/client/scripts/apple_compile.sh index 48b438bb..fb44af30 100755 --- a/client/scripts/apple_compile.sh +++ b/client/scripts/apple_compile.sh @@ -270,6 +270,6 @@ print G "done." sed -i '' '/Original<\/string>/d' AmneziaVPN.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings fi -print Y "Opening in XCode..." -open AmneziaVPN.xcodeproj +# print Y "Opening in XCode..." +# open AmneziaVPN.xcodeproj print G "All done!" diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp new file mode 100644 index 00000000..b78863ba --- /dev/null +++ b/client/secure_qsettings.cpp @@ -0,0 +1,254 @@ +#include "secure_qsettings.h" +#include "platforms/ios/MobileUtils.h" + +#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), + encryptedKeys({"Servers/serversList"}) +{ + bool encrypted = m_settings.value("Conf/encrypted").toBool(); + + // convert settings to encrypted for if updated to >= 2.1.0 + if (encryptionRequired() && ! encrypted) { + for (const QString &key : m_settings.allKeys()) { + if (encryptedKeys.contains(key)) { + const QVariant &val = value(key); + setValue(key, val); + } + } + m_settings.setValue("Conf/encrypted", true); + m_settings.sync(); + } +} + +QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue) const +{ + QMutexLocker locker(&mutex); + + if (m_cache.contains(key)) { + return m_cache.value(key); + } + + if (!m_settings.contains(key)) return defaultValue; + + QVariant retVal; + + // 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) { + + if (getEncKey().isEmpty() || getEncIv().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"; + retVal = QVariant(); + } + } + } + else { + qWarning() << "SecureQSettings::value invalid QVariant value"; + retVal = QVariant(); + } + + m_cache.insert(key, retVal); + return retVal; +} + +void SecureQSettings::setValue(const QString &key, const QVariant &value) +{ + QMutexLocker locker(&mutex); + + if (encryptionRequired() && encryptedKeys.contains(key)) { + if (!getEncKey().isEmpty() && !getEncIv().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; + } + + } + else { + m_settings.setValue(key, value); + } + + m_cache.insert(key, value); + sync(); +} + +void SecureQSettings::remove(const QString &key) +{ + QMutexLocker locker(&mutex); + + m_settings.remove(key); + m_cache.remove(key); + + sync(); +} + +void SecureQSettings::sync() +{ + m_settings.sync(); +} + +QByteArray SecureQSettings::backupAppConfig() const +{ + QJsonObject cfg; + + for (const QString &key : m_settings.allKeys()) { + cfg.insert(key, QJsonValue::fromVariant(value(key))); + } + + return QJsonDocument(cfg).toJson(); +} + +bool SecureQSettings::restoreAppConfig(const QByteArray &json) +{ + QJsonObject cfg = QJsonDocument::fromJson(json).object(); + if (cfg.isEmpty()) return false; + + for (const QString &key : cfg.keys()) { + setValue(key, cfg.value(key).toVariant()); + } + + sync(); + return true; +} + + +QByteArray SecureQSettings::encryptText(const QByteArray& value) const +{ + QSimpleCrypto::QBlockCipher cipher; + return cipher.encryptAesBlockCipher(value, getEncKey(), getEncIv()); +} + +QByteArray SecureQSettings::decryptText(const QByteArray& ba) const +{ + QSimpleCrypto::QBlockCipher cipher; + return cipher.decryptAesBlockCipher(ba, getEncKey(), getEncIv()); +} + +bool SecureQSettings::encryptionRequired() const +{ + // TODO: review on linux + return true; +} + +QByteArray SecureQSettings::getEncKey() const +{ + // load keys from system key storage + m_key = getSecTag(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"; + } + + setSecTag(settingsKeyTag, key); + + // check + m_key = getSecTag(settingsKeyTag); + if (key != m_key) { + qCritical() << "SecureQSettings::getEncKey Unable to store key in keychain" << key.size() << m_key.size(); + return {}; + } + } + + return m_key; +} + +QByteArray SecureQSettings::getEncIv() const +{ + // load keys from system key storage + m_iv = getSecTag(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"; + } + setSecTag(settingsIvTag, iv); + + // check + m_iv = getSecTag(settingsIvTag); + if (iv != m_iv) { + qCritical() << "SecureQSettings::getEncIv Unable to store IV in keychain" << iv.size() << m_iv.size(); + return {}; + } + } + + return m_iv; +} + +QByteArray SecureQSettings::getSecTag(const QString &tag) +{ + ReadPasswordJob job(keyChainName); + 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(keyChainName); + 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 new file mode 100644 index 00000000..9b1f6167 --- /dev/null +++ b/client/secure_qsettings.h @@ -0,0 +1,56 @@ +#ifndef SECUREQSETTINGS_H +#define SECUREQSETTINGS_H + +#include +#include +#include +#include + +#include "keychain.h" + + +constexpr const char* settingsKeyTag = "settingsKeyTag"; +constexpr const char* settingsIvTag = "settingsIvTag"; +constexpr const char* keyChainName = "AmneziaVPN-Keychain"; + + +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 remove(const QString &key); + void sync(); + + QByteArray backupAppConfig() const; + bool restoreAppConfig(const QByteArray &json); + + QByteArray encryptText(const QByteArray &value) const; + QByteArray decryptText(const QByteArray& ba) const; + + bool encryptionRequired() const; + + 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; + + mutable QMap m_cache; + + QStringList encryptedKeys; // encode only key listed here + + mutable QByteArray m_key; + mutable QByteArray m_iv; + + 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 317df740..6e470a33 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -2,15 +2,15 @@ #include "settings.h" #include "utils.h" -#include #include "containers/containers_defs.h" const char Settings::cloudFlareNs1[] = "1.1.1.1"; const char Settings::cloudFlareNs2[] = "1.0.0.1"; + Settings::Settings(QObject* parent) : QObject(parent), - m_settings (ORGANIZATION_NAME, APPLICATION_NAME, this) + m_settings(ORGANIZATION_NAME, APPLICATION_NAME, this) { // Import old settings if (serversCount() == 0) { @@ -178,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 @@ -292,60 +291,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 d5cb1639..c78b9a79 100644 --- a/client/settings.h +++ b/client/settings.h @@ -11,6 +11,7 @@ #include "core/defs.h" #include "containers/containers_defs.h" +#include "secure_qsettings.h" using namespace amnezia; @@ -25,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()); } @@ -110,13 +110,11 @@ public: // static constexpr char openNicNs5[] = "94.103.153.176"; // static constexpr char openNicNs13[] = "144.76.103.143"; - -public: - - + QByteArray backupAppConfig() const { return m_settings.backupAppConfig(); } + bool restoreAppConfig(const QByteArray &cfg) { return m_settings.restoreAppConfig(cfg); } private: - QSettings m_settings; + SecureQSettings m_settings; }; diff --git a/client/ui/models/containers_model.cpp b/client/ui/models/containers_model.cpp index 15fc8f8d..5468452e 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 479690b0..36206855 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 76e5c623..7359bb36 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 bd271558..48b6eeb6 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 9fc5452d..fe0f4ccf 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 5e4feb0f..7bf04b50 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.h b/client/ui/pages.h index d74c64a6..69f417fa 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/AppSettingsLogic.cpp b/client/ui/pages_logic/AppSettingsLogic.cpp index 6429fc96..b2907c3d 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; @@ -25,9 +26,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 +47,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() @@ -74,3 +75,32 @@ 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(); + + 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.")); + } + +} + diff --git a/client/ui/pages_logic/AppSettingsLogic.h b/client/ui/pages_logic/AppSettingsLogic.h index b597b129..fc9f0da7 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/GeneralSettingsLogic.cpp b/client/ui/pages_logic/GeneralSettingsLogic.cpp index 92696afa..a71a7f91 100644 --- a/client/ui/pages_logic/GeneralSettingsLogic.cpp +++ b/client/ui/pages_logic/GeneralSettingsLogic.cpp @@ -12,28 +12,28 @@ 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); - 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/NetworkSettingsLogic.cpp b/client/ui/pages_logic/NetworkSettingsLogic.cpp index bd593e3a..4038d089 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): @@ -13,39 +14,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/NewServerProtocolsLogic.h b/client/ui/pages_logic/NewServerProtocolsLogic.h index a06e6590..abf3d102 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 f0638213..9274ef49 100644 --- a/client/ui/pages_logic/PageLogicBase.cpp +++ b/client/ui/pages_logic/PageLogicBase.cpp @@ -1,11 +1,17 @@ #include "PageLogicBase.h" +#include "ui/uilogic.h" +#include "settings.h" +#include "configurators/vpn_configurator.h" PageLogicBase::PageLogicBase(UiLogic *logic, QObject *parent): QObject(parent), m_pageEnabled{true}, 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 26858ee0..887b0ec7 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 *m_uiLogic; UiLogic *uiLogic() const { return m_uiLogic; } - Settings m_settings; - UiLogic *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/QrDecoderLogic.cpp b/client/ui/pages_logic/QrDecoderLogic.cpp index 01c607f7..0c24ca1c 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/ServerConfiguringProgressLogic.h b/client/ui/pages_logic/ServerConfiguringProgressLogic.h index 9620d4c3..3ca94878 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 e01e1bac..27f865b5 100644 --- a/client/ui/pages_logic/ServerContainersLogic.cpp +++ b/client/ui/pages_logic/ServerContainersLogic.cpp @@ -36,64 +36,64 @@ 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; - 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); } 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 = m_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(); } 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); + ErrorCode e = uiLogic()->pageLogic()->doInstallAction([this, c, &config](){ + return m_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/ServerContainersLogic.h b/client/ui/pages_logic/ServerContainersLogic.h index a49882fa..3f2a26cd 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/ServerListLogic.cpp b/client/ui/pages_logic/ServerListLogic.cpp index 05cac928..fe3f6512 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 e15207b7..bd954c88 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,14 +48,14 @@ void ServerSettingsLogic::onPushButtonClearServer() set_pageEnabled(false); set_pushButtonClearText(tr("Uninstalling Amnezia software...")); - if (m_settings.defaultServerIndex() == uiLogic()->selectedServerIndex) { - uiLogic()->vpnLogic()->onDisconnect(); + if (m_settings->defaultServerIndex() == uiLogic()->selectedServerIndex) { + uiLogic()->pageLogic()->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.")); @@ -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()) { - uiLogic()->vpnLogic()->onDisconnect(); + if (m_settings->defaultServerIndex() == uiLogic()->selectedServerIndex && uiLogic()->m_vpnConnection->isConnected()) { + uiLogic()->pageLogic()->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,14 +120,14 @@ 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(); } 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/ShareConnectionLogic.cpp b/client/ui/pages_logic/ShareConnectionLogic.cpp index 038b3891..6367722a 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" @@ -73,19 +74,19 @@ 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); + QString cfg = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, p, &e); if (e) { cfg = "Error generating config"; break; @@ -96,14 +97,14 @@ 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); 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); @@ -129,13 +130,13 @@ 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); - 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()); } @@ -144,16 +145,16 @@ 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); + cfg = m_configurator->shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, &e); } QJsonObject ssConfig = QJsonDocument::fromJson(cfg.toUtf8()).object(); @@ -186,16 +187,16 @@ 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); + cfg = m_configurator->cloakConfigurator->genCloakConfig(credentials, container, containerConfig, &e); } QJsonObject cloakConfig = QJsonDocument::fromJson(cfg.toUtf8()).object(); @@ -209,19 +210,19 @@ 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); + 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); @@ -235,22 +236,20 @@ 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); + Ikev2Configurator::ConnectionData connData = m_configurator->ikev2Configurator->prepareIkev2Config(credentials, container); - Ikev2Configurator::ConnectionData connData = 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 c3c2ad6d..a167b43e 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.cpp b/client/ui/pages_logic/SitesLogic.cpp index 8b94155f..b31018c0 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) { @@ -40,10 +40,10 @@ void SitesLogic::onUpdatePage() void SitesLogic::onPushButtonAddCustomSitesClicked() { - if (uiLogic()->vpnLogic()->radioButtonVpnModeAllSitesChecked()) { + if (uiLogic()->pageLogic()->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/SitesLogic.h b/client/ui/pages_logic/SitesLogic.h index 2afb3805..35bf1f90 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 e8b3f269..de3173b5 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -1,6 +1,9 @@ #include "StartPageLogic.h" +#include "ViewConfigLogic.h" + #include "core/errorstrings.h" #include "configurators/ssh_configurator.h" +#include "configurators/vpn_configurator.h" #include "../uilogic.h" #include "utils.h" @@ -16,15 +19,8 @@ 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_pushButtonConnectVisible{true}, m_ipAddressPortRegex{Utils::ipAddressPortRegExp()} { @@ -41,7 +37,6 @@ void StartPageLogic::onUpdatePage() set_labelWaitInfoVisible(false); set_labelWaitInfoText(""); - set_pushButtonConnectVisible(true); set_pushButtonConnectKeyChecked(false); @@ -50,8 +45,6 @@ void StartPageLogic::onUpdatePage() void StartPageLogic::onPushButtonConnect() { -// uiLogic()->goToPage(Page::NewServer); -// return; if (pushButtonConnectKeyChecked()){ if (lineEditIpText().isEmpty() || lineEditLoginText().isEmpty() || @@ -68,7 +61,6 @@ void StartPageLogic::onPushButtonConnect() return; } } - qDebug() << "UiLogic::onPushButtonConnect checking new server"; ServerCredentials serverCredentials; serverCredentials.hostName = lineEditIpText(); @@ -85,7 +77,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; @@ -99,7 +91,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 @@ -153,19 +145,10 @@ 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); - - 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"; @@ -174,8 +157,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); @@ -209,7 +192,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/StartPageLogic.h b/client/ui/pages_logic/StartPageLogic.h index f5f132f8..24bdc53f 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/pages_logic/ViewConfigLogic.cpp b/client/ui/pages_logic/ViewConfigLogic.cpp new file mode 100644 index 00000000..17d8814e --- /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 00000000..4713158e --- /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/pages_logic/VpnLogic.cpp b/client/ui/pages_logic/VpnLogic.cpp index 5812441e..44a37a5c 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 = m_configurator->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); } @@ -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.cpp b/client/ui/pages_logic/WizardLogic.cpp index 7936524d..5fe820f1 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/WizardLogic.h b/client/ui/pages_logic/WizardLogic.h index cfba5d2d..3827c86e 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 2e341383..59019990 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 m_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 e110c465..d88252c8 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 98115f29..3b672747 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 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); 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 1d5c7f78..45141050 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 8cf3949f..50b17a46 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" @@ -82,7 +81,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 8639ba54..508c2914 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 9aa8d0f3..1d5da936 100644 --- a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp +++ b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp @@ -46,10 +46,9 @@ QJsonObject ShadowSocksLogic::getProtocolConfigFromPage(QJsonObject oldConfig) void ShadowSocksLogic::onPushButtonSaveClicked() { - QJsonObject protocolConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::ShadowSocks); - //protocolConfig = getShadowSocksConfigFromPage(protocolConfig); + QJsonObject protocolConfig = m_settings->protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Proto::ShadowSocks); - 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 +81,14 @@ 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); 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 b7c2c9ee..4e566825 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/property_helper.h b/client/ui/property_helper.h index 3d254c71..927105b3 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/qml/Pages/PageAppSetting.qml b/client/ui/qml/Pages/PageAppSetting.qml index b795ceb5..7e8d415a 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/PageServerContainers.qml b/client/ui/qml/Pages/PageServerContainers.qml index fb5dd97e..4b05568a 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() + + } +} diff --git a/client/ui/qml/Pages/PageShareConnection.qml b/client/ui/qml/Pages/PageShareConnection.qml index c124c969..9bd84bdd 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/PageStart.qml b/client/ui/qml/Pages/PageStart.qml index 3ff11a86..ab53792d 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() } diff --git a/client/ui/qml/Pages/PageViewConfig.qml b/client/ui/qml/Pages/PageViewConfig.qml new file mode 100644 index 00000000..acefb9b3 --- /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/systemtray_notificationhandler.cpp b/client/ui/systemtray_notificationhandler.cpp index 21e24ac1..e142caf5 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 fe2d541d..e1468da7 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" @@ -74,30 +76,20 @@ using namespace amnezia; using namespace PageEnumNS; -UiLogic::UiLogic(QObject *parent) : +UiLogic::UiLogic(std::shared_ptr settings, std::shared_ptr configurator, + std::shared_ptr serverController, + QObject *parent) : QObject(parent), - m_dialogConnectErrorText{} + m_settings(settings), + m_configurator(configurator), + m_serverController(serverController) { - 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, configurator, serverController); m_vpnConnection->moveToThread(&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)); @@ -139,55 +131,40 @@ 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()) { - 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); 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); + 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()); } -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()) { + if (! m_settings->isStartMinimized()) { emit show(); } else { @@ -201,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(); } } @@ -235,30 +198,29 @@ 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->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())); + m_configurator->sshConfigurator->openSshTerminal(m_settings->serverCredentials(m_settings->defaultServerIndex())); break; case Qt::Key_Escape: case Qt::Key_Back: @@ -280,7 +242,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 +261,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); } @@ -344,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, @@ -385,7 +347,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 +356,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); @@ -442,9 +404,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) { @@ -587,7 +549,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); } } @@ -607,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()); @@ -632,13 +599,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 @@ -681,7 +646,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); @@ -692,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 4e818bcc..b5b6092b 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" @@ -16,7 +20,12 @@ #include "models/protocols_model.h" #include "notificationhandler.h" -#include "settings.h" + +class Settings; +class VpnConfigurator; +class ServerController; + +class PageLogicBase; class AppSettingsLogic; class GeneralSettingsLogic; @@ -30,6 +39,7 @@ class ServerContainersLogic; class ShareConnectionLogic; class SitesLogic; class StartPageLogic; +class ViewConfigLogic; class VpnLogic; class WizardLogic; @@ -50,18 +60,19 @@ 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(QObject *parent = nullptr); + explicit UiLogic(std::shared_ptr settings, std::shared_ptr configurator, + std::shared_ptr serverController, QObject *parent = nullptr); ~UiLogic(); void showOnStartup(); + friend class PageLogicBase; + friend class AppSettingsLogic; friend class GeneralSettingsLogic; friend class NetworkSettingsLogic; @@ -73,6 +84,7 @@ public: friend class ShareConnectionLogic; friend class SitesLogic; friend class StartPageLogic; + friend class ViewConfigLogic; friend class VpnLogic; friend class WizardLogic; @@ -92,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); @@ -106,9 +114,6 @@ public: void shareTempFile(const QString &suggestedName, QString ext, const QString& data); - QString getDialogConnectErrorText() const; - void setDialogConnectErrorText(const QString &dialogConnectErrorText); - signals: void dialogConnectErrorTextChanged(); @@ -125,9 +130,6 @@ signals: void raise(); void toggleLogPanel(); -private: - QString m_dialogConnectErrorText; - private slots: // containers - INOUT arg void installServer(QMap &containers); @@ -168,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; @@ -190,29 +177,36 @@ 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; VpnConnection* m_vpnConnection; QThread m_vpnConnectionThread; - Settings m_settings; + + std::shared_ptr m_settings; + std::shared_ptr m_configurator; + std::shared_ptr m_serverController; NotificationHandler* m_notificationHandler; diff --git a/client/utils.cpp b/client/utils.cpp index 046d582c..67552513 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; @@ -214,6 +213,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 ff5c5e8c..61981db7 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/client/vpnconnection.cpp b/client/vpnconnection.cpp index d2461b07..6e117ce4 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -29,9 +29,12 @@ #include "utils.h" #include "vpnconnection.h" -VpnConnection::VpnConnection(QObject* parent) : QObject(parent), - m_settings(this) - +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) { } @@ -56,7 +59,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 +70,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 +88,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 +107,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 +135,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 +156,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 +170,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); } } @@ -215,18 +218,15 @@ QString VpnConnection::createVpnConfigurationForProto(int serverIndex, QString configData; if (lastVpnConfig.contains(proto)) { configData = lastVpnConfig.value(proto); - configData = VpnConfigurator::processConfigWithLocalSettings(serverIndex, container, proto, configData); - - qDebug() << "VpnConnection::createVpnConfiguration: using saved config for" << ProtocolProps::protoToString(proto); + configData = m_configurator->processConfigWithLocalSettings(serverIndex, container, proto, configData); } 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) { @@ -237,9 +237,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); } } @@ -272,7 +272,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; @@ -284,7 +284,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) { @@ -346,7 +346,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; @@ -360,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(); @@ -382,7 +380,6 @@ void VpnConnection::disconnectFromVpn() return; } m_vpnProtocol.data()->stop(); - // qDebug() << "Disconnect from VPN 2"; } VpnProtocol::VpnConnectionState VpnConnection::connectionState() diff --git a/client/vpnconnection.h b/client/vpnconnection.h index d0dc2135..18446e74 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(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); @@ -73,7 +78,10 @@ protected: QSharedPointer m_vpnProtocol; private: - Settings m_settings; + std::shared_ptr m_settings; + std::shared_ptr m_configurator; + std::shared_ptr m_serverController; + QJsonObject m_vpnConfiguration; QJsonObject m_routeMode; QString m_remoteAddress; diff --git a/deploy/build_ios.sh b/deploy/build_ios.sh new file mode 100644 index 00000000..994a96ed --- /dev/null +++ b/deploy/build_ios.sh @@ -0,0 +1,49 @@ +#!/bin/bash +echo "Build script started ..." + +set -o errexit -o nounset + +# Hold on to current directory +PROJECT_DIR=$(pwd) +DEPLOY_DIR=$PROJECT_DIR/deploy + +mkdir -p $DEPLOY_DIR/build +BUILD_DIR=$DEPLOY_DIR/build + +echo "Project dir: ${PROJECT_DIR}" +echo "Build dir: ${BUILD_DIR}" + +APP_NAME=AmneziaVPN +APP_FILENAME=$APP_NAME.app +APP_DOMAIN=org.amneziavpn.package +PLIST_NAME=$APP_NAME.plist + +OUT_APP_DIR=$BUILD_DIR/client +BUNDLE_DIR=$OUT_APP_DIR/$APP_FILENAME + +PRO_FILE_PATH=$PROJECT_DIR/$APP_NAME.pro +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/ios/bin +fi + +echo "Using Qt in $QT_BIN_DIR" + + +# Checking env +$QT_BIN_DIR/qmake -v + +# Build App +echo "Building App..." +cd $PROJECT_DIR/client +$PROJECT_DIR/client/scripts/apple_compile.sh ios + +# Build and run tests here + +#echo "............Deploy.................." + + diff --git a/ipc/ipc.h b/ipc/ipc.h index d78a450b..d69f6517 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 fc82c49e..ba42332c 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 f9cdd20f..b8f085c3 100644 --- a/ipc/ipcserverprocess.cpp +++ b/ipc/ipcserverprocess.cpp @@ -1,4 +1,5 @@ #include "ipcserverprocess.h" +#include "ipc.h" #include #ifndef Q_OS_IOS @@ -19,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() @@ -38,16 +27,11 @@ 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()) { + qDebug() << "IpcServerProcess failed to start, program is empty"; + } m_process->start(); qDebug() << "IpcServerProcess started, " << m_process->program() << m_process->arguments(); @@ -81,9 +65,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 0ed61ee8..b427d639 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; @@ -21,7 +20,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;