mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 129ae44edc | |||
| 16fc44f989 | |||
| ef909d3605 | |||
| b9ca3315c6 | |||
| e9ed5b59a4 | |||
| 047dbb2677 | |||
| e9efe32f9b | |||
| 2dd3531e78 | |||
| 129f79ca2c | |||
| 50769f231d |
@@ -547,7 +547,7 @@ jobs:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
ANDROID_BUILD_PLATFORM: android-36
|
ANDROID_BUILD_PLATFORM: android-36
|
||||||
QT_VERSION: 6.10.1
|
QT_VERSION: 6.11.1
|
||||||
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
||||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||||
|
|
||||||
set(PROJECT AmneziaVPN)
|
set(PROJECT AmneziaVPN)
|
||||||
set(AMNEZIAVPN_VERSION 4.8.15.4)
|
set(AMNEZIAVPN_VERSION 4.8.19.0)
|
||||||
|
|
||||||
project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}
|
project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}
|
||||||
DESCRIPTION "AmneziaVPN"
|
DESCRIPTION "AmneziaVPN"
|
||||||
@@ -12,7 +12,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
|||||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||||
|
|
||||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||||
set(APP_ANDROID_VERSION_CODE 2120)
|
set(APP_ANDROID_VERSION_CODE 2129)
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
set(MZ_PLATFORM_NAME "linux")
|
set(MZ_PLATFORM_NAME "linux")
|
||||||
|
|||||||
+1
-1
Submodule client/3rd-prebuilt updated: 51bb4703a4...4680bd8fb4
@@ -792,6 +792,16 @@ class AmneziaActivity : QtActivity() {
|
|||||||
else -> type = "*/*"
|
else -> type = "*/*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Force system document picker to avoid third-party file managers
|
||||||
|
// that may lack storage permissions (common on Android TV devices)
|
||||||
|
val systemPickerPackage = listOf("com.google.android.documentsui", "com.android.documentsui")
|
||||||
|
.firstOrNull { pkg ->
|
||||||
|
try { packageManager.getPackageInfo(pkg, 0); true }
|
||||||
|
catch (_: PackageManager.NameNotFoundException) { false }
|
||||||
|
}
|
||||||
|
if (systemPickerPackage != null) {
|
||||||
|
`package` = systemPickerPackage
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Intent(this@AmneziaActivity, TvFilePicker::class.java)
|
Intent(this@AmneziaActivity, TvFilePicker::class.java)
|
||||||
@@ -1064,13 +1074,11 @@ class AmneziaActivity : QtActivity() {
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun sendTouch(x: Float, y: Float) {
|
fun sendTouch(x: Float, y: Float) {
|
||||||
Log.v(TAG, "Send touch: $x, $y")
|
Log.v(TAG, "Send touch: $x, $y")
|
||||||
blockingCall {
|
|
||||||
findQtWindow(window.decorView)?.let {
|
findQtWindow(window.decorView)?.let {
|
||||||
Log.v(TAG, "Send touch to $it")
|
Log.v(TAG, "Send touch to $it")
|
||||||
it.dispatchTouchEvent(createEvent(x, y, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN))
|
it.dispatchTouchEvent(createEvent(x, y, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN))
|
||||||
it.dispatchTouchEvent(createEvent(x, y, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP))
|
it.dispatchTouchEvent(createEvent(x, y, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findQtWindow(view: View): View? {
|
private fun findQtWindow(view: View): View? {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "amnezia_application.h"
|
#include "amnezia_application.h"
|
||||||
#include "core/api/apiUtils.h"
|
#include "core/api/apiUtils.h"
|
||||||
#include "core/networkUtilities.h"
|
#include "core/networkUtilities.h"
|
||||||
|
#include "settings.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
@@ -51,15 +52,78 @@ namespace
|
|||||||
constexpr QLatin1String unprocessableSubscriptionMessage("Failed to retrieve subscription information. Is it activated?");
|
constexpr QLatin1String unprocessableSubscriptionMessage("Failed to retrieve subscription information. Is it activated?");
|
||||||
|
|
||||||
constexpr int proxyStorageRequestTimeoutMsecs = 3000;
|
constexpr int proxyStorageRequestTimeoutMsecs = 3000;
|
||||||
|
|
||||||
|
QStringList shuffledProxyUrls(const QStringList &proxyUrls)
|
||||||
|
{
|
||||||
|
QStringList shuffled = proxyUrls;
|
||||||
|
std::random_device randomDevice;
|
||||||
|
std::mt19937 generator(randomDevice());
|
||||||
|
std::shuffle(shuffled.begin(), shuffled.end(), generator);
|
||||||
|
return shuffled;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getProxyUrlsCacheKey(const QString &serviceType, const QString &userCountryCode)
|
||||||
|
{
|
||||||
|
return QStringLiteral("service_%1_country_%2").arg(serviceType, userCountryCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool decryptProxyUrlsPayload(const QByteArray &encryptedPayload, bool isDevEnvironment, QByteArray &decryptedPayload)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
QByteArray key = isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
|
||||||
|
if (!isDevEnvironment) {
|
||||||
|
QCryptographicHash hash(QCryptographicHash::Sha512);
|
||||||
|
hash.addData(key);
|
||||||
|
QByteArray h = hash.result().toHex();
|
||||||
|
|
||||||
|
QByteArray decKey = QByteArray::fromHex(h.left(64));
|
||||||
|
QByteArray iv = QByteArray::fromHex(h.mid(64, 32));
|
||||||
|
QByteArray ba = QByteArray::fromBase64(encryptedPayload);
|
||||||
|
|
||||||
|
QSimpleCrypto::QBlockCipher cipher;
|
||||||
|
decryptedPayload = cipher.decryptAesBlockCipher(ba, decKey, iv);
|
||||||
|
} else {
|
||||||
|
decryptedPayload = encryptedPayload;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (...) {
|
||||||
|
Utils::logException();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList readCachedProxyUrls(const QByteArray &cachedProxyUrlsEncrypted, bool isDevEnvironment)
|
||||||
|
{
|
||||||
|
if (cachedProxyUrlsEncrypted.isEmpty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray cachedProxyUrlsDecrypted;
|
||||||
|
if (!decryptProxyUrlsPayload(cachedProxyUrlsEncrypted, isDevEnvironment, cachedProxyUrlsDecrypted)) {
|
||||||
|
qCritical() << "error decrypting cached proxy urls payload";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray endpointsArray = QJsonDocument::fromJson(cachedProxyUrlsDecrypted).array();
|
||||||
|
QStringList endpoints;
|
||||||
|
endpoints.reserve(endpointsArray.size());
|
||||||
|
for (const QJsonValue &endpoint : endpointsArray) {
|
||||||
|
endpoints.push_back(endpoint.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpoints;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GatewayController::GatewayController(const QString &gatewayEndpoint, const bool isDevEnvironment, const int requestTimeoutMsecs,
|
GatewayController::GatewayController(const QString &gatewayEndpoint, const bool isDevEnvironment, const int requestTimeoutMsecs,
|
||||||
const bool isStrictKillSwitchEnabled, QObject *parent)
|
const bool isStrictKillSwitchEnabled, const std::shared_ptr<Settings> &settings,
|
||||||
|
QObject *parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
m_gatewayEndpoint(gatewayEndpoint),
|
m_gatewayEndpoint(gatewayEndpoint),
|
||||||
m_isDevEnvironment(isDevEnvironment),
|
m_isDevEnvironment(isDevEnvironment),
|
||||||
m_requestTimeoutMsecs(requestTimeoutMsecs),
|
m_requestTimeoutMsecs(requestTimeoutMsecs),
|
||||||
m_isStrictKillSwitchEnabled(isStrictKillSwitchEnabled)
|
m_isStrictKillSwitchEnabled(isStrictKillSwitchEnabled),
|
||||||
|
m_settings(settings)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,8 +374,9 @@ QFuture<QPair<ErrorCode, QByteArray>> GatewayController::postAsync(const QString
|
|||||||
QStringList proxyStorageUrls;
|
QStringList proxyStorageUrls;
|
||||||
appendStorageUrls(primaryBaseUrls, proxyStorageUrls);
|
appendStorageUrls(primaryBaseUrls, proxyStorageUrls);
|
||||||
appendStorageUrls(fallbackBaseUrls, proxyStorageUrls);
|
appendStorageUrls(fallbackBaseUrls, proxyStorageUrls);
|
||||||
|
const QString proxyUrlsCacheKey = getProxyUrlsCacheKey(serviceType, userCountryCode);
|
||||||
|
|
||||||
getProxyUrlsAsync(proxyStorageUrls, 0, [this, encRequestData, endpoint, processResponse](const QStringList &proxyUrls) {
|
getProxyUrlsAsync(proxyStorageUrls, 0, proxyUrlsCacheKey, [this, encRequestData, endpoint, processResponse](const QStringList &proxyUrls) {
|
||||||
getProxyUrlAsync(proxyUrls, 0, [this, encRequestData, endpoint, processResponse](const QString &proxyUrl) {
|
getProxyUrlAsync(proxyUrls, 0, [this, encRequestData, endpoint, processResponse](const QString &proxyUrl) {
|
||||||
bypassProxyAsync(endpoint, proxyUrl, encRequestData,
|
bypassProxyAsync(endpoint, proxyUrl, encRequestData,
|
||||||
[processResponse, this](const QByteArray &decryptedBody, bool isDecryptionSuccessful,
|
[processResponse, this](const QByteArray &decryptedBody, bool isDecryptionSuccessful,
|
||||||
@@ -357,8 +422,6 @@ QStringList GatewayController::getProxyUrls(const QString &serviceType, const QS
|
|||||||
std::shuffle(primaryBaseUrls.begin(), primaryBaseUrls.end(), generator);
|
std::shuffle(primaryBaseUrls.begin(), primaryBaseUrls.end(), generator);
|
||||||
std::shuffle(fallbackBaseUrls.begin(), fallbackBaseUrls.end(), generator);
|
std::shuffle(fallbackBaseUrls.begin(), fallbackBaseUrls.end(), generator);
|
||||||
|
|
||||||
QByteArray key = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
|
|
||||||
|
|
||||||
auto appendStorageUrls = [&serviceType, &userCountryCode](const QStringList &baseUrls, QStringList &target) {
|
auto appendStorageUrls = [&serviceType, &userCountryCode](const QStringList &baseUrls, QStringList &target) {
|
||||||
if (!serviceType.isEmpty()) {
|
if (!serviceType.isEmpty()) {
|
||||||
for (const auto &baseUrl : baseUrls) {
|
for (const auto &baseUrl : baseUrls) {
|
||||||
@@ -374,10 +437,12 @@ QStringList GatewayController::getProxyUrls(const QString &serviceType, const QS
|
|||||||
QStringList proxyStorageUrls;
|
QStringList proxyStorageUrls;
|
||||||
appendStorageUrls(primaryBaseUrls, proxyStorageUrls);
|
appendStorageUrls(primaryBaseUrls, proxyStorageUrls);
|
||||||
appendStorageUrls(fallbackBaseUrls, proxyStorageUrls);
|
appendStorageUrls(fallbackBaseUrls, proxyStorageUrls);
|
||||||
|
const QString proxyUrlsCacheKey = getProxyUrlsCacheKey(serviceType, userCountryCode);
|
||||||
|
const QByteArray cachedProxyUrlsEncrypted = m_settings->readGatewayProxyUrls(proxyUrlsCacheKey);
|
||||||
|
|
||||||
if (proxyStorageUrls.empty()) {
|
if (proxyStorageUrls.empty()) {
|
||||||
qDebug() << "empty storage endpoint list";
|
qDebug() << "empty storage endpoint list";
|
||||||
return {};
|
return readCachedProxyUrls(cachedProxyUrlsEncrypted, m_isDevEnvironment);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &proxyStorageUrl : proxyStorageUrls) {
|
for (const auto &proxyStorageUrl : proxyStorageUrls) {
|
||||||
@@ -392,26 +457,8 @@ QStringList GatewayController::getProxyUrls(const QString &serviceType, const QS
|
|||||||
auto encryptedResponseBody = reply->readAll();
|
auto encryptedResponseBody = reply->readAll();
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
|
||||||
EVP_PKEY *privateKey = nullptr;
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
try {
|
if (!decryptProxyUrlsPayload(encryptedResponseBody, m_isDevEnvironment, responseBody)) {
|
||||||
if (!m_isDevEnvironment) {
|
|
||||||
QCryptographicHash hash(QCryptographicHash::Sha512);
|
|
||||||
hash.addData(key);
|
|
||||||
QByteArray hashResult = hash.result().toHex();
|
|
||||||
|
|
||||||
QByteArray key = QByteArray::fromHex(hashResult.left(64));
|
|
||||||
QByteArray iv = QByteArray::fromHex(hashResult.mid(64, 32));
|
|
||||||
|
|
||||||
QByteArray ba = QByteArray::fromBase64(encryptedResponseBody);
|
|
||||||
|
|
||||||
QSimpleCrypto::QBlockCipher blockCipher;
|
|
||||||
responseBody = blockCipher.decryptAesBlockCipher(ba, key, iv);
|
|
||||||
} else {
|
|
||||||
responseBody = encryptedResponseBody;
|
|
||||||
}
|
|
||||||
} catch (...) {
|
|
||||||
Utils::logException();
|
|
||||||
qCritical() << "error loading private key from environment variables or decrypting payload" << encryptedResponseBody;
|
qCritical() << "error loading private key from environment variables or decrypting payload" << encryptedResponseBody;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -422,6 +469,8 @@ QStringList GatewayController::getProxyUrls(const QString &serviceType, const QS
|
|||||||
for (const auto &endpoint : endpointsArray) {
|
for (const auto &endpoint : endpointsArray) {
|
||||||
endpoints.push_back(endpoint.toString());
|
endpoints.push_back(endpoint.toString());
|
||||||
}
|
}
|
||||||
|
m_settings->writeGatewayProxyUrls(proxyUrlsCacheKey, encryptedResponseBody);
|
||||||
|
|
||||||
return endpoints;
|
return endpoints;
|
||||||
} else {
|
} else {
|
||||||
auto replyError = reply->error();
|
auto replyError = reply->error();
|
||||||
@@ -433,7 +482,7 @@ QStringList GatewayController::getProxyUrls(const QString &serviceType, const QS
|
|||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return readCachedProxyUrls(cachedProxyUrlsEncrypted, m_isDevEnvironment);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GatewayController::shouldBypassProxy(const QNetworkReply::NetworkError &replyError, const QByteArray &decryptedResponseBody,
|
bool GatewayController::shouldBypassProxy(const QNetworkReply::NetworkError &replyError, const QByteArray &decryptedResponseBody,
|
||||||
@@ -571,10 +620,12 @@ void GatewayController::bypassProxy(const QString &endpoint, const QString &serv
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GatewayController::getProxyUrlsAsync(const QStringList proxyStorageUrls, const int currentProxyStorageIndex,
|
void GatewayController::getProxyUrlsAsync(const QStringList proxyStorageUrls, const int currentProxyStorageIndex,
|
||||||
std::function<void(const QStringList &)> onComplete)
|
const QString &proxyUrlsCacheKey, std::function<void(const QStringList &)> onComplete)
|
||||||
{
|
{
|
||||||
|
const QByteArray cachedProxyUrlsEncrypted = m_settings->readGatewayProxyUrls(proxyUrlsCacheKey);
|
||||||
|
|
||||||
if (currentProxyStorageIndex >= proxyStorageUrls.size()) {
|
if (currentProxyStorageIndex >= proxyStorageUrls.size()) {
|
||||||
onComplete({});
|
onComplete(shuffledProxyUrls(readCachedProxyUrls(cachedProxyUrlsEncrypted, m_isDevEnvironment)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -587,33 +638,17 @@ void GatewayController::getProxyUrlsAsync(const QStringList proxyStorageUrls, co
|
|||||||
|
|
||||||
// connect(reply, &QNetworkReply::sslErrors, this, [state](const QList<QSslError> &e) { *(state->sslErrors) = e; });
|
// connect(reply, &QNetworkReply::sslErrors, this, [state](const QList<QSslError> &e) { *(state->sslErrors) = e; });
|
||||||
|
|
||||||
connect(reply, &QNetworkReply::finished, this, [this, proxyStorageUrls, currentProxyStorageIndex, onComplete, reply]() {
|
connect(reply, &QNetworkReply::finished, this,
|
||||||
|
[this, proxyStorageUrls, currentProxyStorageIndex, proxyUrlsCacheKey, onComplete, reply]() {
|
||||||
if (reply->error() == QNetworkReply::NoError) {
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
QByteArray encrypted = reply->readAll();
|
QByteArray encrypted = reply->readAll();
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
try {
|
if (!decryptProxyUrlsPayload(encrypted, m_isDevEnvironment, responseBody)) {
|
||||||
QByteArray key = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
|
|
||||||
if (!m_isDevEnvironment) {
|
|
||||||
QCryptographicHash hash(QCryptographicHash::Sha512);
|
|
||||||
hash.addData(key);
|
|
||||||
QByteArray h = hash.result().toHex();
|
|
||||||
|
|
||||||
QByteArray decKey = QByteArray::fromHex(h.left(64));
|
|
||||||
QByteArray iv = QByteArray::fromHex(h.mid(64, 32));
|
|
||||||
QByteArray ba = QByteArray::fromBase64(encrypted);
|
|
||||||
|
|
||||||
QSimpleCrypto::QBlockCipher cipher;
|
|
||||||
responseBody = cipher.decryptAesBlockCipher(ba, decKey, iv);
|
|
||||||
} else {
|
|
||||||
responseBody = encrypted;
|
|
||||||
}
|
|
||||||
} catch (...) {
|
|
||||||
Utils::logException();
|
|
||||||
qCritical() << "error decrypting payload";
|
qCritical() << "error decrypting payload";
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
this, [=]() { getProxyUrlsAsync(proxyStorageUrls, currentProxyStorageIndex + 1, onComplete); }, Qt::QueuedConnection);
|
this, [=]() { getProxyUrlsAsync(proxyStorageUrls, currentProxyStorageIndex + 1, proxyUrlsCacheKey, onComplete); }, Qt::QueuedConnection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,13 +656,9 @@ void GatewayController::getProxyUrlsAsync(const QStringList proxyStorageUrls, co
|
|||||||
QStringList endpoints;
|
QStringList endpoints;
|
||||||
for (const QJsonValue &endpoint : endpointsArray)
|
for (const QJsonValue &endpoint : endpointsArray)
|
||||||
endpoints.push_back(endpoint.toString());
|
endpoints.push_back(endpoint.toString());
|
||||||
|
m_settings->writeGatewayProxyUrls(proxyUrlsCacheKey, encrypted);
|
||||||
|
|
||||||
QStringList shuffled = endpoints;
|
onComplete(shuffledProxyUrls(endpoints));
|
||||||
std::random_device randomDevice;
|
|
||||||
std::mt19937 generator(randomDevice());
|
|
||||||
std::shuffle(shuffled.begin(), shuffled.end(), generator);
|
|
||||||
|
|
||||||
onComplete(shuffled);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,7 +667,7 @@ void GatewayController::getProxyUrlsAsync(const QStringList proxyStorageUrls, co
|
|||||||
qDebug() << "go to the next storage endpoint";
|
qDebug() << "go to the next storage endpoint";
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
this, [=]() { getProxyUrlsAsync(proxyStorageUrls, currentProxyStorageIndex + 1, onComplete); }, Qt::QueuedConnection);
|
this, [=]() { getProxyUrlsAsync(proxyStorageUrls, currentProxyStorageIndex + 1, proxyUrlsCacheKey, onComplete); }, Qt::QueuedConnection);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
#include <QPair>
|
#include <QPair>
|
||||||
#include <QPromise>
|
#include <QPromise>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "core/defs.h"
|
#include "core/defs.h"
|
||||||
|
|
||||||
@@ -14,13 +17,16 @@
|
|||||||
#include "platforms/ios/ios_controller.h"
|
#include "platforms/ios/ios_controller.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class Settings;
|
||||||
|
|
||||||
class GatewayController : public QObject
|
class GatewayController : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit GatewayController(const QString &gatewayEndpoint, const bool isDevEnvironment, const int requestTimeoutMsecs,
|
explicit GatewayController(const QString &gatewayEndpoint, const bool isDevEnvironment, const int requestTimeoutMsecs,
|
||||||
const bool isStrictKillSwitchEnabled, QObject *parent = nullptr);
|
const bool isStrictKillSwitchEnabled, const std::shared_ptr<Settings> &settings,
|
||||||
|
QObject *parent = nullptr);
|
||||||
|
|
||||||
amnezia::ErrorCode post(const QString &endpoint, const QJsonObject apiPayload, QByteArray &responseBody);
|
amnezia::ErrorCode post(const QString &endpoint, const QJsonObject apiPayload, QByteArray &responseBody);
|
||||||
QFuture<QPair<amnezia::ErrorCode, QByteArray>> postAsync(const QString &endpoint, const QJsonObject apiPayload);
|
QFuture<QPair<amnezia::ErrorCode, QByteArray>> postAsync(const QString &endpoint, const QJsonObject apiPayload);
|
||||||
@@ -53,7 +59,7 @@ private:
|
|||||||
std::function<bool(QNetworkReply *reply, const QList<QSslError> &sslErrors)> replyProcessingFunction);
|
std::function<bool(QNetworkReply *reply, const QList<QSslError> &sslErrors)> replyProcessingFunction);
|
||||||
|
|
||||||
void getProxyUrlsAsync(const QStringList proxyStorageUrls, const int currentProxyStorageIndex,
|
void getProxyUrlsAsync(const QStringList proxyStorageUrls, const int currentProxyStorageIndex,
|
||||||
std::function<void(const QStringList &)> onComplete);
|
const QString &proxyUrlsCacheKey, std::function<void(const QStringList &)> onComplete);
|
||||||
void getProxyUrlAsync(const QStringList proxyUrls, const int currentProxyIndex, std::function<void(const QString &)> onComplete);
|
void getProxyUrlAsync(const QStringList proxyUrls, const int currentProxyIndex, std::function<void(const QString &)> onComplete);
|
||||||
void bypassProxyAsync(
|
void bypassProxyAsync(
|
||||||
const QString &endpoint, const QString &proxyUrl, EncryptedRequestData encRequestData,
|
const QString &endpoint, const QString &proxyUrl, EncryptedRequestData encRequestData,
|
||||||
@@ -63,6 +69,7 @@ private:
|
|||||||
QString m_gatewayEndpoint;
|
QString m_gatewayEndpoint;
|
||||||
bool m_isDevEnvironment = false;
|
bool m_isDevEnvironment = false;
|
||||||
bool m_isStrictKillSwitchEnabled = false;
|
bool m_isStrictKillSwitchEnabled = false;
|
||||||
|
std::shared_ptr<Settings> m_settings;
|
||||||
|
|
||||||
inline static QString m_proxyUrl;
|
inline static QString m_proxyUrl;
|
||||||
};
|
};
|
||||||
|
|||||||
+32
-32
@@ -390,55 +390,55 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
|
|||||||
|
|
||||||
config.m_killSwitchEnabled = QVariant(obj.value("killSwitchOption").toString()).toBool();
|
config.m_killSwitchEnabled = QVariant(obj.value("killSwitchOption").toString()).toBool();
|
||||||
|
|
||||||
if (!obj.value("Jc").isNull()) {
|
if (const auto jc = obj.value("Jc"); !jc.isUndefined()) {
|
||||||
config.m_junkPacketCount = obj.value("Jc").toString();
|
config.m_junkPacketCount = jc.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("Jmin").isNull()) {
|
if (const auto jmin = obj.value("Jmin"); !jmin.isUndefined()) {
|
||||||
config.m_junkPacketMinSize = obj.value("Jmin").toString();
|
config.m_junkPacketMinSize = jmin.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("Jmax").isNull()) {
|
if (const auto jmax = obj.value("Jmax"); !jmax.isUndefined()) {
|
||||||
config.m_junkPacketMaxSize = obj.value("Jmax").toString();
|
config.m_junkPacketMaxSize = jmax.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("S1").isNull()) {
|
if (const auto s1 = obj.value("S1"); !s1.isUndefined()) {
|
||||||
config.m_initPacketJunkSize = obj.value("S1").toString();
|
config.m_initPacketJunkSize = s1.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("S2").isNull()) {
|
if (const auto s2 = obj.value("S2"); !s2.isUndefined()) {
|
||||||
config.m_responsePacketJunkSize = obj.value("S2").toString();
|
config.m_responsePacketJunkSize = s2.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("S3").isNull()) {
|
if (const auto s3 = obj.value("S3"); !s3.isUndefined()) {
|
||||||
config.m_cookieReplyPacketJunkSize = obj.value("S3").toString();
|
config.m_cookieReplyPacketJunkSize = s3.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("S4").isNull()) {
|
if (const auto s4 = obj.value("S4"); !s4.isUndefined()) {
|
||||||
config.m_transportPacketJunkSize = obj.value("S4").toString();
|
config.m_transportPacketJunkSize = s4.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!obj.value("H1").isNull()) {
|
if (const auto h1 = obj.value("H1"); !h1.isUndefined()) {
|
||||||
config.m_initPacketMagicHeader = obj.value("H1").toString();
|
config.m_initPacketMagicHeader = h1.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("H2").isNull()) {
|
if (const auto h2 = obj.value("H2"); !h2.isUndefined()) {
|
||||||
config.m_responsePacketMagicHeader = obj.value("H2").toString();
|
config.m_responsePacketMagicHeader = h2.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("H3").isNull()) {
|
if (const auto h3 = obj.value("H3"); !h3.isUndefined()) {
|
||||||
config.m_underloadPacketMagicHeader = obj.value("H3").toString();
|
config.m_underloadPacketMagicHeader = h3.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("H4").isNull()) {
|
if (const auto h4 = obj.value("H4"); !h4.isUndefined()) {
|
||||||
config.m_transportPacketMagicHeader = obj.value("H4").toString();
|
config.m_transportPacketMagicHeader = h4.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!obj.value("I1").isNull()) {
|
if (const auto i1 = obj.value("I1"); !i1.isUndefined()) {
|
||||||
config.m_specialJunk["I1"] = obj.value("I1").toString();
|
config.m_specialJunk["I1"] = i1.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("I2").isNull()) {
|
if (const auto i2 = obj.value("I2"); !i2.isUndefined()) {
|
||||||
config.m_specialJunk["I2"] = obj.value("I2").toString();
|
config.m_specialJunk["I2"] = i2.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("I3").isNull()) {
|
if (const auto i3 = obj.value("I3"); !i3.isUndefined()) {
|
||||||
config.m_specialJunk["I3"] = obj.value("I3").toString();
|
config.m_specialJunk["I3"] = i3.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("I4").isNull()) {
|
if (const auto i4 = obj.value("I4"); !i4.isUndefined()) {
|
||||||
config.m_specialJunk["I4"] = obj.value("I4").toString();
|
config.m_specialJunk["I4"] = i4.toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("I5").isNull()) {
|
if (const auto i5 = obj.value("I5"); !i5.isUndefined()) {
|
||||||
config.m_specialJunk["I5"] = obj.value("I5").toString();
|
config.m_specialJunk["I5"] = i5.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace
|
|||||||
const char cloudFlareNs2[] = "1.0.0.1";
|
const char cloudFlareNs2[] = "1.0.0.1";
|
||||||
|
|
||||||
constexpr char gatewayEndpoint[] = "http://gw.amnezia.org:80/";
|
constexpr char gatewayEndpoint[] = "http://gw.amnezia.org:80/";
|
||||||
|
constexpr char proxyUrlsKey[] = "Conf/proxyUrls/";
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::Settings(QObject *parent) : QObject(parent), m_settings(ORGANIZATION_NAME, APPLICATION_NAME, this)
|
Settings::Settings(QObject *parent) : QObject(parent), m_settings(ORGANIZATION_NAME, APPLICATION_NAME, this)
|
||||||
@@ -526,6 +527,24 @@ void Settings::toggleDevGatewayEnv(bool enabled)
|
|||||||
m_settings.setValue("Conf/devGatewayEnv", enabled);
|
m_settings.setValue("Conf/devGatewayEnv", enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray Settings::readGatewayProxyUrls(const QString &cacheKey) const
|
||||||
|
{
|
||||||
|
if (cacheKey.isEmpty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_settings.value(QString(proxyUrlsKey) + cacheKey).toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::writeGatewayProxyUrls(const QString &cacheKey, const QByteArray &proxyUrlsEncrypted)
|
||||||
|
{
|
||||||
|
if (cacheKey.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_settings.setValue(QString(proxyUrlsKey) + cacheKey, proxyUrlsEncrypted);
|
||||||
|
}
|
||||||
|
|
||||||
bool Settings::isHomeAdLabelVisible()
|
bool Settings::isHomeAdLabelVisible()
|
||||||
{
|
{
|
||||||
return m_settings.value("Conf/homeAdLabelVisible", true).toBool();
|
return m_settings.value("Conf/homeAdLabelVisible", true).toBool();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
@@ -234,6 +235,8 @@ public:
|
|||||||
QString getGatewayEndpoint(bool isTestPurchase = false);
|
QString getGatewayEndpoint(bool isTestPurchase = false);
|
||||||
bool isDevGatewayEnv(bool isTestPurchase = false);
|
bool isDevGatewayEnv(bool isTestPurchase = false);
|
||||||
void toggleDevGatewayEnv(bool enabled);
|
void toggleDevGatewayEnv(bool enabled);
|
||||||
|
QByteArray readGatewayProxyUrls(const QString &cacheKey) const;
|
||||||
|
void writeGatewayProxyUrls(const QString &cacheKey, const QByteArray &proxyUrlsEncrypted);
|
||||||
|
|
||||||
bool isHomeAdLabelVisible();
|
bool isHomeAdLabelVisible();
|
||||||
void disableHomeAdLabel();
|
void disableHomeAdLabel();
|
||||||
|
|||||||
@@ -1027,7 +1027,7 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||||
m_settings->isStrictKillSwitchEnabled());
|
m_settings->isStrictKillSwitchEnabled(), m_settings);
|
||||||
|
|
||||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||||
auto installationUuid = m_settings->getInstallationUuid(true);
|
auto installationUuid = m_settings->getInstallationUuid(true);
|
||||||
@@ -1273,6 +1273,6 @@ ErrorCode ApiConfigsController::executeRequest(const QString &endpoint, const QJ
|
|||||||
bool isTestPurchase)
|
bool isTestPurchase)
|
||||||
{
|
{
|
||||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(isTestPurchase), m_settings->isDevGatewayEnv(isTestPurchase),
|
GatewayController gatewayController(m_settings->getGatewayEndpoint(isTestPurchase), m_settings->isDevGatewayEnv(isTestPurchase),
|
||||||
apiDefs::requestTimeoutMsecs, m_settings->isStrictKillSwitchEnabled());
|
apiDefs::requestTimeoutMsecs, m_settings->isStrictKillSwitchEnabled(), m_settings);
|
||||||
return gatewayController.post(endpoint, apiPayload, responseBody);
|
return gatewayController.post(endpoint, apiPayload, responseBody);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ void ApiNewsController::fetchNews(bool showError)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto gatewayController = QSharedPointer<GatewayController>::create(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(),
|
auto gatewayController = QSharedPointer<GatewayController>::create(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(),
|
||||||
apiDefs::requestTimeoutMsecs, m_settings->isStrictKillSwitchEnabled());
|
apiDefs::requestTimeoutMsecs,
|
||||||
|
m_settings->isStrictKillSwitchEnabled(), m_settings);
|
||||||
QJsonObject payload;
|
QJsonObject payload;
|
||||||
payload.insert("locale", m_settings->getAppLanguage().name().split("_").first());
|
payload.insert("locale", m_settings->getAppLanguage().name().split("_").first());
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ bool ApiSettingsController::getAccountInfo(bool reload)
|
|||||||
|
|
||||||
bool isTestPurchase = apiConfig.value(apiDefs::key::isTestPurchase).toBool(false);
|
bool isTestPurchase = apiConfig.value(apiDefs::key::isTestPurchase).toBool(false);
|
||||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(isTestPurchase), m_settings->isDevGatewayEnv(isTestPurchase),
|
GatewayController gatewayController(m_settings->getGatewayEndpoint(isTestPurchase), m_settings->isDevGatewayEnv(isTestPurchase),
|
||||||
requestTimeoutMsecs, m_settings->isStrictKillSwitchEnabled());
|
requestTimeoutMsecs, m_settings->isStrictKillSwitchEnabled(), m_settings);
|
||||||
|
|
||||||
QJsonObject apiPayload;
|
QJsonObject apiPayload;
|
||||||
apiPayload[configKey::userCountryCode] = apiConfig.value(configKey::userCountryCode).toString();
|
apiPayload[configKey::userCountryCode] = apiConfig.value(configKey::userCountryCode).toString();
|
||||||
@@ -110,7 +110,7 @@ void ApiSettingsController::getRenewalLink()
|
|||||||
auto gatewayController = QSharedPointer<GatewayController>::create(m_settings->getGatewayEndpoint(isTestPurchase),
|
auto gatewayController = QSharedPointer<GatewayController>::create(m_settings->getGatewayEndpoint(isTestPurchase),
|
||||||
m_settings->isDevGatewayEnv(isTestPurchase),
|
m_settings->isDevGatewayEnv(isTestPurchase),
|
||||||
requestTimeoutMsecs,
|
requestTimeoutMsecs,
|
||||||
m_settings->isStrictKillSwitchEnabled());
|
m_settings->isStrictKillSwitchEnabled(), m_settings);
|
||||||
|
|
||||||
QJsonObject apiPayload;
|
QJsonObject apiPayload;
|
||||||
apiPayload[configKey::userCountryCode] = apiConfig.value(configKey::userCountryCode).toString();
|
apiPayload[configKey::userCountryCode] = apiConfig.value(configKey::userCountryCode).toString();
|
||||||
|
|||||||
Reference in New Issue
Block a user