diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 63bda344..220fbd79 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,12 +10,12 @@ 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 }} steps: - name: 'Install Qt' @@ -75,13 +75,13 @@ 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 }} steps: - name: 'Get sources' @@ -137,13 +137,13 @@ 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 }} steps: - name: 'Setup xcode' @@ -228,13 +228,13 @@ 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 }} steps: - name: 'Setup xcode' @@ -293,13 +293,13 @@ jobs: # ------------------------------------------------------ Build-Android: - name: 'Build-Android' runs-on: ubuntu-latest env: ANDROID_BUILD_PLATFORM: android-34 QT_VERSION: 6.6.2 QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools' + PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }} steps: - name: 'Install desktop Qt' @@ -439,3 +439,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..e117a6c6 100644 --- a/.github/workflows/tag-deploy.yml +++ b/.github/workflows/tag-deploy.yml @@ -15,6 +15,7 @@ jobs: env: QT_VERSION: 6.4.1 QIF_VERSION: 4.5 + PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_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 53dc9ed2..41e05838 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.0.4 +project(${PROJECT} VERSION 4.7.0.0 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 55) +set(APP_ANDROID_VERSION_CODE 57) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(MZ_PLATFORM_NAME "linux") diff --git a/README.md b/README.md index 2e43e856..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 @@ -154,9 +156,11 @@ The Android app has the following requirements: * Android platform SDK 33 * CMake 3.25.0 -After you have installed QT, QT Creator, and Android Studio, you need to configure QT Creator correctly. Click in the top menu bar on `QT Creator` -> `Preferences` -> `Devices` and select the tab `Android`. - * set path to JDK 11 - * set path to Android SDK ($ANDROID_HOME) +After you have installed QT, QT Creator, and Android Studio, you need to configure QT Creator correctly. + +- Click in the top menu bar on `QT Creator` -> `Preferences` -> `Devices` and select the tab `Android`. +- Set path to JDK 11 +- Set path to Android SDK (`$ANDROID_HOME`) In case you get errors regarding missing SDK or 'SDK manager not running', you cannot fix them by correcting the paths. If you have some spare GBs on your disk, you can let QT Creator install all requirements by choosing an empty folder for `Android SDK location` and clicking on `Set Up SDK`. Be aware: This will install a second Android SDK and NDK on your machine!  Double-check that the right CMake version is configured:  Click on `QT Creator` -> `Preferences` and click on the side menu on `Kits`. Under the center content view's `Kits` tab, you'll find an entry for `CMake Tool`. If the default selected CMake version is lower than 3.25.0, install on your system CMake >= 3.25.0 and choose `System CMake at ` from the drop-down list. If this entry is missing, you either have not installed CMake yet or QT Creator hasn't found the path to it. In that case, click in the preferences window on the side menu item `CMake`, then on the tab `Tools` in the center content view, and finally on the button `Add` to set the path to your installed CMake.  @@ -179,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 ff8445c8..c38a587f 160000 --- a/client/3rd-prebuilt +++ b/client/3rd-prebuilt @@ -1 +1 @@ -Subproject commit ff8445c8aa1cda38497bb6f6cb0e520f5a3c8de0 +Subproject commit c38a587fcda89bab4009560d36239fa8de74705e diff --git a/client/3rd/OpenVPNAdapter b/client/3rd/OpenVPNAdapter index 7c821a8d..dea60409 160000 --- a/client/3rd/OpenVPNAdapter +++ b/client/3rd/OpenVPNAdapter @@ -1 +1 @@ -Subproject commit 7c821a8d5c1ad5ad94e0763b4f25a875b5a6fe1b +Subproject commit dea6040996298e947d63fb172709e6abfec2ba93 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/CMakeLists.txt b/client/CMakeLists.txt index baad1b9a..0a155b18 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -24,6 +24,9 @@ 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}") + if(IOS) set(PACKAGES ${PACKAGES} Multimedia) endif() @@ -34,7 +37,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 @@ -136,6 +139,7 @@ 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 ) # Mozilla headres @@ -252,7 +256,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 8fe97cd7..b8ce5b00 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -3,13 +3,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include "logger.h" #include "ui/models/installedAppsModel.h" @@ -116,7 +116,7 @@ void AmneziaApplication::init() } connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, [this](QString data) { - m_pageController->replaceStartPage(); + m_pageController->goToPageHome(); m_importController->extractConfigFromData(data); m_pageController->goToPageViewConfig(); }); @@ -127,13 +127,13 @@ void AmneziaApplication::init() #ifdef Q_OS_IOS IosController::Instance()->initialize(); connect(IosController::Instance(), &IosController::importConfigFromOutside, [this](QString data) { - m_pageController->replaceStartPage(); + m_pageController->goToPageHome(); m_importController->extractConfigFromData(data); m_pageController->goToPageViewConfig(); }); connect(IosController::Instance(), &IosController::importBackupFromOutside, [this](QString filePath) { - m_pageController->replaceStartPage(); + m_pageController->goToPageHome(); m_pageController->goToPageSettingsBackup(); m_settingsController->importBackupFromOutside(filePath); }); @@ -161,13 +161,15 @@ void AmneziaApplication::init() m_engine->load(url); m_systemController->setQmlRoot(m_engine->rootObjects().value(0)); + bool enabled = m_settings->isSaveLogs(); #ifndef Q_OS_ANDROID - if (m_settings->isSaveLogs()) { + if (enabled) { if (!Logger::init()) { qWarning() << "Initialization of debug subsystem failed"; } } #endif + Logger::setServiceLogsEnabled(enabled); #ifdef Q_OS_WIN if (m_parser.isSet("a")) @@ -359,6 +361,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() @@ -367,25 +381,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); @@ -394,6 +409,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..6fb61f44 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -45,6 +45,8 @@ #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())) @@ -103,6 +105,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 +138,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 f1d2682b..c1c40b52 100644 --- a/client/android/AndroidManifest.xml +++ b/client/android/AndroidManifest.xml @@ -11,6 +11,9 @@ + + + @@ -31,9 +34,11 @@ android:label="-- %%INSERT_APP_NAME%% --" android:icon="@mipmap/icon" android:roundIcon="@mipmap/icon_round" + android:banner="@mipmap/ic_banner" android:theme="@style/NoActionBar" android:fullBackupContent="@xml/backup_content" android:dataExtractionRules="@xml/data_extraction_rules" + android:hasFragileUserData="false" tools:targetApi="s"> + diff --git a/client/android/res/mipmap-anydpi-v26/ic_banner.xml b/client/android/res/mipmap-anydpi-v26/ic_banner.xml new file mode 100644 index 00000000..cf3108b3 --- /dev/null +++ b/client/android/res/mipmap-anydpi-v26/ic_banner.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/client/android/res/mipmap-xhdpi/ic_banner.png b/client/android/res/mipmap-xhdpi/ic_banner.png new file mode 100644 index 00000000..f5029b23 Binary files /dev/null and b/client/android/res/mipmap-xhdpi/ic_banner.png differ diff --git a/client/android/res/mipmap-xhdpi/ic_banner_foreground.png b/client/android/res/mipmap-xhdpi/ic_banner_foreground.png new file mode 100644 index 00000000..1c21902e Binary files /dev/null and b/client/android/res/mipmap-xhdpi/ic_banner_foreground.png differ diff --git a/client/android/res/values/ic_banner_background.xml b/client/android/res/values/ic_banner_background.xml new file mode 100644 index 00000000..fa6f91c7 --- /dev/null +++ b/client/android/res/values/ic_banner_background.xml @@ -0,0 +1,4 @@ + + + #1E1E1F + \ No newline at end of file diff --git a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt index e3ed6d39..8a78750b 100644 --- a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt +++ b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt @@ -1,6 +1,7 @@ package org.amnezia.vpn import android.Manifest +import android.annotation.SuppressLint import android.app.AlertDialog import android.app.NotificationManager import android.content.BroadcastReceiver @@ -230,7 +231,10 @@ class AmneziaActivity : QtActivity() { override fun onStop() { Log.d(TAG, "Stop Amnezia activity") doUnbindService() - QtAndroidController.onServiceDisconnected() + mainScope.launch { + qtInitialized.await() + QtAndroidController.onServiceDisconnected() + } super.onStop() } @@ -542,7 +546,7 @@ class AmneziaActivity : QtActivity() { } }.also { startActivityForResult(it, OPEN_FILE_ACTION_CODE, ActivityResultHandler( - onSuccess = { + onAny = { val uri = it?.data?.toString() ?: "" Log.d(TAG, "Open file: $uri") mainScope.launch { @@ -556,8 +560,12 @@ class AmneziaActivity : QtActivity() { } @Suppress("unused") + @SuppressLint("UnsupportedChromeOsCameraSystemFeature") fun isCameraPresent(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA) + @Suppress("unused") + fun isOnTv(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) + @Suppress("unused") fun startQrCodeReader() { Log.v(TAG, "Start camera") diff --git a/client/android/utils/src/main/kotlin/net/NetworkState.kt b/client/android/utils/src/main/kotlin/net/NetworkState.kt index 3cff8c04..26d23215 100644 --- a/client/android/utils/src/main/kotlin/net/NetworkState.kt +++ b/client/android/utils/src/main/kotlin/net/NetworkState.kt @@ -88,16 +88,24 @@ 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) { - try { - connectivityManager.requestNetwork(networkRequest, networkCallback, handler) - } catch (e: SecurityException) { - Log.e(TAG, "Failed to bind network listener: $e") - // Android 11 bug: https://issuetracker.google.com/issues/175055271 - if (e.message?.startsWith("Package android does not belong to") == true) { - delay(1000) + val numberAttempts = 3 + var attemptCount = 0 + while(true) { + try { connectivityManager.requestNetwork(networkRequest, networkCallback, handler) - } else { - throw e + break + } catch (e: SecurityException) { + Log.e(TAG, "Failed to bind network listener: $e") + // Android 11 bug: https://issuetracker.google.com/issues/175055271 + if (e.message?.startsWith("Package android does not belong to") == true) { + if (++attemptCount > numberAttempts) { + throw e + } + delay(1000) + continue + } else { + throw e + } } } } else { diff --git a/client/cmake/3rdparty.cmake b/client/cmake/3rdparty.cmake index ec544764..087f4961 100644 --- a/client/cmake/3rdparty.cmake +++ b/client/cmake/3rdparty.cmake @@ -8,9 +8,9 @@ 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 +83,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/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp index c4bdf860..fafb7c2b 100644 --- a/client/configurators/openvpn_configurator.cpp +++ b/client/configurators/openvpn_configurator.cpp @@ -119,18 +119,21 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPairisSitesSplitTunnelingEnabled()) { config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n"); + +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) // Prevent ipv6 leak config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n"); +#endif config.append("block-ipv6\n"); } else if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { // no redirect-gateway } else if (m_settings->routeMode() == Settings::VpnAllExceptSites) { -#ifndef Q_OS_ANDROID +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n"); -#endif // Prevent ipv6 leak config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n"); +#endif config.append("block-ipv6\n"); } } diff --git a/client/containers/containers_defs.cpp b/client/containers/containers_defs.cpp index cdf14db8..7647c166 100644 --- a/client/containers/containers_defs.cpp +++ b/client/containers/containers_defs.cpp @@ -96,7 +96,7 @@ QMap ContainerProps::containerHumanNames() { DockerContainer::Awg, "AmneziaWG" }, { DockerContainer::Xray, "XRay" }, { DockerContainer::Ipsec, QObject::tr("IPsec") }, - { DockerContainer::SSXray, "ShadowSocks"}, + { DockerContainer::SSXray, "Shadowsocks"}, { DockerContainer::TorWebSite, QObject::tr("Website in Tor network") }, { DockerContainer::Dns, QObject::tr("AmneziaDNS") }, diff --git a/client/core/controllers/apiController.cpp b/client/core/controllers/apiController.cpp index 35b459be..8e5f8ed5 100644 --- a/client/core/controllers/apiController.cpp +++ b/client/core/controllers/apiController.cpp @@ -5,7 +5,11 @@ #include #include +#include "QBlockCipher.h" +#include "QRsa.h" + #include "amnezia_application.h" +#include "core/enums/apiEnums.h" #include "configurators/wireguard_configurator.h" #include "version.h" @@ -25,25 +29,74 @@ 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, QObject *parent) : QObject(parent), m_gatewayEndpoint(gatewayEndpoint) { } -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 +114,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 +218,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 +235,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 +267,154 @@ 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 key = PROD_AGW_PUBLIC_KEY; + QSimpleCrypto::QRsa rsa; + publicKey = rsa.getPublicKeyFromByteArray(key); + } 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..6cfde983 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, 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,12 @@ 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; }; #endif // APICONTROLLER_H diff --git a/client/core/controllers/serverController.cpp b/client/core/controllers/serverController.cpp index 11efb57a..233d66d4 100644 --- a/client/core/controllers/serverController.cpp +++ b/client/core/controllers/serverController.cpp @@ -569,6 +569,7 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential // Xray vars vars.append({ { "$XRAY_SITE_NAME", xrayConfig.value(config_key::site).toString(protocols::xray::defaultSite) } }); + vars.append({ { "$XRAY_SERVER_PORT", xrayConfig.value(config_key::port).toString(protocols::xray::defaultPort) } }); // Wireguard vars vars.append({ { "$WIREGUARD_SUBNET_IP", diff --git a/client/core/defs.h b/client/core/defs.h index a441ee1c..ebc07f4b 100644 --- a/client/core/defs.h +++ b/client/core/defs.h @@ -106,6 +106,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..8c16d786 100644 --- a/client/core/errorstrings.cpp +++ b/client/core/errorstrings.cpp @@ -60,6 +60,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/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 @@ + + + + AD + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AF + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AI + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AL + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AO + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AS + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AT + Created with sketchtool. + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AU + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AW + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AX + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + AZ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BA + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BB + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BD + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BF + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BH + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BI + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BJ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BL + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BN + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BO + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BS + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BT + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BV + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BW + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BY + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + BZ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CA + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CC + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CD + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CF + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CH + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CI + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CK + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CL + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CN + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CO + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CU + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CV + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CW + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CX + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CY + Created with sketchtool. + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + CZ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + DE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + DJ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + DK + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + DM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + DO + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + DZ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + EC + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + EE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + EG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + ER + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + ES + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + ET + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + EU + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + FI + Created with sketchtool. + + + + + + + + + + + + + + + + + \ 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 @@ + + + + FJ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + FK + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + FM + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + FO + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + FR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GA + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GB + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GD + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GF + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GH + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GI + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GL + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GN + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GP + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GQ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GR + Created with sketchtool. + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GS + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GT + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GU + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GW + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + GY + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + HK + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + HM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + HN + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + HR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + HT + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + HU + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + ID + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + IE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + IL + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + IM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + IN + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + IO + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + IQ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + IR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + IS + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + IT + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + JE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + JM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + JO + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + JP + Created with sketchtool. + + + + + + + + + + + + + + + + + \ 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 @@ + + + + KE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + KG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + KH + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + KI + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + KM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + KN + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + KP + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + KR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + KW + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + KY + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + KZ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + LA + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + LB + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + LC + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + LI + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + LK + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + LR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + LS + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + LT + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + LU + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + LV + Created with sketchtool. + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + LY + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MA + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MC + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MD + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + ME + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MF + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MH + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MK + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + ML + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MN + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MO + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MP + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MQ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MS + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MT + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MU + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MV + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MW + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MX + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MY + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + MZ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + NA + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + NC + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + NE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + NF + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + NG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + NI + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + NL + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + NP + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + NR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + NU + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + NZ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + OM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PA + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PF + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PH + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PK + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PL + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PN + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PS + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PT + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PW + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + PY + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + QA + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + RE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + RO + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + RS + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + RU + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + RW + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SA + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SB + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SC + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SD + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SH + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SI + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SJ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SK + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SL + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SN + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SO + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SR + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SS + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + ST + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SV + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SX + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SY + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + SZ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TC + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TD + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TF + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TH + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TJ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TK + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TL + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TN + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TO + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TR + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TT + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TV + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TW + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + TZ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + UA + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + UG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + UM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + US + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + UY + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + UZ + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + VA + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + VC + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + VE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + VG + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + VI + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + VN + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + VU + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + WF + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + WS + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + XK + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + YE + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + YT + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + ZA + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + ZM + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + ZW + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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.cpp b/client/logger.cpp index 0dc836c6..c76bc698 100644 --- a/client/logger.cpp +++ b/client/logger.cpp @@ -99,6 +99,29 @@ void Logger::deInit() m_file.close(); } +bool Logger::setServiceLogsEnabled(bool enabled) { +#ifdef AMNEZIA_DESKTOP + IpcClient *m_IpcClient = new IpcClient; + + if (!m_IpcClient->isSocketConnected()) { + if (!IpcClient::init(m_IpcClient)) { + qWarning() << "Error occurred when init IPC client"; + return false; + } + } + + if (m_IpcClient->Interface()) { + m_IpcClient->Interface()->setLogsEnabled(enabled); + } + else { + qWarning() << "Error occurred setting up service logs"; + return false; + } +#endif + + return true; +} + QString Logger::userLogsDir() { return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/log"; @@ -141,7 +164,9 @@ bool Logger::openLogsFolder() bool Logger::openServiceLogsFolder() { QString path = Utils::systemLogPath(); +#ifdef Q_OS_WIN path = "file:///" + path; +#endif QDesktopServices::openUrl(QUrl::fromLocalFile(path)); return true; } @@ -184,8 +209,7 @@ void Logger::clearServiceLogs() } if (m_IpcClient->Interface()) { - m_IpcClient->Interface()->setLogsEnabled(false); - m_IpcClient->Interface()->cleanUp(); + m_IpcClient->Interface()->clearLogs(); } else { qWarning() << "Error occurred cleaning up service logs"; diff --git a/client/logger.h b/client/logger.h index f8bfc225..0dcbd35c 100644 --- a/client/logger.h +++ b/client/logger.h @@ -26,6 +26,7 @@ public: static bool init(); static void deInit(); + static bool setServiceLogsEnabled(bool enabled); static bool openLogsFolder(); static bool openServiceLogsFolder(); static QString appLogFileNamePath(); diff --git a/client/platforms/android/android_controller.cpp b/client/platforms/android/android_controller.cpp index be404a15..c9ee3cfd 100644 --- a/client/platforms/android/android_controller.cpp +++ b/client/platforms/android/android_controller.cpp @@ -179,6 +179,11 @@ bool AndroidController::isCameraPresent() return callActivityMethod("isCameraPresent", "()Z"); } +bool AndroidController::isOnTv() +{ + return callActivityMethod("isOnTv", "()Z"); +} + void AndroidController::startQrReaderActivity() { callActivityMethod("startQrCodeReader", "()V"); diff --git a/client/platforms/android/android_controller.h b/client/platforms/android/android_controller.h index d015dbe3..1041c31f 100644 --- a/client/platforms/android/android_controller.h +++ b/client/platforms/android/android_controller.h @@ -35,6 +35,7 @@ public: void saveFile(const QString &fileName, const QString &data); QString openFile(const QString &filter); bool isCameraPresent(); + bool isOnTv(); void startQrReaderActivity(); void setSaveLogs(bool enabled); void exportLogsFile(const QString &fileName); diff --git a/client/platforms/windows/windowsservicemanager.h b/client/platforms/windows/windowsservicemanager.h index e0709309..7638588f 100644 --- a/client/platforms/windows/windowsservicemanager.h +++ b/client/platforms/windows/windowsservicemanager.h @@ -12,7 +12,7 @@ #include "Winsvc.h" /** - * @brief The WindowsServiceManager provides controll over the MozillaVPNBroker + * @brief The WindowsServiceManager provides control over the MozillaVPNBroker * service via SCM */ class WindowsServiceManager : public QObject { diff --git a/client/protocols/ikev2_vpn_protocol_windows.cpp b/client/protocols/ikev2_vpn_protocol_windows.cpp index ed6fb174..2c753c8a 100644 --- a/client/protocols/ikev2_vpn_protocol_windows.cpp +++ b/client/protocols/ikev2_vpn_protocol_windows.cpp @@ -206,8 +206,8 @@ ErrorCode Ikev2Protocol::start() certInstallProcess->setProgram(PermittedProcess::CertUtil); QStringList arguments({"-f", "-importpfx", "-p", m_config[config_key::password].toString(), - QDir::toNativeSeparators(m_filename), "NoExport" - }); + QDir::toNativeSeparators(m_filename), "NoExport" + }); certInstallProcess->setArguments(arguments); certInstallProcess->start(); @@ -223,40 +223,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"; +} +} +} - { - 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()); +{ + 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.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, diff --git a/client/protocols/protocols_defs.cpp b/client/protocols/protocols_defs.cpp index 9be5a75f..ac5bb1ad 100644 --- a/client/protocols/protocols_defs.cpp +++ b/client/protocols/protocols_defs.cpp @@ -65,14 +65,14 @@ QString ProtocolProps::transportProtoToString(TransportProto proto, Proto p) QMap ProtocolProps::protocolHumanNames() { return { { Proto::OpenVpn, "OpenVPN" }, - { Proto::ShadowSocks, "ShadowSocks" }, + { Proto::ShadowSocks, "Shadowsocks" }, { Proto::Cloak, "Cloak" }, { Proto::WireGuard, "WireGuard" }, { Proto::Awg, "AmneziaWG" }, { Proto::Ikev2, "IKEv2" }, { Proto::L2tp, "L2TP" }, { Proto::Xray, "XRay" }, - { Proto::SSXray, "ShadowSocks"}, + { Proto::SSXray, "Shadowsocks"}, { Proto::TorWebSite, "Website in Tor network" }, @@ -154,6 +154,7 @@ bool ProtocolProps::defaultPortChangeable(Proto p) case Proto::Awg: return true; case Proto::Ikev2: return false; case Proto::L2tp: return false; + case Proto::Xray: return true; case Proto::TorWebSite: return false; case Proto::Dns: return false; diff --git a/client/resources.qrc b/client/resources.qrc index a12b0805..5001f2cb 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -1,18 +1,9 @@ - images/close.png - images/settings.png - images/favorites_disabled.png - images/favorites_enabled.png - images/favorites_hover.png - images/download.png - images/upload.png images/tray/active.png images/tray/default.png images/tray/error.png - images/arrow_left.png images/AmneziaVPN.png - images/share.png server_scripts/remove_container.sh server_scripts/setup_host_firewall.sh server_scripts/openvpn_cloak/Dockerfile @@ -22,9 +13,6 @@ server_scripts/install_docker.sh server_scripts/build_container.sh server_scripts/prepare_host.sh - images/check.png - images/uncheck.png - images/settings_grey.png server_scripts/check_connection.sh server_scripts/remove_all_containers.sh server_scripts/openvpn_cloak/run_container.sh @@ -38,7 +26,6 @@ server_scripts/openvpn_shadowsocks/run_container.sh server_scripts/openvpn_shadowsocks/start.sh server_scripts/openvpn_shadowsocks/template.ovpn - images/folder.png server_scripts/wireguard/configure_container.sh server_scripts/wireguard/Dockerfile server_scripts/wireguard/run_container.sh @@ -61,26 +48,6 @@ server_scripts/ipsec/start.sh server_scripts/ipsec/mobileconfig.plist server_scripts/ipsec/strongswan.profile - images/background_connected.png - images/background_connected@2x.png - images/delete.png - images/animation.gif - images/connected.png - images/disconnected.png - images/svg/gpp_good_black_24dp.svg - images/svg/gpp_maybe_black_24dp.svg - images/svg/close_black_24dp.svg - images/svg/delete_black_24dp.svg - images/svg/done_black_24dp.svg - images/svg/format_list_bulleted_black_24dp.svg - images/svg/logout_black_24dp.svg - images/svg/miscellaneous_services_black_24dp.svg - images/svg/refresh_black_24dp.svg - images/svg/settings_black_24dp.svg - images/svg/share_black_24dp.svg - images/svg/vpn_key_black_24dp.svg - images/svg/control_point_black_24dp.svg - images/svg/settings_suggest_black_24dp.svg server_scripts/website_tor/Dockerfile server_scripts/check_user_in_sudo.sh ui/qml/Controls2/BasicButtonType.qml @@ -96,7 +63,6 @@ ui/qml/Pages2/PageSetupWizardStart.qml ui/qml/main2.qml images/amneziaBigLogo.png - images/amneziaBigLogo.svg ui/qml/Controls2/FlickableType.qml ui/qml/Pages2/PageSetupWizardCredentials.qml ui/qml/Controls2/HeaderType.qml @@ -132,9 +98,6 @@ ui/qml/Controls2/Header2Type.qml images/controls/plus.svg ui/qml/Components/ConnectButton.qml - images/connectionProgress.svg - images/connectionOff.svg - images/connectionOn.svg images/controls/download.svg ui/qml/Controls2/ProgressBarType.qml ui/qml/Components/ConnectionTypeSelectionDrawer.qml @@ -237,5 +200,274 @@ server_scripts/socks5_proxy/configure_container.sh server_scripts/socks5_proxy/start.sh server_scripts/ipsec/template.conf + ui/qml/Pages2/PageSetupWizardApiServicesList.qml + ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml + ui/qml/Controls2/CardWithIconsType.qml + images/controls/tag.svg + images/controls/history.svg + images/controls/gauge.svg + images/controls/map-pin.svg + ui/qml/Controls2/LabelWithImageType.qml + images/controls/info.svg + ui/qml/Controls2/TextAreaWithFooterType.qml + images/controls/scan-line.svg + images/controls/folder-search-2.svg + ui/qml/Pages2/PageSettingsApiServerInfo.qml + images/controls/bug.svg + ui/qml/Pages2/PageDevMenu.qml + images/controls/refresh-cw.svg + ui/qml/Pages2/PageSettingsApiLanguageList.qml + images/controls/archive-restore.svg + images/controls/help-circle.svg + + + images/flagKit/ZW.svg + images/flagKit/ZM.svg + images/flagKit/ZA.svg + images/flagKit/YT.svg + images/flagKit/YE.svg + images/flagKit/XK.svg + images/flagKit/WS.svg + images/flagKit/WF.svg + images/flagKit/VU.svg + images/flagKit/VN.svg + images/flagKit/VI.svg + images/flagKit/VG.svg + images/flagKit/VE.svg + images/flagKit/VC.svg + images/flagKit/VA.svg + images/flagKit/UZ.svg + images/flagKit/UY.svg + images/flagKit/US.svg + images/flagKit/UM.svg + images/flagKit/UG.svg + images/flagKit/UA.svg + images/flagKit/TZ.svg + images/flagKit/TW.svg + images/flagKit/TV.svg + images/flagKit/TT.svg + images/flagKit/TR.svg + images/flagKit/TO.svg + images/flagKit/TN.svg + images/flagKit/TM.svg + images/flagKit/TL.svg + images/flagKit/TK.svg + images/flagKit/TJ.svg + images/flagKit/TH.svg + images/flagKit/TG.svg + images/flagKit/TF.svg + images/flagKit/TD.svg + images/flagKit/TC.svg + images/flagKit/SZ.svg + images/flagKit/SY.svg + images/flagKit/SX.svg + images/flagKit/SV.svg + images/flagKit/ST.svg + images/flagKit/SS.svg + images/flagKit/SR.svg + images/flagKit/SO.svg + images/flagKit/SN.svg + images/flagKit/SM.svg + images/flagKit/SL.svg + images/flagKit/SK.svg + images/flagKit/SJ.svg + images/flagKit/SI.svg + images/flagKit/SH.svg + images/flagKit/SG.svg + images/flagKit/SE.svg + images/flagKit/SD.svg + images/flagKit/SC.svg + images/flagKit/SB.svg + images/flagKit/SA.svg + images/flagKit/RW.svg + images/flagKit/RU.svg + images/flagKit/RS.svg + images/flagKit/RO.svg + images/flagKit/RE.svg + images/flagKit/QA.svg + images/flagKit/PY.svg + images/flagKit/PW.svg + images/flagKit/PT.svg + images/flagKit/PS.svg + images/flagKit/PR.svg + images/flagKit/PN.svg + images/flagKit/PM.svg + images/flagKit/PL.svg + images/flagKit/PK.svg + images/flagKit/PH.svg + images/flagKit/PG.svg + images/flagKit/PF.svg + images/flagKit/PE.svg + images/flagKit/PA.svg + images/flagKit/OM.svg + images/flagKit/NZ.svg + images/flagKit/NU.svg + images/flagKit/NR.svg + images/flagKit/NP.svg + images/flagKit/NO.svg + images/flagKit/NL.svg + images/flagKit/NI.svg + images/flagKit/NG.svg + images/flagKit/NF.svg + images/flagKit/NE.svg + images/flagKit/NC.svg + images/flagKit/NA.svg + images/flagKit/MZ.svg + images/flagKit/MY.svg + images/flagKit/MX.svg + images/flagKit/MW.svg + images/flagKit/MV.svg + images/flagKit/MU.svg + images/flagKit/MT.svg + images/flagKit/MS.svg + images/flagKit/MR.svg + images/flagKit/MQ.svg + images/flagKit/MP.svg + images/flagKit/MO.svg + images/flagKit/MN.svg + images/flagKit/MM.svg + images/flagKit/ML.svg + images/flagKit/MK.svg + images/flagKit/MH.svg + images/flagKit/MG.svg + images/flagKit/MF.svg + images/flagKit/ME.svg + images/flagKit/MD.svg + images/flagKit/MC.svg + images/flagKit/MA.svg + images/flagKit/LY.svg + images/flagKit/LV.svg + images/flagKit/LU.svg + images/flagKit/LT.svg + images/flagKit/LS.svg + images/flagKit/LR.svg + images/flagKit/LK.svg + images/flagKit/LI.svg + images/flagKit/LC.svg + images/flagKit/LB.svg + images/flagKit/LA.svg + images/flagKit/KZ.svg + images/flagKit/KY.svg + images/flagKit/KW.svg + images/flagKit/KR.svg + images/flagKit/KP.svg + images/flagKit/KN.svg + images/flagKit/KM.svg + images/flagKit/KI.svg + images/flagKit/KH.svg + images/flagKit/KG.svg + images/flagKit/KE.svg + images/flagKit/JP.svg + images/flagKit/JO.svg + images/flagKit/JM.svg + images/flagKit/JE.svg + images/flagKit/IT.svg + images/flagKit/IS.svg + images/flagKit/IR.svg + images/flagKit/IQ.svg + images/flagKit/IO.svg + images/flagKit/IN.svg + images/flagKit/IM.svg + images/flagKit/IL.svg + images/flagKit/IE.svg + images/flagKit/ID.svg + images/flagKit/HU.svg + images/flagKit/HT.svg + images/flagKit/HR.svg + images/flagKit/HN.svg + images/flagKit/HM.svg + images/flagKit/HK.svg + images/flagKit/GY.svg + images/flagKit/GW.svg + images/flagKit/GU.svg + images/flagKit/GT.svg + images/flagKit/GS.svg + images/flagKit/GR.svg + images/flagKit/GQ.svg + images/flagKit/GP.svg + images/flagKit/GN.svg + images/flagKit/GM.svg + images/flagKit/GL.svg + images/flagKit/GI.svg + images/flagKit/GH.svg + images/flagKit/GG.svg + images/flagKit/GF.svg + images/flagKit/GE.svg + images/flagKit/GD.svg + images/flagKit/GB.svg + images/flagKit/GA.svg + images/flagKit/FR.svg + images/flagKit/FO.svg + images/flagKit/FM.svg + images/flagKit/FK.svg + images/flagKit/FJ.svg + images/flagKit/FI.svg + images/flagKit/EU.svg + images/flagKit/ET.svg + images/flagKit/ES.svg + images/flagKit/ER.svg + images/flagKit/EG.svg + images/flagKit/EE.svg + images/flagKit/EC.svg + images/flagKit/DZ.svg + images/flagKit/DO.svg + images/flagKit/DM.svg + images/flagKit/DK.svg + images/flagKit/DJ.svg + images/flagKit/DE.svg + images/flagKit/CZ.svg + images/flagKit/CY.svg + images/flagKit/CX.svg + images/flagKit/CW.svg + images/flagKit/CV.svg + images/flagKit/CU.svg + images/flagKit/CR.svg + images/flagKit/CO.svg + images/flagKit/CN.svg + images/flagKit/CM.svg + images/flagKit/CL.svg + images/flagKit/CK.svg + images/flagKit/CI.svg + images/flagKit/CH.svg + images/flagKit/CG.svg + images/flagKit/CF.svg + images/flagKit/CD.svg + images/flagKit/CC.svg + images/flagKit/CA.svg + images/flagKit/BZ.svg + images/flagKit/BY.svg + images/flagKit/BW.svg + images/flagKit/BV.svg + images/flagKit/BT.svg + images/flagKit/BS.svg + images/flagKit/BR.svg + images/flagKit/BO.svg + images/flagKit/BN.svg + images/flagKit/BM.svg + images/flagKit/BL.svg + images/flagKit/BJ.svg + images/flagKit/BI.svg + images/flagKit/BH.svg + images/flagKit/BG.svg + images/flagKit/BF.svg + images/flagKit/BE.svg + images/flagKit/BD.svg + images/flagKit/BB.svg + images/flagKit/BA.svg + images/flagKit/AZ.svg + images/flagKit/AX.svg + images/flagKit/AW.svg + images/flagKit/AU.svg + images/flagKit/AT.svg + images/flagKit/AS.svg + images/flagKit/AR.svg + images/flagKit/AO.svg + images/flagKit/AM.svg + images/flagKit/AL.svg + images/flagKit/AI.svg + images/flagKit/AG.svg + images/flagKit/AF.svg + images/flagKit/AE.svg + images/flagKit/AD.svg diff --git a/client/secure_qsettings.cpp b/client/secure_qsettings.cpp index 592f77d4..1e2a2273 100644 --- a/client/secure_qsettings.cpp +++ b/client/secure_qsettings.cpp @@ -185,7 +185,7 @@ QByteArray SecureQSettings::decryptText(const QByteArray &ba) const bool SecureQSettings::encryptionRequired() const { -#ifdef Q_OS_LINUX +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) // QtKeyChain failing on Linux return false; #endif @@ -200,7 +200,7 @@ QByteArray SecureQSettings::getEncKey() const if (m_key.isEmpty()) { // Create new key QSimpleCrypto::QBlockCipher cipher; - QByteArray key = cipher.generateSecureRandomBytes(32); + QByteArray key = cipher.generatePrivateSalt(32); if (key.isEmpty()) { qCritical() << "SecureQSettings::getEncKey Unable to generate new enc key"; } @@ -226,7 +226,7 @@ QByteArray SecureQSettings::getEncIv() const if (m_iv.isEmpty()) { // Create new IV QSimpleCrypto::QBlockCipher cipher; - QByteArray iv = cipher.generateSecureRandomBytes(32); + QByteArray iv = cipher.generatePrivateSalt(32); if (iv.isEmpty()) { qCritical() << "SecureQSettings::getEncIv Unable to generate new enc IV"; } diff --git a/client/server_scripts/xray/configure_container.sh b/client/server_scripts/xray/configure_container.sh index 541e155b..a84751c7 100644 --- a/client/server_scripts/xray/configure_container.sh +++ b/client/server_scripts/xray/configure_container.sh @@ -29,7 +29,7 @@ cat > /opt/amnezia/xray/server.json < Settings::containers(int serverIndex) const QMap containersMap; for (const QJsonValue &val : containers) { - containersMap.insert(ContainerProps::containerFromString(val.toObject().value(config_key::container).toString()), - val.toObject()); + containersMap.insert(ContainerProps::containerFromString(val.toObject().value(config_key::container).toString()), val.toObject()); } return containersMap; @@ -226,6 +232,8 @@ void Settings::setSaveLogs(bool enabled) } } #endif + Logger::setServiceLogsEnabled(enabled); + if (enabled) { setLogEnableDate(QDateTime::currentDateTime()); } @@ -440,6 +448,17 @@ QString Settings::getInstallationUuid(const bool needCreate) auto uuid = value("Conf/installationUuid", "").toString(); if (needCreate && uuid.isEmpty()) { uuid = QUuid::createUuid().toString(); + + //remove {} from uuid + uuid.remove(0, 1); + uuid.chop(1); + + setInstallationUuid(uuid); + } else if (uuid.contains("{") && uuid.contains("}")) { + //remove {} from old uuid + uuid.remove(0, 1); + uuid.chop(1); + setInstallationUuid(uuid); } return uuid; @@ -474,11 +493,8 @@ QVariant Settings::value(const QString &key, const QVariant &defaultValue) const if (QThread::currentThread() == QCoreApplication::instance()->thread()) { returnValue = m_settings.value(key, defaultValue); } else { - QMetaObject::invokeMethod(&m_settings, "value", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QVariant, returnValue), - Q_ARG(const QString&, key), - Q_ARG(const QVariant&, defaultValue)); + QMetaObject::invokeMethod(&m_settings, "value", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariant, returnValue), + Q_ARG(const QString &, key), Q_ARG(const QVariant &, defaultValue)); } return returnValue; } @@ -488,9 +504,22 @@ void Settings::setValue(const QString &key, const QVariant &value) if (QThread::currentThread() == QCoreApplication::instance()->thread()) { m_settings.setValue(key, value); } else { - QMetaObject::invokeMethod(&m_settings, "setValue", - Qt::BlockingQueuedConnection, - Q_ARG(const QString&, key), - Q_ARG(const QVariant&, value)); + QMetaObject::invokeMethod(&m_settings, "setValue", Qt::BlockingQueuedConnection, Q_ARG(const QString &, key), + Q_ARG(const QVariant &, value)); } } + +void Settings::resetGatewayEndpoint() +{ + m_gatewayEndpoint = gatewayEndpoint; +} + +void Settings::setGatewayEndpoint(const QString &endpoint) +{ + m_gatewayEndpoint = endpoint; +} + +QString Settings::getGatewayEndpoint() +{ + return m_gatewayEndpoint; +} diff --git a/client/settings.h b/client/settings.h index 74d1b4b9..ee10c3b8 100644 --- a/client/settings.h +++ b/client/settings.h @@ -160,9 +160,6 @@ public: setValue("Conf/secondaryDns", secondaryDns); } - static const char cloudFlareNs1[]; - static const char cloudFlareNs2[]; - // static constexpr char openNicNs5[] = "94.103.153.176"; // static constexpr char openNicNs13[] = "144.76.103.143"; @@ -218,6 +215,10 @@ public: void setKillSwitchEnabled(bool enabled); QString getInstallationUuid(const bool needCreate); + void resetGatewayEndpoint(); + void setGatewayEndpoint(const QString &endpoint); + QString getGatewayEndpoint(); + signals: void saveLogsChanged(bool enabled); void screenshotsEnabledChanged(bool enabled); @@ -231,6 +232,8 @@ private: void setInstallationUuid(const QString &uuid); mutable SecureQSettings m_settings; + + QString m_gatewayEndpoint; }; #endif // SETTINGS_H diff --git a/client/translations/amneziavpn_ar_EG.ts b/client/translations/amneziavpn_ar_EG.ts index 9e101c2d..42ea2720 100644 --- a/client/translations/amneziavpn_ar_EG.ts +++ b/client/translations/amneziavpn_ar_EG.ts @@ -1,97 +1,145 @@ + + ApiServicesModel + + + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s + + + + + VPN to access blocked sites in regions with high levels of Internet censorship. + + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. + + + + + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship + + + + + %1 MBit/s + + + + + %1 days + + + + + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> + + + + + Free + + + + + %1 $/month + + + AppSplitTunnelingController Application added: %1 - + تمت إضافة التطبيق: %1 The application has already been added - + التطبيق مٌضاف بالفعل The selected applications have been added - + تمت إضافة التطبيقات المٌختارة Application removed: %1 - + تم حذف التطبيق: %1 ConnectButton - + Unable to disconnect during configuration preparation - + غير قادر علي قطع الاتصال اثناء إعداد التكوين ConnectionController - - - + + + Connect اتصل - + VPN Protocols is not installed. Please install VPN container at first لم يتم تثبيت بروتوكولات VPN, من فضلك قم بتنزيل حاوية VPN اولاً - + Connecting... اتصال... - + Connected تم الاتصال - + Reconnecting... إعادة الاتصال... - + Disconnecting... إنهاء الاتصال... - + Preparing... - + جاري التحضير... - + Settings updated successfully, reconnnection... تم تحديث الاعدادات بنجاح, جاري إعادة الاتصال... - + Settings updated successfully تم تحديث الاعدادات بنجاح - + The selected protocol is not supported on the current platform - البروتوكول المحدد غير مدعوم علي المنصة الحالية + البروتوكول المحدد غير مدعوم علي المنصة الحالية - + unable to create configuration - + غير قادر علي إنشاء تكوين @@ -130,7 +178,7 @@ &لصق - + &SelectAll &تحديد الكل @@ -148,11 +196,7 @@ Unable change protocol while there is an active connection - قم بتغيير البروتوكول عند تواجد اتصال - - - The selected protocol is not supported on the current platform - البروتوكول المحدد غير مدعوم علي المنصة الحالية + غير قادر علي تغيير البروتوكول اثناء تواجد اتصال @@ -207,13 +251,13 @@ Can't be disabled for current server Unable to open file - + غير قادر علي فتح الملف Invalid configuration file - + ملف تكوين غير صحيح @@ -223,38 +267,30 @@ Can't be disabled for current server In the imported configuration, potentially dangerous lines were found: - + في التكوين المستورد، تم العثور على سطور يحتمل أن تكون خطرة: InstallController - installed successfully. - تم التثبيت بنجاح - - - is already installed on the server. - بالفعل مٌثبت علي الخادم - - - + %1 installed successfully. %1 تم التثبيت بنجاح. - + %1 is already installed on the server. %1 بالفعل مٌثبت علي الخادم. - + Added containers that were already installed on the server تمت إضافة الحاويات التي كانت مٌثبتة بالفعل علي الخادم - + Already installed containers were found on the server. All installed containers have been added to the application @@ -262,78 +298,82 @@ Already installed containers were found on the server. All installed containers تمت إضافة جميع الحاويات المٌثبتة إلي التطبيق - + Settings updated successfully تم تحديث الاعدادات بنجاح - + Server '%1' was rebooted تمت إعادة تشغيل الخادم%1 - + Server '%1' was removed تمت إزالة الخادم '%1' - + All containers from server '%1' have been removed قد تم حذفها '%1' جميع الحاويات من الخادم - + %1 has been removed from the server '%2' %1 تم حدف '%2' اسم الخادم - - %1 cached profile cleared + + Api config removed - 1% has been removed from the server '%2' - %1 من الخادم '%2' تم مسحة + + %1 cached profile cleared + تم مسح ملف تعريف %1 المخزن مؤقتًا - Server ' - خادم - - - ' was removed - تم حذفة - - - has been removed from the server ' - قد تمت إزالتة من الخادم - - - + Please login as the user من فضلك قم بتسجيل الدخول كمستخدم - + Server added successfully تمت إضافة الخادم بنجاح + + + %1 installed successfully. + + + + + API config reloaded + + + + + Successfully changed the country of connection to %1 + + InstalledAppsDrawer - + Choose application - + اختر تطبيق - + application name - + اسم التطبيق - + Add selected - + اضف اختيارك @@ -386,45 +426,53 @@ Already installed containers were found on the server. All installed containers PageDeinstalling - + Removing services from %1 من %1 مسح الخدمة - + Usually it takes no more than 5 minutes في العادة تستغرق اقل من 5 دقائق - PageHome + PageDevMenu - - Logging enabled + + Gateway endpoint + + + PageHome - + + Logging enabled + تم تمكين التسجيل + + + Split tunneling enabled تقسيم الانفاق مٌفعل - + Split tunneling disabled تقسيم الانفاق مٌعطل - + VPN protocol بروتوكول VPN - + Servers الخوادم - + Unable change server while there is an active connection لا يمكن تغير الخادم بينما هناك اتصال مفعل @@ -432,354 +480,355 @@ Already installed containers were found on the server. All installed containers PageProtocolAwgSettings - + AmneziaWG settings اعدادات AmneziaWG - + Port منفذ - + MTU - + - Remove AmneziaWG - قم بحذف AmneziaWG - - - Remove AmneziaWG from server? - قم بحذف AmneziaWG من الخادم؟ - - - + All users with whom you shared a connection with will no longer be able to connect to it. جميع المستخدمين الذين شاركت معهم اتصال لن يكونو قادرين علي الاتصال مرة اخري. - + Save احفظ - + + Jc - Junk packet count + + + + + Jmin - Junk packet minimum size + + + + + Jmax - Junk packet maximum size + + + + + S1 - Init packet junk size + + + + + S2 - Response packet junk size + + + + + H1 - Init packet magic header + + + + + H2 - Response packet magic header + + + + + H4 - Transport packet magic header + + + + + H3 - Underload packet magic header + + + + The values of the H1-H4 fields must be unique - + يجب أن تكون قيم الحقول H1-H4 فريدة - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) - + يجب ألا تساوي قيمة الحقل S1 + حجم بدء الرسالة (148) S2 + حجم استجابة الرسالة (92) - + Save settings? احفظ الإعدادات؟ - + Continue واصل - + Cancel إلغاء - + Unable change settings while there is an active connection - + لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط PageProtocolCloakSettings - + Cloak settings Cloak إعدادات - + Disguised as traffic from متنكراً في حركة مرور من - + Port منفذ - + Cipher الشفرة - + Save احفظ - + Unable change settings while there is an active connection - + لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط PageProtocolOpenVpnSettings - + OpenVPN settings OpenVPN اعدادات - + VPN address subnet الشبكة الفرعية لعنوان VPN - + Network protocol بروتوكول الشبكة - + Port منفذ - + Auto-negotiate encryption التفاوض التلقائي علي الشبكة - + Hash - + SHA512 - + SHA384 - + SHA256 - + SHA3-512 - + SHA3-384 - + SHA3-256 - + whirlpool - + BLAKE2b512 - + BLAKE2s256 - + SHA1 - + Cipher شفرة - + AES-256-GCM - + AES-192-GCM - + AES-128-GCM - + AES-256-CBC - + AES-192-CBC - + AES-128-CBC - + ChaCha20-Poly1305 - + ARIA-256-CBC - + CAMELLIA-256-CBC - + none لا شئ - + TLS auth TLS مصادقة - + Block DNS requests outside of VPN احظر طلبات DNS خارج ال VPN - + Additional client configuration commands اوامر تكوين العميل الاضافية - - + + Commands: الاوامر: - + Additional server configuration commands اوامر تكوين الخادم الاضافية - + Unable change settings while there is an active connection - + لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط - Remove OpenVPN - احذف OpenVPN - - - Remove OpenVPN from server? - احذف OpenVPN من الخادم? - - - All users with whom you shared a connection with will no longer be able to connect to it. - جميع المستخدمين الذين شاركت معهم اتصال لن يكونو قادرين علي الاتصال مرة اخري. - - - + Save احفظ - - All users with whom you shared a connection will no longer be able to connect to it - جميع المستخدمين الذين شاركت اتصال معهم لن يستطيعو الاتصال بعد الان - - - Continue - واصل - - - Cancel - إلغاء - PageProtocolRaw - + settings إعدادات - + Show connection options اظهر اختيارات الاتصال - Connection options - اختيارات الاتصال - - - + Connection options %1 %1 اختيارات الاتصال - + Remove احذف - + Remove %1 from server? احذف %1 من الخادم ? - + All users with whom you shared a connection with will no longer be able to connect to it. جميع المستخدمين الذين شاركت معهم اتصال لن يكونو قادرين علي الاتصال مرة اخري. - from server? - من الخادم - - - All users with whom you shared a connection will no longer be able to connect to it - جميع المستخدمين الذين شاركت اتصال معهم لن يستطيعو الاتصال بعد الان - - - + Continue واصل - + Cancel إلغاء @@ -787,68 +836,56 @@ Already installed containers were found on the server. All installed containers PageProtocolShadowSocksSettings - + Shadowsocks settings Shadowsocks إعدادات - + Port منفذ - + Cipher تشفير - + Save احفظ - + Unable change settings while there is an active connection - + لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط PageProtocolWireGuardSettings - + WG settings - + إعدادات WG - + Port - منفذ + منفذ - + MTU - + - + Unable change settings while there is an active connection - + لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط - All users with whom you shared a connection will no longer be able to connect to it. - جميع المستخدمين الذين شاركت معاهم اتصال لن يستطيعو الاتصال بعد الان. - - - Continue - واصل - - - Cancel - إلغاء - - - + Save احفظ @@ -856,66 +893,62 @@ Already installed containers were found on the server. All installed containers PageProtocolXraySettings - + XRay settings - + إعدادات XRay - + Disguised as traffic from - متنكراً في حركة مرور من + متنكراً في حركة مرور من - + Save - احفظ + احفظ - + Unable change settings while there is an active connection - + لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط PageServiceDnsSettings - + A DNS service is installed on your server, and it is only accessible via VPN. تم تثبيت خدمة DNS علي الخادم الخاص بك, و فقط متاح من خلال VPN. - + The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab. عنوان ال DNS متطابق لنفس عنوان الخادم بك, يمكنك تهيئة DNS في الاعدادات, تحت علامة تبويب الاتصال. - + Remove احذف - + Remove %1 from server? احذف %1 ? - + Cannot remove AmneziaDNS from running server - + لا يمكن إزالة AmneziaDNS من الخادم قيد التشغيل - from server? - من الخادم - - - + Continue واصل - + Cancel إلغاء @@ -923,253 +956,218 @@ Already installed containers were found on the server. All installed containers PageServiceSftpSettings - + Settings updated successfully تم تحديث الإعدادات بنجاح - + SFTP settings SFTP إعدادات - + Host استضافة - - - - + + + + Copied تم الاستنساخ - + Port منفذ - + User name اسم المستخدم - + Password كلمة المرور - + Mount folder on device قم بتثبيت المجلد علي الجهاز - + In order to mount remote SFTP folder as local drive, perform following steps: <br> لتثبيت مجلد SFTP كمحرك اقراص محلي, اتبع هذه الخطوات : <br> - - + + <br>1. Install the latest version of <br>1. تحميل اخر اصدار من - - + + <br>2. Install the latest version of <br>2. تحمير اخر اصدار من - + Detailed instructions تعليمات مفصلة - - - Remove SFTP and all data stored there - امسح SFTP وجميع البيانات المخزنة - - - - Remove SFTP and all data stored there? - امسح SFTP وجميع البيانات المخزنة؟ - - - - Continue - واصل - - - - Cancel - إلغاء - PageServiceSocksProxySettings - + Settings updated successfully - + تم تحديث الإعدادات بنجاح - - + + SOCKS5 settings - + إعدادات SOCKS5 - + Host - استضافة + استضافة - - - - + + + + Copied - + تم النسخ - - + + Port - منفذ + منفذ - + User name - اسم المستخدم + اسم المستخدم - - + + Password - كلمة المرور + كلمة المرور - + Username - + اسم المستخدم - - + + Change connection settings - + تغيير إعدادات الاتصال - + The port must be in the range of 1 to 65535 - + يجب أن يكون المنفذ في النطاق من 1 إلى 65535 - + Password cannot be empty - + لا يمكن ان تكون كلمة المرور فارغة - + Username cannot be empty - + اسم المستخدم لا يمكن ان يكون فارغ PageServiceTorWebsiteSettings - + Settings updated successfully تم تحديث الإعدادات بنجاح - + Tor website settings Tor إعدادات متصفح - + Website address عنوان المتصفح - + Copied تم الاستنساخ - + Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL. - + After creating your onion site, it takes a few minutes for the Tor network to make it available for use. - + When configuring WordPress set the this onion address as domain. عند تكوين WordPress قم بتعيين عنوان ال onion هذا ك domain. - - - Remove website - احذف متصفح - - - - The site with all data will be removed from the tor network. - سيتم حذف الموقع وجميع البيانات من الشبكة. - - - - Continue - واصل - - - - Cancel - إلغاء - PageSettings - + Settings إعدادات - + Servers الخوادم - + Connection الاتصال - + Application تطبيق - + Backup نسخة احتياطية - + About AmneziaVPN عن AmneziaVPN + Dev console + + + + Close application إغلاق التطبيق @@ -1177,267 +1175,319 @@ Already installed containers were found on the server. All installed containers PageSettingsAbout - This is a free and open source application. If you like it, support the developers with a donation. -And if you don't like the app, all the more support it - the donation will be used to improve the app. - هذا تطبيق مجاني و مفتوح المصدر. إذا عجبك التطبيق, ادعم المطورين ب تبرع. - وإذا لما يعجبك, فهذا سبب اكبر لدعمة - تستخدم التبرعات في تطوير التطبيق - - - + Support Amnezia دعم Amenzia - + Amnezia is a free and open-source application. You can support the developers if you like it. هو تطبيق مجاني ومفتوح المصدر يمكنك دعم مطورين Amnezia إذا اعجبك. - + Contacts التواصل - + Telegram group مجموعة ال Telegram - + To discuss features لمناقشة الميزات - + https://t.me/amnezia_vpn_en - + Mail البريد - + For reviews and bug reports لل مراجعات والابلاغات عن المشاكل - + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client - + Website موقع - - https://amnezia.org - - - - + Software version: %1 %1 :إصدار البرنامج - + Check for updates تحقق من وجود تحديثات - + Privacy Policy سياسات الخصوصية - PageSettingsAppSplitTunneling + PageSettingsApiServerInfo - - Cannot change split tunneling settings during active connection - لا يمكن تغير إعدادات تقسيم الانفاق بينما هناك اتصال مٌفعل - - - - Only the apps from the list should have access via VPN + + For the region - - Apps from the list should not have access via VPN + + Price - - App split tunneling + + Work period - - Mode - وضع + + Speed + - - Remove - احذف + + Support tag + - + + Copied + + + + + Reload API config + + + + + Reload API config? + + + + + Continue واصل - + + Cancel إلغاء - - application name + + Cannot reload API config during active connection - - Open executable file + + Remove from application + + + Remove from application? + + + + + Cannot remove server during active connection + لا يمكن إزالة الخادم أثناء الاتصال النشط + + + + PageSettingsAppSplitTunneling + + + Cannot change split tunneling settings during active connection + لا يمكن تغير إعدادات تقسيم الانفاق بينما هناك اتصال مٌفعل + + + + Only the apps from the list should have access via VPN + يجب أن تتمتع التطبيقات الموجودة في القائمة فقط بإمكانية الوصول عبر VPN + + + + Apps from the list should not have access via VPN + لا يجب ان تتمتع التطبيقات في القائمة بولوج ل VPN + + + + App split tunneling + تقسيم نفق التطبيق + + + + Mode + وضع + + + + Remove + احذف + + + + Continue + واصل + + + + Cancel + إلغاء + + + + application name + اسم التطبيق + + Open executable file + افتح ملف قابل للتنفيذ + + + Executable files (*.*) - + ملفات قابلة للتنفيذ (*.*) PageSettingsApplication - + Application تطبيق - + Allow application screenshots اسمح بلقطات شاشة التطبيق - + Enable notifications - + تفعيل الإشعارات - + Enable notifications to show the VPN state in the status bar - + تفعيل الإشعارات لإظهار حالة ال VPN في شريط الحالة - + Auto start تشغيل تلقائي - Launch the application every time - شغل البرنامج كل مرة - - - starts - يبدأ - - - + Launch the application every time the device is starts قم بتشغيل التطبيق فكل مرة يتم فيها تشغيل الجهاز - + Auto connect اتصال تلقائي - + Connect to VPN on app start اتصل ب ال VPN عند تشغيل التطبيق - + Start minimized ابدأ ب الحجم الادني - + Launch application minimized تشغيل التطبيق في الحد الادني - + Language اللغة - + Logging تسجيل - + Enabled مٌفعل - + Disabled مٌعطل - + Reset settings and remove all data from the application إعادة ضبط الاعدادات ومسح جميع البيانات من التطبيق - + Reset settings and remove all data from the application? إعادة ضبط الاعدادات ومسح جميع البيانات من التطبيق؟ - + All settings will be reset to default. All installed AmneziaVPN services will still remain on the server. سيتم ضبط الاعدادات الافتراضية. جميع خدمات AmneziaVPN المٌثبتة ستبقي علي الخادم. - + Continue واصل - + Cancel إلغاء - + Cannot reset settings during active connection - + لا يمكن إعادة ضبط الإعدادات اثناء تواجد اتصال فعال PageSettingsBackup - + Settings restored from backup file تم إعادة الاعدادات من ملف نسخة احتياطية - - It will help you instantly restore connection settings at the next installation - سيساعدك علي إعادة إعدادات الاتصال بسرعة عند إعادة تثبيت التطبيق - Back up your configuration @@ -1507,147 +1557,131 @@ And if you don't like the app, all the more support it - the donation will Cannot restore backup settings during active connection - + لا يمكن استعادة إعدادات النسخ الاحتياطي أثناء الاتصال النشط PageSettingsConnection - + Connection الاتصال - + When AmneziaDNS is not used or installed عندما يكون AmneziaDNS غير مٌثبت او غير مستخدم - + Allows you to use the VPN only for certain Apps يسمح لك بأستخدام ال VPN علي تطبيقات معينة - Use AmneziaDNS if installed on the server - استخدم AmneziaDNS إذا كان مٌثبت علي الخادم - - - + Use AmneziaDNS استخدم AmneziaDNS - + If AmneziaDNS is installed on the server في حالة كان AmneziaDNS مٌثبت علي الخادم - + DNS servers خوادم DNS - + Site-based split tunneling انقسام الانفاق القائم علي الموقع - + Allows you to select which sites you want to access through the VPN يسمح لك بتحديد اي موقع تريد الوصول له عن طريق ال VPN - + App-based split tunneling انقسام الانفاق القائم علي التطبيق - - - KillSwitch - - + KillSwitch + + + + Disables your internet if your encrypted VPN connection drops out for any reason. - + يعطل اتصال الإنترنت الخاص بك إذا انقطع اتصال VPN المشفر لأي سبب من الأسباب. - + Cannot change killSwitch settings during active connection - - - - Split site tunneling - قسم نفق الموقع - - - Allows you to connect to some sites through a secure connection, and to others bypassing it - يسمحلك بألاتصال ببعض المواقع بسرية, وعلي الاخرين تجاوزه - - - Separate application tunneling - فرق نفق التطبيق + لا يمكن تغيير إعدادات KillSwitch اثناء تواجد اتصال فعال PageSettingsDns - + Default server does not support custom DNS الخادم الافتراضي لا يدعم DNS مخصص - + DNS servers خوادم ال DNS - + If AmneziaDNS is not used or installed AmneziaVPN ليس مٌستخدم او مٌثبت - + Primary DNS الرئيسي DNS - + Secondary DNS الثانوي DNS - + Restore default استعادة الافتراضي - + Restore default DNS settings? قم بأعادة ضبط إعدادات ال DNS الافتراضية؟ - + Continue واصل - + Cancel إلغاء - + Settings have been reset لم يتم إعادة ضبط الإعدادات - + Save احفظ - + Settings saved تم حفظ الإعدادات @@ -1655,72 +1689,72 @@ And if you don't like the app, all the more support it - the donation will PageSettingsLogging - + Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - + تم تمكين التسجيل. لاحظ أنه سيتم تعطيل السجلات تلقائيًا بعد 14 يومًا، وسيتم حذف جميع ملفات السجل. - + Logging التسجيل - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. سيتم حفظ سجلات البرنامج بشكل تلقائي عند تفعيل هذه الميزة, بشكل افتراضي, هذه الميزة مٌعطلة. قم بتفعيل هذه الميزة في حالة هناك خلل في التطبيق. - + Save logs احفظ السجلات - + Open folder with logs افتح مجلد يحتوي علي سجلات - + Save احفظ - + Logs files (*.log) ملفات الولوج (*.log) - + Logs file saved تم حفظ ملف السجل - + Save logs to file احفظ السجلات في ملف - + Clear logs? مسح السجلات؟ - + Continue واصل - + Cancel إلغاء - + Logs have been cleaned up تم مسح السجلات - + Clear logs احذف السجلات @@ -1728,34 +1762,22 @@ And if you don't like the app, all the more support it - the donation will PageSettingsServerData - + All installed containers have been added to the application تمت إضافة جميع الحاويات المٌثبتة للتطبيق - + No new installed containers found لم يتم العثور علي اي حاويات جديدة مٌثبتة - Clear Amnezia cache - حذف ذاكرة تخزين Amnezia المؤقتة - - - May be needed when changing other settings - قد يكون ضروري عند تغير الإعدادات الاخري - - - Clear cached profiles? - حذف الملفات الشخصية المخزنة مؤقتاً؟ - - - + Do you want to reboot the server? هل تريد إعادة تشغيل الخادم؟ - + Do you want to clear server from Amnezia software? هل تريد حذف الخادم من Amnezia? @@ -1764,94 +1786,94 @@ And if you don't like the app, all the more support it - the donation will - - - - - - Continue - واصل - + Continue + واصل + + + + + + Cancel إلغاء - + Check the server for previously installed Amnezia services افحص الخادم عن اي خدمات Amnezia مٌثبتة سابقاُ - + Add them to the application if they were not displayed اضفهم إلي التطبيق إذا لم يكونو ظاهرين - + Reboot server إعادة تشغيل الخادم - + The reboot process may take approximately 30 seconds. Are you sure you wish to proceed? عملية إعادة التشغيل قد تستغرق 30 ثانية, هل تريد الاستكمال؟ - + Cannot reboot server during active connection - + لا يمكن إعادة تشغيل الخادم أثناء الاتصال النشط - + Remove server from application احذف خادم من التطبيق - + Do you want to remove the server from application? هل تريد حذف الخادم من التطبيق؟ - + Cannot remove server during active connection - + لا يمكن إزالة الخادم أثناء الاتصال النشط - + All users whom you shared a connection with will no longer be able to connect to it. جميع المستخدمين الذين شاركت معهم اتصال لن يستطيعو الاتصال مرة اخري. - + Cannot clear server from Amnezia software during active connection - + لا يمكن مسح الخادم من برنامج Amnezia أثناء الاتصال النشط - + Reset API config إعادة تكوين API - + Do you want to reset API config? هل تريد إعادة تكوين API? - + Cannot reset API config during active connection - + لا يمكن إعادة تعيين تكوين API أثناء الاتصال النشط - + All installed AmneziaVPN services will still remain on the server. جميع خدمات AmneziaVPN المٌثبتة ستظل علي الخادم. - + Clear server from Amnezia software احذف خادم من Amnezia @@ -1859,27 +1881,27 @@ And if you don't like the app, all the more support it - the donation will PageSettingsServerInfo - + Server name اسم الخادم - + Save احفظ - + Protocols البروتوكولات - + Services الخدمات - + Management الإدارة @@ -1887,67 +1909,59 @@ And if you don't like the app, all the more support it - the donation will PageSettingsServerProtocol - + settings الإعدادات - + Clear %1 profile - + مسح ملف تعريف %1 - + Clear %1 profile? - + مسح ملف تعريف %1؟ - + - + Unable to clear %1 profile while there is an active connection - + غير قادر على مسح ملف تعريف %1 أثناء وجود اتصال نشط - + Remove احذف - + + Remove %1 from server? + + + + All users with whom you shared a connection will no longer be able to connect to it. جميع المستخدمين الذين شاركت معاهم اتصال لن يستطيعو الاتصال بعد الان. - + Cannot remove active container - + لا يمكن إزالة الحاوية النشطة - from server? - من الخادم؟ - - - - Remove %1 from server? - احذف %1 من الخادم ? - - - All users with whom you shared a connection will no longer be able to connect to it - جميع المستخدمين الذين شاركت اتصال معهم لن يستطيعو الاتصال بعد الان - - - - + + Continue واصل - - + + Cancel إلغاء @@ -1955,7 +1969,7 @@ And if you don't like the app, all the more support it - the donation will PageSettingsServersList - + Servers الخوادم @@ -1963,221 +1977,322 @@ And if you don't like the app, all the more support it - the donation will PageSettingsSplitTunneling - Only the addresses in the list must be opened via VPN - يجب فتح العنواين التي في القائمة عبر VPN - - - Addresses from the list should never be opened via VPN - لا يجب ابداً فتح العنواين التي في القائمة عن طريق VPN - - - Split site tunneling - قسم نفق الموقع - - - + Default server does not support split tunneling function السرفر الافتراضي لا يدعم ميزة تقسيم الانفاق - + Addresses from the list should not be accessed via VPN لا يجب الولوج للعنواين المذكورة هنا من خلال ال VPN - + Split tunneling تقسيم الانفاق - + Mode وضع - + Remove احذف - + Continue واصل - + Cancel إلغاء - + Only the sites listed here will be accessed through the VPN سيتم الولوج للمواقع المذكورة هنا فقط عن طريق ال VPN - + Cannot change split tunneling settings during active connection لا يمكن تغير إعدادات تقسيم الانفاق بينما هناك اتصال مٌفعل - + website or IP موقع او IP - + Import / Export Sites - + Import استرد - + Save site list احفظ قائمة المواقع - + Save sites احفظ المواقع - - - + + + Sites files (*.json) - + Import a list of sites استرد قائمة من المواقع - + Replace site list تبديل قائمة المواقع - - + + Open sites file افتح ملف المواقع - + Add imported sites to existing ones إضافة المواقع المستردة للمواقع الموجودة + + PageSetupWizardApiServiceInfo + + + For the region + + + + + Price + + + + + Work period + + + + + Speed + + + + + Features + + + + + Connect + اتصل + + + + PageSetupWizardApiServicesList + + + VPN by Amnezia + + + + + Choose a VPN service that suits your needs. + + + PageSetupWizardConfigSource - Server connection - اتصال الخادم + اتصال الخادم - Do not use connection code from public sources. It may have been created to intercept your data. - -It's okay as long as it's from someone you trust. - لا تستخدم رمز الاتصال من المصادر العامة. ربما تم إنشاؤه لاعتراض بياناتك - -لا بأس طالما انه من شخص تثق به. - - - Do not use connection codes from untrusted sources, as they may be created to intercept your data. - لا تستخدم رموز اتصال من مصادر غير موثوقة, حيث قد يكون تم إنشاؤها لاعتراض بياناتك. + لا تستخدم رموز اتصال من مصادر غير موثوقة, حيث قد يكون تم إنشاؤها لاعتراض بياناتك. - What do you have? - ماذا لديك؟ + ماذا لديك؟ - File with connection settings or backup - ملف إعدادات اتصال او نسخ احتياطي + ملف إعدادات اتصال او نسخ احتياطي + + + + Connection + الاتصال + + + + Insert the key, add a configuration file or scan the QR-code + + Insert key + + + + + Insert + ادخل + + + + Continue + واصل + + + + Other connection options + + + + + VPN by Amnezia + + + + + Connect to classic paid and free VPN services from Amnezia + + + + + Self-hosted VPN + + + + + Configure Amnezia VPN on your own server + + + + + Restore from backup + استرجاع من ملف يحتوي علي نسخة احتياطية + + + + Open backup file + افتح ملف نسخ احتياطي + + + + Backup files (*.backup) + ملفات نٌسخ احتياطية (*.backup) + + + File with connection settings ملف إعدادات اتصال - + Open config file افتح ملف تكوين - + QR code رمز QR - + + I have nothing + ليس لدي اي شئ + + Key as text - مفتاح كنص + مفتاح كنص PageSetupWizardCredentials - + Configure your server تكوين الخادم الخاص بك - + Server IP address [:port] عنوان خادم IP [:منفذ] - + Continue واصل - + All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties ستظل جميع البيانات التي تدخلها سرية للغاية ولن تتم مشاركتها أو الكشف عنها ل Amnezia أو أي طرف ثالث - + 255.255.255.255:22 - + SSH Username - + Password or SSH private key كلمة مرور او مفتاح SSH خاص - + + How to run your VPN server + + + + + Where to get connection data, step-by-step instructions for buying a VPS + + + + Ip address cannot be empty لا يمكن لعنوان IP ان يكون فارغ - + Enter the address in the format 255.255.255.255:88 ادخل العنوان في شكل 255.255.255.255:88 - + Login cannot be empty تسجيل دخول لا يمكن ان يكون فارغ - + Password/private key cannot be empty كلمة مرور/مفتاح خاص لأ يمكن ان يكونو فارغين @@ -2185,22 +2300,22 @@ It's okay as long as it's from someone you trust. PageSetupWizardEasy - + What is the level of internet control in your region? ما هو مستوي التحكم في الانترنت في منطقتك؟ - + Choose a VPN protocol اختر بروتوكول VPN - + Skip setup تخطي الإعداد - + Continue واصل @@ -2208,38 +2323,38 @@ It's okay as long as it's from someone you trust. PageSetupWizardInstalling - - + + Usually it takes no more than 5 minutes عادة لا تستغرق اكثر من 5 دقائق - + The server has already been added to the application تمت إضافة الخادم بالفعل للتطبيق - + Amnezia has detected that your server is currently اكتشف Amnezia الخادم الخاص بك موجود حاليًا - + busy installing other software. Amnezia installation مشغول بتثبيت برامج اخري, تثبيت Amnezia - + Cancel installation إلغاء التثبيت - + will pause until the server finishes installing other software سيتوقف مؤقتًا حتى ينتهي الخادم من تثبيت البرامج الأخرى - + Installing جاري التثبيت @@ -2247,50 +2362,50 @@ It's okay as long as it's from someone you trust. PageSetupWizardProtocolSettings - + Installing %1 تثبيت %1 - + More detailed اكثر تفصيلاً - + Close اغلق - + Network protocol بروتوكول شبكة - + Port منفذ - + Install تثبيت - + The port must be in the range of 1 to 65535 - + يجب أن يكون المنفذ في النطاق من 1 إلى 65535 PageSetupWizardProtocols - + VPN protocol VPN بروتوكول - + Choose the one with the highest priority for you. Later, you can install other protocols and additional services, such as DNS proxy and SFTP. اختر بالنسبة للأولوية القصوى بالنسبة لك. ويمكنك لاحقًا تثبيت بروتوكولات وخدمات إضافية أخرى، مثل وكيل DNS وSFTP. @@ -2298,7 +2413,7 @@ It's okay as long as it's from someone you trust. PageSetupWizardQrReader - + Point the camera at the QR code and hold for a couple of seconds. قم بتوجيه الكاميرا نحو رمز QR و اثبت لبضع ثوان. @@ -2306,61 +2421,56 @@ It's okay as long as it's from someone you trust. PageSetupWizardStart - Settings restored from backup file - تم استرداد الإعدادات من ملف نسخة احتياطية + تم استرداد الإعدادات من ملف نسخة احتياطية - Free service for creating a personal VPN on your server. - خدمة مجانية لأنشاء VPN شخصي علي الخادم الشخصي. + خدمة مجانية لأنشاء VPN شخصي علي الخادم الشخصي. - Helps you access blocked content without revealing your privacy, even to VPN providers. - يساعدك في الولوج للمحتوي المحظور بدون إظهار خصوصيات, حتي لمزود ال VPN. + يساعدك في الولوج للمحتوي المحظور بدون إظهار خصوصيات, حتي لمزود ال VPN. - I have the data to connect - لدي البيانات المطلوبة للأتصال + لدي البيانات المطلوبة للأتصال - I have nothing - ليس لدي اي شئ + ليس لدي اي شئ - - https://amnezia.org/instructions/0_starter-guide - + + Let's get started + PageSetupWizardTextKey - + Connection key مفتاح اتصال - + A line that starts with vpn://... يجب ان تٌكتب بهذه الطريقة حتي بوجود التحذير كي تظهر بشكل صحيح داخل التطبيق سطر يبدأ ب ...//:vpn - + Key مفتاح - + Insert ادخل - + Continue واصل @@ -2368,32 +2478,32 @@ It's okay as long as it's from someone you trust. PageSetupWizardViewConfig - + New connection اتصال جديد - + Collapse content طي المحتوي - + Show content اظهر المحتوي - + Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider. - + تمكين تشويش WireGuard. قد يكون من المفيد إذا تم حظر WireGuard على مزود الخدمة الخاص بك. - + Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data. استخدم رموز اتصال فقط من المصادر التي تثق بها, ربما تم إنشاء رموز من مصادر عامة لاعتراض بياناتك. - + Connect اتصل @@ -2401,223 +2511,207 @@ It's okay as long as it's from someone you trust. PageShare - + Save OpenVPN config احفظ تكوين OpenVPN - + Save WireGuard config احفظ تكوين WireGuard - + Save AmneziaWG config احفظ تكوين AmneziaWG - + Save Shadowsocks config احفظ تكوين Shadowsocks - + Save Cloak config احفظ تكوين Cloak - + Save XRay config - + حفظ تكوين XRay - + For the AmneziaVPN app AmneziaVPN من اجل تطبيق - + OpenVPN native format تنسيق OpenVPN الاصلي - + WireGuard native format تنسيق WireGuard الاصلي - + AmneziaWG native format تنسيق AmneziaWG اصلي - + Shadowsocks native format تنسيق Shadowsocks الاصلي - + Cloak native format تنسيق Cloak الاصلي - + XRay native format - + الشكل الاصلي ل XRay - + Share VPN Access شارك اتصال VPN - + Share full access to the server and VPN شارك ولوج كامل للخادم و ال VPN - + Use for your own devices, or share with those you trust to manage the server. استخدمه للأجهزة الخاصة بك، أو شاركه مع من تثق بهم لإدارة الخادم. - - + + Users المستخدمين - + Share VPN access without the ability to manage the server شارك اتصال VPN بدون القدرة علي إدارة الخادم - + Search ابحث - + Creation date: %1 - + تاريخ الإنشاء: %1 - + Latest handshake: %1 - + اخر تصافح: %1 - + Data received: %1 - + البيانات المستلمة: %1 - + Data sent: %1 - + البيانات المٌرسلة: %1 - Creation date: - تاريخ الإنشاء: - - - + Rename إعادة التسمية - + Client name اسم العميل - + Save احفظ - + Revoke سحب وإبطال - + Revoke the config for a user - %1? سحب وإبطال للمستخدم - %1? - + The user will no longer be able to connect to your server. المستخدم لن يكون قادر علي الاتصال بعد الان. - + Continue واصل - + Cancel إلغاء - + Connection الاتصال - Full access to server - ولوج كامل للخادم - - - Servers - الخوادم - - - - + + Server خادم - + File with connection settings to ملف بإعدادات إلي - Protocols - البروتوكولات - - - - + + Protocol بروتوكول - + Connection to اتصال إلي - + Config revoked تم سحب وإبطال التكوين - + User name اسم المستخدم - - + + Connection format تنسيق الاتصال - - + + Share شارك @@ -2625,50 +2719,50 @@ It's okay as long as it's from someone you trust. PageShareFullAccess - + Full access to the server and VPN ولوج كامل للخادم و ال VPN - + We recommend that you use full access to the server only for your own additional devices. نحن ننصحك بأستخدام ولوج كامل للخادم فقط لأجهزتك الاضافية. - + If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. إذا شاركت ولوج كامل مع الاشخاص, سيكونو قادرين علي حذف وإضافة بروتوكولات و خدمات إلي الخادم, والذي سيجعل VPN يعمل بشكل غير صحيح لجميع المستخدمين. - + Server خادم - + Accessing التواصل - + File with accessing settings to ملف مع إعدادات الوصول إلي - + Share مشاركة - + Connection to اتصال إلي - + File with connection settings to معلف مع إعدادات الاتصال إلي @@ -2676,15 +2770,20 @@ It's okay as long as it's from someone you trust. PageStart - + Logging was disabled after 14 days, log files were deleted + تم تعطيل التسجيل بعد 14 يومًا، وتم حذف ملفات السجل + + + + Settings restored from backup file PopupType - + Close اغلاق @@ -2936,7 +3035,7 @@ It's okay as long as it's from someone you trust. SOCKS5 proxy server - + @@ -3014,50 +3113,6 @@ It's okay as long as it's from someone you trust. Timeout connecting to server انتهت مدة الاتصال بالخادم - - Sftp error: File does not exist - خطأ Sftp: الملف غير موجود - - - Sftp error: Permission denied - خطأ Sftp: تم حظر الصلحيات - - - Sftp error: Generic failure - خطأ Sftp: فشل عام - - - Sftp error: Garbage received from server - خطأ Sftp: تم استلام نفايات من الخادم - - - Sftp error: No connection has been set up - خطأ Sftp: لم يتم إعداد اتصال - - - Sftp error: There was a connection, but we lost it - خطأ Sftp: كان هناك اتصال, ولكن خسرناه - - - Sftp error: Operation not supported by libssh yet - خطأ Sftp: العملية ليست مدعومة من libssh بعد - - - Sftp error: No such file or directory path exists - خطأ Sftp: لا يوجد مسار ملف او مجلد مثل هذا - - - Sftp error: An attempt to create an already existing file or directory has been made - خطأ Sftp: محاولة إنشاء ملف او مجلد موجود بالفعل - - - Sftp error: Write-protected filesystem - خطأ Sftp: نظام كتابة الملفات محمي - - - Sftp error: No media was in remote drive - خطأ Sftp: لا يوجد وسائط في القرص البعيد - VPN connection error @@ -3074,7 +3129,7 @@ It's okay as long as it's from someone you trust. هذا التكوين بالفعل تمت إضافتة للبرنامج - + ErrorCode: %1. @@ -3086,17 +3141,17 @@ It's okay as long as it's from someone you trust. Background service is not running - + خدمة الخلفية ليست قيد التشغيل Server error: Packet manager error - + خطأ في الخادم: خطأ في مدير الحزم SCP error: Generic failure - + خطأ SCP: فشل عام @@ -3151,50 +3206,55 @@ It's okay as long as it's from someone you trust. In the response from the server, an empty config was received - + في الاستجابة من الخادم، تم تلقي تكوين فارغ SSL error occurred - + حدث خطأ SSL Server response timeout on api request - + انتهت مهلة استجابة الخادم عند طلب واجهة برمجة التطبيقات - - QFile error: The file could not be opened + + Missing AGW public key - QFile error: An error occurred when reading from the file - + QFile error: The file could not be opened + خطأ QFile: لا يمكن فتح الملف - QFile error: The file could not be accessed - + QFile error: An error occurred when reading from the file + خطأ QFile: ظهر خطأ اثناء القراءه من الملف - QFile error: An unspecified error occurred - + QFile error: The file could not be accessed + خطأ QFile: لا يمكن الوصول للملف - QFile error: A fatal error occurred - + QFile error: An unspecified error occurred + خطأ QFile: ظهر خطأ غير محدد - QFile error: The operation was aborted - + QFile error: A fatal error occurred + خطأ QFile: حدث خطأ فادح - + + QFile error: The operation was aborted + خطأ QFile: تم إحباط العملية + + + Internal error خطأ داخلي @@ -3239,12 +3299,12 @@ It's okay as long as it's from someone you trust. XRay with REALITY - Suitable for countries with the highest level of internet censorship. Traffic masking as web traffic at the TLS level, and protection against detection by active probing methods. - + الأشعة السينية مع الواقع - مناسبة للبلدان التي لديها أعلى مستوى من الرقابة على الإنترنت. إخفاء حركة المرور كحركة مرور على الويب على مستوى TLS، والحماية من الكشف عن طريق طرق التحقيق النشطة. IKEv2/IPsec - Modern stable protocol, a bit faster than others, restores connection after signal loss. It has native support on the latest versions of Android and iOS. - + IKEv2/IPsec - بروتوكول مستقر حديث، أسرع قليلاً من البروتوكولات الأخرى، يستعيد الاتصال بعد فقدان الإشارة. يتمتع بدعم أصلي على أحدث إصدارات Android وiOS. @@ -3319,7 +3379,10 @@ WireGuard is very susceptible to blocking due to its distinct packet signatures. It uniquely identifies censors during the TLS handshake phase, seamlessly operating as a proxy for legitimate clients while diverting censors to genuine websites like google.com, thus presenting an authentic TLS certificate and data. This advanced capability differentiates REALITY from similar technologies by its ability to disguise web traffic as coming from random, legitimate sites without the need for specific configurations. Unlike older protocols such as VMess, VLESS, and the XTLS-Vision transport, REALITY's innovative "friend or foe" recognition at the TLS handshake enhances security and circumvents detection by sophisticated DPI systems employing active probing techniques. This makes REALITY a robust solution for maintaining internet freedom in environments with stringent censorship. - + تم تصميم بروتوكول REALITY، وهو تطور رائد قام به مبدعو XRay، خصيصًا لمواجهة أعلى مستويات الرقابة على الإنترنت من خلال نهجه الجديد في التهرب. +فهو يحدد بشكل فريد الرقباء أثناء مرحلة مصافحة TLS، ويعمل بسلاسة كوكيل للعملاء الشرعيين بينما يحول الرقباء إلى مواقع الويب الأصلية مثل google.com، وبالتالي يقدم شهادة وبيانات TLS أصلية. +هذه الإمكانية المتقدمة تميز REALITY عن التقنيات المشابهة من خلال قدرتها على إخفاء حركة مرور الويب على أنها قادمة من مواقع عشوائية وشرعية دون الحاجة إلى تكوينات محددة. +على عكس البروتوكولات القديمة مثل VMess وVLESS ونقل XTLS-Vision، فإن التعرف المبتكر على "الصديق أو العدو" من REALITY عند مصافحة TLS يعزز الأمان ويتحايل على الكشف بواسطة أنظمة DPI المتطورة التي تستخدم تقنيات التحقيق النشطة. وهذا يجعل من REALITY حلاً قويًا للحفاظ على حرية الإنترنت في البيئات التي تخضع لرقابة صارمة. @@ -3350,10 +3413,6 @@ For more detailed information, you can AmneziaWG - Special protocol from Amnezia, based on WireGuard. It's fast like WireGuard, but very resistant to blockages. Recommended for regions with high levels of censorship. بروتوكول AmneziaWG - بروتوكول خاص من Amnezia, يعتمد علي WireGuard. سريع مثل WireGuard, لكن مقاوم جداً للحجب. ينصح للمناطق ذات مستوي عالي من الرقابة. - - IKEv2/IPsec - Modern stable protocol, a bit faster than others, restores connection after signal loss. - بروتوكول IKEv2/IPsec - بروتوكول مستقر حديث, اسرع بقليل من الباقي, يسترجع الاتصال بعد خسارة الاشارة. - Deploy a WordPress site on the Tor network in two clicks. @@ -3502,139 +3561,139 @@ While it offers a blend of security, stability, and speed, it's essential t vmess:// url is invalid - + عنوان //:vmess غير صحيح Invalid streamSettings protocol: - + بروتوكول streamSettings غير صحيح: Unknown transport method: - + طريقة نقل غير معروفة: VMess string should start with 'vmess://' - + نص VMess يجب ان يبدأ ب '//:vmess' VMess string should be a valid base64 string - + نص VMess يجب ان يكون نص base64 صحيح JSON should not be empty - + لا يجب ان يكون JSON فارغ VLESS link should start with vless:// - + رابط VLESS يجب ان يبدأ ب //:vless link parse failed: %1 - + فشل تحليل الرابط: %1 empty host - + مضيف فارغ missing port - + منفذ مفقود missing uuid - + uuid مفقود Invalid ssd link: json: field %1 must exist - + رابط ssd غير صالح: json: يجب أن يكون الحقل %1 موجودًا Invalid ssd link: json: field %1 must be valid port number - + رابط ssd غير صالح: json: الحقل %1 يجب أن يكون رقم منفذ صالحًا Invalid ssd link: json: field %1 must be of type 'string' - + رابط ssd غير صالح: json: يجب أن يكون الحقل %1 من النوع "string" Invalid ssd link: json: field %1 must be an array - + رابط ssd غير صالح: json: الحقل %1 يجب أن يكون قائمة Skipping invalid ssd server: server must be an object - + تخطي خادم ssd غير صالح: يجب أن يكون الخادم كائنًا Skipping invalid ssd server: missing required field %1 - + تخطي خادم ssd غير صالح: الحقل المطلوب %1 مفقود Skipping invalid ssd server: field %1 should be of type 'string' - + تخطي خادم ssd غير صالح: يجب أن يكون الحقل %1 من النوع "string" Invalid ssd link: should begin with ssd:// - + رابط ssd غير صالح: يجب أن يبدأ بـ //:ssd Invalid ssd link: base64 parse failed - + رابط SSD غير صالح: فشل تحليل Base64 Invalid ssd link: json parse failed - + رابط ssd غير صالح: فشل تحليل json Invalid ssd link: rc4-md5 encryption is not supported by v2ray-core - + رابط ssd غير صالح: تشفير rc4-md5 غير مدعوم بواسطة v2ray-core SS URI is too short - + عنوان SS قصير جداً Can't find the colon separator between method and password - + لا يمكن العثور على فاصل النقطتين بين method وكلمة المرور Can't find the at separator between password and hostname - + لا يمكن العثور على فاصل النقطتين بين كلمة المرور وكلمة واسم المستضيف Can't find the colon separator between hostname and port - + لا يمكن العثور على فاصل النقطتين بين اسم المستضيف و المنفذ SelectLanguageDrawer - + Choose language اختر لغة @@ -3642,13 +3701,13 @@ While it offers a blend of security, stability, and speed, it's essential t Settings - + Server #1 خادم #1 - - + + Server خادم @@ -3665,51 +3724,43 @@ While it offers a blend of security, stability, and speed, it's essential t All settings have been reset to default values تم استرجاع جميع الإعدادات للإعدادات الافتراضية - - Cached profiles cleared - تم حذف الملفات الشخصية المٌخزنة مؤقتاُ - ShareConnectionDrawer - - + + Save AmneziaVPN config احفظ تكوين AmneziaVPN - + Share شارك - + Copy انسخ - - + + Copied تم النسخ - + Copy config string انسخ نص التكوين - + Show connection settings اظهر إعدادات الاتصال - Show content - 展示内容 - - - + To read the QR code in the Amnezia app, select "Add server" → "I have data to connect" → "QR code, key or settings file" حتي تقرأ رمز ال QR في تطبيق Amnezia, اختار "إضافة خادم" - "لدي بيانات الاتصال" - "رمز Qr, او مفتاح تعريف او ملف إعدادات" @@ -3793,7 +3844,7 @@ While it offers a blend of security, stability, and speed, it's essential t TextFieldWithHeaderType - + The field can't be empty الحقل لا يمكن ان يكون فارغ @@ -3852,43 +3903,35 @@ While it offers a blend of security, stability, and speed, it's essential t amnezia::ContainerProps - + Low منخفض - + High متوسط او عالي - Extreme - شديد - - - + I just want to increase the level of my privacy. انا فقط اريد زيادة مستوي الخصوصية. - + I want to bypass censorship. This option recommended in most cases. أريد تجاوز الرقابة. يوصى بهذا الخيار في معظم الحالات. - - Most VPN protocols are blocked. Recommended if other options are not working. - يتم حظر معظم بروتوكولات VPN. يوصى به إذا كانت الخيارات الأخرى لا تعمل. - main2 - + Private key passphrase عبارة المرور الخاصة بالمفتاح - + Save احفظ diff --git a/client/translations/amneziavpn_fa_IR.ts b/client/translations/amneziavpn_fa_IR.ts index 0b5b264c..5b2c5818 100644 --- a/client/translations/amneziavpn_fa_IR.ts +++ b/client/translations/amneziavpn_fa_IR.ts @@ -1,6 +1,54 @@ + + ApiServicesModel + + + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s + + + + + VPN to access blocked sites in regions with high levels of Internet censorship. + + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. + + + + + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship + + + + + %1 MBit/s + + + + + %1 days + + + + + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> + + + + + Free + + + + + %1 $/month + + + AppSplitTunnelingController @@ -27,7 +75,7 @@ ConnectButton - + Unable to disconnect during configuration preparation @@ -35,63 +83,63 @@ ConnectionController - + VPN Protocols is not installed. Please install VPN container at first پروتکل وی‎پی‎ان نصب نشده است لطفا کانتینر وی‎پی‎ان را نصب کنید - + Connecting... در حال ارتباط... - + Connected متصل - + Preparing... - + Settings updated successfully, reconnnection... تنظیمات به روز رسانی شد در حال اتصال دوباره... - + Settings updated successfully تنظیمات با موفقیت به‎روز‎رسانی شدند - + The selected protocol is not supported on the current platform پروتکل انتخاب شده بر روی این پلتفرم پشتیبانی نمی‎‎شود - + unable to create configuration - + Reconnecting... اتصال دوباره... - - - + + + Connect اتصال - + Disconnecting... قطع ارتباط... @@ -132,7 +180,7 @@ &پیوست - + &SelectAll &انتخاب همه @@ -230,84 +278,104 @@ Can't be disabled for current server InstallController - + %1 installed successfully. %1 با موفقیت نصب شد. - + %1 is already installed on the server. %1 در حال حاضر بر روی سرور نصب شده است. - + Added containers that were already installed on the server کانتینرهایی که بر روی سرور موجود بودند اضافه شدند - + Already installed containers were found on the server. All installed containers have been added to the application کانتینرهای نصب شده بر روی سرور شناسایی شدند. تمام کانتینترهای نصب شده به نرم افزار اضافه شدند - + Settings updated successfully تنظیمات با موفقیت به‎روز‎رسانی شدند - + Server '%1' was rebooted سرور %1 راه اندازی مجدد شد - + Server '%1' was removed سرور %1 حذف شد - + All containers from server '%1' have been removed تمام کانتینترها از سرور %1 حذف شدند - + %1 has been removed from the server '%2' %1 از سرور %2 حذف شد - + + Api config removed + + + + %1 cached profile cleared - + Please login as the user لطفا به عنوان کاربر وارد شوید - + Server added successfully سرور با موفقیت اضافه شد + + + %1 installed successfully. + + + + + API config reloaded + + + + + Successfully changed the country of connection to %1 + + InstalledAppsDrawer - + Choose application - + application name - + Add selected @@ -362,45 +430,53 @@ Already installed containers were found on the server. All installed containers PageDeinstalling - + Removing services from %1 حذف سرویس‎ها از %1 - + Usually it takes no more than 5 minutes معمولا بیش از 5 دقیقه طول نمی‎کشد + + PageDevMenu + + + Gateway endpoint + + + PageHome - + Logging enabled - + Split tunneling enabled فعال شدن تونل تقسیم‌شده - + Split tunneling disabled تونل تقسیم‌شده غیرفعال شده - + VPN protocol پروتکل وی‎پی‎ان - + Servers سرورها - + Unable change server while there is an active connection امکان تغییر سرور در هنگام متصل بودن وجود ندارد @@ -408,17 +484,17 @@ Already installed containers were found on the server. All installed containers PageProtocolAwgSettings - + AmneziaWG settings تنظیمات AmneziaWG - + Port پورت - + MTU @@ -431,42 +507,87 @@ Already installed containers were found on the server. All installed containers آیا میخواهید AmneziaWG از سرور حذف شود؟ - + All users with whom you shared a connection with will no longer be able to connect to it. همه کاربرانی که با آن‌ها ارتباطی به اشتراک گذاشته‌اید دیگر قادر به اتصال به آن نخواهند بود. - + Save ذخیره - + + Jc - Junk packet count + + + + + Jmin - Junk packet minimum size + + + + + Jmax - Junk packet maximum size + + + + + S1 - Init packet junk size + + + + + S2 - Response packet junk size + + + + + H1 - Init packet magic header + + + + + H2 - Response packet magic header + + + + + H4 - Transport packet magic header + + + + + H3 - Underload packet magic header + + + + The values of the H1-H4 fields must be unique - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) - + Save settings? تنظیمات را ذخیره کن? - + Continue ادامه - + Cancel کنسل - + Unable change settings while there is an active connection @@ -474,33 +595,33 @@ Already installed containers were found on the server. All installed containers PageProtocolCloakSettings - + Cloak settings تنظیمات Cloak - + Disguised as traffic from پنهان کردن به عنوان ترافیک از - + Port پورت - + Cipher رمزگذاری - + Save ذخیره - + Unable change settings while there is an active connection @@ -508,170 +629,170 @@ Already installed containers were found on the server. All installed containers PageProtocolOpenVpnSettings - + OpenVPN settings تنظیمات OpenVPN - + VPN address subnet زیرشبکه آدرس VPN - + Network protocol پروتکل شبکه - + Port پورت - + Auto-negotiate encryption رمزگذاری خودکار - + Hash هش - + SHA512 SHA512 - + SHA384 SHA384 - + SHA256 SHA256 - + SHA3-512 SHA3-512 - + SHA3-384 SHA3-384 - + SHA3-256 SHA3-256 - + whirlpool whirlpool - + BLAKE2b512 BLAKE2b512 - + BLAKE2s256 BLAKE2s256 - + SHA1 SHA1 - + Cipher رمزگذاری - + AES-256-GCM AES-256-GCM - + AES-192-GCM AES-192-GCM - + AES-128-GCM AES-128-GCM - + AES-256-CBC AES-256-CBC - + AES-192-CBC AES-192-CBC - + AES-128-CBC AES-128-CBC - + ChaCha20-Poly1305 ChaCha20-Poly1305 - + ARIA-256-CBC ARIA-256-CBC - + CAMELLIA-256-CBC CAMELLIA-256-CBC - + none none - + TLS auth اعتبار TLS - + Block DNS requests outside of VPN مسدود کردن درخواست‎های DNS خارج از وی‎پی‎ان - + Additional client configuration commands تنظیمات و دستورات اضافه برنامه متصل شونده - - + + Commands: دستورات: - + Additional server configuration commands تنظیمات و دستورات اضافه سرور - + Unable change settings while there is an active connection @@ -696,7 +817,7 @@ Already installed containers were found on the server. All installed containers کنسل - + Save ذخیره @@ -704,32 +825,32 @@ Already installed containers were found on the server. All installed containers PageProtocolRaw - + settings تنظیمات - + Show connection options نمایش تنظیمات اتصال - + Connection options %1 تنظیمات اتصال %1 - + Remove حذف - + Remove %1 from server? %1 از سرور حذف شود؟ - + All users with whom you shared a connection with will no longer be able to connect to it. همه کاربرانی که با آن‌ها ارتباطی به اشتراک گذاشته‌اید دیگر قادر به اتصال به آن نخواهند بود. @@ -738,12 +859,12 @@ Already installed containers were found on the server. All installed containers همه کاربرانی که با آن این پروتکل VPN را به اشتراک گذاشته‌اید دیگر نمی‌توانند به آن متصل شوند. - + Continue ادامه - + Cancel کنسل @@ -751,28 +872,28 @@ Already installed containers were found on the server. All installed containers PageProtocolShadowSocksSettings - + Shadowsocks settings تنظیمات Shadowsocks - + Port پورت - + Cipher رمزگذاری - + Save ذخیره - + Unable change settings while there is an active connection @@ -780,22 +901,22 @@ Already installed containers were found on the server. All installed containers PageProtocolWireGuardSettings - + WG settings - + Port پورت - + MTU - + Unable change settings while there is an active connection @@ -808,7 +929,7 @@ Already installed containers were found on the server. All installed containers کنسل - + Save ذخیره @@ -816,22 +937,22 @@ Already installed containers were found on the server. All installed containers PageProtocolXraySettings - + XRay settings - + Disguised as traffic from پنهان کردن به عنوان ترافیک از - + Save ذخیره - + Unable change settings while there is an active connection @@ -846,39 +967,39 @@ Already installed containers were found on the server. All installed containers PageServiceDnsSettings - + A DNS service is installed on your server, and it is only accessible via VPN. یک سرویس DSN بر روی سرور شما نصب شده و فقط از طریق وی‎پی‎ان قابل دسترسی می‎باشد. - + The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab. آدرس DSN همان آدرس سرور شماست. میتوانید از قسمت تنظیمات و تب اتصالات DSN خود را تنظیم کنید. - + Remove جذف - + Remove %1 from server? %1 از سرور حذف شود؟ - + Continue ادامه - + Cancel کنسل - + Cannot remove AmneziaDNS from running server @@ -886,157 +1007,153 @@ Already installed containers were found on the server. All installed containers PageServiceSftpSettings - + Settings updated successfully تنظیمات با موفقیت به‎روز‎رسانی شد - + SFTP settings تنظیمات SFTP - + Host هاست - - - - + + + + Copied کپی شد - + Port پورت - + User name نام کاربری - + Password رمز عبور - + Mount folder on device بارگذاری پوشه بر روی دستگاه - + In order to mount remote SFTP folder as local drive, perform following steps: <br> برای بارگذاری پوشه SFTP بر روی درایو محلی قدم‎های زیر را انجام دهید: <br> - - + + <br>1. Install the latest version of <br> 1. آخرین نسخه را نصب کنید - - + + <br>2. Install the latest version of <br> 2. آخرین نسخه را نصب کنید - + Detailed instructions جزییات دستورالعمل‎ها - Remove SFTP and all data stored there - حذف SFTP و تمام داده‎های ذخیره شده در آن + حذف SFTP و تمام داده‎های ذخیره شده در آن - Remove SFTP and all data stored there? - پوشه SFTP و تمام داده‎های آن حذف شوند؟ + پوشه SFTP و تمام داده‎های آن حذف شوند؟ - Continue - ادامه + ادامه - Cancel - کنسل + کنسل PageServiceSocksProxySettings - + Settings updated successfully - - + + SOCKS5 settings - + Host هاست - - - - + + + + Copied کپی شد - - + + Port پورت - + User name نام کاربری - - + + Password رمز عبور - + Username - - + + Change connection settings - + The port must be in the range of 1 to 65535 - + Password cannot be empty - + Username cannot be empty @@ -1044,95 +1161,96 @@ Already installed containers were found on the server. All installed containers PageServiceTorWebsiteSettings - + Settings updated successfully تنظیمات با موفقیت به‎روز‎‌رسانی شد - + Tor website settings تنظیمات وب‎سایت Tor - + Website address آدرس وب‎سایت - + Copied کپی شد - + Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL. - + After creating your onion site, it takes a few minutes for the Tor network to make it available for use. پس از ایجاد سایت پیاز خود، چند دقیقه طول می‌کشد تا شبکه تور آن را برای استفاده فراهم کند. - + When configuring WordPress set the this onion address as domain. زمانی که سایت وردپرس را تنظیم میکنید این آدرس پیازی را به عنوان دامنه قرار دهید. - Remove website - حذف وب سایت + حذف وب سایت - The site with all data will be removed from the tor network. - سایت با تمام داده‎ها از شبکه Tor حذف خواهد شد. + سایت با تمام داده‎ها از شبکه Tor حذف خواهد شد. - Continue - ادامه + ادامه - Cancel - کنسل + کنسل PageSettings - + Settings تنظیمات - + Servers سرورها - + Connection ارتباط - + Application نرم‎افزار - + Backup بک‎آپ - + About AmneziaVPN درباره Amnezia + Dev console + + + + Close application بستن نرم‎افزار @@ -1140,135 +1258,209 @@ Already installed containers were found on the server. All installed containers PageSettingsAbout - + Support Amnezia پشتیبانی از Amnezia - + Amnezia is a free and open-source application. You can support the developers if you like it. Amnezia یک برنامه رایگان و متن باز است. اگر دوست دارید می توانید از توسعه دهندگان حمایت کنید. - + Contacts مخاطب - + Telegram group گروه تلگرام - + To discuss features برای گفتگو در مورد ویژگی‎ها - + https://t.me/amnezia_vpn_en https://t.me/amnezia_vpn - + Mail ایمیل - + For reviews and bug reports برای ارائه نظرات و گزارشات باگ - + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website وب سایت - https://amnezia.org - https://amnezia.org + https://amnezia.org - + Software version: %1 %1 :نسخه نرم‎افزار - + Check for updates بررسی بروز‎رسانی - + Privacy Policy - PageSettingsAppSplitTunneling + PageSettingsApiServerInfo - - Cannot change split tunneling settings during active connection - نمی توان تنظیمات تونل تقسیم را در طول اتصال فعال تغییر داد - - - - Only the apps from the list should have access via VPN + + For the region - - Apps from the list should not have access via VPN + + Price - - App split tunneling + + Work period - - Mode - حالت - - - - Remove + + Speed - + + Support tag + + + + + Copied + کپی شد + + + + Reload API config + + + + + Reload API config? + + + + + Continue - + + Cancel کنسل - + + Cannot reload API config during active connection + + + + + Remove from application + + + + + Remove from application? + + + + + Cannot remove server during active connection + + + + + PageSettingsAppSplitTunneling + + + Cannot change split tunneling settings during active connection + نمی توان تنظیمات تونل تقسیم را در طول اتصال فعال تغییر داد + + + + Only the apps from the list should have access via VPN + + + + + Apps from the list should not have access via VPN + + + + + App split tunneling + + + + + Mode + حالت + + + + Remove + + + + + Continue + + + + + Cancel + کنسل + + + application name - + Open executable file - + Executable files (*.*) @@ -1276,102 +1468,102 @@ Already installed containers were found on the server. All installed containers PageSettingsApplication - + Application نرم افزار - + Allow application screenshots مجوز اسکرین‎شات در برنامه - + Enable notifications - + Enable notifications to show the VPN state in the status bar - + Auto start شروع خودکار - + Launch the application every time the device is starts راه‎اندازی نرم‎افزار با هر بار روشن شدن دستگاه - + Auto connect اتصال خودکار - + Connect to VPN on app start اتصال به وی‎‎پی‎ان با شروع نرم‎افزار - + Start minimized شروع به صورت کوچک - + Launch application minimized راه‎اندازی برنامه به صورت کوچک - + Language زبان - + Logging گزارشات - + Enabled فعال - + Disabled غیر فعال - + Reset settings and remove all data from the application ریست کردن تنظیمات و حذف تمام داده‎ها از نرم‎افزار - + Reset settings and remove all data from the application? ریست کردن تنظیمات و حذف تمام داده‎ها از نرم‎افزار؟ - + All settings will be reset to default. All installed AmneziaVPN services will still remain on the server. تمام تنظیمات به حالت پیش‎فرض ریست می‎شوند. تمام سرویس‎های Amnezia بر روی سرور باقی می‎مانند. - + Continue ادامه - + Cancel کنسل - + Cannot reset settings during active connection @@ -1379,7 +1571,7 @@ Already installed containers were found on the server. All installed containers PageSettingsBackup - + Settings restored from backup file تنظیمات از فایل پشتیبان بازیابی شد @@ -1458,62 +1650,62 @@ Already installed containers were found on the server. All installed containers PageSettingsConnection - + Connection ارتباط - + Use AmneziaDNS استفاده از AmneziaDNS - + If AmneziaDNS is installed on the server اگر AmneziaDNS بر روی سرور نصب شده باشد - + DNS servers سرورهای DNS - + When AmneziaDNS is not used or installed وقتی AmneziaDNS استفاده نشده یا نصب نشده است - + Allows you to use the VPN only for certain Apps به شما امکان می دهد از VPN فقط برای برخی برنامه ها استفاده کنید - + KillSwitch - + Disables your internet if your encrypted VPN connection drops out for any reason. - + Cannot change killSwitch settings during active connection - + Site-based split tunneling جداسازی ترافیک بر اساس سایت - + Allows you to select which sites you want to access through the VPN میتوانید مشخص کنید که چه سایت‎هایی از وی‎پی‎ان استفاده کنند - + App-based split tunneling جداسازی ترافیک بر اساس نرم‎افزار @@ -1521,62 +1713,62 @@ Already installed containers were found on the server. All installed containers PageSettingsDns - + Default server does not support custom DNS سرور پیش‌فرض از دی‌ان‌اس سفارشی پشتیبانی نمی‌کند - + DNS servers سرورهای DNS - + If AmneziaDNS is not used or installed اگر AmneziaDNS نصب نباشد یا استفاده نشود - + Primary DNS DNS اصلی - + Secondary DNS DNS ثانویه - + Restore default بازگشت به پیش‎فرض - + Restore default DNS settings? بازگشت به تنظیمات پیش‎فرض DNS؟ - + Continue ادامه - + Cancel کنسل - + Settings have been reset تنظیمات ریست شد - + Save ذخیره - + Settings saved ذخیره تنظیمات @@ -1584,72 +1776,72 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - + Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - + Logging گزارشات - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. فعال کردن این عملکرد باعث ذخیره خودکار لاگ‌های برنامه می‌شود. به طور پیش‌فرض، قابلیت ثبت لاگ غیرفعال است. در صورت بروز خطا در برنامه، ذخیره لاگ را فعال کنید. - + Save logs ذخیره گزارشات - + Open folder with logs باز کردن پوشه گزارشات - + Save ذخیره - + Logs files (*.log) Logs files (*.log) - + Logs file saved فایل گزارشات ذخیره شد - + Save logs to file ذخیره گزارشات در فایل - + Clear logs? پاک کردن گزارشات؟ - + Continue ادامه - + Cancel کنسل - + Logs have been cleaned up گزارشات پاک شدند - + Clear logs پاک کردن گزارشات @@ -1657,7 +1849,7 @@ Already installed containers were found on the server. All installed containers PageSettingsServerData - + All installed containers have been added to the application تمام کانتینرهای نصب شده به نرم‎افزار اضافه شدند @@ -1674,7 +1866,7 @@ Already installed containers were found on the server. All installed containers پاک کردن پروفایل ذخیره شده؟ - + No new installed containers found کانتینر نصب شده جدیدی پیدا نشد @@ -1683,104 +1875,104 @@ Already installed containers were found on the server. All installed containers - - - - - - Continue - ادامه - + Continue + ادامه + + + + + + Cancel کنسل - + Check the server for previously installed Amnezia services چک کردن سرویس‎های نصب شده Amnezia بر روی سرور - + Add them to the application if they were not displayed اضافه کردن آنها به نرم‎افزار اگر نمایش داده نشده‎اند - + Reboot server سرور را دوباره راه‌اندازی کنید - + Do you want to reboot the server? آیا می‌خواهید سرور را دوباره راه‌اندازی کنید؟ - + The reboot process may take approximately 30 seconds. Are you sure you wish to proceed? فرآیند راه‌اندازی ممکن است حدود ۳۰ ثانیه طول بکشد. آیا مطمئن هستید که می‌خواهید ادامه دهید؟ - + Cannot reboot server during active connection - + Do you want to remove the server from application? آیا می‌خواهید سرور را از برنامه حذف کنید؟ - + Cannot remove server during active connection - + Do you want to clear server from Amnezia software? آیا می‌خواهید سرور را از نرم‌افزار Amnezia پاک کنید؟ - + All users whom you shared a connection with will no longer be able to connect to it. همه کاربرانی که با آن‌ها ارتباطی به اشتراک گذاشته‌اید دیگر قادر به اتصال به آن نخواهند بود. - + Cannot clear server from Amnezia software during active connection - + Reset API config تنظیمات API را بازنشانی کنید - + Do you want to reset API config? آیا می خواهید پیکربندی API را بازنشانی کنید؟ - + Cannot reset API config during active connection - + Remove server from application حذف کردن سرور از نرم‎افزار - + All installed AmneziaVPN services will still remain on the server. تمام سرویس‎های نصب‎شده Amnezia همچنان بر روی سرور باقی خواهند ماند. - + Clear server from Amnezia software پاک کردن سرور از نرم‎افزار Amnezia @@ -1788,27 +1980,27 @@ Already installed containers were found on the server. All installed containers PageSettingsServerInfo - + Server name نام سرور - + Save ذخیره - + Protocols پروتکل‎ها - + Services سرویس‎ها - + Management مدیریت @@ -1816,59 +2008,59 @@ Already installed containers were found on the server. All installed containers PageSettingsServerProtocol - + settings تنظیمات - + Clear %1 profile - + Clear %1 profile? - + - + Unable to clear %1 profile while there is an active connection - + Remove حذف - + Remove %1 from server? حذف %1 از سرور؟ - + All users with whom you shared a connection will no longer be able to connect to it. تمام کاربرانی که این ارتباط را با آنها به اشتراک گذاشته‎اید دیگر نمی‎توانند به آن متصل شوند. - + Cannot remove active container - - + + Continue ادامه - - + + Cancel کنسل @@ -1876,7 +2068,7 @@ Already installed containers were found on the server. All installed containers PageSettingsServersList - + Servers سرورها @@ -1884,110 +2076,155 @@ Already installed containers were found on the server. All installed containers PageSettingsSplitTunneling - + Default server does not support split tunneling function سرور پیش‌فرض از عملکرد تونل‌سازی تقسیم شده پشتیبانی نمی‌کند - + Addresses from the list should not be accessed via VPN دسترسی به آدرس‎های لیست بدون وی‎پی‎ان - + Split tunneling جداسازی ترافیک - + Mode حالت - + Remove حذف - + Continue ادامه - + Cancel کنسل - + Cannot change split tunneling settings during active connection نمی توان تنظیمات تونل تقسیم را در طول اتصال فعال تغییر داد - + Only the sites listed here will be accessed through the VPN تنها سایت‌های موجود در اینجا از طریق VPN دسترسی داده خواهند شد - + website or IP وب‌سایت یا آدرس IP - + Import / Export Sites وارد کردن / صادر کردن وب‌سایت‌ها - + Import بارگذاری - + Save site list ذخیره لیست سایت‎ها - + Save sites ذخیره سایت‎ها - - - + + + Sites files (*.json) Sites files (*.json) - + Import a list of sites بارگذاری لیست سایت‎ها - + Replace site list جایگزین کردن لیست سایت - - + + Open sites file باز کردن فایل سایت‎ها - + Add imported sites to existing ones اضافه کردن سایت‎های بارگذاری شده به سایت‎های موجود + + PageSetupWizardApiServiceInfo + + + For the region + + + + + Price + + + + + Work period + + + + + Speed + + + + + Features + + + + + Connect + اتصال + + + + PageSetupWizardApiServicesList + + + VPN by Amnezia + + + + + Choose a VPN service that suits your needs. + + + PageSetupWizardConfigSource - Server connection - ارتباط سرور + ارتباط سرور Do not use connection code from public sources. It may have been created to intercept your data. @@ -1998,95 +2235,171 @@ It's okay as long as it's from someone you trust. ایرادی ندارد که از طرف کسی باشد که به او اعتماد دارید. - Do not use connection codes from untrusted sources, as they may be created to intercept your data. - از کدهای اتصال از منابع نامعتبر استفاده نکنید، زیرا ممکن است برای رهگیری داده های شما ایجاد شده باشند. + از کدهای اتصال از منابع نامعتبر استفاده نکنید، زیرا ممکن است برای رهگیری داده های شما ایجاد شده باشند. - What do you have? - چی داری؟ + چی داری؟ - + File with connection settings فایل شامل تنظیمات اتصال - File with connection settings or backup - فایل شامل تنظیمات اتصال یا بک‎آپ + فایل شامل تنظیمات اتصال یا بک‎آپ - + + Connection + ارتباط + + + + Insert the key, add a configuration file or scan the QR-code + + + + + Insert key + + + + + Insert + وارد کردن + + + + Continue + + + + + Other connection options + + + + + VPN by Amnezia + + + + + Connect to classic paid and free VPN services from Amnezia + + + + + Self-hosted VPN + + + + + Configure Amnezia VPN on your own server + + + + + Restore from backup + بازیابی از پشتیبان + + + + Open backup file + باز کردن فایل پشتیبان + + + + Backup files (*.backup) + Backup files (*.backup) + + + Open config file باز کردن فایل تنظیمات - + QR code QR-Code - + + I have nothing + من هیچی ندارم + + Key as text - متن شامل کلید + متن شامل کلید PageSetupWizardCredentials - + Server IP address [:port] آدرس آی‎پی سرور (:پورت) - + Continue ادامه - + Enter the address in the format 255.255.255.255:88 آدرس را با فرمت 255.255.255.255:88 وارد کنید - + Configure your server سرور خود را پیکربندی کنید - + 255.255.255.255:22 - + SSH Username - + Password or SSH private key رمز عبور یا کلید خصوصی SSH - + All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties تمام داده‎هایی که شما وارد می‎کنید به شدت محرمانه‎ است و با Amnezia یا هر شخص ثالث دیگری به اشتراک گذاشته نمی‎شود - + + How to run your VPN server + + + + + Where to get connection data, step-by-step instructions for buying a VPS + + + + Ip address cannot be empty آدرس آی‎پی نمی‎تواند خالی باشد - + Login cannot be empty نام‎کاربری نمی‎تواند خالی باشد - + Password/private key cannot be empty پسورد یا کلید خصوصی نمی‎تواند خالی باشد @@ -2094,22 +2407,22 @@ It's okay as long as it's from someone you trust. PageSetupWizardEasy - + What is the level of internet control in your region? سطح کنترل اینترنت در منطقه شما چگونه است؟ - + Choose a VPN protocol یک پروتکل VPN را انتخاب کنید - + Skip setup رد شدن از تنظیم - + Continue ادامه @@ -2117,38 +2430,38 @@ It's okay as long as it's from someone you trust. PageSetupWizardInstalling - + The server has already been added to the application سرور در حال حاضر به نرم‎افزار اضافه شده است - + Amnezia has detected that your server is currently Amnezia has detected that your server is currently - + busy installing other software. Amnezia installation مشغول نصب نرم افزارهای دیگر نصب Amnezia - + will pause until the server finishes installing other software متوقف شده تا زمانی که سرور نصب نرم‎افزار دیگر را تمام کند - + Installing در حال نصب - + Cancel installation لغو عملیات نصب - - + + Usually it takes no more than 5 minutes معمولا بیش از 5 دقیقه طول نمی‎کشد @@ -2156,37 +2469,37 @@ It's okay as long as it's from someone you trust. PageSetupWizardProtocolSettings - + Installing %1 در حال نصب %1 - + More detailed جزییات بیشتر - + Close بستن - + Network protocol پروتکل شبکه - + Port پورت - + Install نصب - + The port must be in the range of 1 to 65535 @@ -2194,12 +2507,12 @@ It's okay as long as it's from someone you trust. PageSetupWizardProtocols - + VPN protocol پروتکل وی‎پی‎ان - + Choose the one with the highest priority for you. Later, you can install other protocols and additional services, such as DNS proxy and SFTP. پروتکلی که بیشترین اولویت را برای شما دارد انتخاب کنید. بعدا، میتوانید پروتکل‎ها و سرویس‎های اضافه مانند پروکسی DNS و SFTP را هم نصب کنید. @@ -2207,7 +2520,7 @@ It's okay as long as it's from someone you trust. PageSetupWizardQrReader - + Point the camera at the QR code and hold for a couple of seconds. دوربین را روی QR Code بگیرید و برای چند ثانیه آن را نگه دارید. @@ -2215,60 +2528,55 @@ It's okay as long as it's from someone you trust. PageSetupWizardStart - Settings restored from backup file - تنظیمات از فایل بک‎آپ بازیابی شدند + تنظیمات از فایل بک‎آپ بازیابی شدند - Free service for creating a personal VPN on your server. - سرویس رایگان برای ایجاد وی‎پی‎ان شخصی بر روی سرور خودتان. + سرویس رایگان برای ایجاد وی‎پی‎ان شخصی بر روی سرور خودتان. - Helps you access blocked content without revealing your privacy, even to VPN providers. - به شما کمک می‎کند که بدون فاش کردن حریم شخصی خودتان, حتی برای ارائه دهنده وی‎پی‎ان به محتوای مسدود شده دسترسی پیدا کنید. + به شما کمک می‎کند که بدون فاش کردن حریم شخصی خودتان, حتی برای ارائه دهنده وی‎پی‎ان به محتوای مسدود شده دسترسی پیدا کنید. - I have the data to connect - من داده برای اتصال دارم + من داده برای اتصال دارم - I have nothing - من هیچی ندارم + من هیچی ندارم - - https://amnezia.org/instructions/0_starter-guide - + + Let's get started + PageSetupWizardTextKey - + Connection key کلید ارتباط - + A line that starts with vpn://... خطی که با آن شروع می شود vpn://... - + Key کلید - + Insert وارد کردن - + Continue ادامه @@ -2276,32 +2584,32 @@ It's okay as long as it's from someone you trust. PageSetupWizardViewConfig - + New connection ارتباط جدید - + Collapse content جمع کردن محتوا - + Show content نمایش محتوا - + Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider. - + Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data. از کدهای اتصال فقط از منابع مورد اعتماد خود استفاده کنید. ممکن است کدهایی از منابع عمومی برای رهگیری داده های شما ایجاد شده باشند - + Connect اتصال @@ -2309,144 +2617,144 @@ It's okay as long as it's from someone you trust. PageShare - + OpenVPN native format فرمت OpenVPN - + WireGuard native format فرمت WireGuard - + Connection ارتباط - - + + Server سرور - + Config revoked تنظیمات ابطال‎شد - + Connection to ارتباط با - + File with connection settings to فایل شامل تنظیمات ارتباط با - + Save OpenVPN config ذخیره تنظیمات OpenVPN - + Save WireGuard config ذخیره تنظیمات WireGuard - + Save AmneziaWG config تنظیمات AmneziaWG را ذخیره کنید - + Save Shadowsocks config ذخیره تنظیمات Shadowsocks - + Save Cloak config ذخیره تنظیمات Cloak - + Save XRay config - + For the AmneziaVPN app برای نرم‎افزار AmneziaVPN - + AmneziaWG native format فرمت بومی AmneziaWG - + Shadowsocks native format فرمت Shadowsocks - + Cloak native format فرمت Cloak - + XRay native format - + Share VPN Access اتصال vpn را به اشتراک بگذارید - + Share full access to the server and VPN به اشتراک گذاشتن دسترسی کامل به سرور و وی‎پی‎ان - + Use for your own devices, or share with those you trust to manage the server. برای دستگاه‎های خودتان استفاده کنید یا با آنهایی که برای مدیریت سرور به آن‎ها اعتماد دارید به اشتراک بگذارید. - - + + Users کاربران - + User name نام کاربری - + Search جستجو - + Creation date: %1 - + Latest handshake: %1 - + Data received: %1 - + Data sent: %1 @@ -2455,65 +2763,65 @@ It's okay as long as it's from someone you trust. تاریخ ایجاد: - + Rename تغییر نام - + Client name نام کلاینت - + Save ذخیره - + Revoke ابطال - + Revoke the config for a user - %1? لغو پیکربندی برای یک کاربر - %1? - + The user will no longer be able to connect to your server. کاربر دیگر نمی‎تواند به سرور وصل شود. - + Continue ادامه - + Cancel کنسل - + Share VPN access without the ability to manage the server به اشتراک گذاشتن دسترسی وی‎پی‎ان بدون امکان مدیریت سرور - - + + Protocol پروتکل - - + + Connection format فرمت ارتباط - - + + Share اشتراک‎گذاری @@ -2521,50 +2829,50 @@ It's okay as long as it's from someone you trust. PageShareFullAccess - + Full access to the server and VPN دسترسی کامل به سرور و وی‎پی‎ان - + We recommend that you use full access to the server only for your own additional devices. ما پیشنهاد میکنیم که ازحالت دسترسی کامل به سرور فقط برای دستگاه‎های دیگر خودتان استفاده کنید. - + If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. اگر دسترسی کامل را با دیگران به اشتراک بگذارید، آن‎ها می‎توانند پروتکل‎ها و سرویس‎ها را حذف یا اضافه کنند که باعث می‎شود که وی‎پی‎ان دیگر برای سایر کاربران کار نکند. - + Server سرور - + Accessing در حال دسترسی به - + File with accessing settings to فایل شامل تنظیمات دسترسی به - + Share اشتراک‎گذاری - + Connection to ارتباط با - + File with connection settings to فایل شامل تنظیمات ارتباط با @@ -2572,15 +2880,20 @@ It's okay as long as it's from someone you trust. PageStart - + Logging was disabled after 14 days, log files were deleted + + + Settings restored from backup file + + PopupType - + Close بستن @@ -2971,7 +3284,7 @@ It's okay as long as it's from someone you trust. این پیکربندی قبلاً به برنامه اضافه شده است - + ErrorCode: %1. کد خطا: %1. @@ -3056,37 +3369,42 @@ It's okay as long as it's from someone you trust. - - QFile error: The file could not be opened + + Missing AGW public key - QFile error: An error occurred when reading from the file + QFile error: The file could not be opened - QFile error: The file could not be accessed + QFile error: An error occurred when reading from the file - QFile error: An unspecified error occurred + QFile error: The file could not be accessed - QFile error: A fatal error occurred + QFile error: An unspecified error occurred + QFile error: A fatal error occurred + + + + QFile error: The operation was aborted - + Internal error Internal error @@ -3539,7 +3857,7 @@ For more detailed information, you can SelectLanguageDrawer - + Choose language انتخاب زبان @@ -3547,13 +3865,13 @@ For more detailed information, you can Settings - + Server #1 Server #1 - - + + Server Server @@ -3578,39 +3896,39 @@ For more detailed information, you can ShareConnectionDrawer - - + + Save AmneziaVPN config ذخیره تنظیمات AmneziaVPN - + Share اشتراک‎گذاری - + Copy کپی - - + + Copied کپی شد - + Copy config string کپی‎کردن متن تنظیمات - + Show connection settings نمایش تنظیمات ارتباط - + To read the QR code in the Amnezia app, select "Add server" → "I have data to connect" → "QR code, key or settings file" برای خواندن QR Code در نرم‎افزار AmneziaVPN "اضافه کردن سرور" -> "من داده برای اتصال دارم" -> "QR Code، کلید یا فایل تنظیمات" @@ -3694,7 +4012,7 @@ For more detailed information, you can TextFieldWithHeaderType - + The field can't be empty این فیلد نمی‌تواند خالی باشد. @@ -3753,12 +4071,12 @@ For more detailed information, you can amnezia::ContainerProps - + Low پایین - + High متوسط یا بالا @@ -3767,12 +4085,12 @@ For more detailed information, you can شدید - + I just want to increase the level of my privacy. من فقط میخواهم سطح حریم شخصی خودم را بالا ببرم - + I want to bypass censorship. This option recommended in most cases. من میخواهم از سانسور عبور کنم. این گزینه در اکثر موارد توصیه می‎‌شود @@ -3784,12 +4102,12 @@ For more detailed information, you can main2 - + Private key passphrase عبارت کلید خصوصی - + Save ذخیره diff --git a/client/translations/amneziavpn_hi_IN.ts b/client/translations/amneziavpn_hi_IN.ts index e63fe3ff..e5cd57d8 100644 --- a/client/translations/amneziavpn_hi_IN.ts +++ b/client/translations/amneziavpn_hi_IN.ts @@ -1,6 +1,54 @@ + + ApiServicesModel + + + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s + + + + + VPN to access blocked sites in regions with high levels of Internet censorship. + + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. + + + + + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship + + + + + %1 MBit/s + + + + + %1 days + + + + + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> + + + + + Free + + + + + %1 $/month + + + AppSplitTunnelingController @@ -27,7 +75,7 @@ ConnectButton - + Unable to disconnect during configuration preparation कॉन्फ़िगरेशन तैयारी के दौरान डिस्कनेक्ट करने में असमर्थ @@ -35,62 +83,62 @@ ConnectionController - - - + + + Connect कनेक्ट - + VPN Protocols is not installed. Please install VPN container at first पीएन प्रोटोकॉल स्थापित नहीं है. कृपया पहले वीपीएन कंटेनर स्थापित करें - + Connected जुड़ा हुआ - + The selected protocol is not supported on the current platform चयनित प्रोटोकॉल वर्तमान प्लेटफ़ॉर्म पर समर्थित नहीं है - + unable to create configuration कॉन्फ़िगरेशन बनाने में असमर्थ - + Connecting... कनेक्ट... - + Reconnecting... पुनः कनेक्ट हो रहा है... - + Disconnecting... डिस्कनेक्ट हो रहा है... - + Preparing... तैयार कर रहे हैं... - + Settings updated successfully, reconnnection... सेटिंग्स सफलतापूर्वक अपडेट हो गईं... - + Settings updated successfully सेटिंग्स सफलतापूर्वक अपडेट हो गईं @@ -131,7 +179,7 @@ &चपकाएं - + &SelectAll &सबका चयन करें @@ -226,84 +274,104 @@ Can't be disabled for current server InstallController - + %1 installed successfully. %1 सफलतापूर्वक स्थापित हुआ. - + %1 is already installed on the server. %1 पहले से ही सर्वर पर स्थापित है. - + Added containers that were already installed on the server सर्वर पर पहले से स्थापित कंटेनर जोड़े गए - + Already installed containers were found on the server. All installed containers have been added to the application सर्वर पर पहले से स्थापित कंटेनर पाए गए। सभी स्थापित कंटेनरों को एप्लिकेशन में जोड़ दिया गया है - + Settings updated successfully सेटिंग्स सफलतापूर्वक अपडेट हो गईं - + Server '%1' was rebooted सर्वर '%1' रीबूट किया गया था - + Server '%1' was removed सर्वर '%1' रीबूट किया गया था - + All containers from server '%1' have been removed सर्वर '%1' से सभी कंटेनर हटा दिए गए हैं - + %1 has been removed from the server '%2' %1 को सर्वर '%2' से हटा दिया गया है - + + Api config removed + + + + %1 cached profile cleared %1 कैश्ड प्रोफ़ाइल साफ़ की गई - + Please login as the user कृपया उपयोगकर्ता के रूप में लॉगिन करें - + Server added successfully सर्वर सफलतापूर्वक जोड़ा गया + + + %1 installed successfully. + + + + + API config reloaded + + + + + Successfully changed the country of connection to %1 + + InstalledAppsDrawer - + Choose application एप्लिकेशन चुनें - + application name आवेदन का नाम - + Add selected चुने हुए को जोड़ो @@ -358,45 +426,53 @@ Already installed containers were found on the server. All installed containers PageDeinstalling - + Removing services from %1 सर्वर से %1 हटाया गया - + Usually it takes no more than 5 minutes आमतौर पर इसमें 5 मिनट से अधिक समय नहीं लगता है + + PageDevMenu + + + Gateway endpoint + + + PageHome - + Logging enabled लॉगिंग सक्षम - + Split tunneling enabled स्प्लिट टनलिंग सक्षम - + Split tunneling disabled स्प्लिट टनलिंग अक्षम - + VPN protocol VPN प्रोटोकॉल - + Servers सर्वर - + Unable change server while there is an active connection सक्रिय कनेक्शन होने पर सर्वर बदलने में असमर्थ @@ -404,57 +480,102 @@ Already installed containers were found on the server. All installed containers PageProtocolAwgSettings - + AmneziaWG settings Amneziaडब्ल्यूजी सेटिंग्स - + Port पोर्ट - + MTU एमटीयू - + + Jc - Junk packet count + + + + + Jmin - Junk packet minimum size + + + + + Jmax - Junk packet maximum size + + + + + S1 - Init packet junk size + + + + + S2 - Response packet junk size + + + + + H1 - Init packet magic header + + + + + H2 - Response packet magic header + + + + + H4 - Transport packet magic header + + + + + H3 - Underload packet magic header + + + + Save सहेजें - + The values of the H1-H4 fields must be unique H1-H4 फ़ील्ड का मान अद्वितीय होना चाहिए - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) फ़ील्ड S1 + संदेश आरंभ आकार (148) का मान S2 + संदेश प्रतिक्रिया आकार (92) के बराबर नहीं होना चाहिए - + Save settings? सेटिंग्स सेव करें? - + All users with whom you shared a connection with will no longer be able to connect to it. वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे. - + Unable change settings while there is an active connection सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ - + Continue जारी रखना - + Cancel रद्द करना @@ -462,33 +583,33 @@ Already installed containers were found on the server. All installed containers PageProtocolCloakSettings - + Cloak settings लबादा सेटिंग - + Disguised as traffic from से यातायात के रूप में प्रच्छन्न - + Port पोर्ट - + Cipher साइफर - + Save सहेजें - + Unable change settings while there is an active connection सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ @@ -496,175 +617,175 @@ Already installed containers were found on the server. All installed containers PageProtocolOpenVpnSettings - + OpenVPN settings OpenVPN सेटिंग्स - + VPN address subnet VPN एड्रेस सबनेट - + Network protocol नेटवर्क प्रोटोकॉल - + Port पोर्ट - + Auto-negotiate encryption स्वतः-निगोशिएट एन्क्रिप्शन - + Hash - + SHA512 - + SHA384 - + SHA256 - + SHA3-512 - + SHA3-384 - + SHA3-256 - + whirlpool - + BLAKE2b512 - + BLAKE2s256 अक्षम - + SHA1 - + Cipher साइफर - + AES-256-GCM - + AES-192-GCM - + AES-128-GCM एईएस-128-जीसीएम - + AES-256-CBC - + AES-192-CBC - + AES-128-CBC एईएस-128-सीबीसी - + ChaCha20-Poly1305 चाचा20-पॉली1305 - + ARIA-256-CBC एआरआईए-256-सीबीसी - + CAMELLIA-256-CBC कैमेलिया-256-सीबीसी - + none कोई नहीं - + TLS auth टीएलएस प्राधिकरण - + Block DNS requests outside of VPN VPN के बाहर डीएनएस अनुरोधों को ब्लॉक करें - + Additional client configuration commands अतिरिक्त क्लाइंट कॉन्फ़िगरेशन आदेश - - + + Commands: आदेश: - + Additional server configuration commands अतिरिक्त सर्वर कॉन्फ़िगरेशन आदेश - + Save सहेजें - + Unable change settings while there is an active connection सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ @@ -672,42 +793,42 @@ Already installed containers were found on the server. All installed containers PageProtocolRaw - + settings समायोजन - + Show connection options कनेक्शन विकल्प दिखाएँ - + Connection options %1 कनेक्शन विकल्प%1 - + Remove निकालना - + Remove %1 from server? सर्वर से %1 हटाएँ? - + All users with whom you shared a connection with will no longer be able to connect to it. वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे. - + Continue जारी रखना - + Cancel रद्द करना @@ -715,28 +836,28 @@ Already installed containers were found on the server. All installed containers PageProtocolShadowSocksSettings - + Shadowsocks settings शैडोसॉक्स सेटिंग्स - + Port पोर्ट - + Cipher साइफर - + Save सहेजें - + Unable change settings while there is an active connection सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ @@ -744,27 +865,27 @@ Already installed containers were found on the server. All installed containers PageProtocolWireGuardSettings - + WG settings डब्ल्यूजी सेटिंग्स - + Port बंदरगाह - + MTU एमटीयू - + Save सहेजें - + Unable change settings while there is an active connection सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ @@ -772,22 +893,22 @@ Already installed containers were found on the server. All installed containers PageProtocolXraySettings - + XRay settings एक्सरे सेटिंग्स - + Disguised as traffic from से यातायात के रूप में प्रच्छन्न - + Save सहेजें - + Unable change settings while there is an active connection सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ @@ -795,39 +916,39 @@ Already installed containers were found on the server. All installed containers PageServiceDnsSettings - + A DNS service is installed on your server, and it is only accessible via VPN. आपके सर्वर पर एक DNS सेवा स्थापित है, और यह केवल वीपीएन के माध्यम से पहुंच योग्य है. - + The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab. DNS पता आपके सर्वर के पते के समान है। आप कनेक्शन टैब के अंतर्गत सेटिंग्स में DNS को कॉन्फ़िगर कर सकते हैं. - + Remove निकालना - + Remove %1 from server? सर्वर से %1 हटाएँ? - + Continue जारी रखना - + Cancel रद्द करना - + Cannot remove AmneziaDNS from running server चल रहे सर्वर से एम्नेज़िया डीएनएस को नहीं हटाया जा सकता @@ -835,157 +956,153 @@ Already installed containers were found on the server. All installed containers PageServiceSftpSettings - + Settings updated successfully सेटिंग्स सफलतापूर्वक अपडेट हो गईं - + SFTP settings एसएफटीपी सेटिंग्स - + Host मेज़बान - - - - + + + + Copied कॉपी किया गया - + Port पोर्ट - + User name उपयोगकर्ता नाम - + Password पासवर्ड - + Mount folder on device डिवाइस पर फ़ोल्डर माउंट करें - + In order to mount remote SFTP folder as local drive, perform following steps: <br> दूरस्थ SFTP फ़ोल्डर को स्थानीय ड्राइव के रूप में माउंट करने के लिए, निम्नलिखित चरण निष्पादित करें: <br> - - + + <br>1. Install the latest version of <br>1. का नवीनतम संस्करण स्थापित करें - - + + <br>2. Install the latest version of <br>2. का नवीनतम संस्करण स्थापित करें - + Detailed instructions विस्तृत निर्देश - Remove SFTP and all data stored there - एसएफटीपी और वहां संग्रहीत सभी डेटा हटा दें + एसएफटीपी और वहां संग्रहीत सभी डेटा हटा दें - Remove SFTP and all data stored there? - एसएफटीपी और वहां संग्रहीत सभी डेटा हटाएं? + एसएफटीपी और वहां संग्रहीत सभी डेटा हटाएं? - Continue - जारी रखना + जारी रखना - Cancel - रद्द करना + रद्द करना PageServiceSocksProxySettings - + Settings updated successfully सेटिंग्स सफलतापूर्वक अपडेट हो गईं - - + + SOCKS5 settings - + Host मेज़बान - - - - + + + + Copied कॉपी किया गया - - + + Port - + User name उपयोगकर्ता नाम - - + + Password पासवर्ड - + Username - - + + Change connection settings - + The port must be in the range of 1 to 65535 - + Password cannot be empty - + Username cannot be empty @@ -993,95 +1110,96 @@ Already installed containers were found on the server. All installed containers PageServiceTorWebsiteSettings - + Settings updated successfully सेटिंग्स सफलतापूर्वक अपडेट हो गईं - + Tor website settings टोर वेबसाइट सेटिंग्स - + Website address वेबसाइट का पता - + Copied कॉपी किया गया - + Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL. इस यूआरएल को खोलने के लिए <a href='https://www.torproject.org/download/' style='color: #FBB26A;'>Tor ब्राउज़र</a> का उपयोग करें। - + After creating your onion site, it takes a few minutes for the Tor network to make it available for use. आपकी onionसाइट बनाने के बाद, टोर नेटवर्क को इसे उपयोग के लिए उपलब्ध कराने में कुछ मिनट लगते हैं. - + When configuring WordPress set the this onion address as domain. वर्डप्रेस को कॉन्फ़िगर करते समय इस प्याज पते को डोमेन के रूप में सेट करें. - Remove website - वेबसाइट हटाएँ + वेबसाइट हटाएँ - The site with all data will be removed from the tor network. - सभी डेटा वाली साइट को टोर नेटवर्क से हटा दिया जाएगा. + सभी डेटा वाली साइट को टोर नेटवर्क से हटा दिया जाएगा. - Continue - जारी रखना + जारी रखना - Cancel - रद्द करना + रद्द करना PageSettings - + Settings समायोजन - + Servers सर्वर - + Connection कनेक्शन - + Application एप्लिकेशन - + Backup बैकअप - + About AmneziaVPN AmneziaVPN के बारे में + Dev console + + + + Close application एप्लिकेशन बंद करो @@ -1089,85 +1207,155 @@ Already installed containers were found on the server. All installed containers PageSettingsAbout - + Support Amnezia Amnezia का समर्थन करें - + Amnezia is a free and open-source application. You can support the developers if you like it. एमनेज़िया एक निःशुल्क और ओपन-सोर्स एप्लिकेशन है। यदि आपको यह पसंद है तो आप डेवलपर्स का समर्थन कर सकते हैं।. - + Contacts संपर्क - + Telegram group टेलीग्राम समूह - + To discuss features सुविधाओं पर चर्चा करना - + https://t.me/amnezia_vpn_en - + Mail मेल - + For reviews and bug reports समीक्षाओं और बग रिपोर्टों के लिए - + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website वेबसाइट - - https://amnezia.org - - - - + Software version: %1 सॉफ़्टवेयर संस्करण: %1 - + Check for updates अद्यतन के लिए जाँच - + Privacy Policy गोपनीयता नीति + + PageSettingsApiServerInfo + + + For the region + + + + + Price + + + + + Work period + + + + + Speed + + + + + Support tag + + + + + Copied + कॉपी किया गया + + + + Reload API config + + + + + Reload API config? + + + + + + Continue + जारी रखना + + + + + Cancel + रद्द करना + + + + Cannot reload API config during active connection + + + + + Remove from application + + + + + Remove from application? + + + + + Cannot remove server during active connection + सक्रिय कनेक्शन के दौरान सर्वर को हटाया नहीं जा सकता + + PageSettingsAppSplitTunneling - + Cannot change split tunneling settings during active connection सक्रिय कनेक्शन के दौरान स्प्लिट टनलिंग सेटिंग्स को नहीं बदला जा सकता @@ -1180,52 +1368,52 @@ Already installed containers were found on the server. All installed containers सूची के ऐप्स को वीपीएन के माध्यम से एक्सेस नहीं किया जाना चाहिए - + Only the apps from the list should have access via VPN - + Apps from the list should not have access via VPN - + App split tunneling ऐप स्प्लिट टनलिंग - + Mode तरीका - + Remove निकालना - + Continue जारी रखना - + Cancel रद्द करना - + application name आवेदन का नाम - + Open executable file निष्पादन योग्य फ़ाइल खोलें - + Executable files (*.*) निष्पादनीय फाइल (*.*) @@ -1233,102 +1421,102 @@ Already installed containers were found on the server. All installed containers PageSettingsApplication - + Application एप्लिकेशन - + Allow application screenshots एप्लिकेशन स्क्रीनशॉट की अनुमति दें - + Enable notifications - + Enable notifications to show the VPN state in the status bar - + Auto start ऑटो स्टार्ट - + Launch the application every time the device is starts हर बार डिवाइस चालू होने पर एप्लिकेशन लॉन्च करें - + Auto connect ऑटो कनेक्ट - + Connect to VPN on app start ऐप शुरू होने पर वीपीएन से कनेक्ट करें - + Start minimized स्टार्ट को मिनिमाइज किया गया - + Launch application minimized लॉन्च एप्लिकेशन को न्यूनतम किया गया - + Language भाषा - + Logging लॉगिंग - + Enabled सक्रिय किया - + Disabled अक्षम - + Reset settings and remove all data from the application सेटिंग्स रीसेट करें और एप्लिकेशन से सभी डेटा हटा दें - + Reset settings and remove all data from the application? सेटिंग्स रीसेट करें और एप्लिकेशन से सभी डेटा हटा दें? - + All settings will be reset to default. All installed AmneziaVPN services will still remain on the server. सभी सेटिंग्स डिफ़ॉल्ट पर रीसेट हो जाएंगी. सभी स्थापित AmneziaVPN सेवाएँ अभी भी सर्वर पर रहेंगी।. - + Continue जारी रखना - + Cancel रद्द करना - + Cannot reset settings during active connection सक्रिय कनेक्शन के दौरान सेटिंग्स रीसेट नहीं की जा सकतीं @@ -1336,7 +1524,7 @@ Already installed containers were found on the server. All installed containers PageSettingsBackup - + Settings restored from backup file बैकअप फ़ाइल से सेटिंग्स पुनर्स्थापित की गईं @@ -1415,62 +1603,62 @@ Already installed containers were found on the server. All installed containers PageSettingsConnection - + Connection कनेक्शन - + When AmneziaDNS is not used or installed जब AmneziaDNS का उपयोग या स्थापित नहीं किया जाता है - + Allows you to use the VPN only for certain Apps आपको केवल कुछ ऐप्स के लिए वीपीएन का उपयोग करने की अनुमति देता है - + Use AmneziaDNS Amneziaडीएनएस का प्रयोग करें - + If AmneziaDNS is installed on the server यदि AmneziaDNS सर्वर पर स्थापित है - + DNS servers DNS सर्वर - + Site-based split tunneling साइट-आधारित विभाजित टनलिंग - + Allows you to select which sites you want to access through the VPN आपको यह चुनने की अनुमति देता है कि आप वीपीएन के माध्यम से किन साइटों तक पहुंचना चाहते हैं - + App-based split tunneling ऐप-आधारित स्प्लिट टनलिंग - + KillSwitch स्विच बन्द कर दो - + Disables your internet if your encrypted VPN connection drops out for any reason. यदि आपका एन्क्रिप्टेड वीपीएन कनेक्शन किसी भी कारण से बंद हो जाता है तो आपका इंटरनेट अक्षम कर देता है. - + Cannot change killSwitch settings during active connection सक्रिय कनेक्शन के दौरान किलस्विच सेटिंग्स को नहीं बदला जा सकता @@ -1478,62 +1666,62 @@ Already installed containers were found on the server. All installed containers PageSettingsDns - + Default server does not support custom DNS डिफ़ॉल्ट सर्वर कस्टम डीएनएस का समर्थन नहीं करता है - + DNS servers DNS सर्वर - + If AmneziaDNS is not used or installed यदि AmneziaDNS का उपयोग या स्थापित नहीं किया गया है - + Primary DNS प्राथमिक डीएनएस - + Secondary DNS द्वितीयक डीएनएस - + Restore default डिफ़ॉल्ट बहाल - + Restore default DNS settings? डिफ़ॉल्ट DNS सेटिंग्स पुनर्स्थापित करें? - + Continue जारी रखना - + Cancel रद्द करना - + Settings have been reset सेटिंग्स रीसेट कर दी गई हैं - + Save सहेजें - + Settings saved सेटिंग्स को सहेजा गया @@ -1541,72 +1729,72 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - + Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. लॉगिंग सक्षम है. ध्यान दें कि 14 दिनों के बाद लॉग स्वचालित रूप से अक्षम हो जाएंगे, और सभी लॉग फ़ाइलें हटा दी जाएंगी. - + Logging लॉगिंग - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. इस फ़ंक्शन को सक्षम करने से एप्लिकेशन के लॉग स्वचालित रूप से सहेजे जाएंगे, डिफ़ॉल्ट रूप से, लॉगिंग कार्यक्षमता अक्षम है। एप्लिकेशन की खराबी की स्थिति में लॉग सेविंग सक्षम करें. - + Save logs लॉग सहेजें - + Open folder with logs लॉग के साथ फ़ोल्डर खोलें - + Save सहेजें - + Logs files (*.log) लॉग फ़ाइलें (*.log) - + Logs file saved लॉग फ़ाइल सहेजी गई - + Save logs to file फ़ाइल में लॉग सहेजें - + Clear logs? लॉग साफ़ करें? - + Continue जारी रखना - + Cancel रद्द करना - + Logs have been cleaned up लॉग साफ़ कर दिए गए हैं - + Clear logs लॉग साफ़ करें @@ -1614,22 +1802,22 @@ Already installed containers were found on the server. All installed containers PageSettingsServerData - + All installed containers have been added to the application सभी स्थापित कंटेनरों को एप्लिकेशन में जोड़ दिया गया है - + No new installed containers found कोई नया स्थापित कंटेनर नहीं मिला - + Do you want to reboot the server? क्या आप सर्वर को रीबूट करना चाहते हैं? - + Do you want to clear server from Amnezia software? क्या आप एमनेज़िया सॉफ़्टवेयर से सर्वर साफ़ करना चाहते हैं? @@ -1638,94 +1826,94 @@ Already installed containers were found on the server. All installed containers - - - - - - Continue - जारी रखना - + Continue + जारी रखना + + + + + + Cancel रद्द करना - + Check the server for previously installed Amnezia services पहले से स्थापित एमनेज़िया सेवाओं के लिए सर्वर की जाँच करें - + Add them to the application if they were not displayed यदि वे प्रदर्शित नहीं थे तो उन्हें एप्लिकेशन में जोड़ें - + Reboot server सर्वर रीबूट करें - + The reboot process may take approximately 30 seconds. Are you sure you wish to proceed? रीबूट प्रक्रिया में लगभग 30 सेकंड लग सकते हैं। आप निश्चित है आप आगे बढ़ना चाहते है? - + Cannot reboot server during active connection सक्रिय कनेक्शन के दौरान सर्वर को रीबूट नहीं किया जा सकता - + Remove server from application एप्लिकेशन से सर्वर हटाएं - + Do you want to remove the server from application? क्या आप एप्लिकेशन से सर्वर हटाना चाहते हैं? - + Cannot remove server during active connection सक्रिय कनेक्शन के दौरान सर्वर को हटाया नहीं जा सकता - + All users whom you shared a connection with will no longer be able to connect to it. वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे. - + Cannot clear server from Amnezia software during active connection सक्रिय कनेक्शन के दौरान एमनेज़िया सॉफ़्टवेयर से सर्वर साफ़ नहीं किया जा सकता - + Reset API config एपीआई कॉन्फिगरेशन रीसेट करें - + Do you want to reset API config? क्या आप एपीआई कॉन्फिगरेशन रीसेट करना चाहते हैं? - + Cannot reset API config during active connection सक्रिय कनेक्शन के दौरान एपीआई कॉन्फिगरेशन को रीसेट नहीं किया जा सकता - + All installed AmneziaVPN services will still remain on the server. सभी स्थापित AmneziaVPN सेवाएँ अभी भी सर्वर पर रहेंगी. - + Clear server from Amnezia software एमनेज़िया सॉफ़्टवेयर से सर्वर साफ़ करें @@ -1733,27 +1921,27 @@ Already installed containers were found on the server. All installed containers PageSettingsServerInfo - + Server name सर्वर का नाम - + Save सहेजें - + Protocols प्रोटोकॉल - + Services सेवाएं - + Management प्रबंध @@ -1761,17 +1949,17 @@ Already installed containers were found on the server. All installed containers PageSettingsServerProtocol - + settings समायोजन - + Clear %1 profile %1 प्रोफ़ाइल साफ़ करें - + Clear %1 profile? %1 प्रोफ़ाइल साफ़ करें? @@ -1781,39 +1969,39 @@ Already installed containers were found on the server. All installed containers - + Unable to clear %1 profile while there is an active connection सक्रिय कनेक्शन होने पर %1 प्रोफ़ाइल साफ़ करने में असमर्थ - + Remove निकालना - + All users with whom you shared a connection will no longer be able to connect to it. वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे. - + Cannot remove active container सक्रिय कंटेनर को हटाया नहीं जा सकता - + Remove %1 from server? सर्वर से %1 हटाएँ? - - + + Continue जारी रखना - - + + Cancel रद्द करना @@ -1821,7 +2009,7 @@ Already installed containers were found on the server. All installed containers PageSettingsServersList - + Servers सर्वर @@ -1829,201 +2017,322 @@ Already installed containers were found on the server. All installed containers PageSettingsSplitTunneling - + Default server does not support split tunneling function डिफ़ॉल्ट सर्वर स्प्लिट टनलिंग फ़ंक्शन का समर्थन नहीं करता है - + Addresses from the list should not be accessed via VPN सूची के पतों को वीपीएन के माध्यम से एक्सेस नहीं किया जाना चाहिए - + Split tunneling विभाजित सुरंग - + Mode तरीका - + Remove निकालना - + Continue जारी रखना - + Cancel रद्द करना - + Only the sites listed here will be accessed through the VPN केवल यहां सूचीबद्ध साइटों को ही वीपीएन के माध्यम से एक्सेस किया जाएगा - + Cannot change split tunneling settings during active connection सक्रिय कनेक्शन के दौरान स्प्लिट टनलिंग सेटिंग्स को नहीं बदला जा सकता - + website or IP वेबसाइट या आईपी - + Import / Export Sites आयात/निर्यात साइटें - + Import आयात - + Save site list साइट सूची सहेजें - + Save sites साइटें सहेजें - - - + + + Sites files (*.json) - + Import a list of sites साइटों की सूची आयात करें - + Replace site list साइट सूची बदलें - - + + Open sites file साइट फ़ाइल खोलें - + Add imported sites to existing ones आयातित साइटों को मौजूदा साइटों में जोड़ें + + PageSetupWizardApiServiceInfo + + + For the region + + + + + Price + + + + + Work period + + + + + Speed + + + + + Features + + + + + Connect + कनेक्ट + + + + PageSetupWizardApiServicesList + + + VPN by Amnezia + + + + + Choose a VPN service that suits your needs. + + + PageSetupWizardConfigSource - Server connection - सर्वर कनेक्शन + सर्वर कनेक्शन - Do not use connection codes from untrusted sources, as they may be created to intercept your data. - अविश्वसनीय स्रोतों से कनेक्शन कोड का उपयोग न करें, क्योंकि वे आपके डेटा को बाधित करने के लिए बनाए जा सकते हैं. + अविश्वसनीय स्रोतों से कनेक्शन कोड का उपयोग न करें, क्योंकि वे आपके डेटा को बाधित करने के लिए बनाए जा सकते हैं. - What do you have? - तुम्हारे पास क्या है? + तुम्हारे पास क्या है? - File with connection settings or backup - कनेक्शन सेटिंग्स वाली फ़ाइल + कनेक्शन सेटिंग्स वाली फ़ाइल + + + + Connection + कनेक्शन + + + + Insert the key, add a configuration file or scan the QR-code + + Insert key + + + + + Insert + डालना + + + + Continue + जारी रखना + + + + Other connection options + + + + + VPN by Amnezia + + + + + Connect to classic paid and free VPN services from Amnezia + + + + + Self-hosted VPN + + + + + Configure Amnezia VPN on your own server + + + + + Restore from backup + बैकअप से बहाल करना + + + + Open backup file + बैकअप फ़ाइल खोलें + + + + Backup files (*.backup) + बैकअप फ़ाइलें (*.backup) + + + File with connection settings कनेक्शन सेटिंग्स वाली फ़ाइल - + Open config file कॉन्फ़िग फ़ाइल खोलें - + QR code क्यू आर संहिता - + + I have nothing + मेरे पास कुछ नहीं है + + Key as text - पाठ के रूप में कुंजी + पाठ के रूप में कुंजी PageSetupWizardCredentials - + Configure your server अपना सर्वर कॉन्फ़िगर करें - + Server IP address [:port] सर्वर आईपी पता [:पोर्ट] - + Continue जारी रखना - + All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties आपके द्वारा दर्ज किया गया सभी डेटा पूरी तरह से गोपनीय रहेगा और एमनेज़िया या किसी तीसरे पक्ष को साझा या प्रकट नहीं किया जाएगा - + 255.255.255.255:22 255.255.255.255:22 - + SSH Username SSH उपयोगकर्ता नाम - + Password or SSH private key पासवर्ड या SSH निजी कुंजी - + + How to run your VPN server + + + + + Where to get connection data, step-by-step instructions for buying a VPS + + + + Ip address cannot be empty आईपी ​​पता खाली नहीं हो सकता - + Enter the address in the format 255.255.255.255:88 पता 255.255.255.255:88 प्रारूप में दर्ज करें - + Login cannot be empty लॉगिन खाली नहीं हो सकता - + Password/private key cannot be empty पासवर्ड/निजी कुंजी खाली नहीं हो सकती @@ -2031,22 +2340,22 @@ Already installed containers were found on the server. All installed containers PageSetupWizardEasy - + What is the level of internet control in your region? आपके क्षेत्र में इंटरनेट नियंत्रण का स्तर क्या है? - + Choose a VPN protocol एक वीपीएन प्रोटोकॉल चुनें - + Continue जारी रखना - + Skip setup सेटअप छोड़ें @@ -2054,38 +2363,38 @@ Already installed containers were found on the server. All installed containers PageSetupWizardInstalling - - + + Usually it takes no more than 5 minutes आमतौर पर इसमें 5 मिनट से अधिक समय नहीं लगता है - + The server has already been added to the application सर्वर को पहले ही एप्लिकेशन में जोड़ा जा चुका है - + Amnezia has detected that your server is currently Amnezia ने पता लगाया है कि आपका सर्वर वर्तमान में है - + busy installing other software. Amnezia installation अन्य सॉफ़्टवेयर स्थापित करने में व्यस्त। भूलने की बीमारी की स्थापना - + Cancel installation स्थापना रद्द करें - + will pause until the server finishes installing other software जब तक सर्वर अन्य सॉफ़्टवेयर इंस्टॉल करना समाप्त नहीं कर लेता तब तक रुकेगा - + Installing स्थापित कर रहा है @@ -2093,37 +2402,37 @@ Already installed containers were found on the server. All installed containers PageSetupWizardProtocolSettings - + Installing %1 %1 स्थापित किया जा रहा है - + More detailed अधिक विवरण - + Close बंद करना - + Network protocol नेटवर्क प्रोटोकॉल - + Port منفذ - + Install स्थापित करना - + The port must be in the range of 1 to 65535 @@ -2131,12 +2440,12 @@ Already installed containers were found on the server. All installed containers PageSetupWizardProtocols - + VPN protocol VPN प्रोटोकॉल - + Choose the one with the highest priority for you. Later, you can install other protocols and additional services, such as DNS proxy and SFTP. वह चुनें जो आपके लिए सर्वोच्च प्राथमिकता हो। बाद में, आप अन्य प्रोटोकॉल और अतिरिक्त सेवाएँ, जैसे DNS प्रॉक्सी और SFTP स्थापित कर सकते हैं. @@ -2144,7 +2453,7 @@ Already installed containers were found on the server. All installed containers PageSetupWizardQrReader - + Point the camera at the QR code and hold for a couple of seconds. कैमरे को QR कोड पर रखें और कुछ सेकंड के लिए रोककर रखें. @@ -2152,60 +2461,55 @@ Already installed containers were found on the server. All installed containers PageSetupWizardStart - Settings restored from backup file - बैकअप फ़ाइल से सेटिंग्स पुनर्स्थापित की गईं + बैकअप फ़ाइल से सेटिंग्स पुनर्स्थापित की गईं - Free service for creating a personal VPN on your server. - आपके सर्वर पर व्यक्तिगत वीपीएन बनाने के लिए निःशुल्क सेवा. + आपके सर्वर पर व्यक्तिगत वीपीएन बनाने के लिए निःशुल्क सेवा. - Helps you access blocked content without revealing your privacy, even to VPN providers. - आपकी गोपनीयता को उजागर किए बिना, यहां तक ​​कि वीपीएन प्रदाताओं को भी, अवरुद्ध सामग्री तक पहुंचने में आपकी सहायता करता है. + आपकी गोपनीयता को उजागर किए बिना, यहां तक ​​कि वीपीएन प्रदाताओं को भी, अवरुद्ध सामग्री तक पहुंचने में आपकी सहायता करता है. - I have the data to connect - मेरे पास कनेक्ट करने के लिए डेटा है + मेरे पास कनेक्ट करने के लिए डेटा है - I have nothing - मेरे पास कुछ नहीं है + मेरे पास कुछ नहीं है - - https://amnezia.org/instructions/0_starter-guide - + + Let's get started + PageSetupWizardTextKey - + Connection key कनेक्शन कुंजी - + A line that starts with vpn://... एक लाइन जो vpn://... से शुरू होती है... - + Key चाबी - + Insert डालना - + Continue जारी रखना @@ -2213,32 +2517,32 @@ Already installed containers were found on the server. All installed containers PageSetupWizardViewConfig - + New connection नया कनेक्शन - + Collapse content सामग्री संक्षिप्त करें - + Show content सामग्री दिखाओ - + Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider. वायरगार्ड अस्पष्टीकरण सक्षम करें. यदि आपके प्रदाता पर वायरगार्ड अवरुद्ध है तो यह उपयोगी हो सकता है. - + Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data. केवल उन स्रोतों से कनेक्शन कोड का उपयोग करें जिन पर आपको भरोसा है। हो सकता है कि आपके डेटा को इंटरसेप्ट करने के लिए सार्वजनिक स्रोतों से कोड बनाए गए हों. - + Connect कनेक्ट @@ -2246,37 +2550,37 @@ Already installed containers were found on the server. All installed containers PageShare - + Save OpenVPN config OpenVPN कॉन्फ़िगरेशन सहेजें - + Save WireGuard config वायरगार्ड कॉन्फ़िगरेशन सहेजें - + Save AmneziaWG config AmneziaWG कॉन्फ़िगरेशन सहेजें - + Save Shadowsocks config शैडोसॉक्स कॉन्फ़िगरेशन सहेजें - + Save Cloak config क्लोक कॉन्फ़िगरेशन सहेजें - + Save XRay config एक्सरे कॉन्फिगरेशन सहेजें - + For the AmneziaVPN app AmneziaVPN ऐप के लिए @@ -2285,78 +2589,78 @@ Already installed containers were found on the server. All installed containers OpenVpn मूल स्वरूप - + WireGuard native format वायरगार्ड मूल प्रारूप - + AmneziaWG native format AmneziaWG मूल प्रारूप - + Shadowsocks native format शैडोसॉक्स मूल प्रारूप - + Cloak native format लबादा देशी स्वरूप - + XRay native format एक्सरे देशी प्रारूप - + Share VPN Access VPN एक्सेस साझा करें - + Share full access to the server and VPN सर्वर और वीपीएन तक पूर्ण पहुंच साझा करें - + Use for your own devices, or share with those you trust to manage the server. अपने स्वयं के उपकरणों के लिए उपयोग करें, या सर्वर को प्रबंधित करने के लिए उन लोगों के साथ साझा करें जिन पर आप भरोसा करते हैं. - - + + Users उपयोगकर्ताओं - + Share VPN access without the ability to manage the server सर्वर को प्रबंधित करने की क्षमता के बिना वीपीएन एक्सेस साझा करें - + Search खोज - + Creation date: %1 निर्माण दिनांक: %1 - + Latest handshake: %1 नवीनतम हाथ मिलाना: %1 - + Data received: %1 प्राप्त डेटा: %1 - + Data sent: %1 डेटा भेजा गया: %1 @@ -2365,96 +2669,96 @@ Already installed containers were found on the server. All installed containers निर्माण तिथि: - + Rename नाम बदलें - + Client name ग्राहक नाम - + Save सहेजें - + Revoke निरस्त करें - + Revoke the config for a user - %1? किसी उपयोक्ता के लिए कॉन्फ़िगरेशन निरस्त करें - %1? - + The user will no longer be able to connect to your server. उपयोगकर्ता अब आपके सर्वर से कनेक्ट नहीं हो पाएगा. - + Continue जारी रखना - + Cancel रद्द करना - + Connection कनेक्शन - - + + Server सर्वर - + File with connection settings to कनेक्शन सेटिंग्स वाली फ़ाइल - - + + Protocol शिष्टाचार - + Connection to कनेक्शन के लिए - + Config revoked कॉन्फ़िगरेशन निरस्त कर दिया गया - + OpenVPN native format - + User name उपयोगकर्ता नाम - - + + Connection format कनेक्शन प्रारूप - - + + Share शेयर करना @@ -2462,50 +2766,50 @@ Already installed containers were found on the server. All installed containers PageShareFullAccess - + Full access to the server and VPN सर्वर और वीपीएन तक पूर्ण पहुंच - + We recommend that you use full access to the server only for your own additional devices. हम अनुशंसा करते हैं कि आप सर्वर तक पूर्ण पहुंच का उपयोग केवल अपने अतिरिक्त उपकरणों के लिए करें. - + If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. यदि आप अन्य लोगों के साथ पूर्ण पहुंच साझा करते हैं, तो वे सर्वर पर प्रोटोकॉल और सेवाओं को हटा और जोड़ सकते हैं, जिससे वीपीएन सभी उपयोगकर्ताओं के लिए गलत तरीके से काम करेगा. - + Server सर्वर - + Accessing एक्सेस करना - + File with accessing settings to एक्सेस सेटिंग्स वाली फ़ाइल - + Share शेयर करना - + Connection to के लिए कनेक्शन - + File with connection settings to कनेक्शन सेटिंग्स वाली फ़ाइल @@ -2513,15 +2817,20 @@ Already installed containers were found on the server. All installed containers PageStart - + Logging was disabled after 14 days, log files were deleted 14 दिनों के बाद लॉगिंग अक्षम कर दी गई, लॉग फ़ाइलें हटा दी गईं + + + Settings restored from backup file + बैकअप फ़ाइल से सेटिंग्स पुनर्स्थापित की गईं + PopupType - + Close बंद करना @@ -2892,7 +3201,12 @@ Already installed containers were found on the server. All installed containers - + + Missing AGW public key + + + + ErrorCode: %1. ErrorCode: %1. @@ -2957,37 +3271,37 @@ Already installed containers were found on the server. All installed containers कॉन्फ़िगरेशन में सर्वर से कनेक्ट करने के लिए कोई कंटेनर और क्रेडेंशियल नहीं है - + QFile error: The file could not be opened Qफ़ाइल त्रुटि: फ़ाइल खोली नहीं जा सकी - + QFile error: An error occurred when reading from the file Qफ़ाइल त्रुटि: फ़ाइल से पढ़ते समय एक त्रुटि उत्पन्न हुई - + QFile error: The file could not be accessed Qफ़ाइल त्रुटि: फ़ाइल तक नहीं पहुंचा जा सका - + QFile error: An unspecified error occurred Qफ़ाइल त्रुटि: एक अनिर्दिष्ट त्रुटि उत्पन्न हुई - + QFile error: A fatal error occurred Qफ़ाइल त्रुटि: एक घातक त्रुटि उत्पन्न हुई - + QFile error: The operation was aborted Qफ़ाइल त्रुटि: ऑपरेशन निरस्त कर दिया गया था - + Internal error आंतरिक त्रुटि @@ -3427,7 +3741,7 @@ While it offers a blend of security, stability, and speed, it's essential t SelectLanguageDrawer - + Choose language भाषा चुनें @@ -3435,13 +3749,13 @@ While it offers a blend of security, stability, and speed, it's essential t Settings - + Server #1 सर्वर #1 - - + + Server सर्वर @@ -3462,39 +3776,39 @@ While it offers a blend of security, stability, and speed, it's essential t ShareConnectionDrawer - - + + Save AmneziaVPN config AmneziaVPN कॉन्फ़िगरेशन सहेजें - + Share शेयर करना - + Copy कॉपी - - + + Copied कॉपी किया गया - + Copy config string कॉन्फिग स्ट्रिंग कॉपी करें - + Show connection settings कनेक्शन सेटिंग दिखाएं - + To read the QR code in the Amnezia app, select "Add server" → "I have data to connect" → "QR code, key or settings file" एमनेज़िया ऐप में क्यूआर कोड पढ़ने के लिए, "सर्वर जोड़ें" → "मेरे पास कनेक्ट करने के लिए डेटा है" → "क्यूआर कोड, कुंजी या सेटिंग्स फ़ाइल" चुनें। @@ -3578,7 +3892,7 @@ While it offers a blend of security, stability, and speed, it's essential t TextFieldWithHeaderType - + The field can't be empty फ़ील्ड खाली नहीं हो सकती @@ -3637,7 +3951,7 @@ While it offers a blend of security, stability, and speed, it's essential t amnezia::ContainerProps - + Low कम @@ -3650,17 +3964,17 @@ While it offers a blend of security, stability, and speed, it's essential t चरम - + High - + I just want to increase the level of my privacy. मैं बस अपनी गोपनीयता का स्तर बढ़ाना चाहता हूं. - + I want to bypass censorship. This option recommended in most cases. मैं सेंसरशिप को दरकिनार करना चाहता हूं। अधिकांश मामलों में इस विकल्प की अनुशंसा की जाती है. @@ -3672,12 +3986,12 @@ While it offers a blend of security, stability, and speed, it's essential t main2 - + Private key passphrase निजी कुंजी पासफ़्रेज़ - + Save सहेजें diff --git a/client/translations/amneziavpn_my_MM.ts b/client/translations/amneziavpn_my_MM.ts index 2e4cd920..0a71b0a5 100644 --- a/client/translations/amneziavpn_my_MM.ts +++ b/client/translations/amneziavpn_my_MM.ts @@ -1,6 +1,54 @@ + + ApiServicesModel + + + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s + + + + + VPN to access blocked sites in regions with high levels of Internet censorship. + + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. + + + + + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship + + + + + %1 MBit/s + + + + + %1 days + + + + + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> + + + + + Free + + + + + %1 $/month + + + AppSplitTunnelingController @@ -27,7 +75,7 @@ ConnectButton - + Unable to disconnect during configuration preparation @@ -35,62 +83,62 @@ ConnectionController - + VPN Protocols is not installed. Please install VPN container at first VPN ပရိုတိုကောများကို မထည့်သွင်းရသေးပါ။ ကျေးဇူးပြု၍ VPN ကွန်တိန်နာကို အရင်ထည့်သွင်းပါ။ - + Connecting... ချိတ်ဆက်နေပါပြီ... - + Connected ချိတ်ဆက်ပြီးသွားပါပြီ - + Preparing... - + Settings updated successfully, reconnnection... ဆက်တင်များကို အောင်မြင်စွာ အပ်ဒိတ်လုပ်ပြီးပါပြီ၊ ပြန်လည်ချိတ်ဆက်နေပါသည်... - + Settings updated successfully ဆက်တင်များကို အောင်မြင်စွာ အပ်ဒိတ်လုပ်ပြီးပါပြီ။ - + The selected protocol is not supported on the current platform ရွေးချယ်ထားသော ပရိုတိုကောကို လက်ရှိပလက်ဖောင်းပေါ်တွင် အ‌ထောက်အပံ့မပေးထားပါ။ - + unable to create configuration - + Reconnecting... ပြန်လည်ချိတ်ဆက်နေပါသည်... - - - + + + Connect ချိတ်ဆက်မည် - + Disconnecting... အဆက်အသွယ်ဖြတ်နေပါသည်... @@ -131,7 +179,7 @@ &Paste - + &SelectAll &SelectAll @@ -230,84 +278,104 @@ Can't be disabled for current server InstallController - + %1 installed successfully. %1 ကို အောင်မြင်စွာ ထည့်သွင်းပြီးပါပြီ. - + %1 is already installed on the server. %1 ကို ဆာဗာတွင် ထည့်သွင်းပြီးဖြစ်သည်. - + Added containers that were already installed on the server ဆာဗာတွင် ထည့်သွင်းပြီးသား ကွန်တိန်နာများကို ပေါင်းထည့်ပြီးပါပြီ။ - + Already installed containers were found on the server. All installed containers have been added to the application ထည့်သွင်းပြီးသား ကွန်တိန်နာများကို ဆာဗာပေါ်တွင် တွေ့ရှိခဲ့သည်။ ထည့်သွင်းထားသည့် ကွန်တိန်နာအားလုံးကို အပလီကေးရှင်းထဲသို့ ပေါင်းထည့်ပြီးပါပြီ။ - + Settings updated successfully ဆက်တင်များကို အောင်မြင်စွာ အပ်ဒိတ်လုပ်ပြီးပါပြီ။ - + Server '%1' was rebooted ဆာဗာ '%1' ကို ပြန်လည်စတင်ခဲ့သည်။ - + Server '%1' was removed ဆာဗာ '%1' ကို ဖယ်ရှားခဲ့သည်။ - + All containers from server '%1' have been removed ဆာဗာ '%1' မှ ကွန်တိန်နာအားလုံးကို ဖယ်ရှားလိုက်ပါပြီ။ - + %1 has been removed from the server '%2' %1 ကို ဆာဗာ '%2' မှ ဖယ်ရှားလိုက်ပါပြီ - + + Api config removed + + + + %1 cached profile cleared - + Please login as the user အသုံးပြုသူအဖြစ် log in ဝင်ရောက်ပါ။ - + Server added successfully ဆာဗာကို အောင်မြင်စွာ ထည့်သွင်းပြီးပါပြီ။ + + + %1 installed successfully. + + + + + API config reloaded + + + + + Successfully changed the country of connection to %1 + + InstalledAppsDrawer - + Choose application - + application name - + Add selected @@ -362,45 +430,53 @@ Already installed containers were found on the server. All installed containers PageDeinstalling - + Removing services from %1 ဝန်ဆောင်မှုများကို %1 မှ ဖယ်ရှားနေပါသည်။ - + Usually it takes no more than 5 minutes များသောအားဖြင့် 5 မိနစ်ထက်မပိုပါ။ + + PageDevMenu + + + Gateway endpoint + + + PageHome - + Logging enabled - + Split tunneling enabled split tunnelling ဖွင့်ထားပါသည်။ - + Split tunneling disabled split tunnelling ပိတ်ထားပါသည်။ - + VPN protocol VPN ပရိုတိုကော - + Servers ဆာဗာများ - + Unable change server while there is an active connection လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆာဗာကို ပြောင်းလဲ၍မရပါ။ @@ -408,17 +484,17 @@ Already installed containers were found on the server. All installed containers PageProtocolAwgSettings - + AmneziaWG settings AmneziaWG ဆက်တင်များ - + Port Port - + MTU @@ -431,42 +507,87 @@ Already installed containers were found on the server. All installed containers AmneziaWG ကို ဆာဗာမှ ဖယ်ရှားမည်လား? - + All users with whom you shared a connection with will no longer be able to connect to it. သင့်တွင် သင့်ကိုမည်သည့် ချိတ်ဆက်ထားသော အသုံးပြုသူများသည် အကြောင်းအရာသို့ ဆက်သွယ်ရန် မရနိုင်ပါ။ - + Save သိမ်းဆည်းမည် - + + Jc - Junk packet count + + + + + Jmin - Junk packet minimum size + + + + + Jmax - Junk packet maximum size + + + + + S1 - Init packet junk size + + + + + S2 - Response packet junk size + + + + + H1 - Init packet magic header + + + + + H2 - Response packet magic header + + + + + H4 - Transport packet magic header + + + + + H3 - Underload packet magic header + + + + The values of the H1-H4 fields must be unique - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) - + Save settings? သိမ်းဆည်းမည်လား။ - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Cancel ပယ်ဖျက်မည် - + Unable change settings while there is an active connection @@ -474,33 +595,33 @@ Already installed containers were found on the server. All installed containers PageProtocolCloakSettings - + Cloak settings ဖုံးကွယ်အသွင်ယူမှု ဆက်တင်များ - + Disguised as traffic from traffic အဖြစ် အသွင်ယူထားသည် - + Port Port - + Cipher စာဝှက် - + Save သိမ်းဆည်းမည် - + Unable change settings while there is an active connection @@ -508,170 +629,170 @@ Already installed containers were found on the server. All installed containers PageProtocolOpenVpnSettings - + OpenVPN settings OpenVPN ဆက်တင်များ - + VPN address subnet VPN လိပ်စာ ကွန်ရက်ခွဲ - + Network protocol ကွန်ယက် ပရိုတိုကော - + Port Port - + Auto-negotiate encryption အလိုအလျောက် ညှိနှိုင်း ကုဒ်ဝှက်ခြင်း - + Hash Hash - + SHA512 SHA512 - + SHA384 SHA384 - + SHA256 SHA256 - + SHA3-512 SHA3-512 - + SHA3-384 SHA3-384 - + SHA3-256 SHA3-256 - + whirlpool whirlpool - + BLAKE2b512 BLAKE2b512 - + BLAKE2s256 BLAKE2s256 - + SHA1 SHA1 - + Cipher စာဝှက် - + AES-256-GCM AES-256-GCM - + AES-192-GCM AES-192-GCM - + AES-128-GCM AES-128-GCM - + AES-256-CBC AES-256-CBC - + AES-192-CBC AES-192-CBC - + AES-128-CBC AES-128-CBC - + ChaCha20-Poly1305 ChaCha20-Poly1305 - + ARIA-256-CBC ARIA-256-CBC - + CAMELLIA-256-CBC CAMELLIA-256-CBC - + none none - + TLS auth TLS auth - + Block DNS requests outside of VPN VPN ပြင်ပရှိ DNS တောင်းဆိုမှုများကို ပိတ်ပင်မည်။ - + Additional client configuration commands ထပ်တိုး client ဖွဲ့စည်းမှုဆိုင်ရာ ညွှန်ကြားချက်များ - - + + Commands: အမိန့်ပေးခိုင်းစေချက်များ: - + Additional server configuration commands ထပ်တိုး ဆာဗာ ဖွဲ့စည်းမှုဆိုင်ရာ ညွှန်ကြားချက်များ - + Unable change settings while there is an active connection @@ -696,7 +817,7 @@ Already installed containers were found on the server. All installed containers ပယ်ဖျက်မည် - + Save သိမ်းဆည်းမည် @@ -704,32 +825,32 @@ Already installed containers were found on the server. All installed containers PageProtocolRaw - + settings ဆက်တင်များ - + Show connection options ချိတ်ဆက်မှုရွေးချယ်စရာများကို ပြပါ။ - + Connection options %1 ချိတ်ဆက်မှုရွေးချယ်စရာများ %1 - + Remove ဖယ်ရှားမည် - + Remove %1 from server? %1 ကို ဆာဗာမှ ဖယ်ရှားမည်လား? - + All users with whom you shared a connection with will no longer be able to connect to it. သင့်တွင် သင့်ကိုမည်သည့် ချိတ်ဆက်ထားသော အသုံးပြုသူများသည် အကြောင်းအရာသို့ ဆက်သွယ်ရန် မရနိုင်ပါ။ @@ -738,12 +859,12 @@ Already installed containers were found on the server. All installed containers Все пользователи, с которыми вы поделились этим VPN-протоколом, больше не смогут к нему подключаться. - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Cancel ပယ်ဖျက်မည် @@ -751,28 +872,28 @@ Already installed containers were found on the server. All installed containers PageProtocolShadowSocksSettings - + Shadowsocks settings Shadowsocks ဆက်တင်များ - + Port Port - + Cipher စာဝှက် - + Save သိမ်းဆည်းမည် - + Unable change settings while there is an active connection @@ -780,22 +901,22 @@ Already installed containers were found on the server. All installed containers PageProtocolWireGuardSettings - + WG settings - + Port Port - + MTU - + Unable change settings while there is an active connection @@ -808,7 +929,7 @@ Already installed containers were found on the server. All installed containers ပယ်ဖျက်မည် - + Save သိမ်းဆည်းမည် @@ -816,22 +937,22 @@ Already installed containers were found on the server. All installed containers PageProtocolXraySettings - + XRay settings - + Disguised as traffic from traffic အဖြစ် အသွင်ယူထားသည် - + Save သိမ်းဆည်းမည် - + Unable change settings while there is an active connection @@ -846,39 +967,39 @@ Already installed containers were found on the server. All installed containers PageServiceDnsSettings - + A DNS service is installed on your server, and it is only accessible via VPN. DNS ဝန်ဆောင်မှုကို သင့်ဆာဗာတွင် ထည့်သွင်းထားပြီးဖြစ်ပြီး ၎င်းကို VPN မှတစ်ဆင့်သာ အသုံးပြုနိုင်သည်. - + The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab. DNS လိပ်စာသည် သင့်ဆာဗာလိပ်စာနှင့် အတူတူပင်ဖြစ်ပါသည်။ ချိတ်ဆက်မှုတက်ဘ်အောက်ရှိ ဆက်တင်များတွင် DNS ကို ပြင်ဆင်ချိန်ညှိနိုင်ပါသည်. - + Remove ဖယ်ရှားမည် - + Remove %1 from server? %1 ကို ဆာဗာမှ ဖယ်ရှားမည်လား? - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Cancel ပယ်ဖျက်မည် - + Cannot remove AmneziaDNS from running server @@ -886,157 +1007,153 @@ Already installed containers were found on the server. All installed containers PageServiceSftpSettings - + Settings updated successfully ဆက်တင်များကို အောင်မြင်စွာ အပ်ဒိတ်လုပ်ပြီးပါပြီ။ - + SFTP settings SFTP ဆက်တင်များ - + Host Host - - - - + + + + Copied ကူးယူပြီးပါပြီ - + Port Port - + User name အသုံးပြုသူနာမည် - + Password စကားဝှက် - + Mount folder on device ဖိုင်တွဲကို စက်တွင် တပ်ဆင်မည်။ - + In order to mount remote SFTP folder as local drive, perform following steps: <br> အဝေးမှ SFTP ဖိုင်တွဲကို စက်တွင်း drive အဖြစ် တပ်ဆင်ရန်အတွက် အောက်ပါအဆင့်များကို လုပ်ဆောင်ပါ: <br> - - + + <br>1. Install the latest version of <br>၁။ နောက်ဆုံးထွက်ဗားရှင်းကို ထည့်သွင်းမည် - - + + <br>2. Install the latest version of <br>၂။ နောက်ဆုံးထွက်ဗားရှင်းကို ထည့်သွင်းမည် - + Detailed instructions အသေးစိတ်ညွှန်ကြားချက်များ - Remove SFTP and all data stored there - SFTP ဖယ်ရှားပါ + SFTP ဖယ်ရှားပါ - Remove SFTP and all data stored there? - SFTP နှင့် ထိုနေရာတွင် သိမ်းဆည်းထားသည့် ဒေတာအားလုံးကို ဖယ်ရှားမည်လား? + SFTP နှင့် ထိုနေရာတွင် သိမ်းဆည်းထားသည့် ဒေတာအားလုံးကို ဖယ်ရှားမည်လား? - Continue - ဆက်လက်လုပ်ဆောင်မည် + ဆက်လက်လုပ်ဆောင်မည် - Cancel - ပယ်ဖျက်မည် + ပယ်ဖျက်မည် PageServiceSocksProxySettings - + Settings updated successfully ဆက်တင်များကို အောင်မြင်စွာ အပ်ဒိတ်လုပ်ပြီးပါပြီ။ - - + + SOCKS5 settings - + Host Host - - - - + + + + Copied ကူးယူပြီးပါပြီ - - + + Port Port - + User name အသုံးပြုသူနာမည် - - + + Password စကားဝှက် - + Username - - + + Change connection settings - + The port must be in the range of 1 to 65535 - + Password cannot be empty - + Username cannot be empty @@ -1044,95 +1161,96 @@ Already installed containers were found on the server. All installed containers PageServiceTorWebsiteSettings - + Settings updated successfully ဆက်တင်များကို အောင်မြင်စွာ အပ်ဒိတ်လုပ်ပြီးပါပြီ။ - + Tor website settings Tor ဝဘ်ဆိုက်ဆက်တင်များ - + Website address ဝဘ်ဆိုဒ်လိပ်စာ - + Copied ကူးယူပြီးပါပြီ - + Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL. ဤ URL ကိုဖွင့်ရန် <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> ကို အသုံးပြုပါ. - + After creating your onion site, it takes a few minutes for the Tor network to make it available for use. သင်၏ onion ဆိုက်ကို ဖန်တီးပြီးနောက်၊ Tor ကွန်ရက်က ၄င်းကိုအသုံးပြုနိုင်အောင်ပြုလုပ်‌ပေးရန် မိနစ်အနည်းငယ်အချိန်ယူသည်. - + When configuring WordPress set the this onion address as domain. WordPress ကို ချိန်ညှိသည့်အခါ ဤ onion လိပ်စာကို domain အဖြစ် သတ်မှတ်ပါ. - Remove website - ဝဘ်ဆိုက်ကိုဖယ်ရှားမည် + ဝဘ်ဆိုက်ကိုဖယ်ရှားမည် - The site with all data will be removed from the tor network. - ဒေတာအားလုံးပါသည့် ဆိုက်ကို tor ကွန်ရက်မှ ဖယ်ရှားပါမည်. + ဒေတာအားလုံးပါသည့် ဆိုက်ကို tor ကွန်ရက်မှ ဖယ်ရှားပါမည်. - Continue - ဆက်လက်လုပ်ဆောင်မည် + ဆက်လက်လုပ်ဆောင်မည် - Cancel - ပယ်ဖျက်မည် + ပယ်ဖျက်မည် PageSettings - + Settings ဆက်တင်များ - + Servers ဆာဗာများ - + Connection ချိတ်ဆက်မှု - + Application အပလီကေးရှင်း - + Backup backup ယူမည် - + About AmneziaVPN AmneziaVPN အကြောင်း + Dev console + + + + Close application အပလီကေးရှင်းကို ပိတ်မည် @@ -1140,135 +1258,209 @@ Already installed containers were found on the server. All installed containers PageSettingsAbout - + Support Amnezia Amnezia ကိုကူညီပံ့ပိုးမည် - + Amnezia is a free and open-source application. You can support the developers if you like it. Amnezia သည် အခမဲ့ဖြစ်ပြီး open-source application တစ်ခုဖြစ်သည်။ သင်နှစ်သက်ပါက developer များကို ပံ့ပိုးနိုင်ပါသည်။ - + Contacts ဆက်သွယ်ရန်လိပ်စာများ - + Telegram group Telegram ဂရု - + To discuss features feature များကိုဆွေးနွေးရန် - + https://t.me/amnezia_vpn_en https://t.me/amnezia_vpn - + Mail မေးလ် - + For reviews and bug reports သုံးသပ်ချက်များနှင့် ချွတ်ယွင်းချက်အစီရင်ခံစာများအတွက် - + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website ဝဘ်ဆိုက် - https://amnezia.org - https://amnezia.org + https://amnezia.org - + Software version: %1 ဆော့ဖ်ဝဲဗားရှင်း: %1 - + Check for updates အပ်ဒိတ်များရှိမရှိ စစ်ဆေးမည် - + Privacy Policy ကိုယ်ရေးအချက်အလက်မူဝါဒ - PageSettingsAppSplitTunneling + PageSettingsApiServerInfo - - Cannot change split tunneling settings during active connection - လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် split tunneling ဆက်တင်များကို ပြောင်းလဲ၍မရပါ - - - - Only the apps from the list should have access via VPN + + For the region - - Apps from the list should not have access via VPN + + Price - - App split tunneling + + Work period - - Mode - Mode + + Speed + - - Remove - ဖယ်ရှားမည် + + Support tag + - + + Copied + ကူးယူပြီးပါပြီ + + + + Reload API config + + + + + Reload API config? + + + + + Continue - + + Cancel ပယ်ဖျက်မည် - + + Cannot reload API config during active connection + + + + + Remove from application + + + + + Remove from application? + + + + + Cannot remove server during active connection + + + + + PageSettingsAppSplitTunneling + + + Cannot change split tunneling settings during active connection + လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် split tunneling ဆက်တင်များကို ပြောင်းလဲ၍မရပါ + + + + Only the apps from the list should have access via VPN + + + + + Apps from the list should not have access via VPN + + + + + App split tunneling + + + + + Mode + Mode + + + + Remove + ဖယ်ရှားမည် + + + + Continue + + + + + Cancel + ပယ်ဖျက်မည် + + + application name - + Open executable file - + Executable files (*.*) @@ -1276,102 +1468,102 @@ Already installed containers were found on the server. All installed containers PageSettingsApplication - + Application အပလီကေးရှင်း - + Allow application screenshots အပလီကေးရှင်းကို screenshot ရိုက်ရန်ခွင့်ပြုမည် - + Enable notifications - + Enable notifications to show the VPN state in the status bar - + Auto start အလိုအ‌လျှောက်စတင်မည် - + Launch the application every time the device is starts စက်စတင်ချိန်တိုင်း အပလီကေးရှင်းကို စတင်မည် - + Auto connect အလိုအ‌လျှောက်ချိတ်ဆက်မည် - + Connect to VPN on app start အက်ပ်စတင်ချိန်တွင် VPN သို့ ချိတ်ဆက်မည် - + Start minimized အက်ပ်စတင်သည့်အခါ minimized ထားပြီးစတင်မည် - + Launch application minimized အက်ပ်စတင်သည့်အခါ minimized ထားပြီးစတင်မည် - + Language ဘာသာစကား - + Logging လော့ဂ်အင် - + Enabled ဖွင့်ထားပါသည် - + Disabled ပိတ်ထားပါသည် - + Reset settings and remove all data from the application ဆက်တင်များနဂိုတိုင်းထားပြီး အပလီကေးရှင်းမှဒေတာအားလုံးဖယ်ရှားမည် - + Reset settings and remove all data from the application? ဆက်တင်များကို ပြန်လည်သတ်မှတ်ပြီး အပလီကေးရှင်းမှ ဒေတာအားလုံးကို ဖယ်ရှားမည်လား? - + All settings will be reset to default. All installed AmneziaVPN services will still remain on the server. ဆက်တင်အားလုံးကို မူရင်းအတိုင်း ပြန်လည်သတ်မှတ်ပါမည်. ထည့်သွင်းထားသော AmneziaVPN ဝန်ဆောင်မှုများအားလုံးသည် ဆာဗာပေါ်တွင် ဆက်လက်ရှိနေမည်ဖြစ်သည်. - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Cancel ပယ်ဖျက်မည် - + Cannot reset settings during active connection @@ -1379,7 +1571,7 @@ Already installed containers were found on the server. All installed containers PageSettingsBackup - + Settings restored from backup file ဆက်တင်များကို အရန်ဖိုင်မှ ပြန်လည်ရယူပြီးပါပြီ @@ -1458,62 +1650,62 @@ Already installed containers were found on the server. All installed containers PageSettingsConnection - + Connection ချိတ်ဆက်မှု - + Use AmneziaDNS AmneziaDNS ကို အသုံးပြုမည် - + If AmneziaDNS is installed on the server အကယ်၍ AmneziaDNS ကို ဆာဗာတွင် ထည့်သွင်းထားလျှင် - + DNS servers DNS ဆာဗာများ - + When AmneziaDNS is not used or installed AmneziaDNS ကို အသုံးမပြု သို့မဟုတ် ထည့်သွင်းခြင်းမပြုသည့်အခါ - + Allows you to use the VPN only for certain Apps အချို့သောအက်ပ်များအတွက်သာ VPN ကို အသုံးပြုခွင့်ပေးသည် - + KillSwitch - + Disables your internet if your encrypted VPN connection drops out for any reason. - + Cannot change killSwitch settings during active connection - + Site-based split tunneling ဝက်ဆိုဒ်အခြေပြု split tunneling - + Allows you to select which sites you want to access through the VPN VPN မှတဆင့် သင်ဝင်ရောက်လိုသည့်ဆိုဒ်များကို ရွေးချယ်စေနိုင်သည် - + App-based split tunneling App အခြေပြု split tunneling @@ -1521,62 +1713,62 @@ Already installed containers were found on the server. All installed containers PageSettingsDns - + Default server does not support custom DNS မူရင်းဆာဗာသည် စိတ်ကြိုက် DNS ကို အထောက်အပံ့မပေးပါ - + DNS servers DNS ဆာဗာများ - + If AmneziaDNS is not used or installed AmneziaDNS ကို အသုံးမပြု သို့မဟုတ် ထည့်သွင်းခြင်းမပြုသည့်အခါ - + Primary DNS Primary DNS - + Secondary DNS Secondary DNS - + Restore default မူရင်းအတိုင်းပြန်လည်ထားရှိမည် - + Restore default DNS settings? မူရင်း DNS ဆက်တင်များကို ပြန်လည်ရယူလိုပါသလား? - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Cancel ပယ်ဖျက်မည် - + Settings have been reset ဆက်တင်များကို ပြန်လည်သတ်မှတ်ပြီးပါပြီ - + Save သိမ်းဆည်းမည် - + Settings saved ဆက်တင်များကို သိမ်းဆည်းပြီးပြီ @@ -1584,73 +1776,73 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - + Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - + Logging လော့ဂ်အင် - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. ဤလုပ်ဆောင်ချက်ကို ဖွင့်ခြင်းဖြင့် အပလီကေးရှင်း၏ မှတ်တမ်းများကို အလိုအလျောက် သိမ်းဆည်းပေးမည် ဖြစ်ပြီး မူရင်းအတိုင်း၊ မှတ်တမ်းလုပ်ဆောင်ချက်ကို ပိတ်ထားသည်။ အပလီကေးရှင်းချို့ယွင်းချက်ရှိသောအခါ မှတ်တမ်းသိမ်းဆည်းခြင်းကို ဖွင့်ပါ။ - + Save logs မှတ်တမ်းများကိုသိမ်းဆည်းမည် - + Open folder with logs မှတ်တမ်းများဖြင့် ဖိုင်တွဲကိုဖွင့်မည် - + Save သိမ်းဆည်းမည် - + Logs files (*.log) မှတ်တမ်းဖိုင်များ (*.log) မှတ်တမ်းဖိုင်များ (*.log) - + Logs file saved မှတ်တမ်းဖိုင်များသိမ်းဆည်းပြီးပါပြီ - + Save logs to file မှတ်တမ်းများကို ဖိုင်တွင်သိမ်းဆည်းမည် - + Clear logs? မှတ်တမ်းများရှင်းလင်းမည်လား? - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Cancel ပယ်ဖျက်မည် - + Logs have been cleaned up မှတ်တမ်းများကို ရှင်းလင်းပြီးပါပြီ - + Clear logs မှတ်တမ်းများရှင်းလင်းမည် @@ -1658,7 +1850,7 @@ Already installed containers were found on the server. All installed containers PageSettingsServerData - + All installed containers have been added to the application ထည့်သွင်းထားသည့် ကွန်တိန်နာအားလုံးကို အပလီကေးရှင်းသို့ ပေါင်းထည့်လိုက်ပြီ @@ -1675,7 +1867,7 @@ Already installed containers were found on the server. All installed containers ကက်ရှ်ပရိုဖိုင်များကို ရှင်းမည်လား? - + No new installed containers found အသစ်ထည့်သွင်းထားသော ကွန်တိန်နာများ မတွေ့ရှိပါ @@ -1684,104 +1876,104 @@ Already installed containers were found on the server. All installed containers - - - - - - Continue - ဆက်လက်လုပ်ဆောင်မည် - + Continue + ဆက်လက်လုပ်ဆောင်မည် + + + + + + Cancel ပယ်ဖျက်မည် - + Check the server for previously installed Amnezia services ယခင်က ထည့်သွင်းထားသော Amnezia ဝန်ဆောင်မှုများရှိမရှိ ဆာဗာကို စစ်ဆေးမည် - + Add them to the application if they were not displayed ဖော်ဆောင်ပြသခြင်းမရှိပါက ၎င်းတို့ကို အပလီကေးရှင်းထဲသို့ ထည့်မည် - + Reboot server ဆာဗာကို ပြန်လည်စတင်မည် - + Do you want to reboot the server? ဆာဗာကို ပြန်လည်စတင်ချင်ပါသလား? - + The reboot process may take approximately 30 seconds. Are you sure you wish to proceed? ပြန်လည်စတင်သည့် လုပ်ငန်းစဉ်သည် စက္ကန့် 30 ခန့် ကြာနိုင်သည်. ဆက်လက်လုပ်ဆောင်လိုပါသလား? - + Cannot reboot server during active connection - + Do you want to remove the server from application? ဆာဗာကို အပလီကေးရှင်းမှဖယ်ရှားချင်ပါသလား? - + Cannot remove server during active connection - + Do you want to clear server from Amnezia software? ဆာဗာကို Amnezia ဆော့ဖ်ဝဲလ်မှ ရှင်းလင်းလိုပါသလား? - + All users whom you shared a connection with will no longer be able to connect to it. သင်ချိတ်ဆက်မှုတစ်ခုနှင့် မျှဝေထားသည့် အသုံးပြုသူအားလုံး ၎င်းကို ချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ။ - + Cannot clear server from Amnezia software during active connection - + Reset API config API config ကို ပြန်လည်သတ်မှတ်မည် - + Do you want to reset API config? API config ကို ပြန်လည်သတ်မှတ်ချင်ပါသလား? - + Cannot reset API config during active connection - + Remove server from application ဆာဗာကို အပလီကေးရှင်းမှဖယ်ရှားမည် - + All installed AmneziaVPN services will still remain on the server. ထည့်သွင်းထားသော AmneziaVPN ဝန်ဆောင်မှုများအားလုံးသည် ဆာဗာပေါ်တွင် ဆက်လက်ရှိနေမည်ဖြစ်သည်. - + Clear server from Amnezia software ဆာဗာကို Amnezia ဆော့ဖ်ဝဲလ်မှ ရှင်းလင်းမည် @@ -1789,27 +1981,27 @@ Already installed containers were found on the server. All installed containers PageSettingsServerInfo - + Server name ဆာဗာအမည် - + Save သိမ်းဆည်းမည် - + Protocols ပရိုတိုကောများ - + Services ဝန်ဆောင်မှုများ - + Management စီမံခန့်ခွဲမှု @@ -1817,59 +2009,59 @@ Already installed containers were found on the server. All installed containers PageSettingsServerProtocol - + settings ဆက်တင်များ - + Clear %1 profile - + Clear %1 profile? - + - + Unable to clear %1 profile while there is an active connection - + Remove ဖယ်ရှားမည် - + Remove %1 from server? %1 ကို ဆာဗာမှ ဖယ်ရှားမည်လား? - + All users with whom you shared a connection will no longer be able to connect to it. သင်နှင့်အတူချိတ်ဆက်မှုတစ်ခုကို မျှဝေထားသည့် အသုံးပြုသူအားလုံး ဤချိတ်ဆက်မှုကိုချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ. - + Cannot remove active container - - + + Continue ဆက်လက်လုပ်ဆောင်မည် - - + + Cancel ပယ်ဖျက်မည် @@ -1877,7 +2069,7 @@ Already installed containers were found on the server. All installed containers PageSettingsServersList - + Servers ဆာဗာများ @@ -1885,110 +2077,155 @@ Already installed containers were found on the server. All installed containers PageSettingsSplitTunneling - + Default server does not support split tunneling function မူရင်းဆာဗာသည် split tunneling လုပ်ဆောင်ချက်ကို အထောက်အပံ့မပေးပါ - + Addresses from the list should not be accessed via VPN စာရင်းတွင်ဖော်ပြထားသောလိပ်စာများကို VPN ဖြင့် ဝင်ရောက်ခြင်းပြုနိုင်လိမ့်မည် မဟုတ်ပေ - + Split tunneling Split tunneling - + Mode Mode - + Remove ဖယ်ရှားမည် - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Cancel ပယ်ဖျက်မည် - + Import / Export Sites ဆိုက်များ သွင်း/ထုတ်မည် - + Only the sites listed here will be accessed through the VPN ဤနေရာတွင်ဖော်ပြထားသောဆိုက်များကိုသာ VPN မှတဆင့်ဝင်ရောက်ပါမည် - + Cannot change split tunneling settings during active connection လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် split tunneling ဆက်တင်များကို ပြောင်းလဲ၍မရပါ - + website or IP ဝဘ်ဆိုက် သို့မဟုတ် IP - + Import တင်သွင်းမည် - + Save site list ဆိုက်စာရင်းကို သိမ်းဆည်းမည် - + Save sites ဆိုက်များသိမ်းဆည်းမည် - - - + + + Sites files (*.json) ဆိုက်ဖိုင်များ (*.json) - + Import a list of sites ဆိုက်စာရင်းတစ်ခု တင်သွင်းမည် - + Replace site list ဆိုက်စာရင်းကို အစားထိုးမည် - - + + Open sites file ဆိုက်ဖိုင်များ ဖွင့်မည် - + Add imported sites to existing ones တင်သွင်းထားသော ဆိုက်များကို ရှိပြီးသားဆိုက်များထဲသို့ ထည့်မည် + + PageSetupWizardApiServiceInfo + + + For the region + + + + + Price + + + + + Work period + + + + + Speed + + + + + Features + + + + + Connect + ချိတ်ဆက်မည် + + + + PageSetupWizardApiServicesList + + + VPN by Amnezia + + + + + Choose a VPN service that suits your needs. + + + PageSetupWizardConfigSource - Server connection - ဆာဗာချိတ်ဆက်မှု + ဆာဗာချိတ်ဆက်မှု Do not use connection code from public sources. It may have been created to intercept your data. @@ -1999,95 +2236,171 @@ It's okay as long as it's from someone you trust. သင်ယုံကြည်ရတဲ့သူတစ်ယောက်ဆီမှ ရရှိတဲ့ကုဒ်ဖြစ်နေသရွေ့တော့ အဆင်ပြေပါသည်. - Do not use connection codes from untrusted sources, as they may be created to intercept your data. - သင့်ဒေတာကို ကြားဖြတ်ရန် ဖန်တီးထားနိုင်သောကြောင့် မယုံကြည်ရသော ရင်းမြစ်များမှ ချိတ်ဆက်ကုဒ်များကို မသုံးပါနှင့်။ + သင့်ဒေတာကို ကြားဖြတ်ရန် ဖန်တီးထားနိုင်သောကြောင့် မယုံကြည်ရသော ရင်းမြစ်များမှ ချိတ်ဆက်ကုဒ်များကို မသုံးပါနှင့်။ - What do you have? - သင့်တွင်ဘာရှိပါသလဲ? + သင့်တွင်ဘာရှိပါသလဲ? - + File with connection settings ချိတ်ဆက်မှုဆက်တင်များပါဝင်သောဖိုင် - File with connection settings or backup - ချိတ်ဆက်မှုဆက်တင်များ သို့မဟုတ် အရန်သိမ်းဆည်းထားမှုပါဝင်သောဖိုင် + ချိတ်ဆက်မှုဆက်တင်များ သို့မဟုတ် အရန်သိမ်းဆည်းထားမှုပါဝင်သောဖိုင် - + + Connection + ချိတ်ဆက်မှု + + + + Insert the key, add a configuration file or scan the QR-code + + + + + Insert key + + + + + Insert + ထည်သွင်းမည် + + + + Continue + + + + + Other connection options + + + + + VPN by Amnezia + + + + + Connect to classic paid and free VPN services from Amnezia + + + + + Self-hosted VPN + + + + + Configure Amnezia VPN on your own server + + + + + Restore from backup + အရန်သိမ်းထားသည့်ဖိုင်မှ ပြန်လည်ရယူမည် + + + + Open backup file + အရန်သိမ်းထားသည့်ဖိုင်ကို ဖွင့်မည် + + + + Backup files (*.backup) + ဖိုင်များကိုအရန်သိမ်းဆည်းမည် (*.backup) + + + Open config file config ဖိုင်ကိုဖွင့်မည် - + QR code QR-ကုဒ် - + + I have nothing + ကျွန်ုပ်တွင်ဘာမှမရှိပါ + + Key as text - Key ကိုစာသားအဖြစ် + Key ကိုစာသားအဖြစ် PageSetupWizardCredentials - + Server IP address [:port] ဆာဗာ IP လိပ်စာ [:port] - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Enter the address in the format 255.255.255.255:88 လိပ်စာကို 255.255.255.255:88 ဖော်မတ်ဖြင့် ထည့်ပါ - + Configure your server သင်၏ဆာဗာကို စီစဉ်ချိန်ညှိပါ။ - + 255.255.255.255:22 255.255.255.255:22 - + SSH Username SSH အသုံးပြုသူအမည် - + Password or SSH private key စကားဝှက် သိုမဟုတ် SSH private key - + All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties သင်ထည့်သွင်းသည့်ဒေတာအားလုံးကို တင်းကြပ်လုံခြုံစွာလျှို့ဝှက်ထားမည်ဖြစ်ပြီး Amnezia သို့မဟုတ် မည်သည့်ပြင်ပအဖွဲ့အစည်းကိုမျှ မျှဝေမည် သို့မဟုတ် ထုတ်ဖော်မည်မဟုတ်ပါ - + + How to run your VPN server + + + + + Where to get connection data, step-by-step instructions for buying a VPS + + + + Ip address cannot be empty IP လိပ်စာသည် ဗလာမဖြစ်ရပါ - + Login cannot be empty လော့ဂ်အင်အချက်အလက်သည် ဗလာမဖြစ်ရပါ - + Password/private key cannot be empty စကားဝှက်/private key သည် ဗလာမဖြစ်ရပါ @@ -2095,22 +2408,22 @@ It's okay as long as it's from someone you trust. PageSetupWizardEasy - + What is the level of internet control in your region? သင့်ဒေသရှိ အင်တာနက်ထိန်းချုပ်မှုအဆင့်က ဘယ်လောက်ရှိပါသလဲ? - + Choose a VPN protocol VPN ပရိုတိုကောကို ရွေးပါ။ - + Skip setup စနစ်ထည့်သွင်းမှုကို ကျော်သွားပါ။ - + Continue ဆက်လက်လုပ်ဆောင်မည် @@ -2118,38 +2431,38 @@ It's okay as long as it's from someone you trust. PageSetupWizardInstalling - + The server has already been added to the application ဆာဗာကို အပလီကေးရှင်းတွင် ထည့်သွင်းပြီးပါပြီ - + Amnezia has detected that your server is currently Amnezia သည် သင့်ဆာဗာက - + busy installing other software. Amnezia installation အခြားဆော့ဖ်ဝဲကို ထည့်သွင်းနေသောကြောင့် အလုပ်ရှုပ်နေကြောင်းထောက်လှန်းမိပါသည်. Amnezia ထည့်သွင်းခြင်းလုပ်ငန်းစဥ် - + will pause until the server finishes installing other software ဆာဗာကို အခြားဆော့ဖ်ဝဲကို ထည့်သွင်းခြင်း မပြီးမချင်း ခေတ္တရပ်ထားပါမည် - + Installing ထည့်သွင်းနေသည် - + Cancel installation ထည့်သွင်းမှုကို ပယ်ဖျက်မည် - - + + Usually it takes no more than 5 minutes များသောအားဖြင့် 5 မိနစ်ထက်မပိုပါ @@ -2157,37 +2470,37 @@ It's okay as long as it's from someone you trust. PageSetupWizardProtocolSettings - + Installing %1 ထည့်သွင်းနေသည် %1 - + More detailed ပိုမိုအသေးစိတ် - + Close ပိတ်မည် - + Network protocol ကွန်ရက်ပရိုတိုကော - + Port Port - + Install ထည်သွင်းမည် - + The port must be in the range of 1 to 65535 @@ -2195,12 +2508,12 @@ It's okay as long as it's from someone you trust. PageSetupWizardProtocols - + VPN protocol VPN ပရိုတိုကော - + Choose the one with the highest priority for you. Later, you can install other protocols and additional services, such as DNS proxy and SFTP. သင့်အတွက် ဦးစားပေးအဖြစ်ဆုံးကို ရွေးချယ်ပါ. နောက်ပိုင်းတွင်၊ သင်သည် DNS proxy နှင့် SFTP ကဲ့သို့သော အခြားပရိုတိုကောများနှင့် ထပ်ဆောင်းဝန်ဆောင်မှုများကို ထည့်သွင်းနိုင်သည်. @@ -2208,7 +2521,7 @@ It's okay as long as it's from someone you trust. PageSetupWizardQrReader - + Point the camera at the QR code and hold for a couple of seconds. ကင်မရာနှင့် QR ကုဒ်ကို ချိန်ပြီး စက္ကန့်အနည်းငယ်လောက် ငြိမ်ထားပေးပါ. @@ -2216,60 +2529,59 @@ It's okay as long as it's from someone you trust. PageSetupWizardStart - Settings restored from backup file - ဆက်တင်များကို အရန်သိမ်းဆည်းထားသောဖိုင်မှ ပြန်လည်ရယူပြီးပါပြီ + ဆက်တင်များကို အရန်သိမ်းဆည်းထားသောဖိုင်မှ ပြန်လည်ရယူပြီးပါပြီ - Free service for creating a personal VPN on your server. - သင့်ဆာဗာပေါ်တွင် ကိုယ်ပိုင် VPN ဖန်တီးရန်အတွက် အခမဲ့ဝန်ဆောင်မှု. + သင့်ဆာဗာပေါ်တွင် ကိုယ်ပိုင် VPN ဖန်တီးရန်အတွက် အခမဲ့ဝန်ဆောင်မှု. - Helps you access blocked content without revealing your privacy, even to VPN providers. - အခြား VPN ဝန်ဆောင်မှုများကိုပင် သင်၏ privacy ကိုမဖော်ပြဘဲ ပိတ်ဆို့ထားသော အကြောင်းအရာများကို သင်ဝင်ရောက်ကြည့်ရှုနိုင်ရန် အကူအညီပေးပါသည်. + အခြား VPN ဝန်ဆောင်မှုများကိုပင် သင်၏ privacy ကိုမဖော်ပြဘဲ ပိတ်ဆို့ထားသော အကြောင်းအရာများကို သင်ဝင်ရောက်ကြည့်ရှုနိုင်ရန် အကူအညီပေးပါသည်. - I have the data to connect - ကျွန်ုပ်တွင်ချိတ်ဆက်ဖို့အတွက်ဒေတာရှိသည် + ကျွန်ုပ်တွင်ချိတ်ဆက်ဖို့အတွက်ဒေတာရှိသည် - I have nothing - ကျွန်ုပ်တွင်ဘာမှမရှိပါ + ကျွန်ုပ်တွင်ဘာမှမရှိပါ - https://amnezia.org/instructions/0_starter-guide - https://amnezia.org/instructions/0_starter-guide + https://amnezia.org/instructions/0_starter-guide + + + + Let's get started + PageSetupWizardTextKey - + Connection key ချိန်ဆက်မှု key - + A line that starts with vpn://... vpn://... ဖြင့် စတင်သော စာကြောင်း... - + Key Key - + Insert ထည်သွင်းမည် - + Continue ဆက်လက်လုပ်ဆောင်မည် @@ -2277,32 +2589,32 @@ It's okay as long as it's from someone you trust. PageSetupWizardViewConfig - + New connection ချိတ်ဆက်မှုအသစ် - + Collapse content အကြောင်းအရာများကိုဖြန့်ချမည် - + Show content အကြောင်းအရာများကိုပြမည် - + Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider. - + Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data. သင်ယုံကြည်ရသော ရင်းမြစ်များမှသာ ချိတ်ဆက်ကုဒ်များကို အသုံးပြုပါ။ သင့်ဒေတာကို ကြားဖြတ်ရန် အများသူငှာ ရင်းမြစ်များမှ ကုဒ်များကို ဖန်တီးထားသည်။ - + Connect ချိတ်ဆက်မည် @@ -2310,144 +2622,144 @@ It's okay as long as it's from someone you trust. PageShare - + OpenVPN native format OpenVPN မူရင်းဖောမတ် - + WireGuard native format WireGuard မူရင်းဖော်မတ် - + Connection ချိတ်ဆက်မှု - - + + Server ဆာဗာ - + Config revoked Config ကိုပြန်ရုပ်သိမ်းလိုက်ပါပြီ - + Connection to ဤဆာဗာသို့ချိတ်ဆက်မှု - + File with connection settings to ဤဆာဗာနှင့်ချိတ်ဆက်မှု ဆက်တင်များပါရှိသော ဖိုင် - + Save OpenVPN config OpenVPN config ကိုသိမ်းဆည်းမည် - + Save WireGuard config WireGuard config ကိုသိမ်းဆည်းမည် - + Save AmneziaWG config AmneziaWG config ကိုသိမ်းဆည်းမည် - + Save Shadowsocks config Shadowsocks config ကိုသိမ်းဆည်းမည် - + Save Cloak config Cloak config ကိုသိမ်းဆည်းမည် - + Save XRay config - + For the AmneziaVPN app AmneziaVPN အက်ပ်အတွက် - + AmneziaWG native format AmneziaWG မူရင်းဖော်မတ် - + Shadowsocks native format Shadowsocks မူရင်းဖောမတ် - + Cloak native format Cloak မူရင်းဖော်မတ် - + XRay native format - + Share VPN Access VPN အသုံးပြုခွင့်ကိုမျှဝေမည် - + Share full access to the server and VPN ဆာဗာနှင့် VPN သို့ အပြည့်အဝဝင်ရောက်ခွင့်ကို မျှဝေမည် - + Use for your own devices, or share with those you trust to manage the server. သင့်ကိုယ်ပိုင်စက်ပစ္စည်းများအတွက် အသုံးပြုရန် သို့မဟုတ် ဆာဗာကို စီမံခန့်ခွဲရန် သင်ယုံကြည်ရသူများနှင့် မျှဝေရန်. - - + + Users အသုံးပြုသူများ - + User name အသုံးပြုသူနာမည် - + Search ရှာဖွေမည် - + Creation date: %1 - + Latest handshake: %1 - + Data received: %1 - + Data sent: %1 @@ -2456,65 +2768,65 @@ It's okay as long as it's from someone you trust. ဖန်တီးပြုလုပ်သည့်ရက်စွဲ: - + Rename အမည်ပြောင်းမည် - + Client name ကလိုင်းရင့်အမည် - + Save သိမ်းဆည်းမည် - + Revoke ပြန်ရုပ်သိမ်းမည် - + Revoke the config for a user - %1? အသုံးပြုသူ %1 အတွက် config ကို ပြန်လည်ရုပ်သိမ်းမည်လား? - + The user will no longer be able to connect to your server. ဤအသုံးပြုသူသည် သင့်ဆာဗာသို့ ချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ. - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Cancel ပယ်ဖျက်မည် - + Share VPN access without the ability to manage the server ဆာဗာကို စီမံခန့်ခွဲနိုင်စွမ်းမပါရှိဘဲ VPN အသုံးပြုခွင့်ကို မျှဝေမည် - - + + Protocol ပရိုတိုကော - - + + Connection format ချိတ်ဆက်မှုဖောမတ် - - + + Share မျှဝေမည် @@ -2522,50 +2834,50 @@ It's okay as long as it's from someone you trust. PageShareFullAccess - + Full access to the server and VPN ဆာဗာနှင့် VPN ကို အပြည့်အဝဝင်ရောက်ခွင့် - + We recommend that you use full access to the server only for your own additional devices. သင့်ကိုယ်ပိုင်အပိုပစ္စည်းများအတွက်သာ ဆာဗာသို့ အပြည့်အဝဝင်ရောက်ခွင့်ကို အသုံးပြုရန် ကျွန်ုပ်တို့ အကြံပြုပါသည်. - + If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. သင်သည် အခြားသူများနှင့် အပြည့်အဝဝင်ရောက်ခွင့်ကို မျှဝေပါက၊ ၎င်းတို့သည် ပရိုတိုကောများနှင့် ဝန်ဆောင်မှုများကို ဆာဗာသို့ထည့်သွင်းခြင်း ဆာဗာမှဖယ်ရှားခြင်းများ ပြုလုပ်နိုင်သောကြောင့် အသုံးပြုသူများအားလုံးအတွက် VPN မှားယွင်းစွာ လုပ်ဆောင်ခြင်းများဖြစ်စေနိုင်ပါသည်. - + Server ဆာဗာ - + Accessing ဝင်ရောက်နေသည် - + File with accessing settings to ဤဆာဗာနှင့်ဝင်ရောက်နိုင်မှု ဆက်တင်များပါရှိသော ဖိုင် - + Share မျှဝေမည် - + Connection to ဤဆာဗာသို့ချိတ်ဆက်မှု - + File with connection settings to ဤဆာဗာနှင့်ချိတ်ဆက်မှု ဆက်တင်များပါရှိသော ဖိုင် @@ -2573,15 +2885,20 @@ It's okay as long as it's from someone you trust. PageStart - + Logging was disabled after 14 days, log files were deleted + + + Settings restored from backup file + + PopupType - + Close ပိတ်မည် @@ -2967,7 +3284,7 @@ It's okay as long as it's from someone you trust. ဤ config ကို အပလီကေးရှင်းထဲသို့ ထည့်သွင်းပြီးဖြစ်သည် - + ErrorCode: %1. မှားယွင်းမှုကုတ်: %1. @@ -3057,37 +3374,42 @@ It's okay as long as it's from someone you trust. - - QFile error: The file could not be opened + + Missing AGW public key - QFile error: An error occurred when reading from the file + QFile error: The file could not be opened - QFile error: The file could not be accessed + QFile error: An error occurred when reading from the file - QFile error: An unspecified error occurred + QFile error: The file could not be accessed - QFile error: A fatal error occurred + QFile error: An unspecified error occurred + QFile error: A fatal error occurred + + + + QFile error: The operation was aborted - + Internal error စက်တွင်းဖြစ်သော မှားယွင်းမှု @@ -3536,7 +3858,7 @@ For more detailed information, you can SelectLanguageDrawer - + Choose language ဘာသာစကားကို ရွေးချယ်ပါ @@ -3544,13 +3866,13 @@ For more detailed information, you can Settings - + Server #1 ဆာဗာ #1 - - + + Server ဆာဗာ @@ -3575,39 +3897,39 @@ For more detailed information, you can ShareConnectionDrawer - - + + Save AmneziaVPN config AmneziaWG config ကိုသိမ်းဆည်းမည် - + Share မျှဝေမည် - + Copy ကူးယူမည် - - + + Copied ကူးယူပြီးပါပြီ - + Copy config string config string ကိုကူးယူမည် - + Show connection settings ချိတ်ဆက်မှုဆက်တင်များကို ပြပါ - + To read the QR code in the Amnezia app, select "Add server" → "I have data to connect" → "QR code, key or settings file" Amnezia အက်ပ်ရှိ QR ကုဒ်ကိုဖတ်ရန်အတွက်အောက်ပါအတိုင်း ရွေးချယ်ပါ "ဆာဗာထည့်ရန်" → "ချိတ်ဆက်ရန် ဒေတာရှိသည်" → "QR ကုဒ်၊ key သို့မဟုတ် ဆက်တင်ဖိုင်" @@ -3691,7 +4013,7 @@ For more detailed information, you can TextFieldWithHeaderType - + The field can't be empty ဖြည့်သွင်းရမည့်နေရာသည် အလွတ်မဖြစ်ရပါ @@ -3750,12 +4072,12 @@ For more detailed information, you can amnezia::ContainerProps - + Low Low - + High Medium သို့မဟုတ် High @@ -3764,12 +4086,12 @@ For more detailed information, you can Extreme - + I just want to increase the level of my privacy. ကျွန်ုပ်၏ကိုယ်ရေးကိုယ်တာလုံခြုံမှုအဆင့်ကို မြှင့်တင်လိုပါသည်. - + I want to bypass censorship. This option recommended in most cases. ဆင်ဆာဖြတ်တောက်ခြင်းကို ကျော်ဖြတ်ချင်ပါသည်. ဤရွေးချယ်မှုကို ကိစ္စအများစုအတွက် အကြံပြုထားသည်. @@ -3781,12 +4103,12 @@ For more detailed information, you can main2 - + Private key passphrase ကိုယ်ပိုင် key စကားဝှက် - + Save သိမ်းဆည်းမည် diff --git a/client/translations/amneziavpn_ru_RU.ts b/client/translations/amneziavpn_ru_RU.ts index e7462ac4..f616c3ae 100644 --- a/client/translations/amneziavpn_ru_RU.ts +++ b/client/translations/amneziavpn_ru_RU.ts @@ -1,6 +1,54 @@ + + ApiServicesModel + + + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s + Классический VPN для комфортной работы, загрузки больших файлов и просмотра видео. Работает для любых сайтов. Скорость до %1 Мбит/с + + + + VPN to access blocked sites in regions with high levels of Internet censorship. + VPN для доступа к заблокированным сайтам в регионах с высоким уровнем интернет-цензуры. + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. + Amnezia Premium — классический VPN для комфортной работы, загрузки больших файлов и просмотра видео в высоком разрешении. Работает на всех сайтах, даже в странах с самым высоким уровнем интернет-цензуры. + + + + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship + Amnezia Free - это бесплатный VPN для обхода блокировок в странах с высоким уровнем интернет-цензуры + + + + %1 MBit/s + + + + + %1 days + %1 дней + + + + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> + Через VPN будут открываться только популярные сайты, заблокированные в вашем регионе, такие как Instagram, Facebook, Twitter и другие. Остальные сайты будут открываться с вашего реального IP-адреса, <a href="%1/free" style="color: #FBB26A;">подробности на сайте.</a> + + + + Free + Бесплатно + + + + %1 $/month + %1 $/месяц + + AppSplitTunnelingController @@ -27,7 +75,7 @@ ConnectButton - + Unable to disconnect during configuration preparation Невозможно отключиться во время подготовки конфигурации @@ -35,62 +83,62 @@ ConnectionController - + VPN Protocols is not installed. Please install VPN container at first VPN-протоколы не установлены. Пожалуйста, установите протокол - + Connecting... Подключение... - + Connected Подключено - + Preparing... Подготовка... - + Settings updated successfully, reconnnection... Настройки успешно обновлены, переподключение... - + Settings updated successfully Настройки успешно обновлены - + The selected protocol is not supported on the current platform Выбранный протокол не поддерживается на данном устройстве - + unable to create configuration не удалось создать конфигурацию - + Reconnecting... Переподключение... - - - + + + Connect Подключиться - + Disconnecting... Отключение... @@ -131,7 +179,7 @@ Вставить - + &SelectAll Выбрать всё @@ -230,84 +278,104 @@ Can't be disabled for current server InstallController - + %1 installed successfully. %1 успешно установлен. - + %1 is already installed on the server. %1 уже установлен на сервер. - + Added containers that were already installed on the server Добавлены сервисы и протоколы, которые были ранее установлены на сервер - + Already installed containers were found on the server. All installed containers have been added to the application На сервере обнаружены установленные протоколы и сервисы. Все они были добавлены в приложение - + Settings updated successfully Настройки успешно обновлены - + Server '%1' was rebooted Сервер '%1' был перезагружен - + Server '%1' was removed Сервер '%1' был удален - + All containers from server '%1' have been removed Все протоколы и сервисы были удалены с сервера '%1' - + %1 has been removed from the server '%2' %1 был удален с сервера '%2' - + + Api config removed + Конфигурация API удалена + + + %1 cached profile cleared %1 закэшированный профиль очищен - + Please login as the user Пожалуйста, войдите в систему от имени пользователя - + Server added successfully Сервер успешно добавлен + + + %1 installed successfully. + %1 успешно установлен. + + + + API config reloaded + Конфигурация API перезагружена + + + + Successfully changed the country of connection to %1 + Изменение страны подключения на %1 + InstalledAppsDrawer - + Choose application Выберите приложение - + application name название приложения - + Add selected Добавить выбранные @@ -362,45 +430,53 @@ Already installed containers were found on the server. All installed containers PageDeinstalling - + Removing services from %1 Удаление сервисов c %1 - + Usually it takes no more than 5 minutes Обычно это занимает не более 5 минут + + PageDevMenu + + + Gateway endpoint + + + PageHome - + Logging enabled Логирование включено - + Split tunneling enabled Раздельное туннелирование включено - + Split tunneling disabled Раздельное туннелирование выключено - + VPN protocol VPN-протокол - + Servers Серверы - + Unable change server while there is an active connection Невозможно изменить сервер во время активного соединения @@ -408,17 +484,17 @@ Already installed containers were found on the server. All installed containers PageProtocolAwgSettings - + AmneziaWG settings Настройки AmneziaWG - + Port Порт - + MTU MTU @@ -431,42 +507,87 @@ Already installed containers were found on the server. All installed containers Удалить AmneziaWG с сервера? - + All users with whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Save Сохранить - + + Jc - Junk packet count + + + + + Jmin - Junk packet minimum size + + + + + Jmax - Junk packet maximum size + + + + + S1 - Init packet junk size + + + + + S2 - Response packet junk size + + + + + H1 - Init packet magic header + + + + + H2 - Response packet magic header + + + + + H4 - Transport packet magic header + + + + + H3 - Underload packet magic header + + + + The values of the H1-H4 fields must be unique Значения в полях H1-H4 должны быть уникальными - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) Значение в поле S1 + размер инициации сообщения (148) не должно равняться значению в поле S2 + размер ответа на сообщение (92) - + Save settings? Сохранить настройки? - + Continue Продолжить - + Cancel Отменить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -474,33 +595,33 @@ Already installed containers were found on the server. All installed containers PageProtocolCloakSettings - + Cloak settings Настройки Cloak - + Disguised as traffic from Замаскировать трафик под - + Port Порт - + Cipher Шифрование - + Save Сохранить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -508,170 +629,170 @@ Already installed containers were found on the server. All installed containers PageProtocolOpenVpnSettings - + OpenVPN settings Настройки OpenVPN - + VPN address subnet Подсеть VPN-адресов - + Network protocol Сетевой протокол - + Port Порт - + Auto-negotiate encryption Шифрование с автоматическим согласованием - + Hash Хэш - + SHA512 SHA512 - + SHA384 SHA384 - + SHA256 SHA256 - + SHA3-512 SHA3-512 - + SHA3-384 SHA3-384 - + SHA3-256 SHA3-256 - + whirlpool whirlpool - + BLAKE2b512 BLAKE2b512 - + BLAKE2s256 BLAKE2s256 - + SHA1 SHA1 - + Cipher Шифрование - + AES-256-GCM AES-256-GCM - + AES-192-GCM AES-192-GCM - + AES-128-GCM AES-128-GCM - + AES-256-CBC AES-256-CBC - + AES-192-CBC AES-192-CBC - + AES-128-CBC AES-128-CBC - + ChaCha20-Poly1305 ChaCha20-Poly1305 - + ARIA-256-CBC ARIA-256-CBC - + CAMELLIA-256-CBC CAMELLIA-256-CBC - + none none - + TLS auth TLS авторизация - + Block DNS requests outside of VPN Блокировать DNS-запросы за пределами VPN - + Additional client configuration commands Дополнительные команды конфигурации клиента - - + + Commands: Команды: - + Additional server configuration commands Дополнительные команды конфигурации сервера - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -696,7 +817,7 @@ Already installed containers were found on the server. All installed containers Отменить - + Save Сохранить @@ -704,32 +825,32 @@ Already installed containers were found on the server. All installed containers PageProtocolRaw - + settings настройки - + Show connection options Показать параметры подключения - + Connection options %1 Параметры подключения %1 - + Remove Удалить - + Remove %1 from server? Удалить %1 с сервера? - + All users with whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. @@ -738,12 +859,12 @@ Already installed containers were found on the server. All installed containers Все пользователи, с которыми вы поделились этим VPN-протоколом, больше не смогут к нему подключаться. - + Continue Продолжить - + Cancel Отменить @@ -751,28 +872,28 @@ Already installed containers were found on the server. All installed containers PageProtocolShadowSocksSettings - + Shadowsocks settings Настройки Shadowsocks - + Port Порт - + Cipher Шифрование - + Save Сохранить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -780,22 +901,22 @@ Already installed containers were found on the server. All installed containers PageProtocolWireGuardSettings - + WG settings Настройки WG - + Port Порт - + MTU MTU - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -820,7 +941,7 @@ Already installed containers were found on the server. All installed containers Отменить - + Save Сохранить @@ -828,22 +949,22 @@ Already installed containers were found on the server. All installed containers PageProtocolXraySettings - + XRay settings Настройки XRay - + Disguised as traffic from Замаскировать трафик под - + Save Сохранить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -858,39 +979,39 @@ Already installed containers were found on the server. All installed containers PageServiceDnsSettings - + A DNS service is installed on your server, and it is only accessible via VPN. На вашем сервере установлен DNS-сервис, доступ к нему возможен только через VPN. - + The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab. Адрес DNS совпадает с адресом вашего сервера. Настроить DNS можно во вкладке "Соединение" настроек приложения. - + Remove Удалить - + Remove %1 from server? Удалить %1 с сервера? - + Continue Продолжить - + Cancel Отменить - + Cannot remove AmneziaDNS from running server Невозможно удалить AmneziaDNS с работающего сервера @@ -898,157 +1019,153 @@ Already installed containers were found on the server. All installed containers PageServiceSftpSettings - + Settings updated successfully Настройки успешно обновлены - + SFTP settings Настройки SFTP - + Host Хост - - - - + + + + Copied Скопировано - + Port Порт - + User name Имя пользователя - + Password Пароль - + Mount folder on device Смонтировать папку на устройстве - + In order to mount remote SFTP folder as local drive, perform following steps: <br> Чтобы смонтировать SFTP-папку как локальный диск, выполните следующие действия: <br> - - + + <br>1. Install the latest version of <br>1. Установите последнюю версию - - + + <br>2. Install the latest version of <br>2. Установите последнюю версию - + Detailed instructions Подробные инструкции - Remove SFTP and all data stored there - Удалить SFTP-хранилище со всеми данными + Удалить SFTP-хранилище со всеми данными - Remove SFTP and all data stored there? - Удалить SFTP-хранилище и все хранящиеся там данные? + Удалить SFTP-хранилище и все хранящиеся там данные? - Continue - Продолжить + Продолжить - Cancel - Отменить + Отменить PageServiceSocksProxySettings - + Settings updated successfully Настройки успешно обновлены - - + + SOCKS5 settings Настройки SOCKS5 - + Host Хост - - - - + + + + Copied Скопировано - - + + Port Порт - + User name Имя пользователя - - + + Password Пароль - + Username Имя пользователя - - + + Change connection settings Изменить настройки соединения - + The port must be in the range of 1 to 65535 Порт должен быть в диапазоне от 1 до 65535 - + Password cannot be empty Пароль не может быть пустым - + Username cannot be empty Имя пользователя не может быть пустым @@ -1056,95 +1173,96 @@ Already installed containers were found on the server. All installed containers PageServiceTorWebsiteSettings - + Settings updated successfully Настройки успешно обновлены - + Tor website settings Настройки сайта в сети Тоr - + Website address Адрес сайта - + Copied Скопировано - + Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL. Используйте <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> для открытия этой ссылки. - + After creating your onion site, it takes a few minutes for the Tor network to make it available for use. Через несколько минут после установки ваш onion-сайт станет доступен в сети Tor. - + When configuring WordPress set the this onion address as domain. При настройке WordPress укажите этот onion-адрес в качестве домена. - Remove website - Удалить сайт + Удалить сайт - The site with all data will be removed from the tor network. - Сайт со всеми данными будет удален из сети Tor. + Сайт со всеми данными будет удален из сети Tor. - Continue - Продолжить + Продолжить - Cancel - Отменить + Отменить PageSettings - + Settings Настройки - + Servers Серверы - + Connection Соединение - + Application Приложение - + Backup Резервное копирование - + About AmneziaVPN Об AmneziaVPN + Dev console + + + + Close application Закрыть приложение @@ -1152,7 +1270,7 @@ Already installed containers were found on the server. All installed containers PageSettingsAbout - + Support Amnezia Поддержите Amnezia @@ -1161,130 +1279,204 @@ Already installed containers were found on the server. All installed containers Показать другие способы на GitHub - + Amnezia is a free and open-source application. You can support the developers if you like it. Amnezia — это бесплатное приложение с открытым исходным кодом. Поддержите разработчиков, если оно вам нравится. - + Contacts Контакты - + Telegram group Группа в Telegram - + To discuss features Для обсуждения возможностей - + https://t.me/amnezia_vpn_en https://t.me/amnezia_vpn - + Mail Почта - + For reviews and bug reports Для отзывов и сообщений об ошибках - + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website Веб-сайт - https://amnezia.org - https://amnezia.org + https://amnezia.org - + Software version: %1 Версия ПО: %1 - + Check for updates Проверить обновления - + Privacy Policy Политика конфиденциальности - PageSettingsAppSplitTunneling + PageSettingsApiServerInfo - - Cannot change split tunneling settings during active connection - Невозможно изменить настройки раздельного туннелирования во время активного соединения + + For the region + Для региона - - Only the apps from the list should have access via VPN - Только приложения из списка должны работать через VPN + + Price + Цена - - Apps from the list should not have access via VPN - Приложения из списка не должны работать через VPN + + Work period + Период работы - - App split tunneling - Раздельное туннелирование приложений + + Speed + Скорость - - Mode - Режим + + Support tag + - - Remove - Удалить + + Copied + Скопировано - + + Reload API config + Перезагрузить конфигурацию API + + + + Reload API config? + Перезагрузить конфигурацию API? + + + + Continue Продолжить - + + Cancel Отменить - + + Cannot reload API config during active connection + Невозможно перзагрузить API конфигурацию при активном соединении + + + + Remove from application + Удалить из приложения + + + + Remove from application? + Удалить из приложения? + + + + Cannot remove server during active connection + Невозможно удалить сервер во время активного соединения + + + + PageSettingsAppSplitTunneling + + + Cannot change split tunneling settings during active connection + Невозможно изменить настройки раздельного туннелирования во время активного соединения + + + + Only the apps from the list should have access via VPN + Только приложения из списка должны работать через VPN + + + + Apps from the list should not have access via VPN + Приложения из списка не должны работать через VPN + + + + App split tunneling + Раздельное туннелирование приложений + + + + Mode + Режим + + + + Remove + Удалить + + + + Continue + Продолжить + + + + Cancel + Отменить + + + application name название приложения - + Open executable file Открыть исполняемый файл - + Executable files (*.*) Исполняемые файлы (*.*) @@ -1292,102 +1484,102 @@ Already installed containers were found on the server. All installed containers PageSettingsApplication - + Application Приложение - + Allow application screenshots Разрешить скриншоты приложения - + Auto start Автозапуск - + Launch the application every time the device is starts Запускать приложение при загрузке устройства - + Auto connect Автоподключение - + Connect to VPN on app start Подключаться к VPN при запуске приложения - + Start minimized Запускать в свернутом виде - + Launch application minimized Запускать приложение в свернутом виде - + Language Язык - + Enable notifications Включить уведомления - + Enable notifications to show the VPN state in the status bar Включить уведомления для отображения статуса VPN в строке состояния - + Logging Логирование - + Enabled Включено - + Disabled Отключено - + Reset settings and remove all data from the application Сбросить настройки и удалить все данные из приложения - + Reset settings and remove all data from the application? Сбросить настройки и удалить все данные из приложения? - + All settings will be reset to default. All installed AmneziaVPN services will still remain on the server. Все настройки будут сброшены до значений по умолчанию. Все установленные сервисы AmneziaVPN останутся на сервере. - + Continue Продолжить - + Cancel Отменить - + Cannot reset settings during active connection Невозможно сбросить настройки во время активного соединения @@ -1399,7 +1591,7 @@ Already installed containers were found on the server. All installed containers Резервное копирование - + Settings restored from backup file Настройки восстановлены из файла резервной копии @@ -1482,7 +1674,7 @@ Already installed containers were found on the server. All installed containers PageSettingsConnection - + Connection Соединение @@ -1495,57 +1687,57 @@ Already installed containers were found on the server. All installed containers Подключение к VPN при запуске приложения - + Use AmneziaDNS Использовать AmneziaDNS - + If AmneziaDNS is installed on the server Если AmneziaDNS установлен на сервере - + DNS servers DNS-серверы - + When AmneziaDNS is not used or installed Когда AmneziaDNS не используется или не установлен - + Allows you to use the VPN only for certain Apps Позволяет использовать VPN только для определенных приложений - + KillSwitch - Аварийный выключатель + KillSwitch - + Disables your internet if your encrypted VPN connection drops out for any reason. Отключает ваше интернет-соединение, если ваше зашифрованное VPN-соединение по какой-либо причине прерывается. - + Cannot change killSwitch settings during active connection Невозможно изменить настройки аварийного выключателя во время активного соединения - + Site-based split tunneling Раздельное туннелирование сайтов - + Allows you to select which sites you want to access through the VPN Позволяет выбирать, к каким сайтам подключаться через VPN - + App-based split tunneling Раздельное туннелирование приложений @@ -1557,12 +1749,12 @@ Already installed containers were found on the server. All installed containers PageSettingsDns - + Default server does not support custom DNS Сервер по умолчанию не поддерживает пользовательские DNS - + DNS servers DNS-серверы @@ -1571,52 +1763,52 @@ Already installed containers were found on the server. All installed containers Когда AmneziaDNS не используется или не установлен - + If AmneziaDNS is not used or installed Если AmneziaDNS не используется или не установлен - + Primary DNS Первичный DNS - + Secondary DNS Вторичный DNS - + Restore default Восстановить по умолчанию - + Restore default DNS settings? Восстановить настройки DNS по умолчанию? - + Continue Продолжить - + Cancel Отменить - + Settings have been reset Настройки сброшены - + Save Сохранить - + Settings saved Настройки сохранены @@ -1624,72 +1816,72 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - + Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. Логирование включено. Обратите внимание, что логирование будет автоматически отключено через 14 дней, и все логи будут удалены. - + Logging Логирование - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. Включение этой функции позволяет сохранять логи на вашем устройстве. По умолчанию она отключена. Включите сохранение логов в случае сбоев в работе приложения. - + Save logs Сохранять логи - + Open folder with logs Открыть папку с логами - + Save Сохранить - + Logs files (*.log) Файлы логов (*.log) - + Logs file saved Файл с логами сохранен - + Save logs to file Сохранить логи в файл - + Clear logs? Очистить логи? - + Continue Продолжить - + Cancel Отменить - + Logs have been cleaned up Логи очищены - + Clear logs Очистить логи @@ -1697,7 +1889,7 @@ Already installed containers were found on the server. All installed containers PageSettingsServerData - + All installed containers have been added to the application Все установленные протоколы и сервисы были добавлены в приложение @@ -1714,7 +1906,7 @@ Already installed containers were found on the server. All installed containers Удалить кэш Amnezia? - + No new installed containers found Новые установленные протоколы и сервисы не обнаружены @@ -1723,94 +1915,94 @@ Already installed containers were found on the server. All installed containers - - - - - - Continue - Продолжить - + Continue + Продолжить + + + + + + Cancel Отменить - + Check the server for previously installed Amnezia services Проверить сервер на наличие ранее установленных сервисов Amnezia - + Add them to the application if they were not displayed Добавить их в приложение, если они не отображаются - + Reboot server Перезагрузить сервер - + Do you want to reboot the server? Вы уверены, что хотите перезагрузить сервер? - + The reboot process may take approximately 30 seconds. Are you sure you wish to proceed? Процесс перезагрузки может занять около 30 секунд. Вы уверены, что хотите продолжить? - + Cannot reboot server during active connection Невозможно перезагрузить сервер во время активного соединения - + Do you want to remove the server from application? Вы уверены, что хотите удалить сервер из приложения? - + Cannot remove server during active connection Невозможно удалить сервер во время активного соединения - + Do you want to clear server from Amnezia software? Вы хотите очистить сервер от всех сервисов Amnezia? - + All users whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Cannot clear server from Amnezia software during active connection Невозможно очистить сервер от сервисов Amnezia во время активного соединения - + Reset API config Сбросить конфигурацию API - + Do you want to reset API config? Вы хотите сбросить конфигурацию API? - + Cannot reset API config during active connection Невозможно сбросить конфигурацию API во время активного соединения - + Remove server from application Удалить сервер из приложения @@ -1819,12 +2011,12 @@ Already installed containers were found on the server. All installed containers Удалить сервер? - + All installed AmneziaVPN services will still remain on the server. Все установленные сервисы и протоколы Amnezia останутся на сервере. - + Clear server from Amnezia software Очистить сервер от протоколов и сервисов Amnezia @@ -1840,27 +2032,27 @@ Already installed containers were found on the server. All installed containers PageSettingsServerInfo - + Server name Имя сервера - + Save Сохранить - + Protocols Протоколы - + Services Сервисы - + Management Управление @@ -1872,17 +2064,17 @@ Already installed containers were found on the server. All installed containers PageSettingsServerProtocol - + settings настройки - + Clear %1 profile Очистить профиль %1 - + Clear %1 profile? Очистить профиль %1? @@ -1892,27 +2084,27 @@ Already installed containers were found on the server. All installed containers - + Unable to clear %1 profile while there is an active connection Невозможно очистить профиль %1 во время активного соединения - + Remove Удалить - + Remove %1 from server? Удалить %1 с сервера? - + All users with whom you shared a connection will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Cannot remove active container Невозможно удалить активный контейнер @@ -1921,14 +2113,14 @@ Already installed containers were found on the server. All installed containers Все пользователи, с которыми вы поделились VPN, больше не смогут к нему подключаться. - - + + Continue Продолжить - - + + Cancel Отменить @@ -1936,7 +2128,7 @@ Already installed containers were found on the server. All installed containers PageSettingsServersList - + Servers Серверы @@ -1944,7 +2136,7 @@ Already installed containers were found on the server. All installed containers PageSettingsSplitTunneling - + Default server does not support split tunneling function Сервер по умолчанию не поддерживает раздельное туннелирование @@ -1953,32 +2145,32 @@ Already installed containers were found on the server. All installed containers Только адреса из списка должны открываться через VPN - + Addresses from the list should not be accessed via VPN Адреса из списка не должны открываться через VPN - + Split tunneling Раздельное туннелирование - + Mode Режим - + Remove Удалить - + Continue Продолжить - + Cancel Отменить @@ -1987,75 +2179,120 @@ Already installed containers were found on the server. All installed containers Сайт или IP - + Import / Export Sites Импорт/экспорт сайтов - + Only the sites listed here will be accessed through the VPN Только адреса из списка должны открываться через VPN - + Cannot change split tunneling settings during active connection Невозможно изменить настройки раздельного туннелирования во время активного соединения - + website or IP веб-сайт или IP - + Import Импорт - + Save site list Сохранить список сайтов - + Save sites Сохранить сайты - - - + + + Sites files (*.json) Файлы сайтов (*.json) - + Import a list of sites Импортировать список с сайтами - + Replace site list Заменить список с сайтами - - + + Open sites file Открыть список с сайтами - + Add imported sites to existing ones Добавить импортированные сайты к существующим + + PageSetupWizardApiServiceInfo + + + For the region + Для региона + + + + Price + Цена + + + + Work period + Период работы + + + + Speed + Скорость + + + + Features + Особенности + + + + Connect + Подключиться + + + + PageSetupWizardApiServicesList + + + VPN by Amnezia + VPN от Amnezia + + + + Choose a VPN service that suits your needs. + Выберите VPN-сервис, который подходит именно вам. + + PageSetupWizardConfigSource - Server connection - Подключение к серверу + Подключение к серверу Do not use connection code from public sources. It may have been created to intercept your data. @@ -2066,39 +2303,105 @@ It's okay as long as it's from someone you trust. Всё в порядке, если кодом поделился пользователь, которому вы доверяете. - Do not use connection codes from untrusted sources, as they may be created to intercept your data. - Не используйте коды подключения из ненадежных источников, так как они могут быть созданы для перехвата ваших данных. + Не используйте коды подключения из ненадежных источников, так как они могут быть созданы для перехвата ваших данных. - What do you have? - Что у вас есть? + Что у вас есть? - + File with connection settings Файл с настройками подключения - File with connection settings or backup - Файл с настройками подключения или резервной копией + Файл с настройками подключения или резервной копией - + + Connection + Соединение + + + + Insert the key, add a configuration file or scan the QR-code + Вставьте ключ, добавьте файл конфигурации или отсканируйте QR-код + + + + Insert key + Вставьте ключ + + + + Insert + Вставить + + + + Continue + Продолжить + + + + Other connection options + Другие варианты подключения + + + + VPN by Amnezia + VPN от Amnezia + + + + Connect to classic paid and free VPN services from Amnezia + Подключайтесь к классическим платным и бесплатным VPN-сервисам от Amnezia + + + + Self-hosted VPN + Self-hosted VPN + + + + Configure Amnezia VPN on your own server + Настроить VPN на собственном сервере + + + + Restore from backup + Восстановить из резервной копии + + + + Open backup file + Открыть резервную копию + + + + Backup files (*.backup) + Файлы резервных копий (*.backup) + + + Open config file Открыть файл с конфигурацией - + QR code QR-код - + + I have nothing + У меня ничего нет + + Key as text - Ключ в виде текста + Ключ в виде текста @@ -2108,7 +2411,7 @@ It's okay as long as it's from someone you trust. Подключение к серверу - + Server IP address [:port] IP-адрес[:порт] сервера @@ -2121,7 +2424,7 @@ It's okay as long as it's from someone you trust. Password / SSH private key - + Continue Продолжить @@ -2131,7 +2434,7 @@ and will not be shared or disclosed to the Amnezia or any third parties Все данные, которые вы вводите, останутся строго конфиденциальными и не будут переданы или раскрыты Amnezia или каким-либо третьим лицам - + Enter the address in the format 255.255.255.255:88 Введите адрес в формате 255.255.255.255:88 @@ -2140,42 +2443,52 @@ and will not be shared or disclosed to the Amnezia or any third parties Login to connect via SSH - + Configure your server Настроить ваш сервер - + 255.255.255.255:22 255.255.255.255:22 - + SSH Username Имя пользователя SSH - + Password or SSH private key Пароль или закрытый ключ SSH - + All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties Все данные, которые вы вводите, останутся строго конфиденциальными и не будут переданы или раскрыты Amnezia или каким-либо третьим лицам - + + How to run your VPN server + Как создать VPN на собственном сервере + + + + Where to get connection data, step-by-step instructions for buying a VPS + Где взять данные для подключения, пошаговые инстуркции по покупке VPS + + + Ip address cannot be empty Поле с IP-адресом не может быть пустым - + Login cannot be empty Поле с логином не может быть пустым - + Password/private key cannot be empty Поле с паролем/закрытым ключом не может быть пустым @@ -2183,17 +2496,17 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardEasy - + What is the level of internet control in your region? Какой уровень контроля над интернетом в вашем регионе? - + Choose a VPN protocol Выберите VPN-протокол - + Skip setup Пропустить настройку @@ -2206,7 +2519,7 @@ and will not be shared or disclosed to the Amnezia or any third parties Выбрать VPN-протокол - + Continue Продолжить @@ -2218,38 +2531,38 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardInstalling - + The server has already been added to the application Сервер уже был добавлен в приложение - + Amnezia has detected that your server is currently Amnezia обнаружила, что ваш сервер в настоящее время - + busy installing other software. Amnezia installation занят установкой других протоколов или сервисов. Установка Amnezia - + will pause until the server finishes installing other software будет приостановлена до тех пор, пока сервер не завершит установку другого ПО - + Installing Установка - + Cancel installation Отменить установку - - + + Usually it takes no more than 5 minutes Обычно это занимает не более 5 минут @@ -2257,37 +2570,37 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardProtocolSettings - + Installing %1 Устанавливается %1 - + More detailed Подробнее - + Close Закрыть - + Network protocol Сетевой протокол - + Port Порт - + Install Установить - + The port must be in the range of 1 to 65535 Порт должен быть в диапазоне от 1 до 65535 @@ -2295,12 +2608,12 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardProtocols - + VPN protocol VPN-протокол - + Choose the one with the highest priority for you. Later, you can install other protocols and additional services, such as DNS proxy and SFTP. Выберите протокол, который вам больше подходит. В дальнейшем можно установить другие протоколы и дополнительные сервисы, такие как DNS-прокси и SFTP. @@ -2308,7 +2621,7 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardQrReader - + Point the camera at the QR code and hold for a couple of seconds. Наведите камеру на QR-код и удерживайте ее в течение нескольких секунд. @@ -2316,60 +2629,59 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardStart - Settings restored from backup file - Настройки восстановлены из резервной копии + Настройки восстановлены из резервной копии - Free service for creating a personal VPN on your server. - Простое и бесплатное приложение для запуска собственного VPN на своем сервере. + Простое и бесплатное приложение для запуска собственного VPN на своем сервере. - Helps you access blocked content without revealing your privacy, even to VPN providers. - Помогает получить доступ к заблокированному контенту, не раскрывая вашу конфиденциальность даже провайдерам VPN. + Помогает получить доступ к заблокированному контенту, не раскрывая вашу конфиденциальность даже провайдерам VPN. - I have the data to connect - У меня есть данные для подключения + У меня есть данные для подключения - I have nothing - У меня ничего нет + У меня ничего нет - https://amnezia.org/instructions/0_starter-guide - https://amnezia.org/ru/starter-guide + https://amnezia.org/ru/starter-guide + + + + Let's get started + Приступим PageSetupWizardTextKey - + Connection key Ключ для подключения - + A line that starts with vpn://... Строка, которая начинается с vpn://... - + Key Ключ - + Insert Вставить - + Continue Продолжить @@ -2377,7 +2689,7 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardViewConfig - + New connection Новое соединение @@ -2386,27 +2698,27 @@ and will not be shared or disclosed to the Amnezia or any third parties Не используйте код подключения из публичных источников. Его могли создать, чтобы перехватить ваши данные. - + Collapse content Свернуть - + Show content Показать - + Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider. Включить обфускацию WireGuard. Это может быть полезно, если WireGuard блокируется вашим провайдером. - + Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data. Используйте файлы конфигурации только из тех источников, которым вы доверяете. Файлы из общедоступных источников могли быть созданы с целью перехвата ваших личных данных. - + Connect Подключиться @@ -2414,12 +2726,12 @@ and will not be shared or disclosed to the Amnezia or any third parties PageShare - + OpenVPN native format Оригинальный формат OpenVPN - + WireGuard native format Оригинальный формат WireGuard @@ -2428,7 +2740,7 @@ and will not be shared or disclosed to the Amnezia or any third parties VPN-Доступ - + Connection Соединение @@ -2441,8 +2753,8 @@ and will not be shared or disclosed to the Amnezia or any third parties Доступ к управлению сервером. Пользователь, с которым вы делитесь полным доступом к соединению, сможет добавлять и удалять ваши протоколы и службы на сервере, а также изменять настройки. - - + + Server Сервер @@ -2451,123 +2763,123 @@ and will not be shared or disclosed to the Amnezia or any third parties Доступ - + Config revoked Конфигурация отозвана - + Connection to Подключение к - + File with connection settings to Файл с настройками подключения к - + Save OpenVPN config Сохранить конфигурацию OpenVPN - + Save WireGuard config Сохранить конфигурацию WireGuard - + Save AmneziaWG config Сохранить конфигурацию AmneziaWG - + Save Shadowsocks config Сохранить конфигурацию Shadowsocks - + Save Cloak config Сохранить конфигурацию Cloak - + Save XRay config Сохранить конфигурацию XRay - + For the AmneziaVPN app Для приложения AmneziaVPN - + AmneziaWG native format Оригинальный формат AmneziaWG - + Shadowsocks native format Оригинальный формат Shadowsocks - + Cloak native format Оригинальный формат Cloak - + XRay native format Оригинальный формат XRay - + Share VPN Access Поделиться VPN - + Share full access to the server and VPN Поделиться полным доступом к серверу и VPN - + Use for your own devices, or share with those you trust to manage the server. Используйте для собственных устройств или передайте управление сервером тем, кому вы доверяете. - - + + Users Пользователи - + User name Имя пользователя - + Search Поиск - + Creation date: %1 Дата создания: %1 - + Latest handshake: %1 Последнее рукопожатие: %1 - + Data received: %1 Получено данных: %1 - + Data sent: %1 Отправлено данных: %1 @@ -2576,42 +2888,42 @@ and will not be shared or disclosed to the Amnezia or any third parties Дата создания: - + Rename Переименовать - + Client name Имя клиента - + Save Сохранить - + Revoke Отозвать - + Revoke the config for a user - %1? Отозвать конфигурацию для пользователя - %1? - + The user will no longer be able to connect to your server. Пользователь больше не сможет подключаться к вашему серверу. - + Continue Продолжить - + Cancel Отменить @@ -2620,25 +2932,25 @@ and will not be shared or disclosed to the Amnezia or any third parties Полный доступ - + Share VPN access without the ability to manage the server Поделиться доступом к VPN без возможности управления сервером - - + + Protocol Протокол - - + + Connection format Формат подключения - - + + Share Поделиться @@ -2646,50 +2958,50 @@ and will not be shared or disclosed to the Amnezia or any third parties PageShareFullAccess - + Full access to the server and VPN Полный доступ к серверу и VPN - + We recommend that you use full access to the server only for your own additional devices. Мы рекомендуем использовать полный доступ к серверу только для собственных устройств. - + If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. Если вы поделитесь полным доступом с другими людьми, то они смогут удалять и добавлять протоколы и сервисы на сервер, что приведет к некорректной работе VPN для всех пользователей. - + Server Сервер - + Accessing Доступ - + File with accessing settings to Файл с настройками доступа к - + Share Поделиться - + Connection to Подключение к - + File with connection settings to Файл с настройками подключения к @@ -2697,15 +3009,20 @@ and will not be shared or disclosed to the Amnezia or any third parties PageStart - + Logging was disabled after 14 days, log files were deleted Логирование было отключено по прошествии 14 дней, файлы логов были удалены. + + + Settings restored from backup file + Настройки восстановлены из бэкап файла + PopupType - + Close Закрыть @@ -3104,7 +3421,7 @@ and will not be shared or disclosed to the Amnezia or any third parties Данная конфигурация уже была добавлена в приложение - + ErrorCode: %1. Код ошибки: %1. @@ -3183,37 +3500,42 @@ and will not be shared or disclosed to the Amnezia or any third parties Тайм-аут ответа сервера на запрос API - + + Missing AGW public key + + + + QFile error: The file could not be opened Ошибка QFile: не удалось открыть файл - + QFile error: An error occurred when reading from the file Ошибка QFile: произошла ошибка при чтении из файла - + QFile error: The file could not be accessed Ошибка QFile: не удалось получить доступ к файлу - + QFile error: An unspecified error occurred Ошибка QFile: произошла неизвестная ошибка - + QFile error: A fatal error occurred Ошибка QFile: произошла фатальная ошибка - + QFile error: The operation was aborted Ошибка QFile: операция была прервана - + Internal error Внутренняя ошибка @@ -3750,7 +4072,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin SelectLanguageDrawer - + Choose language Выберите язык @@ -3758,13 +4080,13 @@ This means that AmneziaWG keeps the fast performance of the original while addin Settings - + Server #1 Сервер #1 - - + + Server Сервер @@ -3789,39 +4111,39 @@ This means that AmneziaWG keeps the fast performance of the original while addin ShareConnectionDrawer - - + + Save AmneziaVPN config Сохранить конфигурацию AmneziaVPN - + Share Поделиться - + Copy Скопировать - - + + Copied Скопировано - + Copy config string Скопировать строку конфигурации - + Show connection settings Показать настройки подключения - + To read the QR code in the Amnezia app, select "Add server" → "I have data to connect" → "QR code, key or settings file" Для считывания QR-кода в приложении Amnezia выберите "Добавить сервер" → "У меня есть данные для подключения" → "Открыть файл конфигурации, ключ или QR-код" @@ -3905,7 +4227,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin TextFieldWithHeaderType - + The field can't be empty Поле не может быть пустым @@ -3964,12 +4286,12 @@ This means that AmneziaWG keeps the fast performance of the original while addin amnezia::ContainerProps - + Low Низкий - + High Высокий @@ -3978,12 +4300,12 @@ This means that AmneziaWG keeps the fast performance of the original while addin Экстремальный - + I just want to increase the level of my privacy. Я просто хочу повысить уровень своей приватности. - + I want to bypass censorship. This option recommended in most cases. Я хочу обойти блокировки. Этот вариант рекомендуется в большинстве случаев. @@ -4011,12 +4333,12 @@ This means that AmneziaWG keeps the fast performance of the original while addin main2 - + Private key passphrase Парольная фраза для закрытого ключа - + Save Сохранить diff --git a/client/translations/amneziavpn_uk_UA.ts b/client/translations/amneziavpn_uk_UA.ts index 8979533e..c7206586 100644 --- a/client/translations/amneziavpn_uk_UA.ts +++ b/client/translations/amneziavpn_uk_UA.ts @@ -24,6 +24,54 @@ VPN Підключено + + ApiServicesModel + + + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s + + + + + VPN to access blocked sites in regions with high levels of Internet censorship. + + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. + + + + + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship + + + + + %1 MBit/s + + + + + %1 days + + + + + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> + + + + + Free + + + + + %1 $/month + + + AppSplitTunnelingController @@ -50,7 +98,7 @@ ConnectButton - + Unable to disconnect during configuration preparation @@ -58,62 +106,62 @@ ConnectionController - + VPN Protocols is not installed. Please install VPN container at first VPN протоколи не встановлено. Будь-ласка, встановіть VPN контейнер - + unable to create configuration - + Connecting... Підключення... - + Connected Підключено - + Preparing... - + Settings updated successfully, reconnnection... Налаштування оновлено, підключення... - + Settings updated successfully Налаштування оновлено. - + The selected protocol is not supported on the current platform Вибраний протокол не підтримується на цьому пристрої - + Reconnecting... Перепідключення... - - - + + + Connect Підключитись - + Disconnecting... Відключаємось... @@ -154,7 +202,7 @@ &Вставити - + &SelectAll &Вибрати все @@ -257,83 +305,103 @@ Can't be disabled for current server InstallController - + %1 installed successfully. %1 встановлено. - + %1 is already installed on the server. %1 вже встановлено на сервері. - + Added containers that were already installed on the server Додані сервіси і протоколи, які були раніше встановлені на сервері - + Already installed containers were found on the server. All installed containers have been added to the application На сервері знайдені сервіси та протоколи, всі вони додані в застосунок - + Settings updated successfully Налаштування оновлено - + Server '%1' was rebooted Сервер '%1' перезавантажено - + Server '%1' was removed Сервер '%1' був видалений - + All containers from server '%1' have been removed Всі сервіси та протоколи були видалені з сервера '%1' - + %1 has been removed from the server '%2' %1 був видалений з сервера '%2' - + + Api config removed + + + + %1 cached profile cleared - + Please login as the user Буль-ласка, увійдіть в систему від імені користувача - + Server added successfully Сервер додано + + + %1 installed successfully. + + + + + API config reloaded + + + + + Successfully changed the country of connection to %1 + + InstalledAppsDrawer - + Choose application - + application name - + Add selected @@ -388,45 +456,53 @@ Already installed containers were found on the server. All installed containers PageDeinstalling - + Removing services from %1 Видалення сервісів з %1 - + Usually it takes no more than 5 minutes Зазвичай, це займає не більше 5 хвилин + + PageDevMenu + + + Gateway endpoint + + + PageHome - + Logging enabled - + Split tunneling enabled Роздільне тунелювання увімкнено - + Split tunneling disabled Роздільне тунелювання вимкнено - + VPN protocol VPN протокол - + Servers Сервери - + Unable change server while there is an active connection Не можна змінити сервер при активному підключенні @@ -434,47 +510,92 @@ Already installed containers were found on the server. All installed containers PageProtocolAwgSettings - + AmneziaWG settings налаштування AmneziaWG - + Port Порт - + MTU - + + Jc - Junk packet count + + + + + Jmin - Junk packet minimum size + + + + + Jmax - Junk packet maximum size + + + + + S1 - Init packet junk size + + + + + S2 - Response packet junk size + + + + + H1 - Init packet magic header + + + + + H2 - Response packet magic header + + + + + H4 - Transport packet magic header + + + + + H3 - Underload packet magic header + + + + Save Зберегти - + The values of the H1-H4 fields must be unique - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) - + Save settings? - + All users with whom you shared a connection with will no longer be able to connect to it. - + Unable change settings while there is an active connection @@ -495,12 +616,12 @@ Already installed containers were found on the server. All installed containers Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись. - + Continue Продовжити - + Cancel Відмінити @@ -512,33 +633,33 @@ Already installed containers were found on the server. All installed containers PageProtocolCloakSettings - + Cloak settings Налаштування Cloak - + Disguised as traffic from Замаскувати трафік під - + Port Порт - + Cipher Шифрування - + Save Зберегти - + Unable change settings while there is an active connection @@ -550,7 +671,7 @@ Already installed containers were found on the server. All installed containers PageProtocolOpenVpnSettings - + OpenVPN settings налаштування OpenVPN @@ -559,170 +680,170 @@ Already installed containers were found on the server. All installed containers Підмережа для VPN - + VPN address subnet - + Network protocol Мережевий притокол - + Port Порт - + Auto-negotiate encryption Автоматично отримувати шифрування - + Hash Хеш - + SHA512 SHA512 - + SHA384 SHA384 - + SHA256 SHA256 - + SHA3-512 SHA3-512 - + SHA3-384 SHA3-384 - + SHA3-256 SHA3-256 - + whirlpool whirlpool - + BLAKE2b512 BLAKE2b512 - + BLAKE2s256 BLAKE2s256 - + SHA1 SHA1 - + Cipher Шифрування - + AES-256-GCM AES-256-GCM - + AES-192-GCM AES-192-GCM - + AES-128-GCM AES-128-GCM - + AES-256-CBC AES-256-CBC - + AES-192-CBC AES-192-CBC - + AES-128-CBC AES-128-CBC - + ChaCha20-Poly1305 ChaCha20-Poly1305 - + ARIA-256-CBC ARIA-256-CBC - + CAMELLIA-256-CBC CAMELLIA-256-CBC - + none none - + TLS auth TLS авторизація - + Block DNS requests outside of VPN Блокувати DNS запити за межами VPN тунеля - + Additional client configuration commands Додаткові команди конфігурації клієнта - - + + Commands: Команди: - + Additional server configuration commands Додаткові команти конфігурації сервера - + Save Зберегти - + Unable change settings while there is an active connection @@ -758,32 +879,32 @@ Already installed containers were found on the server. All installed containers PageProtocolRaw - + settings налаштування - + Show connection options Показати параметри підключення - + Connection options %1 Параметри підключення %1 - + Remove Видалити - + Remove %1 from server? Видалити %1 з сервера? - + All users with whom you shared a connection with will no longer be able to connect to it. @@ -796,12 +917,12 @@ Already installed containers were found on the server. All installed containers Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись. - + Continue Продовжити - + Cancel Відмінити @@ -809,28 +930,28 @@ Already installed containers were found on the server. All installed containers PageProtocolShadowSocksSettings - + Shadowsocks settings Налаштування Shadowsocks - + Port Порт - + Cipher Шифрування - + Save Зберегти - + Unable change settings while there is an active connection @@ -842,27 +963,27 @@ Already installed containers were found on the server. All installed containers PageProtocolWireGuardSettings - + WG settings - + Port Порт - + MTU - + Save Зберегти - + Unable change settings while there is an active connection @@ -870,22 +991,22 @@ Already installed containers were found on the server. All installed containers PageProtocolXraySettings - + XRay settings - + Disguised as traffic from Замаскувати трафік під - + Save Зберегти - + Unable change settings while there is an active connection @@ -900,39 +1021,39 @@ Already installed containers were found on the server. All installed containers PageServiceDnsSettings - + A DNS service is installed on your server, and it is only accessible via VPN. На вашому сервері встановлено DNS-сервіс, доступ до нього можливо тільки через VPN. - + The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab. Адреса DNS сервера співпадає з адресою вашого сервера. Налаштувати DNS можливо на вкладці "Підключення" налаштувань застосунку - + Remove Видалити - + Remove %1 from server? Видалити %1 з сервера? - + Continue Продовжити - + Cancel Відмінити - + Cannot remove AmneziaDNS from running server @@ -940,30 +1061,30 @@ Already installed containers were found on the server. All installed containers PageServiceSftpSettings - + Settings updated successfully Налаштування оновлено - + SFTP settings Налаштування SFTP - + Host Хост - - - - + + + + Copied Скопійовано - + Port Порт @@ -972,129 +1093,125 @@ Already installed containers were found on the server. All installed containers Логін - + User name Імя користувача - + Password Пароль - + Mount folder on device Змонтувати папку з вашого пристрою - + In order to mount remote SFTP folder as local drive, perform following steps: <br> Для того щоб додати SFTP-папку, як локальний диск на вашому пристрої, виконайте наступні дії: <br> - - + + <br>1. Install the latest version of <br>1. Встановіть останню версію - - + + <br>2. Install the latest version of <br>2. Встановіть останню версію - + Detailed instructions Детальні інструкції - Remove SFTP and all data stored there - Видалити SFTP-сховище з усіма даними + Видалити SFTP-сховище з усіма даними - Remove SFTP and all data stored there? - Видалити SFTP-сховище з усіма даними які там зберігаються? + Видалити SFTP-сховище з усіма даними які там зберігаються? - Continue - Продовжити + Продовжити - Cancel - Відмінити + Відмінити PageServiceSocksProxySettings - + Settings updated successfully - - + + SOCKS5 settings - + Host Хост - - - - + + + + Copied Скопійовано - - + + Port Порт - + User name - - + + Password Пароль - + Username - - + + Change connection settings - + The port must be in the range of 1 to 65535 - + Password cannot be empty - + Username cannot be empty @@ -1102,37 +1219,37 @@ Already installed containers were found on the server. All installed containers PageServiceTorWebsiteSettings - + Settings updated successfully Налаштування оновлено - + Tor website settings Налаштування сайту в мережі Тоr - + Website address Адреса сайту - + Copied Скопійовано - + Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL. Використовуйте <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> для відкриття цього посилання. - + After creating your onion site, it takes a few minutes for the Tor network to make it available for use. Через кілька хвилин після встановлення ваш сайт Onion стане доступним у мережі Tor. - + When configuring WordPress set the this onion address as domain. При налаштуванні WordPress, вкажіть цей Onion в якості домена. @@ -1141,60 +1258,61 @@ Already installed containers were found on the server. All installed containers При налаштуванні WordPress, вкажіть цей Onion в якості домена. - Remove website - Видалити сайт + Видалити сайт - The site with all data will be removed from the tor network. - Сайт з усіма даними буде видалено з мережі Tor. + Сайт з усіма даними буде видалено з мережі Tor. - Continue - Продовжити + Продовжити - Cancel - Відмінити + Відмінити PageSettings - + Settings Налаштування - + Servers Сервери - + Connection Підключення - + Application Застосунок - + Backup Резервне копіювання - + About AmneziaVPN Про AmneziaVPN + Dev console + + + + Close application Закрити застосунок @@ -1206,7 +1324,7 @@ Already installed containers were found on the server. All installed containers Підтримайте проект донатом - + Support Amnezia Підтримайте Amnezia @@ -1231,130 +1349,204 @@ Already installed containers were found on the server. All installed containers Показати інші способи на Github - + Amnezia is a free and open-source application. You can support the developers if you like it. - + Contacts Контакти - + Telegram group Група в Telegram - + To discuss features Для дискусій - + https://t.me/amnezia_vpn_en https://t.me/amnezia_vpn - + Mail Пошта - + For reviews and bug reports Для відгуків і повідомлень про помилки - + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website Веб-сайт - https://amnezia.org - https://amnezia.org + https://amnezia.org - + Software version: %1 Версія ПЗ: %1 - + Check for updates Перевірити оновлення - + Privacy Policy + + PageSettingsApiServerInfo + + + For the region + + + + + Price + + + + + Work period + + + + + Speed + + + + + Support tag + + + + + Copied + Скопійовано + + + + Reload API config + + + + + Reload API config? + + + + + + Continue + Продовжити + + + + + Cancel + Відмінити + + + + Cannot reload API config during active connection + + + + + Remove from application + + + + + Remove from application? + + + + + Cannot remove server during active connection + + + PageSettingsAppSplitTunneling - + Cannot change split tunneling settings during active connection Не можна змінити налаштування роздільного тунелювання при підключеному VPN - + Only the apps from the list should have access via VPN - + Apps from the list should not have access via VPN - + App split tunneling - + Mode Режим - + Remove Видалити - + Continue Продовжити - + Cancel Відмінити - + application name - + Open executable file - + Executable files (*.*) @@ -1362,102 +1554,102 @@ Already installed containers were found on the server. All installed containers PageSettingsApplication - + Application Застосунок - + Allow application screenshots Дозволити скріншоти в застосунку - + Enable notifications - + Enable notifications to show the VPN state in the status bar - + Auto start Автозапуск - + Launch the application every time the device is starts Запускати застосунок при старті - + Auto connect Автопідключення - + Connect to VPN on app start Підключення до VPN при старті застосунку - + Start minimized Запускати в згорнутому вигляді - + Launch application minimized Запускати застосунок в згорнутому вигляді - + Language Мова - + Logging Логування - + Enabled Увімкнено - + Disabled Вимкнено - + Reset settings and remove all data from the application Скинути налаштування і видалити всі дані із застосунку - + Reset settings and remove all data from the application? Скинути налаштування і видалити всі дані із застосунку? - + All settings will be reset to default. All installed AmneziaVPN services will still remain on the server. Всі дані із застосунку будуть видалені, всі встановлені сервіси AmneziaVPN залишаться на сервері. - + Continue Продовжити - + Cancel Відмінити - + Cannot reset settings during active connection @@ -1469,7 +1661,7 @@ Already installed containers were found on the server. All installed containers Резервне копіювання - + Settings restored from backup file Відновлення налаштувань із бекап файлу @@ -1552,7 +1744,7 @@ Already installed containers were found on the server. All installed containers PageSettingsConnection - + Connection З'єднання @@ -1565,57 +1757,57 @@ Already installed containers were found on the server. All installed containers Підключення до VPN при старті застосунку - + Use AmneziaDNS Використовувати AmneziaDNS - + If AmneziaDNS is installed on the server Якщо він встановлений на сервері - + DNS servers DNS сервер - + When AmneziaDNS is not used or installed Ці адреси будуть використовуватись коли вимкнений AmneziaDNS - + Allows you to use the VPN only for certain Apps Дозволяє використовувати VPN тільки для вибраних застосунків - + KillSwitch - + Disables your internet if your encrypted VPN connection drops out for any reason. - + Cannot change killSwitch settings during active connection - + Site-based split tunneling Роздільне тунелювання сайтів - + Allows you to select which sites you want to access through the VPN Дозволяє доступ до одних сайтів через VPN, а для інших в обхід VPN - + App-based split tunneling Роздільне VPN-тунелювання застосунків @@ -1627,12 +1819,12 @@ Already installed containers were found on the server. All installed containers PageSettingsDns - + Default server does not support custom DNS Сервер за замовчуванням не підтримує користувацький DNS - + DNS servers DNS сервер @@ -1641,52 +1833,52 @@ Already installed containers were found on the server. All installed containers Ці адреси будуть використовуватись, коли вимкнено або не встановлено AmneziaDNS - + If AmneziaDNS is not used or installed Якщо AmneziaDNS вимкнено або не встановлено - + Primary DNS Основний DNS - + Secondary DNS Допоміжний DNS - + Restore default Відновити за замовчуванням - + Restore default DNS settings? Відновити налаштування DNS за замовчуванням? - + Continue Продовжити - + Cancel Відмінити - + Settings have been reset Налаштування скинуті - + Save Зберегти - + Settings saved Зберегти налаштування @@ -1694,72 +1886,72 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - + Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - + Logging Логування - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. - + Save logs Зберегти логи - + Open folder with logs Відкрити папку з логами - + Save Зберегти - + Logs files (*.log) Logs files (*.log) - + Logs file saved Файл з логами збережено - + Save logs to file Зберегти логи в файл - + Clear logs? Очистити логи? - + Continue Продовжити - + Cancel Відмінити - + Logs have been cleaned up Логи видалено - + Clear logs Видалити логи @@ -1767,7 +1959,7 @@ Already installed containers were found on the server. All installed containers PageSettingsServerData - + All installed containers have been added to the application Всі встановлені протоколи та сервіси були додані в застосунок @@ -1784,7 +1976,7 @@ Already installed containers were found on the server. All installed containers Видалити кеш Amnezia? - + No new installed containers found Нові встановлені протоколи і сервіси не виявлені @@ -1793,89 +1985,89 @@ Already installed containers were found on the server. All installed containers - - - - - - Continue - Продовжити - + Continue + Продовжити + + + + + + Cancel Відмінити - + Check the server for previously installed Amnezia services Проверить сервер на наличие ранее установленных сервисов Amnezia - + Add them to the application if they were not displayed Додати їх в застосунок, якщо вони не були відображені - + Reboot server Перезавантажити сервер - + Do you want to reboot the server? Ви впевнені, що хочете перезавантажити сервер? - + The reboot process may take approximately 30 seconds. Are you sure you wish to proceed? Процес перезавантаження може зайняти близько 30 сек. Ви впевені, що хочете продовжити? - + Cannot reboot server during active connection - + Remove server from application - + Do you want to remove the server from application? Ви впевнені, що хочете видалити сервер із застосунку? - + Cannot remove server during active connection - + Clear server from Amnezia software - + Do you want to clear server from Amnezia software? - + All users whom you shared a connection with will no longer be able to connect to it. - + Cannot clear server from Amnezia software during active connection - + Cannot reset API config during active connection @@ -1884,12 +2076,12 @@ Already installed containers were found on the server. All installed containers Ви хочете очистити сервер від сервісів Amnezia? - + Reset API config Скинути API конфігурацію - + Do you want to reset API config? Ви хочете скинути API конфігурацію @@ -1902,7 +2094,7 @@ Already installed containers were found on the server. All installed containers Видалити сервер із застосунку? - + All installed AmneziaVPN services will still remain on the server. Всі встановлені сервіси та протоколи Amnezia все ще залишаться на сервері. @@ -1922,27 +2114,27 @@ Already installed containers were found on the server. All installed containers PageSettingsServerInfo - + Server name Імя сервера - + Save Зберегти - + Protocols Протоколи - + Services Сервіси - + Management @@ -1954,27 +2146,27 @@ Already installed containers were found on the server. All installed containers PageSettingsServerProtocol - + settings Налаштування - + Clear %1 profile - + Clear %1 profile? - + Unable to clear %1 profile while there is an active connection - + Cannot remove active container @@ -1984,17 +2176,17 @@ Already installed containers were found on the server. All installed containers - + Remove Видалити - + Remove %1 from server? Видалити %1 з сервера? - + All users with whom you shared a connection will no longer be able to connect to it. Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись. @@ -2003,14 +2195,14 @@ Already installed containers were found on the server. All installed containers Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись. - - + + Continue Продовжити - - + + Cancel Відмінити @@ -2018,7 +2210,7 @@ Already installed containers were found on the server. All installed containers PageSettingsServersList - + Servers Сервери @@ -2030,32 +2222,32 @@ Already installed containers were found on the server. All installed containers Тільки адреси із списку мають відкриватись через VPN - + Addresses from the list should not be accessed via VPN Адреси із списку не повинні відкриватись через VPN - + Split tunneling Роздільне VPN-тунелювання - + Mode Режим - + Remove Видалити - + Continue Продовжити - + Cancel Відмінити @@ -2064,80 +2256,125 @@ Already installed containers were found on the server. All installed containers Сайт чи IP - + Import / Export Sites Імпорт / Експорт Сайтів - + Only the sites listed here will be accessed through the VPN Тільки адреси зі списку повинні відкриватись через VPN - + Cannot change split tunneling settings during active connection Не можна змінити налаштування роздільного тунелювання при підключеному VPN - + Default server does not support split tunneling function - + website or IP вебсайт або IP - + Import Імпорт - + Save site list Зберегти список сайтів - + Save sites Зберегти - - - + + + Sites files (*.json) Sites files (*.json) - + Import a list of sites Імпортувати список із сайтами - + Replace site list Замінити список із сайтами - - + + Open sites file Відкрити список із сайтами - + Add imported sites to existing ones Додати імпортовані сайти до існуючих + + PageSetupWizardApiServiceInfo + + + For the region + + + + + Price + + + + + Work period + + + + + Speed + + + + + Features + + + + + Connect + Підключитись + + + + PageSetupWizardApiServicesList + + + VPN by Amnezia + + + + + Choose a VPN service that suits your needs. + + + PageSetupWizardConfigSource - Server connection - Підключення до сервера + Підключення до сервера Do not use connection code from public sources. It may have been created to intercept your data. @@ -2148,39 +2385,105 @@ It's okay as long as it's from someone you trust. Все в порядку, якщо ви використовуєте код, яким поділився користувач, якому ви довіряєте. - Do not use connection codes from untrusted sources, as they may be created to intercept your data. - Не використовуйте код підключення з загальнодоступних джерел. Можливо, його було створено для перехоплення ваших даних. + Не використовуйте код підключення з загальнодоступних джерел. Можливо, його було створено для перехоплення ваших даних. - What do you have? - Виберіть що у вас є + Виберіть що у вас є - + File with connection settings Файл з налаштуваннями підключення - File with connection settings or backup - Файл з налаштуваннями підключення або бекап + Файл з налаштуваннями підключення або бекап - + + Connection + + + + + Insert the key, add a configuration file or scan the QR-code + + + + + Insert key + + + + + Insert + Вставити + + + + Continue + Продовжити + + + + Other connection options + + + + + VPN by Amnezia + + + + + Connect to classic paid and free VPN services from Amnezia + + + + + Self-hosted VPN + + + + + Configure Amnezia VPN on your own server + + + + + Restore from backup + Відновити із бекапа + + + + Open backup file + Відкрити бекап файл + + + + Backup files (*.backup) + Файли резервної копії (*.backup) + + + Open config file Відкрити файл з конфігурацією - + QR code QR-код - + + I have nothing + У мене нічого нема + + Key as text - Ключ у вигляді тексту + Ключ у вигляді тексту @@ -2190,7 +2493,7 @@ It's okay as long as it's from someone you trust. Підключення до сервера - + Server IP address [:port] Server IP address [:port] @@ -2203,7 +2506,7 @@ It's okay as long as it's from someone you trust. Password / SSH private key - + Continue Продовжити @@ -2214,7 +2517,7 @@ and will not be shared or disclosed to the Amnezia or any third parties і не будуть передані чи розголошені Amnezia або будь-яким третім особам - + Enter the address in the format 255.255.255.255:88 Введіть адресу в форматі 255.255.255.255:88 @@ -2223,42 +2526,52 @@ and will not be shared or disclosed to the Amnezia or any third parties Login to connect via SSH - + Configure your server Налаштувати свій сервер - + 255.255.255.255:22 - + SSH Username - + Password or SSH private key - + All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties Усі дані, які ви вводите, залишатимуться суворо конфіденційними та не будуть передані чи розголошені Amnezia або будь-яким третім особам - + + How to run your VPN server + + + + + Where to get connection data, step-by-step instructions for buying a VPS + + + + Ip address cannot be empty Поле IP address не може бути пустим - + Login cannot be empty Поле Login не може бути пустим - + Password/private key cannot be empty Поле Password/Private key не може бути пустим @@ -2266,17 +2579,17 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardEasy - + What is the level of internet control in your region? Який рівень контроля над інтернетом у вашому регіоні? - + Choose a VPN protocol - + Skip setup @@ -2289,7 +2602,7 @@ and will not be shared or disclosed to the Amnezia or any third parties Вибрати VPN-протокол - + Continue Продовжити @@ -2301,7 +2614,7 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardInstalling - + The server has already been added to the application Сервер уже додано в застосунок @@ -2314,33 +2627,33 @@ and will not be shared or disclosed to the Amnezia or any third parties зайнятий встановленням інших протоколів та сервісів. Встановлення Amnezia - + Amnezia has detected that your server is currently Amnezia виявила, що сервер - + busy installing other software. Amnezia installation зайнятий встановленням інших протоколів та сервісів. Встановлення Amnezia - + will pause until the server finishes installing other software буде призупинено, поки сервер не завершить встановлення - + Installing Встановлення - + Cancel installation Відмінити встановлення - - + + Usually it takes no more than 5 minutes Зазвичай, займає не більше 5 хвилин @@ -2348,37 +2661,37 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardProtocolSettings - + Installing %1 Встановити %1 - + More detailed Детальніше - + Close Закрити - + Network protocol Мережевий протокол - + Port Порт - + Install Встановити - + The port must be in the range of 1 to 65535 @@ -2386,12 +2699,12 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardProtocols - + VPN protocol VPN протокол - + Choose the one with the highest priority for you. Later, you can install other protocols and additional services, such as DNS proxy and SFTP. Виберіть протокол, який вам більше підходить. Пізніше можна встановити інші протоколи і додаткові сервіси, такі як DNS-проксі, TOR-сайт и SFTP. @@ -2399,7 +2712,7 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardQrReader - + Point the camera at the QR code and hold for a couple of seconds. Наведіть камеру на QR-код і утримуйте її протягом декількох секунд. @@ -2407,60 +2720,55 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardStart - Settings restored from backup file - Відновлення налаштувань із бекап файлу + Відновлення налаштувань із бекап файлу - Free service for creating a personal VPN on your server. - Простий і безкоштовний застосунок для запуска self-hosted VPN з високими вимогами до приватності. + Простий і безкоштовний застосунок для запуска self-hosted VPN з високими вимогами до приватності. - Helps you access blocked content without revealing your privacy, even to VPN providers. - Допомагає отримати доступ до заблокованого вмісту, не повідомляючи про вашу конфіденційність, навіть постачальникам VPN. + Допомагає отримати доступ до заблокованого вмісту, не повідомляючи про вашу конфіденційність, навіть постачальникам VPN. - I have the data to connect - У мене є дані для підключення + У мене є дані для підключення - I have nothing - У мене нічого нема + У мене нічого нема - - https://amnezia.org/instructions/0_starter-guide + + Let's get started PageSetupWizardTextKey - + Connection key Ключ для підключення - + A line that starts with vpn://... Стрічка, яка починається з vpn://... - + Key Ключ - + Insert Вставити - + Continue Продовжити @@ -2468,7 +2776,7 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardViewConfig - + New connection Нове підключення @@ -2481,27 +2789,27 @@ and will not be shared or disclosed to the Amnezia or any third parties Не використовуйте код підключення з загальнодоступних джерел. Він може бути створений для перехоплення ваших даних. - + Collapse content Згорнути - + Show content Показати вміст ключа - + Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider. - + Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data. - + Connect Підключитись @@ -2509,12 +2817,12 @@ and will not be shared or disclosed to the Amnezia or any third parties PageShare - + OpenVPN native format OpenVPN нативний формат - + WireGuard native format WireGuard нативний формат @@ -2523,7 +2831,7 @@ and will not be shared or disclosed to the Amnezia or any third parties VPN-Доступ - + Connection З'єднання @@ -2536,8 +2844,8 @@ and will not be shared or disclosed to the Amnezia or any third parties Доступ до керування сервером. Користувач, з яким ви ділитесь повним доступом до підключення, зможе додавати та видаляти протоколи і служби на сервері, а також змінювати налаштування. - - + + Server Сервер @@ -2546,123 +2854,123 @@ and will not be shared or disclosed to the Amnezia or any third parties Доступ - + Config revoked Кофігурацію відкликано - + Connection to Підключення до - + File with connection settings to Файл з налаштуванням доступу до - + Save OpenVPN config Зберегти OpenVPN конфігурацію - + Save WireGuard config Збергти WireGuard конфігурацію - + Save AmneziaWG config Зберегти AmneziaWG конфігурацію - + Save Shadowsocks config Зберегти конфігурацію Shadowsocks - + Save Cloak config Зберегти конфігурацію Cloak - + Save XRay config - + For the AmneziaVPN app Для AmneziaVPN - + AmneziaWG native format нативний формат AmneziaWG - + Shadowsocks native format Shadowsocks нативний формат - + Cloak native format Cloak нативний формат - + XRay native format - + Share VPN Access Поділитись VPN з'єднанням - + Share full access to the server and VPN Поділитись повним доступом до серверу - + Use for your own devices, or share with those you trust to manage the server. Використовуйте для власних пристроїв або передайте керування сервером тим, кому довіряєте. - - + + Users Користувачі - + User name Ім'я користувача - + Search Пошук - + Creation date: %1 - + Latest handshake: %1 - + Data received: %1 - + Data sent: %1 @@ -2671,42 +2979,42 @@ and will not be shared or disclosed to the Amnezia or any third parties Дата створення: - + Rename Перейменувати - + Client name - + Save Зберегти - + Revoke Відкликати - + Revoke the config for a user - %1? Відкликати доступ для користувача - %1? - + The user will no longer be able to connect to your server. Користувач більше не зможе підключатись до вашого сервера - + Continue Продовжити - + Cancel Відмінити @@ -2715,25 +3023,25 @@ and will not be shared or disclosed to the Amnezia or any third parties Повний доступ - + Share VPN access without the ability to manage the server Поділитись доступом до VPN, без можливості керування сервером - - + + Protocol Протокол - - + + Connection format Формат підключення - - + + Share Поділитись @@ -2741,49 +3049,49 @@ and will not be shared or disclosed to the Amnezia or any third parties PageShareFullAccess - + Full access to the server and VPN Повний доступ до серверу та VPN - + We recommend that you use full access to the server only for your own additional devices. Ми рекомендуємо використовувати повний доступ тілки для власних пристроїв. - + If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. Якщо ви ділитеся повним доступом з іншими людьми, вони можуть видаляти та додавати протоколи та служби на сервер, що призведе до некоректної роботи VPN для всіх користувачів. - + Server Сервер - + Accessing Доступ - + File with accessing settings to Файл з налаштуваннями доступу до - + Share Поділитись - + Connection to Підключення до - + File with connection settings to Файл з налаштуванням доступу до @@ -2791,15 +3099,20 @@ and will not be shared or disclosed to the Amnezia or any third parties PageStart - + Logging was disabled after 14 days, log files were deleted + + + Settings restored from backup file + Відновлення налаштувань із бекап файлу + PopupType - + Close Закрити @@ -3200,7 +3513,7 @@ and will not be shared or disclosed to the Amnezia or any third parties Ця конфігурація вже була додана в застосунок - + ErrorCode: %1. @@ -3279,37 +3592,42 @@ and will not be shared or disclosed to the Amnezia or any third parties - - QFile error: The file could not be opened + + Missing AGW public key - QFile error: An error occurred when reading from the file + QFile error: The file could not be opened - QFile error: The file could not be accessed + QFile error: An error occurred when reading from the file - QFile error: An unspecified error occurred + QFile error: The file could not be accessed - QFile error: A fatal error occurred + QFile error: An unspecified error occurred + QFile error: A fatal error occurred + + + + QFile error: The operation was aborted - + Internal error Internal error @@ -3791,7 +4109,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin SelectLanguageDrawer - + Choose language Выберите язык @@ -3799,13 +4117,13 @@ This means that AmneziaWG keeps the fast performance of the original while addin Settings - + Server #1 Server #1 - - + + Server Server @@ -3830,39 +4148,39 @@ This means that AmneziaWG keeps the fast performance of the original while addin ShareConnectionDrawer - - + + Save AmneziaVPN config Зберегти config AmneziaVPN - + Share Поділитись - + Copy Скопіювати - - + + Copied Скопійовано - + Copy config string Скопіювати стрічку конфігурації - + Show connection settings Показати налаштування підключення - + To read the QR code in the Amnezia app, select "Add server" → "I have data to connect" → "QR code, key or settings file" Для зчитування QR-коду в застосунку Amnezia виберіть "Додати сервер" → "У мене є дані підключенн" → "QR-код, ключ чи файл налаштувань" @@ -3946,7 +4264,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin TextFieldWithHeaderType - + The field can't be empty Поле не може бути пустим @@ -4005,12 +4323,12 @@ This means that AmneziaWG keeps the fast performance of the original while addin amnezia::ContainerProps - + Low Низький - + High Високий @@ -4019,12 +4337,12 @@ This means that AmneziaWG keeps the fast performance of the original while addin Екстремальний - + I just want to increase the level of my privacy. Я просто хочу підвищити свій рівень безпеки в інтернеті. - + I want to bypass censorship. This option recommended in most cases. Я хочу обійти блокування. Цей варіант рекомендується в більшості випадків. @@ -4052,12 +4370,12 @@ This means that AmneziaWG keeps the fast performance of the original while addin main2 - + Private key passphrase Пароль для особистого ключа - + Save Зберегти diff --git a/client/translations/amneziavpn_ur_PK.ts b/client/translations/amneziavpn_ur_PK.ts index 05d06466..b18d60e7 100644 --- a/client/translations/amneziavpn_ur_PK.ts +++ b/client/translations/amneziavpn_ur_PK.ts @@ -1,6 +1,54 @@ + + ApiServicesModel + + + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s + + + + + VPN to access blocked sites in regions with high levels of Internet censorship. + + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. + + + + + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship + + + + + %1 MBit/s + + + + + %1 days + + + + + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> + + + + + Free + + + + + %1 $/month + + + AppSplitTunnelingController @@ -27,7 +75,7 @@ ConnectButton - + Unable to disconnect during configuration preparation تشکیل کی تیاری کے دوران منقطع ہونا ممکن نہیں ہے @@ -35,61 +83,61 @@ ConnectionController - - - + + + Connect جوڑنا - + The selected protocol is not supported on the current platform منتخب کردہ پروٹوکول موجودہ پلیٹ فارم پر تعاون یافتہ نہیں ہے - + VPN Protocols is not installed. Please install VPN container at first وی پی این پروٹوکول انسٹال نہیں ہے,براہ کرم پہلےوی پی این کنٹینر انسٹال کریں - + unable to create configuration تشکیل تیار کرنے میں ناکام - + Connecting... جوڑاجارھاھے.... - + Connected جوڑاجارھاھے - + Reconnecting... دوبارہ جوڑنےکی کوشش... - + Disconnecting... منقطع کرنا... - + Preparing... تیاری کیا جا رہا ہے... - + Settings updated successfully, reconnnection... ترتیب ک ھوگی،دوبارہ جوڑنےکی کوشش... - + Settings updated successfully دوبارہ ترتیب تاذہ کامیاب @@ -130,7 +178,7 @@ چ&سپاںکریں - + &SelectAll &تمام منتخب کریں @@ -224,84 +272,104 @@ Can't be disabled for current server InstallController - + %1 installed successfully. %1 کامیابی سےنصب. - + %1 is already installed on the server. %1 پہلے ہی سرور پر انسٹال ہے. - + Added containers that were already installed on the server وہ کنٹینرز شامل کیے گئے جو پہلے سے سرور پر نصب تھے - + Already installed containers were found on the server. All installed containers have been added to the application سرور پر پہلے سے نصب کنٹینرز پائے گئے۔ تمام نصب کنٹینرز کو ایپلی کیشن میں شامل کر دیا گیا ہے - + Settings updated successfully ترتیب کامیابی کے ساتھ اپ ڈیٹ ہو گئی - + Server '%1' was rebooted سرور %1 دوبارہ چالو کیا گیا تھا - + Server '%1' was removed سرور %1 ہٹا دیا گیا تھا - + All containers from server '%1' have been removed سرور '%1' سے تمام کنٹینرز ہٹا دیے گئے ہیں - + %1 has been removed from the server '%2' سرور '%2' سے %1 ہٹا دیا گیا ہے - + + Api config removed + + + + %1 cached profile cleared %1 کیش کردہ پروفائل ختم کر دی گئی - + Please login as the user براہ کرم صارف کے طور پر لاگ ان کریں - + Server added successfully سرور کامیابی سے شامل کیا گیا + + + %1 installed successfully. + + + + + API config reloaded + + + + + Successfully changed the country of connection to %1 + + InstalledAppsDrawer - + Choose application ایپلیکیشن کو منتخب کریں - + application name ایپلیکیشن کا نام - + Add selected ایپلیکیشن کا نام @@ -358,45 +426,53 @@ Already installed containers were found on the server. All installed containers PageDeinstalling - + Removing services from %1 سروسز کو %1 سے ہٹایا جا رہا ہے - + Usually it takes no more than 5 minutes عام طور پر اس میں 5 منٹ سے زیادہ نہیں لگتا ہے + + PageDevMenu + + + Gateway endpoint + + + PageHome - + Logging enabled لاگنگ فعال ہے - + Split tunneling enabled سپلٹ ٹنلنگ فعال ہے - + Split tunneling disabled سپلٹ ٹنلنگ غیر فعال ہے - + VPN protocol وی پی این پروٹوکول - + Servers سرور - + Unable change server while there is an active connection فعال کنکشن موجود ہونے کی وجہ سے سرور تبدیل کرنے میں ناکام ہیں @@ -404,57 +480,102 @@ Already installed containers were found on the server. All installed containers PageProtocolAwgSettings - + AmneziaWG settings امنیزیا وی جی کی ترتیبات - + Port پورٹ - + MTU ام ٹی یو - + All users with whom you shared a connection with will no longer be able to connect to it. آپ جن لوگوں کے ساتھ آپ نے اس کنکشن کا اشتراک کیا تھا، وہ اس سے مزید جڑ نہیں سکیں گے۔ - + Save محفوظ کریں - + + Jc - Junk packet count + + + + + Jmin - Junk packet minimum size + + + + + Jmax - Junk packet maximum size + + + + + S1 - Init packet junk size + + + + + S2 - Response packet junk size + + + + + H1 - Init packet magic header + + + + + H2 - Response packet magic header + + + + + H4 - Transport packet magic header + + + + + H3 - Underload packet magic header + + + + The values of the H1-H4 fields must be unique H1 تا H4 فیلڈز کی قیمتیں مخصوص ہونی چاہیے - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) S1 + پیغام شروع کار (148) کے فیلڈ کی قیمت S2 + پیغام جواب (92) کے سائز کے برابر نہیں ہونی چاہئے - + Save settings? ترتیبات محفوظ کریں? - + Continue جاری رکھیں - + Cancel منسوخ کریں - + Unable change settings while there is an active connection جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا @@ -462,33 +583,33 @@ Already installed containers were found on the server. All installed containers PageProtocolCloakSettings - + Cloak settings پوشیدہ ترتیب - + Disguised as traffic from کے طور پر ٹریفک کی طرح - + Port پورٹ - + Cipher رمز - + Save محفوظ کریں - + Unable change settings while there is an active connection جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا @@ -496,175 +617,175 @@ Already installed containers were found on the server. All installed containers PageProtocolOpenVpnSettings - + OpenVPN settings اوپن وی پی این ترتیبات - + VPN address subnet وی پی این ایڈریس سب نیٹ - + Network protocol نیٹ ورک پروٹوکول - + Port پورٹ - + Auto-negotiate encryption خود کار مذاکرتی رمزنگاری - + Hash ہیش - + SHA512 - + SHA384 - + SHA256 - + SHA3-512 - + SHA3-384 - + SHA3-256 - + whirlpool بھنور - + BLAKE2b512 - + BLAKE2s256 - + SHA1 - + Cipher رمز - + AES-256-GCM - + AES-192-GCM - + AES-128-GCM - + AES-256-CBC - + AES-192-CBC - + AES-128-CBC - + ChaCha20-Poly1305 - + ARIA-256-CBC - + CAMELLIA-256-CBC - + none کوئی نہیں - + TLS auth TLS توثیق - + Block DNS requests outside of VPN وی پی این کے باہر DNS درخواستوں کو بلاک کریں - + Additional client configuration commands مزید کلائنٹ ترتیباتی احکامات - - + + Commands: احکامات: - + Additional server configuration commands اضافی سرور کنفیگریشن احکامات - + Unable change settings while there is an active connection جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا - + Save احفظ @@ -672,42 +793,42 @@ Already installed containers were found on the server. All installed containers PageProtocolRaw - + settings ترتیبات - + Show connection options کنکشن کے اختیارات دکھائیں - + Connection options %1 کنکشن کے اختیارات %1 - + Remove ہٹائیں - + Remove %1 from server? سرور سے %1 کو ہٹائیں؟ - + All users with whom you shared a connection with will no longer be able to connect to it. آپ جن لوگوں کے ساتھ آپ نے ایک کنکشن شیئر کیا تھا، وہ اب اس سے مزید جڑ نہیں سکیں گے. - + Continue جاری رکھیں - + Cancel منسوخ کریں @@ -715,28 +836,28 @@ Already installed containers were found on the server. All installed containers PageProtocolShadowSocksSettings - + Shadowsocks settings شیڈو ساکس ترتیبات - + Port پورٹ - + Cipher رمز - + Save محفوظ کریں - + Unable change settings while there is an active connection جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا @@ -744,27 +865,27 @@ Already installed containers were found on the server. All installed containers PageProtocolWireGuardSettings - + WG settings وائر گارڈ ترتیبات - + Port پورٹ - + MTU ام ٹی یو - + Unable change settings while there is an active connection جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا - + Save محفوظ کریں @@ -772,22 +893,22 @@ Already installed containers were found on the server. All installed containers PageProtocolXraySettings - + XRay settings XRay کی ترتیبات - + Disguised as traffic from کے طور پر ٹریفک کی طرح - + Save محفوظ - + Unable change settings while there is an active connection جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا @@ -795,39 +916,39 @@ Already installed containers were found on the server. All installed containers PageServiceDnsSettings - + A DNS service is installed on your server, and it is only accessible via VPN. ایک DNS سروس آپ کے سرور پر انسٹال کی گئی ہے، اور صرف VPN کے ذریعے یہ قابل رسائی ہے. - + The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab. ایڈریس وہی ہے جو آپ کے سرور کا پتہ ہے۔ آپ کنکشنز ٹیب کے نیچے سیٹنگز میں DNS کنفیگر کر سکتے ہیں. - + Remove ہٹائیں - + Remove %1 from server? سرور سے %1 کو ہٹا دیں? - + Cannot remove AmneziaDNS from running server آمنیزیا ڈی این ایس کو چل رہے سرور سے ہٹا نہیں سکتے - + Continue جاری رہے - + Cancel منسوخ کریں @@ -835,161 +956,157 @@ Already installed containers were found on the server. All installed containers PageServiceSftpSettings - + Settings updated successfully ترتیبات کامیابی سے اپ ڈیٹ ہوگئیں - + SFTP settings ایس ایف ٹی پی ترتیبات - + Host The term "Host" in the context of SFTP (Secure File Transfer Protocol) can be translated into Urdu as: میزبان - - - - + + + + Copied نقل کر دیا گیا - + Port پورٹ - + User name صارف کا نام - + Password پاس ورڈ - + Mount folder on device آلے پر فولڈر ماؤنٹ کریں - + In order to mount remote SFTP folder as local drive, perform following steps: <br> ریموٹ SFTP فولڈر کو لوکل ڈرائیو کے طور پر ماؤنٹ کرنے کے لیے، درج ذیل اقدامات کریں - - + + <br>1. Install the latest version of <br>1کا تازہ ترین ورژن انسٹال کریں - - + + <br>2. Install the latest version of .<br>2کا تازہ ترین ورژن انسٹال کریں ۔ - + Detailed instructions تفصیلی ہدایات - Remove SFTP and all data stored there - کو ہٹا دیں اور وہاں ذخیرہ شدہ تمام ڈیٹا کو ختم کر دیں + کو ہٹا دیں اور وہاں ذخیرہ شدہ تمام ڈیٹا کو ختم کر دیں - Remove SFTP and all data stored there? - SFTP اور وہاں ذخیرہ کردہ تمام ڈیٹا کو ہٹائیں؟ + SFTP اور وہاں ذخیرہ کردہ تمام ڈیٹا کو ہٹائیں؟ - Continue - جاری رہے + جاری رہے - Cancel - منسوخ کریں + منسوخ کریں PageServiceSocksProxySettings - + Settings updated successfully - - + + SOCKS5 settings - + Host The term "Host" in the context of SFTP (Secure File Transfer Protocol) can be translated into Urdu as: میزبان - - - - + + + + Copied - - + + Port پورٹ - + User name صارف کا نام - - + + Password پاس ورڈ - + Username - - + + Change connection settings - + The port must be in the range of 1 to 65535 - + Password cannot be empty - + Username cannot be empty @@ -997,95 +1114,96 @@ Already installed containers were found on the server. All installed containers PageServiceTorWebsiteSettings - + Settings updated successfully ترتیبات کامیابی سے اپ ڈیٹ ہوگئی ہیں - + Tor website settings ویب سائٹ کی ترتیبات - + Website address ویب سائٹ کا پتہ - + Copied نقل کر لیا گیا - + Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL. - + After creating your onion site, it takes a few minutes for the Tor network to make it available for use. اپنی اونین ویب سائٹ بنانے کے بعد، ٹور نیٹ ورک کو اسے دستیاب کرنے میں کچھ منٹ لگ سکتے ہیں۔ - + When configuring WordPress set the this onion address as domain. وورڈپریس کو ترتیب دیتے وقت، اس انیون ایڈریس کو ڈومین کے طور پر مقرر کریں. - Remove website - ویب سائٹ کو ہٹا دیں + ویب سائٹ کو ہٹا دیں - The site with all data will be removed from the tor network. - تمام ڈیٹا والی سائٹ کو ٹور نیٹ ورک سے ہٹا دیا جائے گا. + تمام ڈیٹا والی سائٹ کو ٹور نیٹ ورک سے ہٹا دیا جائے گا. - Continue - جاری رکھیں + جاری رکھیں - Cancel - منسوخ کریں + منسوخ کریں PageSettings - + Settings ترتیبات - + Servers سرور - + Connection کنکشن - + Application ایپلیکیشن - + Backup بیک اپ - + About AmneziaVPN AmneziaVPN کے بارے میں + Dev console + + + + Close application براہ کرم ایپلیکیشن بند کریں @@ -1093,85 +1211,155 @@ Already installed containers were found on the server. All installed containers PageSettingsAbout - + Support Amnezia Amnezia کی حمایت کریں - + Amnezia is a free and open-source application. You can support the developers if you like it. ایمنیزیا ایک مفت اور آزاد سورس ایپلیکیشن ہے۔ آپ اگر اسے پسند کریں تو ڈویلپرز کی حمایت کرسکتے ہیں. - + Contacts رابطے - + Telegram group ٹیلیگرام گروپ - + To discuss features "فیچرز" پر گفتگو کرنے کے لئے - + https://t.me/amnezia_vpn_en - + Mail میل - + For reviews and bug reports جائزہ اور بگ رپورٹس کے لئے - + GitHub گِٹ ہَب - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website ویب سائٹ - - https://amnezia.org - - - - + Software version: %1 سافٹ ویئر ورژن: %1 - + Check for updates اپ ڈیٹس چیک کریں - + Privacy Policy رازداری کی پالیسی + + PageSettingsApiServerInfo + + + For the region + + + + + Price + + + + + Work period + + + + + Speed + + + + + Support tag + + + + + Copied + + + + + Reload API config + + + + + Reload API config? + + + + + + Continue + + + + + + Cancel + + + + + Cannot reload API config during active connection + + + + + Remove from application + + + + + Remove from application? + + + + + Cannot remove server during active connection + چالو کنکشن کے دوران سرور کو ہٹایا نہیں جا سکتا + + PageSettingsAppSplitTunneling - + Cannot change split tunneling settings during active connection فعال کنکشن کے دوران سپلٹ ٹنلنگ کی ترتیبات تبدیل نہیں کی جا سکتیں @@ -1184,52 +1372,52 @@ Already installed containers were found on the server. All installed containers فہرست میں شامل ایپ کو وی پی این کے ذریعے دسترس نہیں کیا جائے گا - + Only the apps from the list should have access via VPN - + Apps from the list should not have access via VPN - + App split tunneling ایپ اسپلٹ ٹنلنگ - + Mode موڈ - + Remove ہٹائیں - + Continue جاری رکھیں - + Cancel منسوخ - + application name ایپ کا نام - + Open executable file قابل اجراء فائل کو کھولیں - + Executable files (*.*) قابل اجراء فائل (*.*) @@ -1237,102 +1425,102 @@ Already installed containers were found on the server. All installed containers PageSettingsApplication - + Application ایپلیکیشن - + Allow application screenshots ایپلیکیشن میں تصویریں لینے کی اجازت دیں - + Enable notifications - + Enable notifications to show the VPN state in the status bar - + Auto start خود کار شروع - + Launch the application every time the device is starts جب بھی آلہ چلائے، ایپلیکیشن کو لانچ کریں - + Auto connect خودکار منسلک - + Connect to VPN on app start ایپ شروع ہونے پر VPN سے جڑیں - + Start minimized کمینائز شروع کریں - + Launch application minimized ایپلیکیشن کو کمینائز کر کے لانچ کریں - + Language زبان - + Logging لاگنگ - + Enabled فعال - + Disabled غیر فعال - + Reset settings and remove all data from the application ترتیبات کو دوبارہ ترتیب کریں اور ایپلیکیشن سے تمام ڈیٹا کو ختم کریں - + Reset settings and remove all data from the application? ترتیبات کو دوبارہ ترتیب دیں اور ایپلیکیشن سے تمام ڈیٹا کو ہٹا دیں؟ - + All settings will be reset to default. All installed AmneziaVPN services will still remain on the server. تمام ترتیبات کو معمولی حالت پر لوٹایا جائے گا۔ سب انسٹال کیے گئے امنیزیا وی پی این سروسزسرورپرموجودرہیںگی. - + Continue جاری رکھیں - + Cancel منسوخ - + Cannot reset settings during active connection چالو کنکشن کے دوران ترتیبات کو دوبارہ ترتیب نہیں دی جا سکتی @@ -1340,7 +1528,7 @@ Already installed containers were found on the server. All installed containers PageSettingsBackup - + Settings restored from backup file ترتیبات بیک اپ فائل سے بحال کردی گئی ہیں @@ -1419,62 +1607,62 @@ Already installed containers were found on the server. All installed containers PageSettingsConnection - + Connection کنکشن - + When AmneziaDNS is not used or installed ایمنیزیا ڈی این ایس کو استعمال نہیں کیا گیا ہو یا اسے انسٹال نہیں کیا گیاہے - + Allows you to use the VPN only for certain Apps آپ کو صرف مخصوص ایپلیکیشنز کے لئے وی پی این استعمال کرنے کی اجازت دیتا ہے - + Use AmneziaDNS AmneziaDNS استعمال کریں - + If AmneziaDNS is installed on the server اگر سرور پر AmneziaDNS انسٹال کیا گیا ہو تو - + DNS servers ڈی این ایس سرور - + Site-based split tunneling سائٹ کے بنیادی سپلٹ ٹنلنگ - + Allows you to select which sites you want to access through the VPN آپ کو یہ امکان فراہم کرتا ہے کہ آپ وی پی این کے ذریعہ کس سائٹ کو دسترس دینا چاہتے ہیں وہ منتخب کریں - + App-based split tunneling ایپ کے بنیاد پر سپلٹ ٹنلنگ - + KillSwitch - + Disables your internet if your encrypted VPN connection drops out for any reason. - + Cannot change killSwitch settings during active connection @@ -1482,62 +1670,62 @@ Already installed containers were found on the server. All installed containers PageSettingsDns - + Default server does not support custom DNS افتراضی سرور کا مخصوص DNS کو سپورٹ نہیں کرتا ہے - + DNS servers ڈی این ایس سرور - + If AmneziaDNS is not used or installed اگر AmneziaDNS استعمال نہیں کیا گیا ہو یا انسٹال نہیں کیا گیا ہو تو - + Primary DNS اولین DNS - + Secondary DNS ثانوی DNS - + Restore default اصل حالت کو بحال کریں - + Restore default DNS settings? اصل DNS ترتیبات کو بحال کریں؟ - + Continue براہ کرم جاری رکھیں - + Cancel منسوخ - + Settings have been reset ترتیبات کو دوبارہ ترتیب دیا گیا ہے - + Save محفوظ - + Settings saved ترتیبات محفوظ ہوگئیں @@ -1545,72 +1733,72 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - + Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. لاگنگ فعال ہے۔ یاد رہے کہ لاگوں کو 14 دنوں کے بعد خود بخود غیر فعال کر دیا جائے گا، اور تمام لاگ فائلیں حذف کردی جائیں گی. - + Logging لاگنگ - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. اس فعل کو فعال کرنے سے، ایپلیکیشن کے لاگ خود بخود محفوظ ہوجائیں گے۔ پہلے سے، لاگنگ کی فعالیت غیر فعال ہوتی ہے۔ اگر ایپلیکیشن میں کوئی خرابی ہو، تو لاگ کو بچانا فعال کریں. - + Save logs لاگوں کو محفوظ کریں - + Open folder with logs فائلوں کے فولڈر کو کھولیں - + Save محفوظ - + Logs files (*.log) لاگ فائلیں (*.log) - + Logs file saved لاگ فائل محفوظ ہوگئی - + Save logs to file لاگوں کو فائل میں محفوظ کریں - + Clear logs? کیا آپ لاگوں کو صاف کرنا چاہتے ہیں؟ - + Continue براہ کرم جاری رکھیں - + Cancel منسوخ - + Logs have been cleaned up تم مسح السجلاتلاگوں کو صاف کر دیا گیا ہے - + Clear logs لاگوں کو صاف کریں @@ -1618,22 +1806,22 @@ Already installed containers were found on the server. All installed containers PageSettingsServerData - + All installed containers have been added to the application تمام انسٹال شدہ کنٹینرز کو ایپلیکیشن میں شامل کر دیا گیا ہے - + No new installed containers found کوئی نئے انسٹال شدہ کنٹینرز نہیں ملے - + Do you want to reboot the server? کیا آپ سرور کو دوبارہ چالو کرنا چاہتے ہیں؟ - + Do you want to clear server from Amnezia software? هل تريد حذف الخادم من Amnezia?کیا آپ سرور کو Amnezia سافٹ ویئر سے صاف کرنا چاہتے ہیں؟ @@ -1642,94 +1830,94 @@ Already installed containers were found on the server. All installed containers - - - - - - Continue - براہ کرم جاری رکھیں - + Continue + براہ کرم جاری رکھیں + + + + + + Cancel منسوخ - + Check the server for previously installed Amnezia services سرور پر پہلے سے انسٹال کی گئی Amnezia سروسز کو چیک کریں - + Add them to the application if they were not displayed اگر وہ دکھایا نہیں گیا تو انہیں ایپلیکیشن میں شامل کریں - + Reboot server سرور کو دوبارہ چالو کریں - + The reboot process may take approximately 30 seconds. Are you sure you wish to proceed? ریبوٹ کا عمل تقریباً 30 سیکنڈ لے سکتا ہے۔ کیا آپ براہ کرم جاری رکھنا چاہتے ہیں؟ - + Cannot reboot server during active connection چالو کنکشن کے دوران سرور کو دوبارہ چالو نہیں کیا جا سکتا - + Remove server from application ایپلیکیشن سے سرور کو ہٹا دیں - + Do you want to remove the server from application? کیا آپ ایپلیکیشن سے سرور کو ہٹانا چاہتے ہیں؟ - + Cannot remove server during active connection چالو کنکشن کے دوران سرور کو ہٹایا نہیں جا سکتا - + All users whom you shared a connection with will no longer be able to connect to it. آپ نے اپنی کنکشن کا اشتراک دینے والے تمام صارفین کو اس سے جڑنے کی اجازت نہیں ہوگی. - + Cannot clear server from Amnezia software during active connection چالو کنکشن کے دوران سرور کو ایمنیزیا سافٹ ویئر سے صاف کرنا ممکن نہیں - + Reset API config API کونفیگ کو دوبارہ ترتیب دیں - + Do you want to reset API config? کیا آپ API کونفیگ کو دوبارہ ترتیب دینا چاہتے ہیں؟ - + Cannot reset API config during active connection چالو کنکشن کے دوران API ترتیبات کو دوبارہ ترتیب نہیں دی جا سکتی - + All installed AmneziaVPN services will still remain on the server. سرور پر تمام انسٹال شدہ AmneziaVPN سروسز محفوظ رہیں گے. - + Clear server from Amnezia software Amnezia سافٹ ویئر کو سرور سے صاف کریں @@ -1737,27 +1925,27 @@ Already installed containers were found on the server. All installed containers PageSettingsServerInfo - + Server name سرور کا نام - + Save محفوظ - + Protocols پروٹوکولات - + Services خدمات - + Management مینجمنٹ @@ -1765,27 +1953,27 @@ Already installed containers were found on the server. All installed containers PageSettingsServerProtocol - + settings ترتیبات - + Clear %1 profile %1 پروفائل کو صاف کریں - + Clear %1 profile? کیا آپ واقعی %1 پروفائل کو صاف کرنا چاہتے ہیں؟ - + Unable to clear %1 profile while there is an active connection فعال کنکشن کے دوران %1 پروفائل کو صاف نہیں کیا جا سکتا - + Cannot remove active container فعال کنٹینر کو ہٹانا ممکن نہیں @@ -1795,29 +1983,29 @@ Already installed containers were found on the server. All installed containers - + Remove ہٹائیں - + All users with whom you shared a connection will no longer be able to connect to it. آپ نے جن کے ساتھ کنکشن شئیر کیا تھا، ان تمام صارفین کو اس سے جڑنے کی اجازت نہیں ہوگی. - + Remove %1 from server? کیا آپ سرور سے %1 کو ہٹانا چاہتے ہیں؟ - - + + Continue براہ کرم جاری رکھیں - - + + Cancel منسوخ @@ -1825,7 +2013,7 @@ Already installed containers were found on the server. All installed containers PageSettingsServersList - + Servers سرور @@ -1833,201 +2021,322 @@ Already installed containers were found on the server. All installed containers PageSettingsSplitTunneling - + Default server does not support split tunneling function افتراضی سرور سپلٹ ٹنلنگ فعال نہیں کرتا - + Addresses from the list should not be accessed via VPN اس فہرست سے پتوں کا وی پی این کے ذریعے دسترس حاصل نہیں کیا جانا چاہئے - + Split tunneling اسپلٹ ٹنلنگ - + Mode موڈ - + Remove ہٹائیں - + Continue براہ کرم جاری رکھیں - + Cancel منسوخ - + Only the sites listed here will be accessed through the VPN صرف یہاں درج کردہ سائٹس وی پی این کے ذریعے دسترس حاصل کریں گی - + Cannot change split tunneling settings during active connection فعال کنکشن کے دوران سپلٹ ٹنلنگ کی ترتیبات تبدیل نہیں کی جا سکتیں - + website or IP ویب سائٹ یا آئی پی - + Import / Export Sites سائٹس درآمد / برآمد - + Import درآمد - + Save site list سائٹ کی فہرست کو محفوظ کریں - + Save sites سائٹس کو محفوظ کریں - - - + + + Sites files (*.json) سائٹس فائلیں (*.json) - + Import a list of sites ایک فہرست کو درآمد کریں - + Replace site list سائٹ کی فہرست کو بدلیں - - + + Open sites file سائٹس فائل کو کھولیں - + Add imported sites to existing ones آمدہ سائٹس کو موجودہ میں شامل کریں + + PageSetupWizardApiServiceInfo + + + For the region + + + + + Price + + + + + Work period + + + + + Speed + + + + + Features + + + + + Connect + + + + + PageSetupWizardApiServicesList + + + VPN by Amnezia + + + + + Choose a VPN service that suits your needs. + + + PageSetupWizardConfigSource - Server connection - سرور کنکشن + سرور کنکشن - Do not use connection codes from untrusted sources, as they may be created to intercept your data. - غیر معتبر ماخذ سے کنکشن کوڈ استعمال نہ کریں، کیونکہ یہ آپ کے ڈیٹا کو منسلک کرنے کے لئے تخلیق کیا گیا ہوسکتا ہے. + غیر معتبر ماخذ سے کنکشن کوڈ استعمال نہ کریں، کیونکہ یہ آپ کے ڈیٹا کو منسلک کرنے کے لئے تخلیق کیا گیا ہوسکتا ہے. - What do you have? - آپ کو کس میں مدد چاہیے؟ + آپ کو کس میں مدد چاہیے؟ - File with connection settings or backup - کنکشن کی ترتیبات یا بیک اپ والی فائل + کنکشن کی ترتیبات یا بیک اپ والی فائل + + + + Connection + کنکشن + + + + Insert the key, add a configuration file or scan the QR-code + + Insert key + + + + + Insert + داخل کریں + + + + Continue + + + + + Other connection options + + + + + VPN by Amnezia + + + + + Connect to classic paid and free VPN services from Amnezia + + + + + Self-hosted VPN + + + + + Configure Amnezia VPN on your own server + + + + + Restore from backup + بیک اپ سے بحال کریں + + + + Open backup file + بیک اپ فائل کو کھولیں + + + + Backup files (*.backup) + بیک اپ فائلیں (*.backup) + + + File with connection settings کنکشن کی ترتیبات والی فائل - + Open config file کنفیگ فائل کو کھولیں - + QR code QR کوڈ - + + I have nothing + میرے پاس کچھ نہیں ہے + + Key as text - متن کے طور پر کلید + متن کے طور پر کلید PageSetupWizardCredentials - + Configure your server اپنے سرور کو ترتیب دیں - + Server IP address [:port] سرور آئی پی پتہ [:پورٹ] - + Continue براہ کرم جاری رکھیں - + All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties آپ جو ڈیٹا داخل کریں گے وہ بالکل خفیہ رہے گا اور نہ تو امنیزیا یا کسی تیسری شخصیت کے ساتھ اشتراک کیا جائے گا - + 255.255.255.255:22 - + SSH Username ایس ایس ایچ صارف نام - + Password or SSH private key پاس ورڈ یا SSH نجی کلید - + + How to run your VPN server + + + + + Where to get connection data, step-by-step instructions for buying a VPS + + + + Ip address cannot be empty آئی پی پتہ خالی نہیں ہو سکتا - + Enter the address in the format 255.255.255.255:88 ایڈریس درج کریں فارمیٹ 255.255.255.255:88 - + Login cannot be empty لاگ ان نام خالی نہیں ہو سکتا - + Password/private key cannot be empty پاس ورڈ یا نجی کلید خالی نہیں ہو سکتی @@ -2035,22 +2344,22 @@ Already installed containers were found on the server. All installed containers PageSetupWizardEasy - + What is the level of internet control in your region? آپ کے علاقے میں انٹرنیٹ کنٹرول کا سطح کیا ہے؟ - + Choose a VPN protocol ایک VPN پروٹوکول کا انتخاب کریں - + Skip setup ترتیب چھوڑیں - + Continue جاری رکھیں @@ -2058,38 +2367,38 @@ Already installed containers were found on the server. All installed containers PageSetupWizardInstalling - - + + Usually it takes no more than 5 minutes عموماً یہ 5 منٹ سے زیادہ نہیں لیتا - + The server has already been added to the application سرور پہلے ہی ایپلیکیشن میں شامل کر دیا گیا ہے - + Amnezia has detected that your server is currently ایمنیزیا نے دریافت کیا ہے کہ آپ کا سرور موجودہ - + busy installing other software. Amnezia installation مصروف ہے اور دوسرے سافٹ ویئر کی انسٹالیشن کر رہا ہے - + Cancel installation انسٹالیشن منسوخ - + will pause until the server finishes installing other software دوسرے سافٹ ویئر کی انسٹالیشن ختم ہونے تک انتظار کرے گا - + Installing انسٹال ہو رہی ہے @@ -2097,37 +2406,37 @@ Already installed containers were found on the server. All installed containers PageSetupWizardProtocolSettings - + Installing %1 %1 کی انسٹالیشن - + More detailed مزید تفصیلات والا - + Close بند - + Network protocol نیٹ ورک پروٹوکول - + Port پورٹ - + Install انسٹال - + The port must be in the range of 1 to 65535 @@ -2135,12 +2444,12 @@ Already installed containers were found on the server. All installed containers PageSetupWizardProtocols - + VPN protocol وی پی این پروٹوکول - + Choose the one with the highest priority for you. Later, you can install other protocols and additional services, such as DNS proxy and SFTP. آپ کے لئے سب سے زیادہ اہم پروٹوکول کا انتخاب کریں۔ بعد میں، آپ دوسرے پروٹوکول اور اضافی خدمات، جیسے DNS پراکسی اور SFTP، انسٹال کر سکتے ہیں۔ @@ -2148,7 +2457,7 @@ Already installed containers were found on the server. All installed containers PageSetupWizardQrReader - + Point the camera at the QR code and hold for a couple of seconds. کیمرے کو QR کوڈ پر موجود کریں اور کچھ سیکنڈ کے لئے رکھیں. @@ -2156,60 +2465,55 @@ Already installed containers were found on the server. All installed containers PageSetupWizardStart - Settings restored from backup file - ترتیبات بیک اپ فائل سے بحال کردی گئی ہیں + ترتیبات بیک اپ فائل سے بحال کردی گئی ہیں - Free service for creating a personal VPN on your server. - آپ کے سرور پر ایک ذاتی وی پی این بنانے کے لئے مفت خدمات. + آپ کے سرور پر ایک ذاتی وی پی این بنانے کے لئے مفت خدمات. - Helps you access blocked content without revealing your privacy, even to VPN providers. - آپ کو ریاست کردہ مواد تک رسائی فراہم کرتا ہے بغیر آپ کے خصوصیت کو وی پی این فراہم کرنے والوں تک بھی ظاہر نہیں کرتا. + آپ کو ریاست کردہ مواد تک رسائی فراہم کرتا ہے بغیر آپ کے خصوصیت کو وی پی این فراہم کرنے والوں تک بھی ظاہر نہیں کرتا. - I have the data to connect - میرے پاس اس کنکشن کے لئے ڈیٹا موجود ہے + میرے پاس اس کنکشن کے لئے ڈیٹا موجود ہے - I have nothing - میرے پاس کچھ نہیں ہے + میرے پاس کچھ نہیں ہے - - https://amnezia.org/instructions/0_starter-guide - + + Let's get started + PageSetupWizardTextKey - + Connection key کنکشن کی کلید - + A line that starts with vpn://... ایک لائن جو vpn:// سے شروع ہوتی ہے... - + Key کلید - + Insert داخل کریں - + Continue جاری رہنے دیں @@ -2217,32 +2521,32 @@ Already installed containers were found on the server. All installed containers PageSetupWizardViewConfig - + New connection نیا کنکشن - + Collapse content مواد کو غیر فعال کریں - + Show content مواد دکھائیں - + Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider. وائر گارڈ کی غلط شناخت کو بروئے کار لانے کے لئے وائر گارڈ غلط شناخت کو فعال کریں۔ آپ کے پرووائیڈر پر وائر گارڈ بند ہونے کی صورت میں یہ کار آمد ہو سکتی ہے۔ - + Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data. صرف ان ماخذ سے کنکشن کوڈ استعمال کریں جن پر آپ کو اعتماد ہو۔ عوامی ماخذوں سے کوڈز آپ کے ڈیٹا کو منسلک کرنے کے لیے بنائے گئے ہو سکتے ہیں. - + Connect کنکٹ @@ -2250,37 +2554,37 @@ Already installed containers were found on the server. All installed containers PageShare - + Save OpenVPN config اوپن وی پی این کی ترتیبات کو محفوظ کریں - + Save WireGuard config وائر گارڈ کی ترتیبات کو محفوظ کریں - + Save AmneziaWG config ایمنیزیا ڈبلیو جی کی ترتیبات کو محفوظ کریں - + Save Shadowsocks config شیڈو ساکس کی ترتیبات کو محفوظ کریں - + Save Cloak config چادر کی ترتیبات کو محفوظ کریں - + Save XRay config "XRay کنفیگ کو محفوظ کریں - + For the AmneziaVPN app AmneziaVPN ایپ کے لئے @@ -2289,78 +2593,78 @@ Already installed containers were found on the server. All installed containers OpenVPN کا اصل فارمیٹ - + WireGuard native format وائر گارڈ کا اصل فارمیٹ - + AmneziaWG native format ایمنیزیا ڈبلیو جی کا اصل فارمیٹ - + Shadowsocks native format شیڈو ساکس کا اصل فارمیٹ - + Cloak native format Cloak کا اصل فارمیٹ - + XRay native format ایکس رے کا نیٹویٹ فارمیٹ - + Share VPN Access VPN دسترسی شیئر - + Share full access to the server and VPN سرور اور وی پی این کے لئے مکمل دسترسی کو شیئر کریں - + Use for your own devices, or share with those you trust to manage the server. اپنی خود کی ڈیوائسز کے لئے استعمال کریں، یا ان لوگوں کے ساتھ شیئر کریں جن پر آپ کا بھروسہ ہو کہ وہ سرور کو منظم کر سکیں. - - + + Users صارفین - + Share VPN access without the ability to manage the server سرور کو منظم کرنے کی صلاحیت کے بغیر وی پی این کی دسترسی شیئر - + Search تلاش - + Creation date: %1 - + Latest handshake: %1 - + Data received: %1 - + Data sent: %1 @@ -2369,96 +2673,96 @@ Already installed containers were found on the server. All installed containers تخلیق کی تاریخ: - + Rename نام تبدیل - + Client name کلائنٹ کا نام - + Save محفوظ - + Revoke واپس لین - + Revoke the config for a user - %1? کیا آپ مستعمل کے لئے کنفیگ کو واپس لینا چاہتے ہیں - %1؟ - + The user will no longer be able to connect to your server. صارف آپ کے سرور سے متصل ہونے کا اختیار نہیں رہے گا. - + Continue جاری رکھیں - + Cancel منسوخ - + Connection کنکشن - - + + Server سرور - + File with connection settings to کنکشن کی ترتیبات کی فائل - - + + Protocol پروٹوکول - + Connection to کنکشن کو - + Config revoked کنفیگ منسوخ - + OpenVPN native format - + User name صارف کا نام - - + + Connection format کنکشن فارمیٹ - - + + Share شیئر @@ -2466,50 +2770,50 @@ Already installed containers were found on the server. All installed containers PageShareFullAccess - + Full access to the server and VPN سرور اور وی پی این کی مکمل رسائی - + We recommend that you use full access to the server only for your own additional devices. ہم آپ کو سرور کا مکمل رسائی صرف اپنی اضافی ڈیوائسز کے لئے استعمال کرنے کی تجویز دیتے ہیں. - + If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. "اگر آپ دوسروں کے ساتھ مکمل رسائی شیئر کریں تو وہ سرور پروٹوکول اور خدمات کو ہٹا سکتے ہیں اور شامل کر سکتے ہیں، جس سے وی پی این تمام صارفین کے لئے غلط کام کرے گا. - + Server سرور - + Accessing رسائی - + File with accessing settings to ترتیبات کے ساتھ دسترسی کی فائل - + Share شیئر - + Connection to کنکشن کو - + File with connection settings to کنکشن کی ترتیبات کی فائل @@ -2517,15 +2821,20 @@ Already installed containers were found on the server. All installed containers PageStart - + Logging was disabled after 14 days, log files were deleted لاگنگ کو 14 دنوں کے بعد غیر فعال کر دیا گیا، لاگ فائلوں کو حذف کر دیا گیا + + + Settings restored from backup file + ترتیبات بیک اپ فائل سے بحال کردی گئی ہیں + PopupType - + Close بند @@ -2871,7 +3180,7 @@ Already installed containers were found on the server. All installed containers یہ تشکیل پہلے ہی ایپلی کیشن میں شامل کی جا چکی ہے - + ErrorCode: %1. ایرر کوڈ: %1. @@ -2961,37 +3270,42 @@ Already installed containers were found on the server. All installed containers - + + Missing AGW public key + + + + QFile error: The file could not be opened QFile کی خرابی: فائل کو نہیں کھولا جا سکا - + QFile error: An error occurred when reading from the file کیو فائل کی خرابی: فائل سے پڑھتے وقت ایک خرابی پیش آگئی - + QFile error: The file could not be accessed QFile کی خرابی: فائل تک رسائی نہیں ہو سکی - + QFile error: An unspecified error occurred کیو فائل میں خرابی: ایک غیر متعینہ خرابی پیش آگئی - + QFile error: A fatal error occurred کیو فائل میں خرابی: ایک مہلک خرابی پیش آگئی - + QFile error: The operation was aborted کیو فائل کی خرابی: آپریشن روک دیا گیا تھا - + Internal error داخلی خامی @@ -3373,7 +3687,7 @@ While it offers a blend of security, stability, and speed, it's essential t SelectLanguageDrawer - + Choose language زبان کا انتخاب کریں @@ -3381,13 +3695,13 @@ While it offers a blend of security, stability, and speed, it's essential t Settings - + Server #1 سرور نمبر 1 - - + + Server سرور @@ -3408,39 +3722,39 @@ While it offers a blend of security, stability, and speed, it's essential t ShareConnectionDrawer - - + + Save AmneziaVPN config AmneziaVPN ترتیب کو محفوظ کریں - + Share بانٹیں - + Copy کاپی - - + + Copied کاپی - + Copy config string تشکیل سٹرنگ کو کاپی کریں - + Show connection settings کنکشن کی ترتیبات دکھائیں - + To read the QR code in the Amnezia app, select "Add server" → "I have data to connect" → "QR code, key or settings file" ایمنیزیا ایپ میں QR کوڈ پڑھنے کے لیے، "سرور شامل کریں" → "میرے پاس جوڑنے کے لیے ڈیٹا ہے" → "QR کوڈ، کلید یا سیٹنگ فائل" کو منتخب کریں @@ -3524,7 +3838,7 @@ While it offers a blend of security, stability, and speed, it's essential t TextFieldWithHeaderType - + The field can't be empty یہ فیلڈ خالی نہیں ہو سکتا @@ -3583,7 +3897,7 @@ While it offers a blend of security, stability, and speed, it's essential t amnezia::ContainerProps - + Low کم @@ -3596,17 +3910,17 @@ While it offers a blend of security, stability, and speed, it's essential t انتہائی - + High - + I just want to increase the level of my privacy. میں صرف اپنی خصوصیت کا سطح بڑھانا چاہتا ہوں. - + I want to bypass censorship. This option recommended in most cases. میں سانسر شدگی سے چھٹکارا حاصل کرنا چاہتا ہوں۔ یہ اختیار بیشتر صورتوں میں تجویز کیا جاتا ہے. @@ -3618,12 +3932,12 @@ While it offers a blend of security, stability, and speed, it's essential t main2 - + Private key passphrase نجی کلید پاس فریز - + Save محفوظ کریں diff --git a/client/translations/amneziavpn_zh_CN.ts b/client/translations/amneziavpn_zh_CN.ts index f984eddf..423c9e00 100644 --- a/client/translations/amneziavpn_zh_CN.ts +++ b/client/translations/amneziavpn_zh_CN.ts @@ -1,6 +1,54 @@ + + ApiServicesModel + + + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s + + + + + VPN to access blocked sites in regions with high levels of Internet censorship. + + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. + + + + + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship + + + + + %1 MBit/s + + + + + %1 days + + + + + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> + + + + + Free + + + + + %1 $/month + + + AppSplitTunnelingController @@ -27,7 +75,7 @@ ConnectButton - + Unable to disconnect during configuration preparation @@ -35,61 +83,61 @@ ConnectionController - - - + + + Connect 连接 - + VPN Protocols is not installed. Please install VPN container at first 请先安装VPN协议 - + Connecting... 连接中 - + Connected 已连接 - + Reconnecting... 重连中 - + Disconnecting... 断开中 - + Preparing... - + Settings updated successfully, reconnnection... 配置已更新, 重连中... - + Settings updated successfully 配置更新成功 - + The selected protocol is not supported on the current platform 当前平台不支持所选协议 - + unable to create configuration @@ -130,7 +178,7 @@ 粘贴 - + &SelectAll 全选 @@ -237,58 +285,78 @@ Can't be disabled for current server 已安装在服务器上 - + %1 installed successfully. %1 安装成功。 - + %1 is already installed on the server. 服务器上已经安装 %1。 - + Added containers that were already installed on the server 添加已安装在服务器上的容器 - + Already installed containers were found on the server. All installed containers have been added to the application 在服务上发现已经安装协议并添加至应用 - + Settings updated successfully 配置更新成功 - + Server '%1' was rebooted 服务器 '%1' 已重新启动 - + Server '%1' was removed 已移除服务器 '%1' - + All containers from server '%1' have been removed 服务器 '%1' 的所有容器已移除 - + %1 has been removed from the server '%2' %1 已从服务器 '%2' 上移除 - + + Api config removed + + + + %1 cached profile cleared + + + %1 installed successfully. + + + + + API config reloaded + + + + + Successfully changed the country of connection to %1 + + 1% has been removed from the server '%2' %1 已从服务器 '%2' 上移除 @@ -306,12 +374,12 @@ Already installed containers were found on the server. All installed containers 协议已从 - + Please login as the user 请以用户身份登录 - + Server added successfully 增加服务器成功 @@ -319,17 +387,17 @@ Already installed containers were found on the server. All installed containers InstalledAppsDrawer - + Choose application - + application name - + Add selected @@ -384,45 +452,53 @@ Already installed containers were found on the server. All installed containers PageDeinstalling - + Removing services from %1 正从 %1 移除服务 - + Usually it takes no more than 5 minutes 大约5分钟之内完成 + + PageDevMenu + + + Gateway endpoint + + + PageHome - + Logging enabled - + Split tunneling enabled 用户分隔隧道已启用 - + Split tunneling disabled 分隔隧道已禁用 - + VPN protocol VPN协议 - + Servers 服务器 - + Unable change server while there is an active connection 已建立连接时无法更改服务器配置 @@ -430,17 +506,17 @@ Already installed containers were found on the server. All installed containers PageProtocolAwgSettings - + AmneziaWG settings AmneziaWG 配置 - + Port 端口 - + MTU @@ -453,42 +529,87 @@ Already installed containers were found on the server. All installed containers 从服务上移除AmneziaWG? - + All users with whom you shared a connection with will no longer be able to connect to it. 与您共享连接的所有用户将无法再连接到该连接。 - + Save 保存 - + + Jc - Junk packet count + + + + + Jmin - Junk packet minimum size + + + + + Jmax - Junk packet maximum size + + + + + S1 - Init packet junk size + + + + + S2 - Response packet junk size + + + + + H1 - Init packet magic header + + + + + H2 - Response packet magic header + + + + + H4 - Transport packet magic header + + + + + H3 - Underload packet magic header + + + + The values of the H1-H4 fields must be unique - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) - + Save settings? 保存设置? - + Continue 继续 - + Cancel 取消 - + Unable change settings while there is an active connection @@ -496,33 +617,33 @@ Already installed containers were found on the server. All installed containers PageProtocolCloakSettings - + Cloak settings Cloak 配置 - + Disguised as traffic from 伪装流量为 - + Port 端口 - + Cipher 加密算法 - + Save 保存 - + Unable change settings while there is an active connection @@ -530,170 +651,170 @@ Already installed containers were found on the server. All installed containers PageProtocolOpenVpnSettings - + OpenVPN settings OpenVPN 配置 - + VPN address subnet VPN 地址子网 - + Network protocol 网络协议 - + Port 端口 - + Auto-negotiate encryption 自定义加密方式 - + Hash - + SHA512 - + SHA384 - + SHA256 - + SHA3-512 - + SHA3-384 - + SHA3-256 - + whirlpool - + BLAKE2b512 - + BLAKE2s256 - + SHA1 - + Cipher - + AES-256-GCM - + AES-192-GCM - + AES-128-GCM - + AES-256-CBC - + AES-192-CBC - + AES-128-CBC - + ChaCha20-Poly1305 - + ARIA-256-CBC - + CAMELLIA-256-CBC - + none - + TLS auth TLS认证 - + Block DNS requests outside of VPN 阻止VPN外的DNS请求 - + Additional client configuration commands 附加客户端配置命令 - - + + Commands: 命令: - + Additional server configuration commands 附加服务器端配置命令 - + Unable change settings while there is an active connection @@ -710,7 +831,7 @@ Already installed containers were found on the server. All installed containers 与您共享连接的所有用户将无法再连接到该连接。 - + Save 保存 @@ -730,12 +851,12 @@ Already installed containers were found on the server. All installed containers PageProtocolRaw - + settings 配置 - + Show connection options 显示连接选项 @@ -744,22 +865,22 @@ Already installed containers were found on the server. All installed containers 连接选项 - + Connection options %1 %1 连接选项 - + Remove 移除 - + Remove %1 from server? 从服务器移除 %1 ? - + All users with whom you shared a connection with will no longer be able to connect to it. 与您共享连接的所有用户将无法再连接到该连接。 @@ -772,12 +893,12 @@ Already installed containers were found on the server. All installed containers 与您共享连接的所有用户将无法再连接到此链接 - + Continue 继续 - + Cancel 取消 @@ -785,28 +906,28 @@ Already installed containers were found on the server. All installed containers PageProtocolShadowSocksSettings - + Shadowsocks settings Shadowsocks 配置 - + Port 端口 - + Cipher 加密算法 - + Save 保存 - + Unable change settings while there is an active connection @@ -814,22 +935,22 @@ Already installed containers were found on the server. All installed containers PageProtocolWireGuardSettings - + WG settings - + Port 端口 - + MTU - + Unable change settings while there is an active connection @@ -846,7 +967,7 @@ Already installed containers were found on the server. All installed containers 取消 - + Save 保存 @@ -854,22 +975,22 @@ Already installed containers were found on the server. All installed containers PageProtocolXraySettings - + XRay settings - + Disguised as traffic from 伪装流量为 - + Save 保存 - + Unable change settings while there is an active connection @@ -877,29 +998,29 @@ Already installed containers were found on the server. All installed containers PageServiceDnsSettings - + A DNS service is installed on your server, and it is only accessible via VPN. 您的服务器已安装DNS服务,仅能通过VPN访问。 - + The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab. 其地址与您的服务器地址相同。您可以在 设置 连接 中进行配置。 - + Remove 移除 - + Remove %1 from server? 从服务器移除 %1 ? - + Cannot remove AmneziaDNS from running server @@ -908,12 +1029,12 @@ Already installed containers were found on the server. All installed containers 从服务器 - + Continue 继续 - + Cancel 取消 @@ -921,157 +1042,153 @@ Already installed containers were found on the server. All installed containers PageServiceSftpSettings - + Settings updated successfully 配置更新成功 - + SFTP settings SFTP 配置 - + Host 主机 - - - - + + + + Copied 拷贝 - + Port 端口 - + User name 用户名 - + Password 密码 - + Mount folder on device 挂载文件夹 - + In order to mount remote SFTP folder as local drive, perform following steps: <br> 为将远程 SFTP 文件夹挂载到本地,请执行以下步骤: <br> - - + + <br>1. Install the latest version of <br>1. 安装最新版的 - - + + <br>2. Install the latest version of <br>2. 安装最新版的 - + Detailed instructions 详细说明 - Remove SFTP and all data stored there - 移除SFTP和其本地所有数据 + 移除SFTP和其本地所有数据 - Remove SFTP and all data stored there? - 移除SFTP和其本地所有数据? + 移除SFTP和其本地所有数据? - Continue - 继续 + 继续 - Cancel - 取消 + 取消 PageServiceSocksProxySettings - + Settings updated successfully 配置更新成功 - - + + SOCKS5 settings - + Host 主机 - - - - + + + + Copied - - + + Port 端口 - + User name 用户名 - - + + Password 密码 - + Username - - + + Change connection settings - + The port must be in the range of 1 to 65535 - + Password cannot be empty - + Username cannot be empty @@ -1079,95 +1196,96 @@ Already installed containers were found on the server. All installed containers PageServiceTorWebsiteSettings - + Settings updated successfully 配置更新成功 - + Tor website settings Tor网站配置 - + Website address 网址 - + Copied 已拷贝 - + Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL. 用 <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor 浏览器</a> 打开上面网址. - + After creating your onion site, it takes a few minutes for the Tor network to make it available for use. 创建您的洋葱网站后,需要几分钟时间,才能使其在Tor网络上可用 - + When configuring WordPress set the this onion address as domain. 配置 WordPress 时,将此洋葱地址设置为域。 - Remove website - 移除网站 + 移除网站 - The site with all data will be removed from the tor network. - 网站及其所有数据将从 Tor 网络中删除 + 网站及其所有数据将从 Tor 网络中删除 - Continue - 继续 + 继续 - Cancel - 取消 + 取消 PageSettings - + Settings 设置 - + Servers 服务器 - + Connection 连接 - + Application 应用 - + Backup 备份 - + About AmneziaVPN 关于 + Dev console + + + + Close application 关闭应用 @@ -1181,135 +1299,205 @@ And if you don't like the app, all the more support it - the donation will 如果您不喜欢,请捐助支持我们改进它。 - + Support Amnezia 支持Amnezia - + Amnezia is a free and open-source application. You can support the developers if you like it. Amnezia 是一款免费的开源应用程序。 如果您喜欢的话可以支持开发者。 - + Contacts 联系方式 - + Telegram group 电报群 - + To discuss features 用于功能讨论 - + https://t.me/amnezia_vpn_en - + Mail 邮件 - + For reviews and bug reports 用于评论和提交软件的缺陷 - + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website 官网 - - https://amnezia.org - - - - + Software version: %1 软件版本: %1 - + Check for updates 检查更新 - + Privacy Policy 隐私政策 - PageSettingsAppSplitTunneling + PageSettingsApiServerInfo - - Cannot change split tunneling settings during active connection - 无法在活动连接期间更改分割隧道设置 - - - - Only the apps from the list should have access via VPN + + For the region - - Apps from the list should not have access via VPN + + Price - - App split tunneling + + Work period - - Mode - 规则 - - - - Remove + + Speed - + + Support tag + + + + + Copied + + + + + Reload API config + + + + + Reload API config? + + + + + Continue 继续 - + + Cancel 取消 - + + Cannot reload API config during active connection + + + + + Remove from application + + + + + Remove from application? + + + + + Cannot remove server during active connection + + + + + PageSettingsAppSplitTunneling + + + Cannot change split tunneling settings during active connection + 无法在活动连接期间更改分割隧道设置 + + + + Only the apps from the list should have access via VPN + + + + + Apps from the list should not have access via VPN + + + + + App split tunneling + + + + + Mode + 规则 + + + + Remove + + + + + Continue + 继续 + + + + Cancel + 取消 + + + application name - + Open executable file - + Executable files (*.*) @@ -1317,27 +1505,27 @@ And if you don't like the app, all the more support it - the donation will PageSettingsApplication - + Application 应用 - + Allow application screenshots 允许截屏 - + Enable notifications - + Enable notifications to show the VPN state in the status bar - + Auto start 自动运行 @@ -1350,77 +1538,77 @@ And if you don't like the app, all the more support it - the donation will 启动时自动运行运用程序 - + Launch the application every time the device is starts 每次设备启动时启动应用程序 - + Auto connect 自动连接 - + Connect to VPN on app start 应用开启时连接VPN - + Start minimized 最小化 - + Launch application minimized 开启应用软件时窗口最小化 - + Language 语言 - + Logging 日志 - + Enabled 开启 - + Disabled 禁用 - + Reset settings and remove all data from the application 重置并清理应用的所有数据 - + Reset settings and remove all data from the application? 重置并清理应用的所有数据? - + All settings will be reset to default. All installed AmneziaVPN services will still remain on the server. 所有配置恢复为默认值。服务器已安装的AmneziaVPN服务将被保留。 - + Continue 继续 - + Cancel 取消 - + Cannot reset settings during active connection @@ -1428,7 +1616,7 @@ And if you don't like the app, all the more support it - the donation will PageSettingsBackup - + Settings restored from backup file 从备份文件还原配置 @@ -1511,32 +1699,32 @@ And if you don't like the app, all the more support it - the donation will PageSettingsConnection - + Connection 连接 - + When AmneziaDNS is not used or installed 当未使用或未安装AmneziaDNS时 - + Allows you to use the VPN only for certain Apps 只允许在某些应用程序中使用 VPN - + KillSwitch - + Disables your internet if your encrypted VPN connection drops out for any reason. - + Cannot change killSwitch settings during active connection @@ -1545,17 +1733,17 @@ And if you don't like the app, all the more support it - the donation will 使用AmneziaDNS,如其已安装在服务器上 - + Use AmneziaDNS 使用AmneziaDNS - + If AmneziaDNS is installed on the server 如果已在服务器安装AmneziaDNS - + DNS servers DNS服务器 @@ -1564,17 +1752,17 @@ And if you don't like the app, all the more support it - the donation will 如果未使用或未安装AmneziaDNS - + Site-based split tunneling 基于网站的隧道分离 - + Allows you to select which sites you want to access through the VPN 配置想要通过VPN访问网站 - + App-based split tunneling 基于应用的隧道分离 @@ -1598,62 +1786,62 @@ And if you don't like the app, all the more support it - the donation will PageSettingsDns - + Default server does not support custom DNS 默认服务器不支持自定义 DNS - + DNS servers DNS服务器 - + If AmneziaDNS is not used or installed 如果未使用或未安装AmneziaDNS - + Primary DNS 首选 DNS - + Secondary DNS 备用 DNS - + Restore default 恢复默认配置 - + Restore default DNS settings? 是否恢复默认DNS配置? - + Continue 继续 - + Cancel 取消 - + Settings have been reset 已重置 - + Save 保存 - + Settings saved 配置已保存 @@ -1661,72 +1849,72 @@ And if you don't like the app, all the more support it - the donation will PageSettingsLogging - + Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - + Logging 日志 - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. 默认情况下,日志功能是禁用的。如果应用程序出现故障,则启用日志保存功能。 - + Save logs 记录日志 - + Open folder with logs 打开日志文件夹 - + Save 保存 - + Logs files (*.log) - + Logs file saved 日志文件已保存 - + Save logs to file 保存日志到文件 - + Clear logs? 清理日志? - + Continue 继续 - + Cancel 取消 - + Logs have been cleaned up 日志已清理 - + Clear logs 清理日志 @@ -1734,12 +1922,12 @@ And if you don't like the app, all the more support it - the donation will PageSettingsServerData - + All installed containers have been added to the application 所有已安装的容器,已被添加到应用软件 - + No new installed containers found 未发现新安装的容器 @@ -1756,12 +1944,12 @@ And if you don't like the app, all the more support it - the donation will 清除缓存? - + Do you want to reboot the server? 您想重新启动服务器吗? - + Do you want to clear server from Amnezia software? 您要清除服务器上的Amnezia软件吗? @@ -1770,84 +1958,84 @@ And if you don't like the app, all the more support it - the donation will - - - - - - Continue - 继续 - + Continue + 继续 + + + + + + Cancel 取消 - + Check the server for previously installed Amnezia services 检查服务器上,是否存在之前安装的 Amnezia 服务 - + Add them to the application if they were not displayed 如果存在且未显示,则添加到应用软件 - + Reboot server 重新启动服务器 - + The reboot process may take approximately 30 seconds. Are you sure you wish to proceed? 重新启动过程可能需要大约30秒。您确定要继续吗? - + Cannot reboot server during active connection - + Remove server from application 移除本地服务器信息 - + Do you want to remove the server from application? 您想要从应用程序中移除服务器吗? - + Cannot remove server during active connection - + All users whom you shared a connection with will no longer be able to connect to it. 与您共享连接的所有用户将无法再连接到该连接。 - + Cannot clear server from Amnezia software during active connection - + Reset API config 重置 API 配置 - + Do you want to reset API config? 您想重置 API 配置吗? - + Cannot reset API config during active connection @@ -1856,12 +2044,12 @@ And if you don't like the app, all the more support it - the donation will 移除本地服务器信息? - + All installed AmneziaVPN services will still remain on the server. 所有已安装的 AmneziaVPN 服务仍将保留在服务器上。 - + Clear server from Amnezia software 清理Amnezia中服务器信息 @@ -1877,27 +2065,27 @@ And if you don't like the app, all the more support it - the donation will PageSettingsServerInfo - + Server name 服务器名 - + Save 保存 - + Protocols 协议 - + Services 服务 - + Management 管理 @@ -1909,42 +2097,42 @@ And if you don't like the app, all the more support it - the donation will PageSettingsServerProtocol - + settings 配置 - + Clear %1 profile - + Clear %1 profile? - + - + Unable to clear %1 profile while there is an active connection - + Remove 移除 - + All users with whom you shared a connection will no longer be able to connect to it. 与您共享连接的所有用户将无法再连接到该连接。 - + Cannot remove active container @@ -1957,7 +2145,7 @@ And if you don't like the app, all the more support it - the donation will 从服务器 - + Remove %1 from server? 从服务器移除 %1 ? @@ -1966,14 +2154,14 @@ And if you don't like the app, all the more support it - the donation will 与您共享连接的所有用户将无法再连接到此链接 - - + + Continue 继续 - - + + Cancel 取消 @@ -1981,7 +2169,7 @@ And if you don't like the app, all the more support it - the donation will PageSettingsServersList - + Servers 服务器 @@ -2001,7 +2189,7 @@ And if you don't like the app, all the more support it - the donation will 网站级VPN分流 - + Default server does not support split tunneling function 默认服务器不支持分离隧道功能 @@ -2010,32 +2198,32 @@ And if you don't like the app, all the more support it - the donation will 仅使用VPN访问 - + Addresses from the list should not be accessed via VPN 不使用VPN访问 - + Split tunneling 隧道分离 - + Mode 规则 - + Remove 移除 - + Continue 继续 - + Cancel 取消 @@ -2048,75 +2236,120 @@ And if you don't like the app, all the more support it - the donation will 导入/导出网站 - + Cannot change split tunneling settings during active connection 无法在活动连接期间更改分割隧道设置 - + Only the sites listed here will be accessed through the VPN 只有这里列出的网站将通过VPN访问 - + website or IP 网站或IP - + Import / Export Sites 导入/导出网站 - + Import 导入 - + Save site list 保存网址 - + Save sites 保存网址 - - - + + + Sites files (*.json) - + Import a list of sites 导入网址列表 - + Replace site list 替换网址列表 - - + + Open sites file 打开网址文件 - + Add imported sites to existing ones 将导入的网址添加到现有网址中 + + PageSetupWizardApiServiceInfo + + + For the region + + + + + Price + + + + + Work period + + + + + Speed + + + + + Features + + + + + Connect + 连接 + + + + PageSetupWizardApiServicesList + + + VPN by Amnezia + + + + + Choose a VPN service that suits your needs. + + + PageSetupWizardConfigSource - Server connection - 服务器连接 + 服务器连接 Do not use connection code from public sources. It may have been created to intercept your data. @@ -2126,39 +2359,105 @@ It's okay as long as it's from someone you trust. 请确保连接码来源可信。 - Do not use connection codes from untrusted sources, as they may be created to intercept your data. - 请勿使用来自不受信任来源的连接代码,因为它们可能是为了拦截您的数据而创建的。 + 请勿使用来自不受信任来源的连接代码,因为它们可能是为了拦截您的数据而创建的。 - What do you have? - 你用什么方式创建连接? + 你用什么方式创建连接? - File with connection settings or backup - 包含连接配置或备份的文件 + 包含连接配置或备份的文件 + + + + Connection + 连接 + + + + Insert the key, add a configuration file or scan the QR-code + + Insert key + + + + + Insert + 插入 + + + + Continue + 继续 + + + + Other connection options + + + + + VPN by Amnezia + + + + + Connect to classic paid and free VPN services from Amnezia + + + + + Self-hosted VPN + + + + + Configure Amnezia VPN on your own server + + + + + Restore from backup + 从备份还原 + + + + Open backup file + 打开备份文件 + + + + Backup files (*.backup) + + + + File with connection settings 包含连接配置的文件 - + Open config file 打开配置文件 - + QR code 二维码 - + + I have nothing + 我没有 + + Key as text - 授权码文本 + 授权码文本 @@ -2168,12 +2467,12 @@ It's okay as long as it's from someone you trust. 连接服务器 - + Configure your server 配置服务器 - + Server IP address [:port] 服务器IP [:端口] @@ -2186,12 +2485,12 @@ It's okay as long as it's from someone you trust. 密码 或 私钥 - + Continue 继续 - + All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties 您输入的所有数据将严格保密,不会与 Amnezia 或任何第三方共享或披露 @@ -2202,37 +2501,47 @@ and will not be shared or disclosed to the Amnezia or any third parties 不会向 Amnezia 或任何第三方分享或披露 - + 255.255.255.255:22 - + SSH Username SSH 用户名 - + Password or SSH private key 密码或 SSH 私钥 - + + How to run your VPN server + + + + + Where to get connection data, step-by-step instructions for buying a VPS + + + + Ip address cannot be empty IP不能为空 - + Enter the address in the format 255.255.255.255:88 按照这种格式输入 255.255.255.255:88 - + Login cannot be empty 账号不能为空 - + Password/private key cannot be empty 密码或私钥不能为空 @@ -2240,17 +2549,17 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardEasy - + What is the level of internet control in your region? 您所在地区的互联网管控力度如何? - + Choose a VPN protocol 选择 VPN 协议 - + Skip setup 跳过设置 @@ -2263,7 +2572,7 @@ and will not be shared or disclosed to the Amnezia or any third parties 我想选择VPN协议 - + Continue 继续 @@ -2275,28 +2584,28 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardInstalling - - + + Usually it takes no more than 5 minutes 通常不超过5分钟 - + The server has already been added to the application 服务器已添加到应用软件中 - + Amnezia has detected that your server is currently Amnezia 检测到您的服务器当前 - + busy installing other software. Amnezia installation 正安装其他软件。Amnezia安装 - + Cancel installation 取消安装 @@ -2309,12 +2618,12 @@ and will not be shared or disclosed to the Amnezia or any third parties 正安装其他软件。Amnezia安装 - + will pause until the server finishes installing other software 将暂停,直到其他软件安装完成。 - + Installing 安装中 @@ -2322,37 +2631,37 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardProtocolSettings - + Installing %1 正在安装 %1 - + More detailed 更多细节 - + Close 关闭 - + Network protocol 网络协议 - + Port 端口 - + Install 安装 - + The port must be in the range of 1 to 65535 @@ -2360,12 +2669,12 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardProtocols - + VPN protocol VPN 协议 - + Choose the one with the highest priority for you. Later, you can install other protocols and additional services, such as DNS proxy and SFTP. 选择你认为优先级最高的一项。稍后,您可以安装其他协议和附加服务,例如 DNS 代理和 SFTP。 @@ -2373,7 +2682,7 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardQrReader - + Point the camera at the QR code and hold for a couple of seconds. 将相机对准二维码并按住几秒钟 @@ -2381,60 +2690,55 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardStart - Settings restored from backup file - 从备份文件还原配置 + 从备份文件还原配置 - Free service for creating a personal VPN on your server. - 在您的服务器上架设私人免费VPN服务。 + 在您的服务器上架设私人免费VPN服务。 - Helps you access blocked content without revealing your privacy, even to VPN providers. - 帮助您访问受限内容,保护您的隐私,即使是VPN提供商也无法获取。 + 帮助您访问受限内容,保护您的隐私,即使是VPN提供商也无法获取。 - I have the data to connect - 我有连接配置 + 我有连接配置 - I have nothing - 我没有 + 我没有 - - https://amnezia.org/instructions/0_starter-guide - + + Let's get started + PageSetupWizardTextKey - + Connection key 连接授权码 - + A line that starts with vpn://... 以 vpn://... 开始的行 - + Key 授权码 - + Insert 插入 - + Continue 继续 @@ -2442,7 +2746,7 @@ and will not be shared or disclosed to the Amnezia or any third parties PageSetupWizardViewConfig - + New connection 新连接 @@ -2451,27 +2755,27 @@ and will not be shared or disclosed to the Amnezia or any third parties 请勿使用公共来源的连接码。它可以被创建来拦截您的数据。 - + Collapse content 折叠内容 - + Show content 显示内容 - + Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider. - + Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data. 只使用您信任的来源提供的连接代码。公共来源的代码可能是为了拦截您的数据而创建的。 - + Connect 连接 @@ -2479,118 +2783,118 @@ and will not be shared or disclosed to the Amnezia or any third parties PageShare - + Save OpenVPN config 保存OpenVPN配置 - + Save WireGuard config 保存WireGuard配置 - + Save AmneziaWG config 保存 AmneziaWG 配置 - + Save Shadowsocks config 保存 Shadowsocks 配置 - + Save Cloak config 保存斗篷配置 - + Save XRay config - + For the AmneziaVPN app AmneziaVPN 应用 - + OpenVPN native format OpenVPN原生格式 - + WireGuard native format WireGuard原生格式 - + AmneziaWG native format AmneziaWG 本地格式 - + Shadowsocks native format Shadowsocks原生格式 - + Cloak native format Cloak原生格式 - + XRay native format - + Share VPN Access 共享 VPN 访问 - + Share full access to the server and VPN 共享服务器和VPN的完全访问权限 - + Use for your own devices, or share with those you trust to manage the server. 用于您自己的设备,或与您信任的人共享以管理服务器. - - + + Users 用户 - + Share VPN access without the ability to manage the server 共享 VPN 访问,无需管理服务器 - + Search 搜索 - + Creation date: %1 - + Latest handshake: %1 - + Data received: %1 - + Data sent: %1 @@ -2599,42 +2903,42 @@ and will not be shared or disclosed to the Amnezia or any third parties 创建日期: - + Rename 重新命名 - + Client name 客户名称 - + Save 保存 - + Revoke 撤销 - + Revoke the config for a user - %1? 撤销用户的配置- %1? - + The user will no longer be able to connect to your server. 该用户将无法再连接到您的服务器. - + Continue 继续 - + Cancel 取消 @@ -2647,7 +2951,7 @@ and will not be shared or disclosed to the Amnezia or any third parties 访问VPN - + Connection 连接 @@ -2676,8 +2980,8 @@ and will not be shared or disclosed to the Amnezia or any third parties 服务器 - - + + Server 服务器 @@ -2690,7 +2994,7 @@ and will not be shared or disclosed to the Amnezia or any third parties 访问配置文件的内容为: - + File with connection settings to 连接配置文件的内容为: @@ -2699,35 +3003,35 @@ and will not be shared or disclosed to the Amnezia or any third parties 协议 - - + + Protocol 协议 - + Connection to 连接到 - + Config revoked 配置已撤销 - + User name 用户名 - - + + Connection format 连接格式 - - + + Share 共享 @@ -2735,50 +3039,50 @@ and will not be shared or disclosed to the Amnezia or any third parties PageShareFullAccess - + Full access to the server and VPN 对服务器和VPN的完全访问权限 - + We recommend that you use full access to the server only for your own additional devices. 我们建议您仅为自己的附加设备使用服务器的完全访问权限. - + If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. 如果您与其他人共享完全访问权限,他们可以从服务器中删除和添加协议和服务,这将导致VPN对所有用户的工作出现问题。 - + Server 服务器 - + Accessing 访问 - + File with accessing settings to 访问配置文件的内容为 - + Share 共享 - + Connection to 连接到 - + File with connection settings to 连接配置文件的内容为 @@ -2786,15 +3090,20 @@ and will not be shared or disclosed to the Amnezia or any third parties PageStart - + Logging was disabled after 14 days, log files were deleted + + + Settings restored from backup file + 从备份文件还原配置 + PopupType - + Close 关闭 @@ -3222,37 +3531,42 @@ and will not be shared or disclosed to the Amnezia or any third parties - - QFile error: The file could not be opened + + Missing AGW public key - QFile error: An error occurred when reading from the file + QFile error: The file could not be opened - QFile error: The file could not be accessed + QFile error: An error occurred when reading from the file - QFile error: An unspecified error occurred + QFile error: The file could not be accessed - QFile error: A fatal error occurred + QFile error: An unspecified error occurred + QFile error: A fatal error occurred + + + + QFile error: The operation was aborted - + ErrorCode: %1. 错误代码: %1. @@ -3320,7 +3634,7 @@ and will not be shared or disclosed to the Amnezia or any third parties 该配置不包含任何用于连接到服务器的容器和凭据。 - + Internal error @@ -3833,7 +4147,7 @@ While it offers a blend of security, stability, and speed, it's essential t SelectLanguageDrawer - + Choose language 选择语言 @@ -3841,13 +4155,13 @@ While it offers a blend of security, stability, and speed, it's essential t Settings - + Server #1 - - + + Server 服务器 @@ -3872,34 +4186,34 @@ While it offers a blend of security, stability, and speed, it's essential t ShareConnectionDrawer - - + + Save AmneziaVPN config 保存配置 - + Share 共享 - + Copy 拷贝 - - + + Copied 已拷贝 - + Copy config string 复制配置字符串 - + Show connection settings 显示连接配置 @@ -3908,7 +4222,7 @@ While it offers a blend of security, stability, and speed, it's essential t 展示内容 - + To read the QR code in the Amnezia app, select "Add server" → "I have data to connect" → "QR code, key or settings file" 要应用二维码到 Amnezia,请底部工具栏点击“+”→“连接方式”→“二维码、授权码或配置文件” @@ -3992,7 +4306,7 @@ While it offers a blend of security, stability, and speed, it's essential t TextFieldWithHeaderType - + The field can't be empty 输入不能为空 @@ -4051,12 +4365,12 @@ While it offers a blend of security, stability, and speed, it's essential t amnezia::ContainerProps - + Low - + High 中或高 @@ -4065,12 +4379,12 @@ While it offers a blend of security, stability, and speed, it's essential t 极度 - + I just want to increase the level of my privacy. 只是想提高隐私保护级别。 - + I want to bypass censorship. This option recommended in most cases. 想要绕过审查制度。大多数情况下推荐使用此选项。 @@ -4098,12 +4412,12 @@ While it offers a blend of security, stability, and speed, it's essential t main2 - + Private key passphrase 私钥密码 - + Save 保存 diff --git a/client/ui/controllers/connectionController.cpp b/client/ui/controllers/connectionController.cpp index 76c352f4..c7f95000 100644 --- a/client/ui/controllers/connectionController.cpp +++ b/client/ui/controllers/connectionController.cpp @@ -8,6 +8,7 @@ #include #include "core/controllers/vpnConfigurationController.h" +#include "core/enums/apiEnums.h" #include "version.h" ConnectionController::ConnectionController(const QSharedPointer &serversModel, @@ -16,7 +17,6 @@ ConnectionController::ConnectionController(const QSharedPointer &s const QSharedPointer &vpnConnection, const std::shared_ptr &settings, QObject *parent) : QObject(parent), - m_apiController(this), m_serversModel(serversModel), m_containersModel(containersModel), m_clientManagementModel(clientManagementModel), @@ -27,33 +27,39 @@ ConnectionController::ConnectionController(const QSharedPointer &s connect(this, &ConnectionController::connectToVpn, m_vpnConnection.get(), &VpnConnection::connectToVpn, Qt::QueuedConnection); connect(this, &ConnectionController::disconnectFromVpn, m_vpnConnection.get(), &VpnConnection::disconnectFromVpn, Qt::QueuedConnection); - connect(&m_apiController, &ApiController::configUpdated, this, - static_cast(&ConnectionController::openConnection)); - connect(&m_apiController, qOverload(&ApiController::errorOccurred), this, qOverload(&ConnectionController::connectionErrorOccurred)); + connect(this, &ConnectionController::configFromApiUpdated, this, &ConnectionController::continueConnection); m_state = Vpn::ConnectionState::Disconnected; } void ConnectionController::openConnection() { -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true)) - { - emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning); - return; - } -#endif +// #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +// if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true)) +// { +// emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning); +// return; +// } +// #endif int serverIndex = m_serversModel->getDefaultServerIndex(); QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex); + auto configVersion = serverConfig.value(config_key::configVersion).toInt(); emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing); - if (serverConfig.value(config_key::configVersion).toInt() + if (configVersion == ApiConfigSources::Telegram && !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) { - m_apiController.updateServerConfigFromApi(m_settings->getInstallationUuid(true), serverIndex, serverConfig); + emit updateApiConfigFromTelegram(); + } else if (configVersion && m_serversModel->isApiKeyExpired(serverIndex)) { + qDebug() << "attempt to update api config by end_date event"; + if (configVersion == ApiConfigSources::Telegram) { + emit updateApiConfigFromTelegram(); + } else { + emit updateApiConfigFromGateway(); + } } else { - openConnection(false, serverConfig, serverIndex); + continueConnection(); } } @@ -185,12 +191,11 @@ bool ConnectionController::isProtocolConfigExists(const QJsonObject &containerCo return true; } -void ConnectionController::openConnection(const bool updateConfig, const QJsonObject &config, const int serverIndex) +void ConnectionController::continueConnection() { - // Update config for this server as it was received from API - if (updateConfig) { - m_serversModel->editServer(config, serverIndex); - } + int serverIndex = m_serversModel->getDefaultServerIndex(); + QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex); + auto configVersion = serverConfig.value(config_key::configVersion).toInt(); if (!m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) { emit noInstalledContainers(); @@ -223,7 +228,7 @@ void ConnectionController::openConnection(const bool updateConfig, const QJsonOb auto dns = m_serversModel->getDnsPair(serverIndex); - auto vpnConfiguration = vpnConfigurationController.createVpnConfiguration(dns, config, containerConfig, container, errorCode); + auto vpnConfiguration = vpnConfigurationController.createVpnConfiguration(dns, serverConfig, containerConfig, container, errorCode); if (errorCode != ErrorCode::NoError) { emit connectionErrorOccurred(tr("unable to create configuration")); return; diff --git a/client/ui/controllers/connectionController.h b/client/ui/controllers/connectionController.h index bc8f7e2f..25d4d74a 100644 --- a/client/ui/controllers/connectionController.h +++ b/client/ui/controllers/connectionController.h @@ -1,7 +1,6 @@ #ifndef CONNECTIONCONTROLLER_H #define CONNECTIONCONTROLLER_H -#include "core/controllers/apiController.h" #include "protocols/vpnprotocol.h" #include "ui/models/clientManagementModel.h" #include "ui/models/containers_model.h" @@ -58,13 +57,15 @@ signals: void connectButtonClicked(); void preparingConfig(); + void updateApiConfigFromGateway(); + void updateApiConfigFromTelegram(); + void configFromApiUpdated(); + private: Vpn::ConnectionState getCurrentConnectionState(); bool isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container); - void openConnection(const bool updateConfig, const QJsonObject &config, const int serverIndex); - - ApiController m_apiController; + void continueConnection(); QSharedPointer m_serversModel; QSharedPointer m_containersModel; diff --git a/client/ui/controllers/exportController.cpp b/client/ui/controllers/exportController.cpp index a5605674..20c32409 100644 --- a/client/ui/controllers/exportController.cpp +++ b/client/ui/controllers/exportController.cpp @@ -133,7 +133,7 @@ ErrorCode ExportController::generateNativeConfig(const DockerContainer container int serverIndex = m_serversModel->getProcessedServerIndex(); ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); auto dns = m_serversModel->getDnsPair(serverIndex); - bool isApiConfig = qvariant_cast(m_serversModel->data(serverIndex, ServersModel::IsServerFromApiRole)); + bool isApiConfig = qvariant_cast(m_serversModel->data(serverIndex, ServersModel::IsServerFromTelegramApiRole)); QJsonObject containerConfig = m_containersModel->getContainerConfig(container); containerConfig.insert(config_key::container, ContainerProps::containerToString(container)); diff --git a/client/ui/controllers/importController.cpp b/client/ui/controllers/importController.cpp index 60a90e4e..7ffcedd7 100644 --- a/client/ui/controllers/importController.cpp +++ b/client/ui/controllers/importController.cpp @@ -240,9 +240,9 @@ void ImportController::processNativeWireGuardConfig() auto containerConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::WireGuard)).toObject(); auto protocolConfig = QJsonDocument::fromJson(containerConfig.value(config_key::last_config).toString().toUtf8()).object(); - QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(3, 10)); - QString junkPacketMinSize = QString::number(50); - QString junkPacketMaxSize = QString::number(1000); + QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5)); + QString junkPacketMinSize = QString::number(10); + QString junkPacketMaxSize = QString::number(50); protocolConfig[config_key::junkPacketCount] = junkPacketCount; protocolConfig[config_key::junkPacketMinSize] = junkPacketMinSize; protocolConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize; diff --git a/client/ui/controllers/installController.cpp b/client/ui/controllers/installController.cpp index 514091d4..66e04520 100644 --- a/client/ui/controllers/installController.cpp +++ b/client/ui/controllers/installController.cpp @@ -7,6 +7,7 @@ #include #include +#include "core/controllers/apiController.h" #include "core/controllers/serverController.h" #include "core/controllers/vpnConfigurationController.h" #include "core/networkUtilities.h" @@ -15,14 +16,24 @@ #include "ui/models/protocols/wireguardConfigModel.h" #include "utilities.h" -#ifdef Q_OS_IOS - #include -#endif - namespace { Logger logger("ServerController"); + namespace configKey + { + constexpr char serviceInfo[] = "service_info"; + constexpr char serviceType[] = "service_type"; + constexpr char serviceProtocol[] = "service_protocol"; + constexpr char userCountryCode[] = "user_country_code"; + + constexpr char serverCountryCode[] = "server_country_code"; + constexpr char serverCountryName[] = "server_country_name"; + constexpr char availableCountries[] = "available_countries"; + + constexpr char apiConfig[] = "api_config"; + } + #ifdef Q_OS_WINDOWS QString getNextDriverLetter() { @@ -52,12 +63,14 @@ namespace InstallController::InstallController(const QSharedPointer &serversModel, const QSharedPointer &containersModel, const QSharedPointer &protocolsModel, const QSharedPointer &clientManagementModel, - const std::shared_ptr &settings, QObject *parent) + const QSharedPointer &apiServicesModel, const std::shared_ptr &settings, + QObject *parent) : QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel), m_protocolModel(protocolsModel), m_clientManagementModel(clientManagementModel), + m_apiServicesModel(apiServicesModel), m_settings(settings) { } @@ -85,9 +98,9 @@ void InstallController::install(DockerContainer container, int port, TransportPr containerConfig.insert(config_key::transport_proto, ProtocolProps::transportProtoToString(transportProto, protocol)); if (container == DockerContainer::Awg) { - QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(3, 10)); - QString junkPacketMinSize = QString::number(50); - QString junkPacketMaxSize = QString::number(1000); + QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5)); + QString junkPacketMinSize = QString::number(10); + QString junkPacketMaxSize = QString::number(50); int s1 = QRandomGenerator::global()->bounded(15, 150); int s2 = QRandomGenerator::global()->bounded(15, 150); @@ -432,7 +445,7 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia containerConfig.insert(config_key::password, password); } else if (protocol == Proto::Socks5Proxy) { QString proxyConfig = serverController->getTextFileFromContainer(container, credentials, - protocols::socks5Proxy::proxyConfigPath, errorCode); + protocols::socks5Proxy::proxyConfigPath, errorCode); const static QRegularExpression usernameAndPasswordRegExp("users (\\w+):CL:(\\w+)"); QRegularExpressionMatch usernameAndPasswordMatch = usernameAndPasswordRegExp.match(proxyConfig); @@ -591,25 +604,8 @@ void InstallController::removeProcessedContainer() void InstallController::removeApiConfig(const int serverIndex) { - auto serverConfig = m_serversModel->getServerConfig(serverIndex); - -#ifdef Q_OS_IOS - QString vpncName = QString("%1 (%2) %3") - .arg(serverConfig[config_key::description].toString()) - .arg(serverConfig[config_key::hostName].toString()) - .arg(serverConfig[config_key::vpnproto].toString()); - - AmneziaVPN::removeVPNC(vpncName.toStdString()); -#endif - - serverConfig.remove(config_key::dns1); - serverConfig.remove(config_key::dns2); - serverConfig.remove(config_key::containers); - serverConfig.remove(config_key::hostName); - - serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None)); - - m_serversModel->editServer(serverConfig, serverIndex); + m_serversModel->removeApiConfig(serverIndex); + emit apiConfigRemoved(tr("Api config removed")); } void InstallController::clearCachedProfile(QSharedPointer serverController) @@ -801,6 +797,110 @@ void InstallController::addEmptyServer() emit installServerFinished(tr("Server added successfully")); } +bool InstallController::fillAvailableServices() +{ + ApiController apiController(m_settings->getGatewayEndpoint()); + + QByteArray responseBody; + ErrorCode errorCode = apiController.getServicesList(responseBody); + if (errorCode != ErrorCode::NoError) { + emit installationErrorOccurred(errorCode); + return false; + } + + QJsonObject data = QJsonDocument::fromJson(responseBody).object(); + m_apiServicesModel->updateModel(data); + return true; +} + +bool InstallController::installServiceFromApi() +{ + if (m_serversModel->isServerFromApiAlreadyExists(m_apiServicesModel->getCountryCode(), m_apiServicesModel->getSelectedServiceType(), + m_apiServicesModel->getSelectedServiceProtocol())) { + emit installationErrorOccurred(ErrorCode::ApiConfigAlreadyAdded); + return false; + } + + ApiController apiController(m_settings->getGatewayEndpoint()); + QJsonObject serverConfig; + + ErrorCode errorCode = apiController.getConfigForService(m_settings->getInstallationUuid(true), m_apiServicesModel->getCountryCode(), + m_apiServicesModel->getSelectedServiceType(), + m_apiServicesModel->getSelectedServiceProtocol(), "", serverConfig); + if (errorCode != ErrorCode::NoError) { + emit installationErrorOccurred(errorCode); + return false; + } + + auto serviceInfo = m_apiServicesModel->getSelectedServiceInfo(); + QJsonObject apiConfig = serverConfig.value(configKey::apiConfig).toObject(); + apiConfig.insert(configKey::serviceInfo, serviceInfo); + apiConfig.insert(configKey::userCountryCode, m_apiServicesModel->getCountryCode()); + apiConfig.insert(configKey::serviceType, m_apiServicesModel->getSelectedServiceType()); + apiConfig.insert(configKey::serviceProtocol, m_apiServicesModel->getSelectedServiceProtocol()); + + serverConfig.insert(configKey::apiConfig, apiConfig); + + m_serversModel->addServer(serverConfig); + emit installServerFromApiFinished(tr("%1 installed successfully.").arg(m_apiServicesModel->getSelectedServiceName())); + return true; +} + +bool InstallController::updateServiceFromApi(const int serverIndex, const QString &newCountryCode, const QString &newCountryName, + bool reloadServiceConfig) +{ + ApiController apiController(m_settings->getGatewayEndpoint()); + + auto serverConfig = m_serversModel->getServerConfig(serverIndex); + auto apiConfig = serverConfig.value(configKey::apiConfig).toObject(); + + QJsonObject newServerConfig; + ErrorCode errorCode = + apiController.getConfigForService(m_settings->getInstallationUuid(true), apiConfig.value(configKey::userCountryCode).toString(), + apiConfig.value(configKey::serviceType).toString(), + apiConfig.value(configKey::serviceProtocol).toString(), newCountryCode, newServerConfig); + if (errorCode != ErrorCode::NoError) { + emit installationErrorOccurred(errorCode); + return false; + } + + QJsonObject newApiConfig = newServerConfig.value(configKey::apiConfig).toObject(); + newApiConfig.insert(configKey::serviceInfo, apiConfig.value(configKey::serviceInfo)); + newApiConfig.insert(configKey::userCountryCode, apiConfig.value(configKey::userCountryCode)); + newApiConfig.insert(configKey::serviceType, apiConfig.value(configKey::serviceType)); + newApiConfig.insert(configKey::serviceProtocol, apiConfig.value(configKey::serviceProtocol)); + + newServerConfig.insert(configKey::apiConfig, newApiConfig); + m_serversModel->editServer(newServerConfig, serverIndex); + + if (reloadServiceConfig) { + emit reloadServerFromApiFinished(tr("API config reloaded")); + } else if (newCountryName.isEmpty()) { + emit updateServerFromApiFinished(); + } else { + emit changeApiCountryFinished(tr("Successfully changed the country of connection to %1").arg(newCountryName)); + } + return true; +} + +void InstallController::updateServiceFromTelegram(const int serverIndex) +{ + ApiController *apiController = new ApiController(m_settings->getGatewayEndpoint()); + + auto serverConfig = m_serversModel->getServerConfig(serverIndex); + + apiController->updateServerConfigFromApi(m_settings->getInstallationUuid(true), serverIndex, serverConfig); + connect(apiController, &ApiController::finished, this, [this, apiController](const QJsonObject &config, const int serverIndex) { + m_serversModel->editServer(config, serverIndex); + emit updateServerFromApiFinished(); + apiController->deleteLater(); + }); + connect(apiController, &ApiController::errorOccurred, this, [this, apiController](ErrorCode errorCode) { + emit installationErrorOccurred(errorCode); + apiController->deleteLater(); + }); +} + bool InstallController::isUpdateDockerContainerRequired(const DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig) { diff --git a/client/ui/controllers/installController.h b/client/ui/controllers/installController.h index 5e7fd41d..7eea216a 100644 --- a/client/ui/controllers/installController.h +++ b/client/ui/controllers/installController.h @@ -10,6 +10,7 @@ #include "ui/models/containers_model.h" #include "ui/models/protocols_model.h" #include "ui/models/servers_model.h" +#include "ui/models/apiServicesModel.h" class InstallController : public QObject { @@ -18,6 +19,7 @@ public: explicit InstallController(const QSharedPointer &serversModel, const QSharedPointer &containersModel, const QSharedPointer &protocolsModel, const QSharedPointer &clientManagementModel, + const QSharedPointer &apiServicesModel, const std::shared_ptr &settings, QObject *parent = nullptr); ~InstallController(); @@ -50,11 +52,21 @@ public slots: void addEmptyServer(); + bool fillAvailableServices(); + bool installServiceFromApi(); + bool updateServiceFromApi(const int serverIndex, const QString &newCountryCode, const QString &newCountryName, bool reloadServiceConfig = false); + + void updateServiceFromTelegram(const int serverIndex); + signals: void installContainerFinished(const QString &finishMessage, bool isServiceInstall); void installServerFinished(const QString &finishMessage); + void installServerFromApiFinished(const QString &message); void updateContainerFinished(const QString &message); + void updateServerFromApiFinished(); + void changeApiCountryFinished(const QString &message); + void reloadServerFromApiFinished(const QString &message); void scanServerFinished(bool isInstalledContainerFound); @@ -77,6 +89,7 @@ signals: void currentContainerUpdated(); void cachedProfileCleared(const QString &message); + void apiConfigRemoved(const QString &message); private: void installServer(const DockerContainer container, const QMap &installedContainers, @@ -95,6 +108,8 @@ private: QSharedPointer m_containersModel; QSharedPointer m_protocolModel; QSharedPointer m_clientManagementModel; + QSharedPointer m_apiServicesModel; + std::shared_ptr m_settings; ServerCredentials m_processedServerCredentials; diff --git a/client/ui/controllers/pageController.cpp b/client/ui/controllers/pageController.cpp index 3c6583d3..b9561600 100644 --- a/client/ui/controllers/pageController.cpp +++ b/client/ui/controllers/pageController.cpp @@ -46,16 +46,16 @@ PageController::PageController(const QSharedPointer &serversModel, m_isTriggeredByConnectButton = false; } -QString PageController::getInitialPage() +bool PageController::isStartPageVisible() { if (m_serversModel->getServersCount()) { if (m_serversModel->getDefaultServerIndex() < 0) { auto defaultServerIndex = m_serversModel->index(0); m_serversModel->setData(defaultServerIndex, true, ServersModel::Roles::IsDefaultRole); } - return getPagePath(PageLoader::PageEnum::PageStart); + return false; } else { - return getPagePath(PageLoader::PageEnum::PageSetupWizardStart); + return true; } } diff --git a/client/ui/controllers/pageController.h b/client/ui/controllers/pageController.h index c9d655ba..2cc2d983 100644 --- a/client/ui/controllers/pageController.h +++ b/client/ui/controllers/pageController.h @@ -47,6 +47,8 @@ namespace PageLoader PageSetupWizardTextKey, PageSetupWizardViewConfig, PageSetupWizardQrReader, + PageSetupWizardApiServicesList, + PageSetupWizardApiServiceInfo, PageProtocolOpenVpnSettings, PageProtocolShadowSocksSettings, @@ -57,7 +59,9 @@ namespace PageLoader PageProtocolIKev2Settings, PageProtocolRaw, - PageShareFullAccess + PageShareFullAccess, + + PageDevMenu }; Q_ENUM_NS(PageEnum) @@ -75,7 +79,7 @@ public: QObject *parent = nullptr); public slots: - QString getInitialPage(); + bool isStartPageVisible(); QString getPagePath(PageLoader::PageEnum page); void closeWindow(); @@ -110,7 +114,6 @@ signals: void closePage(); void restorePageHomeState(bool isContainerInstalled = false); - void replaceStartPage(); void showErrorMessage(amnezia::ErrorCode); void showErrorMessage(const QString &errorMessage); diff --git a/client/ui/controllers/settingsController.cpp b/client/ui/controllers/settingsController.cpp index aceac551..93fd8971 100644 --- a/client/ui/controllers/settingsController.cpp +++ b/client/ui/controllers/settingsController.cpp @@ -252,3 +252,36 @@ void SettingsController::requestNotificationPermission() AndroidController::instance()->requestNotificationPermission(); #endif } + +QString SettingsController::getInstallationUuid() +{ + return m_settings->getInstallationUuid(false); +} + +void SettingsController::enableDevMode() +{ + m_isDevModeEnabled = true; + emit devModeEnabled(); +} + +bool SettingsController::isDevModeEnabled() +{ + return m_isDevModeEnabled; +} + +void SettingsController::resetGatewayEndpoint() +{ + m_settings->resetGatewayEndpoint(); + emit gatewayEndpointChanged(m_settings->getGatewayEndpoint()); +} + +void SettingsController::setGatewayEndpoint(const QString &endpoint) +{ + m_settings->setGatewayEndpoint(endpoint); + emit gatewayEndpointChanged(endpoint); +} + +QString SettingsController::getGatewayEndpoint() +{ + return m_settings->getGatewayEndpoint(); +} diff --git a/client/ui/controllers/settingsController.h b/client/ui/controllers/settingsController.h index 43ad10e8..a18888a9 100644 --- a/client/ui/controllers/settingsController.h +++ b/client/ui/controllers/settingsController.h @@ -25,6 +25,9 @@ public: Q_PROPERTY(bool isLoggingEnabled READ isLoggingEnabled WRITE toggleLogging NOTIFY loggingStateChanged) Q_PROPERTY(bool isNotificationPermissionGranted READ isNotificationPermissionGranted NOTIFY onNotificationStateChanged) + Q_PROPERTY(bool isDevModeEnabled READ isDevModeEnabled NOTIFY devModeEnabled) + Q_PROPERTY(QString gatewayEndpoint READ getGatewayEndpoint WRITE setGatewayEndpoint NOTIFY gatewayEndpointChanged) + public slots: void toggleAmneziaDns(bool enable); bool isAmneziaDnsEnabled(); @@ -70,6 +73,15 @@ public slots: bool isNotificationPermissionGranted(); void requestNotificationPermission(); + QString getInstallationUuid(); + + void enableDevMode(); + bool isDevModeEnabled(); + + void resetGatewayEndpoint(); + void setGatewayEndpoint(const QString &endpoint); + QString getGatewayEndpoint(); + signals: void primaryDnsChanged(); void secondaryDnsChanged(); @@ -89,6 +101,9 @@ signals: void onNotificationStateChanged(); + void devModeEnabled(); + void gatewayEndpointChanged(const QString &endpoint); + private: QSharedPointer m_serversModel; QSharedPointer m_containersModel; @@ -101,6 +116,8 @@ private: QDateTime m_loggingDisableDate; + bool m_isDevModeEnabled = false; + void checkIfNeedDisableLogs(); }; diff --git a/client/ui/macos_util.h b/client/ui/macos_util.h index 15677e42..ff16390a 100644 --- a/client/ui/macos_util.h +++ b/client/ui/macos_util.h @@ -3,7 +3,7 @@ #ifndef Q_OS_IOS #include -#include +#include void setDockIconVisible(bool visible); void fixWidget(QWidget *widget); diff --git a/client/ui/models/apiCountryModel.cpp b/client/ui/models/apiCountryModel.cpp new file mode 100644 index 00000000..ae58329f --- /dev/null +++ b/client/ui/models/apiCountryModel.cpp @@ -0,0 +1,80 @@ +#include "apiCountryModel.h" + +#include + +#include "logger.h" + +namespace +{ + Logger logger("ApiCountryModel"); + + namespace configKey + { + constexpr char serverCountryCode[] = "server_country_code"; + constexpr char serverCountryName[] = "server_country_name"; + } +} + +ApiCountryModel::ApiCountryModel(QObject *parent) : QAbstractListModel(parent) +{ +} + +int ApiCountryModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_countries.size(); +} + +QVariant ApiCountryModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= static_cast(rowCount())) + return QVariant(); + + QJsonObject countryInfo = m_countries.at(index.row()).toObject(); + + switch (role) { + case CountryCodeRole: { + return countryInfo.value(configKey::serverCountryCode).toString(); + } + case CountryNameRole: { + return countryInfo.value(configKey::serverCountryName).toString(); + } + } + + return QVariant(); +} + +void ApiCountryModel::updateModel(const QJsonArray &data, const QString ¤tCountryCode) +{ + beginResetModel(); + + m_countries = data; + for (int i = 0; i < m_countries.size(); i++) { + if (m_countries.at(i).toObject().value(configKey::serverCountryCode).toString() == currentCountryCode) { + m_currentIndex = i; + emit currentIndexChanged(m_currentIndex); + break; + } + } + + endResetModel(); +} + +int ApiCountryModel::getCurrentIndex() +{ + return m_currentIndex; +} + +void ApiCountryModel::setCurrentIndex(const int i) +{ + m_currentIndex = i; + emit currentIndexChanged(m_currentIndex); +} + +QHash ApiCountryModel::roleNames() const +{ + QHash roles; + roles[CountryNameRole] = "countryName"; + roles[CountryCodeRole] = "countryCode"; + return roles; +} diff --git a/client/ui/models/apiCountryModel.h b/client/ui/models/apiCountryModel.h new file mode 100644 index 00000000..8789158b --- /dev/null +++ b/client/ui/models/apiCountryModel.h @@ -0,0 +1,42 @@ +#ifndef APICOUNTRYMODEL_H +#define APICOUNTRYMODEL_H + +#include +#include + +class ApiCountryModel : public QAbstractListModel +{ + Q_OBJECT + +public: + enum Roles { + CountryNameRole = Qt::UserRole + 1, + CountryCodeRole + }; + + explicit ApiCountryModel(QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + Q_PROPERTY(int currentIndex READ getCurrentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) + +public slots: + void updateModel(const QJsonArray &data, const QString ¤tCountryCode); + + int getCurrentIndex(); + void setCurrentIndex(const int i); + +signals: + void currentIndexChanged(const int index); + +protected: + QHash roleNames() const override; + +private: + QJsonArray m_countries; + int m_currentIndex; +}; + +#endif // APICOUNTRYMODEL_H diff --git a/client/ui/models/apiServicesModel.cpp b/client/ui/models/apiServicesModel.cpp new file mode 100644 index 00000000..3e74d259 --- /dev/null +++ b/client/ui/models/apiServicesModel.cpp @@ -0,0 +1,203 @@ +#include "apiServicesModel.h" + +#include + +#include "logger.h" + +namespace +{ + Logger logger("ApiServicesModel"); + + namespace configKey + { + constexpr char userCountryCode[] = "user_country_code"; + constexpr char services[] = "services"; + constexpr char serviceInfo[] = "service_info"; + constexpr char serviceType[] = "service_type"; + constexpr char serviceProtocol[] = "service_protocol"; + + constexpr char name[] = "name"; + constexpr char price[] = "price"; + constexpr char speed[] = "speed"; + constexpr char timelimit[] = "timelimit"; + constexpr char region[] = "region"; + + constexpr char availableCountries[] = "available_countries"; + + constexpr char storeEndpoint[] = "store_endpoint"; + } + + namespace serviceType + { + constexpr char amneziaFree[] = "amnezia-free"; + constexpr char amneziaPremium[] = "amnezia-premium"; + } +} + +ApiServicesModel::ApiServicesModel(QObject *parent) : QAbstractListModel(parent) +{ +} + +int ApiServicesModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_services.size(); +} + +QVariant ApiServicesModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= static_cast(rowCount())) + return QVariant(); + + QJsonObject service = m_services.at(index.row()).toObject(); + QJsonObject serviceInfo = service.value(configKey::serviceInfo).toObject(); + auto serviceType = service.value(configKey::serviceType).toString(); + + switch (role) { + case NameRole: { + return serviceInfo.value(configKey::name).toString(); + } + case CardDescriptionRole: { + auto speed = serviceInfo.value(configKey::speed).toString(); + if (serviceType == serviceType::amneziaPremium) { + return tr("Classic VPN for comfortable work, downloading large files and watching videos. " + "Works for any sites. Speed up to %1 MBit/s") + .arg(speed); + } else { + return tr("VPN to access blocked sites in regions with high levels of Internet censorship. "); + } + } + case ServiceDescriptionRole: { + if (serviceType == serviceType::amneziaPremium) { + return tr("Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. " + "It works for all websites, even in countries with the highest level of internet censorship."); + } else { + return tr("Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship"); + } + } + case SpeedRole: { + auto speed = serviceInfo.value(configKey::speed).toString(); + return tr("%1 MBit/s").arg(speed); + } + case WorkPeriodRole: { + auto timelimit = serviceInfo.value(configKey::timelimit).toString(); + if (timelimit == "0") { + return ""; + } + return tr("%1 days").arg(timelimit); + } + case RegionRole: { + return serviceInfo.value(configKey::region).toString(); + } + case FeaturesRole: { + if (serviceType == serviceType::amneziaPremium) { + return tr(""); + } else { + return tr("VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. " + "Other sites will be opened from your real IP address, " + "more details on the website."); + } + } + case PriceRole: { + auto price = serviceInfo.value(configKey::price).toString(); + if (price == "free") { + return tr("Free"); + } + return tr("%1 $/month").arg(price); + } + } + + return QVariant(); +} + +void ApiServicesModel::updateModel(const QJsonObject &data) +{ + beginResetModel(); + + m_countryCode = data.value(configKey::userCountryCode).toString(); + m_services = data.value(configKey::services).toArray(); + if (m_services.isEmpty()) { + QJsonObject service; + service.insert(configKey::serviceInfo, data.value(configKey::serviceInfo)); + service.insert(configKey::serviceType, data.value(configKey::serviceType)); + + m_services.push_back(service); + m_selectedServiceIndex = 0; + } + + endResetModel(); +} + +void ApiServicesModel::setServiceIndex(const int index) +{ + m_selectedServiceIndex = index; +} + +QJsonObject ApiServicesModel::getSelectedServiceInfo() +{ + QJsonObject service = m_services.at(m_selectedServiceIndex).toObject(); + return service.value(configKey::serviceInfo).toObject(); +} + +QString ApiServicesModel::getSelectedServiceType() +{ + QJsonObject service = m_services.at(m_selectedServiceIndex).toObject(); + return service.value(configKey::serviceType).toString(); +} + +QString ApiServicesModel::getSelectedServiceProtocol() +{ + QJsonObject service = m_services.at(m_selectedServiceIndex).toObject(); + return service.value(configKey::serviceProtocol).toString(); +} + +QString ApiServicesModel::getSelectedServiceName() +{ + auto modelIndex = index(m_selectedServiceIndex, 0); + return data(modelIndex, ApiServicesModel::Roles::NameRole).toString(); +} + +QJsonArray ApiServicesModel::getSelectedServiceCountries() +{ + QJsonObject service = m_services.at(m_selectedServiceIndex).toObject(); + return service.value(configKey::availableCountries).toArray(); +} + +QString ApiServicesModel::getCountryCode() +{ + return m_countryCode; +} + +QString ApiServicesModel::getStoreEndpoint() +{ + QJsonObject service = m_services.at(m_selectedServiceIndex).toObject(); + return service.value(configKey::storeEndpoint).toString(); +} + +QVariant ApiServicesModel::getSelectedServiceData(const QString roleString) +{ + QModelIndex modelIndex = index(m_selectedServiceIndex); + auto roles = roleNames(); + for (auto it = roles.begin(); it != roles.end(); it++) { + if (QString(it.value()) == roleString) { + return data(modelIndex, it.key()); + } + } + + return {}; +} + +QHash ApiServicesModel::roleNames() const +{ + QHash roles; + roles[NameRole] = "name"; + roles[CardDescriptionRole] = "cardDescription"; + roles[ServiceDescriptionRole] = "serviceDescription"; + roles[SpeedRole] = "speed"; + roles[WorkPeriodRole] = "workPeriod"; + roles[RegionRole] = "region"; + roles[FeaturesRole] = "features"; + roles[PriceRole] = "price"; + + return roles; +} diff --git a/client/ui/models/apiServicesModel.h b/client/ui/models/apiServicesModel.h new file mode 100644 index 00000000..64676be6 --- /dev/null +++ b/client/ui/models/apiServicesModel.h @@ -0,0 +1,56 @@ +#ifndef APISERVICESMODEL_H +#define APISERVICESMODEL_H + +#include +#include + +class ApiServicesModel : public QAbstractListModel +{ + Q_OBJECT + +public: + enum Roles { + NameRole = Qt::UserRole + 1, + CardDescriptionRole, + ServiceDescriptionRole, + SpeedRole, + WorkPeriodRole, + RegionRole, + FeaturesRole, + PriceRole + }; + + explicit ApiServicesModel(QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + +public slots: + void updateModel(const QJsonObject &data); + + void setServiceIndex(const int index); + + QJsonObject getSelectedServiceInfo(); + QString getSelectedServiceType(); + QString getSelectedServiceProtocol(); + QString getSelectedServiceName(); + QJsonArray getSelectedServiceCountries(); + + QString getCountryCode(); + + QString getStoreEndpoint(); + + QVariant getSelectedServiceData(const QString roleString); + +protected: + QHash roleNames() const override; + +private: + QString m_countryCode; + QJsonArray m_services; + + int m_selectedServiceIndex; +}; + +#endif // APISERVICESMODEL_H diff --git a/client/ui/models/containers_model.cpp b/client/ui/models/containers_model.cpp index 734f1e2d..41d26bc7 100644 --- a/client/ui/models/containers_model.cpp +++ b/client/ui/models/containers_model.cpp @@ -94,6 +94,26 @@ bool ContainersModel::isServiceContainer(const int containerIndex) return qvariant_cast(data(index(containerIndex), ServiceTypeRole) == ServiceType::Other); } +bool ContainersModel::hasInstalledServices() +{ + for (const auto &container : m_containers.keys()) { + if (ContainerProps::containerService(container) == ServiceType::Other) { + return true; + } + } + return false; +} + +bool ContainersModel::hasInstalledProtocols() +{ + for (const auto &container : m_containers.keys()) { + if (ContainerProps::containerService(container) == ServiceType::Vpn) { + return true; + } + } + return false; +} + QHash ContainersModel::roleNames() const { QHash roles; diff --git a/client/ui/models/containers_model.h b/client/ui/models/containers_model.h index 2a8117ea..3bd0ddc1 100644 --- a/client/ui/models/containers_model.h +++ b/client/ui/models/containers_model.h @@ -54,6 +54,9 @@ public slots: bool isSupportedByCurrentPlatform(const int containerIndex); bool isServiceContainer(const int containerIndex); + bool hasInstalledServices(); + bool hasInstalledProtocols(); + protected: QHash roleNames() const override; diff --git a/client/ui/models/languageModel.cpp b/client/ui/models/languageModel.cpp index f90b47b7..fe6f7a6c 100644 --- a/client/ui/models/languageModel.cpp +++ b/client/ui/models/languageModel.cpp @@ -103,3 +103,12 @@ QString LanguageModel::getCurrentLanguageName() { return m_availableLanguages[getCurrentLanguageIndex()].name; } + +QString LanguageModel::getCurrentSiteUrl() +{ + auto language = static_cast(getCurrentLanguageIndex()); + switch (language) { + case LanguageSettings::AvailableLanguageEnum::Russian: return "https://storage.googleapis.com/kldscp/amnezia.org"; + default: return "https://amnezia.org"; + } +} diff --git a/client/ui/models/languageModel.h b/client/ui/models/languageModel.h index ea29dda5..2c80880a 100644 --- a/client/ui/models/languageModel.h +++ b/client/ui/models/languageModel.h @@ -59,6 +59,7 @@ public slots: int getCurrentLanguageIndex(); int getLineHeightAppend(); QString getCurrentLanguageName(); + QString getCurrentSiteUrl(); signals: void updateTranslations(const QLocale &locale); diff --git a/client/ui/models/protocols/awgConfigModel.cpp b/client/ui/models/protocols/awgConfigModel.cpp index 6b9234f4..658658df 100644 --- a/client/ui/models/protocols/awgConfigModel.cpp +++ b/client/ui/models/protocols/awgConfigModel.cpp @@ -26,24 +26,12 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in case Roles::JunkPacketCountRole: m_protocolConfig.insert(config_key::junkPacketCount, value.toString()); break; case Roles::JunkPacketMinSizeRole: m_protocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break; case Roles::JunkPacketMaxSizeRole: m_protocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break; - case Roles::InitPacketJunkSizeRole: - m_protocolConfig.insert(config_key::initPacketJunkSize, value.toString()); - break; - case Roles::ResponsePacketJunkSizeRole: - m_protocolConfig.insert(config_key::responsePacketJunkSize, value.toString()); - break; - case Roles::InitPacketMagicHeaderRole: - m_protocolConfig.insert(config_key::initPacketMagicHeader, value.toString()); - break; - case Roles::ResponsePacketMagicHeaderRole: - m_protocolConfig.insert(config_key::responsePacketMagicHeader, value.toString()); - break; - case Roles::UnderloadPacketMagicHeaderRole: - m_protocolConfig.insert(config_key::underloadPacketMagicHeader, value.toString()); - break; - case Roles::TransportPacketMagicHeaderRole: - m_protocolConfig.insert(config_key::transportPacketMagicHeader, value.toString()); - break; + case Roles::InitPacketJunkSizeRole: m_protocolConfig.insert(config_key::initPacketJunkSize, value.toString()); break; + case Roles::ResponsePacketJunkSizeRole: m_protocolConfig.insert(config_key::responsePacketJunkSize, value.toString()); break; + case Roles::InitPacketMagicHeaderRole: m_protocolConfig.insert(config_key::initPacketMagicHeader, value.toString()); break; + case Roles::ResponsePacketMagicHeaderRole: m_protocolConfig.insert(config_key::responsePacketMagicHeader, value.toString()); break; + case Roles::UnderloadPacketMagicHeaderRole: m_protocolConfig.insert(config_key::underloadPacketMagicHeader, value.toString()); break; + case Roles::TransportPacketMagicHeaderRole: m_protocolConfig.insert(config_key::transportPacketMagicHeader, value.toString()); break; } emit dataChanged(index, index, QList { role }); @@ -82,6 +70,8 @@ void AwgConfigModel::updateModel(const QJsonObject &config) QJsonObject protocolConfig = config.value(config_key::awg).toObject(); + auto defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::Awg), Proto::Awg); + m_protocolConfig.insert(config_key::transport_proto, protocolConfig.value(config_key::transport_proto).toString(defaultTransportProto)); m_protocolConfig[config_key::last_config] = protocolConfig.value(config_key::last_config); m_protocolConfig[config_key::port] = protocolConfig.value(config_key::port).toString(protocols::awg::defaultPort); m_protocolConfig[config_key::mtu] = protocolConfig.value(config_key::mtu).toString(protocols::awg::defaultMtu); @@ -98,14 +88,11 @@ void AwgConfigModel::updateModel(const QJsonObject &config) m_protocolConfig[config_key::initPacketMagicHeader] = protocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader); m_protocolConfig[config_key::responsePacketMagicHeader] = - protocolConfig.value(config_key::responsePacketMagicHeader) - .toString(protocols::awg::defaultResponsePacketMagicHeader); + protocolConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader); m_protocolConfig[config_key::underloadPacketMagicHeader] = - protocolConfig.value(config_key::underloadPacketMagicHeader) - .toString(protocols::awg::defaultUnderloadPacketMagicHeader); + protocolConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader); m_protocolConfig[config_key::transportPacketMagicHeader] = - protocolConfig.value(config_key::transportPacketMagicHeader) - .toString(protocols::awg::defaultTransportPacketMagicHeader); + protocolConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader); endResetModel(); } @@ -163,22 +150,17 @@ AwgConfig::AwgConfig(const QJsonObject &jsonConfig) port = jsonConfig.value(config_key::port).toString(protocols::awg::defaultPort); mtu = jsonConfig.value(config_key::mtu).toString(protocols::awg::defaultMtu); junkPacketCount = jsonConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount); - junkPacketMinSize = - jsonConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize); - junkPacketMaxSize = - jsonConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize); - initPacketJunkSize = - jsonConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize); - responsePacketJunkSize = - jsonConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize); - initPacketMagicHeader = - jsonConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader); - responsePacketMagicHeader = jsonConfig.value(config_key::responsePacketMagicHeader) - .toString(protocols::awg::defaultResponsePacketMagicHeader); - underloadPacketMagicHeader = jsonConfig.value(config_key::underloadPacketMagicHeader) - .toString(protocols::awg::defaultUnderloadPacketMagicHeader); - transportPacketMagicHeader = jsonConfig.value(config_key::transportPacketMagicHeader) - .toString(protocols::awg::defaultTransportPacketMagicHeader); + junkPacketMinSize = jsonConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize); + junkPacketMaxSize = jsonConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize); + initPacketJunkSize = jsonConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize); + responsePacketJunkSize = jsonConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize); + initPacketMagicHeader = jsonConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader); + responsePacketMagicHeader = + jsonConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader); + underloadPacketMagicHeader = + jsonConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader); + transportPacketMagicHeader = + jsonConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader); } bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const @@ -186,8 +168,7 @@ bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const if (port != other.port || junkPacketCount != other.junkPacketCount || junkPacketMinSize != other.junkPacketMinSize || junkPacketMaxSize != other.junkPacketMaxSize || initPacketJunkSize != other.initPacketJunkSize || responsePacketJunkSize != other.responsePacketJunkSize || initPacketMagicHeader != other.initPacketMagicHeader - || responsePacketMagicHeader != other.responsePacketMagicHeader - || underloadPacketMagicHeader != other.underloadPacketMagicHeader + || responsePacketMagicHeader != other.responsePacketMagicHeader || underloadPacketMagicHeader != other.underloadPacketMagicHeader || transportPacketMagicHeader != other.transportPacketMagicHeader) { return false; } diff --git a/client/ui/models/protocols/cloakConfigModel.cpp b/client/ui/models/protocols/cloakConfigModel.cpp index 203f08b5..a9f06f4d 100644 --- a/client/ui/models/protocols/cloakConfigModel.cpp +++ b/client/ui/models/protocols/cloakConfigModel.cpp @@ -51,14 +51,11 @@ void CloakConfigModel::updateModel(const QJsonObject &config) m_fullConfig = config; QJsonObject protocolConfig = config.value(config_key::cloak).toObject(); - m_protocolConfig.insert(config_key::cipher, - protocolConfig.value(config_key::cipher).toString(protocols::cloak::defaultCipher)); - - m_protocolConfig.insert(config_key::port, - protocolConfig.value(config_key::port).toString(protocols::cloak::defaultPort)); - - m_protocolConfig.insert(config_key::site, - protocolConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite)); + auto defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::Cloak), Proto::Cloak); + m_protocolConfig.insert(config_key::transport_proto, protocolConfig.value(config_key::transport_proto).toString(defaultTransportProto)); + m_protocolConfig.insert(config_key::cipher, protocolConfig.value(config_key::cipher).toString(protocols::cloak::defaultCipher)); + m_protocolConfig.insert(config_key::port, protocolConfig.value(config_key::port).toString(protocols::cloak::defaultPort)); + m_protocolConfig.insert(config_key::site, protocolConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite)); endResetModel(); } diff --git a/client/ui/models/protocols/ikev2ConfigModel.cpp b/client/ui/models/protocols/ikev2ConfigModel.cpp index a11b6652..05494a07 100644 --- a/client/ui/models/protocols/ikev2ConfigModel.cpp +++ b/client/ui/models/protocols/ikev2ConfigModel.cpp @@ -35,8 +35,7 @@ QVariant Ikev2ConfigModel::data(const QModelIndex &index, int role) const switch (role) { case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort); - case Roles::CipherRole: - return m_protocolConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher); + case Roles::CipherRole: return m_protocolConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher); } return QVariant(); @@ -50,11 +49,8 @@ void Ikev2ConfigModel::updateModel(const QJsonObject &config) m_fullConfig = config; QJsonObject protocolConfig = config.value(config_key::shadowsocks).toObject(); - m_protocolConfig.insert(config_key::cipher, - protocolConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher)); - - m_protocolConfig.insert(config_key::port, - protocolConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort)); + m_protocolConfig.insert(config_key::cipher, protocolConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher)); + m_protocolConfig.insert(config_key::port, protocolConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort)); endResetModel(); } diff --git a/client/ui/models/protocols/openvpnConfigModel.cpp b/client/ui/models/protocols/openvpnConfigModel.cpp index 30d00306..a04c2b1a 100644 --- a/client/ui/models/protocols/openvpnConfigModel.cpp +++ b/client/ui/models/protocols/openvpnConfigModel.cpp @@ -19,9 +19,7 @@ bool OpenVpnConfigModel::setData(const QModelIndex &index, const QVariant &value } switch (role) { - case Roles::SubnetAddressRole: - m_protocolConfig.insert(amnezia::config_key::subnet_address, value.toString()); - break; + case Roles::SubnetAddressRole: m_protocolConfig.insert(amnezia::config_key::subnet_address, value.toString()); break; case Roles::TransportProtoRole: m_protocolConfig.insert(config_key::transport_proto, value.toString()); break; case Roles::PortRole: m_protocolConfig.insert(config_key::port, value.toString()); break; case Roles::AutoNegotiateEncryprionRole: m_protocolConfig.insert(config_key::ncp_disable, !value.toBool()); break; @@ -29,12 +27,8 @@ bool OpenVpnConfigModel::setData(const QModelIndex &index, const QVariant &value case Roles::CipherRole: m_protocolConfig.insert(config_key::cipher, value.toString()); break; case Roles::TlsAuthRole: m_protocolConfig.insert(config_key::tls_auth, value.toBool()); break; case Roles::BlockDnsRole: m_protocolConfig.insert(config_key::block_outside_dns, value.toBool()); break; - case Roles::AdditionalClientCommandsRole: - m_protocolConfig.insert(config_key::additional_client_config, value.toString()); - break; - case Roles::AdditionalServerCommandsRole: - m_protocolConfig.insert(config_key::additional_server_config, value.toString()); - break; + case Roles::AdditionalClientCommandsRole: m_protocolConfig.insert(config_key::additional_client_config, value.toString()); break; + case Roles::AdditionalServerCommandsRole: m_protocolConfig.insert(config_key::additional_server_config, value.toString()); break; } emit dataChanged(index, index, QList { role }); @@ -49,26 +43,21 @@ QVariant OpenVpnConfigModel::data(const QModelIndex &index, int role) const switch (role) { case Roles::SubnetAddressRole: - return m_protocolConfig.value(amnezia::config_key::subnet_address) - .toString(amnezia::protocols::openvpn::defaultSubnetAddress); + return m_protocolConfig.value(amnezia::config_key::subnet_address).toString(amnezia::protocols::openvpn::defaultSubnetAddress); case Roles::TransportProtoRole: return m_protocolConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto); case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString(protocols::openvpn::defaultPort); case Roles::AutoNegotiateEncryprionRole: return !m_protocolConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable); case Roles::HashRole: return m_protocolConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash); - case Roles::CipherRole: - return m_protocolConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher); - case Roles::TlsAuthRole: - return m_protocolConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth); + case Roles::CipherRole: return m_protocolConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher); + case Roles::TlsAuthRole: return m_protocolConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth); case Roles::BlockDnsRole: return m_protocolConfig.value(config_key::block_outside_dns).toBool(protocols::openvpn::defaultBlockOutsideDns); case Roles::AdditionalClientCommandsRole: - return m_protocolConfig.value(config_key::additional_client_config) - .toString(protocols::openvpn::defaultAdditionalClientConfig); + return m_protocolConfig.value(config_key::additional_client_config).toString(protocols::openvpn::defaultAdditionalClientConfig); case Roles::AdditionalServerCommandsRole: - return m_protocolConfig.value(config_key::additional_server_config) - .toString(protocols::openvpn::defaultAdditionalServerConfig); + return m_protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig); case Roles::IsPortEditable: return m_container == DockerContainer::OpenVpn ? true : false; case Roles::IsTransportProtoEditable: return m_container == DockerContainer::OpenVpn ? true : false; case Roles::HasRemoveButton: return m_container == DockerContainer::OpenVpn ? true : false; @@ -84,14 +73,13 @@ void OpenVpnConfigModel::updateModel(const QJsonObject &config) m_fullConfig = config; QJsonObject protocolConfig = config.value(config_key::openvpn).toObject(); - m_protocolConfig.insert(config_key::subnet_address, - protocolConfig.value(amnezia::config_key::subnet_address) - .toString(amnezia::protocols::openvpn::defaultSubnetAddress)); + m_protocolConfig.insert( + config_key::subnet_address, + protocolConfig.value(amnezia::config_key::subnet_address).toString(amnezia::protocols::openvpn::defaultSubnetAddress)); QString transportProto; if (m_container == DockerContainer::OpenVpn) { - transportProto = - protocolConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto); + transportProto = protocolConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto); } else { transportProto = "tcp"; } @@ -100,23 +88,18 @@ void OpenVpnConfigModel::updateModel(const QJsonObject &config) m_protocolConfig.insert(config_key::ncp_disable, protocolConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable)); - m_protocolConfig.insert(config_key::cipher, - protocolConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher)); - m_protocolConfig.insert(config_key::hash, - protocolConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash)); + m_protocolConfig.insert(config_key::cipher, protocolConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher)); + m_protocolConfig.insert(config_key::hash, protocolConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash)); m_protocolConfig.insert(config_key::block_outside_dns, protocolConfig.value(config_key::block_outside_dns).toBool(protocols::openvpn::defaultBlockOutsideDns)); - m_protocolConfig.insert(config_key::port, - protocolConfig.value(config_key::port).toString(protocols::openvpn::defaultPort)); + m_protocolConfig.insert(config_key::port, protocolConfig.value(config_key::port).toString(protocols::openvpn::defaultPort)); + m_protocolConfig.insert(config_key::tls_auth, protocolConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth)); m_protocolConfig.insert( - config_key::tls_auth, - protocolConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth)); - m_protocolConfig.insert(config_key::additional_client_config, - protocolConfig.value(config_key::additional_client_config) - .toString(protocols::openvpn::defaultAdditionalClientConfig)); - m_protocolConfig.insert(config_key::additional_server_config, - protocolConfig.value(config_key::additional_server_config) - .toString(protocols::openvpn::defaultAdditionalServerConfig)); + config_key::additional_client_config, + protocolConfig.value(config_key::additional_client_config).toString(protocols::openvpn::defaultAdditionalClientConfig)); + m_protocolConfig.insert( + config_key::additional_server_config, + protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig)); endResetModel(); } diff --git a/client/ui/models/protocols/shadowsocksConfigModel.cpp b/client/ui/models/protocols/shadowsocksConfigModel.cpp index 2fe2d2a9..769bef20 100644 --- a/client/ui/models/protocols/shadowsocksConfigModel.cpp +++ b/client/ui/models/protocols/shadowsocksConfigModel.cpp @@ -35,8 +35,7 @@ QVariant ShadowSocksConfigModel::data(const QModelIndex &index, int role) const switch (role) { case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort); - case Roles::CipherRole: - return m_protocolConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher); + case Roles::CipherRole: return m_protocolConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher); case Roles::IsPortEditableRole: return m_container == DockerContainer::ShadowSocks ? true : false; case Roles::IsCipherEditableRole: return m_container == DockerContainer::ShadowSocks ? true : false; } @@ -52,11 +51,11 @@ void ShadowSocksConfigModel::updateModel(const QJsonObject &config) m_fullConfig = config; QJsonObject protocolConfig = config.value(config_key::shadowsocks).toObject(); - m_protocolConfig.insert(config_key::cipher, - protocolConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher)); - - m_protocolConfig.insert(config_key::port, - protocolConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort)); + auto defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::ShadowSocks), Proto::ShadowSocks); + m_protocolConfig.insert(config_key::transport_proto, + protocolConfig.value(config_key::transport_proto).toString(defaultTransportProto)); + m_protocolConfig.insert(config_key::cipher, protocolConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher)); + m_protocolConfig.insert(config_key::port, protocolConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort)); endResetModel(); } diff --git a/client/ui/models/protocols/wireguardConfigModel.cpp b/client/ui/models/protocols/wireguardConfigModel.cpp index 8903f40f..65bf2bb3 100644 --- a/client/ui/models/protocols/wireguardConfigModel.cpp +++ b/client/ui/models/protocols/wireguardConfigModel.cpp @@ -51,6 +51,9 @@ void WireGuardConfigModel::updateModel(const QJsonObject &config) m_fullConfig = config; QJsonObject protocolConfig = config.value(config_key::wireguard).toObject(); + auto defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::WireGuard), Proto::WireGuard); + m_protocolConfig.insert(config_key::transport_proto, + protocolConfig.value(config_key::transport_proto).toString(defaultTransportProto)); m_protocolConfig[config_key::last_config] = protocolConfig.value(config_key::last_config); m_protocolConfig[config_key::port] = protocolConfig.value(config_key::port).toString(protocols::wireguard::defaultPort); diff --git a/client/ui/models/protocols/xrayConfigModel.cpp b/client/ui/models/protocols/xrayConfigModel.cpp index d5b50481..84bbb2f7 100644 --- a/client/ui/models/protocols/xrayConfigModel.cpp +++ b/client/ui/models/protocols/xrayConfigModel.cpp @@ -47,8 +47,11 @@ void XrayConfigModel::updateModel(const QJsonObject &config) m_fullConfig = config; QJsonObject protocolConfig = config.value(config_key::xray).toObject(); - m_protocolConfig.insert(config_key::site, - protocolConfig.value(config_key::site).toString(protocols::xray::defaultSite)); + auto defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::Xray), Proto::Xray); + m_protocolConfig.insert(config_key::transport_proto, + protocolConfig.value(config_key::transport_proto).toString(defaultTransportProto)); + m_protocolConfig.insert(config_key::port, protocolConfig.value(config_key::port).toString(protocols::xray::defaultPort)); + m_protocolConfig.insert(config_key::site, protocolConfig.value(config_key::site).toString(protocols::xray::defaultSite)); endResetModel(); } diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp index 3f167029..85e5dae2 100644 --- a/client/ui/models/servers_model.cpp +++ b/client/ui/models/servers_model.cpp @@ -1,8 +1,31 @@ #include "servers_model.h" #include "core/controllers/serverController.h" +#include "core/enums/apiEnums.h" #include "core/networkUtilities.h" +#ifdef Q_OS_IOS + #include +#endif + +namespace +{ + namespace configKey + { + constexpr char apiConfig[] = "api_config"; + constexpr char serviceInfo[] = "service_info"; + constexpr char availableCountries[] = "available_countries"; + constexpr char serverCountryCode[] = "server_country_code"; + constexpr char serverCountryName[] = "server_country_name"; + constexpr char userCountryCode[] = "user_country_code"; + constexpr char serviceType[] = "service_type"; + constexpr char serviceProtocol[] = "service_protocol"; + + constexpr char publicKeyInfo[] = "public_key"; + constexpr char endDate[] = "end_date"; + } +} + ServersModel::ServersModel(std::shared_ptr settings, QObject *parent) : m_settings(settings), QAbstractListModel(parent) { m_isAmneziaDnsEnabled = m_settings->useAmneziaDns(); @@ -63,6 +86,7 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const } const QJsonObject server = m_servers.at(index.row()).toObject(); + const auto apiConfig = server.value(configKey::apiConfig).toObject(); const auto configVersion = server.value(config_key::configVersion).toInt(); switch (role) { case NameRole: { @@ -98,8 +122,23 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const case HasInstalledContainers: { return serverHasInstalledContainers(index.row()); } - case IsServerFromApiRole: { - return server.value(config_key::configVersion).toInt(); + case IsServerFromTelegramApiRole: { + return server.value(config_key::configVersion).toInt() == ApiConfigSources::Telegram; + } + case IsServerFromGatewayApiRole: { + return server.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway; + } + case ApiConfigRole: { + return apiConfig; + } + case IsCountrySelectionAvailableRole: { + return !apiConfig.value(configKey::availableCountries).toArray().isEmpty(); + } + case ApiAvailableCountriesRole: { + return apiConfig.value(configKey::availableCountries).toArray(); + } + case ApiServerCountryCodeRole: { + return apiConfig.value(configKey::serverCountryCode).toString(); } case HasAmneziaDns: { QString primaryDns = server.value(config_key::dns1).toString(); @@ -146,10 +185,13 @@ const QString ServersModel::getDefaultServerName() QString ServersModel::getServerDescription(const QJsonObject &server, const int index) const { const auto configVersion = server.value(config_key::configVersion).toInt(); + const auto apiConfig = server.value(configKey::apiConfig).toObject(); QString description; - if (configVersion) { + if (configVersion && !apiConfig.value(configKey::serverCountryCode).toString().isEmpty()) { + return apiConfig.value(configKey::serverCountryName).toString(); + } else if (configVersion) { return server.value(config_key::description).toString(); } else if (data(index, HasWriteAccessRole).toBool()) { if (m_isAmneziaDnsEnabled && isAmneziaDnsContainerInstalled(index)) { @@ -208,6 +250,12 @@ void ServersModel::setProcessedServerIndex(const int index) { m_processedServerIndex = index; updateContainersModel(); + if (data(index, IsServerFromGatewayApiRole).toBool()) { + if (data(index, IsCountrySelectionAvailableRole).toBool()) { + emit updateApiLanguageModel(); + } + emit updateApiServicesModel(); + } emit processedServerIndexChanged(m_processedServerIndex); } @@ -233,7 +281,8 @@ bool ServersModel::isDefaultServerCurrentlyProcessed() bool ServersModel::isDefaultServerFromApi() { - return qvariant_cast(data(m_defaultServerIndex, IsServerFromApiRole)); + return data(m_defaultServerIndex, IsServerFromTelegramApiRole).toBool() + || data(m_defaultServerIndex, IsServerFromGatewayApiRole).toBool(); } bool ServersModel::isProcessedServerHasWriteAccess() @@ -315,7 +364,12 @@ QHash ServersModel::roleNames() const roles[DefaultContainerRole] = "defaultContainer"; roles[HasInstalledContainers] = "hasInstalledContainers"; - roles[IsServerFromApiRole] = "isServerFromApi"; + roles[IsServerFromTelegramApiRole] = "isServerFromTelegramApi"; + roles[IsServerFromGatewayApiRole] = "isServerFromGatewayApi"; + roles[ApiConfigRole] = "apiConfig"; + roles[IsCountrySelectionAvailableRole] = "isCountrySelectionAvailable"; + roles[ApiAvailableCountriesRole] = "apiAvailableCountries"; + roles[ApiServerCountryCodeRole] = "apiServerCountryCode"; return roles; } @@ -399,8 +453,7 @@ void ServersModel::addContainerConfig(const int containerIndex, const QJsonObjec auto defaultContainer = server.value(config_key::defaultContainer).toString(); if (ContainerProps::containerFromString(defaultContainer) == DockerContainer::None - && ContainerProps::containerService(container) != ServiceType::Other - && ContainerProps::isSupportedByCurrentPlatform(container)) { + && ContainerProps::containerService(container) != ServiceType::Other && ContainerProps::isSupportedByCurrentPlatform(container)) { server.insert(config_key::defaultContainer, ContainerProps::containerToString(container)); } @@ -565,7 +618,7 @@ void ServersModel::toggleAmneziaDns(bool enabled) bool ServersModel::isServerFromApiAlreadyExists(const quint16 crc) { - for (const auto &server : qAsConst(m_servers)) { + for (const auto &server : std::as_const(m_servers)) { if (static_cast(server.toObject().value(config_key::crc).toInt()) == crc) { return true; } @@ -573,6 +626,19 @@ bool ServersModel::isServerFromApiAlreadyExists(const quint16 crc) return false; } +bool ServersModel::isServerFromApiAlreadyExists(const QString &userCountryCode, const QString &serviceType, const QString &serviceProtocol) +{ + for (const auto &server : std::as_const(m_servers)) { + const auto apiConfig = server.toObject().value(configKey::apiConfig).toObject(); + if (apiConfig.value(configKey::userCountryCode).toString() == userCountryCode + && apiConfig.value(configKey::serviceType).toString() == serviceType + && apiConfig.value(configKey::serviceProtocol).toString() == serviceProtocol) { + return true; + } + } + return false; +} + bool ServersModel::serverHasInstalledContainers(const int serverIndex) const { QJsonObject server = m_servers.at(serverIndex).toObject(); @@ -621,14 +687,89 @@ bool ServersModel::isDefaultServerDefaultContainerHasSplitTunneling() auto containers = server.value(config_key::containers).toArray(); for (auto i = 0; i < containers.size(); i++) { auto container = containers.at(i).toObject(); + if (container.value(config_key::container).toString() != ContainerProps::containerToString(defaultContainer)) { + continue; + } if (defaultContainer == DockerContainer::Awg || defaultContainer == DockerContainer::WireGuard) { - auto containerConfig = container.value(ContainerProps::containerTypeToString(defaultContainer)).toObject(); - return !(containerConfig.value(config_key::last_config).toString().contains("AllowedIPs = 0.0.0.0/0, ::/0")); + QJsonObject serverProtocolConfig = container.value(ContainerProps::containerTypeToString(defaultContainer)).toObject(); + QString clientProtocolConfigString = serverProtocolConfig.value(config_key::last_config).toString(); + QJsonObject clientProtocolConfig = QJsonDocument::fromJson(clientProtocolConfigString.toUtf8()).object(); + return (clientProtocolConfigString.contains("AllowedIPs") && !clientProtocolConfigString.contains("AllowedIPs = 0.0.0.0/0, ::/0")) + || (!clientProtocolConfig.value(config_key::allowed_ips).toArray().isEmpty() + && !clientProtocolConfig.value(config_key::allowed_ips).toArray().contains("0.0.0.0/0")); } else if (defaultContainer == DockerContainer::Cloak || defaultContainer == DockerContainer::OpenVpn || defaultContainer == DockerContainer::ShadowSocks) { - auto containerConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::OpenVpn)).toObject(); - return !(containerConfig.value(config_key::last_config).toString().contains("redirect-gateway")); + auto serverProtocolConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::OpenVpn)).toObject(); + QString clientProtocolConfigString = serverProtocolConfig.value(config_key::last_config).toString(); + return !clientProtocolConfigString.isEmpty() && !clientProtocolConfigString.contains("redirect-gateway"); } } return false; } + +bool ServersModel::isServerFromApi(const int serverIndex) +{ + return data(serverIndex, IsServerFromTelegramApiRole).toBool() || data(serverIndex, IsServerFromGatewayApiRole).toBool(); +} + +bool ServersModel::isApiKeyExpired(const int serverIndex) +{ + auto serverConfig = m_servers.at(serverIndex).toObject(); + auto apiConfig = serverConfig.value(configKey::apiConfig).toObject(); + + auto publicKeyInfo = apiConfig.value(configKey::publicKeyInfo).toObject(); + const QString endDate = publicKeyInfo.value(configKey::endDate).toString(); + if (endDate.isEmpty()) { + publicKeyInfo.insert(configKey::endDate, QDateTime::currentDateTimeUtc().addDays(1).toString(Qt::ISODate)); + apiConfig.insert(configKey::publicKeyInfo, publicKeyInfo); + serverConfig.insert(configKey::apiConfig, apiConfig); + editServer(serverConfig, serverIndex); + + return false; + } + + auto endDateDateTime = QDateTime::fromString(endDate, Qt::ISODate).toUTC(); + if (endDateDateTime < QDateTime::currentDateTimeUtc()) { + return true; + } + return false; +} + +void ServersModel::removeApiConfig(const int serverIndex) +{ + auto serverConfig = getServerConfig(serverIndex); + +#ifdef Q_OS_IOS + QString vpncName = QString("%1 (%2) %3") + .arg(serverConfig[config_key::description].toString()) + .arg(serverConfig[config_key::hostName].toString()) + .arg(serverConfig[config_key::vpnproto].toString()); + + AmneziaVPN::removeVPNC(vpncName.toStdString()); +#endif + + serverConfig.remove(config_key::dns1); + serverConfig.remove(config_key::dns2); + serverConfig.remove(config_key::containers); + serverConfig.remove(config_key::hostName); + + auto apiConfig = serverConfig.value(configKey::apiConfig).toObject(); + apiConfig.remove(configKey::publicKeyInfo); + serverConfig.insert(configKey::apiConfig, apiConfig); + + serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None)); + + editServer(serverConfig, serverIndex); +} + +const QString ServersModel::getDefaultServerImagePathCollapsed() +{ + const auto server = m_servers.at(m_defaultServerIndex).toObject(); + const auto apiConfig = server.value(configKey::apiConfig).toObject(); + const auto countryCode = apiConfig.value(configKey::serverCountryCode).toString(); + + if (countryCode.isEmpty()) { + return ""; + } + return QString("qrc:/countriesFlags/images/flagKit/%1.svg").arg(countryCode); +} diff --git a/client/ui/models/servers_model.h b/client/ui/models/servers_model.h index e6b9226b..0f18ea30 100644 --- a/client/ui/models/servers_model.h +++ b/client/ui/models/servers_model.h @@ -3,8 +3,8 @@ #include -#include "settings.h" #include "core/controllers/serverController.h" +#include "settings.h" class ServersModel : public QAbstractListModel { @@ -30,7 +30,13 @@ public: DefaultContainerRole, HasInstalledContainers, - IsServerFromApiRole, + + IsServerFromTelegramApiRole, + IsServerFromGatewayApiRole, + ApiConfigRole, + IsCountrySelectionAvailableRole, + ApiAvailableCountriesRole, + ApiServerCountryCodeRole, HasAmneziaDns }; @@ -49,8 +55,10 @@ public: Q_PROPERTY(QString defaultServerName READ getDefaultServerName NOTIFY defaultServerNameChanged) Q_PROPERTY(QString defaultServerDefaultContainerName READ getDefaultServerDefaultContainerName NOTIFY defaultServerDefaultContainerChanged) Q_PROPERTY(QString defaultServerDescriptionCollapsed READ getDefaultServerDescriptionCollapsed NOTIFY defaultServerDefaultContainerChanged) + Q_PROPERTY(QString defaultServerImagePathCollapsed READ getDefaultServerImagePathCollapsed NOTIFY defaultServerDefaultContainerChanged) Q_PROPERTY(QString defaultServerDescriptionExpanded READ getDefaultServerDescriptionExpanded NOTIFY defaultServerDefaultContainerChanged) - Q_PROPERTY(bool isDefaultServerDefaultContainerHasSplitTunneling READ isDefaultServerDefaultContainerHasSplitTunneling NOTIFY defaultServerDefaultContainerChanged) + Q_PROPERTY(bool isDefaultServerDefaultContainerHasSplitTunneling READ isDefaultServerDefaultContainerHasSplitTunneling NOTIFY + defaultServerDefaultContainerChanged) Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIndexChanged) Q_PROPERTY(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged) @@ -60,6 +68,7 @@ public slots: const int getDefaultServerIndex(); const QString getDefaultServerName(); const QString getDefaultServerDescriptionCollapsed(); + const QString getDefaultServerImagePathCollapsed(); const QString getDefaultServerDescriptionExpanded(); const QString getDefaultServerDefaultContainerName(); bool isDefaultServerCurrentlyProcessed(); @@ -101,6 +110,7 @@ public slots: QPair getDnsPair(const int serverIndex); bool isServerFromApiAlreadyExists(const quint16 crc); + bool isServerFromApiAlreadyExists(const QString &userCountryCode, const QString &serviceType, const QString &serviceProtocol); QVariant getDefaultServerData(const QString roleString); @@ -108,6 +118,10 @@ public slots: bool isDefaultServerDefaultContainerHasSplitTunneling(); + bool isServerFromApi(const int serverIndex); + bool isApiKeyExpired(const int serverIndex); + void removeApiConfig(const int serverIndex); + protected: QHash roleNames() const override; @@ -121,6 +135,9 @@ signals: void defaultServerContainersUpdated(const QJsonArray &containers); void defaultServerDefaultContainerChanged(const int containerIndex); + void updateApiLanguageModel(); + void updateApiServicesModel(); + private: ServerCredentials serverCredentials(int index) const; diff --git a/client/ui/qml/Components/ConnectButton.qml b/client/ui/qml/Components/ConnectButton.qml index dcf8caa3..cb706158 100644 --- a/client/ui/qml/Components/ConnectButton.qml +++ b/client/ui/qml/Components/ConnectButton.qml @@ -11,9 +11,9 @@ import Style 1.0 Button { id: root - property string defaultButtonColor: AmneziaStyle.color.white - property string progressButtonColor: AmneziaStyle.color.white - property string connectedButtonColor: AmneziaStyle.color.orange + property string defaultButtonColor: AmneziaStyle.color.paleGray + property string progressButtonColor: AmneziaStyle.color.paleGray + property string connectedButtonColor: AmneziaStyle.color.goldenApricot implicitWidth: 190 implicitHeight: 190 @@ -50,13 +50,13 @@ Button { verticalOffset: 0 radius: 10 samples: 25 - color: root.activeFocus ? AmneziaStyle.color.white : AmneziaStyle.color.orange + color: root.activeFocus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.goldenApricot source: backgroundCircle } ShapePath { fillColor: AmneziaStyle.color.transparent - strokeColor: AmneziaStyle.color.white + strokeColor: AmneziaStyle.color.paleGray strokeWidth: root.activeFocus ? 1 : 0 capStyle: ShapePath.RoundCap @@ -74,7 +74,7 @@ Button { fillColor: AmneziaStyle.color.transparent strokeColor: { if (ConnectionController.isConnectionInProgress) { - return AmneziaStyle.color.connectionInProgress + return AmneziaStyle.color.darkCharcoal } else if (ConnectionController.isConnected) { return connectedButtonColor } else { @@ -115,7 +115,7 @@ Button { ShapePath { fillColor: AmneziaStyle.color.transparent - strokeColor: AmneziaStyle.color.white + strokeColor: AmneziaStyle.color.paleGray strokeWidth: 3 capStyle: ShapePath.RoundCap diff --git a/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml b/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml index 5a3bf475..405d4eda 100644 --- a/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml +++ b/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml @@ -53,7 +53,7 @@ DrawerType2 { Layout.fillWidth: true Layout.topMargin: 16 - visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi") + visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling text: qsTr("Split tunneling on the server") descriptionText: qsTr("Enabled \nCan't be disabled for current server") @@ -68,7 +68,7 @@ DrawerType2 { } DividerType { - visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi") + visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling } LabelWithButtonType { diff --git a/client/ui/qml/Components/InstalledAppsDrawer.qml b/client/ui/qml/Components/InstalledAppsDrawer.qml index 1024b054..e5d10055 100644 --- a/client/ui/qml/Components/InstalledAppsDrawer.qml +++ b/client/ui/qml/Components/InstalledAppsDrawer.qml @@ -134,7 +134,7 @@ DrawerType2 { anchors.rightMargin: 16 anchors.leftMargin: 16 - backgroundColor: AmneziaStyle.color.greyDark + backgroundColor: AmneziaStyle.color.slateGray textFieldPlaceholderText: qsTr("application name") } diff --git a/client/ui/qml/Components/QuestionDrawer.qml b/client/ui/qml/Components/QuestionDrawer.qml index 1ea1417e..a0e86dbc 100644 --- a/client/ui/qml/Components/QuestionDrawer.qml +++ b/client/ui/qml/Components/QuestionDrawer.qml @@ -89,10 +89,10 @@ DrawerType2 { Layout.leftMargin: 16 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray borderWidth: 1 text: noButtonText diff --git a/client/ui/qml/Components/SelectLanguageDrawer.qml b/client/ui/qml/Components/SelectLanguageDrawer.qml index 38331079..4d9d7f0e 100644 --- a/client/ui/qml/Components/SelectLanguageDrawer.qml +++ b/client/ui/qml/Components/SelectLanguageDrawer.qml @@ -147,8 +147,8 @@ DrawerType2 { indicator: Rectangle { width: parent.width - 1 height: parent.height - color: radioButton.hovered ? AmneziaStyle.color.greyDark : AmneziaStyle.color.blackLight - border.color: radioButton.focus ? AmneziaStyle.color.white : AmneziaStyle.color.transparent + color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack + border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent border.width: radioButton.focus ? 1 : 0 Behavior on color { diff --git a/client/ui/qml/Components/ShareConnectionDrawer.qml b/client/ui/qml/Components/ShareConnectionDrawer.qml index 8bb38893..3235ad0a 100644 --- a/client/ui/qml/Components/ShareConnectionDrawer.qml +++ b/client/ui/qml/Components/ShareConnectionDrawer.qml @@ -113,10 +113,10 @@ DrawerType2 { Layout.topMargin: 8 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray borderWidth: 1 text: qsTr("Copy") @@ -136,10 +136,10 @@ DrawerType2 { visible: false defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray borderWidth: 1 text: qsTr("Copy config string") @@ -155,10 +155,10 @@ DrawerType2 { Layout.topMargin: 24 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray borderWidth: 1 text: qsTr("Show connection settings") @@ -282,9 +282,9 @@ DrawerType2 { readOnly: true activeFocusOnTab: false - color: AmneziaStyle.color.white - selectionColor: AmneziaStyle.color.brown - selectedTextColor: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray font.pixelSize: 16 font.weight: Font.Medium diff --git a/client/ui/qml/Components/TransportProtoSelector.qml b/client/ui/qml/Components/TransportProtoSelector.qml index adb7371f..e40dd4bb 100644 --- a/client/ui/qml/Components/TransportProtoSelector.qml +++ b/client/ui/qml/Components/TransportProtoSelector.qml @@ -16,7 +16,7 @@ Rectangle { implicitWidth: transportProtoButtonGroup.implicitWidth implicitHeight: transportProtoButtonGroup.implicitHeight - color: AmneziaStyle.color.blackLight + color: AmneziaStyle.color.onyxBlack radius: 16 onFocusChanged: { diff --git a/client/ui/qml/Controls2/BackButtonType.qml b/client/ui/qml/Controls2/BackButtonType.qml index ff898e08..86fc86a2 100644 --- a/client/ui/qml/Controls2/BackButtonType.qml +++ b/client/ui/qml/Controls2/BackButtonType.qml @@ -30,7 +30,7 @@ Item { ImageButtonType { id: backButton image: backButtonImage - imageColor: AmneziaStyle.color.white + imageColor: AmneziaStyle.color.paleGray implicitWidth: 40 implicitHeight: 40 diff --git a/client/ui/qml/Controls2/BasicButtonType.qml b/client/ui/qml/Controls2/BasicButtonType.qml index 0b6c4a6f..5c599013 100644 --- a/client/ui/qml/Controls2/BasicButtonType.qml +++ b/client/ui/qml/Controls2/BasicButtonType.qml @@ -10,15 +10,15 @@ import "TextTypes" Button { id: root - property string hoveredColor: AmneziaStyle.color.whiteHovered - property string defaultColor: AmneziaStyle.color.white - property string disabledColor: AmneziaStyle.color.greyDisabled - property string pressedColor: AmneziaStyle.color.grey + property string hoveredColor: AmneziaStyle.color.lightGray + property string defaultColor: AmneziaStyle.color.paleGray + property string disabledColor: AmneziaStyle.color.charcoalGray + property string pressedColor: AmneziaStyle.color.mutedGray - property string textColor: AmneziaStyle.color.black + property string textColor: AmneziaStyle.color.midnightBlack - property string borderColor: AmneziaStyle.color.white - property string borderFocusedColor: AmneziaStyle.color.white + property string borderColor: AmneziaStyle.color.paleGray + property string borderFocusedColor: AmneziaStyle.color.paleGray property int borderWidth: 0 property int borderFocusedWidth: 1 diff --git a/client/ui/qml/Controls2/BusyIndicatorType.qml b/client/ui/qml/Controls2/BusyIndicatorType.qml index 590006ee..55af280f 100644 --- a/client/ui/qml/Controls2/BusyIndicatorType.qml +++ b/client/ui/qml/Controls2/BusyIndicatorType.qml @@ -43,7 +43,7 @@ Popup { ShapePath { fillColor: AmneziaStyle.color.transparent - strokeColor: AmneziaStyle.color.greyDisabled + strokeColor: AmneziaStyle.color.charcoalGray strokeWidth: 3 capStyle: ShapePath.RoundCap diff --git a/client/ui/qml/Controls2/CardType.qml b/client/ui/qml/Controls2/CardType.qml index 1e623853..50f84dbf 100644 --- a/client/ui/qml/Controls2/CardType.qml +++ b/client/ui/qml/Controls2/CardType.qml @@ -11,16 +11,16 @@ RadioButton { property string bodyText property string footerText - property string hoveredColor: AmneziaStyle.color.blackHovered + property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite property string defaultColor: AmneziaStyle.color.transparent property string disabledColor: AmneziaStyle.color.transparent - property string pressedColor: AmneziaStyle.color.blackPressed + property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite property string selectedColor: AmneziaStyle.color.transparent - property string textColor: AmneziaStyle.color.black + property string textColor: AmneziaStyle.color.midnightBlack property string pressedBorderColor: Qt.rgba(251/255, 178/255, 106/255, 0.3) - property string selectedBorderColor: AmneziaStyle.color.orange + property string selectedBorderColor: AmneziaStyle.color.goldenApricot property string defaultBodredColor: AmneziaStyle.color.transparent property int borderWidth: 0 @@ -84,7 +84,7 @@ RadioButton { Text { text: root.headerText wrapMode: Text.WordWrap - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray font.pixelSize: 25 font.weight: 700 font.family: "PT Root UI VF" @@ -99,7 +99,7 @@ RadioButton { Text { text: root.bodyText wrapMode: Text.WordWrap - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray font.pixelSize: 16 font.weight: 400 font.family: "PT Root UI VF" @@ -115,7 +115,7 @@ RadioButton { text: root.footerText wrapMode: Text.WordWrap visible: root.footerText !== "" - color: AmneziaStyle.color.grey + color: AmneziaStyle.color.mutedGray font.pixelSize: 13 font.weight: 400 font.family: "PT Root UI VF" diff --git a/client/ui/qml/Controls2/CardWithIconsType.qml b/client/ui/qml/Controls2/CardWithIconsType.qml new file mode 100644 index 00000000..8630434b --- /dev/null +++ b/client/ui/qml/Controls2/CardWithIconsType.qml @@ -0,0 +1,177 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Button { + id: root + + property string headerText + property string bodyText + property string footerText + + property string hoveredColor: AmneziaStyle.color.slateGray + property string defaultColor: AmneziaStyle.color.onyxBlack + + property string textColor: AmneziaStyle.color.midnightBlack + + property string rightImageSource + property string rightImageColor: AmneziaStyle.color.paleGray + + property string leftImageSource + + property real textOpacity: 1.0 + + hoverEnabled: true + + background: Rectangle { + id: backgroundRect + anchors.fill: parent + radius: 16 + + color: defaultColor + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + + contentItem: Item { + anchors.left: parent.left + anchors.right: parent.right + + implicitHeight: content.implicitHeight + RowLayout { + id: content + anchors.fill: parent + + Image { + id: leftImage + source: leftImageSource + + visible: leftImageSource !== "" + + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 24 + } + + ColumnLayout { + ListItemTitleType { + text: root.headerText + visible: text !== "" + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.topMargin: 16 + Layout.bottomMargin: root.bodyText !== "" ? 0 : 16 + + opacity: root.textOpacity + } + + CaptionTextType { + text: root.bodyText + visible: text !== "" + + color: AmneziaStyle.color.mutedGray + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: root.footerText !== "" ? 0 : 16 + + opacity: root.textOpacity + } + + ButtonTextType { + text: root.footerText + visible: text !== "" + + color: AmneziaStyle.color.mutedGray + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.topMargin: 16 + Layout.bottomMargin: 16 + + opacity: root.textOpacity + } + } + + ImageButtonType { + id: rightImage + + implicitWidth: 40 + implicitHeight: 40 + + hoverEnabled: false + image: rightImageSource + imageColor: rightImageColor + visible: rightImageSource ? true : false + + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.topMargin: 16 + Layout.bottomMargin: 16 + Layout.rightMargin: 16 + + Rectangle { + id: rightImageBackground + anchors.fill: parent + radius: 12 + color: "transparent" + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + onClicked: { + if (clickedFunction && typeof clickedFunction === "function") { + clickedFunction() + } + } + } + } + } + + MouseArea { + anchors.fill: parent + + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + + onEntered: { + backgroundRect.color = root.hoveredColor + + if (rightImageSource) { + rightImageBackground.color = rightImage.hoveredColor + } + root.textOpacity = 0.8 + } + + onExited: { + backgroundRect.color = root.defaultColor + + if (rightImageSource) { + rightImageBackground.color = rightImage.defaultColor + } + root.textOpacity = 1 + } + + onPressedChanged: { + if (rightImageSource) { + rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor + } + root.textOpacity = 0.7 + } + + onClicked: { + root.clicked() + } + } +} diff --git a/client/ui/qml/Controls2/CheckBoxType.qml b/client/ui/qml/Controls2/CheckBoxType.qml index 1816c58c..a26a68f1 100644 --- a/client/ui/qml/Controls2/CheckBoxType.qml +++ b/client/ui/qml/Controls2/CheckBoxType.qml @@ -11,26 +11,26 @@ CheckBox { id: root property string descriptionText - property string descriptionTextColor: AmneziaStyle.color.grey - property string descriptionTextDisabledColor: AmneziaStyle.color.greyDisabled + property string descriptionTextColor: AmneziaStyle.color.mutedGray + property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray - property string textColor: AmneziaStyle.color.white - property string textDisabledColor: AmneziaStyle.color.grey + property string textColor: AmneziaStyle.color.paleGray + property string textDisabledColor: AmneziaStyle.color.mutedGray - property string hoveredColor: AmneziaStyle.color.blackHovered + property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite property string defaultColor: AmneziaStyle.color.transparent - property string pressedColor: AmneziaStyle.color.blackPressed + property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite - property string defaultBorderColor: AmneziaStyle.color.white - property string checkedBorderColor: AmneziaStyle.color.orange - property string checkedBorderDisabledColor: AmneziaStyle.color.brownDark + property string defaultBorderColor: AmneziaStyle.color.paleGray + property string checkedBorderColor: AmneziaStyle.color.goldenApricot + property string checkedBorderDisabledColor: AmneziaStyle.color.deepBrown - property string borderFocusedColor: AmneziaStyle.color.white + property string borderFocusedColor: AmneziaStyle.color.paleGray - property string checkedImageColor: AmneziaStyle.color.orange - property string pressedImageColor: AmneziaStyle.color.orangeDark + property string checkedImageColor: AmneziaStyle.color.goldenApricot + property string pressedImageColor: AmneziaStyle.color.burntOrange property string defaultImageColor: AmneziaStyle.color.transparent - property string checkedDisabledImageColor: AmneziaStyle.color.brownLight + property string checkedDisabledImageColor: AmneziaStyle.color.mutedBrown property string imageSource: "qrc:/images/controls/check.svg" diff --git a/client/ui/qml/Controls2/ContextMenuType.qml b/client/ui/qml/Controls2/ContextMenuType.qml index 867fcb10..fd341e6d 100644 --- a/client/ui/qml/Controls2/ContextMenuType.qml +++ b/client/ui/qml/Controls2/ContextMenuType.qml @@ -20,7 +20,8 @@ Menu { MenuItem { text: qsTr("&Paste") shortcut: StandardKey.Paste - enabled: textObj.canPaste + // Fix calling paste from clipboard when launching app on android + enabled: Qt.platform.os === "android" ? true : textObj.canPaste onTriggered: textObj.paste() } diff --git a/client/ui/qml/Controls2/DividerType.qml b/client/ui/qml/Controls2/DividerType.qml index a6dec6fb..2eb535ec 100644 --- a/client/ui/qml/Controls2/DividerType.qml +++ b/client/ui/qml/Controls2/DividerType.qml @@ -10,5 +10,5 @@ Rectangle { Layout.rightMargin: 16 height: 1 - color: AmneziaStyle.color.greyDark + color: AmneziaStyle.color.slateGray } diff --git a/client/ui/qml/Controls2/DrawerType2.qml b/client/ui/qml/Controls2/DrawerType2.qml index 0611fb12..6647bc88 100644 --- a/client/ui/qml/Controls2/DrawerType2.qml +++ b/client/ui/qml/Controls2/DrawerType2.qml @@ -21,8 +21,8 @@ Item { property Component collapsedContent property Component expandedContent - property string defaultColor: AmneziaStyle.color.blackLight - property string borderColor: AmneziaStyle.color.greyDark + property string defaultColor: AmneziaStyle.color.onyxBlack + property string borderColor: AmneziaStyle.color.slateGray property real expandedHeight property real collapsedHeight: 0 diff --git a/client/ui/qml/Controls2/DropDownType.qml b/client/ui/qml/Controls2/DropDownType.qml index 437c5146..906cfffe 100644 --- a/client/ui/qml/Controls2/DropDownType.qml +++ b/client/ui/qml/Controls2/DropDownType.qml @@ -11,31 +11,31 @@ Item { id: root property string text - property string textColor: AmneziaStyle.color.white - property string textDisabledColor: AmneziaStyle.color.grey + property string textColor: AmneziaStyle.color.paleGray + property string textDisabledColor: AmneziaStyle.color.mutedGray property int textMaximumLineCount: 2 property int textElide: Qt.ElideRight property string descriptionText - property string descriptionTextColor: AmneziaStyle.color.grey - property string descriptionTextDisabledColor: AmneziaStyle.color.greyDisabled + property string descriptionTextColor: AmneziaStyle.color.mutedGray + property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray property string headerText property string headerBackButtonImage property var rootButtonClickedFunction property string rootButtonImage: "qrc:/images/controls/chevron-down.svg" - property string rootButtonImageColor: AmneziaStyle.color.white - property string rootButtonBackgroundColor: AmneziaStyle.color.blackLight - property string rootButtonBackgroundHoveredColor: AmneziaStyle.color.blackLight - property string rootButtonBackgroundPressedColor: AmneziaStyle.color.blackLight + property string rootButtonImageColor: AmneziaStyle.color.paleGray + property string rootButtonBackgroundColor: AmneziaStyle.color.onyxBlack + property string rootButtonBackgroundHoveredColor: AmneziaStyle.color.onyxBlack + property string rootButtonBackgroundPressedColor: AmneziaStyle.color.onyxBlack - property string borderFocusedColor: AmneziaStyle.color.white + property string borderFocusedColor: AmneziaStyle.color.paleGray property int borderFocusedWidth: 1 - property string rootButtonHoveredBorderColor: AmneziaStyle.color.greyDisabled - property string rootButtonDefaultBorderColor: AmneziaStyle.color.greyDark - property string rootButtonPressedBorderColor: AmneziaStyle.color.white + property string rootButtonHoveredBorderColor: AmneziaStyle.color.charcoalGray + property string rootButtonDefaultBorderColor: AmneziaStyle.color.slateGray + property string rootButtonPressedBorderColor: AmneziaStyle.color.paleGray property int rootButtonTextLeftMargins: 16 property int rootButtonTextTopMargin: 16 diff --git a/client/ui/qml/Controls2/Header2Type.qml b/client/ui/qml/Controls2/Header2Type.qml index 4c8cb79b..c435cbe2 100644 --- a/client/ui/qml/Controls2/Header2Type.qml +++ b/client/ui/qml/Controls2/Header2Type.qml @@ -39,7 +39,7 @@ Item { implicitHeight: 40 image: root.actionButtonImage - imageColor: AmneziaStyle.color.white + imageColor: AmneziaStyle.color.paleGray visible: image ? true : false @@ -59,7 +59,7 @@ Item { text: root.descriptionText - color: AmneziaStyle.color.grey + color: AmneziaStyle.color.mutedGray visible: root.descriptionText !== "" } diff --git a/client/ui/qml/Controls2/HeaderType.qml b/client/ui/qml/Controls2/HeaderType.qml index 60cb5b8a..f1cafbff 100644 --- a/client/ui/qml/Controls2/HeaderType.qml +++ b/client/ui/qml/Controls2/HeaderType.qml @@ -48,7 +48,7 @@ Item { Layout.alignment: Qt.AlignRight image: root.actionButtonImage - imageColor: AmneziaStyle.color.white + imageColor: AmneziaStyle.color.paleGray visible: image ? true : false @@ -68,7 +68,7 @@ Item { text: root.descriptionText - color: AmneziaStyle.color.grey + color: AmneziaStyle.color.mutedGray visible: root.descriptionText !== "" } diff --git a/client/ui/qml/Controls2/HorizontalRadioButton.qml b/client/ui/qml/Controls2/HorizontalRadioButton.qml index addda1ab..1ac1cd30 100644 --- a/client/ui/qml/Controls2/HorizontalRadioButton.qml +++ b/client/ui/qml/Controls2/HorizontalRadioButton.qml @@ -9,19 +9,19 @@ import "TextTypes" RadioButton { id: root - property string hoveredColor: AmneziaStyle.color.blackHovered + property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite property string defaultColor: AmneziaStyle.color.transparent property string checkedColor: AmneziaStyle.color.transparent property string disabledColor: AmneziaStyle.color.transparent - property string textColor: AmneziaStyle.color.white - property string textDisabledColor: AmneziaStyle.color.grey + property string textColor: AmneziaStyle.color.paleGray + property string textDisabledColor: AmneziaStyle.color.mutedGray - property string pressedBorderColor: AmneziaStyle.color.greyDisabled - property string checkedBorderColor: AmneziaStyle.color.orange + property string pressedBorderColor: AmneziaStyle.color.charcoalGray + property string checkedBorderColor: AmneziaStyle.color.goldenApricot property string defaultBodredColor: AmneziaStyle.color.transparent - property string checkedDisabledBorderColor: AmneziaStyle.color.brownLight - property string borderFocusedColor: AmneziaStyle.color.white + property string checkedDisabledBorderColor: AmneziaStyle.color.mutedBrown + property string borderFocusedColor: AmneziaStyle.color.paleGray property int borderWidth: 0 implicitWidth: content.implicitWidth diff --git a/client/ui/qml/Controls2/ImageButtonType.qml b/client/ui/qml/Controls2/ImageButtonType.qml index 7a47050c..fffb6d84 100644 --- a/client/ui/qml/Controls2/ImageButtonType.qml +++ b/client/ui/qml/Controls2/ImageButtonType.qml @@ -9,18 +9,18 @@ Button { property string image - property string hoveredColor: AmneziaStyle.color.blackHovered + property string hoveredColor: AmneziaStyle.color.translucentWhite property string defaultColor: AmneziaStyle.color.transparent - property string pressedColor: AmneziaStyle.color.blackPressed - property string disableColor: AmneziaStyle.color.greyDark + property string pressedColor: AmneziaStyle.color.sheerWhite + property string disableColor: AmneziaStyle.color.slateGray - property string imageColor: AmneziaStyle.color.grey - property string disableImageColor: AmneziaStyle.color.greyDark + property string imageColor: AmneziaStyle.color.mutedGray + property string disableImageColor: AmneziaStyle.color.slateGray property alias backgroundColor: background.color property alias backgroundRadius: background.radius - property string borderFocusedColor: AmneziaStyle.color.white + property string borderFocusedColor: AmneziaStyle.color.paleGray property int borderFocusedWidth: 1 hoverEnabled: true diff --git a/client/ui/qml/Controls2/LabelWithButtonType.qml b/client/ui/qml/Controls2/LabelWithButtonType.qml index 9a55e521..3b1609f7 100644 --- a/client/ui/qml/Controls2/LabelWithButtonType.qml +++ b/client/ui/qml/Controls2/LabelWithButtonType.qml @@ -26,16 +26,16 @@ Item { property alias eyeButton: eyeImage property FlickableType parentFlickable - property string textColor: AmneziaStyle.color.white - property string textDisabledColor: AmneziaStyle.color.grey - property string descriptionColor: AmneziaStyle.color.grey - property string descriptionDisabledColor: AmneziaStyle.color.greyDisabled + property string textColor: AmneziaStyle.color.paleGray + property string textDisabledColor: AmneziaStyle.color.mutedGray + property string descriptionColor: AmneziaStyle.color.mutedGray + property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray property real textOpacity: 1.0 - property string borderFocusedColor: AmneziaStyle.color.white + property string borderFocusedColor: AmneziaStyle.color.paleGray property int borderFocusedWidth: 1 - property string rightImageColor: AmneziaStyle.color.white + property string rightImageColor: AmneziaStyle.color.paleGray property bool descriptionOnTop: false property bool hideDescription: true diff --git a/client/ui/qml/Controls2/LabelWithImageType.qml b/client/ui/qml/Controls2/LabelWithImageType.qml new file mode 100644 index 00000000..57d60d8f --- /dev/null +++ b/client/ui/qml/Controls2/LabelWithImageType.qml @@ -0,0 +1,38 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +RowLayout { + property string imageSource + property string leftText + property var rightText + property bool isRightTextUndefined: rightText === undefined + + visible: !isRightTextUndefined + + Image { + Layout.preferredHeight: 18 + Layout.preferredWidth: 18 + source: imageSource + } + + ListItemTitleType { + Layout.fillWidth: true + Layout.rightMargin: 10 + Layout.alignment: Qt.AlignRight + + text: leftText + } + + ParagraphTextType { + visible: rightText !== "" + + Layout.alignment: Qt.AlignLeft + + text: isRightTextUndefined ? "" : rightText + } +} diff --git a/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml b/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml index 67118913..f7b777a7 100644 --- a/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml +++ b/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml @@ -105,8 +105,8 @@ ListView { indicator: Rectangle { width: parent.width - 1 height: parent.height - color: radioButton.hovered ? AmneziaStyle.color.greyDark : AmneziaStyle.color.blackLight - border.color: radioButton.focus ? AmneziaStyle.color.white : AmneziaStyle.color.transparent + color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack + border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent border.width: radioButton.focus ? 1 : 0 Behavior on color { diff --git a/client/ui/qml/Controls2/PopupType.qml b/client/ui/qml/Controls2/PopupType.qml index 0a6e6914..bd4aa4fb 100644 --- a/client/ui/qml/Controls2/PopupType.qml +++ b/client/ui/qml/Controls2/PopupType.qml @@ -84,11 +84,11 @@ Popup { implicitHeight: 32 defaultColor: "white" - hoveredColor: AmneziaStyle.color.whiteHovered - pressedColor: AmneziaStyle.color.whiteHovered - disabledColor: AmneziaStyle.color.greyDisabled + hoveredColor: AmneziaStyle.color.lightGray + pressedColor: AmneziaStyle.color.lightGray + disabledColor: AmneziaStyle.color.charcoalGray - textColor: AmneziaStyle.color.black + textColor: AmneziaStyle.color.midnightBlack borderWidth: 0 text: qsTr("Close") diff --git a/client/ui/qml/Controls2/ProgressBarType.qml b/client/ui/qml/Controls2/ProgressBarType.qml index 0ae63dc3..83e49771 100644 --- a/client/ui/qml/Controls2/ProgressBarType.qml +++ b/client/ui/qml/Controls2/ProgressBarType.qml @@ -10,14 +10,14 @@ ProgressBar { implicitHeight: 4 background: Rectangle { - color: AmneziaStyle.color.brown + color: AmneziaStyle.color.richBrown } contentItem: Item { Rectangle { width: root.visualPosition * parent.width height: parent.height - color: AmneziaStyle.color.orange + color: AmneziaStyle.color.goldenApricot } } } diff --git a/client/ui/qml/Controls2/SwitcherType.qml b/client/ui/qml/Controls2/SwitcherType.qml index 6bf430de..9b2885ea 100644 --- a/client/ui/qml/Controls2/SwitcherType.qml +++ b/client/ui/qml/Controls2/SwitcherType.qml @@ -10,29 +10,29 @@ Switch { id: root property alias descriptionText: description.text - property string descriptionTextColor: AmneziaStyle.color.grey - property string descriptionTextDisabledColor: AmneziaStyle.color.greyDisabled + property string descriptionTextColor: AmneziaStyle.color.mutedGray + property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray - property string textColor: AmneziaStyle.color.white - property string textDisabledColor: AmneziaStyle.color.grey + property string textColor: AmneziaStyle.color.paleGray + property string textDisabledColor: AmneziaStyle.color.mutedGray - property string checkedIndicatorColor: AmneziaStyle.color.brown + property string checkedIndicatorColor: AmneziaStyle.color.richBrown property string defaultIndicatorColor: AmneziaStyle.color.transparent - property string checkedDisabledIndicatorColor: AmneziaStyle.color.brownDark + property string checkedDisabledIndicatorColor: AmneziaStyle.color.deepBrown - property string borderFocusedColor: AmneziaStyle.color.white + property string borderFocusedColor: AmneziaStyle.color.paleGray property int borderFocusedWidth: 1 - property string checkedIndicatorBorderColor: AmneziaStyle.color.brown - property string defaultIndicatorBorderColor: AmneziaStyle.color.greyDisabled - property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.brownDark + property string checkedIndicatorBorderColor: AmneziaStyle.color.richBrown + property string defaultIndicatorBorderColor: AmneziaStyle.color.charcoalGray + property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.deepBrown - property string checkedInnerCircleColor: AmneziaStyle.color.orange - property string defaultInnerCircleColor: AmneziaStyle.color.white - property string checkedDisabledInnerCircleColor: AmneziaStyle.color.brownLight - property string defaultDisabledInnerCircleColor: AmneziaStyle.color.greyDisabled + property string checkedInnerCircleColor: AmneziaStyle.color.goldenApricot + property string defaultInnerCircleColor: AmneziaStyle.color.paleGray + property string checkedDisabledInnerCircleColor: AmneziaStyle.color.mutedBrown + property string defaultDisabledInnerCircleColor: AmneziaStyle.color.charcoalGray - property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.blackHovered + property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent hoverEnabled: enabled ? true : false diff --git a/client/ui/qml/Controls2/TabButtonType.qml b/client/ui/qml/Controls2/TabButtonType.qml index 5f34aaf4..d57ff3a0 100644 --- a/client/ui/qml/Controls2/TabButtonType.qml +++ b/client/ui/qml/Controls2/TabButtonType.qml @@ -6,13 +6,13 @@ import Style 1.0 TabButton { id: root - property string hoveredColor: AmneziaStyle.color.brown - property string defaultColor: AmneziaStyle.color.greyDark - property string selectedColor: AmneziaStyle.color.orange + property string hoveredColor: AmneziaStyle.color.richBrown + property string defaultColor: AmneziaStyle.color.slateGray + property string selectedColor: AmneziaStyle.color.goldenApricot - property string textColor: AmneziaStyle.color.white + property string textColor: AmneziaStyle.color.paleGray - property string borderFocusedColor: AmneziaStyle.color.white + property string borderFocusedColor: AmneziaStyle.color.paleGray property int borderFocusedWidth: 1 property bool isSelected: false diff --git a/client/ui/qml/Controls2/TabImageButtonType.qml b/client/ui/qml/Controls2/TabImageButtonType.qml index 4484f8e4..abe544aa 100644 --- a/client/ui/qml/Controls2/TabImageButtonType.qml +++ b/client/ui/qml/Controls2/TabImageButtonType.qml @@ -6,15 +6,15 @@ import Style 1.0 TabButton { id: root - property string hoveredColor: AmneziaStyle.color.brown - property string defaultColor: AmneziaStyle.color.white - property string selectedColor: AmneziaStyle.color.orange + property string hoveredColor: AmneziaStyle.color.richBrown + property string defaultColor: AmneziaStyle.color.paleGray + property string selectedColor: AmneziaStyle.color.goldenApricot property string image property bool isSelected: false - property string borderFocusedColor: AmneziaStyle.color.white + property string borderFocusedColor: AmneziaStyle.color.paleGray property int borderFocusedWidth: 1 property var clickedFunc diff --git a/client/ui/qml/Controls2/TextAreaType.qml b/client/ui/qml/Controls2/TextAreaType.qml index db84ba61..9359fa16 100644 --- a/client/ui/qml/Controls2/TextAreaType.qml +++ b/client/ui/qml/Controls2/TextAreaType.qml @@ -11,12 +11,12 @@ Rectangle { property alias textArea: textArea property alias textAreaText: textArea.text - property string borderHoveredColor: AmneziaStyle.color.greyDisabled - property string borderNormalColor: AmneziaStyle.color.greyDark - property string borderFocusedColor: AmneziaStyle.color.white + property string borderHoveredColor: AmneziaStyle.color.charcoalGray + property string borderNormalColor: AmneziaStyle.color.slateGray + property string borderFocusedColor: AmneziaStyle.color.paleGray height: 148 - color: AmneziaStyle.color.blackLight + color: AmneziaStyle.color.onyxBlack border.width: 1 border.color: getBorderColor(borderNormalColor) radius: 16 @@ -54,10 +54,10 @@ Rectangle { anchors.topMargin: 16 anchors.bottomMargin: 16 - color: AmneziaStyle.color.white - selectionColor: AmneziaStyle.color.brown - selectedTextColor: AmneziaStyle.color.white - placeholderTextColor: AmneziaStyle.color.grey + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray + placeholderTextColor: AmneziaStyle.color.mutedGray font.pixelSize: 16 font.weight: Font.Medium diff --git a/client/ui/qml/Controls2/TextAreaWithFooterType.qml b/client/ui/qml/Controls2/TextAreaWithFooterType.qml new file mode 100644 index 00000000..102929e2 --- /dev/null +++ b/client/ui/qml/Controls2/TextAreaWithFooterType.qml @@ -0,0 +1,183 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Rectangle { + id: root + + property string placeholderText + property string text + property string headerText + property alias textArea: textArea + property alias textAreaText: textArea.text + + property string borderHoveredColor: AmneziaStyle.color.charcoalGray + property string borderNormalColor: AmneziaStyle.color.slateGray + property string borderFocusedColor: AmneziaStyle.color.paleGray + + property string firstButtonImage + property string secondButtonImage + + property var firstButtonClickedFunc + property var secondButtonClickedFunc + + height: 148 + color: AmneziaStyle.color.onyxBlack + border.width: 1 + border.color: getBorderColor(borderNormalColor) + radius: 16 + + property FlickableType parentFlickable: null + onFocusChanged: { + if (root.activeFocus) { + if (root.parentFlickable) { + root.parentFlickable.ensureVisible(root) + } + } + } + + MouseArea { + id: parentMouse + anchors.fill: parent + cursorShape: Qt.IBeamCursor + onClicked: textArea.forceActiveFocus() + hoverEnabled: true + + ColumnLayout { + anchors.fill: parent + anchors.margins: 16 + spacing: 0 + + LabelTextType { + Layout.fillWidth: true + text: root.headerText + } + + TextArea { + id: textArea + + Layout.fillWidth: true + Layout.fillHeight: true + + leftPadding: 0 + Layout.bottomMargin: 16 + + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray + placeholderTextColor: AmneziaStyle.color.mutedGray + + font.pixelSize: 16 + font.weight: Font.Medium + font.family: "PT Root UI VF" + + placeholderText: root.placeholderText + text: root.text + + + KeyNavigation.tab: firstButton + + onCursorVisibleChanged: { + if (textArea.cursorVisible) { + fl.interactive = true + } else { + fl.interactive = false + } + } + + wrapMode: Text.Wrap + + MouseArea { + id: textAreaMouse + anchors.fill: parent + acceptedButtons: Qt.RightButton + hoverEnabled: true + onClicked: { + fl.interactive = true + contextMenu.open() + } + } + + onFocusChanged: { + root.border.color = getBorderColor(borderNormalColor) + } + + ContextMenuType { + id: contextMenu + textObj: textArea + } + } + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: -8 + spacing: 0 + ImageButtonType { + id: firstButton + visible: root.firstButtonImage !== "" + + imageColor: AmneziaStyle.color.paleGray + + image: root.firstButtonImage + onClicked: function() { + if (root.firstButtonClickedFunc && typeof root.firstButtonClickedFunc === "function") { + root.firstButtonClickedFunc() + } + } + } + + ImageButtonType { + id: secondButton + visible: root.secondButtonImage !== "" + + imageColor: AmneziaStyle.color.paleGray + + image: root.secondButtonImage + onClicked: function() { + if (root.secondButtonClickedFunc && typeof root.secondButtonClickedFunc === "function") { + root.secondButtonClickedFunc() + } + } + } + + Item { + Layout.fillWidth: true + } + + ImageButtonType { + id: resetButton + imageColor: AmneziaStyle.color.paleGray + + visible: root.textAreaText !== "" + image: "qrc:/images/controls/close.svg" + + onClicked: function() { + root.textAreaText = "" + textArea.focus = true + } + } + } + } + + onPressed: { + root.border.color = getBorderColor(borderFocusedColor) + } + + onExited: { + root.border.color = getBorderColor(borderNormalColor) + } + + onEntered: { + root.border.color = getBorderColor(borderHoveredColor) + } + } + + + function getBorderColor(noneFocusedColor) { + return textArea.focus ? root.borderFocusedColor : noneFocusedColor + } +} diff --git a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml index 7ab8f9e3..4ec0976b 100644 --- a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml +++ b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml @@ -10,8 +10,8 @@ Item { id: root property string headerText - property string headerTextDisabledColor: AmneziaStyle.color.greyDisabled - property string headerTextColor: AmneziaStyle.color.grey + property string headerTextDisabledColor: AmneziaStyle.color.charcoalGray + property string headerTextColor: AmneziaStyle.color.mutedGray property alias errorText: errorField.text property bool checkEmptyText: false @@ -23,18 +23,18 @@ Item { property alias textField: textField property alias textFieldText: textField.text - property string textFieldTextColor: AmneziaStyle.color.white - property string textFieldTextDisabledColor: AmneziaStyle.color.grey + property string textFieldTextColor: AmneziaStyle.color.paleGray + property string textFieldTextDisabledColor: AmneziaStyle.color.mutedGray property string textFieldPlaceholderText property bool textFieldEditable: true - property string borderColor: AmneziaStyle.color.greyDark - property string borderFocusedColor: AmneziaStyle.color.white + property string borderColor: AmneziaStyle.color.slateGray + property string borderFocusedColor: AmneziaStyle.color.paleGray - property string backgroundColor: AmneziaStyle.color.blackLight + property string backgroundColor: AmneziaStyle.color.onyxBlack property string backgroundDisabledColor: AmneziaStyle.color.transparent - property string bgBorderHoveredColor: AmneziaStyle.color.greyDisabled + property string bgBorderHoveredColor: AmneziaStyle.color.charcoalGray implicitWidth: content.implicitWidth implicitHeight: content.implicitHeight @@ -92,10 +92,10 @@ Item { inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText placeholderText: root.textFieldPlaceholderText - placeholderTextColor: AmneziaStyle.color.greyDisabled + placeholderTextColor: AmneziaStyle.color.charcoalGray - selectionColor: AmneziaStyle.color.brown - selectedTextColor: AmneziaStyle.color.white + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray font.pixelSize: 16 font.weight: 400 @@ -149,7 +149,9 @@ Item { text: root.errorText visible: root.errorText !== "" - color: AmneziaStyle.color.red + color: AmneziaStyle.color.vibrantRed + + Layout.fillWidth: true } } diff --git a/client/ui/qml/Controls2/TextTypes/ButtonTextType.qml b/client/ui/qml/Controls2/TextTypes/ButtonTextType.qml index 0bf5b203..28056758 100644 --- a/client/ui/qml/Controls2/TextTypes/ButtonTextType.qml +++ b/client/ui/qml/Controls2/TextTypes/ButtonTextType.qml @@ -6,7 +6,7 @@ Text { lineHeight: 24 lineHeightMode: Text.FixedHeight - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray font.pixelSize: 16 font.weight: 600 font.family: "PT Root UI VF" diff --git a/client/ui/qml/Controls2/TextTypes/CaptionTextType.qml b/client/ui/qml/Controls2/TextTypes/CaptionTextType.qml index 4b480154..ba511289 100644 --- a/client/ui/qml/Controls2/TextTypes/CaptionTextType.qml +++ b/client/ui/qml/Controls2/TextTypes/CaptionTextType.qml @@ -6,7 +6,7 @@ Text { lineHeight: 16 + LanguageModel.getLineHeightAppend() lineHeightMode: Text.FixedHeight - color: AmneziaStyle.color.black + color: AmneziaStyle.color.midnightBlack font.pixelSize: 13 font.weight: 400 font.family: "PT Root UI VF" diff --git a/client/ui/qml/Controls2/TextTypes/Header1TextType.qml b/client/ui/qml/Controls2/TextTypes/Header1TextType.qml index fa4aaa4e..40a0b35e 100644 --- a/client/ui/qml/Controls2/TextTypes/Header1TextType.qml +++ b/client/ui/qml/Controls2/TextTypes/Header1TextType.qml @@ -6,7 +6,7 @@ Text { lineHeight: 38 + LanguageModel.getLineHeightAppend() lineHeightMode: Text.FixedHeight - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray font.pixelSize: 32 font.weight: 700 font.family: "PT Root UI VF" diff --git a/client/ui/qml/Controls2/TextTypes/Header2TextType.qml b/client/ui/qml/Controls2/TextTypes/Header2TextType.qml index e456c117..74412cfd 100644 --- a/client/ui/qml/Controls2/TextTypes/Header2TextType.qml +++ b/client/ui/qml/Controls2/TextTypes/Header2TextType.qml @@ -6,7 +6,7 @@ Text { lineHeight: 30 + LanguageModel.getLineHeightAppend() lineHeightMode: Text.FixedHeight - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray font.pixelSize: 25 font.weight: 700 font.family: "PT Root UI VF" diff --git a/client/ui/qml/Controls2/TextTypes/LabelTextType.qml b/client/ui/qml/Controls2/TextTypes/LabelTextType.qml index edad6ef9..9a9a1963 100644 --- a/client/ui/qml/Controls2/TextTypes/LabelTextType.qml +++ b/client/ui/qml/Controls2/TextTypes/LabelTextType.qml @@ -6,7 +6,7 @@ Text { lineHeight: 16 + LanguageModel.getLineHeightAppend() lineHeightMode: Text.FixedHeight - color: AmneziaStyle.color.grey + color: AmneziaStyle.color.mutedGray font.pixelSize: 13 font.weight: 400 font.family: "PT Root UI VF" diff --git a/client/ui/qml/Controls2/TextTypes/ListItemTitleType.qml b/client/ui/qml/Controls2/TextTypes/ListItemTitleType.qml index eef97c60..40cd7835 100644 --- a/client/ui/qml/Controls2/TextTypes/ListItemTitleType.qml +++ b/client/ui/qml/Controls2/TextTypes/ListItemTitleType.qml @@ -6,7 +6,7 @@ Text { lineHeight: 21.6 + LanguageModel.getLineHeightAppend() lineHeightMode: Text.FixedHeight - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray font.pixelSize: 18 font.weight: 400 font.family: "PT Root UI VF" diff --git a/client/ui/qml/Controls2/TextTypes/ParagraphTextType.qml b/client/ui/qml/Controls2/TextTypes/ParagraphTextType.qml index b2723007..109b2876 100644 --- a/client/ui/qml/Controls2/TextTypes/ParagraphTextType.qml +++ b/client/ui/qml/Controls2/TextTypes/ParagraphTextType.qml @@ -5,7 +5,7 @@ Text { lineHeight: 24 + LanguageModel.getLineHeightAppend() lineHeightMode: Text.FixedHeight - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray font.pixelSize: 16 font.weight: 400 font.family: "PT Root UI VF" diff --git a/client/ui/qml/Controls2/TextTypes/SmallTextType.qml b/client/ui/qml/Controls2/TextTypes/SmallTextType.qml index 06966c4f..6c28607a 100644 --- a/client/ui/qml/Controls2/TextTypes/SmallTextType.qml +++ b/client/ui/qml/Controls2/TextTypes/SmallTextType.qml @@ -6,7 +6,7 @@ Text { lineHeight: 20 + LanguageModel.getLineHeightAppend() lineHeightMode: Text.FixedHeight - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray font.pixelSize: 14 font.weight: 400 font.family: "PT Root UI VF" diff --git a/client/ui/qml/Controls2/TopCloseButtonType.qml b/client/ui/qml/Controls2/TopCloseButtonType.qml index af9f4576..1bd7fef6 100644 --- a/client/ui/qml/Controls2/TopCloseButtonType.qml +++ b/client/ui/qml/Controls2/TopCloseButtonType.qml @@ -25,7 +25,7 @@ Popup { id: button image: "qrc:/images/svg/close_black_24dp.svg" - imageColor: AmneziaStyle.color.white + imageColor: AmneziaStyle.color.paleGray implicitWidth: 40 implicitHeight: 40 diff --git a/client/ui/qml/Controls2/VerticalRadioButton.qml b/client/ui/qml/Controls2/VerticalRadioButton.qml index 04ae91a3..1a781f20 100644 --- a/client/ui/qml/Controls2/VerticalRadioButton.qml +++ b/client/ui/qml/Controls2/VerticalRadioButton.qml @@ -14,15 +14,15 @@ RadioButton { property int textElide: Qt.ElideRight property string descriptionText - property string hoveredColor: AmneziaStyle.color.blackHovered + property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite property string defaultColor: AmneziaStyle.color.transparent property string disabledColor: AmneziaStyle.color.transparent property string selectedColor: AmneziaStyle.color.transparent - property string textColor: AmneziaStyle.color.white - property string selectedTextColor: AmneziaStyle.color.orange + property string textColor: AmneziaStyle.color.paleGray + property string selectedTextColor: AmneziaStyle.color.goldenApricot - property string borderFocusedColor: AmneziaStyle.color.white + property string borderFocusedColor: AmneziaStyle.color.paleGray property int borderFocusedWidth: 1 property string imageSource @@ -139,7 +139,7 @@ RadioButton { CaptionTextType { id: description - color: AmneziaStyle.color.grey + color: AmneziaStyle.color.mutedGray text: root.descriptionText visible: root.descriptionText !== "" diff --git a/client/ui/qml/Controls2/WarningType.qml b/client/ui/qml/Controls2/WarningType.qml index 6d30fcb3..24e5ecad 100644 --- a/client/ui/qml/Controls2/WarningType.qml +++ b/client/ui/qml/Controls2/WarningType.qml @@ -10,9 +10,9 @@ import "TextTypes" Rectangle { id: root - property string textColor: AmneziaStyle.color.white - property string backGroundColor: AmneziaStyle.color.blackLight - property string imageColor: AmneziaStyle.color.white + property string textColor: AmneziaStyle.color.paleGray + property string backGroundColor: AmneziaStyle.color.onyxBlack + property string imageColor: AmneziaStyle.color.paleGray property string textString property int textFormat: Text.PlainText diff --git a/client/ui/qml/Modules/Style/AmneziaStyle.qml b/client/ui/qml/Modules/Style/AmneziaStyle.qml index 7f1850aa..c0038246 100644 --- a/client/ui/qml/Modules/Style/AmneziaStyle.qml +++ b/client/ui/qml/Modules/Style/AmneziaStyle.qml @@ -5,22 +5,22 @@ import QtQuick QtObject { property QtObject color: QtObject { readonly property color transparent: 'transparent' - readonly property color white: '#D7D8DB' - readonly property color whiteHovered: '#C1C2C5' - readonly property color grey: '#878B91' - readonly property color greyDisabled: '#494B50' - readonly property color greyDark: '#2C2D30' - readonly property color blackLight: '#1C1D21' - readonly property color blackHovered: '#01010114' - readonly property color blackPressed: '#0101011f' - readonly property color black: '#0E0E11' - readonly property color orange: '#FBB26A' - readonly property color orangeDark: '#A85809' - readonly property color brownLight: '#84603D' - readonly property color brown: '#633303' - readonly property color brownDark: '#402102' - readonly property color red: '#EB5757' - - readonly property color connectionInProgress: '#261E1A' + readonly property color paleGray: '#D7D8DB' + readonly property color lightGray: '#C1C2C5' + readonly property color mutedGray: '#878B91' + readonly property color charcoalGray: '#494B50' + readonly property color slateGray: '#2C2D30' + readonly property color onyxBlack: '#1C1D21' + readonly property color midnightBlack: '#0E0E11' + readonly property color goldenApricot: '#FBB26A' + readonly property color burntOrange: '#A85809' + readonly property color mutedBrown: '#84603D' + readonly property color richBrown: '#633303' + readonly property color deepBrown: '#402102' + readonly property color vibrantRed: '#EB5757' + readonly property color darkCharcoal: '#261E1A' + readonly property color sheerWhite: Qt.rgba(1, 1, 1, 0.12) + readonly property color translucentWhite: Qt.rgba(1, 1, 1, 0.08) + readonly property color barelyTranslucentWhite: Qt.rgba(1, 1, 1, 0.05) } -} \ No newline at end of file +} diff --git a/client/ui/qml/Pages2/PageDeinstalling.qml b/client/ui/qml/Pages2/PageDeinstalling.qml index 15633fa0..f5fdb29a 100644 --- a/client/ui/qml/Pages2/PageDeinstalling.qml +++ b/client/ui/qml/Pages2/PageDeinstalling.qml @@ -5,6 +5,7 @@ import QtQuick.Layouts import SortFilterProxyModel 0.2 import PageEnum 1.0 +import Style 1.0 import "./" import "../Controls2" diff --git a/client/ui/qml/Pages2/PageDevMenu.qml b/client/ui/qml/Pages2/PageDevMenu.qml new file mode 100644 index 00000000..af6f773a --- /dev/null +++ b/client/ui/qml/Pages2/PageDevMenu.qml @@ -0,0 +1,94 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import SortFilterProxyModel 0.2 + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + defaultActiveFocusItem: focusItem + + Item { + id: focusItem + KeyNavigation.tab: backButton + } + + ColumnLayout { + id: backButtonLayout + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + anchors.topMargin: 20 + + BackButtonType { + id: backButton + // KeyNavigation.tab: removeButton + } + } + + FlickableType { + id: fl + anchors.top: backButtonLayout.bottom + anchors.bottom: parent.bottom + contentHeight: content.implicitHeight + + ColumnLayout { + id: content + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + HeaderType { + id: header + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + headerText: "Dev menu" + } + + + TextFieldWithHeaderType { + id: passwordTextField + + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + parentFlickable: fl + + headerText: qsTr("Gateway endpoint") + textFieldText: SettingsController.gatewayEndpoint + + buttonImageSource: textFieldText !== "" ? "qrc:/images/controls/refresh-cw.svg" : "" + + clickedFunc: function() { + SettingsController.resetGatewayEndpoint() + } + + textField.onEditingFinished: { + textFieldText = textField.text.replace(/^\s+|\s+$/g, '') + if (textFieldText !== SettingsController.gatewayEndpoint) { + SettingsController.gatewayEndpoint = textFieldText + } + } + + // KeyNavigation.tab: saveButton + } + } + } +} diff --git a/client/ui/qml/Pages2/PageHome.qml b/client/ui/qml/Pages2/PageHome.qml index da52d535..8074337a 100644 --- a/client/ui/qml/Pages2/PageHome.qml +++ b/client/ui/qml/Pages2/PageHome.qml @@ -57,10 +57,10 @@ PageType { implicitHeight: 36 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.grey + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.mutedGray borderWidth: 0 visible: isLoggingEnabled ? true : false @@ -94,10 +94,10 @@ PageType { implicitHeight: 36 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.grey + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.mutedGray leftImageColor: AmneziaStyle.color.transparent borderWidth: 0 @@ -106,7 +106,7 @@ PageType { buttonTextLabel.font.weight: 500 property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled || AppSplitTunnelingModel.isTunnelingEnabled || - (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi")) + ServersModel.isDefaultServerDefaultContainerHasSplitTunneling text: isSplitTunnelingEnabled ? qsTr("Split tunneling enabled") : qsTr("Split tunneling disabled") @@ -243,7 +243,7 @@ PageType { hoverEnabled: false image: "qrc:/images/controls/chevron-down.svg" - imageColor: AmneziaStyle.color.white + imageColor: AmneziaStyle.color.paleGray icon.width: 18 icon.height: 18 @@ -265,11 +265,21 @@ PageType { } } - LabelTextType { - id: collapsedServerMenuDescription - Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44 + RowLayout { Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded + Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44 + spacing: 0 + + Image { + Layout.rightMargin: 8 + visible: source !== "" + source: ServersModel.defaultServerImagePathCollapsed + } + + LabelTextType { + id: collapsedServerMenuDescription + text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded + } } } @@ -304,8 +314,8 @@ PageType { DropDownType { id: containersDropDown - rootButtonImageColor: AmneziaStyle.color.black - rootButtonBackgroundColor: AmneziaStyle.color.white + rootButtonImageColor: AmneziaStyle.color.midnightBlack + rootButtonBackgroundColor: AmneziaStyle.color.paleGray rootButtonBackgroundHoveredColor: Qt.rgba(215, 216, 219, 0.8) rootButtonBackgroundPressedColor: Qt.rgba(215, 216, 219, 0.65) rootButtonHoveredBorderColor: AmneziaStyle.color.transparent @@ -314,7 +324,7 @@ PageType { rootButtonTextBottomMargin: 8 text: ServersModel.defaultServerDefaultContainerName - textColor: AmneziaStyle.color.black + textColor: AmneziaStyle.color.midnightBlack headerText: qsTr("VPN protocol") headerBackButtonImage: "qrc:/images/controls/arrow-left.svg" @@ -505,7 +515,7 @@ PageType { ImageButtonType { id: serverInfoButton image: "qrc:/images/controls/settings.svg" - imageColor: AmneziaStyle.color.white + imageColor: AmneziaStyle.color.paleGray implicitWidth: 56 implicitHeight: 56 diff --git a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml index ec4aa010..8651fa27 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml @@ -5,6 +5,7 @@ import QtQuick.Layouts import SortFilterProxyModel 0.2 import PageEnum 1.0 +import Style 1.0 import "./" import "../Controls2" @@ -143,7 +144,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 16 - headerText: "Jc - Junk packet count" + headerText: qsTr("Jc - Junk packet count") textFieldText: junkPacketCount textField.validator: IntValidator { bottom: 0 } parentFlickable: fl @@ -168,7 +169,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 16 - headerText: "Jmin - Junk packet minimum size" + headerText: qsTr("Jmin - Junk packet minimum size") textFieldText: junkPacketMinSize textField.validator: IntValidator { bottom: 0 } parentFlickable: fl @@ -189,7 +190,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 16 - headerText: "Jmax - Junk packet maximum size" + headerText: qsTr("Jmax - Junk packet maximum size") textFieldText: junkPacketMaxSize textField.validator: IntValidator { bottom: 0 } parentFlickable: fl @@ -210,7 +211,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 16 - headerText: "S1 - Init packet junk size" + headerText: qsTr("S1 - Init packet junk size") textFieldText: initPacketJunkSize textField.validator: IntValidator { bottom: 0 } parentFlickable: fl @@ -231,7 +232,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 16 - headerText: "S2 - Response packet junk size" + headerText: qsTr("S2 - Response packet junk size") textFieldText: responsePacketJunkSize textField.validator: IntValidator { bottom: 0 } parentFlickable: fl @@ -252,7 +253,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 16 - headerText: "H1 - Init packet magic header" + headerText: qsTr("H1 - Init packet magic header") textFieldText: initPacketMagicHeader textField.validator: IntValidator { bottom: 0 } parentFlickable: fl @@ -273,7 +274,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 16 - headerText: "H2 - Response packet magic header" + headerText: qsTr("H2 - Response packet magic header") textFieldText: responsePacketMagicHeader textField.validator: IntValidator { bottom: 0 } parentFlickable: fl @@ -294,7 +295,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 16 - headerText: "H4 - Transport packet magic header" + headerText: qsTr("H4 - Transport packet magic header") textFieldText: transportPacketMagicHeader textField.validator: IntValidator { bottom: 0 } parentFlickable: fl @@ -316,7 +317,7 @@ PageType { Layout.topMargin: 16 parentFlickable: fl - headerText: "H3 - Underload packet magic header" + headerText: qsTr("H3 - Underload packet magic header") textFieldText: underloadPacketMagicHeader textField.validator: IntValidator { bottom: 0 } diff --git a/client/ui/qml/Pages2/PageProtocolCloakSettings.qml b/client/ui/qml/Pages2/PageProtocolCloakSettings.qml index 5ef5771e..5089a764 100644 --- a/client/ui/qml/Pages2/PageProtocolCloakSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolCloakSettings.qml @@ -5,6 +5,7 @@ import QtQuick.Layouts import SortFilterProxyModel 0.2 import PageEnum 1.0 +import Style 1.0 import "./" import "../Controls2" diff --git a/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml b/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml index d2330c27..30540a93 100644 --- a/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml @@ -295,7 +295,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 32 Layout.preferredHeight: checkboxLayout.implicitHeight - color: AmneziaStyle.color.blackLight + color: AmneziaStyle.color.onyxBlack radius: 16 Connections { diff --git a/client/ui/qml/Pages2/PageProtocolRaw.qml b/client/ui/qml/Pages2/PageProtocolRaw.qml index 1acc5b54..24853afd 100644 --- a/client/ui/qml/Pages2/PageProtocolRaw.qml +++ b/client/ui/qml/Pages2/PageProtocolRaw.qml @@ -192,9 +192,9 @@ PageType { leftPadding: 0 height: 24 - color: AmneziaStyle.color.white - selectionColor: AmneziaStyle.color.brown - selectedTextColor: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray font.pixelSize: 16 font.weight: Font.Medium @@ -224,7 +224,7 @@ PageType { visible: ServersModel.isProcessedServerHasWriteAccess() text: qsTr("Remove ") + ContainersModel.getProcessedContainerName() - textColor: AmneziaStyle.color.red + textColor: AmneziaStyle.color.vibrantRed Keys.onTabPressed: lastItemTabClicked(focusItem) clickedFunction: function() { diff --git a/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml b/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml index 2cf18544..4d3b2c4e 100644 --- a/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml @@ -5,6 +5,7 @@ import QtQuick.Layouts import SortFilterProxyModel 0.2 import PageEnum 1.0 +import Style 1.0 import "./" import "../Controls2" diff --git a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml index 4e6a851e..758375b1 100644 --- a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml @@ -5,6 +5,7 @@ import QtQuick.Layouts import SortFilterProxyModel 0.2 import PageEnum 1.0 +import Style 1.0 import "./" import "../Controls2" diff --git a/client/ui/qml/Pages2/PageProtocolXraySettings.qml b/client/ui/qml/Pages2/PageProtocolXraySettings.qml index 6a8094d7..20ee1da6 100644 --- a/client/ui/qml/Pages2/PageProtocolXraySettings.qml +++ b/client/ui/qml/Pages2/PageProtocolXraySettings.qml @@ -6,6 +6,7 @@ import SortFilterProxyModel 0.2 import PageEnum 1.0 import ContainerEnum 1.0 +import Style 1.0 import "./" import "../Controls2" diff --git a/client/ui/qml/Pages2/PageServiceDnsSettings.qml b/client/ui/qml/Pages2/PageServiceDnsSettings.qml index 7d9f2df4..bb3cbf96 100644 --- a/client/ui/qml/Pages2/PageServiceDnsSettings.qml +++ b/client/ui/qml/Pages2/PageServiceDnsSettings.qml @@ -70,7 +70,7 @@ PageType { width: parent.width text: qsTr("Remove ") + ContainersModel.getProcessedContainerName() - textColor: AmneziaStyle.color.red + textColor: AmneziaStyle.color.vibrantRed Keys.onTabPressed: root.lastItemTabClicked() diff --git a/client/ui/qml/Pages2/PageServiceSftpSettings.qml b/client/ui/qml/Pages2/PageServiceSftpSettings.qml index 9b5425db..9bdbf2db 100644 --- a/client/ui/qml/Pages2/PageServiceSftpSettings.qml +++ b/client/ui/qml/Pages2/PageServiceSftpSettings.qml @@ -115,7 +115,7 @@ PageType { descriptionOnTop: true rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.white + rightImageColor: AmneziaStyle.color.paleGray clickedFunction: function() { GC.copyToClipBoard(descriptionText) @@ -139,7 +139,7 @@ PageType { KeyNavigation.tab: usernameLabel.rightButton rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.white + rightImageColor: AmneziaStyle.color.paleGray clickedFunction: function() { GC.copyToClipBoard(descriptionText) @@ -163,7 +163,7 @@ PageType { KeyNavigation.tab: passwordLabel.eyeButton rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.white + rightImageColor: AmneziaStyle.color.paleGray clickedFunction: function() { GC.copyToClipBoard(descriptionText) @@ -194,7 +194,7 @@ PageType { } rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.white + rightImageColor: AmneziaStyle.color.paleGray buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg" @@ -218,10 +218,10 @@ PageType { Layout.rightMargin: 16 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray borderWidth: 1 parentFlickable: fl @@ -282,10 +282,10 @@ PageType { implicitHeight: 32 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.orange + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.goldenApricot text: qsTr("Detailed instructions") diff --git a/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml b/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml index 95343f63..9d21963d 100644 --- a/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml +++ b/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml @@ -6,6 +6,7 @@ import SortFilterProxyModel 0.2 import PageEnum 1.0 import ContainerProps 1.0 +import Style 1.0 import "./" import "../Controls2" @@ -106,7 +107,7 @@ PageType { descriptionOnTop: true rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: "#D7D8DB" + rightImageColor: AmneziaStyle.color.paleGray clickedFunction: function() { GC.copyToClipBoard(descriptionText) @@ -130,7 +131,7 @@ PageType { KeyNavigation.tab: usernameLabel.rightButton rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: "#D7D8DB" + rightImageColor: AmneziaStyle.color.paleGray clickedFunction: function() { GC.copyToClipBoard(descriptionText) @@ -154,7 +155,7 @@ PageType { KeyNavigation.tab: passwordLabel.eyeButton rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: "#D7D8DB" + rightImageColor: AmneziaStyle.color.paleGray clickedFunction: function() { GC.copyToClipBoard(descriptionText) @@ -179,7 +180,7 @@ PageType { rightButton.KeyNavigation.tab: changeSettingsButton rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: "#D7D8DB" + rightImageColor: AmneziaStyle.color.paleGray buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg" diff --git a/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml b/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml index de1fefb8..946a77bb 100644 --- a/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml +++ b/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml @@ -83,10 +83,10 @@ PageType { } descriptionOnTop: true - textColor: AmneziaStyle.color.orange + textColor: AmneziaStyle.color.goldenApricot rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.white + rightImageColor: AmneziaStyle.color.paleGray Keys.onTabPressed: lastItemTabClicked(focusItem) diff --git a/client/ui/qml/Pages2/PageSettings.qml b/client/ui/qml/Pages2/PageSettings.qml index f8056c63..bb5ca766 100644 --- a/client/ui/qml/Pages2/PageSettings.qml +++ b/client/ui/qml/Pages2/PageSettings.qml @@ -4,6 +4,7 @@ import QtQuick.Layouts import QtQuick.Dialogs import PageEnum 1.0 +import Style 1.0 import "./" import "../Controls2" @@ -128,6 +129,26 @@ PageType { DividerType {} + LabelWithButtonType { + id: devConsole + visible: SettingsController.isDevModeEnabled + Layout.fillWidth: true + + text: qsTr("Dev console") + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: "qrc:/images/controls/bug.svg" + + // Keys.onTabPressed: lastItemTabClicked(header) + + clickedFunction: function() { + PageController.goToPage(PageEnum.PageDevMenu) + } + } + + DividerType { + visible: SettingsController.isDevModeEnabled + } + LabelWithButtonType { id: close visible: GC.isDesktop() diff --git a/client/ui/qml/Pages2/PageSettingsAbout.qml b/client/ui/qml/Pages2/PageSettingsAbout.qml index f6fcea62..1e38a539 100644 --- a/client/ui/qml/Pages2/PageSettingsAbout.qml +++ b/client/ui/qml/Pages2/PageSettingsAbout.qml @@ -85,7 +85,7 @@ PageType { font.pixelSize: 14 text: qsTr("Amnezia is a free and open-source application. You can support the developers if you like it.") - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray } ParagraphTextType { @@ -163,7 +163,7 @@ PageType { parentFlickable: fl clickedFunction: function() { - Qt.openUrlExternally(qsTr("https://amnezia.org")) + Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl()) } } @@ -177,7 +177,19 @@ PageType { horizontalAlignment: Text.AlignHCenter text: qsTr("Software version: %1").arg(SettingsController.getAppVersion()) - color: AmneziaStyle.color.grey + color: AmneziaStyle.color.mutedGray + + MouseArea { + property int clickCount: 0 + anchors.fill: parent + onClicked: { + if (clickCount > 10) { + SettingsController.enableDevMode() + } else { + clickCount++ + } + } + } } BasicButtonType { @@ -188,10 +200,10 @@ PageType { implicitHeight: 32 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.orange + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.goldenApricot text: qsTr("Check for updates") @@ -211,10 +223,10 @@ PageType { implicitHeight: 25 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.orange + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.goldenApricot text: qsTr("Privacy Policy") @@ -222,7 +234,7 @@ PageType { parentFlickable: fl clickedFunc: function() { - Qt.openUrlExternally("https://amnezia.org/en/policy") + Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/policy") } } } diff --git a/client/ui/qml/Pages2/PageSettingsApiLanguageList.qml b/client/ui/qml/Pages2/PageSettingsApiLanguageList.qml new file mode 100644 index 00000000..234e5142 --- /dev/null +++ b/client/ui/qml/Pages2/PageSettingsApiLanguageList.qml @@ -0,0 +1,103 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + ListView { + id: menuContent + + property var selectedText + + width: parent.width + height: menuContent.contentItem.height + + clip: true + interactive: false + model: ApiCountryModel + + ButtonGroup { + id: containersRadioButtonGroup + } + + delegate: Item { + implicitWidth: parent.width + implicitHeight: content.implicitHeight + + ColumnLayout { + id: content + + anchors.fill: parent + + RowLayout { + VerticalRadioButton { + id: containerRadioButton + + Layout.fillWidth: true + Layout.leftMargin: 16 + + text: countryName + + ButtonGroup.group: containersRadioButtonGroup + + imageSource: "qrc:/images/controls/download.svg" + + checked: index === ApiCountryModel.currentIndex + + onClicked: { + if (index !== ApiCountryModel.currentIndex) { + PageController.showBusyIndicator(true) + var prevIndex = ApiCountryModel.currentIndex + ApiCountryModel.currentIndex = index + if (!InstallController.updateServiceFromApi(ServersModel.defaultIndex, countryCode, countryName)) { + ApiCountryModel.currentIndex = prevIndex + } + } + } + + MouseArea { + anchors.fill: containerRadioButton + cursorShape: Qt.PointingHandCursor + enabled: false + } + + Keys.onEnterPressed: { + if (checkable) { + checked = true + } + containerRadioButton.clicked() + } + Keys.onReturnPressed: { + if (checkable) { + checked = true + } + containerRadioButton.clicked() + } + } + + Image { + Layout.rightMargin: 32 + Layout.alignment: Qt.AlignRight + + source: "qrc:/countriesFlags/images/flagKit/" + countryCode + ".svg" + } + } + + DividerType { + Layout.fillWidth: true + } + } + } + } +} diff --git a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml new file mode 100644 index 00000000..f23e36d9 --- /dev/null +++ b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml @@ -0,0 +1,208 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + defaultActiveFocusItem: focusItem + + FlickableType { + id: fl + anchors.top: parent.top + anchors.bottom: parent.bottom + contentHeight: content.height + + ColumnLayout { + id: content + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + spacing: 0 + + Item { + id: focusItem +// KeyNavigation.tab: backButton + } + + LabelWithImageType { + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: "qrc:/images/controls/map-pin.svg" + leftText: qsTr("For the region") + rightText: ApiServicesModel.getSelectedServiceData("region") + } + + LabelWithImageType { + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: "qrc:/images/controls/tag.svg" + leftText: qsTr("Price") + rightText: ApiServicesModel.getSelectedServiceData("price") + } + + LabelWithImageType { + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: "qrc:/images/controls/history.svg" + leftText: qsTr("Work period") + rightText: ApiServicesModel.getSelectedServiceData("workPeriod") + + visible: rightText !== "" + } + + LabelWithImageType { + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: "qrc:/images/controls/gauge.svg" + leftText: qsTr("Speed") + rightText: ApiServicesModel.getSelectedServiceData("speed") + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + onLinkActivated: function(link) { + Qt.openUrlExternally(link) + } + textFormat: Text.RichText + text: { + var text = ApiServicesModel.getSelectedServiceData("features") + if (text === undefined) { + return "" + } + return text.replace("%1", LanguageModel.getCurrentSiteUrl()) + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + } + + LabelWithButtonType { + id: supportUuid + Layout.fillWidth: true + + text: qsTr("Support tag") + descriptionText: SettingsController.getInstallationUuid() + + descriptionOnTop: true + +// parentFlickable: fl +// KeyNavigation.tab: passwordLabel.eyeButton + + rightImageSource: "qrc:/images/controls/copy.svg" + rightImageColor: AmneziaStyle.color.paleGray + + clickedFunction: function() { + GC.copyToClipBoard(descriptionText) + PageController.showNotificationMessage(qsTr("Copied")) + if (!GC.isMobile()) { + this.rightButton.forceActiveFocus() + } + } + } + + BasicButtonType { + id: resetButton + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: 24 + Layout.bottomMargin: 16 + Layout.leftMargin: 8 + implicitHeight: 32 + + defaultColor: "transparent" + hoveredColor: Qt.rgba(1, 1, 1, 0.08) + pressedColor: Qt.rgba(1, 1, 1, 0.12) + textColor: AmneziaStyle.color.vibrantRed + + text: qsTr("Reload API config") + +// Keys.onTabPressed: lastItemTabClicked(focusItem) + + clickedFunc: function() { + var headerText = qsTr("Reload API config?") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { + PageController.showNotificationMessage(qsTr("Cannot reload API config during active connection")) + } else { + PageController.showBusyIndicator(true) + InstallController.updateServiceFromApi(ServersModel.processedIndex, "", "", true) + PageController.showBusyIndicator(false) + } + } + var noButtonFunction = function() { + if (!GC.isMobile()) { + removeButton.forceActiveFocus() + } + } + + showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } + + BasicButtonType { + id: removeButton + Layout.alignment: Qt.AlignHCenter + Layout.bottomMargin: 16 + Layout.leftMargin: 8 + implicitHeight: 32 + + defaultColor: "transparent" + hoveredColor: Qt.rgba(1, 1, 1, 0.08) + pressedColor: Qt.rgba(1, 1, 1, 0.12) + textColor: AmneziaStyle.color.vibrantRed + + text: qsTr("Remove from application") + +// Keys.onTabPressed: lastItemTabClicked(focusItem) + + clickedFunc: function() { + var headerText = qsTr("Remove from application?") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { + PageController.showNotificationMessage(qsTr("Cannot remove server during active connection")) + } else { + PageController.showBusyIndicator(true) + InstallController.removeProcessedServer() + PageController.showBusyIndicator(false) + } + } + var noButtonFunction = function() { + if (!GC.isMobile()) { + removeButton.forceActiveFocus() + } + } + + showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } + } + } +} diff --git a/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml b/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml index 2a650d6b..2e8bda2f 100644 --- a/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml +++ b/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml @@ -215,7 +215,7 @@ PageType { text: appPath rightImageSource: "qrc:/images/controls/trash.svg" - rightImageColor: AmneziaStyle.color.white + rightImageColor: AmneziaStyle.color.paleGray clickedFunction: function() { var headerText = qsTr("Remove ") + appPath + "?" @@ -242,7 +242,7 @@ PageType { Rectangle { anchors.fill: addAppButton anchors.bottomMargin: -24 - color: AmneziaStyle.color.black + color: AmneziaStyle.color.midnightBlack opacity: 0.8 } diff --git a/client/ui/qml/Pages2/PageSettingsApplication.qml b/client/ui/qml/Pages2/PageSettingsApplication.qml index 1693018c..0f85ac30 100644 --- a/client/ui/qml/Pages2/PageSettingsApplication.qml +++ b/client/ui/qml/Pages2/PageSettingsApplication.qml @@ -224,7 +224,7 @@ PageType { text: qsTr("Reset settings and remove all data from the application") rightImageSource: "qrc:/images/controls/chevron-right.svg" - textColor: AmneziaStyle.color.red + textColor: AmneziaStyle.color.vibrantRed Keys.onTabPressed: lastItemTabClicked() parentFlickable: fl @@ -241,7 +241,7 @@ PageType { } else { SettingsController.clearSettings() - PageController.replaceStartPage() + PageController.goToPageHome() } if (!GC.isMobile()) { diff --git a/client/ui/qml/Pages2/PageSettingsBackup.qml b/client/ui/qml/Pages2/PageSettingsBackup.qml index 0a4f5994..abede9b3 100644 --- a/client/ui/qml/Pages2/PageSettingsBackup.qml +++ b/client/ui/qml/Pages2/PageSettingsBackup.qml @@ -28,7 +28,6 @@ PageType { function onRestoreBackupFinished() { PageController.showNotificationMessage(qsTr("Settings restored from backup file")) - //goToStartPage() PageController.goToPageHome() } @@ -122,10 +121,10 @@ PageType { Layout.topMargin: -8 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray borderWidth: 1 text: qsTr("Restore from backup") diff --git a/client/ui/qml/Pages2/PageSettingsConnection.qml b/client/ui/qml/Pages2/PageSettingsConnection.qml index 218ffe28..31b1c764 100644 --- a/client/ui/qml/Pages2/PageSettingsConnection.qml +++ b/client/ui/qml/Pages2/PageSettingsConnection.qml @@ -3,6 +3,7 @@ import QtQuick.Controls import QtQuick.Layouts import PageEnum 1.0 +import Style 1.0 import "./" import "../Controls2" diff --git a/client/ui/qml/Pages2/PageSettingsDns.qml b/client/ui/qml/Pages2/PageSettingsDns.qml index a73de327..1d7517d9 100644 --- a/client/ui/qml/Pages2/PageSettingsDns.qml +++ b/client/ui/qml/Pages2/PageSettingsDns.qml @@ -38,7 +38,7 @@ PageType { anchors.bottom: parent.bottom contentHeight: content.height - property var isServerFromApi: ServersModel.getDefaultServerData("isServerFromApi") + property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex) enabled: !isServerFromApi @@ -103,10 +103,10 @@ PageType { Layout.fillWidth: true defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray borderWidth: 1 text: qsTr("Restore default") diff --git a/client/ui/qml/Pages2/PageSettingsLogging.qml b/client/ui/qml/Pages2/PageSettingsLogging.qml index 6a7fa385..3ab0df8a 100644 --- a/client/ui/qml/Pages2/PageSettingsLogging.qml +++ b/client/ui/qml/Pages2/PageSettingsLogging.qml @@ -115,7 +115,7 @@ disabled after 14 days, and all log files will be deleted.") Layout.fillWidth: true text: qsTr("Open folder with logs") - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray } } @@ -160,7 +160,7 @@ disabled after 14 days, and all log files will be deleted.") Layout.fillWidth: true text: qsTr("Save logs to file") - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray } } @@ -209,7 +209,7 @@ disabled after 14 days, and all log files will be deleted.") Layout.fillWidth: true text: qsTr("Clear logs") - color: AmneziaStyle.color.white + color: AmneziaStyle.color.paleGray } } } diff --git a/client/ui/qml/Pages2/PageSettingsServerData.qml b/client/ui/qml/Pages2/PageSettingsServerData.qml index ffee0289..e170a351 100644 --- a/client/ui/qml/Pages2/PageSettingsServerData.qml +++ b/client/ui/qml/Pages2/PageSettingsServerData.qml @@ -38,7 +38,7 @@ PageType { function onRemoveProcessedServerFinished(finishedMessage) { if (!ServersModel.getServersCount()) { - PageController.replaceStartPage() + PageController.goToPageHome() } else { PageController.goToStartPage() PageController.goToPage(PageEnum.PageSettingsServersList) @@ -119,7 +119,7 @@ PageType { Layout.fillWidth: true text: qsTr("Reboot server") - textColor: AmneziaStyle.color.red + textColor: AmneziaStyle.color.vibrantRed KeyNavigation.tab: labelWithButton3 @@ -160,7 +160,7 @@ PageType { Layout.fillWidth: true text: qsTr("Remove server from application") - textColor: AmneziaStyle.color.red + textColor: AmneziaStyle.color.vibrantRed Keys.onTabPressed: { if (content.isServerWithWriteAccess) { @@ -208,7 +208,7 @@ PageType { Layout.fillWidth: true text: qsTr("Clear server from Amnezia software") - textColor: AmneziaStyle.color.red + textColor: AmneziaStyle.color.vibrantRed Keys.onTabPressed: labelWithButton5.visible ? labelWithButton5.forceActiveFocus() : @@ -247,11 +247,11 @@ PageType { LabelWithButtonType { id: labelWithButton5 - visible: ServersModel.getProcessedServerData("isServerFromApi") + visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") Layout.fillWidth: true text: qsTr("Reset API config") - textColor: AmneziaStyle.color.red + textColor: AmneziaStyle.color.vibrantRed Keys.onTabPressed: root.lastItemTabClickedSignal() @@ -285,7 +285,7 @@ PageType { } DividerType { - visible: ServersModel.getProcessedServerData("isServerFromApi") + visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") } } } diff --git a/client/ui/qml/Pages2/PageSettingsServerInfo.qml b/client/ui/qml/Pages2/PageSettingsServerInfo.qml index cf649ae0..95ae5c8a 100644 --- a/client/ui/qml/Pages2/PageSettingsServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsServerInfo.qml @@ -19,13 +19,19 @@ import "../Components" PageType { id: root + property int pageSettingsServerProtocols: 0 + property int pageSettingsServerServices: 1 + property int pageSettingsServerData: 2 + property int pageSettingsApiServerInfo: 3 + property int pageSettingsApiLanguageList: 4 + defaultActiveFocusItem: focusItem Connections { target: PageController function onGoToPageSettingsServerServices() { - tabBar.currentIndex = 1 + tabBar.currentIndex = root.pageSettingsServerServices } } @@ -70,6 +76,15 @@ PageType { BackButtonType { id: backButton KeyNavigation.tab: headerContent.actionButton + + backButtonFunction: function() { + if (nestedStackView.currentIndex === root.pageSettingsApiServerInfo && + ServersModel.getProcessedServerData("isCountrySelectionAvailable")) { + nestedStackView.currentIndex = root.pageSettingsApiLanguageList + } else { + PageController.closePage() + } + } } HeaderType { @@ -78,11 +93,15 @@ PageType { Layout.leftMargin: 16 Layout.rightMargin: 16 - actionButtonImage: "qrc:/images/controls/edit-3.svg" + actionButtonImage: nestedStackView.currentIndex === root.pageSettingsApiLanguageList ? "qrc:/images/controls/settings.svg" : "qrc:/images/controls/edit-3.svg" headerText: name descriptionText: { - if (ServersModel.isProcessedServerHasWriteAccess()) { + if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) { + return ApiServicesModel.getSelectedServiceData("serviceDescription") + } else if (ServersModel.getProcessedServerData("isServerFromTelegramApi")) { + return serverDescription + } else if (ServersModel.isProcessedServerHasWriteAccess()) { return credentialsLogin + " · " + hostName } else { return hostName @@ -92,7 +111,11 @@ PageType { KeyNavigation.tab: tabBar actionButtonFunction: function() { - serverNameEditDrawer.open() + if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) { + nestedStackView.currentIndex = root.pageSettingsApiServerInfo + } else { + serverNameEditDrawer.open() + } } } @@ -172,13 +195,16 @@ PageType { Layout.fillWidth: true - currentIndex: (ServersModel.getProcessedServerData("isServerFromApi") - && !ServersModel.getProcessedServerData("hasInstalledContainers")) ? 2 : 0 + currentIndex: (ServersModel.getProcessedServerData("isServerFromTelegramApi") + && !ServersModel.getProcessedServerData("hasInstalledContainers")) ? + root.pageSettingsServerData : root.pageSettingsServerProtocols background: Rectangle { color: AmneziaStyle.color.transparent } + visible: !ServersModel.getProcessedServerData("isServerFromGatewayApi") + activeFocusOnTab: true onFocusChanged: { if (activeFocus) { @@ -190,45 +216,53 @@ PageType { id: protocolsTab visible: protocolsPage.installedProtocolsCount width: protocolsPage.installedProtocolsCount ? undefined : 0 - isSelected: tabBar.currentIndex === 0 + isSelected: tabBar.currentIndex === root.pageSettingsServerProtocols text: qsTr("Protocols") KeyNavigation.tab: servicesTab - Keys.onReturnPressed: tabBar.currentIndex = 0 - Keys.onEnterPressed: tabBar.currentIndex = 0 + Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerProtocols + Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerProtocols } + TabButtonType { id: servicesTab visible: servicesPage.installedServicesCount width: servicesPage.installedServicesCount ? undefined : 0 - isSelected: tabBar.currentIndex === 1 + isSelected: tabBar.currentIndex === root.pageSettingsServerServices text: qsTr("Services") KeyNavigation.tab: dataTab - Keys.onReturnPressed: tabBar.currentIndex = 1 - Keys.onEnterPressed: tabBar.currentIndex = 1 + Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerServices + Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerServices } + TabButtonType { id: dataTab - isSelected: tabBar.currentIndex === 2 + isSelected: tabBar.currentIndex === root.pageSettingsServerData text: qsTr("Management") - Keys.onReturnPressed: tabBar.currentIndex = 2 - Keys.onEnterPressed: tabBar.currentIndex = 2 - KeyNavigation.tab: stackView.currentIndex === 0 ? - protocolsPage : - stackView.currentIndex === 1 ? - servicesPage : - dataPage + Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerData + Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerData + Keys.onTabPressed: function() { + if (nestedStackView.currentIndex === root.pageSettingsServerProtocols) { + return protocolsPage + } else if (nestedStackView.currentIndex === root.pageSettingsServerProtocols) { + return servicesPage + } else { + return dataPage + } + } } } StackLayout { - id: stackView + id: nestedStackView Layout.preferredWidth: root.width Layout.preferredHeight: root.height - tabBar.implicitHeight - header.implicitHeight - currentIndex: tabBar.currentIndex + currentIndex: ServersModel.getProcessedServerData("isServerFromGatewayApi") ? + (ServersModel.getProcessedServerData("isCountrySelectionAvailable") ? + root.pageSettingsApiLanguageList : root.pageSettingsApiServerInfo) : tabBar.currentIndex PageSettingsServerProtocols { id: protocolsPage @@ -236,18 +270,34 @@ PageType { onLastItemTabClickedSignal: lastItemTabClicked(focusItem) } + PageSettingsServerServices { id: servicesPage stackView: root.stackView onLastItemTabClickedSignal: lastItemTabClicked(focusItem) } + PageSettingsServerData { id: dataPage stackView: root.stackView onLastItemTabClickedSignal: lastItemTabClicked(focusItem) } + + PageSettingsApiServerInfo { + id: apiInfoPage + stackView: root.stackView + +// onLastItemTabClickedSignal: lastItemTabClicked(focusItem) + } + + PageSettingsApiLanguageList { + id: apiLanguageListPage + stackView: root.stackView + +// onLastItemTabClickedSignal: lastItemTabClicked(focusItem) + } } } diff --git a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml index e06a637e..6410156d 100644 --- a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml +++ b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml @@ -184,7 +184,7 @@ PageType { Keys.onTabPressed: lastItemTabClicked(focusItem) text: qsTr("Remove ") + ContainersModel.getProcessedContainerName() - textColor: AmneziaStyle.color.red + textColor: AmneziaStyle.color.vibrantRed clickedFunction: function() { var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName()) diff --git a/client/ui/qml/Pages2/PageSettingsServerProtocols.qml b/client/ui/qml/Pages2/PageSettingsServerProtocols.qml index 33585d71..0bc1fc7d 100644 --- a/client/ui/qml/Pages2/PageSettingsServerProtocols.qml +++ b/client/ui/qml/Pages2/PageSettingsServerProtocols.qml @@ -8,6 +8,7 @@ import PageEnum 1.0 import ProtocolEnum 1.0 import ContainerProps 1.0 import ContainersModelFilters 1.0 +import Style 1.0 import "./" import "../Controls2" diff --git a/client/ui/qml/Pages2/PageSettingsServerServices.qml b/client/ui/qml/Pages2/PageSettingsServerServices.qml index 72a4d3f7..440fd8db 100644 --- a/client/ui/qml/Pages2/PageSettingsServerServices.qml +++ b/client/ui/qml/Pages2/PageSettingsServerServices.qml @@ -8,6 +8,7 @@ import PageEnum 1.0 import ProtocolEnum 1.0 import ContainerProps 1.0 import ContainersModelFilters 1.0 +import Style 1.0 import "./" import "../Controls2" diff --git a/client/ui/qml/Pages2/PageSettingsServersList.qml b/client/ui/qml/Pages2/PageSettingsServersList.qml index 596505a9..102dd46f 100644 --- a/client/ui/qml/Pages2/PageSettingsServersList.qml +++ b/client/ui/qml/Pages2/PageSettingsServersList.qml @@ -7,6 +7,7 @@ import SortFilterProxyModel 0.2 import PageEnum 1.0 import ProtocolEnum 1.0 import ContainerProps 1.0 +import Style 1.0 import "./" import "../Controls2" @@ -119,7 +120,11 @@ PageType { servicesNameString += servicesName[i] + " · " } - return servicesNameString + hostName + if (ServersModel.isServerFromApi(index)) { + return servicesNameString + serverDescription + } else { + return servicesNameString + hostName + } } rightImageSource: "qrc:/images/controls/chevron-right.svg" diff --git a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml index 60821ebc..f5fe285a 100644 --- a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml +++ b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml @@ -21,7 +21,7 @@ import "../Components" PageType { id: root - property var isServerFromApi: ServersModel.getDefaultServerData("isServerFromApi") + property var isServerFromTelegramApi: ServersModel.getDefaultServerData("isServerFromTelegramApi") defaultActiveFocusItem: searchField.textField @@ -36,7 +36,7 @@ PageType { if (ConnectionController.isConnected) { PageController.showNotificationMessage(qsTr("Cannot change split tunneling settings during active connection")) root.pageEnabled = false - } else if (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && isServerFromApi) { + } else if (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling) { PageController.showNotificationMessage(qsTr("Default server does not support split tunneling function")) root.pageEnabled = false } else { @@ -266,7 +266,7 @@ PageType { text: url descriptionText: ip rightImageSource: "qrc:/images/controls/trash.svg" - rightImageColor: AmneziaStyle.color.white + rightImageColor: AmneziaStyle.color.paleGray clickedFunction: function() { var headerText = qsTr("Remove ") + url + "?" @@ -300,7 +300,7 @@ PageType { Rectangle { anchors.fill: addSiteButton anchors.bottomMargin: -24 - color: AmneziaStyle.color.black + color: AmneziaStyle.color.midnightBlack opacity: 0.8 } @@ -341,7 +341,7 @@ PageType { implicitHeight: 56 image: "qrc:/images/controls/more-vertical.svg" - imageColor: AmneziaStyle.color.white + imageColor: AmneziaStyle.color.paleGray onClicked: function () { moreActionsDrawer.open() diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml new file mode 100644 index 00000000..75fd3d47 --- /dev/null +++ b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml @@ -0,0 +1,154 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + defaultActiveFocusItem: focusItem + + FlickableType { + id: fl + anchors.top: parent.top + anchors.bottom: parent.bottom + contentHeight: content.height + continueButton.implicitHeight + continueButton.anchors.bottomMargin + continueButton.anchors.topMargin + + ColumnLayout { + id: content + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + spacing: 0 + + Item { + id: focusItem + KeyNavigation.tab: backButton + } + + BackButtonType { + id: backButton + Layout.topMargin: 20 +// KeyNavigation.tab: fileButton.rightButton + } + + HeaderType { + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 32 + + headerText: ApiServicesModel.getSelectedServiceData("name") + descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription") + } + + LabelWithImageType { + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: "qrc:/images/controls/map-pin.svg" + leftText: qsTr("For the region") + rightText: ApiServicesModel.getSelectedServiceData("region") + } + + LabelWithImageType { + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: "qrc:/images/controls/tag.svg" + leftText: qsTr("Price") + rightText: ApiServicesModel.getSelectedServiceData("price") + } + + LabelWithImageType { + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: "qrc:/images/controls/history.svg" + leftText: qsTr("Work period") + rightText: ApiServicesModel.getSelectedServiceData("workPeriod") + + visible: rightText !== "" + } + + LabelWithImageType { + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: "qrc:/images/controls/gauge.svg" + leftText: qsTr("Speed") + rightText: ApiServicesModel.getSelectedServiceData("speed") + } + + LabelWithImageType { + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: "qrc:/images/controls/info.svg" + leftText: qsTr("Features") + rightText: "" + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + onLinkActivated: function(link) { + Qt.openUrlExternally(link) + } + textFormat: Text.RichText + text: { + var text = ApiServicesModel.getSelectedServiceData("features") + return text.replace("%1", LanguageModel.getCurrentSiteUrl()) + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + } + } + } + + BasicButtonType { + id: continueButton + + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: parent.bottom + + anchors.topMargin: 32 + anchors.rightMargin: 16 + anchors.leftMargin: 16 + anchors.bottomMargin: 32 + + text: qsTr("Connect") + + clickedFunc: function() { + var endpoint = ApiServicesModel.getStoreEndpoint() + if (endpoint !== undefined && endpoint !== "") { + Qt.openUrlExternally(endpoint) + PageController.closePage() + PageController.closePage() + } else { + PageController.showBusyIndicator(true) + InstallController.installServiceFromApi() + PageController.showBusyIndicator(false) + } + } + } +} diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml new file mode 100644 index 00000000..cb79f19e --- /dev/null +++ b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml @@ -0,0 +1,100 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" + +PageType { + id: root + + defaultActiveFocusItem: focusItem + + FlickableType { + id: fl + anchors.top: parent.top + anchors.bottom: parent.bottom + contentHeight: content.height + + ColumnLayout { + id: content + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + spacing: 0 + + Item { + id: focusItem + KeyNavigation.tab: backButton + } + + BackButtonType { + id: backButton + Layout.topMargin: 20 +// KeyNavigation.tab: fileButton.rightButton + } + + HeaderType { + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 32 + + headerText: qsTr("VPN by Amnezia") + descriptionText: qsTr("Choose a VPN service that suits your needs.") + } + + ListView { + id: containers + width: parent.width + height: containers.contentItem.height + spacing: 16 + + currentIndex: 1 + interactive: false + model: ApiServicesModel + + delegate: Item { + implicitWidth: containers.width + implicitHeight: delegateContent.implicitHeight + + ColumnLayout { + id: delegateContent + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + CardWithIconsType { + id: card + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + headerText: name + bodyText: cardDescription + footerText: price + + rightImageSource: "qrc:/images/controls/chevron-right.svg" + + onClicked: { + ApiServicesModel.setServiceIndex(index) + PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo) + } + } + } + } + } + } + } +} diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml index f7b8949b..3febca4c 100644 --- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml +++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml @@ -4,6 +4,7 @@ import QtQuick.Layouts import QtQuick.Dialogs import PageEnum 1.0 +import Style 1.0 import "./" import "../Controls2" @@ -17,7 +18,9 @@ PageType { target: ImportController function onQrDecodingFinished() { - PageController.closePage() + if (Qt.platform.os === "ios") { + PageController.closePage() + } PageController.goToPage(PageEnum.PageSetupWizardViewConfig) } } @@ -41,46 +44,163 @@ PageType { Item { id: focusItem - KeyNavigation.tab: backButton + KeyNavigation.tab: textKey.textField } - BackButtonType { - id: backButton - Layout.topMargin: 20 - KeyNavigation.tab: fileButton.rightButton - } HeaderType { Layout.fillWidth: true - Layout.topMargin: 8 + Layout.topMargin: 24 Layout.rightMargin: 16 Layout.leftMargin: 16 - headerText: qsTr("Server connection") - descriptionText: qsTr("Do not use connection codes from untrusted sources, as they may be created to intercept your data.") + headerText: qsTr("Connection") } - Header2TextType { + ParagraphTextType { + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 24 + + text: qsTr("Insert the key, add a configuration file or scan the QR-code") + } + + TextFieldWithHeaderType { + id: textKey + Layout.fillWidth: true - Layout.topMargin: 48 Layout.rightMargin: 16 Layout.leftMargin: 16 - text: qsTr("What do you have?") + headerText: qsTr("Insert key") + buttonText: qsTr("Insert") + + clickedFunc: function() { + textField.text = "" + textField.paste() + } + + KeyNavigation.tab: continueButton } - LabelWithButtonType { - id: fileButton + BasicButtonType { + id: continueButton + Layout.fillWidth: true Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + visible: textKey.textFieldText !== "" + + text: qsTr("Continue") + Keys.onTabPressed: lastItemTabClicked(focusItem) + + clickedFunc: function() { + if (ImportController.extractConfigFromData(textKey.textFieldText)) { + PageController.goToPage(PageEnum.PageSetupWizardViewConfig) + } + } + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 24 + + color: AmneziaStyle.color.charcoalGray + text: qsTr("Other connection options") + } + + CardWithIconsType { + id: apiInstalling + + visible: false + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + + headerText: qsTr("VPN by Amnezia") + bodyText: qsTr("Connect to classic paid and free VPN services from Amnezia") - text: !ServersModel.getServersCount() ? qsTr("File with connection settings or backup") : qsTr("File with connection settings") rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/folder-open.svg" + leftImageSource: "qrc:/images/controls/amnezia.svg" - KeyNavigation.tab: qrButton.visible ? qrButton.rightButton : textButton.rightButton + onClicked: function() { + PageController.showBusyIndicator(true) + var result = InstallController.fillAvailableServices() + PageController.showBusyIndicator(false) + if (result) { + PageController.goToPage(PageEnum.PageSetupWizardApiServicesList) + } + } + } - clickedFunction: function() { + CardWithIconsType { + id: manualInstalling + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + + headerText: qsTr("Self-hosted VPN") + bodyText: qsTr("Configure Amnezia VPN on your own server") + + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: "qrc:/images/controls/server.svg" + + onClicked: { + PageController.goToPage(PageEnum.PageSetupWizardCredentials) + } + } + + CardWithIconsType { + id: backupRestore + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + + visible: PageController.isStartPageVisible() + + headerText: qsTr("Restore from backup") + + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: "qrc:/images/controls/archive-restore.svg" + + onClicked: { + var filePath = SystemController.getFileName(qsTr("Open backup file"), + qsTr("Backup files (*.backup)")) + if (filePath !== "") { + PageController.showBusyIndicator(true) + SettingsController.restoreAppConfig(filePath) + PageController.showBusyIndicator(false) + } + } + } + + CardWithIconsType { + id: openFile + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + + headerText: qsTr("File with connection settings") + + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: "qrc:/images/controls/folder-search-2.svg" + + onClicked: { var nameFilter = !ServersModel.getServersCount() ? "Config or backup files (*.vpn *.ovpn *.conf *.json *.backup)" : "Config files (*.vpn *.ovpn *.conf *.json)" var fileName = SystemController.getFileName(qsTr("Open config file"), nameFilter) @@ -92,20 +212,22 @@ PageType { } } - DividerType {} + CardWithIconsType { + id: scanQr - LabelWithButtonType { - id: qrButton Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + visible: SettingsController.isCameraPresent() - text: qsTr("QR code") + headerText: qsTr("QR code") + rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/qr-code.svg" + leftImageSource: "qrc:/images/controls/scan-line.svg" - KeyNavigation.tab: textButton.rightButton - - clickedFunction: function() { + onClicked: { ImportController.startDecodingQr() if (Qt.platform.os === "ios") { PageController.goToPage(PageEnum.PageSetupWizardQrReader) @@ -113,26 +235,25 @@ PageType { } } - DividerType { - visible: SettingsController.isCameraPresent() - } + CardWithIconsType { + id: siteLink - LabelWithButtonType { - id: textButton Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + + visible: PageController.isStartPageVisible() + + headerText: qsTr("I have nothing") - text: qsTr("Key as text") rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/text-cursor.svg" + leftImageSource: "qrc:/images/controls/help-circle.svg" - Keys.onTabPressed: lastItemTabClicked(focusItem) - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSetupWizardTextKey) + onClicked: { + Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl()) } } - - DividerType {} } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml index ea522363..7f1c3eed 100644 --- a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml +++ b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml @@ -3,6 +3,7 @@ import QtQuick.Controls import QtQuick.Layouts import PageEnum 1.0 +import Style 1.0 import "./" import "../Controls2" @@ -142,6 +143,23 @@ PageType { text: qsTr("All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties") } + + CardWithIconsType { + id: siteLink + + Layout.fillWidth: true + Layout.bottomMargin: 16 + + headerText: qsTr("How to run your VPN server") + bodyText: qsTr("Where to get connection data, step-by-step instructions for buying a VPS") + + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: "qrc:/images/controls/help-circle.svg" + + onClicked: { + Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/starter-guide") + } + } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardEasy.qml b/client/ui/qml/Pages2/PageSetupWizardEasy.qml index 0cf4c88c..02a7c928 100644 --- a/client/ui/qml/Pages2/PageSetupWizardEasy.qml +++ b/client/ui/qml/Pages2/PageSetupWizardEasy.qml @@ -187,10 +187,10 @@ PageType { anchors.bottomMargin: 24 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray borderWidth: 1 Keys.onTabPressed: lastItemTabClicked(focusItem) diff --git a/client/ui/qml/Pages2/PageSetupWizardInstalling.qml b/client/ui/qml/Pages2/PageSetupWizardInstalling.qml index b94e40f1..1128761d 100644 --- a/client/ui/qml/Pages2/PageSetupWizardInstalling.qml +++ b/client/ui/qml/Pages2/PageSetupWizardInstalling.qml @@ -5,6 +5,7 @@ import QtQuick.Layouts import SortFilterProxyModel 0.2 import PageEnum 1.0 +import Style 1.0 import "./" import "../Controls2" @@ -46,14 +47,7 @@ PageType { ServersModel.processedIndex = ServersModel.defaultIndex } - PageController.goToStartPage() - if (stackView.currentItem.objectName === PageController.getPagePath(PageEnum.PageSetupWizardStart)) { - PageController.replaceStartPage() - } - if (stackView.currentItem.objectName !== PageController.getPagePath(PageEnum.PageHome)) { - PageController.goToPageHome() - } - + PageController.goToPageHome() PageController.showNotificationMessage(finishedMessage) } diff --git a/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml b/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml index d0841f67..6b4c0a1c 100644 --- a/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml +++ b/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml @@ -95,10 +95,10 @@ PageType { implicitHeight: 32 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.orange + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.goldenApricot text: qsTr("More detailed") KeyNavigation.tab: transportProtoSelector diff --git a/client/ui/qml/Pages2/PageSetupWizardProtocols.qml b/client/ui/qml/Pages2/PageSetupWizardProtocols.qml index 59da549c..48265f66 100644 --- a/client/ui/qml/Pages2/PageSetupWizardProtocols.qml +++ b/client/ui/qml/Pages2/PageSetupWizardProtocols.qml @@ -6,6 +6,7 @@ import SortFilterProxyModel 0.2 import PageEnum 1.0 import ProtocolEnum 1.0 +import Style 1.0 import "./" import "../Controls2" diff --git a/client/ui/qml/Pages2/PageSetupWizardStart.qml b/client/ui/qml/Pages2/PageSetupWizardStart.qml index ee7e2a24..b12c7830 100644 --- a/client/ui/qml/Pages2/PageSetupWizardStart.qml +++ b/client/ui/qml/Pages2/PageSetupWizardStart.qml @@ -14,183 +14,44 @@ import "../Components" PageType { id: root - property bool isControlsDisabled: false - defaultActiveFocusItem: focusItem - Connections { - target: PageController + ColumnLayout { + id: content - function onGoToPageViewConfig() { - PageController.goToPage(PageEnum.PageSetupWizardViewConfig) + anchors.fill: parent + spacing: 0 + + Image { + id: image + source: "qrc:/images/amneziaBigLogo.png" + + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + Layout.topMargin: 32 + Layout.preferredWidth: 360 + Layout.preferredHeight: 287 } - function onClosePage() { - if (stackView.depth <= 1) { - PageController.hideWindow() - return - } - stackView.pop() + Item { + id: focusItem + KeyNavigation.tab: startButton } - function onGoToPage(page, slide) { - var pagePath = PageController.getPagePath(page) - if (slide) { - stackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition) - } else { - stackView.push(pagePath, { "objectName" : pagePath }, StackView.Immediate) - } - } + BasicButtonType { + id: startButton + Layout.fillWidth: true + Layout.bottomMargin: 48 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.alignment: Qt.AlignBottom - function onGoToStartPage() { - while (stackView.depth > 1) { - stackView.pop() - } - } + text: qsTr("Let's get started") - function onDisableControls(disabled) { - isControlsDisabled = disabled - } - - function onDisableTabBar(disabled) { - isControlsDisabled = disabled - } - - function onEscapePressed() { - if (isControlsDisabled) { - return + clickedFunc: function() { + PageController.goToPage(PageEnum.PageSetupWizardConfigSource) } - PageController.closePage() - } - } - - Connections { - target: SettingsController - - function onRestoreBackupFinished() { - PageController.showNotificationMessage(qsTr("Settings restored from backup file")) - PageController.replaceStartPage() - } - } - - Connections { - target: InstallController - - function onInstallationErrorOccurred(error) { - PageController.showBusyIndicator(false) - PageController.showErrorMessage(error) - - var currentPageName = stackView.currentItem.objectName - - if (currentPageName === PageController.getPagePath(PageEnum.PageSetupWizardInstalling)) { - PageController.closePage() - } - } - } - - Connections { - target: ImportController - - function onRestoreAppConfig(data) { - PageController.showBusyIndicator(true) - SettingsController.restoreAppConfigFromData(data) - PageController.showBusyIndicator(false) - } - - function onImportErrorOccurred(error, goToPageHome) { - PageController.showErrorMessage(error) - } - } - - FlickableType { - id: fl - anchors.top: parent.top - anchors.bottom: parent.bottom - contentHeight: content.height - - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - spacing: 0 - - Image { - id: image - source: "qrc:/images/amneziaBigLogo.png" - - Layout.alignment: Qt.AlignCenter - Layout.topMargin: 32 - Layout.leftMargin: 8 - Layout.rightMargin: 8 - Layout.preferredWidth: 344 - Layout.preferredHeight: 279 - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.topMargin: 50 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - text: qsTr("Free service for creating a personal VPN on your server.") + - qsTr(" Helps you access blocked content without revealing your privacy, even to VPN providers.") - } - - Item { - id: focusItem - KeyNavigation.tab: startButton - } - - BasicButtonType { - id: startButton - Layout.fillWidth: true - Layout.topMargin: 32 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - text: qsTr("I have the data to connect") - - clickedFunc: function() { - connectionTypeSelection.open() - } - - KeyNavigation.tab: startButton2 - } - - BasicButtonType { - id: startButton2 - Layout.fillWidth: true - Layout.topMargin: 8 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white - borderWidth: 1 - - text: qsTr("I have nothing") - - clickedFunc: function() { - Qt.openUrlExternally(qsTr("https://amnezia.org/instructions/0_starter-guide")) - } - - Keys.onTabPressed: lastItemTabClicked(focusItem) - } - } - } - - ConnectionTypeSelectionDrawer { - id: connectionTypeSelection - - onClosed: { - PageController.forceTabBarActiveFocus() - root.defaultActiveFocusItem.forceActiveFocus() + Keys.onTabPressed: lastItemTabClicked(focusItem) } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardTextKey.qml b/client/ui/qml/Pages2/PageSetupWizardTextKey.qml index 5c9da47a..c4227df1 100644 --- a/client/ui/qml/Pages2/PageSetupWizardTextKey.qml +++ b/client/ui/qml/Pages2/PageSetupWizardTextKey.qml @@ -3,6 +3,7 @@ import QtQuick.Controls import QtQuick.Layouts import PageEnum 1.0 +import Style 1.0 import "./" import "../Controls2" diff --git a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml index 54f64423..3aac1555 100644 --- a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml +++ b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml @@ -51,13 +51,7 @@ PageType { ServersModel.processedIndex = ServersModel.defaultIndex } - PageController.goToStartPage() - if (stackView.currentItem.objectName === PageController.getPagePath(PageEnum.PageSetupWizardStart)) { - PageController.replaceStartPage() - } - if (stackView.currentItem.objectName !== PageController.getPagePath(PageEnum.PageHome)) { - PageController.goToPageHome() - } + PageController.goToPageHome() } } @@ -107,10 +101,10 @@ PageType { implicitHeight: 32 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.orange + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.goldenApricot text: showContent ? qsTr("Collapse content") : qsTr("Show content") KeyNavigation.tab: connectButton @@ -139,8 +133,8 @@ PageType { iconPath: "qrc:/images/controls/alert-circle.svg" - textColor: AmneziaStyle.color.red - imageColor: AmneziaStyle.color.red + textColor: AmneziaStyle.color.vibrantRed + imageColor: AmneziaStyle.color.vibrantRed } WarningType { @@ -159,7 +153,7 @@ PageType { implicitHeight: configContent.implicitHeight radius: 10 - color: AmneziaStyle.color.blackLight + color: AmneziaStyle.color.onyxBlack visible: showContent @@ -180,7 +174,7 @@ PageType { Rectangle { anchors.fill: columnContent anchors.bottomMargin: -24 - color: AmneziaStyle.color.black + color: AmneziaStyle.color.midnightBlack opacity: 0.8 } diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 459b985f..33577d74 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -273,7 +273,7 @@ PageType { implicitWidth: accessTypeSelectorContent.implicitWidth implicitHeight: accessTypeSelectorContent.implicitHeight - color: AmneziaStyle.color.blackLight + color: AmneziaStyle.color.onyxBlack radius: 16 RowLayout { @@ -327,7 +327,7 @@ PageType { visible: accessTypeSelector.currentIndex === 0 text: qsTr("Share VPN access without the ability to manage the server") - color: AmneziaStyle.color.grey + color: AmneziaStyle.color.mutedGray } TextFieldWithHeaderType { @@ -658,7 +658,7 @@ PageType { ImageButtonType { id: closeSearchButton image: "qrc:/images/controls/close.svg" - imageColor: AmneziaStyle.color.white + imageColor: AmneziaStyle.color.paleGray Keys.onTabPressed: { if (!GC.isMobile()) { @@ -806,7 +806,7 @@ PageType { ColumnLayout { id: textColumn - property string textColor: AmneziaStyle.color.grey + property string textColor: AmneziaStyle.color.mutedGray Layout.bottomMargin: 24 ParagraphTextType { @@ -853,10 +853,10 @@ PageType { Layout.topMargin: 24 defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray borderWidth: 1 text: qsTr("Rename") @@ -946,10 +946,10 @@ PageType { Layout.fillWidth: true defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray borderWidth: 1 text: qsTr("Revoke") diff --git a/client/ui/qml/Pages2/PageShareFullAccess.qml b/client/ui/qml/Pages2/PageShareFullAccess.qml index f22132c1..4807c030 100644 --- a/client/ui/qml/Pages2/PageShareFullAccess.qml +++ b/client/ui/qml/Pages2/PageShareFullAccess.qml @@ -67,7 +67,7 @@ PageType { text: qsTr("We recommend that you use full access to the server only for your own additional devices.\n") + qsTr("If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. ") - color: AmneziaStyle.color.grey + color: AmneziaStyle.color.mutedGray } DropDownType { diff --git a/client/ui/qml/Pages2/PageStart.qml b/client/ui/qml/Pages2/PageStart.qml index 6dd05f09..770347ca 100644 --- a/client/ui/qml/Pages2/PageStart.qml +++ b/client/ui/qml/Pages2/PageStart.qml @@ -24,8 +24,14 @@ PageType { target: PageController function onGoToPageHome() { - tabBar.setCurrentIndex(0) - tabBarStackView.goToTabBarPage(PageEnum.PageHome) + if (PageController.isStartPageVisible()) { + tabBar.visible = false + tabBarStackView.goToTabBarPage(PageEnum.PageSetupWizardStart) + } else { + tabBar.visible = true + tabBar.setCurrentIndex(0) + tabBarStackView.goToTabBarPage(PageEnum.PageHome) + } } function onGoToPageSettings() { @@ -65,7 +71,6 @@ PageType { } function onGoToStartPage() { - connectionTypeSelection.close() while (tabBarStackView.depth > 1) { tabBarStackView.pop() } @@ -78,9 +83,9 @@ PageType { var pageName = tabBarStackView.currentItem.objectName if ((pageName === PageController.getPagePath(PageEnum.PageShare)) || - (pageName === PageController.getPagePath(PageEnum.PageSettings))) { + (pageName === PageController.getPagePath(PageEnum.PageSettings)) || + (pageName === PageController.getPagePath(PageEnum.PageSetupWizardConfigSource))) { PageController.goToPageHome() - tabBar.previousIndex = 0 } else { PageController.closePage() } @@ -126,6 +131,33 @@ PageType { function onCachedProfileCleared(message) { PageController.showNotificationMessage(message) } + + function onApiConfigRemoved(message) { + PageController.showNotificationMessage(message) + } + + function onInstallServerFromApiFinished(message) { + PageController.showBusyIndicator(false) + if (!ConnectionController.isConnected) { + ServersModel.setDefaultServerIndex(ServersModel.getServersCount() - 1); + ServersModel.processedIndex = ServersModel.defaultIndex + } + + PageController.goToPageHome() + PageController.showNotificationMessage(message) + } + + function onChangeApiCountryFinished(message) { + PageController.showBusyIndicator(false) + + PageController.goToPageHome() + PageController.showNotificationMessage(message) + } + + function onReloadServerFromApiFinished(message) { + PageController.goToPageHome() + PageController.showNotificationMessage(message) + } } Connections { @@ -151,6 +183,12 @@ PageType { function onImportErrorOccurred(error, goToPageHome) { PageController.showErrorMessage(error) } + + function onRestoreAppConfig(data) { + PageController.showBusyIndicator(true) + SettingsController.restoreAppConfigFromData(data) + PageController.showBusyIndicator(false) + } } Connections { @@ -159,6 +197,11 @@ PageType { function onLoggingDisableByWatcher() { PageController.showNotificationMessage(qsTr("Logging was disabled after 14 days, log files were deleted")) } + + function onRestoreBackupFinished() { + PageController.showNotificationMessage(qsTr("Settings restored from backup file")) + PageController.goToPageHome() + } } StackViewType { @@ -169,31 +212,37 @@ PageType { anchors.left: parent.left anchors.bottom: tabBar.top - width: parent.width - height: root.height - tabBar.implicitHeight - enabled: !root.isControlsDisabled function goToTabBarPage(page) { - connectionTypeSelection.close() - var pagePath = PageController.getPagePath(page) tabBarStackView.clear(StackView.Immediate) tabBarStackView.replace(pagePath, { "objectName" : pagePath }, StackView.Immediate) } Component.onCompleted: { - var pagePath = PageController.getPagePath(PageEnum.PageHome) - ServersModel.processedIndex = ServersModel.defaultIndex + var pagePath + if (PageController.isStartPageVisible()) { + tabBar.visible = false + pagePath = PageController.getPagePath(PageEnum.PageSetupWizardStart) + } else { + tabBar.visible = true + pagePath = PageController.getPagePath(PageEnum.PageHome) + ServersModel.processedIndex = ServersModel.defaultIndex + } + tabBarStackView.push(pagePath, { "objectName" : pagePath }) } + + Keys.onPressed: function(event) { + PageController.keyPressEvent(event.key) + event.accepted = true + } } TabBar { id: tabBar - property int previousIndex: 0 - anchors.right: parent.right anchors.left: parent.left anchors.bottom: parent.bottom @@ -203,6 +252,8 @@ PageType { leftPadding: 96 rightPadding: 96 + height: visible ? homeTabButton.implicitHeight + tabBar.topPadding + tabBar.bottomPadding : 0 + enabled: !root.isControlsDisabled && !root.isTabBarDisabled background: Shape { @@ -214,13 +265,13 @@ PageType { startY: 0 PathLine { x: width; y: 0 } - PathLine { x: width; y: height - 1 } - PathLine { x: 0; y: height - 1 } + PathLine { x: width; y: tabBar.height - 1 } + PathLine { x: 0; y: tabBar.height - 1 } PathLine { x: 0; y: 0 } strokeWidth: 1 - strokeColor: AmneziaStyle.color.greyDark - fillColor: AmneziaStyle.color.blackLight + strokeColor: AmneziaStyle.color.slateGray + fillColor: AmneziaStyle.color.onyxBlack } } @@ -232,7 +283,6 @@ PageType { tabBarStackView.goToTabBarPage(PageEnum.PageHome) ServersModel.processedIndex = ServersModel.defaultIndex tabBar.currentIndex = 0 - tabBar.previousIndex = 0 } KeyNavigation.tab: shareTabButton @@ -261,7 +311,6 @@ PageType { clickedFunc: function () { tabBarStackView.goToTabBarPage(PageEnum.PageShare) tabBar.currentIndex = 1 - tabBar.previousIndex = 1 } KeyNavigation.tab: settingsTabButton @@ -274,7 +323,6 @@ PageType { clickedFunc: function () { tabBarStackView.goToTabBarPage(PageEnum.PageSettings) tabBar.currentIndex = 2 - tabBar.previousIndex = 2 } KeyNavigation.tab: plusTabButton @@ -285,19 +333,11 @@ PageType { isSelected: tabBar.currentIndex === 3 image: "qrc:/images/controls/plus.svg" clickedFunc: function () { - connectionTypeSelection.open() + tabBarStackView.goToTabBarPage(PageEnum.PageSetupWizardConfigSource) + tabBar.currentIndex = 3 } Keys.onTabPressed: PageController.forceStackActiveFocus() } } - - ConnectionTypeSelectionDrawer { - id: connectionTypeSelection - - onAboutToHide: { - PageController.forceTabBarActiveFocus() - tabBar.setCurrentIndex(tabBar.previousIndex) - } - } } diff --git a/client/ui/qml/main2.qml b/client/ui/qml/main2.qml index ea775d26..a5a47e2c 100644 --- a/client/ui/qml/main2.qml +++ b/client/ui/qml/main2.qml @@ -10,6 +10,7 @@ import Style 1.0 import "Config" import "Controls2" import "Components" +import "Pages2" Window { id: root @@ -22,7 +23,7 @@ Window { maximumWidth: 600 maximumHeight: 800 - color: AmneziaStyle.color.black + color: AmneziaStyle.color.midnightBlack onClosing: function() { console.debug("QML onClosing signal") @@ -31,34 +32,9 @@ Window { title: "AmneziaVPN" - StackViewType { - id: rootStackView - - width: root.width - height: root.height - focus: true - - Component.onCompleted: { - var pagePath = PageController.getInitialPage() - rootStackView.push(pagePath, { "objectName" : pagePath }) - } - - Keys.onPressed: function(event) { - PageController.keyPressEvent(event.key) - event.accepted = true - } - } - Connections { target: PageController - function onReplaceStartPage() { - var pagePath = PageController.getInitialPage() - rootStackView.clear() - PageController.updateNavigationBarColor(PageController.getInitialPageNavigationBarColor()) - rootStackView.replace(pagePath, { "objectName" : pagePath }) - } - function onRaiseMainWindow() { root.show() root.raise() @@ -103,6 +79,10 @@ Window { } } + PageStart { + anchors.fill: parent + } + Item { anchors.right: parent.right anchors.left: parent.left @@ -196,10 +176,10 @@ Window { Layout.fillWidth: true defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.blackHovered - pressedColor: AmneziaStyle.color.blackPressed - disabledColor: AmneziaStyle.color.grey - textColor: AmneziaStyle.color.white + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray borderWidth: 1 text: qsTr("Save") diff --git a/ipc/ipc_interface.rep b/ipc/ipc_interface.rep index c180cb87..07277191 100644 --- a/ipc/ipc_interface.rep +++ b/ipc/ipc_interface.rep @@ -21,6 +21,7 @@ class IpcInterface SLOT( void cleanUp() ); SLOT( void setLogsEnabled(bool enabled) ); + SLOT( void clearLogs() ); SLOT( bool createTun(const QString &dev, const QString &subnet) ); SLOT( bool deleteTun(const QString &dev) ); diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index f2a2da4f..d236edd7 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -163,6 +163,10 @@ void IpcServer::cleanUp() Logger::cleanUp(); } +void IpcServer::clearLogs() { + Logger::clearLogs(); +} + bool IpcServer::createTun(const QString &dev, const QString &subnet) { return Router::createTun(dev, subnet); diff --git a/ipc/ipcserver.h b/ipc/ipcserver.h index 67c6f777..296c2ce1 100644 --- a/ipc/ipcserver.h +++ b/ipc/ipcserver.h @@ -26,6 +26,7 @@ public: virtual bool checkAndInstallDriver() override; virtual QStringList getTapList() override; virtual void cleanUp() override; + virtual void clearLogs() override; virtual void setLogsEnabled(bool enabled) override; virtual bool createTun(const QString &dev, const QString &subnet) override; virtual bool deleteTun(const QString &dev) override; diff --git a/service/server/main.cpp b/service/server/main.cpp index 495192c3..144ddf60 100644 --- a/service/server/main.cpp +++ b/service/server/main.cpp @@ -46,8 +46,6 @@ int main(int argc, char **argv) { Utils::initializePath(Utils::systemLogPath()); - Logger::init(); - if (argc >= 2) { qInfo() << "Started as console application"; return runApplication(argc, argv);