chore: minor ui fixes (#1446)

* chore: minor ui fixes

* chore: update ru translation file

* bugfix: fixed config update by ttl for gateway configs

* bugfix: fixed proxy bypassing

* chore: minor ui fixes

* chore: update ru translation file

* chore: bump version
This commit is contained in:
Nethius 2025-03-04 13:33:35 +07:00 committed by GitHub
parent 728b48044c
commit 678bfffe49
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 963 additions and 401 deletions

View file

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
project(${PROJECT} VERSION 4.8.4.2
project(${PROJECT} VERSION 4.8.4.3
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 2079)
set(APP_ANDROID_VERSION_CODE 2080)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")

View file

@ -157,12 +157,12 @@ ErrorCode GatewayController::post(const QString &endpoint, const QJsonObject api
auto replyProcessingFunction = [&encryptedResponseBody, &reply, &sslErrors, &key, &iv, &salt,
this](QNetworkReply *nestedReply, const QList<QSslError> &nestedSslErrors) {
encryptedResponseBody = nestedReply->readAll();
if (!sslErrors.isEmpty() || !shouldBypassProxy(nestedReply, encryptedResponseBody, true, key, iv, salt)) {
reply = nestedReply;
if (!sslErrors.isEmpty() || shouldBypassProxy(nestedReply, encryptedResponseBody, true, key, iv, salt)) {
sslErrors = nestedSslErrors;
reply = nestedReply;
return true;
return false;
}
return false;
return true;
};
bypassProxy(endpoint, reply, requestFunction, replyProcessingFunction);
@ -212,45 +212,45 @@ QStringList GatewayController::getProxyUrls()
wait.exec();
if (reply->error() == QNetworkReply::NetworkError::NoError) {
break;
}
reply->deleteLater();
}
auto encryptedResponseBody = reply->readAll();
reply->deleteLater();
auto encryptedResponseBody = reply->readAll();
reply->deleteLater();
EVP_PKEY *privateKey = nullptr;
QByteArray responseBody;
try {
if (!m_isDevEnvironment) {
QCryptographicHash hash(QCryptographicHash::Sha512);
hash.addData(key);
QByteArray hashResult = hash.result().toHex();
EVP_PKEY *privateKey = nullptr;
QByteArray responseBody;
try {
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 key = QByteArray::fromHex(hashResult.left(64));
QByteArray iv = QByteArray::fromHex(hashResult.mid(64, 32));
QByteArray ba = QByteArray::fromBase64(encryptedResponseBody);
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;
continue;
}
QSimpleCrypto::QBlockCipher blockCipher;
responseBody = blockCipher.decryptAesBlockCipher(ba, key, iv);
auto endpointsArray = QJsonDocument::fromJson(responseBody).array();
QStringList endpoints;
for (const auto &endpoint : endpointsArray) {
endpoints.push_back(endpoint.toString());
}
return endpoints;
} else {
responseBody = encryptedResponseBody;
reply->deleteLater();
}
} catch (...) {
Utils::logException();
qCritical() << "error loading private key from environment variables or decrypting payload" << encryptedResponseBody;
return {};
}
auto endpointsArray = QJsonDocument::fromJson(responseBody).array();
QStringList endpoints;
for (const auto &endpoint : endpointsArray) {
endpoints.push_back(endpoint.toString());
}
return endpoints;
return {};
}
bool GatewayController::shouldBypassProxy(QNetworkReply *reply, const QByteArray &responseBody, bool checkEncryption, const QByteArray &key,
@ -262,7 +262,7 @@ bool GatewayController::shouldBypassProxy(QNetworkReply *reply, const QByteArray
} else if (responseBody.contains("html")) {
qDebug() << "The response contains an html tag";
return true;
} else if (checkEncryption) {
} else if (reply->error() == QNetworkReply::NetworkError::NoError && checkEncryption) {
try {
QSimpleCrypto::QBlockCipher blockCipher;
static_cast<void>(blockCipher.decryptAesBlockCipher(responseBody, key, iv, "", salt));
@ -296,7 +296,7 @@ void GatewayController::bypassProxy(const QString &endpoint, QNetworkReply *repl
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
wait.exec();
if (!replyProcessingFunction(reply, sslErrors)) {
if (replyProcessingFunction(reply, sslErrors)) {
break;
}
}

File diff suppressed because it is too large Load diff

View file

@ -407,7 +407,7 @@ bool ApiConfigsController::isConfigValid()
return updateServiceFromGateway(serverIndex, "", "");
} else if (configSource && m_serversModel->isApiKeyExpired(serverIndex)) {
qDebug() << "attempt to update api config by expires_at event";
if (configSource == apiDefs::ConfigSource::Telegram) {
if (configSource == apiDefs::ConfigSource::AmneziaGateway) {
return updateServiceFromGateway(serverIndex, "", "");
} else {
m_serversModel->removeApiConfig(serverIndex);

View file

@ -48,8 +48,8 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
}
case ServiceDescriptionRole: {
if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2) {
return tr("Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to 200 "
"Mb/s");
return tr("Classic VPN for seamless work, downloading large files, and watching videos. Access all websites and online resources. "
"Speeds up to 200 Mbps");
} else if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) {
return tr("Free unlimited access to a basic set of websites such as Facebook, Instagram, Twitter (X), Discord, Telegram and "
"more. YouTube is not included in the free plan.");

View file

@ -81,7 +81,7 @@ PageType {
actionButtonImage: "qrc:/images/controls/settings.svg"
headerText: root.processedServer.name
descriptionText: qsTr("Locations for connection")
descriptionText: qsTr("Location for connection")
actionButtonFunction: function() {
PageController.showBusyIndicator(true)

View file

@ -42,8 +42,8 @@ PageType {
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Connected devices")
descriptionText: qsTr("To manage connected devices")
headerText: qsTr("Active devices")
descriptionText: qsTr("Manage currently connected devices")
}
WarningType {
@ -71,8 +71,13 @@ PageType {
rightImageSource: "qrc:/images/controls/trash.svg"
clickedFunction: function() {
var headerText = qsTr("Deactivate the subscription on selected device")
var descriptionText = qsTr("The next time the “Connect” button is pressed, the device will be activated again")
if (isCurrentDevice && ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Cannot unlink device during active connection"))
return
}
var headerText = qsTr("Are you sure you want to unlink this device?")
var descriptionText = qsTr("This will unlink the device from your subscription. You can reconnect it anytime by pressing Connect.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")

View file

@ -99,7 +99,7 @@ PageType {
Layout.leftMargin: 16
headerText: qsTr("How to connect on another device")
descriptionText: qsTr("Instructions on the Amnezia website")
descriptionText: qsTr("Setup guides on the Amnezia website")
}
}

View file

@ -46,7 +46,7 @@ PageType {
Layout.leftMargin: 16
headerText: qsTr("Configuration files")
descriptionText: qsTr("To connect a router or AmneziaWG application")
descriptionText: qsTr("For router setup or the AmneziaWG app")
}
}
@ -123,13 +123,13 @@ PageType {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Configuration file ") + moreOptionsDrawer.countryName
headerText: moreOptionsDrawer.countryName + qsTr(" configuration file")
}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Create a new")
text: qsTr("Generate a new configuration file")
descriptionText: qsTr("The previously created one will stop working")
clickedFunction: function() {
@ -193,9 +193,15 @@ PageType {
}
function showQuestion(isConfigIssue, countryCode, countryName) {
var headerText = qsTr("Revoke the actual %1 configuration file?").arg(countryName)
var descriptionText = qsTr("The previously created file will no longer be valid. It will not be possible to connect using it.")
var yesButtonText = qsTr("Continue")
var headerText
if (isConfigIssue) {
headerText = qsTr("Generate a new %1 configuration file?").arg(countryName)
} else {
headerText = qsTr("Revoke the current %1 configuration file?").arg(countryName)
}
var descriptionText = qsTr("Your previous configuration file will no longer work, and it will not be possible to connect using it")
var yesButtonText = isConfigIssue ? qsTr("Download") : qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {

View file

@ -42,7 +42,7 @@ PageType {
QtObject {
id: deviceCountObject
readonly property string title: qsTr("Connected devices")
readonly property string title: qsTr("Active connections")
readonly property string contentKey: "connectedDevices"
readonly property string objectImageSource: "qrc:/images/controls/monitor.svg"
}
@ -215,7 +215,7 @@ PageType {
text: qsTr("Configuration files")
descriptionText: qsTr("To connect a router or AmneziaWG application")
descriptionText: qsTr("Manage configuration files")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
@ -233,9 +233,9 @@ PageType {
visible: footer.isVisibleForAmneziaFree
text: qsTr("Connected devices")
text: qsTr("Active devices")
descriptionText: qsTr("To manage connected devices")
descriptionText: qsTr("Manage currently connected devices")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
@ -265,6 +265,8 @@ PageType {
LabelWithButtonType {
Layout.fillWidth: true
visible: footer.isVisibleForAmneziaFree
text: qsTr("How to connect on another device")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
@ -273,7 +275,9 @@ PageType {
}
}
DividerType {}
DividerType {
visible: footer.isVisibleForAmneziaFree
}
BasicButtonType {
id: resetButton
@ -325,17 +329,17 @@ PageType {
pressedColor: AmneziaStyle.color.sheerWhite
textColor: AmneziaStyle.color.vibrantRed
text: qsTr("Deactivate the subscription on this device")
text: qsTr("Unlink this device")
clickedFunc: function() {
var headerText = qsTr("Deactivate the subscription on this device?")
var descriptionText = qsTr("The next time the “Connect” button is pressed, the device will be activated again")
var headerText = qsTr("Are you sure you want to unlink this device?")
var descriptionText = qsTr("This will unlink the device from your subscription. You can reconnect it anytime by pressing Connect.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Cannot deactivate subscription during active connection"))
PageController.showNotificationMessage(qsTr("Cannot unlink device during active connection"))
} else {
PageController.showBusyIndicator(true)
if (ApiConfigsController.deactivateDevice()) {

View file

@ -27,7 +27,7 @@ PageType {
QtObject {
id: techSupport
readonly property string title: qsTr("For technical support")
readonly property string title: qsTr("Email Support")
readonly property string description: qsTr("support@amnezia.org")
readonly property string link: "mailto:support@amnezia.org"
}
@ -35,7 +35,7 @@ PageType {
QtObject {
id: paymentSupport
readonly property string title: qsTr("For payment issues")
readonly property string title: qsTr("Email Billing & Orders")
readonly property string description: qsTr("help@vpnpay.io")
readonly property string link: "mailto:help@vpnpay.io"
}
@ -43,7 +43,7 @@ PageType {
QtObject {
id: site
readonly property string title: qsTr("Site")
readonly property string title: qsTr("Website")
readonly property string description: qsTr("amnezia.org")
readonly property string link: LanguageModel.getCurrentSiteUrl()
}
@ -79,7 +79,7 @@ PageType {
Layout.leftMargin: 16
headerText: qsTr("Support")
descriptionText: qsTr("Our technical support specialists are ready to help you at any time")
descriptionText: qsTr("Our technical support specialists are available to assist you at any time")
}
}