diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 63bda344..d9138516 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -10,12 +10,13 @@ env:
jobs:
Build-Linux-Ubuntu:
- name: 'Build-Linux-Ubuntu'
runs-on: ubuntu-20.04
env:
QT_VERSION: 6.6.2
QIF_VERSION: 4.7
+ PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
steps:
- name: 'Install Qt'
@@ -75,13 +76,14 @@ jobs:
# ------------------------------------------------------
Build-Windows:
- name: Build-Windows
runs-on: windows-latest
env:
QT_VERSION: 6.6.2
QIF_VERSION: 4.7
BUILD_ARCH: 64
+ PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
steps:
- name: 'Get sources'
@@ -137,13 +139,14 @@ jobs:
# ------------------------------------------------------
Build-iOS:
- name: 'Build-iOS'
runs-on: macos-13
env:
QT_VERSION: 6.6.2
CC: cc
CXX: c++
+ PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
steps:
- name: 'Setup xcode'
@@ -178,7 +181,7 @@ jobs:
- name: 'Install go'
uses: actions/setup-go@v5
with:
- go-version: '1.20'
+ go-version: '1.22.1'
cache: false
- name: 'Setup gomobile'
@@ -228,13 +231,14 @@ jobs:
# ------------------------------------------------------
Build-MacOS:
- name: 'Build-MacOS'
runs-on: macos-latest
env:
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
QT_VERSION: 6.4.3
QIF_VERSION: 4.6
+ PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
steps:
- name: 'Setup xcode'
@@ -293,28 +297,29 @@ jobs:
# ------------------------------------------------------
Build-Android:
- name: 'Build-Android'
runs-on: ubuntu-latest
env:
ANDROID_BUILD_PLATFORM: android-34
- QT_VERSION: 6.6.2
+ QT_VERSION: 6.7.2
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
+ PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
steps:
- name: 'Install desktop Qt'
- uses: jurplel/install-qt-action@v3
+ uses: jurplel/install-qt-action@v4
with:
version: ${{ env.QT_VERSION }}
host: 'linux'
target: 'desktop'
- arch: 'gcc_64'
+ arch: 'linux_gcc_64'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install android_x86_64 Qt'
- uses: jurplel/install-qt-action@v3
+ uses: jurplel/install-qt-action@v4
with:
version: ${{ env.QT_VERSION }}
host: 'linux'
@@ -325,7 +330,7 @@ jobs:
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install android_x86 Qt'
- uses: jurplel/install-qt-action@v3
+ uses: jurplel/install-qt-action@v4
with:
version: ${{ env.QT_VERSION }}
host: 'linux'
@@ -336,7 +341,7 @@ jobs:
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install android_armv7 Qt'
- uses: jurplel/install-qt-action@v3
+ uses: jurplel/install-qt-action@v4
with:
version: ${{ env.QT_VERSION }}
host: 'linux'
@@ -347,7 +352,7 @@ jobs:
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install android_arm64_v8a Qt'
- uses: jurplel/install-qt-action@v3
+ uses: jurplel/install-qt-action@v4
with:
version: ${{ env.QT_VERSION }}
host: 'linux'
@@ -439,3 +444,21 @@ jobs:
path: deploy/build/AmneziaVPN-release.aab
compression-level: 0
retention-days: 7
+
+ Extra:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Search a corresponding PR
+ uses: octokit/request-action@v2.x
+ id: pull_request
+ with:
+ route: GET /repos/${{ github.repository }}/pulls
+ head: ${{ github.repository_owner }}:${{ github.ref_name }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Add PR link to build summary
+ if: ${{ fromJSON(steps.pull_request.outputs.data)[0].number != '' }}
+ run: |
+ echo "Pull request:" >> $GITHUB_STEP_SUMMARY
+ echo "[[#${{ fromJSON(steps.pull_request.outputs.data)[0].number }}] ${{ fromJSON(steps.pull_request.outputs.data)[0].title }}](${{ fromJSON(steps.pull_request.outputs.data)[0].html_url }})" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/tag-deploy.yml b/.github/workflows/tag-deploy.yml
index b88390f4..dffb3ab1 100644
--- a/.github/workflows/tag-deploy.yml
+++ b/.github/workflows/tag-deploy.yml
@@ -15,6 +15,8 @@ jobs:
env:
QT_VERSION: 6.4.1
QIF_VERSION: 4.5
+ PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
steps:
- name: 'Install desktop Qt'
diff --git a/.gitmodules b/.gitmodules
index 78d45e25..3ceaa56e 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,6 @@
[submodule "client/3rd/amneziawg-apple"]
path = client/3rd/amneziawg-apple
url = https://github.com/amnezia-vpn/amneziawg-apple
+[submodule "client/3rd/QSimpleCrypto"]
+ path = client/3rd/QSimpleCrypto
+ url = https://github.com/amnezia-vpn/QSimpleCrypto.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 51ca8edc..fba4183c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
-project(${PROJECT} VERSION 4.6.1.0
+project(${PROJECT} VERSION 4.8.1.9
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
-set(APP_ANDROID_VERSION_CODE 56)
+set(APP_ANDROID_VERSION_CODE 65)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
diff --git a/README.md b/README.md
index 64fe5e0c..e4a6bf0c 100644
--- a/README.md
+++ b/README.md
@@ -10,10 +10,10 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
-
-
-
-
+
+
+
+
@@ -28,11 +28,12 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
## Features
-- Very easy to use - enter your IP address, SSH login, and password, and Amnezia will automatically install VPN docker containers to your server and connect to the VPN.
-- OpenVPN, Shadowsocks, WireGuard, and IKEv2 protocols support.
-- Masking VPN with OpenVPN over Cloak plugin
-- Split tunneling support - add any sites to the client to enable VPN only for them (only for desktops)
+- Very easy to use - enter your IP address, SSH login, password and Amnezia will automatically install VPN docker containers to your server and connect to the VPN.
+- Classic VPN-protocols: OpenVPN, WireGuard and IKEv2 protocols.
+- Protocols with traffic Masking (Obfuscation): OpenVPN over [Cloak](https://github.com/cbeuw/Cloak) plugin, Shadowsocks (OpenVPN over Shadowsocks), [AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/) and XRay.
+- Split tunneling support - add any sites to the client to enable VPN only for them or add Apps (only for Android and Desktop).
- Windows, MacOS, Linux, Android, iOS releases.
+- Support for AmneziaWG protocol configuration on [Keenetic beta firmware](https://docs.keenetic.com/ua/air/kn-1611/en/6319-latest-development-release.html#UUID-186c4108-5afd-c10b-f38a-cdff6c17fab3_section-idm33192196168192-improved).
## Links
@@ -41,7 +42,8 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
- [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Telegram support channel (English)
- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Telegram support channel (Farsi)
- [https://t.me/amnezia_vpn_mm](https://t.me/amnezia_vpn_mm) - Telegram support channel (Myanmar)
-- [https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Telegram support channel (Russian)
+- [https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Telegram support channel (Russian)
+- [https://vpnpay.io/en/amnezia-premium/](https://vpnpay.io/en/amnezia-premium/) - Amnezia Premium
## Tech
@@ -181,6 +183,7 @@ GPL v3.0
Patreon: [https://www.patreon.com/amneziavpn](https://www.patreon.com/amneziavpn)
+Bitcoin: bc1q26eevjcg9j0wuyywd2e3uc9cs2w58lpkpjxq6p
USDT BEP20: 0x6abD576765a826f87D1D95183438f9408C901bE4
USDT TRC20: TELAitazF1MZGmiNjTcnxDjEiH5oe7LC9d
XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3
diff --git a/client/3rd-prebuilt b/client/3rd-prebuilt
index c38a587f..ba580dc5 160000
--- a/client/3rd-prebuilt
+++ b/client/3rd-prebuilt
@@ -1 +1 @@
-Subproject commit c38a587fcda89bab4009560d36239fa8de74705e
+Subproject commit ba580dc5bd7784f7b1e110ff0365f3286e549a61
diff --git a/client/3rd/OpenVPNAdapter b/client/3rd/OpenVPNAdapter
index dea60409..7c821a8d 160000
--- a/client/3rd/OpenVPNAdapter
+++ b/client/3rd/OpenVPNAdapter
@@ -1 +1 @@
-Subproject commit dea6040996298e947d63fb172709e6abfec2ba93
+Subproject commit 7c821a8d5c1ad5ad94e0763b4f25a875b5a6fe1b
diff --git a/client/3rd/QSimpleCrypto b/client/3rd/QSimpleCrypto
new file mode 160000
index 00000000..c99b33f0
--- /dev/null
+++ b/client/3rd/QSimpleCrypto
@@ -0,0 +1 @@
+Subproject commit c99b33f0e08b7206116ddff85c22d3b97ce1e79d
diff --git a/client/3rd/QSimpleCrypto/QSimpleCrypto.cmake b/client/3rd/QSimpleCrypto/QSimpleCrypto.cmake
deleted file mode 100644
index 7ec5498a..00000000
--- a/client/3rd/QSimpleCrypto/QSimpleCrypto.cmake
+++ /dev/null
@@ -1,20 +0,0 @@
-include_directories(${CMAKE_CURRENT_LIST_DIR})
-
-set(HEADERS ${HEADERS}
- ${CMAKE_CURRENT_LIST_DIR}/include/QAead.h
- ${CMAKE_CURRENT_LIST_DIR}/include/QBlockCipher.h
- ${CMAKE_CURRENT_LIST_DIR}/include/QCryptoError.h
- ${CMAKE_CURRENT_LIST_DIR}/include/QRsa.h
- ${CMAKE_CURRENT_LIST_DIR}/include/QSimpleCrypto_global.h
- ${CMAKE_CURRENT_LIST_DIR}/include/QX509.h
- ${CMAKE_CURRENT_LIST_DIR}/include/QX509Store.h
-)
-
-set(SOURCES ${SOURCES}
- ${CMAKE_CURRENT_LIST_DIR}/sources/QAead.cpp
- ${CMAKE_CURRENT_LIST_DIR}/sources/QBlockCipher.cpp
- ${CMAKE_CURRENT_LIST_DIR}/sources/QCryptoError.cpp
- ${CMAKE_CURRENT_LIST_DIR}/sources/QRsa.cpp
- ${CMAKE_CURRENT_LIST_DIR}/sources/QX509.cpp
- ${CMAKE_CURRENT_LIST_DIR}/sources/QX509Store.cpp
-)
diff --git a/client/3rd/QSimpleCrypto/QSimpleCrypto.pri b/client/3rd/QSimpleCrypto/QSimpleCrypto.pri
deleted file mode 100644
index 99a1c129..00000000
--- a/client/3rd/QSimpleCrypto/QSimpleCrypto.pri
+++ /dev/null
@@ -1,18 +0,0 @@
-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
deleted file mode 100644
index 11f60b31..00000000
--- a/client/3rd/QSimpleCrypto/include/QAead.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * 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
deleted file mode 100644
index e7b83a88..00000000
--- a/client/3rd/QSimpleCrypto/include/QBlockCipher.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * 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
deleted file mode 100644
index fc059654..00000000
--- a/client/3rd/QSimpleCrypto/include/QCryptoError.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#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
deleted file mode 100644
index 45eb3169..00000000
--- a/client/3rd/QSimpleCrypto/include/QRsa.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * 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
deleted file mode 100644
index fdd6c020..00000000
--- a/client/3rd/QSimpleCrypto/include/QSimpleCrypto_global.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#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
deleted file mode 100644
index c31cb9e4..00000000
--- a/client/3rd/QSimpleCrypto/include/QX509.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * 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(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
deleted file mode 100644
index 8cd8ca82..00000000
--- a/client/3rd/QSimpleCrypto/include/QX509Store.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * 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
deleted file mode 100644
index 968c8841..00000000
--- a/client/3rd/QSimpleCrypto/sources/QAead.cpp
+++ /dev/null
@@ -1,364 +0,0 @@
-/**
- * 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
deleted file mode 100644
index 8b86ab98..00000000
--- a/client/3rd/QSimpleCrypto/sources/QBlockCipher.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-/**
- * 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
deleted file mode 100644
index 234f55d7..00000000
--- a/client/3rd/QSimpleCrypto/sources/QCryptoError.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#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
deleted file mode 100644
index 544d6746..00000000
--- a/client/3rd/QSimpleCrypto/sources/QRsa.cpp
+++ /dev/null
@@ -1,274 +0,0 @@
-/**
- * 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
deleted file mode 100644
index ac4fd270..00000000
--- a/client/3rd/QSimpleCrypto/sources/QX509.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/**
- * 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(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
deleted file mode 100644
index bbbec1a8..00000000
--- a/client/3rd/QSimpleCrypto/sources/QX509Store.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/**
- * 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/SingleApplication/singleapplication.cmake b/client/3rd/SingleApplication/singleapplication.cmake
deleted file mode 100644
index 78abfa8a..00000000
--- a/client/3rd/SingleApplication/singleapplication.cmake
+++ /dev/null
@@ -1,25 +0,0 @@
-include_directories(${CMAKE_CURRENT_LIST_DIR})
-
-find_package(Qt6 REQUIRED COMPONENTS
- Core Network
-)
-set(LIBS ${LIBS} Qt6::Core Qt6::Network)
-
-
-set(HEADERS ${HEADERS}
- ${CMAKE_CURRENT_LIST_DIR}/singleapplication.h
- ${CMAKE_CURRENT_LIST_DIR}/singleapplication_p.h
-)
-
-set(SOURCES ${SOURCES}
- ${CMAKE_CURRENT_LIST_DIR}/singleapplication.cpp
- ${CMAKE_CURRENT_LIST_DIR}/singleapplication_p.cpp
-)
-
-if(WIN32)
- if(MSVC)
- set(LIBS ${LIBS} Advapi32.lib)
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- set(LIBS ${LIBS} advapi32)
- endif()
-endif()
diff --git a/client/3rd/SingleApplication/singleapplication.cpp b/client/3rd/SingleApplication/singleapplication.cpp
deleted file mode 100644
index 7e153a00..00000000
--- a/client/3rd/SingleApplication/singleapplication.cpp
+++ /dev/null
@@ -1,274 +0,0 @@
-// The MIT License (MIT)
-//
-// Copyright (c) Itay Grudev 2015 - 2020
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include
-#include
-#include
-
-#include "singleapplication.h"
-#include "singleapplication_p.h"
-
-/**
- * @brief Constructor. Checks and fires up LocalServer or closes the program
- * if another instance already exists
- * @param argc
- * @param argv
- * @param allowSecondary Whether to enable secondary instance support
- * @param options Optional flags to toggle specific behaviour
- * @param timeout Maximum time blocking functions are allowed during app load
- */
-SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout, const QString &userData )
- : app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) )
-{
- Q_D( SingleApplication );
-
-#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
- // On Android and iOS since the library is not supported fallback to
- // standard QApplication behaviour by simply returning at this point.
- qWarning() << "SingleApplication is not supported on Android and iOS systems.";
- return;
-#endif
-
- // Store the current mode of the program
- d->options = options;
-
- // Add any unique user data
- if ( ! userData.isEmpty() )
- d->addAppData( userData );
-
- // Generating an application ID used for identifying the shared memory
- // block and QLocalServer
- d->genBlockServerName();
-
- // To mitigate QSharedMemory issues with large amount of processes
- // attempting to attach at the same time
- SingleApplicationPrivate::randomSleep();
-
-#ifdef Q_OS_UNIX
- // By explicitly attaching it and then deleting it we make sure that the
- // memory is deleted even after the process has crashed on Unix.
- d->memory = new QSharedMemory( d->blockServerName );
- d->memory->attach();
- delete d->memory;
-#endif
- // Guarantee thread safe behaviour with a shared memory block.
- d->memory = new QSharedMemory( d->blockServerName );
-
- // Create a shared memory block
- if( d->memory->create( sizeof( InstancesInfo ) )){
- // Initialize the shared memory block
- if( ! d->memory->lock() ){
- qCritical() << "SingleApplication: Unable to lock memory block after create.";
- abortSafely();
- }
- d->initializeMemoryBlock();
- } else {
- if( d->memory->error() == QSharedMemory::AlreadyExists ){
- // Attempt to attach to the memory segment
- if( ! d->memory->attach() ){
- qCritical() << "SingleApplication: Unable to attach to shared memory block.";
- abortSafely();
- }
- if( ! d->memory->lock() ){
- qCritical() << "SingleApplication: Unable to lock memory block after attach.";
- abortSafely();
- }
- } else {
- qCritical() << "SingleApplication: Unable to create block.";
- abortSafely();
- }
- }
-
- auto *inst = static_cast( d->memory->data() );
- QElapsedTimer time;
- time.start();
-
- // Make sure the shared memory block is initialised and in consistent state
- while( true ){
- // If the shared memory block's checksum is valid continue
- if( d->blockChecksum() == inst->checksum ) break;
-
- // If more than 5s have elapsed, assume the primary instance crashed and
- // assume it's position
- if( time.elapsed() > 5000 ){
- qWarning() << "SingleApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
- d->initializeMemoryBlock();
- }
-
- // Otherwise wait for a random period and try again. The random sleep here
- // limits the probability of a collision between two racing apps and
- // allows the app to initialise faster
- if( ! d->memory->unlock() ){
- qDebug() << "SingleApplication: Unable to unlock memory for random wait.";
- qDebug() << d->memory->errorString();
- }
- SingleApplicationPrivate::randomSleep();
- if( ! d->memory->lock() ){
- qCritical() << "SingleApplication: Unable to lock memory after random wait.";
- abortSafely();
- }
- }
-
- if( inst->primary == false ){
- d->startPrimary();
- if( ! d->memory->unlock() ){
- qDebug() << "SingleApplication: Unable to unlock memory after primary start.";
- qDebug() << d->memory->errorString();
- }
- return;
- }
-
- // Check if another instance can be started
- if( allowSecondary ){
- d->startSecondary();
- if( d->options & Mode::SecondaryNotification ){
- d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance );
- }
- if( ! d->memory->unlock() ){
- qDebug() << "SingleApplication: Unable to unlock memory after secondary start.";
- qDebug() << d->memory->errorString();
- }
- return;
- }
-
- if( ! d->memory->unlock() ){
- qDebug() << "SingleApplication: Unable to unlock memory at end of execution.";
- qDebug() << d->memory->errorString();
- }
-
- d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance );
-
- delete d;
-
- ::exit( EXIT_SUCCESS );
-}
-
-SingleApplication::~SingleApplication()
-{
- Q_D( SingleApplication );
- delete d;
-}
-
-/**
- * Checks if the current application instance is primary.
- * @return Returns true if the instance is primary, false otherwise.
- */
-bool SingleApplication::isPrimary() const
-{
- Q_D( const SingleApplication );
- return d->server != nullptr;
-}
-
-/**
- * Checks if the current application instance is secondary.
- * @return Returns true if the instance is secondary, false otherwise.
- */
-bool SingleApplication::isSecondary() const
-{
- Q_D( const SingleApplication );
- return d->server == nullptr;
-}
-
-/**
- * Allows you to identify an instance by returning unique consecutive instance
- * ids. It is reset when the first (primary) instance of your app starts and
- * only incremented afterwards.
- * @return Returns a unique instance id.
- */
-quint32 SingleApplication::instanceId() const
-{
- Q_D( const SingleApplication );
- return d->instanceNumber;
-}
-
-/**
- * Returns the OS PID (Process Identifier) of the process running the primary
- * instance. Especially useful when SingleApplication is coupled with OS.
- * specific APIs.
- * @return Returns the primary instance PID.
- */
-qint64 SingleApplication::primaryPid() const
-{
- Q_D( const SingleApplication );
- return d->primaryPid();
-}
-
-/**
- * Returns the username the primary instance is running as.
- * @return Returns the username the primary instance is running as.
- */
-QString SingleApplication::primaryUser() const
-{
- Q_D( const SingleApplication );
- return d->primaryUser();
-}
-
-/**
- * Returns the username the current instance is running as.
- * @return Returns the username the current instance is running as.
- */
-QString SingleApplication::currentUser() const
-{
- return SingleApplicationPrivate::getUsername();
-}
-
-/**
- * Sends message to the Primary Instance.
- * @param message The message to send.
- * @param timeout the maximum timeout in milliseconds for blocking functions.
- * @return true if the message was sent successfuly, false otherwise.
- */
-bool SingleApplication::sendMessage( const QByteArray &message, int timeout )
-{
- Q_D( SingleApplication );
-
- // Nobody to connect to
- if( isPrimary() ) return false;
-
- // Make sure the socket is connected
- if( ! d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect ) )
- return false;
-
- d->socket->write( message );
- bool dataWritten = d->socket->waitForBytesWritten( timeout );
- d->socket->flush();
- return dataWritten;
-}
-
-/**
- * Cleans up the shared memory block and exits with a failure.
- * This function halts program execution.
- */
-void SingleApplication::abortSafely()
-{
- Q_D( SingleApplication );
-
- qCritical() << "SingleApplication: " << d->memory->error() << d->memory->errorString();
- delete d;
- ::exit( EXIT_FAILURE );
-}
-
-QStringList SingleApplication::userData() const
-{
- Q_D( const SingleApplication );
- return d->appData();
-}
diff --git a/client/3rd/SingleApplication/singleapplication.h b/client/3rd/SingleApplication/singleapplication.h
deleted file mode 100644
index 400c88ac..00000000
--- a/client/3rd/SingleApplication/singleapplication.h
+++ /dev/null
@@ -1,154 +0,0 @@
-// The MIT License (MIT)
-//
-// Copyright (c) Itay Grudev 2015 - 2018
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#ifndef SINGLE_APPLICATION_H
-#define SINGLE_APPLICATION_H
-
-#include
-#include
-
-#ifndef QAPPLICATION_CLASS
- #define QAPPLICATION_CLASS QApplication
-#endif
-
-#include QT_STRINGIFY(QAPPLICATION_CLASS)
-
-class SingleApplicationPrivate;
-
-/**
- * @brief The SingleApplication class handles multiple instances of the same
- * Application
- * @see QCoreApplication
- */
-class SingleApplication : public QAPPLICATION_CLASS
-{
- Q_OBJECT
-
- using app_t = QAPPLICATION_CLASS;
-
-public:
- /**
- * @brief Mode of operation of SingleApplication.
- * Whether the block should be user-wide or system-wide and whether the
- * primary instance should be notified when a secondary instance had been
- * started.
- * @note Operating system can restrict the shared memory blocks to the same
- * user, in which case the User/System modes will have no effect and the
- * block will be user wide.
- * @enum
- */
- enum Mode {
- User = 1 << 0,
- System = 1 << 1,
- SecondaryNotification = 1 << 2,
- ExcludeAppVersion = 1 << 3,
- ExcludeAppPath = 1 << 4
- };
- Q_DECLARE_FLAGS(Options, Mode)
-
- /**
- * @brief Intitializes a SingleApplication instance with argc command line
- * arguments in argv
- * @arg {int &} argc - Number of arguments in argv
- * @arg {const char *[]} argv - Supplied command line arguments
- * @arg {bool} allowSecondary - Whether to start the instance as secondary
- * if there is already a primary instance.
- * @arg {Mode} mode - Whether for the SingleApplication block to be applied
- * User wide or System wide.
- * @arg {int} timeout - Timeout to wait in milliseconds.
- * @note argc and argv may be changed as Qt removes arguments that it
- * recognizes
- * @note Mode::SecondaryNotification only works if set on both the primary
- * instance and the secondary instance.
- * @note The timeout is just a hint for the maximum time of blocking
- * operations. It does not guarantee that the SingleApplication
- * initialisation will be completed in given time, though is a good hint.
- * Usually 4*timeout would be the worst case (fail) scenario.
- * @see See the corresponding QAPPLICATION_CLASS constructor for reference
- */
- explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000, const QString &userData = {} );
- ~SingleApplication() override;
-
- /**
- * @brief Returns if the instance is the primary instance
- * @returns {bool}
- */
- bool isPrimary() const;
-
- /**
- * @brief Returns if the instance is a secondary instance
- * @returns {bool}
- */
- bool isSecondary() const;
-
- /**
- * @brief Returns a unique identifier for the current instance
- * @returns {qint32}
- */
- quint32 instanceId() const;
-
- /**
- * @brief Returns the process ID (PID) of the primary instance
- * @returns {qint64}
- */
- qint64 primaryPid() const;
-
- /**
- * @brief Returns the username of the user running the primary instance
- * @returns {QString}
- */
- QString primaryUser() const;
-
- /**
- * @brief Returns the username of the current user
- * @returns {QString}
- */
- QString currentUser() const;
-
- /**
- * @brief Sends a message to the primary instance. Returns true on success.
- * @param {int} timeout - Timeout for connecting
- * @returns {bool}
- * @note sendMessage() will return false if invoked from the primary
- * instance.
- */
- bool sendMessage( const QByteArray &message, int timeout = 100 );
-
- /**
- * @brief Get the set user data.
- * @returns {QStringList}
- */
- QStringList userData() const;
-
-Q_SIGNALS:
- void instanceStarted();
- void receivedMessage( quint32 instanceId, QByteArray message );
-
-private:
- SingleApplicationPrivate *d_ptr;
- Q_DECLARE_PRIVATE(SingleApplication)
- void abortSafely();
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options)
-
-#endif // SINGLE_APPLICATION_H
diff --git a/client/3rd/SingleApplication/singleapplication.pri b/client/3rd/SingleApplication/singleapplication.pri
deleted file mode 100644
index 80283fc4..00000000
--- a/client/3rd/SingleApplication/singleapplication.pri
+++ /dev/null
@@ -1,15 +0,0 @@
-QT += core network
-CONFIG += c++11
-
-HEADERS += \
- $$PWD/singleapplication.h \
- $$PWD/singleapplication_p.h
-SOURCES += $$PWD/singleapplication.cpp \
- $$PWD/singleapplication_p.cpp
-
-INCLUDEPATH += $$PWD
-
-win32 {
- msvc:LIBS += Advapi32.lib
- gcc:LIBS += -ladvapi32
-}
diff --git a/client/3rd/SingleApplication/singleapplication_p.cpp b/client/3rd/SingleApplication/singleapplication_p.cpp
deleted file mode 100644
index e65bd955..00000000
--- a/client/3rd/SingleApplication/singleapplication_p.cpp
+++ /dev/null
@@ -1,486 +0,0 @@
-// The MIT License (MIT)
-//
-// Copyright (c) Itay Grudev 2015 - 2020
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-//
-// W A R N I N G !!!
-// -----------------
-//
-// This file is not part of the SingleApplication API. It is used purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or may even be removed.
-//
-
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
-#include
-#else
-#include
-#endif
-
-#include "singleapplication.h"
-#include "singleapplication_p.h"
-
-#ifdef Q_OS_UNIX
- #include
- #include
- #include
-#endif
-
-#ifdef Q_OS_WIN
- #ifndef NOMINMAX
- #define NOMINMAX 1
- #endif
- #include
- #include
-#endif
-
-SingleApplicationPrivate::SingleApplicationPrivate( SingleApplication *q_ptr )
- : q_ptr( q_ptr )
-{
- server = nullptr;
- socket = nullptr;
- memory = nullptr;
- instanceNumber = 0;
-}
-
-SingleApplicationPrivate::~SingleApplicationPrivate()
-{
- if( socket != nullptr ){
- socket->close();
- delete socket;
- }
-
- if( memory != nullptr ){
- memory->lock();
- auto *inst = static_cast(memory->data());
- if( server != nullptr ){
- server->close();
- delete server;
- inst->primary = false;
- inst->primaryPid = -1;
- inst->primaryUser[0] = '\0';
- inst->checksum = blockChecksum();
- }
- memory->unlock();
-
- delete memory;
- }
-}
-
-QString SingleApplicationPrivate::getUsername()
-{
-#ifdef Q_OS_WIN
- wchar_t username[UNLEN + 1];
- // Specifies size of the buffer on input
- DWORD usernameLength = UNLEN + 1;
- if( GetUserNameW( username, &usernameLength ) )
- return QString::fromWCharArray( username );
-#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
- return QString::fromLocal8Bit( qgetenv( "USERNAME" ) );
-#else
- return qEnvironmentVariable( "USERNAME" );
-#endif
-#endif
-#ifdef Q_OS_UNIX
- QString username;
- uid_t uid = geteuid();
- struct passwd *pw = getpwuid( uid );
- if( pw )
- username = QString::fromLocal8Bit( pw->pw_name );
- if ( username.isEmpty() ){
-#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
- username = QString::fromLocal8Bit( qgetenv( "USER" ) );
-#else
- username = qEnvironmentVariable( "USER" );
-#endif
- }
- return username;
-#endif
-}
-
-void SingleApplicationPrivate::genBlockServerName()
-{
- QCryptographicHash appData( QCryptographicHash::Sha256 );
- appData.addData( "SingleApplication", 17 );
- appData.addData( SingleApplication::app_t::applicationName().toUtf8() );
- appData.addData( SingleApplication::app_t::organizationName().toUtf8() );
- appData.addData( SingleApplication::app_t::organizationDomain().toUtf8() );
-
- if ( ! appDataList.isEmpty() )
- appData.addData( appDataList.join( "" ).toUtf8() );
-
- if( ! (options & SingleApplication::Mode::ExcludeAppVersion) ){
- appData.addData( SingleApplication::app_t::applicationVersion().toUtf8() );
- }
-
- if( ! (options & SingleApplication::Mode::ExcludeAppPath) ){
-#ifdef Q_OS_WIN
- appData.addData( SingleApplication::app_t::applicationFilePath().toLower().toUtf8() );
-#else
- appData.addData( SingleApplication::app_t::applicationFilePath().toUtf8() );
-#endif
- }
-
- // User level block requires a user specific data in the hash
- if( options & SingleApplication::Mode::User ){
- appData.addData( getUsername().toUtf8() );
- }
-
- // Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with
- // server naming requirements.
- blockServerName = appData.result().toBase64().replace("/", "_");
-}
-
-void SingleApplicationPrivate::initializeMemoryBlock() const
-{
- auto *inst = static_cast( memory->data() );
- inst->primary = false;
- inst->secondary = 0;
- inst->primaryPid = -1;
- inst->primaryUser[0] = '\0';
- inst->checksum = blockChecksum();
-}
-
-void SingleApplicationPrivate::startPrimary()
-{
- // Reset the number of connections
- auto *inst = static_cast ( memory->data() );
-
- inst->primary = true;
- inst->primaryPid = QCoreApplication::applicationPid();
- qstrncpy( inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser) );
- inst->checksum = blockChecksum();
- instanceNumber = 0;
- // Successful creation means that no main process exists
- // So we start a QLocalServer to listen for connections
- QLocalServer::removeServer( blockServerName );
- server = new QLocalServer();
-
- // Restrict access to the socket according to the
- // SingleApplication::Mode::User flag on User level or no restrictions
- if( options & SingleApplication::Mode::User ){
- server->setSocketOptions( QLocalServer::UserAccessOption );
- } else {
- server->setSocketOptions( QLocalServer::WorldAccessOption );
- }
-
- server->listen( blockServerName );
- QObject::connect(
- server,
- &QLocalServer::newConnection,
- this,
- &SingleApplicationPrivate::slotConnectionEstablished
- );
-}
-
-void SingleApplicationPrivate::startSecondary()
-{
- auto *inst = static_cast ( memory->data() );
-
- inst->secondary += 1;
- inst->checksum = blockChecksum();
- instanceNumber = inst->secondary;
-}
-
-bool SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType )
-{
- QElapsedTimer time;
- time.start();
-
- // Connect to the Local Server of the Primary Instance if not already
- // connected.
- if( socket == nullptr ){
- socket = new QLocalSocket();
- }
-
- if( socket->state() == QLocalSocket::ConnectedState ) return true;
-
- if( socket->state() != QLocalSocket::ConnectedState ){
-
- while( true ){
- randomSleep();
-
- if( socket->state() != QLocalSocket::ConnectingState )
- socket->connectToServer( blockServerName );
-
- if( socket->state() == QLocalSocket::ConnectingState ){
- socket->waitForConnected( static_cast(msecs - time.elapsed()) );
- }
-
- // If connected break out of the loop
- if( socket->state() == QLocalSocket::ConnectedState ) break;
-
- // If elapsed time since start is longer than the method timeout return
- if( time.elapsed() >= msecs ) return false;
- }
- }
-
- // Initialisation message according to the SingleApplication protocol
- QByteArray initMsg;
- QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
-
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
- writeStream.setVersion(QDataStream::Qt_5_6);
-#endif
-
- writeStream << blockServerName.toLatin1();
- writeStream << static_cast(connectionType);
- writeStream << instanceNumber;
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- quint16 checksum = qChecksum(QByteArray(initMsg, static_cast(initMsg.length())));
-#else
- quint16 checksum = qChecksum(initMsg.constData(), static_cast(initMsg.length()));
-#endif
- writeStream << checksum;
-
- // The header indicates the message length that follows
- QByteArray header;
- QDataStream headerStream(&header, QIODevice::WriteOnly);
-
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
- headerStream.setVersion(QDataStream::Qt_5_6);
-#endif
- headerStream << static_cast ( initMsg.length() );
-
- socket->write( header );
- socket->write( initMsg );
- bool result = socket->waitForBytesWritten( static_cast(msecs - time.elapsed()) );
- socket->flush();
- return result;
-}
-
-quint16 SingleApplicationPrivate::blockChecksum() const
-{
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- quint16 checksum = qChecksum(QByteArray(static_cast(memory->constData()), offsetof(InstancesInfo, checksum)));
-#else
- quint16 checksum = qChecksum(static_cast(memory->constData()), offsetof(InstancesInfo, checksum));
-#endif
- return checksum;
-}
-
-qint64 SingleApplicationPrivate::primaryPid() const
-{
- qint64 pid;
-
- memory->lock();
- auto *inst = static_cast( memory->data() );
- pid = inst->primaryPid;
- memory->unlock();
-
- return pid;
-}
-
-QString SingleApplicationPrivate::primaryUser() const
-{
- QByteArray username;
-
- memory->lock();
- auto *inst = static_cast( memory->data() );
- username = inst->primaryUser;
- memory->unlock();
-
- return QString::fromUtf8( username );
-}
-
-/**
- * @brief Executed when a connection has been made to the LocalServer
- */
-void SingleApplicationPrivate::slotConnectionEstablished()
-{
- QLocalSocket *nextConnSocket = server->nextPendingConnection();
- connectionMap.insert(nextConnSocket, ConnectionInfo());
-
- QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose,
- [nextConnSocket, this](){
- auto &info = connectionMap[nextConnSocket];
- Q_EMIT this->slotClientConnectionClosed( nextConnSocket, info.instanceId );
- }
- );
-
- QObject::connect(nextConnSocket, &QLocalSocket::disconnected, nextConnSocket, &QLocalSocket::deleteLater);
-
- QObject::connect(nextConnSocket, &QLocalSocket::destroyed,
- [nextConnSocket, this](){
- connectionMap.remove(nextConnSocket);
- }
- );
-
- QObject::connect(nextConnSocket, &QLocalSocket::readyRead,
- [nextConnSocket, this](){
- auto &info = connectionMap[nextConnSocket];
- switch(info.stage){
- case StageHeader:
- readInitMessageHeader(nextConnSocket);
- break;
- case StageBody:
- readInitMessageBody(nextConnSocket);
- break;
- case StageConnected:
- Q_EMIT this->slotDataAvailable( nextConnSocket, info.instanceId );
- break;
- default:
- break;
- };
- }
- );
-}
-
-void SingleApplicationPrivate::readInitMessageHeader( QLocalSocket *sock )
-{
- if (!connectionMap.contains( sock )){
- return;
- }
-
- if( sock->bytesAvailable() < ( qint64 )sizeof( quint64 ) ){
- return;
- }
-
- QDataStream headerStream( sock );
-
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
- headerStream.setVersion( QDataStream::Qt_5_6 );
-#endif
-
- // Read the header to know the message length
- quint64 msgLen = 0;
- headerStream >> msgLen;
- ConnectionInfo &info = connectionMap[sock];
- info.stage = StageBody;
- info.msgLen = msgLen;
-
- if ( sock->bytesAvailable() >= (qint64) msgLen ){
- readInitMessageBody( sock );
- }
-}
-
-void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock )
-{
- Q_Q(SingleApplication);
-
- if (!connectionMap.contains( sock )){
- return;
- }
-
- ConnectionInfo &info = connectionMap[sock];
- if( sock->bytesAvailable() < ( qint64 )info.msgLen ){
- return;
- }
-
- // Read the message body
- QByteArray msgBytes = sock->read(info.msgLen);
- QDataStream readStream(msgBytes);
-
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
- readStream.setVersion( QDataStream::Qt_5_6 );
-#endif
-
- // server name
- QByteArray latin1Name;
- readStream >> latin1Name;
-
- // connection type
- ConnectionType connectionType = InvalidConnection;
- quint8 connTypeVal = InvalidConnection;
- readStream >> connTypeVal;
- connectionType = static_cast ( connTypeVal );
-
- // instance id
- quint32 instanceId = 0;
- readStream >> instanceId;
-
- // checksum
- quint16 msgChecksum = 0;
- readStream >> msgChecksum;
-
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- const quint16 actualChecksum = qChecksum(QByteArray(msgBytes, static_cast(msgBytes.length() - sizeof(quint16))));
-#else
- const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast(msgBytes.length() - sizeof(quint16)));
-#endif
-
- bool isValid = readStream.status() == QDataStream::Ok &&
- QLatin1String(latin1Name) == blockServerName &&
- msgChecksum == actualChecksum;
-
- if( !isValid ){
- sock->close();
- return;
- }
-
- info.instanceId = instanceId;
- info.stage = StageConnected;
-
- if( connectionType == NewInstance ||
- ( connectionType == SecondaryInstance &&
- options & SingleApplication::Mode::SecondaryNotification ) )
- {
- Q_EMIT q->instanceStarted();
- }
-
- if (sock->bytesAvailable() > 0){
- Q_EMIT this->slotDataAvailable( sock, instanceId );
- }
-}
-
-void SingleApplicationPrivate::slotDataAvailable( QLocalSocket *dataSocket, quint32 instanceId )
-{
- Q_Q(SingleApplication);
- Q_EMIT q->receivedMessage( instanceId, dataSocket->readAll() );
-}
-
-void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedSocket, quint32 instanceId )
-{
- if( closedSocket->bytesAvailable() > 0 )
- Q_EMIT slotDataAvailable( closedSocket, instanceId );
-}
-
-void SingleApplicationPrivate::randomSleep()
-{
-#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
- QThread::msleep( QRandomGenerator::global()->bounded( 8u, 18u ));
-#else
- qsrand( QDateTime::currentMSecsSinceEpoch() % std::numeric_limits::max() );
- QThread::msleep( 8 + static_cast ( static_cast ( qrand() ) / RAND_MAX * 10 ));
-#endif
-}
-
-void SingleApplicationPrivate::addAppData(const QString &data)
-{
- appDataList.push_back(data);
-}
-
-QStringList SingleApplicationPrivate::appData() const
-{
- return appDataList;
-}
diff --git a/client/3rd/SingleApplication/singleapplication_p.h b/client/3rd/SingleApplication/singleapplication_p.h
deleted file mode 100644
index c49a46dd..00000000
--- a/client/3rd/SingleApplication/singleapplication_p.h
+++ /dev/null
@@ -1,104 +0,0 @@
-// The MIT License (MIT)
-//
-// Copyright (c) Itay Grudev 2015 - 2020
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-//
-// W A R N I N G !!!
-// -----------------
-//
-// This file is not part of the SingleApplication API. It is used purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or may even be removed.
-//
-
-#ifndef SINGLEAPPLICATION_P_H
-#define SINGLEAPPLICATION_P_H
-
-#include
-#include
-#include
-#include "singleapplication.h"
-
-struct InstancesInfo {
- bool primary;
- quint32 secondary;
- qint64 primaryPid;
- char primaryUser[128];
- quint16 checksum; // Must be the last field
-};
-
-struct ConnectionInfo {
- qint64 msgLen = 0;
- quint32 instanceId = 0;
- quint8 stage = 0;
-};
-
-class SingleApplicationPrivate : public QObject {
-Q_OBJECT
-public:
- enum ConnectionType : quint8 {
- InvalidConnection = 0,
- NewInstance = 1,
- SecondaryInstance = 2,
- Reconnect = 3
- };
- enum ConnectionStage : quint8 {
- StageHeader = 0,
- StageBody = 1,
- StageConnected = 2,
- };
- Q_DECLARE_PUBLIC(SingleApplication)
-
- SingleApplicationPrivate( SingleApplication *q_ptr );
- ~SingleApplicationPrivate() override;
-
- static QString getUsername();
- void genBlockServerName();
- void initializeMemoryBlock() const;
- void startPrimary();
- void startSecondary();
- bool connectToPrimary( int msecs, ConnectionType connectionType );
- quint16 blockChecksum() const;
- qint64 primaryPid() const;
- QString primaryUser() const;
- void readInitMessageHeader(QLocalSocket *socket);
- void readInitMessageBody(QLocalSocket *socket);
- static void randomSleep();
- void addAppData(const QString &data);
- QStringList appData() const;
-
- SingleApplication *q_ptr;
- QSharedMemory *memory;
- QLocalSocket *socket;
- QLocalServer *server;
- quint32 instanceNumber;
- QString blockServerName;
- SingleApplication::Options options;
- QMap connectionMap;
- QStringList appDataList;
-
-public Q_SLOTS:
- void slotConnectionEstablished();
- void slotDataAvailable( QLocalSocket*, quint32 );
- void slotClientConnectionClosed( QLocalSocket*, quint32 );
-};
-
-#endif // SINGLEAPPLICATION_P_H
diff --git a/client/3rd/qtkeychain b/client/3rd/qtkeychain
index 74776e2a..7460df6a 160000
--- a/client/3rd/qtkeychain
+++ b/client/3rd/qtkeychain
@@ -1 +1 @@
-Subproject commit 74776e2a3e2d98d19943e0968901c5b5e04cc1bd
+Subproject commit 7460df6a978669290de5b56c2d98b199b61c3f88
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index 1fc28b82..2de5db48 100644
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -24,6 +24,12 @@ execute_process(
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
+add_definitions(-DPROD_AGW_PUBLIC_KEY="$ENV{PROD_AGW_PUBLIC_KEY}")
+add_definitions(-DPROD_PROXY_STORAGE_KEY="$ENV{PROD_PROXY_STORAGE_KEY}")
+
+add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}")
+add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}")
+
if(IOS)
set(PACKAGES ${PACKAGES} Multimedia)
endif()
@@ -34,7 +40,7 @@ endif()
find_package(Qt6 REQUIRED COMPONENTS ${PACKAGES})
-set(LIBS ${LIBS}
+set(LIBS ${LIBS}
Qt6::Core Qt6::Gui
Qt6::Network Qt6::Xml Qt6::RemoteObjects
Qt6::Quick Qt6::Svg Qt6::QuickControls2
@@ -55,6 +61,7 @@ qt_add_executable(${PROJECT} MANUAL_FINALIZATION)
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep)
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_interface.rep)
+ qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_tun2socks.rep)
endif()
qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc)
@@ -107,6 +114,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/cmake/3rdparty.cmake)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/../ipc
+ ${CMAKE_CURRENT_LIST_DIR}/../common/logger
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
@@ -128,7 +136,6 @@ set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.h
${CMAKE_CURRENT_LIST_DIR}/protocols/qml_register_protocols.h
${CMAKE_CURRENT_LIST_DIR}/ui/pages.h
- ${CMAKE_CURRENT_LIST_DIR}/ui/property_helper.h
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.h
${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.h
${CMAKE_CURRENT_BINARY_DIR}/version.h
@@ -136,6 +143,8 @@ set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/core/networkUtilities.h
${CMAKE_CURRENT_LIST_DIR}/core/serialization/serialization.h
${CMAKE_CURRENT_LIST_DIR}/core/serialization/transfer.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/enums/apiEnums.h
+ ${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.h
)
# Mozilla headres
@@ -186,6 +195,7 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/core/serialization/trojan.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess_new.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.cpp
)
# Mozilla sources
@@ -252,7 +262,7 @@ set(SOURCES ${SOURCES}
if(WIN32)
configure_file(
- ${CMAKE_CURRENT_LIST_DIR}/platforms/windows/amneziavpn.rc.in
+ ${CMAKE_CURRENT_LIST_DIR}/platforms/windows/amneziavpn.rc.in
${CMAKE_CURRENT_BINARY_DIR}/amneziavpn.rc
)
diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp
index c3adfe31..4e25097d 100644
--- a/client/amnezia_application.cpp
+++ b/client/amnezia_application.cpp
@@ -3,13 +3,15 @@
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
-#include
+#include
+#include
#include "logger.h"
#include "ui/models/installedAppsModel.h"
@@ -28,13 +30,7 @@
#include
#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);
@@ -115,10 +111,11 @@ void AmneziaApplication::init()
qFatal("Android controller initialization failed");
}
- connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, [this](QString data) {
- m_pageController->replaceStartPage();
+ connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, this, [this](QString data) {
+ emit m_pageController->goToPageHome();
m_importController->extractConfigFromData(data);
- m_pageController->goToPageViewConfig();
+ data.clear();
+ emit m_pageController->goToPageViewConfig();
});
m_engine->addImageProvider(QLatin1String("installedAppImage"), new InstalledAppsImageProvider);
@@ -126,16 +123,16 @@ void AmneziaApplication::init()
#ifdef Q_OS_IOS
IosController::Instance()->initialize();
- connect(IosController::Instance(), &IosController::importConfigFromOutside, [this](QString data) {
- m_pageController->replaceStartPage();
+ connect(IosController::Instance(), &IosController::importConfigFromOutside, this, [this](QString data) {
+ emit m_pageController->goToPageHome();
m_importController->extractConfigFromData(data);
- m_pageController->goToPageViewConfig();
+ emit m_pageController->goToPageViewConfig();
});
- connect(IosController::Instance(), &IosController::importBackupFromOutside, [this](QString filePath) {
- m_pageController->replaceStartPage();
+ connect(IosController::Instance(), &IosController::importBackupFromOutside, this, [this](QString filePath) {
+ emit m_pageController->goToPageHome();
m_pageController->goToPageSettingsBackup();
- m_settingsController->importBackupFromOutside(filePath);
+ emit m_settingsController->importBackupFromOutside(filePath);
});
QTimer::singleShot(0, this, [this]() { AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled()); });
@@ -164,7 +161,7 @@ void AmneziaApplication::init()
bool enabled = m_settings->isSaveLogs();
#ifndef Q_OS_ANDROID
if (enabled) {
- if (!Logger::init()) {
+ if (!Logger::init(false)) {
qWarning() << "Initialization of debug subsystem failed";
}
}
@@ -180,16 +177,6 @@ void AmneziaApplication::init()
m_pageController->showOnStartup();
#endif
- // TODO - fix
-#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
- if (isPrimary()) {
- QObject::connect(this, &SingleApplication::instanceStarted, m_pageController.get(), [this]() {
- qDebug() << "Secondary instance started, showing this window instead";
- emit m_pageController->raiseMainWindow();
- });
- }
-#endif
-
// Android TextArea clipboard workaround
// Text from TextArea always has "text/html" mime-type:
// /qt/6.6.1/Src/qtdeclarative/src/quick/items/qquicktextcontrol.cpp:1865
@@ -294,6 +281,24 @@ bool AmneziaApplication::parseCommands()
return true;
}
+#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
+void AmneziaApplication::startLocalServer() {
+ const QString serverName("AmneziaVPNInstance");
+ QLocalServer::removeServer(serverName);
+
+ QLocalServer* server = new QLocalServer(this);
+ server->listen(serverName);
+
+ QObject::connect(server, &QLocalServer::newConnection, this, [server, this]() {
+ if (server) {
+ QLocalSocket* clientConnection = server->nextPendingConnection();
+ clientConnection->deleteLater();
+ }
+ emit m_pageController->raiseMainWindow();
+ });
+}
+#endif
+
QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
{
return m_engine;
@@ -361,6 +366,18 @@ void AmneziaApplication::initModels()
m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get());
connect(m_clientManagementModel.get(), &ClientManagementModel::adminConfigRevoked, m_serversModel.get(),
&ServersModel::clearCachedProfile);
+
+ m_apiServicesModel.reset(new ApiServicesModel(this));
+ m_engine->rootContext()->setContextProperty("ApiServicesModel", m_apiServicesModel.get());
+
+ m_apiCountryModel.reset(new ApiCountryModel(this));
+ m_engine->rootContext()->setContextProperty("ApiCountryModel", m_apiCountryModel.get());
+ connect(m_serversModel.get(), &ServersModel::updateApiLanguageModel, this, [this]() {
+ m_apiCountryModel->updateModel(m_serversModel->getProcessedServerData("apiAvailableCountries").toJsonArray(),
+ m_serversModel->getProcessedServerData("apiServerCountryCode").toString());
+ });
+ connect(m_serversModel.get(), &ServersModel::updateApiServicesModel, this,
+ [this]() { m_apiServicesModel->updateModel(m_serversModel->getProcessedServerData("apiConfig").toJsonObject()); });
}
void AmneziaApplication::initControllers()
@@ -369,25 +386,26 @@ void AmneziaApplication::initControllers()
new ConnectionController(m_serversModel, m_containersModel, m_clientManagementModel, m_vpnConnection, m_settings));
m_engine->rootContext()->setContextProperty("ConnectionController", m_connectionController.get());
- connect(m_connectionController.get(), qOverload(&ConnectionController::connectionErrorOccurred), this, [this](const QString &errorMessage) {
- emit m_pageController->showErrorMessage(errorMessage);
- emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
- });
+ connect(m_connectionController.get(), qOverload(&ConnectionController::connectionErrorOccurred), this,
+ [this](const QString &errorMessage) {
+ emit m_pageController->showErrorMessage(errorMessage);
+ emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
+ });
- connect(m_connectionController.get(), qOverload(&ConnectionController::connectionErrorOccurred), this, [this](ErrorCode errorCode) {
- emit m_pageController->showErrorMessage(errorCode);
- emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
- });
+ connect(m_connectionController.get(), qOverload(&ConnectionController::connectionErrorOccurred), this,
+ [this](ErrorCode errorCode) {
+ emit m_pageController->showErrorMessage(errorCode);
+ emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
+ });
connect(m_connectionController.get(), &ConnectionController::connectButtonClicked, m_connectionController.get(),
&ConnectionController::toggleConnection, Qt::QueuedConnection);
- connect(this, &AmneziaApplication::translationsUpdated, m_connectionController.get(), &ConnectionController::onTranslationsUpdated);
-
m_pageController.reset(new PageController(m_serversModel, m_settings));
m_engine->rootContext()->setContextProperty("PageController", m_pageController.get());
- m_installController.reset(new InstallController(m_serversModel, m_containersModel, m_protocolsModel, m_clientManagementModel, m_settings));
+ m_installController.reset(new InstallController(m_serversModel, m_containersModel, m_protocolsModel, m_clientManagementModel,
+ m_apiServicesModel, m_settings));
m_engine->rootContext()->setContextProperty("InstallController", m_installController.get());
connect(m_installController.get(), &InstallController::passphraseRequestStarted, m_pageController.get(),
&PageController::showPassphraseRequestDrawer);
@@ -396,6 +414,30 @@ void AmneziaApplication::initControllers()
connect(m_installController.get(), &InstallController::currentContainerUpdated, m_connectionController.get(),
&ConnectionController::onCurrentContainerUpdated);
+ connect(m_installController.get(), &InstallController::updateServerFromApiFinished, this, [this]() {
+ disconnect(m_reloadConfigErrorOccurredConnection);
+ emit m_connectionController->configFromApiUpdated();
+ });
+
+ connect(m_connectionController.get(), &ConnectionController::updateApiConfigFromGateway, this, [this]() {
+ m_reloadConfigErrorOccurredConnection = connect(
+ m_installController.get(), qOverload(&InstallController::installationErrorOccurred), this,
+ [this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected); },
+ static_cast(Qt::AutoConnection || Qt::SingleShotConnection));
+ m_installController->updateServiceFromApi(m_serversModel->getDefaultServerIndex(), "", "");
+ });
+
+ connect(m_connectionController.get(), &ConnectionController::updateApiConfigFromTelegram, this, [this]() {
+ m_reloadConfigErrorOccurredConnection = connect(
+ m_installController.get(), qOverload(&InstallController::installationErrorOccurred), this,
+ [this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected); },
+ static_cast(Qt::AutoConnection || Qt::SingleShotConnection));
+ m_serversModel->removeApiConfig(m_serversModel->getDefaultServerIndex());
+ m_installController->updateServiceFromTelegram(m_serversModel->getDefaultServerIndex());
+ });
+
+ connect(this, &AmneziaApplication::translationsUpdated, m_connectionController.get(), &ConnectionController::onTranslationsUpdated);
+
m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
diff --git a/client/amnezia_application.h b/client/amnezia_application.h
index b15d55d7..64566216 100644
--- a/client/amnezia_application.h
+++ b/client/amnezia_application.h
@@ -45,28 +45,22 @@
#include "ui/models/sites_model.h"
#include "ui/models/clientManagementModel.h"
#include "ui/models/appSplitTunnelingModel.h"
+#include "ui/models/apiServicesModel.h"
+#include "ui/models/apiCountryModel.h"
#define amnApp (static_cast(QCoreApplication::instance()))
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
#define AMNEZIA_BASE_CLASS QGuiApplication
#else
- #define AMNEZIA_BASE_CLASS SingleApplication
- #define QAPPLICATION_CLASS QApplication
- #include "singleapplication.h"
+ #define AMNEZIA_BASE_CLASS QApplication
#endif
class AmneziaApplication : public AMNEZIA_BASE_CLASS
{
Q_OBJECT
public:
-#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
AmneziaApplication(int &argc, char *argv[]);
-#else
- AmneziaApplication(int &argc, char *argv[], bool allowSecondary = false,
- SingleApplication::Options options = SingleApplication::User, int timeout = 1000,
- const QString &userData = {});
-#endif
virtual ~AmneziaApplication();
void init();
@@ -76,6 +70,10 @@ public:
void updateTranslator(const QLocale &locale);
bool parseCommands();
+#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
+ void startLocalServer();
+#endif
+
QQmlApplicationEngine *qmlEngine() const;
QNetworkAccessManager *manager() { return m_nam; }
@@ -103,6 +101,8 @@ private:
QSharedPointer m_sitesModel;
QSharedPointer m_appSplitTunnelingModel;
QSharedPointer m_clientManagementModel;
+ QSharedPointer m_apiServicesModel;
+ QSharedPointer m_apiCountryModel;
QScopedPointer m_openVpnConfigModel;
QScopedPointer m_shadowSocksConfigModel;
@@ -134,6 +134,8 @@ private:
QScopedPointer m_appSplitTunnelingController;
QNetworkAccessManager *m_nam;
+
+ QMetaObject::Connection m_reloadConfigErrorOccurredConnection;
};
#endif // AMNEZIA_APPLICATION_H
diff --git a/client/android/AndroidManifest.xml b/client/android/AndroidManifest.xml
index c1c40b52..179def86 100644
--- a/client/android/AndroidManifest.xml
+++ b/client/android/AndroidManifest.xml
@@ -3,7 +3,6 @@
@@ -46,7 +45,7 @@
android:configChanges="uiMode|screenSize|smallestScreenSize|screenLayout|orientation|density
|fontScale|layoutDirection|locale|keyboard|keyboardHidden|navigation|mcc|mnc"
android:launchMode="singleInstance"
- android:windowSoftInputMode="adjustResize"
+ android:windowSoftInputMode="stateUnchanged|adjustResize"
android:exported="true">
@@ -68,9 +67,6 @@
android:name="android.app.lib_name"
android:value="-- %%INSERT_APP_LIB_NAME%% --" />
-
+
+
Unit): AwgConfig = Builder().apply(block).build()
- }
-}
diff --git a/client/android/build.gradle b/client/android/build.gradle
index d768000e..5044727b 100644
--- a/client/android/build.gradle
+++ b/client/android/build.gradle
@@ -3,3 +3,6 @@
// android.bundle.enableUncompressedNativeLibs is deprecated
// disable adding gradle property android.bundle.enableUncompressedNativeLibs by androiddeployqt
useLegacyPackaging
+
+// package name for androiddeployqt
+namespace = "org.amnezia.vpn"
diff --git a/client/android/build.gradle.kts b/client/android/build.gradle.kts
index 7c4cec5a..3c742621 100644
--- a/client/android/build.gradle.kts
+++ b/client/android/build.gradle.kts
@@ -115,9 +115,11 @@ dependencies {
implementation(project(":xray"))
implementation(libs.androidx.core)
implementation(libs.androidx.activity)
+ implementation(libs.androidx.fragment)
implementation(libs.kotlinx.coroutines)
implementation(libs.kotlinx.serialization.protobuf)
implementation(libs.bundles.androidx.camera)
implementation(libs.google.mlkit)
implementation(libs.androidx.datastore)
+ implementation(libs.androidx.biometric)
}
diff --git a/client/android/cloak/src/main/kotlin/Cloak.kt b/client/android/cloak/src/main/kotlin/Cloak.kt
index 5a549130..d408fb19 100644
--- a/client/android/cloak/src/main/kotlin/Cloak.kt
+++ b/client/android/cloak/src/main/kotlin/Cloak.kt
@@ -3,40 +3,16 @@ package org.amnezia.vpn.protocol.cloak
import android.util.Base64
import net.openvpn.ovpn3.ClientAPI_Config
import org.amnezia.vpn.protocol.openvpn.OpenVpn
+import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
import org.json.JSONObject
-/**
- * Config Example:
- * {
- * "protocol": "cloak",
- * "description": "Server 1",
- * "dns1": "1.1.1.1",
- * "dns2": "1.0.0.1",
- * "hostName": "100.100.100.0",
- * "splitTunnelSites": [
- * ],
- * "splitTunnelType": 0,
- * "openvpn_config_data": {
- * "config": "openVpnConfig"
- * }
- * "cloak_config_data": {
- * "BrowserSig": "chrome",
- * "EncryptionMethod": "aes-gcm",
- * "NumConn": 1,
- * "ProxyMethod": "openvpn",
- * "PublicKey": "PublicKey=",
- * "RemoteHost": "100.100.100.0",
- * "RemotePort": "443",
- * "ServerName": "servername",
- * "StreamTimeout": 300,
- * "Transport": "direct",
- * "UID": "UID="
- * }
- * }
- */
-
class Cloak : OpenVpn() {
+ override fun internalInit() {
+ super.internalInit()
+ if (!isInitialized) loadSharedLibrary(context, "ck-ovpn-plugin")
+ }
+
override fun parseConfig(config: JSONObject): ClientAPI_Config {
val openVpnConfig = ClientAPI_Config()
diff --git a/client/android/gradle/libs.versions.toml b/client/android/gradle/libs.versions.toml
index a5466422..c6fa1907 100644
--- a/client/android/gradle/libs.versions.toml
+++ b/client/android/gradle/libs.versions.toml
@@ -1,24 +1,28 @@
[versions]
-agp = "8.2.0"
-kotlin = "1.9.20"
-androidx-core = "1.12.0"
-androidx-activity = "1.8.1"
-androidx-annotation = "1.7.0"
-androidx-camera = "1.3.0"
+agp = "8.5.2"
+kotlin = "1.9.24"
+androidx-core = "1.13.1"
+androidx-activity = "1.9.1"
+androidx-annotation = "1.8.2"
+androidx-biometric = "1.2.0-alpha05"
+androidx-camera = "1.3.4"
+androidx-fragment = "1.8.2"
androidx-security-crypto = "1.1.0-alpha06"
-androidx-datastore = "1.1.0-beta01"
-kotlinx-coroutines = "1.7.3"
+androidx-datastore = "1.1.1"
+kotlinx-coroutines = "1.8.1"
kotlinx-serialization = "1.6.3"
-google-mlkit = "17.2.0"
+google-mlkit = "17.3.0"
[libraries]
androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
androidx-activity = { module = "androidx.activity:activity-ktx", version.ref = "androidx-activity" }
androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidx-annotation" }
+androidx-biometric = { module = "androidx.biometric:biometric-ktx", version.ref = "androidx-biometric" }
androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "androidx-camera" }
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "androidx-camera" }
androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "androidx-camera" }
androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "androidx-camera" }
+androidx-fragment = { module = "androidx.fragment:fragment-ktx", version.ref = "androidx-fragment" }
androidx-security-crypto = { module = "androidx.security:security-crypto-ktx", version.ref = "androidx-security-crypto" }
androidx-datastore = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx-datastore" }
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }
diff --git a/client/android/gradle/wrapper/gradle-wrapper.jar b/client/android/gradle/wrapper/gradle-wrapper.jar
index d64cd491..a4b76b95 100644
Binary files a/client/android/gradle/wrapper/gradle-wrapper.jar and b/client/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/client/android/gradle/wrapper/gradle-wrapper.properties b/client/android/gradle/wrapper/gradle-wrapper.properties
index 1af9e093..e1adfb49 100644
--- a/client/android/gradle/wrapper/gradle-wrapper.properties
+++ b/client/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
-networkTimeout=10000
-validateDistributionUrl=true
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/client/android/gradlew b/client/android/gradlew
index 1aa94a42..f5feea6d 100755
--- a/client/android/gradlew
+++ b/client/android/gradlew
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
diff --git a/client/android/gradlew.bat b/client/android/gradlew.bat
index 93e3f59f..9d21a218 100644
--- a/client/android/gradlew.bat
+++ b/client/android/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
diff --git a/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt b/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt
index abe46245..22fe35cd 100644
--- a/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt
+++ b/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt
@@ -11,28 +11,12 @@ import org.amnezia.vpn.protocol.Protocol
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
import org.amnezia.vpn.protocol.Statistics
import org.amnezia.vpn.protocol.VpnStartException
+import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
import org.amnezia.vpn.util.net.InetNetwork
import org.amnezia.vpn.util.net.getLocalNetworks
import org.amnezia.vpn.util.net.parseInetAddress
import org.json.JSONObject
-/**
- * Config Example:
- * {
- * "protocol": "openvpn",
- * "description": "Server 1",
- * "dns1": "1.1.1.1",
- * "dns2": "1.0.0.1",
- * "hostName": "100.100.100.0",
- * "splitTunnelSites": [
- * ],
- * "splitTunnelType": 0,
- * "openvpn_config_data": {
- * "config": "openVpnConfig"
- * }
- * }
- */
-
open class OpenVpn : Protocol() {
private var openVpnClient: OpenVpnClient? = null
@@ -51,14 +35,17 @@ open class OpenVpn : Protocol() {
}
override fun internalInit() {
- if (!isInitialized) loadSharedLibrary(context, "ovpn3")
+ if (!isInitialized) {
+ loadSharedLibrary(context, "ovpn3")
+ loadSharedLibrary(context, "ovpnutil")
+ }
if (this::scope.isInitialized) {
scope.cancel()
}
scope = CoroutineScope(Dispatchers.IO)
}
- override fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
+ override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
val configBuilder = OpenVpnConfig.Builder()
openVpnClient = OpenVpnClient(
diff --git a/client/android/protocolApi/src/main/kotlin/Exceptions.kt b/client/android/protocolApi/src/main/kotlin/Exceptions.kt
index 739a327c..b80648b0 100644
--- a/client/android/protocolApi/src/main/kotlin/Exceptions.kt
+++ b/client/android/protocolApi/src/main/kotlin/Exceptions.kt
@@ -2,7 +2,6 @@ package org.amnezia.vpn.protocol
sealed class ProtocolException(message: String? = null, cause: Throwable? = null) : Exception(message, cause)
-class LoadLibraryException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
class BadConfigException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
class VpnStartException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
diff --git a/client/android/protocolApi/src/main/kotlin/Protocol.kt b/client/android/protocolApi/src/main/kotlin/Protocol.kt
index a475a2fc..b5c382be 100644
--- a/client/android/protocolApi/src/main/kotlin/Protocol.kt
+++ b/client/android/protocolApi/src/main/kotlin/Protocol.kt
@@ -42,7 +42,7 @@ abstract class Protocol {
protected abstract fun internalInit()
- abstract fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean)
+ abstract suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean)
abstract fun stopVpn()
@@ -158,60 +158,6 @@ abstract class Protocol {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
vpnBuilder.setMetered(false)
}
-
- companion object {
- private fun extractLibrary(context: Context, libraryName: String, destination: File): Boolean {
- Log.d(TAG, "Extracting library: $libraryName")
- val apks = hashSetOf()
- context.applicationInfo.run {
- sourceDir?.let { apks += it }
- splitSourceDirs?.let { apks += it }
- }
- for (abi in Build.SUPPORTED_ABIS) {
- for (apk in apks) {
- ZipFile(File(apk), ZipFile.OPEN_READ).use { zipFile ->
- val mappedName = System.mapLibraryName(libraryName)
- val libraryZipPath = listOf("lib", abi, mappedName).joinToString(File.separator)
- val zipEntry = zipFile.getEntry(libraryZipPath)
- zipEntry?.let {
- Log.d(TAG, "Extracting apk:/$libraryZipPath to ${destination.absolutePath}")
- FileOutputStream(destination).use { outStream ->
- zipFile.getInputStream(zipEntry).use { inStream ->
- inStream.copyTo(outStream, 32 * 1024)
- outStream.fd.sync()
- }
- }
- }
- return true
- }
- }
- }
- return false
- }
-
- @SuppressLint("UnsafeDynamicallyLoadedCode")
- fun loadSharedLibrary(context: Context, libraryName: String) {
- Log.d(TAG, "Loading library: $libraryName")
- try {
- System.loadLibrary(libraryName)
- return
- } catch (_: UnsatisfiedLinkError) {
- Log.d(TAG, "Failed to load library, try to extract it from apk")
- }
- var tempFile: File? = null
- try {
- tempFile = File.createTempFile("lib", ".so", context.codeCacheDir)
- if (extractLibrary(context, libraryName, tempFile)) {
- System.load(tempFile.absolutePath)
- return
- }
- } catch (e: Exception) {
- throw LoadLibraryException("Failed to load library apk: $libraryName", e)
- } finally {
- tempFile?.delete()
- }
- }
- }
}
private fun VpnService.Builder.addAddress(addr: InetNetwork) = addAddress(addr.address, addr.mask)
diff --git a/client/android/qt/build.gradle.kts b/client/android/qt/build.gradle.kts
index 139adf4f..6b1d3fd1 100644
--- a/client/android/qt/build.gradle.kts
+++ b/client/android/qt/build.gradle.kts
@@ -21,5 +21,5 @@ android {
}
dependencies {
- implementation(fileTree(mapOf("dir" to "../libs", "include" to listOf("*.jar"))))
+ api(fileTree(mapOf("dir" to "../libs", "include" to listOf("*.jar"))))
}
diff --git a/client/android/res/values/libs.xml b/client/android/res/values/libs.xml
index fe63866f..3ccf1d80 100644
--- a/client/android/res/values/libs.xml
+++ b/client/android/res/values/libs.xml
@@ -3,7 +3,6 @@
-
diff --git a/client/android/res/values/styles.xml b/client/android/res/values/styles.xml
index 9f4201f8..bc67beb9 100644
--- a/client/android/res/values/styles.xml
+++ b/client/android/res/values/styles.xml
@@ -1,6 +1,9 @@
+ #FF0E0E11
diff --git a/client/android/settings.gradle.kts b/client/android/settings.gradle.kts
index 5cfc8314..68426ec8 100644
--- a/client/android/settings.gradle.kts
+++ b/client/android/settings.gradle.kts
@@ -22,7 +22,7 @@ dependencyResolutionManagement {
includeBuild("./gradle/plugins")
plugins {
- id("com.android.settings") version "8.2.0"
+ id("com.android.settings") version "8.5.2"
id("settings-property-delegate")
}
diff --git a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
index 8a78750b..d5026425 100644
--- a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
+++ b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
@@ -43,6 +43,7 @@ import kotlinx.coroutines.withContext
import org.amnezia.vpn.protocol.getStatistics
import org.amnezia.vpn.protocol.getStatus
import org.amnezia.vpn.qt.QtAndroidController
+import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
import org.amnezia.vpn.util.Log
import org.amnezia.vpn.util.Prefs
import org.json.JSONException
@@ -158,6 +159,11 @@ class AmneziaActivity : QtActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "Create Amnezia activity: $intent")
+ loadLibs()
+ window.apply {
+ addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
+ statusBarColor = getColor(R.color.black)
+ }
mainScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
val proto = mainScope.async(Dispatchers.IO) {
VpnStateStore.getVpnState().vpnProto
@@ -175,6 +181,17 @@ class AmneziaActivity : QtActivity() {
runBlocking { vpnProto = proto.await() }
}
+ private fun loadLibs() {
+ listOf(
+ "rsapss",
+ "crypto_3",
+ "ssl_3",
+ "ssh"
+ ).forEach {
+ loadSharedLibrary(this.applicationContext, it)
+ }
+ }
+
private fun registerBroadcastReceivers() {
notificationStateReceiver = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
registerBroadcastReceiver(
@@ -610,6 +627,14 @@ class AmneziaActivity : QtActivity() {
}
}
+ @Suppress("unused")
+ fun setNavigationBarColor(color: Int) {
+ Log.v(TAG, "Change navigation bar color: ${"#%08X".format(color)}")
+ mainScope.launch {
+ window.navigationBarColor = color
+ }
+ }
+
@Suppress("unused")
fun minimizeApp() {
Log.v(TAG, "Minimize application")
@@ -684,6 +709,17 @@ class AmneziaActivity : QtActivity() {
.show()
}
+ @Suppress("unused")
+ fun requestAuthentication() {
+ Log.v(TAG, "Request authentication")
+ mainScope.launch {
+ qtInitialized.await()
+ Intent(this@AmneziaActivity, AuthActivity::class.java).also {
+ startActivity(it)
+ }
+ }
+ }
+
/**
* Utils methods
*/
diff --git a/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt b/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt
index b30f1503..937127ee 100644
--- a/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt
+++ b/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt
@@ -22,6 +22,7 @@ import androidx.annotation.MainThread
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
+import java.net.UnknownHostException
import java.util.concurrent.ConcurrentHashMap
import kotlin.LazyThreadSafetyMode.NONE
import kotlinx.coroutines.CoroutineExceptionHandler
@@ -31,6 +32,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.cancel
+import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.drop
@@ -39,7 +41,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
import org.amnezia.vpn.protocol.BadConfigException
-import org.amnezia.vpn.protocol.LoadLibraryException
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
import org.amnezia.vpn.protocol.ProtocolState.CONNECTING
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
@@ -49,6 +50,7 @@ import org.amnezia.vpn.protocol.ProtocolState.UNKNOWN
import org.amnezia.vpn.protocol.VpnException
import org.amnezia.vpn.protocol.VpnStartException
import org.amnezia.vpn.protocol.putStatus
+import org.amnezia.vpn.util.LoadLibraryException
import org.amnezia.vpn.util.Log
import org.amnezia.vpn.util.Prefs
import org.amnezia.vpn.util.net.NetworkState
@@ -111,6 +113,10 @@ open class AmneziaVpnService : VpnService() {
get() = clientMessengers.any { it.value.name == ACTIVITY_MESSENGER_NAME }
private val connectionExceptionHandler = CoroutineExceptionHandler { _, e ->
+ connectionJob?.cancel()
+ connectionJob = null
+ disconnectionJob?.cancel()
+ disconnectionJob = null
protocolState.value = DISCONNECTED
when (e) {
is IllegalArgumentException,
@@ -122,6 +128,8 @@ open class AmneziaVpnService : VpnService() {
is LoadLibraryException -> onError("${e.message}. Caused: ${e.cause?.message}")
+ is UnknownHostException -> onError("Unknown host")
+
else -> throw e
}
}
@@ -531,7 +539,7 @@ open class AmneziaVpnService : VpnService() {
protocolState.value = DISCONNECTING
disconnectionJob = connectionScope.launch {
- connectionJob?.join()
+ connectionJob?.cancelAndJoin()
connectionJob = null
vpnProto?.protocol?.stopVpn()
diff --git a/client/android/src/org/amnezia/vpn/AuthActivity.kt b/client/android/src/org/amnezia/vpn/AuthActivity.kt
new file mode 100644
index 00000000..2593315c
--- /dev/null
+++ b/client/android/src/org/amnezia/vpn/AuthActivity.kt
@@ -0,0 +1,97 @@
+package org.amnezia.vpn
+
+import android.os.Build
+import android.os.Bundle
+import androidx.biometric.BiometricManager
+import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
+import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
+import androidx.biometric.BiometricPrompt
+import androidx.biometric.BiometricPrompt.AuthenticationResult
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.FragmentActivity
+import org.amnezia.vpn.qt.QtAndroidController
+import org.amnezia.vpn.util.Log
+
+private const val TAG = "AuthActivity"
+
+private const val AUTHENTICATORS = BIOMETRIC_STRONG or DEVICE_CREDENTIAL
+
+class AuthActivity : FragmentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val biometricManager = BiometricManager.from(applicationContext)
+ when (biometricManager.canAuthenticate(AUTHENTICATORS)) {
+ BiometricManager.BIOMETRIC_SUCCESS -> {
+ showBiometricPrompt(biometricManager)
+ return
+ }
+
+ BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> {
+ Log.w(TAG, "Unknown biometric status")
+ showBiometricPrompt(biometricManager)
+ return
+ }
+
+ BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> {
+ Log.e(TAG, "The specified options are incompatible with the current Android " +
+ "version ${Build.VERSION.SDK_INT}")
+ }
+
+ BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> {
+ Log.w(TAG, "The hardware is unavailable")
+ }
+
+ BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
+ Log.w(TAG, "No biometric or device credential is enrolled")
+ }
+
+ BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> {
+ Log.w(TAG, "There is no suitable hardware")
+ }
+
+ BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> {
+ Log.w(TAG, "A security vulnerability has been discovered with one or " +
+ "more hardware sensors")
+ }
+ }
+ QtAndroidController.onAuthResult(true)
+ finish()
+ }
+
+ private fun showBiometricPrompt(biometricManager: BiometricManager) {
+ val executor = ContextCompat.getMainExecutor(applicationContext)
+ val biometricPrompt = BiometricPrompt(this, executor,
+ object : BiometricPrompt.AuthenticationCallback() {
+ override fun onAuthenticationSucceeded(result: AuthenticationResult) {
+ super.onAuthenticationSucceeded(result)
+ Log.d(TAG, "Authentication succeeded")
+ QtAndroidController.onAuthResult(true)
+ finish()
+ }
+
+ override fun onAuthenticationFailed() {
+ super.onAuthenticationFailed()
+ Log.w(TAG, "Authentication failed")
+ }
+
+ override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
+ super.onAuthenticationError(errorCode, errString)
+ Log.e(TAG, "Authentication error $errorCode: $errString")
+ QtAndroidController.onAuthResult(false)
+ finish()
+ }
+ })
+
+
+
+ val promptInfo = BiometricPrompt.PromptInfo.Builder()
+ .setAllowedAuthenticators(AUTHENTICATORS)
+ .setTitle("AmneziaVPN")
+ .setSubtitle(biometricManager.getStrings(AUTHENTICATORS)?.promptMessage)
+ .build()
+
+ biometricPrompt.authenticate(promptInfo)
+ }
+}
diff --git a/client/android/src/org/amnezia/vpn/AuthHelper.java b/client/android/src/org/amnezia/vpn/AuthHelper.java
deleted file mode 100644
index 940d03c2..00000000
--- a/client/android/src/org/amnezia/vpn/AuthHelper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.amnezia.vpn;
-
-import android.content.Context;
-import android.app.KeyguardManager;
-import android.content.Intent;
-import org.qtproject.qt.android.bindings.QtActivity;
-
-
-import static android.content.Context.KEYGUARD_SERVICE;
-
-public class AuthHelper extends QtActivity {
-
- static final String TAG = "AuthHelper";
-
- public static Intent getAuthIntent(Context context) {
- KeyguardManager mKeyguardManager = (KeyguardManager)context.getSystemService(KEYGUARD_SERVICE);
- if (mKeyguardManager.isDeviceSecure()) {
- return mKeyguardManager.createConfirmDeviceCredentialIntent(null, null);
- } else {
- return null;
- }
- }
-
-}
diff --git a/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt b/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt
index cae7ab75..9faa30d0 100644
--- a/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt
+++ b/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt
@@ -33,10 +33,10 @@ class ImportConfigActivity : ComponentActivity() {
intent?.let(::readConfig)
}
- override fun onNewIntent(intent: Intent?) {
+ override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
Log.d(TAG, "onNewIntent: $intent")
- intent?.let(::readConfig)
+ intent.let(::readConfig)
}
private fun readConfig(intent: Intent) {
diff --git a/client/android/src/org/amnezia/vpn/qt/QtAndroidController.kt b/client/android/src/org/amnezia/vpn/qt/QtAndroidController.kt
index e382b080..4af138a2 100644
--- a/client/android/src/org/amnezia/vpn/qt/QtAndroidController.kt
+++ b/client/android/src/org/amnezia/vpn/qt/QtAndroidController.kt
@@ -25,5 +25,7 @@ object QtAndroidController {
external fun onConfigImported(data: String)
+ external fun onAuthResult(result: Boolean)
+
external fun decodeQrCode(data: String): Boolean
}
\ No newline at end of file
diff --git a/client/android/utils/src/main/kotlin/JsonExt.kt b/client/android/utils/src/main/kotlin/JsonExt.kt
new file mode 100644
index 00000000..45c5bacd
--- /dev/null
+++ b/client/android/utils/src/main/kotlin/JsonExt.kt
@@ -0,0 +1,9 @@
+package org.amnezia.vpn.util
+
+import org.json.JSONArray
+import org.json.JSONObject
+
+inline fun JSONArray.asSequence(): Sequence =
+ (0..()
+ context.applicationInfo.run {
+ sourceDir?.let { apks += it }
+ splitSourceDirs?.let { apks += it }
+ }
+ for (abi in Build.SUPPORTED_ABIS) {
+ for (apk in apks) {
+ ZipFile(File(apk), ZipFile.OPEN_READ).use { zipFile ->
+ val mappedName = System.mapLibraryName(libraryName)
+ val libraryZipPath = listOf("lib", abi, mappedName).joinToString(File.separator)
+ val zipEntry = zipFile.getEntry(libraryZipPath)
+ zipEntry?.let {
+ Log.d(TAG, "Extracting apk:/$libraryZipPath to ${destination.absolutePath}")
+ FileOutputStream(destination).use { outStream ->
+ zipFile.getInputStream(zipEntry).use { inStream ->
+ inStream.copyTo(outStream, 32 * 1024)
+ outStream.fd.sync()
+ }
+ }
+ }
+ return true
+ }
+ }
+ }
+ return false
+ }
+
+ @SuppressLint("UnsafeDynamicallyLoadedCode")
+ fun loadSharedLibrary(context: Context, libraryName: String) {
+ Log.d(TAG, "Loading library: $libraryName")
+ try {
+ System.loadLibrary(libraryName)
+ return
+ } catch (_: UnsatisfiedLinkError) {
+ Log.d(TAG, "Failed to load library, try to extract it from apk")
+ }
+ var tempFile: File? = null
+ try {
+ tempFile = File.createTempFile("lib", ".so", context.codeCacheDir)
+ if (extractLibrary(context, libraryName, tempFile)) {
+ System.load(tempFile.absolutePath)
+ return
+ }
+ } catch (e: Exception) {
+ throw LoadLibraryException("Failed to load library apk: $libraryName", e)
+ } finally {
+ tempFile?.delete()
+ }
+ }
+}
+
+class LoadLibraryException(message: String? = null, cause: Throwable? = null) : Exception(message, cause)
diff --git a/client/android/utils/src/main/kotlin/net/NetworkState.kt b/client/android/utils/src/main/kotlin/net/NetworkState.kt
index 26d23215..b71bf393 100644
--- a/client/android/utils/src/main/kotlin/net/NetworkState.kt
+++ b/client/android/utils/src/main/kotlin/net/NetworkState.kt
@@ -88,7 +88,7 @@ class NetworkState(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
connectivityManager.registerBestMatchingNetworkCallback(networkRequest, networkCallback, handler)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val numberAttempts = 3
+ val numberAttempts = 300
var attemptCount = 0
while(true) {
try {
diff --git a/client/android/utils/src/main/kotlin/net/NetworkUtils.kt b/client/android/utils/src/main/kotlin/net/NetworkUtils.kt
index b75748be..784aa352 100644
--- a/client/android/utils/src/main/kotlin/net/NetworkUtils.kt
+++ b/client/android/utils/src/main/kotlin/net/NetworkUtils.kt
@@ -35,7 +35,7 @@ fun getLocalNetworks(context: Context, ipv6: Boolean): List {
return emptyList()
}
-fun parseInetAddress(address: String): InetAddress = parseNumericAddressCompat(address)
+fun parseInetAddress(address: String): InetAddress = InetAddress.getByName(address)
private val parseNumericAddressCompat: (String) -> InetAddress =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
@@ -60,7 +60,7 @@ private val parseNumericAddressCompat: (String) -> InetAddress =
internal fun convertIpv6ToCanonicalForm(ipv6: String): String = ipv6
.replace("((?:(?:^|:)0+\\b){2,}):?(?!\\S*\\b\\1:0+\\b)(\\S*)".toRegex(), "::$2")
-internal val InetAddress.ip: String
+val InetAddress.ip: String
get() = if (this is Inet4Address) {
hostAddress!!
} else {
diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
index 690510eb..ac11374b 100644
--- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
+++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
@@ -1,54 +1,26 @@
package org.amnezia.vpn.protocol.wireguard
import android.net.VpnService.Builder
-import java.util.TreeMap
+import java.io.IOException
+import java.util.Locale
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.withContext
import org.amnezia.awg.GoBackend
import org.amnezia.vpn.protocol.Protocol
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
import org.amnezia.vpn.protocol.Statistics
import org.amnezia.vpn.protocol.VpnStartException
+import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
import org.amnezia.vpn.util.Log
+import org.amnezia.vpn.util.asSequence
import org.amnezia.vpn.util.net.InetEndpoint
import org.amnezia.vpn.util.net.InetNetwork
import org.amnezia.vpn.util.net.parseInetAddress
+import org.amnezia.vpn.util.optStringOrNull
import org.json.JSONObject
-/**
- * Config example:
- * {
- * "protocol": "wireguard",
- * "description": "Server 1",
- * "dns1": "1.1.1.1",
- * "dns2": "1.0.0.1",
- * "hostName": "100.100.100.0",
- * "splitTunnelSites": [
- * ],
- * "splitTunnelType": 0,
- * "wireguard_config_data": {
- * "client_ip": "10.8.1.1",
- * "hostName": "100.100.100.0",
- * "port": 12345,
- * "client_pub_key": "clientPublicKeyBase64",
- * "client_priv_key": "privateKeyBase64",
- * "psk_key": "presharedKeyBase64",
- * "server_pub_key": "publicKeyBase64",
- * "config": "[Interface]
- * Address = 10.8.1.1/32
- * DNS = 1.1.1.1, 1.0.0.1
- * PrivateKey = privateKeyBase64
- *
- * [Peer]
- * PublicKey = publicKeyBase64
- * PresharedKey = presharedKeyBase64
- * AllowedIPs = 0.0.0.0/0, ::/0
- * Endpoint = 100.100.100.0:12345
- * PersistentKeepalive = 25
- * "
- * }
- * }
- */
-
private const val TAG = "Wireguard"
open class Wireguard : Protocol() {
@@ -79,67 +51,105 @@ open class Wireguard : Protocol() {
if (!isInitialized) loadSharedLibrary(context, "wg-go")
}
- override fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
+ override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
val wireguardConfig = parseConfig(config)
+ val startTime = System.currentTimeMillis()
start(wireguardConfig, vpnBuilder, protect)
+ waitForConnection(startTime)
state.value = CONNECTED
}
+ private suspend fun waitForConnection(startTime: Long) {
+ Log.d(TAG, "Waiting for connection")
+ withContext(Dispatchers.IO) {
+ val time = String.format(Locale.ROOT,"%.3f", startTime / 1000.0)
+ try {
+ delay(1000)
+ var log = getLogcat(time)
+ Log.d(TAG, "First waiting log: $log")
+ // check that there is a connection log,
+ // to avoid infinite connection
+ if (!log.contains("Attaching to interface")) {
+ Log.w(TAG, "Logs do not contain a connection log")
+ return@withContext
+ }
+ while (!log.contains("Received handshake response")) {
+ delay(1000)
+ log = getLogcat(time)
+ }
+ } catch (e: IOException) {
+ Log.e(TAG, "Failed to get logcat: $e")
+ }
+ }
+ }
+
+ private fun getLogcat(time: String): String =
+ ProcessBuilder("logcat", "--buffer=main", "--format=raw", "*:S AmneziaWG/awg0", "-t", time)
+ .redirectErrorStream(true)
+ .start()
+ .inputStream.reader().readText()
+
protected open fun parseConfig(config: JSONObject): WireguardConfig {
- val configDataJson = config.getJSONObject("wireguard_config_data")
- val configData = parseConfigData(configDataJson.getString("config"))
+ val configData = config.getJSONObject("wireguard_config_data")
return WireguardConfig.build {
- configWireguard(configData, configDataJson)
+ configWireguard(config, configData)
configSplitTunneling(config)
configAppSplitTunneling(config)
}
}
- protected fun WireguardConfig.Builder.configWireguard(configData: Map, configDataJson: JSONObject) {
- configData["Address"]?.split(",")?.map { address ->
+ protected fun WireguardConfig.Builder.configWireguard(config: JSONObject, configData: JSONObject) {
+ configData.getString("client_ip").split(",").map { address ->
InetNetwork.parse(address.trim())
- }?.forEach(::addAddress)
+ }.forEach(::addAddress)
- configData["DNS"]?.split(",")?.map { dns ->
- parseInetAddress(dns.trim())
- }?.forEach(::addDnsServer)
+ config.optStringOrNull("dns1")?.let { dns ->
+ addDnsServer(parseInetAddress(dns.trim()))
+ }
+
+ config.optStringOrNull("dns2")?.let { dns ->
+ addDnsServer(parseInetAddress(dns.trim()))
+ }
val defRoutes = hashSetOf(
InetNetwork("0.0.0.0", 0),
InetNetwork("::", 0)
)
val routes = hashSetOf()
- configData["AllowedIPs"]?.split(",")?.map { route ->
+ configData.getJSONArray("allowed_ips").asSequence().map { route ->
InetNetwork.parse(route.trim())
- }?.forEach(routes::add)
+ }.forEach(routes::add)
// if the allowed IPs list contains at least one non-default route, disable global split tunneling
if (routes.any { it !in defRoutes }) disableSplitTunneling()
addRoutes(routes)
- configDataJson.optString("mtu").let { mtu ->
- if (mtu.isNotEmpty()) {
- setMtu(mtu.toInt())
- } else {
- configData["MTU"]?.let { setMtu(it.toInt()) }
- }
+ configData.optStringOrNull("mtu")?.let { setMtu(it.toInt()) }
+
+ val host = configData.getString("hostName").let { parseInetAddress(it.trim()) }
+ val port = configData.getInt("port")
+ setEndpoint(InetEndpoint(host, port))
+
+ if (configData.optBoolean("isObfuscationEnabled")) {
+ setUseProtocolExtension(true)
+ configExtensionParameters(configData)
}
- configData["Endpoint"]?.let { setEndpoint(InetEndpoint.parse(it)) }
- configData["PersistentKeepalive"]?.let { setPersistentKeepalive(it.toInt()) }
- configData["PrivateKey"]?.let { setPrivateKeyHex(it.base64ToHex()) }
- configData["PublicKey"]?.let { setPublicKeyHex(it.base64ToHex()) }
- configData["PresharedKey"]?.let { setPreSharedKeyHex(it.base64ToHex()) }
+ configData.optStringOrNull("persistent_keep_alive")?.let { setPersistentKeepalive(it.toInt()) }
+ configData.getString("client_priv_key").let { setPrivateKeyHex(it.base64ToHex()) }
+ configData.getString("server_pub_key").let { setPublicKeyHex(it.base64ToHex()) }
+ configData.optStringOrNull("psk_key")?.let { setPreSharedKeyHex(it.base64ToHex()) }
}
- protected fun parseConfigData(data: String): Map {
- val parsedData = TreeMap(String.CASE_INSENSITIVE_ORDER)
- data.lineSequence()
- .filter { it.isNotEmpty() && !it.startsWith('[') }
- .forEach { line ->
- val attr = line.split("=", limit = 2)
- parsedData[attr.first().trim()] = attr.last().trim()
- }
- return parsedData
+ protected fun WireguardConfig.Builder.configExtensionParameters(configData: JSONObject) {
+ configData.optStringOrNull("Jc")?.let { setJc(it.toInt()) }
+ configData.optStringOrNull("Jmin")?.let { setJmin(it.toInt()) }
+ configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) }
+ configData.optStringOrNull("S1")?.let { setS1(it.toInt()) }
+ configData.optStringOrNull("S2")?.let { setS2(it.toInt()) }
+ configData.optStringOrNull("H1")?.let { setH1(it.toLong()) }
+ configData.optStringOrNull("H2")?.let { setH2(it.toLong()) }
+ configData.optStringOrNull("H3")?.let { setH3(it.toLong()) }
+ configData.optStringOrNull("H4")?.let { setH4(it.toLong()) }
}
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {
diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt
index 09269f54..7ae3d43b 100644
--- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt
+++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt
@@ -1,6 +1,7 @@
package org.amnezia.vpn.protocol.wireguard
import android.util.Base64
+import org.amnezia.vpn.protocol.BadConfigException
import org.amnezia.vpn.protocol.ProtocolConfig
import org.amnezia.vpn.util.net.InetEndpoint
@@ -12,7 +13,17 @@ open class WireguardConfig protected constructor(
val persistentKeepalive: Int,
val publicKeyHex: String,
val preSharedKeyHex: String?,
- val privateKeyHex: String
+ val privateKeyHex: String,
+ val useProtocolExtension: Boolean,
+ val jc: Int?,
+ val jmin: Int?,
+ val jmax: Int?,
+ val s1: Int?,
+ val s2: Int?,
+ val h1: Long?,
+ val h2: Long?,
+ val h3: Long?,
+ val h4: Long?
) : ProtocolConfig(protocolConfigBuilder) {
protected constructor(builder: Builder) : this(
@@ -21,7 +32,17 @@ open class WireguardConfig protected constructor(
builder.persistentKeepalive,
builder.publicKeyHex,
builder.preSharedKeyHex,
- builder.privateKeyHex
+ builder.privateKeyHex,
+ builder.useProtocolExtension,
+ builder.jc,
+ builder.jmin,
+ builder.jmax,
+ builder.s1,
+ builder.s2,
+ builder.h1,
+ builder.h2,
+ builder.h3,
+ builder.h4
)
fun toWgUserspaceString(): String = with(StringBuilder()) {
@@ -33,6 +54,30 @@ open class WireguardConfig protected constructor(
open fun appendDeviceLine(sb: StringBuilder) = with(sb) {
appendLine("private_key=$privateKeyHex")
+ if (useProtocolExtension) {
+ validateProtocolExtensionParameters()
+ appendLine("jc=$jc")
+ appendLine("jmin=$jmin")
+ appendLine("jmax=$jmax")
+ appendLine("s1=$s1")
+ appendLine("s2=$s2")
+ appendLine("h1=$h1")
+ appendLine("h2=$h2")
+ appendLine("h3=$h3")
+ appendLine("h4=$h4")
+ }
+ }
+
+ private fun validateProtocolExtensionParameters() {
+ if (jc == null) throw BadConfigException("Parameter jc is undefined")
+ if (jmin == null) throw BadConfigException("Parameter jmin is undefined")
+ if (jmax == null) throw BadConfigException("Parameter jmax is undefined")
+ if (s1 == null) throw BadConfigException("Parameter s1 is undefined")
+ if (s2 == null) throw BadConfigException("Parameter s2 is undefined")
+ if (h1 == null) throw BadConfigException("Parameter h1 is undefined")
+ if (h2 == null) throw BadConfigException("Parameter h2 is undefined")
+ if (h3 == null) throw BadConfigException("Parameter h3 is undefined")
+ if (h4 == null) throw BadConfigException("Parameter h4 is undefined")
}
open fun appendPeerLine(sb: StringBuilder) = with(sb) {
@@ -65,6 +110,18 @@ open class WireguardConfig protected constructor(
override var mtu: Int = WIREGUARD_DEFAULT_MTU
+ internal var useProtocolExtension: Boolean = false
+
+ internal var jc: Int? = null
+ internal var jmin: Int? = null
+ internal var jmax: Int? = null
+ internal var s1: Int? = null
+ internal var s2: Int? = null
+ internal var h1: Long? = null
+ internal var h2: Long? = null
+ internal var h3: Long? = null
+ internal var h4: Long? = null
+
fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint }
fun setPersistentKeepalive(persistentKeepalive: Int) = apply { this.persistentKeepalive = persistentKeepalive }
@@ -75,6 +132,18 @@ open class WireguardConfig protected constructor(
fun setPrivateKeyHex(privateKeyHex: String) = apply { this.privateKeyHex = privateKeyHex }
+ fun setUseProtocolExtension(useProtocolExtension: Boolean) = apply { this.useProtocolExtension = useProtocolExtension }
+
+ fun setJc(jc: Int) = apply { this.jc = jc }
+ fun setJmin(jmin: Int) = apply { this.jmin = jmin }
+ fun setJmax(jmax: Int) = apply { this.jmax = jmax }
+ fun setS1(s1: Int) = apply { this.s1 = s1 }
+ fun setS2(s2: Int) = apply { this.s2 = s2 }
+ fun setH1(h1: Long) = apply { this.h1 = h1 }
+ fun setH2(h2: Long) = apply { this.h2 = h2 }
+ fun setH3(h3: Long) = apply { this.h3 = h3 }
+ fun setH4(h4: Long) = apply { this.h4 = h4 }
+
override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) }
}
diff --git a/client/android/xray/src/main/kotlin/Xray.kt b/client/android/xray/src/main/kotlin/Xray.kt
index 3e5f9f7c..6e37c9c2 100644
--- a/client/android/xray/src/main/kotlin/Xray.kt
+++ b/client/android/xray/src/main/kotlin/Xray.kt
@@ -17,72 +17,10 @@ import org.amnezia.vpn.protocol.xray.libXray.Logger
import org.amnezia.vpn.protocol.xray.libXray.Tun2SocksConfig
import org.amnezia.vpn.util.Log
import org.amnezia.vpn.util.net.InetNetwork
+import org.amnezia.vpn.util.net.ip
import org.amnezia.vpn.util.net.parseInetAddress
import org.json.JSONObject
-/**
- * Config example:
- * {
- * "appSplitTunnelType": 0,
- * "config_version": 0,
- * "description": "Server 1",
- * "dns1": "1.1.1.1",
- * "dns2": "1.0.0.1",
- * "hostName": "100.100.100.0",
- * "protocol": "xray",
- * "splitTunnelApps": [],
- * "splitTunnelSites": [],
- * "splitTunnelType": 0,
- * "xray_config_data": {
- * "inbounds": [
- * {
- * "listen": "127.0.0.1",
- * "port": 8080,
- * "protocol": "socks",
- * "settings": {
- * "udp": true
- * }
- * }
- * ],
- * "log": {
- * "loglevel": "error"
- * },
- * "outbounds": [
- * {
- * "protocol": "vless",
- * "settings": {
- * "vnext": [
- * {
- * "address": "100.100.100.0",
- * "port": 443,
- * "users": [
- * {
- * "encryption": "none",
- * "flow": "xtls-rprx-vision",
- * "id": "id"
- * }
- * ]
- * }
- * ]
- * },
- * "streamSettings": {
- * "network": "tcp",
- * "realitySettings": {
- * "fingerprint": "chrome",
- * "publicKey": "publicKey",
- * "serverName": "google.com",
- * "shortId": "id",
- * "spiderX": ""
- * },
- * "security": "reality"
- * }
- * }
- * ]
- * }
- * }
- *
- */
-
private const val TAG = "Xray"
private const val LIBXRAY_TAG = "libXray"
@@ -109,7 +47,7 @@ class Xray : Protocol() {
}
}
- override fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
+ override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
if (isRunning) {
Log.w(TAG, "XRay already running")
return
@@ -124,7 +62,15 @@ class Xray : Protocol() {
.put("loglevel", "warning")
.put("access", "none") // disable access log
- start(xrayConfig, xrayJsonConfig.toString(), vpnBuilder, protect)
+ var xrayJsonConfigString = xrayJsonConfig.toString()
+ config.getString("hostName").let { hostName ->
+ val ipAddress = parseInetAddress(hostName).ip
+ if (hostName != ipAddress) {
+ xrayJsonConfigString = xrayJsonConfigString.replace(hostName, ipAddress)
+ }
+ }
+
+ start(xrayConfig, xrayJsonConfigString, vpnBuilder, protect)
state.value = CONNECTED
isRunning = true
}
diff --git a/client/cmake/3rdparty.cmake b/client/cmake/3rdparty.cmake
index ec544764..2b5036c5 100644
--- a/client/cmake/3rdparty.cmake
+++ b/client/cmake/3rdparty.cmake
@@ -2,15 +2,11 @@ set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/Modules;${CMAKE_MODULE_PATH}")
-if(NOT IOS AND NOT ANDROID)
- include(${CLIENT_ROOT_DIR}/3rd/SingleApplication/singleapplication.cmake)
-endif()
-
add_subdirectory(${CLIENT_ROOT_DIR}/3rd/SortFilterProxyModel)
set(LIBS ${LIBS} SortFilterProxyModel)
+include(${CLIENT_ROOT_DIR}/cmake/QSimpleCrypto.cmake)
include(${CLIENT_ROOT_DIR}/3rd/qrcodegen/qrcodegen.cmake)
-include(${CLIENT_ROOT_DIR}/3rd/QSimpleCrypto/QSimpleCrypto.cmake)
set(LIBSSH_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/libssh/")
set(OPENSSL_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/openssl/")
@@ -83,13 +79,12 @@ set(BUILD_WITH_QT6 ON)
add_subdirectory(${CLIENT_ROOT_DIR}/3rd/qtkeychain)
set(LIBS ${LIBS} qt6keychain)
-
include_directories(
${OPENSSL_INCLUDE_DIR}
${LIBSSH_INCLUDE_DIR}/include
${LIBSSH_ROOT_DIR}/include
${CLIENT_ROOT_DIR}/3rd/libssh/include
- ${CLIENT_ROOT_DIR}/3rd/QSimpleCrypto/include
+ ${CLIENT_ROOT_DIR}/3rd/QSimpleCrypto/src/include
${CLIENT_ROOT_DIR}/3rd/qtkeychain/qtkeychain
${CMAKE_CURRENT_BINARY_DIR}/3rd/qtkeychain
${CMAKE_CURRENT_BINARY_DIR}/3rd/libssh/include
diff --git a/client/cmake/QSimpleCrypto.cmake b/client/cmake/QSimpleCrypto.cmake
new file mode 100644
index 00000000..ec43cb83
--- /dev/null
+++ b/client/cmake/QSimpleCrypto.cmake
@@ -0,0 +1,21 @@
+set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
+set(QSIMPLECRYPTO_DIR ${CLIENT_ROOT_DIR}/3rd/QSimpleCrypto/src)
+
+include_directories(${QSIMPLECRYPTO_DIR})
+
+set(HEADERS ${HEADERS}
+ ${QSIMPLECRYPTO_DIR}/include/QAead.h
+ ${QSIMPLECRYPTO_DIR}/include/QBlockCipher.h
+ ${QSIMPLECRYPTO_DIR}/include/QRsa.h
+ ${QSIMPLECRYPTO_DIR}/include/QSimpleCrypto_global.h
+ ${QSIMPLECRYPTO_DIR}/include/QX509.h
+ ${QSIMPLECRYPTO_DIR}/include/QX509Store.h
+)
+
+set(SOURCES ${SOURCES}
+ ${QSIMPLECRYPTO_DIR}/sources/QAead.cpp
+ ${QSIMPLECRYPTO_DIR}/sources/QBlockCipher.cpp
+ ${QSIMPLECRYPTO_DIR}/sources/QRsa.cpp
+ ${QSIMPLECRYPTO_DIR}/sources/QX509.cpp
+ ${QSIMPLECRYPTO_DIR}/sources/QX509Store.cpp
+)
diff --git a/client/cmake/android.cmake b/client/cmake/android.cmake
index 13c357bd..c96d9ab8 100644
--- a/client/cmake/android.cmake
+++ b/client/cmake/android.cmake
@@ -27,7 +27,6 @@ link_directories(${CMAKE_CURRENT_SOURCE_DIR}/platforms/android)
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_controller.h
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_utils.h
- ${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.h
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.h
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.h
)
@@ -35,7 +34,6 @@ set(HEADERS ${HEADERS}
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_controller.cpp
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_utils.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.cpp
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.cpp
)
diff --git a/client/configurators/wireguard_configurator.cpp b/client/configurators/wireguard_configurator.cpp
index f7faaa52..3f96e74c 100644
--- a/client/configurators/wireguard_configurator.cpp
+++ b/client/configurators/wireguard_configurator.cpp
@@ -95,6 +95,18 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
stdOut.replace("/32", "");
QStringList ips = stdOut.split("\n", Qt::SkipEmptyParts);
+ // remove extra IPs from each line for case when user manually edited the wg0.conf
+ // and added there more IPs for route his itnernal networks, like:
+ // ...
+ // AllowedIPs = 10.8.1.6/32, 192.168.1.0/24, 192.168.2.0/24, ...
+ // ...
+ // without this code - next IP would be 1 if last item in 'ips' has format above
+ QStringList vpnIps;
+ for (const auto &ip : ips) {
+ vpnIps.append(ip.split(",", Qt::SkipEmptyParts).first().trimmed());
+ }
+ ips = vpnIps;
+
// Calc next IP address
if (ips.isEmpty()) {
nextIpNumber = "2";
@@ -187,6 +199,10 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials
jConfig[config_key::server_pub_key] = connData.serverPubKey;
jConfig[config_key::mtu] = wireguarConfig.value(config_key::mtu).toString(protocols::wireguard::defaultMtu);
+ jConfig[config_key::persistent_keep_alive] = "25";
+ QJsonArray allowedIps { "0.0.0.0/0", "::/0" };
+ jConfig[config_key::allowed_ips] = allowedIps;
+
jConfig[config_key::clientId] = connData.clientPubKey;
return QJsonDocument(jConfig).toJson();
diff --git a/client/core/controllers/apiController.cpp b/client/core/controllers/apiController.cpp
index 35b459be..5cdaa7ae 100644
--- a/client/core/controllers/apiController.cpp
+++ b/client/core/controllers/apiController.cpp
@@ -5,8 +5,12 @@
#include
#include
+#include "QBlockCipher.h"
+#include "QRsa.h"
+
#include "amnezia_application.h"
#include "configurators/wireguard_configurator.h"
+#include "core/enums/apiEnums.h"
#include "version.h"
namespace
@@ -25,25 +29,75 @@ namespace
constexpr char uuid[] = "installation_uuid";
constexpr char osVersion[] = "os_version";
constexpr char appVersion[] = "app_version";
+
+ constexpr char userCountryCode[] = "user_country_code";
+ constexpr char serverCountryCode[] = "server_country_code";
+ constexpr char serviceType[] = "service_type";
+
+ constexpr char aesKey[] = "aes_key";
+ constexpr char aesIv[] = "aes_iv";
+ constexpr char aesSalt[] = "aes_salt";
+
+ constexpr char apiPayload[] = "api_payload";
+ constexpr char keyPayload[] = "key_payload";
+ }
+
+ const QStringList proxyStorageUrl = { "" };
+
+ ErrorCode checkErrors(const QList &sslErrors, QNetworkReply *reply)
+ {
+ if (!sslErrors.empty()) {
+ qDebug().noquote() << sslErrors;
+ return ErrorCode::ApiConfigSslError;
+ } else if (reply->error() == QNetworkReply::NoError) {
+ return ErrorCode::NoError;
+ } else if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
+ || reply->error() == QNetworkReply::NetworkError::TimeoutError) {
+ return ErrorCode::ApiConfigTimeoutError;
+ } else {
+ QString err = reply->errorString();
+ qDebug() << QString::fromUtf8(reply->readAll());
+ qDebug() << reply->error();
+ qDebug() << err;
+ qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+ return ErrorCode::ApiConfigDownloadError;
+ }
}
}
-ApiController::ApiController(QObject *parent) : QObject(parent)
+ApiController::ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent)
+ : QObject(parent), m_gatewayEndpoint(gatewayEndpoint), m_isDevEnvironment(isDevEnvironment)
{
}
-void ApiController::processApiConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData, QString &config)
+void ApiController::fillServerConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData,
+ const QByteArray &apiResponseBody, QJsonObject &serverConfig)
{
- if (protocol == configKey::cloak) {
- config.replace("", "\n");
- config.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
+ QString data = QJsonDocument::fromJson(apiResponseBody).object().value(config_key::config).toString();
+
+ data.replace("vpn://", "");
+ QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
+
+ if (ba.isEmpty()) {
+ emit errorOccurred(ErrorCode::ApiConfigEmptyError);
return;
+ }
+
+ QByteArray ba_uncompressed = qUncompress(ba);
+ if (!ba_uncompressed.isEmpty()) {
+ ba = ba_uncompressed;
+ }
+
+ QString configStr = ba;
+ if (protocol == configKey::cloak) {
+ configStr.replace("", "\n");
+ configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
} else if (protocol == configKey::awg) {
- config.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
- auto serverConfig = QJsonDocument::fromJson(config.toUtf8()).object();
+ configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
+ auto serverConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
auto containers = serverConfig.value(config_key::containers).toArray();
if (containers.isEmpty()) {
- return;
+ return; // todo process error
}
auto container = containers.at(0).toObject();
QString containerName = ContainerProps::containerTypeToString(DockerContainer::Awg);
@@ -61,11 +115,75 @@ void ApiController::processApiConfig(const QString &protocol, const ApiControlle
container[containerName] = containerConfig;
containers.replace(0, container);
serverConfig[config_key::containers] = containers;
- config = QString(QJsonDocument(serverConfig).toJson());
+ configStr = QString(QJsonDocument(serverConfig).toJson());
}
+
+ QJsonObject apiConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
+ serverConfig[config_key::dns1] = apiConfig.value(config_key::dns1);
+ serverConfig[config_key::dns2] = apiConfig.value(config_key::dns2);
+ serverConfig[config_key::containers] = apiConfig.value(config_key::containers);
+ serverConfig[config_key::hostName] = apiConfig.value(config_key::hostName);
+
+ if (apiConfig.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway) {
+ serverConfig[config_key::configVersion] = apiConfig.value(config_key::configVersion);
+ serverConfig[config_key::description] = apiConfig.value(config_key::description);
+ serverConfig[config_key::name] = apiConfig.value(config_key::name);
+ }
+
+ auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString();
+ serverConfig[config_key::defaultContainer] = defaultContainer;
+
return;
}
+QStringList ApiController::getProxyUrls()
+{
+ QNetworkRequest request;
+ request.setTransferTimeout(7000);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ QEventLoop wait;
+ QList sslErrors;
+ QNetworkReply *reply;
+
+ for (const auto &proxyStorageUrl : proxyStorageUrl) {
+ request.setUrl(proxyStorageUrl);
+ reply = amnApp->manager()->get(request);
+
+ connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
+ connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
+ wait.exec();
+
+ if (reply->error() == QNetworkReply::NetworkError::NoError) {
+ break;
+ }
+ reply->deleteLater();
+ }
+
+ auto encryptedResponseBody = reply->readAll();
+ reply->deleteLater();
+
+ EVP_PKEY *privateKey = nullptr;
+ QByteArray responseBody;
+ try {
+ QByteArray key = PROD_PROXY_STORAGE_KEY;
+ QSimpleCrypto::QRsa rsa;
+ privateKey = rsa.getPrivateKeyFromByteArray(key, "");
+ responseBody = rsa.decrypt(encryptedResponseBody, privateKey, RSA_PKCS1_PADDING);
+ } catch (...) {
+ qCritical() << "error loading private key from environment variables or decrypting payload";
+ return {};
+ }
+
+ auto endpointsArray = QJsonDocument::fromJson(responseBody).array();
+
+ QStringList endpoints;
+ for (const auto &endpoint : endpointsArray) {
+ endpoints.push_back(endpoint.toString());
+ }
+ return endpoints;
+}
+
ApiController::ApiPayloadData ApiController::generateApiPayloadData(const QString &protocol)
{
ApiController::ApiPayloadData apiPayload;
@@ -101,8 +219,6 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
QThread::msleep(10);
#endif
- auto containerConfig = serverConfig.value(config_key::containers).toArray();
-
if (serverConfig.value(config_key::configVersion).toInt()) {
QNetworkRequest request;
request.setTransferTimeout(7000);
@@ -120,39 +236,13 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
QByteArray requestBody = QJsonDocument(apiPayload).toJson();
- QNetworkReply *reply = amnApp->manager()->post(request, requestBody); // ??
+ QNetworkReply *reply = amnApp->manager()->post(request, requestBody);
QObject::connect(reply, &QNetworkReply::finished, [this, reply, protocol, apiPayloadData, serverIndex, serverConfig]() mutable {
if (reply->error() == QNetworkReply::NoError) {
- QString contents = QString::fromUtf8(reply->readAll());
- QString data = QJsonDocument::fromJson(contents.toUtf8()).object().value(config_key::config).toString();
-
- data.replace("vpn://", "");
- QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
-
- if (ba.isEmpty()) {
- emit errorOccurred(ErrorCode::ApiConfigEmptyError);
- return;
- }
-
- QByteArray ba_uncompressed = qUncompress(ba);
- if (!ba_uncompressed.isEmpty()) {
- ba = ba_uncompressed;
- }
-
- QString configStr = ba;
- processApiConfig(protocol, apiPayloadData, configStr);
-
- QJsonObject apiConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
- serverConfig[config_key::dns1] = apiConfig.value(config_key::dns1);
- serverConfig[config_key::dns2] = apiConfig.value(config_key::dns2);
- serverConfig[config_key::containers] = apiConfig.value(config_key::containers);
- serverConfig[config_key::hostName] = apiConfig.value(config_key::hostName);
-
- auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString();
- serverConfig[config_key::defaultContainer] = defaultContainer;
-
- emit configUpdated(true, serverConfig, serverIndex);
+ auto apiResponseBody = reply->readAll();
+ fillServerConfig(protocol, apiPayloadData, apiResponseBody, serverConfig);
+ emit finished(serverConfig, serverIndex);
} else {
if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
|| reply->error() == QNetworkReply::NetworkError::TimeoutError) {
@@ -178,3 +268,156 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
});
}
}
+
+ErrorCode ApiController::getServicesList(QByteArray &responseBody)
+{
+#ifdef Q_OS_IOS
+ IosController::Instance()->requestInetAccess();
+ QThread::msleep(10);
+#endif
+
+ QNetworkRequest request;
+ request.setTransferTimeout(7000);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ request.setUrl(QString("%1v1/services").arg(m_gatewayEndpoint));
+
+ QNetworkReply *reply;
+ reply = amnApp->manager()->get(request);
+
+ QEventLoop wait;
+ QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
+
+ QList sslErrors;
+ connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
+ wait.exec();
+
+ if (reply->error() == QNetworkReply::NetworkError::TimeoutError || reply->error() == QNetworkReply::NetworkError::OperationCanceledError) {
+ m_proxyUrls = getProxyUrls();
+ for (const QString &proxyUrl : m_proxyUrls) {
+ request.setUrl(QString("%1v1/services").arg(proxyUrl));
+ reply = amnApp->manager()->get(request);
+
+ QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
+ connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
+ wait.exec();
+ if (reply->error() != QNetworkReply::NetworkError::TimeoutError
+ && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
+ break;
+ }
+ reply->deleteLater();
+ }
+ }
+
+ responseBody = reply->readAll();
+ auto errorCode = checkErrors(sslErrors, reply);
+ reply->deleteLater();
+ return errorCode;
+}
+
+ErrorCode ApiController::getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
+ const QString &protocol, const QString &serverCountryCode, QJsonObject &serverConfig)
+{
+#ifdef Q_OS_IOS
+ IosController::Instance()->requestInetAccess();
+ QThread::msleep(10);
+#endif
+
+ QNetworkAccessManager manager;
+ QNetworkRequest request;
+ request.setTransferTimeout(7000);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ request.setUrl(QString("%1v1/config").arg(m_gatewayEndpoint));
+
+ ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
+
+ QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
+ apiPayload[configKey::userCountryCode] = userCountryCode;
+ if (!serverCountryCode.isEmpty()) {
+ apiPayload[configKey::serverCountryCode] = serverCountryCode;
+ }
+ apiPayload[configKey::serviceType] = serviceType;
+ apiPayload[configKey::uuid] = installationUuid;
+
+ QSimpleCrypto::QBlockCipher blockCipher;
+ QByteArray key = blockCipher.generatePrivateSalt(32);
+ QByteArray iv = blockCipher.generatePrivateSalt(32);
+ QByteArray salt = blockCipher.generatePrivateSalt(8);
+
+ QJsonObject keyPayload;
+ keyPayload[configKey::aesKey] = QString(key.toBase64());
+ keyPayload[configKey::aesIv] = QString(iv.toBase64());
+ keyPayload[configKey::aesSalt] = QString(salt.toBase64());
+
+ QByteArray encryptedKeyPayload;
+ QByteArray encryptedApiPayload;
+ try {
+ QSimpleCrypto::QRsa rsa;
+
+ EVP_PKEY *publicKey = nullptr;
+ try {
+ QByteArray rsaKey = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
+ QSimpleCrypto::QRsa rsa;
+ publicKey = rsa.getPublicKeyFromByteArray(rsaKey);
+ } catch (...) {
+ qCritical() << "error loading public key from environment variables";
+ return ErrorCode::ApiMissingAgwPublicKey;
+ }
+
+ encryptedKeyPayload = rsa.encrypt(QJsonDocument(keyPayload).toJson(), publicKey, RSA_PKCS1_PADDING);
+ EVP_PKEY_free(publicKey);
+
+ encryptedApiPayload = blockCipher.encryptAesBlockCipher(QJsonDocument(apiPayload).toJson(), key, iv, "", salt);
+ } catch (...) { // todo change error handling in QSimpleCrypto?
+ qCritical() << "error when encrypting the request body";
+ }
+
+ QJsonObject requestBody;
+ requestBody[configKey::keyPayload] = QString(encryptedKeyPayload.toBase64());
+ requestBody[configKey::apiPayload] = QString(encryptedApiPayload.toBase64());
+
+ QNetworkReply *reply = manager.post(request, QJsonDocument(requestBody).toJson());
+
+ QEventLoop wait;
+ connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
+
+ QList sslErrors;
+ connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
+ wait.exec();
+
+ if (reply->error() == QNetworkReply::NetworkError::TimeoutError || reply->error() == QNetworkReply::NetworkError::OperationCanceledError) {
+ if (m_proxyUrls.isEmpty()) {
+ m_proxyUrls = getProxyUrls();
+ }
+ for (const QString &proxyUrl : m_proxyUrls) {
+ request.setUrl(QString("%1v1/config").arg(proxyUrl));
+ reply = manager.post(request, QJsonDocument(requestBody).toJson());
+
+ QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
+ connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
+ wait.exec();
+ if (reply->error() != QNetworkReply::NetworkError::TimeoutError
+ && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
+ break;
+ }
+ reply->deleteLater();
+ }
+ }
+
+ auto errorCode = checkErrors(sslErrors, reply);
+ if (errorCode) {
+ return errorCode;
+ }
+
+ auto encryptedResponseBody = reply->readAll();
+ reply->deleteLater();
+ try {
+ auto responseBody = blockCipher.decryptAesBlockCipher(encryptedResponseBody, key, iv, "", salt);
+ fillServerConfig(protocol, apiPayloadData, responseBody, serverConfig);
+ } catch (...) { // todo change error handling in QSimpleCrypto?
+ qCritical() << "error when decrypting the request body";
+ }
+
+ return errorCode;
+}
diff --git a/client/core/controllers/apiController.h b/client/core/controllers/apiController.h
index cc5d9f31..1f811498 100644
--- a/client/core/controllers/apiController.h
+++ b/client/core/controllers/apiController.h
@@ -14,14 +14,18 @@ class ApiController : public QObject
Q_OBJECT
public:
- explicit ApiController(QObject *parent = nullptr);
+ explicit ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent = nullptr);
public slots:
void updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig);
+ ErrorCode getServicesList(QByteArray &responseBody);
+ ErrorCode getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
+ const QString &protocol, const QString &serverCountryCode, QJsonObject &serverConfig);
+
signals:
void errorOccurred(ErrorCode errorCode);
- void configUpdated(const bool updateConfig, const QJsonObject &config, const int serverIndex);
+ void finished(const QJsonObject &config, const int serverIndex);
private:
struct ApiPayloadData
@@ -34,7 +38,13 @@ private:
ApiPayloadData generateApiPayloadData(const QString &protocol);
QJsonObject fillApiPayload(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData);
- void processApiConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData, QString &config);
+ void fillServerConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData, const QByteArray &apiResponseBody,
+ QJsonObject &serverConfig);
+ QStringList getProxyUrls();
+
+ QString m_gatewayEndpoint;
+ QStringList m_proxyUrls;
+ bool m_isDevEnvironment = false;
};
#endif // APICONTROLLER_H
diff --git a/client/core/controllers/serverController.cpp b/client/core/controllers/serverController.cpp
index 233d66d4..b6795a01 100644
--- a/client/core/controllers/serverController.cpp
+++ b/client/core/controllers/serverController.cpp
@@ -83,7 +83,6 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
}
qDebug().noquote() << lineToExec;
- Logger::appendSshLog("Run command:" + lineToExec);
error = m_sshClient.executeCommand(lineToExec, cbReadStdOut, cbReadStdErr);
if (error != ErrorCode::NoError) {
@@ -100,13 +99,13 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti
const std::function &cbReadStdErr)
{
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
- Logger::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script);
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
if (e)
return e;
- QString runner = QString("sudo docker exec -i $CONTAINER_NAME %2 %1 ").arg(fileName, (container == DockerContainer::Socks5Proxy ? "sh" : "bash"));
+ QString runner =
+ QString("sudo docker exec -i $CONTAINER_NAME %2 %1 ").arg(fileName, (container == DockerContainer::Socks5Proxy ? "sh" : "bash"));
e = runScript(credentials, replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
@@ -426,7 +425,7 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
if (errorCode)
return errorCode;
- errorCode = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(),dockerFilePath);
+ errorCode = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(), dockerFilePath);
if (errorCode)
return errorCode;
@@ -437,9 +436,10 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
return ErrorCode::NoError;
};
- errorCode = runScript(credentials,
- replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)),
- cbReadStdOut);
+ errorCode =
+ runScript(credentials,
+ replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)),
+ cbReadStdOut);
if (errorCode)
return errorCode;
@@ -621,13 +621,15 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
// Socks5 proxy vars
vars.append({ { "$SOCKS5_PROXY_PORT", socks5ProxyConfig.value(config_key::port).toString(protocols::socks5Proxy::defaultPort) } });
- auto username = socks5ProxyConfig.value(config_key:: userName).toString();
+ auto username = socks5ProxyConfig.value(config_key::userName).toString();
auto password = socks5ProxyConfig.value(config_key::password).toString();
QString socks5user = (!username.isEmpty() && !password.isEmpty()) ? QString("users %1:CL:%2").arg(username, password) : "";
- vars.append({ { "$SOCKS5_USER", socks5user } });
- vars.append({ { "$SOCKS5_AUTH_TYPE", socks5user.isEmpty() ? "none" : "strong" } });
+ vars.append({ { "$SOCKS5_USER", socks5user } });
+ vars.append({ { "$SOCKS5_AUTH_TYPE", socks5user.isEmpty() ? "none" : "strong" } });
- QString serverIp = NetworkUtilities::getIPAddress(credentials.hostName);
+ QString serverIp = (container != DockerContainer::Awg && container != DockerContainer::WireGuard && container != DockerContainer::Xray)
+ ? NetworkUtilities::getIPAddress(credentials.hostName)
+ : credentials.hostName;
if (!serverIp.isEmpty()) {
vars.append({ { "$SERVER_IP_ADDRESS", serverIp } });
} else {
@@ -713,7 +715,8 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
udpProtoScript.append("' | grep -i udp");
tcpProtoScript.append(" | grep LISTEN");
- ErrorCode errorCode = runScript(credentials, replaceVars(tcpProtoScript, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
+ ErrorCode errorCode =
+ runScript(credentials, replaceVars(tcpProtoScript, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
diff --git a/client/core/controllers/vpnConfigurationController.cpp b/client/core/controllers/vpnConfigurationController.cpp
index 818cf57e..52f42c42 100644
--- a/client/core/controllers/vpnConfigurationController.cpp
+++ b/client/core/controllers/vpnConfigurationController.cpp
@@ -100,7 +100,13 @@ QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPairprocessConfigWithLocalSettings(dns, isApiConfig, protocolConfigString);
QJsonObject vpnConfigData = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
- vpnConfigData = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
+ if (container == DockerContainer::Awg || container == DockerContainer::WireGuard) {
+ // add mtu for old configs
+ if (vpnConfigData[config_key::mtu].toString().isEmpty()) {
+ vpnConfigData[config_key::mtu] = container == DockerContainer::Awg ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu;
+ }
+ }
+
vpnConfiguration.insert(ProtocolProps::key_proto_config_data(proto), vpnConfigData);
}
diff --git a/client/core/defs.h b/client/core/defs.h
index a441ee1c..802eca45 100644
--- a/client/core/defs.h
+++ b/client/core/defs.h
@@ -96,6 +96,7 @@ namespace amnezia
// import and install errors
ImportInvalidConfigError = 900,
+ ImportOpenConfigError = 901,
// Android errors
AndroidError = 1000,
@@ -106,6 +107,7 @@ namespace amnezia
ApiConfigEmptyError = 1102,
ApiConfigTimeoutError = 1103,
ApiConfigSslError = 1104,
+ ApiMissingAgwPublicKey = 1105,
// QFile errors
OpenError = 1200,
diff --git a/client/core/enums/apiEnums.h b/client/core/enums/apiEnums.h
new file mode 100644
index 00000000..1f050007
--- /dev/null
+++ b/client/core/enums/apiEnums.h
@@ -0,0 +1,9 @@
+#ifndef APIENUMS_H
+#define APIENUMS_H
+
+enum ApiConfigSources {
+ Telegram = 1,
+ AmneziaGateway
+};
+
+#endif // APIENUMS_H
diff --git a/client/core/errorstrings.cpp b/client/core/errorstrings.cpp
index 645ec6c5..00e94995 100644
--- a/client/core/errorstrings.cpp
+++ b/client/core/errorstrings.cpp
@@ -50,6 +50,7 @@ QString errorString(ErrorCode code) {
case (ErrorCode::AddressPoolError): errorMessage = QObject::tr("VPN pool error: no available addresses"); break;
case (ErrorCode::ImportInvalidConfigError): errorMessage = QObject::tr("The config does not contain any containers and credentials for connecting to the server"); break;
+ case (ErrorCode::ImportOpenConfigError): errorMessage = QObject::tr(""); break;
// Android errors
case (ErrorCode::AndroidError): errorMessage = QObject::tr("VPN connection error"); break;
@@ -60,6 +61,7 @@ QString errorString(ErrorCode code) {
case (ErrorCode::ApiConfigEmptyError): errorMessage = QObject::tr("In the response from the server, an empty config was received"); break;
case (ErrorCode::ApiConfigSslError): errorMessage = QObject::tr("SSL error occurred"); break;
case (ErrorCode::ApiConfigTimeoutError): errorMessage = QObject::tr("Server response timeout on api request"); break;
+ case (ErrorCode::ApiMissingAgwPublicKey): errorMessage = QObject::tr("Missing AGW public key"); break;
// QFile errors
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
diff --git a/client/core/ipcclient.cpp b/client/core/ipcclient.cpp
index 3e364452..b44da1bf 100644
--- a/client/core/ipcclient.cpp
+++ b/client/core/ipcclient.cpp
@@ -29,6 +29,12 @@ QSharedPointer IpcClient::Interface()
return Instance()->m_ipcClient;
}
+QSharedPointer IpcClient::InterfaceTun2Socks()
+{
+ if (!Instance()) return nullptr;
+ return Instance()->m_Tun2SocksClient;
+}
+
bool IpcClient::init(IpcClient *instance)
{
m_instance = instance;
@@ -44,6 +50,12 @@ bool IpcClient::init(IpcClient *instance)
qWarning() << "IpcClient replica is not connected!";
}
+ Instance()->m_Tun2SocksClient.reset(Instance()->m_ClientNode.acquire());
+ Instance()->m_Tun2SocksClient->waitForSource(1000);
+
+ if (!Instance()->m_Tun2SocksClient->isReplicaValid()) {
+ qWarning() << "IpcClient::m_Tun2SocksClient replica is not connected!";
+ }
});
connect(Instance()->m_localSocket, &QLocalSocket::disconnected, [instance](){
@@ -51,16 +63,16 @@ bool IpcClient::init(IpcClient *instance)
});
Instance()->m_localSocket->connectToServer(amnezia::getIpcServiceUrl());
-
Instance()->m_localSocket->waitForConnected();
if (!Instance()->m_ipcClient) {
qDebug() << "IpcClient::init failed";
return false;
}
+
qDebug() << "IpcClient::init succeed";
- return Instance()->m_ipcClient->isReplicaValid();
+ return (Instance()->m_ipcClient->isReplicaValid() && Instance()->m_Tun2SocksClient->isReplicaValid());
}
QSharedPointer IpcClient::CreatePrivilegedProcess()
diff --git a/client/core/ipcclient.h b/client/core/ipcclient.h
index ab5d750a..ad2e6b6e 100644
--- a/client/core/ipcclient.h
+++ b/client/core/ipcclient.h
@@ -6,6 +6,7 @@
#include "ipc.h"
#include "rep_ipc_interface_replica.h"
+#include "rep_ipc_process_tun2socks_replica.h"
#include "privileged_process.h"
@@ -18,6 +19,7 @@ public:
static IpcClient *Instance();
static bool init(IpcClient *instance);
static QSharedPointer Interface();
+ static QSharedPointer InterfaceTun2Socks();
static QSharedPointer CreatePrivilegedProcess();
bool isSocketConnected() const;
@@ -28,8 +30,11 @@ private:
~IpcClient() override;
QRemoteObjectNode m_ClientNode;
+ QRemoteObjectNode m_Tun2SocksNode;
QSharedPointer m_ipcClient;
QPointer m_localSocket;
+ QPointer m_tun2socksSocket;
+ QSharedPointer m_Tun2SocksClient;
struct ProcessDescriptor {
ProcessDescriptor () {
diff --git a/client/core/networkUtilities.cpp b/client/core/networkUtilities.cpp
index 7ffd4c41..a5825f0d 100644
--- a/client/core/networkUtilities.cpp
+++ b/client/core/networkUtilities.cpp
@@ -109,7 +109,10 @@ QStringList NetworkUtilities::summarizeRoutes(const QStringList &ips, const QStr
QString NetworkUtilities::getIPAddress(const QString &host)
{
- if (ipAddressRegExp().match(host).hasMatch()) {
+ QHostAddress address(host);
+ if (QAbstractSocket::IPv4Protocol == address.protocol()) {
+ return host;
+ } else if (QAbstractSocket::IPv6Protocol == address.protocol()) {
return host;
}
diff --git a/client/images/amneziaBigLogo.svg b/client/images/amneziaBigLogo.svg
deleted file mode 100644
index c50c7743..00000000
--- a/client/images/amneziaBigLogo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/animation.gif b/client/images/animation.gif
deleted file mode 100644
index 6f7f38e8..00000000
Binary files a/client/images/animation.gif and /dev/null differ
diff --git a/client/images/arrow_left.png b/client/images/arrow_left.png
deleted file mode 100644
index 3a4d149d..00000000
Binary files a/client/images/arrow_left.png and /dev/null differ
diff --git a/client/images/background_connected.png b/client/images/background_connected.png
deleted file mode 100644
index 62480d5f..00000000
Binary files a/client/images/background_connected.png and /dev/null differ
diff --git a/client/images/background_connected@2x.png b/client/images/background_connected@2x.png
deleted file mode 100644
index 4f76b956..00000000
Binary files a/client/images/background_connected@2x.png and /dev/null differ
diff --git a/client/images/check.png b/client/images/check.png
deleted file mode 100644
index 43039eb1..00000000
Binary files a/client/images/check.png and /dev/null differ
diff --git a/client/images/close.png b/client/images/close.png
deleted file mode 100644
index 072232c1..00000000
Binary files a/client/images/close.png and /dev/null differ
diff --git a/client/images/connected.png b/client/images/connected.png
deleted file mode 100644
index b3c907c8..00000000
Binary files a/client/images/connected.png and /dev/null differ
diff --git a/client/images/connectionOff.svg b/client/images/connectionOff.svg
deleted file mode 100644
index 27905ff9..00000000
--- a/client/images/connectionOff.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-
diff --git a/client/images/connectionOn.svg b/client/images/connectionOn.svg
deleted file mode 100644
index ef317622..00000000
--- a/client/images/connectionOn.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-
diff --git a/client/images/connectionProgress.svg b/client/images/connectionProgress.svg
deleted file mode 100644
index 8c4024c9..00000000
--- a/client/images/connectionProgress.svg
+++ /dev/null
@@ -1,30 +0,0 @@
-
diff --git a/client/images/controls/archive-restore.svg b/client/images/controls/archive-restore.svg
new file mode 100644
index 00000000..d3ad8c9e
--- /dev/null
+++ b/client/images/controls/archive-restore.svg
@@ -0,0 +1,7 @@
+
diff --git a/client/images/controls/bug.svg b/client/images/controls/bug.svg
new file mode 100644
index 00000000..80fd2277
--- /dev/null
+++ b/client/images/controls/bug.svg
@@ -0,0 +1,11 @@
+
diff --git a/client/images/controls/folder-search-2.svg b/client/images/controls/folder-search-2.svg
new file mode 100644
index 00000000..f77ce57d
--- /dev/null
+++ b/client/images/controls/folder-search-2.svg
@@ -0,0 +1,5 @@
+
diff --git a/client/images/controls/gauge.svg b/client/images/controls/gauge.svg
new file mode 100644
index 00000000..4b9c1444
--- /dev/null
+++ b/client/images/controls/gauge.svg
@@ -0,0 +1,4 @@
+
diff --git a/client/images/controls/help-circle.svg b/client/images/controls/help-circle.svg
new file mode 100644
index 00000000..7bcd4450
--- /dev/null
+++ b/client/images/controls/help-circle.svg
@@ -0,0 +1,5 @@
+
diff --git a/client/images/controls/history.svg b/client/images/controls/history.svg
new file mode 100644
index 00000000..73beb8b3
--- /dev/null
+++ b/client/images/controls/history.svg
@@ -0,0 +1,5 @@
+
diff --git a/client/images/controls/info.svg b/client/images/controls/info.svg
new file mode 100644
index 00000000..43a40245
--- /dev/null
+++ b/client/images/controls/info.svg
@@ -0,0 +1,5 @@
+
diff --git a/client/images/controls/map-pin.svg b/client/images/controls/map-pin.svg
new file mode 100644
index 00000000..64b75b48
--- /dev/null
+++ b/client/images/controls/map-pin.svg
@@ -0,0 +1,4 @@
+
diff --git a/client/images/controls/refresh-cw.svg b/client/images/controls/refresh-cw.svg
new file mode 100644
index 00000000..9572e3e2
--- /dev/null
+++ b/client/images/controls/refresh-cw.svg
@@ -0,0 +1,6 @@
+
diff --git a/client/images/controls/scan-line.svg b/client/images/controls/scan-line.svg
new file mode 100644
index 00000000..be4acc2a
--- /dev/null
+++ b/client/images/controls/scan-line.svg
@@ -0,0 +1,7 @@
+
diff --git a/client/images/controls/tag.svg b/client/images/controls/tag.svg
new file mode 100644
index 00000000..88a9db8d
--- /dev/null
+++ b/client/images/controls/tag.svg
@@ -0,0 +1,4 @@
+
diff --git a/client/images/delete.png b/client/images/delete.png
deleted file mode 100644
index 59687bd2..00000000
Binary files a/client/images/delete.png and /dev/null differ
diff --git a/client/images/disconnected.png b/client/images/disconnected.png
deleted file mode 100644
index 199f71dc..00000000
Binary files a/client/images/disconnected.png and /dev/null differ
diff --git a/client/images/download.png b/client/images/download.png
deleted file mode 100644
index 0e949133..00000000
Binary files a/client/images/download.png and /dev/null differ
diff --git a/client/images/favorites_disabled.png b/client/images/favorites_disabled.png
deleted file mode 100644
index 12a821ac..00000000
Binary files a/client/images/favorites_disabled.png and /dev/null differ
diff --git a/client/images/favorites_enabled.png b/client/images/favorites_enabled.png
deleted file mode 100644
index 61e28f42..00000000
Binary files a/client/images/favorites_enabled.png and /dev/null differ
diff --git a/client/images/favorites_hover.png b/client/images/favorites_hover.png
deleted file mode 100644
index 71e7a1b2..00000000
Binary files a/client/images/favorites_hover.png and /dev/null differ
diff --git a/client/images/flagKit/AD.svg b/client/images/flagKit/AD.svg
new file mode 100644
index 00000000..4855f9fb
--- /dev/null
+++ b/client/images/flagKit/AD.svg
@@ -0,0 +1,35 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AE.svg b/client/images/flagKit/AE.svg
new file mode 100644
index 00000000..3095fe31
--- /dev/null
+++ b/client/images/flagKit/AE.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AF.svg b/client/images/flagKit/AF.svg
new file mode 100644
index 00000000..75216b74
--- /dev/null
+++ b/client/images/flagKit/AF.svg
@@ -0,0 +1,34 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AG.svg b/client/images/flagKit/AG.svg
new file mode 100644
index 00000000..ac56b808
--- /dev/null
+++ b/client/images/flagKit/AG.svg
@@ -0,0 +1,44 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AI.svg b/client/images/flagKit/AI.svg
new file mode 100644
index 00000000..7f53e464
--- /dev/null
+++ b/client/images/flagKit/AI.svg
@@ -0,0 +1,50 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AL.svg b/client/images/flagKit/AL.svg
new file mode 100644
index 00000000..43ff1a3b
--- /dev/null
+++ b/client/images/flagKit/AL.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AM.svg b/client/images/flagKit/AM.svg
new file mode 100644
index 00000000..5224d30f
--- /dev/null
+++ b/client/images/flagKit/AM.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AO.svg b/client/images/flagKit/AO.svg
new file mode 100644
index 00000000..86044f3b
--- /dev/null
+++ b/client/images/flagKit/AO.svg
@@ -0,0 +1,37 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AR.svg b/client/images/flagKit/AR.svg
new file mode 100644
index 00000000..4dbc96f1
--- /dev/null
+++ b/client/images/flagKit/AR.svg
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AS.svg b/client/images/flagKit/AS.svg
new file mode 100644
index 00000000..afb37540
--- /dev/null
+++ b/client/images/flagKit/AS.svg
@@ -0,0 +1,36 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AT.svg b/client/images/flagKit/AT.svg
new file mode 100644
index 00000000..627245e3
--- /dev/null
+++ b/client/images/flagKit/AT.svg
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AU.svg b/client/images/flagKit/AU.svg
new file mode 100644
index 00000000..aad6b1e6
--- /dev/null
+++ b/client/images/flagKit/AU.svg
@@ -0,0 +1,36 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AW.svg b/client/images/flagKit/AW.svg
new file mode 100644
index 00000000..892d8aa0
--- /dev/null
+++ b/client/images/flagKit/AW.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AX.svg b/client/images/flagKit/AX.svg
new file mode 100644
index 00000000..577cd268
--- /dev/null
+++ b/client/images/flagKit/AX.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/AZ.svg b/client/images/flagKit/AZ.svg
new file mode 100644
index 00000000..3f082f33
--- /dev/null
+++ b/client/images/flagKit/AZ.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BA.svg b/client/images/flagKit/BA.svg
new file mode 100644
index 00000000..a16324e1
--- /dev/null
+++ b/client/images/flagKit/BA.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BB.svg b/client/images/flagKit/BB.svg
new file mode 100644
index 00000000..5c89e132
--- /dev/null
+++ b/client/images/flagKit/BB.svg
@@ -0,0 +1,38 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BD.svg b/client/images/flagKit/BD.svg
new file mode 100644
index 00000000..e1a3cd31
--- /dev/null
+++ b/client/images/flagKit/BD.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BE.svg b/client/images/flagKit/BE.svg
new file mode 100644
index 00000000..ac00173d
--- /dev/null
+++ b/client/images/flagKit/BE.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BF.svg b/client/images/flagKit/BF.svg
new file mode 100644
index 00000000..5b4286bb
--- /dev/null
+++ b/client/images/flagKit/BF.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BG.svg b/client/images/flagKit/BG.svg
new file mode 100644
index 00000000..e8256f47
--- /dev/null
+++ b/client/images/flagKit/BG.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BH.svg b/client/images/flagKit/BH.svg
new file mode 100644
index 00000000..e1c11093
--- /dev/null
+++ b/client/images/flagKit/BH.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BI.svg b/client/images/flagKit/BI.svg
new file mode 100644
index 00000000..2f208253
--- /dev/null
+++ b/client/images/flagKit/BI.svg
@@ -0,0 +1,36 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BJ.svg b/client/images/flagKit/BJ.svg
new file mode 100644
index 00000000..b21c46e0
--- /dev/null
+++ b/client/images/flagKit/BJ.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BL.svg b/client/images/flagKit/BL.svg
new file mode 100644
index 00000000..b99bc2c7
--- /dev/null
+++ b/client/images/flagKit/BL.svg
@@ -0,0 +1,42 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BM.svg b/client/images/flagKit/BM.svg
new file mode 100644
index 00000000..798dd8b9
--- /dev/null
+++ b/client/images/flagKit/BM.svg
@@ -0,0 +1,49 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BN.svg b/client/images/flagKit/BN.svg
new file mode 100644
index 00000000..1fe9afc4
--- /dev/null
+++ b/client/images/flagKit/BN.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BO.svg b/client/images/flagKit/BO.svg
new file mode 100644
index 00000000..7ee247bd
--- /dev/null
+++ b/client/images/flagKit/BO.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BR.svg b/client/images/flagKit/BR.svg
new file mode 100644
index 00000000..17edb103
--- /dev/null
+++ b/client/images/flagKit/BR.svg
@@ -0,0 +1,35 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BS.svg b/client/images/flagKit/BS.svg
new file mode 100644
index 00000000..767423af
--- /dev/null
+++ b/client/images/flagKit/BS.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BT.svg b/client/images/flagKit/BT.svg
new file mode 100644
index 00000000..d2f749bd
--- /dev/null
+++ b/client/images/flagKit/BT.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BV.svg b/client/images/flagKit/BV.svg
new file mode 100644
index 00000000..00a47ee5
--- /dev/null
+++ b/client/images/flagKit/BV.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BW.svg b/client/images/flagKit/BW.svg
new file mode 100644
index 00000000..ccac652b
--- /dev/null
+++ b/client/images/flagKit/BW.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BY.svg b/client/images/flagKit/BY.svg
new file mode 100644
index 00000000..d584988d
--- /dev/null
+++ b/client/images/flagKit/BY.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/BZ.svg b/client/images/flagKit/BZ.svg
new file mode 100644
index 00000000..8758df23
--- /dev/null
+++ b/client/images/flagKit/BZ.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CA.svg b/client/images/flagKit/CA.svg
new file mode 100644
index 00000000..786b609b
--- /dev/null
+++ b/client/images/flagKit/CA.svg
@@ -0,0 +1,25 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CC.svg b/client/images/flagKit/CC.svg
new file mode 100644
index 00000000..b96f3016
--- /dev/null
+++ b/client/images/flagKit/CC.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CD.svg b/client/images/flagKit/CD.svg
new file mode 100644
index 00000000..0d351c30
--- /dev/null
+++ b/client/images/flagKit/CD.svg
@@ -0,0 +1,31 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CF.svg b/client/images/flagKit/CF.svg
new file mode 100644
index 00000000..68566a2e
--- /dev/null
+++ b/client/images/flagKit/CF.svg
@@ -0,0 +1,43 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CG.svg b/client/images/flagKit/CG.svg
new file mode 100644
index 00000000..bc4eb95b
--- /dev/null
+++ b/client/images/flagKit/CG.svg
@@ -0,0 +1,34 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CH.svg b/client/images/flagKit/CH.svg
new file mode 100644
index 00000000..772f4fa3
--- /dev/null
+++ b/client/images/flagKit/CH.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CI.svg b/client/images/flagKit/CI.svg
new file mode 100644
index 00000000..096d98ab
--- /dev/null
+++ b/client/images/flagKit/CI.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CK.svg b/client/images/flagKit/CK.svg
new file mode 100644
index 00000000..c1ea3734
--- /dev/null
+++ b/client/images/flagKit/CK.svg
@@ -0,0 +1,31 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CL.svg b/client/images/flagKit/CL.svg
new file mode 100644
index 00000000..d456d951
--- /dev/null
+++ b/client/images/flagKit/CL.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CM.svg b/client/images/flagKit/CM.svg
new file mode 100644
index 00000000..482f4a97
--- /dev/null
+++ b/client/images/flagKit/CM.svg
@@ -0,0 +1,38 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CN.svg b/client/images/flagKit/CN.svg
new file mode 100644
index 00000000..883ba157
--- /dev/null
+++ b/client/images/flagKit/CN.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CO.svg b/client/images/flagKit/CO.svg
new file mode 100644
index 00000000..be492e3d
--- /dev/null
+++ b/client/images/flagKit/CO.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CR.svg b/client/images/flagKit/CR.svg
new file mode 100644
index 00000000..271204eb
--- /dev/null
+++ b/client/images/flagKit/CR.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CU.svg b/client/images/flagKit/CU.svg
new file mode 100644
index 00000000..23750cd9
--- /dev/null
+++ b/client/images/flagKit/CU.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CV.svg b/client/images/flagKit/CV.svg
new file mode 100644
index 00000000..4b6152fb
--- /dev/null
+++ b/client/images/flagKit/CV.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CW.svg b/client/images/flagKit/CW.svg
new file mode 100644
index 00000000..14acd27f
--- /dev/null
+++ b/client/images/flagKit/CW.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CX.svg b/client/images/flagKit/CX.svg
new file mode 100644
index 00000000..b3fe73d9
--- /dev/null
+++ b/client/images/flagKit/CX.svg
@@ -0,0 +1,38 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CY.svg b/client/images/flagKit/CY.svg
new file mode 100644
index 00000000..b7860aa9
--- /dev/null
+++ b/client/images/flagKit/CY.svg
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/CZ.svg b/client/images/flagKit/CZ.svg
new file mode 100644
index 00000000..d56c61b8
--- /dev/null
+++ b/client/images/flagKit/CZ.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/DE.svg b/client/images/flagKit/DE.svg
new file mode 100644
index 00000000..4ff1ebd5
--- /dev/null
+++ b/client/images/flagKit/DE.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/DJ.svg b/client/images/flagKit/DJ.svg
new file mode 100644
index 00000000..c0a019f9
--- /dev/null
+++ b/client/images/flagKit/DJ.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/DK.svg b/client/images/flagKit/DK.svg
new file mode 100644
index 00000000..27900e15
--- /dev/null
+++ b/client/images/flagKit/DK.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/DM.svg b/client/images/flagKit/DM.svg
new file mode 100644
index 00000000..d5c401eb
--- /dev/null
+++ b/client/images/flagKit/DM.svg
@@ -0,0 +1,41 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/DO.svg b/client/images/flagKit/DO.svg
new file mode 100644
index 00000000..9188e0be
--- /dev/null
+++ b/client/images/flagKit/DO.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/DZ.svg b/client/images/flagKit/DZ.svg
new file mode 100644
index 00000000..0920d712
--- /dev/null
+++ b/client/images/flagKit/DZ.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/EC.svg b/client/images/flagKit/EC.svg
new file mode 100644
index 00000000..0fbd3ea6
--- /dev/null
+++ b/client/images/flagKit/EC.svg
@@ -0,0 +1,39 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/EE.svg b/client/images/flagKit/EE.svg
new file mode 100644
index 00000000..63605223
--- /dev/null
+++ b/client/images/flagKit/EE.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/EG.svg b/client/images/flagKit/EG.svg
new file mode 100644
index 00000000..32d4447e
--- /dev/null
+++ b/client/images/flagKit/EG.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/ER.svg b/client/images/flagKit/ER.svg
new file mode 100644
index 00000000..bb70368b
--- /dev/null
+++ b/client/images/flagKit/ER.svg
@@ -0,0 +1,40 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/ES.svg b/client/images/flagKit/ES.svg
new file mode 100644
index 00000000..883554f8
--- /dev/null
+++ b/client/images/flagKit/ES.svg
@@ -0,0 +1,34 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/ET.svg b/client/images/flagKit/ET.svg
new file mode 100644
index 00000000..c4387b9f
--- /dev/null
+++ b/client/images/flagKit/ET.svg
@@ -0,0 +1,42 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/EU.svg b/client/images/flagKit/EU.svg
new file mode 100644
index 00000000..db74ffaf
--- /dev/null
+++ b/client/images/flagKit/EU.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/FI.svg b/client/images/flagKit/FI.svg
new file mode 100644
index 00000000..9d243ed5
--- /dev/null
+++ b/client/images/flagKit/FI.svg
@@ -0,0 +1,22 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/FJ.svg b/client/images/flagKit/FJ.svg
new file mode 100644
index 00000000..e3ebc9bb
--- /dev/null
+++ b/client/images/flagKit/FJ.svg
@@ -0,0 +1,51 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/FK.svg b/client/images/flagKit/FK.svg
new file mode 100644
index 00000000..01b0f2a8
--- /dev/null
+++ b/client/images/flagKit/FK.svg
@@ -0,0 +1,58 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/FM.svg b/client/images/flagKit/FM.svg
new file mode 100644
index 00000000..befd157c
--- /dev/null
+++ b/client/images/flagKit/FM.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/FO.svg b/client/images/flagKit/FO.svg
new file mode 100644
index 00000000..77618c05
--- /dev/null
+++ b/client/images/flagKit/FO.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/FR.svg b/client/images/flagKit/FR.svg
new file mode 100644
index 00000000..940de616
--- /dev/null
+++ b/client/images/flagKit/FR.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GA.svg b/client/images/flagKit/GA.svg
new file mode 100644
index 00000000..45c68087
--- /dev/null
+++ b/client/images/flagKit/GA.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GB.svg b/client/images/flagKit/GB.svg
new file mode 100644
index 00000000..679d27c7
--- /dev/null
+++ b/client/images/flagKit/GB.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GD.svg b/client/images/flagKit/GD.svg
new file mode 100644
index 00000000..210dc3fd
--- /dev/null
+++ b/client/images/flagKit/GD.svg
@@ -0,0 +1,49 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GE.svg b/client/images/flagKit/GE.svg
new file mode 100644
index 00000000..818f3f5b
--- /dev/null
+++ b/client/images/flagKit/GE.svg
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GF.svg b/client/images/flagKit/GF.svg
new file mode 100644
index 00000000..bae1448d
--- /dev/null
+++ b/client/images/flagKit/GF.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GG.svg b/client/images/flagKit/GG.svg
new file mode 100644
index 00000000..fa428535
--- /dev/null
+++ b/client/images/flagKit/GG.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GH.svg b/client/images/flagKit/GH.svg
new file mode 100644
index 00000000..528473ff
--- /dev/null
+++ b/client/images/flagKit/GH.svg
@@ -0,0 +1,37 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GI.svg b/client/images/flagKit/GI.svg
new file mode 100644
index 00000000..ecd8530a
--- /dev/null
+++ b/client/images/flagKit/GI.svg
@@ -0,0 +1,38 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GL.svg b/client/images/flagKit/GL.svg
new file mode 100644
index 00000000..33b22333
--- /dev/null
+++ b/client/images/flagKit/GL.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GM.svg b/client/images/flagKit/GM.svg
new file mode 100644
index 00000000..b6330f52
--- /dev/null
+++ b/client/images/flagKit/GM.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GN.svg b/client/images/flagKit/GN.svg
new file mode 100644
index 00000000..2d20595e
--- /dev/null
+++ b/client/images/flagKit/GN.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GP.svg b/client/images/flagKit/GP.svg
new file mode 100644
index 00000000..3dbdcc13
--- /dev/null
+++ b/client/images/flagKit/GP.svg
@@ -0,0 +1,40 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GQ.svg b/client/images/flagKit/GQ.svg
new file mode 100644
index 00000000..e2d5c67d
--- /dev/null
+++ b/client/images/flagKit/GQ.svg
@@ -0,0 +1,34 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GR.svg b/client/images/flagKit/GR.svg
new file mode 100644
index 00000000..a9b12c00
--- /dev/null
+++ b/client/images/flagKit/GR.svg
@@ -0,0 +1,22 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GS.svg b/client/images/flagKit/GS.svg
new file mode 100644
index 00000000..03984521
--- /dev/null
+++ b/client/images/flagKit/GS.svg
@@ -0,0 +1,112 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GT.svg b/client/images/flagKit/GT.svg
new file mode 100644
index 00000000..be45ee89
--- /dev/null
+++ b/client/images/flagKit/GT.svg
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GU.svg b/client/images/flagKit/GU.svg
new file mode 100644
index 00000000..6233a0bb
--- /dev/null
+++ b/client/images/flagKit/GU.svg
@@ -0,0 +1,65 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GW.svg b/client/images/flagKit/GW.svg
new file mode 100644
index 00000000..b09530d4
--- /dev/null
+++ b/client/images/flagKit/GW.svg
@@ -0,0 +1,37 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/GY.svg b/client/images/flagKit/GY.svg
new file mode 100644
index 00000000..e5937c24
--- /dev/null
+++ b/client/images/flagKit/GY.svg
@@ -0,0 +1,42 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/HK.svg b/client/images/flagKit/HK.svg
new file mode 100644
index 00000000..f99b8882
--- /dev/null
+++ b/client/images/flagKit/HK.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/HM.svg b/client/images/flagKit/HM.svg
new file mode 100644
index 00000000..8ef4f346
--- /dev/null
+++ b/client/images/flagKit/HM.svg
@@ -0,0 +1,36 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/HN.svg b/client/images/flagKit/HN.svg
new file mode 100644
index 00000000..50a48cd9
--- /dev/null
+++ b/client/images/flagKit/HN.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/HR.svg b/client/images/flagKit/HR.svg
new file mode 100644
index 00000000..a6cf5daa
--- /dev/null
+++ b/client/images/flagKit/HR.svg
@@ -0,0 +1,35 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/HT.svg b/client/images/flagKit/HT.svg
new file mode 100644
index 00000000..0cd82be1
--- /dev/null
+++ b/client/images/flagKit/HT.svg
@@ -0,0 +1,46 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/HU.svg b/client/images/flagKit/HU.svg
new file mode 100644
index 00000000..795319ea
--- /dev/null
+++ b/client/images/flagKit/HU.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/ID.svg b/client/images/flagKit/ID.svg
new file mode 100644
index 00000000..8101da05
--- /dev/null
+++ b/client/images/flagKit/ID.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/IE.svg b/client/images/flagKit/IE.svg
new file mode 100644
index 00000000..60d9af87
--- /dev/null
+++ b/client/images/flagKit/IE.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/IL.svg b/client/images/flagKit/IL.svg
new file mode 100644
index 00000000..7646f91e
--- /dev/null
+++ b/client/images/flagKit/IL.svg
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/IM.svg b/client/images/flagKit/IM.svg
new file mode 100644
index 00000000..ecc7c12e
--- /dev/null
+++ b/client/images/flagKit/IM.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/IN.svg b/client/images/flagKit/IN.svg
new file mode 100644
index 00000000..3726ceb7
--- /dev/null
+++ b/client/images/flagKit/IN.svg
@@ -0,0 +1,31 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/IO.svg b/client/images/flagKit/IO.svg
new file mode 100644
index 00000000..4d8b5229
--- /dev/null
+++ b/client/images/flagKit/IO.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/IQ.svg b/client/images/flagKit/IQ.svg
new file mode 100644
index 00000000..16c4cf18
--- /dev/null
+++ b/client/images/flagKit/IQ.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/IR.svg b/client/images/flagKit/IR.svg
new file mode 100644
index 00000000..af325017
--- /dev/null
+++ b/client/images/flagKit/IR.svg
@@ -0,0 +1,31 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/IS.svg b/client/images/flagKit/IS.svg
new file mode 100644
index 00000000..385a2bf9
--- /dev/null
+++ b/client/images/flagKit/IS.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/IT.svg b/client/images/flagKit/IT.svg
new file mode 100644
index 00000000..9e76f24c
--- /dev/null
+++ b/client/images/flagKit/IT.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/JE.svg b/client/images/flagKit/JE.svg
new file mode 100644
index 00000000..6663c504
--- /dev/null
+++ b/client/images/flagKit/JE.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/JM.svg b/client/images/flagKit/JM.svg
new file mode 100644
index 00000000..54779e77
--- /dev/null
+++ b/client/images/flagKit/JM.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/JO.svg b/client/images/flagKit/JO.svg
new file mode 100644
index 00000000..b0788e76
--- /dev/null
+++ b/client/images/flagKit/JO.svg
@@ -0,0 +1,34 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/JP.svg b/client/images/flagKit/JP.svg
new file mode 100644
index 00000000..0a655c04
--- /dev/null
+++ b/client/images/flagKit/JP.svg
@@ -0,0 +1,22 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/KE.svg b/client/images/flagKit/KE.svg
new file mode 100644
index 00000000..6c6a6cf6
--- /dev/null
+++ b/client/images/flagKit/KE.svg
@@ -0,0 +1,43 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/KG.svg b/client/images/flagKit/KG.svg
new file mode 100644
index 00000000..12e6a244
--- /dev/null
+++ b/client/images/flagKit/KG.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/KH.svg b/client/images/flagKit/KH.svg
new file mode 100644
index 00000000..9ea454bb
--- /dev/null
+++ b/client/images/flagKit/KH.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/KI.svg b/client/images/flagKit/KI.svg
new file mode 100644
index 00000000..e00e2352
--- /dev/null
+++ b/client/images/flagKit/KI.svg
@@ -0,0 +1,35 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/KM.svg b/client/images/flagKit/KM.svg
new file mode 100644
index 00000000..2da152d5
--- /dev/null
+++ b/client/images/flagKit/KM.svg
@@ -0,0 +1,39 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/KN.svg b/client/images/flagKit/KN.svg
new file mode 100644
index 00000000..e65b7b61
--- /dev/null
+++ b/client/images/flagKit/KN.svg
@@ -0,0 +1,39 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/KP.svg b/client/images/flagKit/KP.svg
new file mode 100644
index 00000000..649feb27
--- /dev/null
+++ b/client/images/flagKit/KP.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/KR.svg b/client/images/flagKit/KR.svg
new file mode 100644
index 00000000..078665a5
--- /dev/null
+++ b/client/images/flagKit/KR.svg
@@ -0,0 +1,38 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/KW.svg b/client/images/flagKit/KW.svg
new file mode 100644
index 00000000..a73b0113
--- /dev/null
+++ b/client/images/flagKit/KW.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/KY.svg b/client/images/flagKit/KY.svg
new file mode 100644
index 00000000..2240dbc6
--- /dev/null
+++ b/client/images/flagKit/KY.svg
@@ -0,0 +1,44 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/KZ.svg b/client/images/flagKit/KZ.svg
new file mode 100644
index 00000000..6076ac54
--- /dev/null
+++ b/client/images/flagKit/KZ.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/LA.svg b/client/images/flagKit/LA.svg
new file mode 100644
index 00000000..5b740da7
--- /dev/null
+++ b/client/images/flagKit/LA.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/LB.svg b/client/images/flagKit/LB.svg
new file mode 100644
index 00000000..401a235d
--- /dev/null
+++ b/client/images/flagKit/LB.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/LC.svg b/client/images/flagKit/LC.svg
new file mode 100644
index 00000000..8d809d3e
--- /dev/null
+++ b/client/images/flagKit/LC.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/LI.svg b/client/images/flagKit/LI.svg
new file mode 100644
index 00000000..1160975a
--- /dev/null
+++ b/client/images/flagKit/LI.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/LICENSE b/client/images/flagKit/LICENSE
new file mode 100644
index 00000000..59f47bf1
--- /dev/null
+++ b/client/images/flagKit/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Bowtie AB
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/client/images/flagKit/LK.svg b/client/images/flagKit/LK.svg
new file mode 100644
index 00000000..55386d5c
--- /dev/null
+++ b/client/images/flagKit/LK.svg
@@ -0,0 +1,43 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/LR.svg b/client/images/flagKit/LR.svg
new file mode 100644
index 00000000..3d6cef1e
--- /dev/null
+++ b/client/images/flagKit/LR.svg
@@ -0,0 +1,36 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/LS.svg b/client/images/flagKit/LS.svg
new file mode 100644
index 00000000..3ec5277d
--- /dev/null
+++ b/client/images/flagKit/LS.svg
@@ -0,0 +1,34 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/LT.svg b/client/images/flagKit/LT.svg
new file mode 100644
index 00000000..8e592267
--- /dev/null
+++ b/client/images/flagKit/LT.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/LU.svg b/client/images/flagKit/LU.svg
new file mode 100644
index 00000000..860e730b
--- /dev/null
+++ b/client/images/flagKit/LU.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/LV.svg b/client/images/flagKit/LV.svg
new file mode 100644
index 00000000..5d0255e6
--- /dev/null
+++ b/client/images/flagKit/LV.svg
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/LY.svg b/client/images/flagKit/LY.svg
new file mode 100644
index 00000000..4b9f2a0e
--- /dev/null
+++ b/client/images/flagKit/LY.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MA.svg b/client/images/flagKit/MA.svg
new file mode 100644
index 00000000..cb22ba95
--- /dev/null
+++ b/client/images/flagKit/MA.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MC.svg b/client/images/flagKit/MC.svg
new file mode 100644
index 00000000..207590a7
--- /dev/null
+++ b/client/images/flagKit/MC.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MD.svg b/client/images/flagKit/MD.svg
new file mode 100644
index 00000000..301e93ee
--- /dev/null
+++ b/client/images/flagKit/MD.svg
@@ -0,0 +1,42 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/ME.svg b/client/images/flagKit/ME.svg
new file mode 100644
index 00000000..9b0838e9
--- /dev/null
+++ b/client/images/flagKit/ME.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MF.svg b/client/images/flagKit/MF.svg
new file mode 100644
index 00000000..c45b62a0
--- /dev/null
+++ b/client/images/flagKit/MF.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MG.svg b/client/images/flagKit/MG.svg
new file mode 100644
index 00000000..c173fdd5
--- /dev/null
+++ b/client/images/flagKit/MG.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MH.svg b/client/images/flagKit/MH.svg
new file mode 100644
index 00000000..e6b66091
--- /dev/null
+++ b/client/images/flagKit/MH.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MK.svg b/client/images/flagKit/MK.svg
new file mode 100644
index 00000000..35b92297
--- /dev/null
+++ b/client/images/flagKit/MK.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/ML.svg b/client/images/flagKit/ML.svg
new file mode 100644
index 00000000..babc6e59
--- /dev/null
+++ b/client/images/flagKit/ML.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MM.svg b/client/images/flagKit/MM.svg
new file mode 100644
index 00000000..eb3c18a3
--- /dev/null
+++ b/client/images/flagKit/MM.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MN.svg b/client/images/flagKit/MN.svg
new file mode 100644
index 00000000..8af15a51
--- /dev/null
+++ b/client/images/flagKit/MN.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MO.svg b/client/images/flagKit/MO.svg
new file mode 100644
index 00000000..be4bc875
--- /dev/null
+++ b/client/images/flagKit/MO.svg
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MP.svg b/client/images/flagKit/MP.svg
new file mode 100644
index 00000000..33151489
--- /dev/null
+++ b/client/images/flagKit/MP.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MQ.svg b/client/images/flagKit/MQ.svg
new file mode 100644
index 00000000..adc82074
--- /dev/null
+++ b/client/images/flagKit/MQ.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MR.svg b/client/images/flagKit/MR.svg
new file mode 100644
index 00000000..da5adee6
--- /dev/null
+++ b/client/images/flagKit/MR.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MS.svg b/client/images/flagKit/MS.svg
new file mode 100644
index 00000000..184c9178
--- /dev/null
+++ b/client/images/flagKit/MS.svg
@@ -0,0 +1,47 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MT.svg b/client/images/flagKit/MT.svg
new file mode 100644
index 00000000..5ce0b3fe
--- /dev/null
+++ b/client/images/flagKit/MT.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MU.svg b/client/images/flagKit/MU.svg
new file mode 100644
index 00000000..f2c6f3f8
--- /dev/null
+++ b/client/images/flagKit/MU.svg
@@ -0,0 +1,37 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MV.svg b/client/images/flagKit/MV.svg
new file mode 100644
index 00000000..f10e07d5
--- /dev/null
+++ b/client/images/flagKit/MV.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MW.svg b/client/images/flagKit/MW.svg
new file mode 100644
index 00000000..5b0cc5c6
--- /dev/null
+++ b/client/images/flagKit/MW.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MX.svg b/client/images/flagKit/MX.svg
new file mode 100644
index 00000000..7ed245bc
--- /dev/null
+++ b/client/images/flagKit/MX.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MY.svg b/client/images/flagKit/MY.svg
new file mode 100644
index 00000000..e7ff885f
--- /dev/null
+++ b/client/images/flagKit/MY.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/MZ.svg b/client/images/flagKit/MZ.svg
new file mode 100644
index 00000000..7f553b00
--- /dev/null
+++ b/client/images/flagKit/MZ.svg
@@ -0,0 +1,43 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NA.svg b/client/images/flagKit/NA.svg
new file mode 100644
index 00000000..cb0ba69f
--- /dev/null
+++ b/client/images/flagKit/NA.svg
@@ -0,0 +1,75 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NC.svg b/client/images/flagKit/NC.svg
new file mode 100644
index 00000000..bae580e8
--- /dev/null
+++ b/client/images/flagKit/NC.svg
@@ -0,0 +1,42 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NE.svg b/client/images/flagKit/NE.svg
new file mode 100644
index 00000000..12bcf8a0
--- /dev/null
+++ b/client/images/flagKit/NE.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NF.svg b/client/images/flagKit/NF.svg
new file mode 100644
index 00000000..b707e52d
--- /dev/null
+++ b/client/images/flagKit/NF.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NG.svg b/client/images/flagKit/NG.svg
new file mode 100644
index 00000000..4063ff84
--- /dev/null
+++ b/client/images/flagKit/NG.svg
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NI.svg b/client/images/flagKit/NI.svg
new file mode 100644
index 00000000..7adb4ba4
--- /dev/null
+++ b/client/images/flagKit/NI.svg
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NL.svg b/client/images/flagKit/NL.svg
new file mode 100644
index 00000000..c62f42ad
--- /dev/null
+++ b/client/images/flagKit/NL.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NO.svg b/client/images/flagKit/NO.svg
new file mode 100644
index 00000000..cdc23f49
--- /dev/null
+++ b/client/images/flagKit/NO.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NP.svg b/client/images/flagKit/NP.svg
new file mode 100644
index 00000000..c879fa80
--- /dev/null
+++ b/client/images/flagKit/NP.svg
@@ -0,0 +1,35 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NR.svg b/client/images/flagKit/NR.svg
new file mode 100644
index 00000000..1a6c3a21
--- /dev/null
+++ b/client/images/flagKit/NR.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NU.svg b/client/images/flagKit/NU.svg
new file mode 100644
index 00000000..3d9bc80c
--- /dev/null
+++ b/client/images/flagKit/NU.svg
@@ -0,0 +1,41 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/NZ.svg b/client/images/flagKit/NZ.svg
new file mode 100644
index 00000000..c1f624df
--- /dev/null
+++ b/client/images/flagKit/NZ.svg
@@ -0,0 +1,34 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/OM.svg b/client/images/flagKit/OM.svg
new file mode 100644
index 00000000..cb08ac82
--- /dev/null
+++ b/client/images/flagKit/OM.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PA.svg b/client/images/flagKit/PA.svg
new file mode 100644
index 00000000..d8516682
--- /dev/null
+++ b/client/images/flagKit/PA.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PE.svg b/client/images/flagKit/PE.svg
new file mode 100644
index 00000000..98a26cf2
--- /dev/null
+++ b/client/images/flagKit/PE.svg
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PF.svg b/client/images/flagKit/PF.svg
new file mode 100644
index 00000000..b29385f4
--- /dev/null
+++ b/client/images/flagKit/PF.svg
@@ -0,0 +1,52 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PG.svg b/client/images/flagKit/PG.svg
new file mode 100644
index 00000000..0630fab6
--- /dev/null
+++ b/client/images/flagKit/PG.svg
@@ -0,0 +1,36 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PH.svg b/client/images/flagKit/PH.svg
new file mode 100644
index 00000000..4c1087b8
--- /dev/null
+++ b/client/images/flagKit/PH.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PK.svg b/client/images/flagKit/PK.svg
new file mode 100644
index 00000000..7ecb09cf
--- /dev/null
+++ b/client/images/flagKit/PK.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PL.svg b/client/images/flagKit/PL.svg
new file mode 100644
index 00000000..fadbd2d6
--- /dev/null
+++ b/client/images/flagKit/PL.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PM.svg b/client/images/flagKit/PM.svg
new file mode 100644
index 00000000..1f39fd0a
--- /dev/null
+++ b/client/images/flagKit/PM.svg
@@ -0,0 +1,66 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PN.svg b/client/images/flagKit/PN.svg
new file mode 100644
index 00000000..f2b2cc4f
--- /dev/null
+++ b/client/images/flagKit/PN.svg
@@ -0,0 +1,51 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PR.svg b/client/images/flagKit/PR.svg
new file mode 100644
index 00000000..7d120445
--- /dev/null
+++ b/client/images/flagKit/PR.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PS.svg b/client/images/flagKit/PS.svg
new file mode 100644
index 00000000..e68583ba
--- /dev/null
+++ b/client/images/flagKit/PS.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PT.svg b/client/images/flagKit/PT.svg
new file mode 100644
index 00000000..49b59be2
--- /dev/null
+++ b/client/images/flagKit/PT.svg
@@ -0,0 +1,38 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PW.svg b/client/images/flagKit/PW.svg
new file mode 100644
index 00000000..4ab7f166
--- /dev/null
+++ b/client/images/flagKit/PW.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/PY.svg b/client/images/flagKit/PY.svg
new file mode 100644
index 00000000..2ae00546
--- /dev/null
+++ b/client/images/flagKit/PY.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/QA.svg b/client/images/flagKit/QA.svg
new file mode 100644
index 00000000..985171d1
--- /dev/null
+++ b/client/images/flagKit/QA.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/RE.svg b/client/images/flagKit/RE.svg
new file mode 100644
index 00000000..7e130938
--- /dev/null
+++ b/client/images/flagKit/RE.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/RO.svg b/client/images/flagKit/RO.svg
new file mode 100644
index 00000000..dd82b266
--- /dev/null
+++ b/client/images/flagKit/RO.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/RS.svg b/client/images/flagKit/RS.svg
new file mode 100644
index 00000000..892dd5e4
--- /dev/null
+++ b/client/images/flagKit/RS.svg
@@ -0,0 +1,39 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/RU.svg b/client/images/flagKit/RU.svg
new file mode 100644
index 00000000..a9ba65b5
--- /dev/null
+++ b/client/images/flagKit/RU.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/RW.svg b/client/images/flagKit/RW.svg
new file mode 100644
index 00000000..43b26156
--- /dev/null
+++ b/client/images/flagKit/RW.svg
@@ -0,0 +1,37 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SA.svg b/client/images/flagKit/SA.svg
new file mode 100644
index 00000000..735b986f
--- /dev/null
+++ b/client/images/flagKit/SA.svg
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SB.svg b/client/images/flagKit/SB.svg
new file mode 100644
index 00000000..768c45c0
--- /dev/null
+++ b/client/images/flagKit/SB.svg
@@ -0,0 +1,39 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SC.svg b/client/images/flagKit/SC.svg
new file mode 100644
index 00000000..62b380b8
--- /dev/null
+++ b/client/images/flagKit/SC.svg
@@ -0,0 +1,43 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SD.svg b/client/images/flagKit/SD.svg
new file mode 100644
index 00000000..c68d6b1b
--- /dev/null
+++ b/client/images/flagKit/SD.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SE.svg b/client/images/flagKit/SE.svg
new file mode 100644
index 00000000..bb4f4e11
--- /dev/null
+++ b/client/images/flagKit/SE.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SG.svg b/client/images/flagKit/SG.svg
new file mode 100644
index 00000000..27011483
--- /dev/null
+++ b/client/images/flagKit/SG.svg
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SH.svg b/client/images/flagKit/SH.svg
new file mode 100644
index 00000000..e0dde764
--- /dev/null
+++ b/client/images/flagKit/SH.svg
@@ -0,0 +1,53 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SI.svg b/client/images/flagKit/SI.svg
new file mode 100644
index 00000000..497f8705
--- /dev/null
+++ b/client/images/flagKit/SI.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SJ.svg b/client/images/flagKit/SJ.svg
new file mode 100644
index 00000000..bef7e505
--- /dev/null
+++ b/client/images/flagKit/SJ.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SK.svg b/client/images/flagKit/SK.svg
new file mode 100644
index 00000000..2b8ba801
--- /dev/null
+++ b/client/images/flagKit/SK.svg
@@ -0,0 +1,46 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SL.svg b/client/images/flagKit/SL.svg
new file mode 100644
index 00000000..817419ef
--- /dev/null
+++ b/client/images/flagKit/SL.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SM.svg b/client/images/flagKit/SM.svg
new file mode 100644
index 00000000..abf62171
--- /dev/null
+++ b/client/images/flagKit/SM.svg
@@ -0,0 +1,25 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SN.svg b/client/images/flagKit/SN.svg
new file mode 100644
index 00000000..09484160
--- /dev/null
+++ b/client/images/flagKit/SN.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SO.svg b/client/images/flagKit/SO.svg
new file mode 100644
index 00000000..6372e377
--- /dev/null
+++ b/client/images/flagKit/SO.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SR.svg b/client/images/flagKit/SR.svg
new file mode 100644
index 00000000..97963b0c
--- /dev/null
+++ b/client/images/flagKit/SR.svg
@@ -0,0 +1,34 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SS.svg b/client/images/flagKit/SS.svg
new file mode 100644
index 00000000..e8d68dd0
--- /dev/null
+++ b/client/images/flagKit/SS.svg
@@ -0,0 +1,44 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/ST.svg b/client/images/flagKit/ST.svg
new file mode 100644
index 00000000..4b355d71
--- /dev/null
+++ b/client/images/flagKit/ST.svg
@@ -0,0 +1,39 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SV.svg b/client/images/flagKit/SV.svg
new file mode 100644
index 00000000..9bfdd5ce
--- /dev/null
+++ b/client/images/flagKit/SV.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SX.svg b/client/images/flagKit/SX.svg
new file mode 100644
index 00000000..ccefe037
--- /dev/null
+++ b/client/images/flagKit/SX.svg
@@ -0,0 +1,45 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SY.svg b/client/images/flagKit/SY.svg
new file mode 100644
index 00000000..040530b6
--- /dev/null
+++ b/client/images/flagKit/SY.svg
@@ -0,0 +1,34 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/SZ.svg b/client/images/flagKit/SZ.svg
new file mode 100644
index 00000000..fc4120de
--- /dev/null
+++ b/client/images/flagKit/SZ.svg
@@ -0,0 +1,47 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TC.svg b/client/images/flagKit/TC.svg
new file mode 100644
index 00000000..c3ea149a
--- /dev/null
+++ b/client/images/flagKit/TC.svg
@@ -0,0 +1,40 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TD.svg b/client/images/flagKit/TD.svg
new file mode 100644
index 00000000..74756faf
--- /dev/null
+++ b/client/images/flagKit/TD.svg
@@ -0,0 +1,32 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TF.svg b/client/images/flagKit/TF.svg
new file mode 100644
index 00000000..d1ea6918
--- /dev/null
+++ b/client/images/flagKit/TF.svg
@@ -0,0 +1,35 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TG.svg b/client/images/flagKit/TG.svg
new file mode 100644
index 00000000..e9f6360f
--- /dev/null
+++ b/client/images/flagKit/TG.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TH.svg b/client/images/flagKit/TH.svg
new file mode 100644
index 00000000..1bf403a2
--- /dev/null
+++ b/client/images/flagKit/TH.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TJ.svg b/client/images/flagKit/TJ.svg
new file mode 100644
index 00000000..77d6728b
--- /dev/null
+++ b/client/images/flagKit/TJ.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TK.svg b/client/images/flagKit/TK.svg
new file mode 100644
index 00000000..3cde9608
--- /dev/null
+++ b/client/images/flagKit/TK.svg
@@ -0,0 +1,31 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TL.svg b/client/images/flagKit/TL.svg
new file mode 100644
index 00000000..41b89521
--- /dev/null
+++ b/client/images/flagKit/TL.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TM.svg b/client/images/flagKit/TM.svg
new file mode 100644
index 00000000..dac62a13
--- /dev/null
+++ b/client/images/flagKit/TM.svg
@@ -0,0 +1,74 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TN.svg b/client/images/flagKit/TN.svg
new file mode 100644
index 00000000..3ff74a9e
--- /dev/null
+++ b/client/images/flagKit/TN.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TO.svg b/client/images/flagKit/TO.svg
new file mode 100644
index 00000000..e0e42ee2
--- /dev/null
+++ b/client/images/flagKit/TO.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TR.svg b/client/images/flagKit/TR.svg
new file mode 100644
index 00000000..e5c0924d
--- /dev/null
+++ b/client/images/flagKit/TR.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TT.svg b/client/images/flagKit/TT.svg
new file mode 100644
index 00000000..69bdb9a9
--- /dev/null
+++ b/client/images/flagKit/TT.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TV.svg b/client/images/flagKit/TV.svg
new file mode 100644
index 00000000..839c97f1
--- /dev/null
+++ b/client/images/flagKit/TV.svg
@@ -0,0 +1,36 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TW.svg b/client/images/flagKit/TW.svg
new file mode 100644
index 00000000..488d1120
--- /dev/null
+++ b/client/images/flagKit/TW.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/TZ.svg b/client/images/flagKit/TZ.svg
new file mode 100644
index 00000000..d652e211
--- /dev/null
+++ b/client/images/flagKit/TZ.svg
@@ -0,0 +1,37 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/UA.svg b/client/images/flagKit/UA.svg
new file mode 100644
index 00000000..8dac8366
--- /dev/null
+++ b/client/images/flagKit/UA.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/UG.svg b/client/images/flagKit/UG.svg
new file mode 100644
index 00000000..7fabd77c
--- /dev/null
+++ b/client/images/flagKit/UG.svg
@@ -0,0 +1,37 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/UM.svg b/client/images/flagKit/UM.svg
new file mode 100644
index 00000000..1a8fc6a7
--- /dev/null
+++ b/client/images/flagKit/UM.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/US.svg b/client/images/flagKit/US.svg
new file mode 100644
index 00000000..846ec9d2
--- /dev/null
+++ b/client/images/flagKit/US.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/UY.svg b/client/images/flagKit/UY.svg
new file mode 100644
index 00000000..81c28154
--- /dev/null
+++ b/client/images/flagKit/UY.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/UZ.svg b/client/images/flagKit/UZ.svg
new file mode 100644
index 00000000..f6cf2140
--- /dev/null
+++ b/client/images/flagKit/UZ.svg
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/VA.svg b/client/images/flagKit/VA.svg
new file mode 100644
index 00000000..14c78aaa
--- /dev/null
+++ b/client/images/flagKit/VA.svg
@@ -0,0 +1,39 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/VC.svg b/client/images/flagKit/VC.svg
new file mode 100644
index 00000000..22cc1d53
--- /dev/null
+++ b/client/images/flagKit/VC.svg
@@ -0,0 +1,37 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/VE.svg b/client/images/flagKit/VE.svg
new file mode 100644
index 00000000..1a14634f
--- /dev/null
+++ b/client/images/flagKit/VE.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/VG.svg b/client/images/flagKit/VG.svg
new file mode 100644
index 00000000..c3c31ed1
--- /dev/null
+++ b/client/images/flagKit/VG.svg
@@ -0,0 +1,42 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/VI.svg b/client/images/flagKit/VI.svg
new file mode 100644
index 00000000..071cf62c
--- /dev/null
+++ b/client/images/flagKit/VI.svg
@@ -0,0 +1,49 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/VN.svg b/client/images/flagKit/VN.svg
new file mode 100644
index 00000000..2bb79564
--- /dev/null
+++ b/client/images/flagKit/VN.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/VU.svg b/client/images/flagKit/VU.svg
new file mode 100644
index 00000000..26e02981
--- /dev/null
+++ b/client/images/flagKit/VU.svg
@@ -0,0 +1,38 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/WF.svg b/client/images/flagKit/WF.svg
new file mode 100644
index 00000000..26a5e414
--- /dev/null
+++ b/client/images/flagKit/WF.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/WS.svg b/client/images/flagKit/WS.svg
new file mode 100644
index 00000000..756c78f5
--- /dev/null
+++ b/client/images/flagKit/WS.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/XK.svg b/client/images/flagKit/XK.svg
new file mode 100644
index 00000000..a9c245fd
--- /dev/null
+++ b/client/images/flagKit/XK.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/YE.svg b/client/images/flagKit/YE.svg
new file mode 100644
index 00000000..535406f9
--- /dev/null
+++ b/client/images/flagKit/YE.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/YT.svg b/client/images/flagKit/YT.svg
new file mode 100644
index 00000000..be67985d
--- /dev/null
+++ b/client/images/flagKit/YT.svg
@@ -0,0 +1,77 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/ZA.svg b/client/images/flagKit/ZA.svg
new file mode 100644
index 00000000..f3ad3726
--- /dev/null
+++ b/client/images/flagKit/ZA.svg
@@ -0,0 +1,44 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/ZM.svg b/client/images/flagKit/ZM.svg
new file mode 100644
index 00000000..3e6f42a8
--- /dev/null
+++ b/client/images/flagKit/ZM.svg
@@ -0,0 +1,42 @@
+
+
\ No newline at end of file
diff --git a/client/images/flagKit/ZW.svg b/client/images/flagKit/ZW.svg
new file mode 100644
index 00000000..dfaf1f3f
--- /dev/null
+++ b/client/images/flagKit/ZW.svg
@@ -0,0 +1,43 @@
+
+
\ No newline at end of file
diff --git a/client/images/folder.png b/client/images/folder.png
deleted file mode 100644
index 07407596..00000000
Binary files a/client/images/folder.png and /dev/null differ
diff --git a/client/images/icon_src.png b/client/images/icon_src.png
deleted file mode 100644
index 1201a89a..00000000
Binary files a/client/images/icon_src.png and /dev/null differ
diff --git a/client/images/icon_src.svg b/client/images/icon_src.svg
deleted file mode 100644
index b27d1360..00000000
--- a/client/images/icon_src.svg
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
-
diff --git a/client/images/settings.png b/client/images/settings.png
deleted file mode 100644
index a64c6116..00000000
Binary files a/client/images/settings.png and /dev/null differ
diff --git a/client/images/settings_grey.png b/client/images/settings_grey.png
deleted file mode 100644
index 60127b5c..00000000
Binary files a/client/images/settings_grey.png and /dev/null differ
diff --git a/client/images/share.png b/client/images/share.png
deleted file mode 100644
index e1451e06..00000000
Binary files a/client/images/share.png and /dev/null differ
diff --git a/client/images/svg/close_black_24dp.svg b/client/images/svg/close_black_24dp.svg
deleted file mode 100644
index 5f1267d7..00000000
--- a/client/images/svg/close_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/control_point_black_24dp.svg b/client/images/svg/control_point_black_24dp.svg
deleted file mode 100644
index 75b25e67..00000000
--- a/client/images/svg/control_point_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/delete_black_24dp.svg b/client/images/svg/delete_black_24dp.svg
deleted file mode 100644
index 69a68354..00000000
--- a/client/images/svg/delete_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/density_small_black_24dp.svg b/client/images/svg/density_small_black_24dp.svg
deleted file mode 100644
index f79483de..00000000
--- a/client/images/svg/density_small_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/done_black_24dp.svg b/client/images/svg/done_black_24dp.svg
deleted file mode 100644
index b7e19d35..00000000
--- a/client/images/svg/done_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/format_list_bulleted_black_24dp.svg b/client/images/svg/format_list_bulleted_black_24dp.svg
deleted file mode 100644
index 21821a14..00000000
--- a/client/images/svg/format_list_bulleted_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/gpp_good_black_24dp.svg b/client/images/svg/gpp_good_black_24dp.svg
deleted file mode 100644
index 45d4a819..00000000
--- a/client/images/svg/gpp_good_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/gpp_maybe_black_24dp.svg b/client/images/svg/gpp_maybe_black_24dp.svg
deleted file mode 100644
index dceeac79..00000000
--- a/client/images/svg/gpp_maybe_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/logout_black_24dp.svg b/client/images/svg/logout_black_24dp.svg
deleted file mode 100644
index 1b785f84..00000000
--- a/client/images/svg/logout_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/miscellaneous_services_black_24dp.svg b/client/images/svg/miscellaneous_services_black_24dp.svg
deleted file mode 100644
index 425990e5..00000000
--- a/client/images/svg/miscellaneous_services_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/refresh_black_24dp.svg b/client/images/svg/refresh_black_24dp.svg
deleted file mode 100644
index f31411f5..00000000
--- a/client/images/svg/refresh_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/settings_black_24dp.svg b/client/images/svg/settings_black_24dp.svg
deleted file mode 100644
index 4165162b..00000000
--- a/client/images/svg/settings_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/settings_suggest_black_24dp.svg b/client/images/svg/settings_suggest_black_24dp.svg
deleted file mode 100644
index 80053d0e..00000000
--- a/client/images/svg/settings_suggest_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/share_black_24dp.svg b/client/images/svg/share_black_24dp.svg
deleted file mode 100644
index 4c5fa323..00000000
--- a/client/images/svg/share_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/svg/vpn_key_black_24dp.svg b/client/images/svg/vpn_key_black_24dp.svg
deleted file mode 100644
index 2c18df46..00000000
--- a/client/images/svg/vpn_key_black_24dp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/images/uncheck.png b/client/images/uncheck.png
deleted file mode 100644
index b6723a44..00000000
Binary files a/client/images/uncheck.png and /dev/null differ
diff --git a/client/images/upload.png b/client/images/upload.png
deleted file mode 100644
index 185e7a7b..00000000
Binary files a/client/images/upload.png and /dev/null differ
diff --git a/client/logger.h b/client/logger.h
deleted file mode 100644
index 0dcbd35c..00000000
--- a/client/logger.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef LOGGER_H
-#define LOGGER_H
-
-#include
-#include
-#include
-#include
-#include
-
-#include "ui/property_helper.h"
-
-#include "mozilla/shared/loglevel.h"
-
-class Logger : public QObject
-{
- Q_OBJECT
- AUTO_PROPERTY(QString, sshLog)
- AUTO_PROPERTY(QString, allLog)
-
-public:
- static Logger& Instance();
-
- static void appendSshLog(const QString &log);
- static void appendAllLog(const QString &log);
-
-
- static bool init();
- static void deInit();
- static bool setServiceLogsEnabled(bool enabled);
- static bool openLogsFolder();
- static bool openServiceLogsFolder();
- static QString appLogFileNamePath();
- static void clearLogs();
- static void clearServiceLogs();
- static void cleanUp();
-
- static QString userLogsFilePath();
- static QString getLogFile();
-
- // compat with Mozilla logger
- Logger(const QString &className) { m_className = className; }
- const QString& className() const { return m_className; }
-
- class Log {
- public:
- Log(Logger* logger, LogLevel level);
- ~Log();
-
- Log& operator<<(uint64_t t);
- Log& operator<<(const char* t);
- Log& operator<<(const QString& t);
- Log& operator<<(const QStringList& t);
- Log& operator<<(const QByteArray& t);
- Log& operator<<(const QJsonObject& t);
- Log& operator<<(QTextStreamFunction t);
- Log& operator<<(const void* t);
-
- // Q_ENUM
- template
- typename std::enable_if::Value, Log&>::type
- operator<<(T t) {
- const QMetaObject* meta = qt_getEnumMetaObject(t);
- const char* name = qt_getEnumName(t);
- addMetaEnum(typename QFlags::Int(t), meta, name);
- return *this;
- }
-
- private:
- void addMetaEnum(quint64 value, const QMetaObject* meta, const char* name);
-
- Logger* m_logger;
- LogLevel m_logLevel;
-
- struct Data {
- Data() : m_ts(&m_buffer, QIODevice::WriteOnly) {}
-
- QString m_buffer;
- QTextStream m_ts;
- };
-
- Data* m_data;
- };
-
- Log error();
- Log warning();
- Log info();
- Log debug();
- QString sensitive(const QString& input);
-
-private:
- Logger() {}
- Logger(Logger const &) = delete;
- Logger& operator= (Logger const&) = delete;
-
- static QString userLogsDir();
-
- static QFile m_file;
- static QTextStream m_textStream;
- static QString m_logFileName;
-
- friend void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
-
- // compat with Mozilla logger
- QString m_className;
-};
-
-#endif // LOGGER_H
diff --git a/client/main.cpp b/client/main.cpp
index 3a719096..aca9e62b 100644
--- a/client/main.cpp
+++ b/client/main.cpp
@@ -15,13 +15,24 @@
#include "platforms/ios/QtAppDelegate-C-Interface.h"
#endif
+#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
+bool isAnotherInstanceRunning()
+{
+ QLocalSocket socket;
+ socket.connectToServer("AmneziaVPNInstance");
+ if (socket.waitForConnected(500)) {
+ qWarning() << "AmneziaVPN is already running";
+ return true;
+ }
+ return false;
+}
+#endif
+
int main(int argc, char *argv[])
{
Migrations migrationsManager;
migrationsManager.doMigrations();
- QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
-
#ifdef Q_OS_WIN
AllowSetForegroundWindow(ASFW_ANY);
#endif
@@ -32,16 +43,14 @@ int main(int argc, char *argv[])
qputenv("ANDROID_OPENSSL_SUFFIX", "_3");
#endif
-#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()) {
+#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
+ if (isAnotherInstanceRunning()) {
QTimer::singleShot(1000, &app, [&]() { app.quit(); });
return app.exec();
}
+ app.startLocalServer();
#endif
// Allow to raise app window if secondary instance launched
diff --git a/client/mozilla/localsocketcontroller.cpp b/client/mozilla/localsocketcontroller.cpp
index 0502facc..4d040288 100644
--- a/client/mozilla/localsocketcontroller.cpp
+++ b/client/mozilla/localsocketcontroller.cpp
@@ -149,7 +149,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
QJsonArray jsAllowedIPAddesses;
QJsonArray plainAllowedIP = wgConfig.value(amnezia::config_key::allowed_ips).toArray();
- QJsonArray defaultAllowedIP = QJsonArray::fromStringList(QString("0.0.0.0/0, ::/0").split(","));
+ QJsonArray defaultAllowedIP = { "0.0.0.0/0", "::/0" };
if (plainAllowedIP != defaultAllowedIP && !plainAllowedIP.isEmpty()) {
// Use AllowedIP list from WG config because of higher priority
diff --git a/client/platforms/android/android_controller.cpp b/client/platforms/android/android_controller.cpp
index c9ee3cfd..2790eb1b 100644
--- a/client/platforms/android/android_controller.cpp
+++ b/client/platforms/android/android_controller.cpp
@@ -98,6 +98,7 @@ bool AndroidController::initialize()
{"onStatisticsUpdate", "(JJ)V", reinterpret_cast(onStatisticsUpdate)},
{"onFileOpened", "(Ljava/lang/String;)V", reinterpret_cast(onFileOpened)},
{"onConfigImported", "(Ljava/lang/String;)V", reinterpret_cast(onConfigImported)},
+ {"onAuthResult", "(Z)V", reinterpret_cast(onAuthResult)},
{"decodeQrCode", "(Ljava/lang/String;)Z", reinterpret_cast(decodeQrCode)}
};
@@ -210,6 +211,11 @@ void AndroidController::setScreenshotsEnabled(bool enabled)
callActivityMethod("setScreenshotsEnabled", "(Z)V", enabled);
}
+void AndroidController::setNavigationBarColor(unsigned int color)
+{
+ callActivityMethod("setNavigationBarColor", "(I)V", color);
+}
+
void AndroidController::minimizeApp()
{
callActivityMethod("minimizeApp", "()V");
@@ -265,6 +271,22 @@ void AndroidController::requestNotificationPermission()
callActivityMethod("requestNotificationPermission", "()V");
}
+bool AndroidController::requestAuthentication()
+{
+ QEventLoop wait;
+ bool result;
+ connect(this, &AndroidController::authenticationResult, this,
+ [&result, &wait](const bool &authResult){
+ qDebug() << "Android authentication result:" << authResult;
+ result = authResult;
+ wait.quit();
+ },
+ static_cast(Qt::QueuedConnection | Qt::SingleShotConnection));
+ callActivityMethod("requestAuthentication", "()V");
+ wait.exec();
+ return result;
+}
+
// Moving log processing to the Android side
jclass AndroidController::log;
jmethodID AndroidController::logDebug;
@@ -462,6 +484,14 @@ void AndroidController::onConfigImported(JNIEnv *env, jobject thiz, jstring data
emit AndroidController::instance()->configImported(AndroidUtils::convertJString(env, data));
}
+// static
+void AndroidController::onAuthResult(JNIEnv *env, jobject thiz, jboolean result)
+{
+ Q_UNUSED(thiz);
+
+ emit AndroidController::instance()->authenticationResult(result);
+}
+
// static
bool AndroidController::decodeQrCode(JNIEnv *env, jobject thiz, jstring data)
{
diff --git a/client/platforms/android/android_controller.h b/client/platforms/android/android_controller.h
index 1041c31f..759c9c3f 100644
--- a/client/platforms/android/android_controller.h
+++ b/client/platforms/android/android_controller.h
@@ -41,11 +41,13 @@ public:
void exportLogsFile(const QString &fileName);
void clearLogs();
void setScreenshotsEnabled(bool enabled);
+ void setNavigationBarColor(unsigned int color);
void minimizeApp();
QJsonArray getAppList();
QPixmap getAppIcon(const QString &package, QSize *size, const QSize &requestedSize);
bool isNotificationPermissionGranted();
void requestNotificationPermission();
+ bool requestAuthentication();
static bool initLogging();
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message);
@@ -63,6 +65,7 @@ signals:
void configImported(QString config);
void importConfigFromOutside(QString config);
void initConnectionState(Vpn::ConnectionState state);
+ void authenticationResult(bool result);
private:
bool isWaitingStatus = true;
@@ -89,6 +92,7 @@ private:
static void onStatisticsUpdate(JNIEnv *env, jobject thiz, jlong rxBytes, jlong txBytes);
static void onConfigImported(JNIEnv *env, jobject thiz, jstring data);
static void onFileOpened(JNIEnv *env, jobject thiz, jstring uri);
+ static void onAuthResult(JNIEnv *env, jobject thiz, jboolean result);
static bool decodeQrCode(JNIEnv *env, jobject thiz, jstring data);
template
diff --git a/client/platforms/android/authResultReceiver.cpp b/client/platforms/android/authResultReceiver.cpp
deleted file mode 100644
index 21e838a2..00000000
--- a/client/platforms/android/authResultReceiver.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "authResultReceiver.h"
-
-AuthResultReceiver::AuthResultReceiver(QSharedPointer ¬ifier) : m_notifier(notifier)
-{
-}
-
-void AuthResultReceiver::handleActivityResult(int receiverRequestCode, int resultCode, const QJniObject &data)
-{
- qDebug() << "receiverRequestCode" << receiverRequestCode << "resultCode" << resultCode;
-
- if (resultCode == -1) { // ResultOK
- emit m_notifier->authSuccessful();
- } else {
- emit m_notifier->authFailed();
- }
-}
diff --git a/client/platforms/android/authResultReceiver.h b/client/platforms/android/authResultReceiver.h
deleted file mode 100644
index 9a88dcf5..00000000
--- a/client/platforms/android/authResultReceiver.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef AUTHRESULTRECEIVER_H
-#define AUTHRESULTRECEIVER_H
-
-#include
-
-#include
-
-class AuthResultNotifier : public QObject
-{
- Q_OBJECT
-
-public:
- AuthResultNotifier(QObject *parent = nullptr) : QObject(parent) {};
-
-signals:
- void authFailed();
- void authSuccessful();
-};
-
-/* Auth result handler for Android */
-class AuthResultReceiver final : public QAndroidActivityResultReceiver
-{
-public:
- AuthResultReceiver(QSharedPointer ¬ifier);
-
- void handleActivityResult(int receiverRequestCode, int resultCode, const QJniObject &data) override;
-
-private:
- QSharedPointer m_notifier;
-};
-
-#endif // AUTHRESULTRECEIVER_H
diff --git a/client/platforms/ios/ios_controller.mm b/client/platforms/ios/ios_controller.mm
index f4ba2798..85fb50b7 100644
--- a/client/platforms/ios/ios_controller.mm
+++ b/client/platforms/ios/ios_controller.mm
@@ -351,8 +351,6 @@ void IosController::vpnStatusDidChange(void *pNotification)
}
}
}
- } else {
- qDebug() << "Disconnect error is absent";
}
}];
} else {
@@ -501,6 +499,20 @@ bool IosController::setupWireGuard()
wgConfig.insert(config_key::persistent_keep_alive, "25");
}
+ if (config.contains(config_key::isObfuscationEnabled) && config.value(config_key::isObfuscationEnabled).toBool()) {
+ wgConfig.insert(config_key::initPacketMagicHeader, config[config_key::initPacketMagicHeader]);
+ wgConfig.insert(config_key::responsePacketMagicHeader, config[config_key::responsePacketMagicHeader]);
+ wgConfig.insert(config_key::underloadPacketMagicHeader, config[config_key::underloadPacketMagicHeader]);
+ wgConfig.insert(config_key::transportPacketMagicHeader, config[config_key::transportPacketMagicHeader]);
+
+ wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
+ wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
+
+ wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
+ wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
+ wgConfig.insert(config_key::junkPacketMaxSize, config[config_key::junkPacketMaxSize]);
+ }
+
QJsonDocument wgConfigDoc(wgConfig);
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
@@ -835,7 +847,7 @@ QString IosController::openFile() {
void IosController::requestInetAccess() {
NSURL *url = [NSURL URLWithString:@"http://captive.apple.com/generate_204"];
- if (url) {
+ if (!url) {
qDebug() << "IosController::requestInetAccess URL error";
return;
}
@@ -847,7 +859,6 @@ void IosController::requestInetAccess() {
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
QString responseBody = QString::fromUtf8((const char*)data.bytes, data.length);
- qDebug() << "IosController::requestInetAccess server response:" << httpResponse.statusCode << "\n\n" <setAutoRemove(false);
+ certFile->open();
+ QString m_filename = certFile->fileName();
+ certFile->write(cert);
+ certFile->close();
+ delete certFile;
{
auto certInstallProcess = IpcClient::CreatePrivilegedProcess();
@@ -193,19 +196,19 @@ ErrorCode Ikev2Protocol::start()
return ErrorCode::AmneziaServiceConnectionFailed;
}
- certInstallProcess->waitForSource(1000);
+ certInstallProcess->waitForSource();
if (!certInstallProcess->isInitialized()) {
qWarning() << "IpcProcess replica is not connected!";
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return ErrorCode::AmneziaServiceConnectionFailed;
}
certInstallProcess->setProgram(PermittedProcess::CertUtil);
- QStringList arguments({"-f" , "-importpfx",
- "-p", m_config[config_key::password].toString(),
- certFile.fileName(), "NoExport"
- });
- certInstallProcess->setArguments(arguments);
+ QStringList arguments({"-f", "-importpfx", "-p", m_config[config_key::password].toString(),
+ QDir::toNativeSeparators(m_filename), "NoExport"
+ });
+
+ certInstallProcess->setArguments(arguments);
certInstallProcess->start();
}
// /*
@@ -219,40 +222,40 @@ ErrorCode Ikev2Protocol::start()
}
{
- {
- if ( !create_new_vpn(tunnelName(), m_config[config_key::hostName].toString())){
- qDebug() <<"Can't create the VPN connect";
- }
- }
- }
+ {
+ if ( !create_new_vpn(tunnelName(), m_config[config_key::hostName].toString())){
+ qDebug() <<"Can't create the VPN connect";
+}
+}
+}
- {
- auto adapterConfigProcess = new QProcess;
+{
+ QProcess adapterConfigProcess;
+ adapterConfigProcess.setProgram("powershell");
+ QString arguments = QString("-command \"Set-VpnConnectionIPsecConfiguration\" "
+ "-ConnectionName '%1' "
+ "-AuthenticationTransformConstants GCMAES128 "
+ "-CipherTransformConstants GCMAES128 "
+ "-EncryptionMethod AES256 "
+ "-IntegrityCheckMethod SHA256 "
+ "-PfsGroup None "
+ "-DHGroup Group14 "
+ "-PassThru -Force\"")
+ .arg(tunnelName());
- adapterConfigProcess->setProgram("powershell");
- QString arguments = QString("-command \"Set-VpnConnectionIPsecConfiguration\" "
- "-ConnectionName '%1' "
- "-AuthenticationTransformConstants GCMAES128 "
- "-CipherTransformConstants GCMAES128 "
- "-EncryptionMethod AES256 "
- "-IntegrityCheckMethod SHA256 "
- "-PfsGroup None "
- "-DHGroup Group14 "
- "-PassThru -Force\"")
- .arg(tunnelName());
- adapterConfigProcess->setNativeArguments(arguments);
+ adapterConfigProcess.setNativeArguments(arguments);
- adapterConfigProcess->start();
- adapterConfigProcess->waitForFinished(5000);
+ adapterConfigProcess.start();
+ adapterConfigProcess.waitForFinished(5000);
+}
+//*/
+{
+ if (!connect_to_vpn(tunnelName())) {
+ qDebug()<<"We can't connect to VPN";
}
- //*/
- {
- if (!connect_to_vpn(tunnelName())) {
- qDebug()<<"We can't connect to VPN";
- }
- }
- //setConnectionState(Connecting);
- return ErrorCode::NoError;
+}
+//setConnectionState(Connecting);
+return ErrorCode::NoError;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
@@ -299,6 +302,7 @@ bool Ikev2Protocol::connect_to_vpn(const QString & vpn_name){
auto ret = RasDial(NULL, NULL, &RasDialParams, 0,
&RasDialFuncCallback,
&hRasConn);
+
if (ret == ERROR_SUCCESS){
return true;
}
diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp
index 04a18327..4c2feb52 100644
--- a/client/protocols/openvpnprotocol.cpp
+++ b/client/protocols/openvpnprotocol.cpp
@@ -6,6 +6,7 @@
#include
#include