fix: minor fixes (#2137)

* refactor: removed premv1 migration code

* fix: i1-i5 parsing when scaning server

* chore: bump version
This commit is contained in:
vkamn
2026-01-19 14:03:54 +08:00
committed by GitHub
parent a45bb5ea4f
commit b591dd7445
12 changed files with 9 additions and 618 deletions

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
set(AMNEZIAVPN_VERSION 4.8.12.7)
set(AMNEZIAVPN_VERSION 4.8.12.8)
project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}
DESCRIPTION "AmneziaVPN"
@@ -12,7 +12,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 2103)
set(APP_ANDROID_VERSION_CODE 2104)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")

View File

@@ -154,9 +154,6 @@ void CoreController::initControllers()
m_apiConfigsController.reset(new ApiConfigsController(m_serversModel, m_apiServicesModel, m_settings));
m_engine->rootContext()->setContextProperty("ApiConfigsController", m_apiConfigsController.get());
m_apiPremV1MigrationController.reset(new ApiPremV1MigrationController(m_serversModel, m_settings, this));
m_engine->rootContext()->setContextProperty("ApiPremV1MigrationController", m_apiPremV1MigrationController.get());
m_apiNewsController.reset(new ApiNewsController(m_newsModel, m_settings, m_serversModel, this));
m_engine->rootContext()->setContextProperty("ApiNewsController", m_apiNewsController.get());
}
@@ -231,8 +228,6 @@ void CoreController::initSignalHandlers()
initAutoConnectHandler();
initAmneziaDnsToggledHandler();
initPrepareConfigHandler();
initImportPremiumV2VpnKeyHandler();
initShowMigrationDrawerHandler();
initStrictKillSwitchHandler();
}
@@ -382,25 +377,6 @@ void CoreController::initPrepareConfigHandler()
});
}
void CoreController::initImportPremiumV2VpnKeyHandler()
{
connect(m_apiPremV1MigrationController.get(), &ApiPremV1MigrationController::importPremiumV2VpnKey, this, [this](const QString &vpnKey) {
m_importController->extractConfigFromData(vpnKey);
m_importController->importConfig();
emit m_apiPremV1MigrationController->migrationFinished();
});
}
void CoreController::initShowMigrationDrawerHandler()
{
QTimer::singleShot(1000, this, [this]() {
if (m_apiPremV1MigrationController->isPremV1MigrationReminderActive() && m_apiPremV1MigrationController->hasConfigsToMigration()) {
m_apiPremV1MigrationController->showMigrationDrawer();
}
});
}
void CoreController::initStrictKillSwitchHandler()
{
connect(m_settingsController.get(), &SettingsController::strictKillSwitchEnabledChanged, m_vpnConnection.get(),

View File

@@ -11,7 +11,6 @@
#include "ui/controllers/api/apiConfigsController.h"
#include "ui/controllers/api/apiSettingsController.h"
#include "ui/controllers/api/apiPremV1MigrationController.h"
#include "ui/controllers/api/apiNewsController.h"
#include "ui/controllers/appSplitTunnelingController.h"
#include "ui/controllers/allowedDnsController.h"
@@ -93,8 +92,6 @@ private:
void initAutoConnectHandler();
void initAmneziaDnsToggledHandler();
void initPrepareConfigHandler();
void initImportPremiumV2VpnKeyHandler();
void initShowMigrationDrawerHandler();
void initStrictKillSwitchHandler();
QQmlApplicationEngine *m_engine {}; // TODO use parent child system here?
@@ -122,7 +119,6 @@ private:
QScopedPointer<ApiSettingsController> m_apiSettingsController;
QScopedPointer<ApiConfigsController> m_apiConfigsController;
QScopedPointer<ApiPremV1MigrationController> m_apiPremV1MigrationController;
QScopedPointer<ApiNewsController> m_apiNewsController;
QSharedPointer<ContainersModel> m_containersModel;

View File

@@ -247,9 +247,6 @@
<file>ui/qml/Pages2/PageSettingsApiNativeConfigs.qml</file>
<file>ui/qml/Pages2/PageSettingsApiDevices.qml</file>
<file>images/controls/monitor.svg</file>
<file>ui/qml/Components/ApiPremV1MigrationDrawer.qml</file>
<file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file>
<file>ui/qml/Components/OtpCodeDrawer.qml</file>
<file>ui/qml/Components/AwgTextField.qml</file>
<file>ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml</file>
<file>ui/qml/Components/SmartScroll.qml</file>

View File

@@ -1,133 +0,0 @@
#include "apiPremV1MigrationController.h"
#include <QEventLoop>
#include <QTimer>
#include "core/api/apiDefs.h"
#include "core/api/apiUtils.h"
#include "core/controllers/gatewayController.h"
ApiPremV1MigrationController::ApiPremV1MigrationController(const QSharedPointer<ServersModel> &serversModel,
const std::shared_ptr<Settings> &settings, QObject *parent)
: QObject(parent), m_serversModel(serversModel), m_settings(settings)
{
}
bool ApiPremV1MigrationController::hasConfigsToMigration()
{
QJsonArray vpnKeys;
auto serversCount = m_serversModel->getServersCount();
for (size_t i = 0; i < serversCount; i++) {
auto serverConfigObject = m_serversModel->getServerConfig(i);
if (apiUtils::getConfigType(serverConfigObject) != apiDefs::ConfigType::AmneziaPremiumV1) {
continue;
}
QString vpnKey = apiUtils::getPremiumV1VpnKey(serverConfigObject);
vpnKeys.append(vpnKey);
}
if (!vpnKeys.isEmpty()) {
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
QJsonObject apiPayload;
apiPayload["configs"] = vpnKeys;
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/prem-v1/is-active-subscription"), apiPayload, responseBody);
auto migrationsStatus = QJsonDocument::fromJson(responseBody).object();
for (const auto &migrationStatus : migrationsStatus) {
if (migrationStatus == "not_found") {
return true;
}
}
}
return false;
}
void ApiPremV1MigrationController::getSubscriptionList(const QString &email)
{
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
QJsonObject apiPayload;
apiPayload[apiDefs::key::email] = email;
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/prem-v1/subscription-list"), apiPayload, responseBody);
if (errorCode == ErrorCode::NoError) {
m_email = email;
m_subscriptionsModel = QJsonDocument::fromJson(responseBody).array();
if (m_subscriptionsModel.isEmpty()) {
emit noSubscriptionToMigrate();
return;
}
emit subscriptionsModelChanged();
} else {
emit errorOccurred(ErrorCode::ApiMigrationError);
}
}
QJsonArray ApiPremV1MigrationController::getSubscriptionModel()
{
return m_subscriptionsModel;
}
void ApiPremV1MigrationController::sendMigrationCode(const int subscriptionIndex)
{
QEventLoop wait;
QTimer::singleShot(1000, &wait, &QEventLoop::quit);
wait.exec(QEventLoop::ExcludeUserInputEvents);
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
QJsonObject apiPayload;
apiPayload[apiDefs::key::email] = m_email;
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/prem-v1/migration-code"), apiPayload, responseBody);
if (errorCode == ErrorCode::NoError) {
m_subscriptionIndex = subscriptionIndex;
emit otpSuccessfullySent();
} else {
emit errorOccurred(ErrorCode::ApiMigrationError);
}
}
void ApiPremV1MigrationController::migrate(const QString &migrationCode)
{
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
QJsonObject apiPayload;
apiPayload[apiDefs::key::email] = m_email;
apiPayload[apiDefs::key::orderId] = m_subscriptionsModel.at(m_subscriptionIndex).toObject().value(apiDefs::key::id).toString();
apiPayload[apiDefs::key::migrationCode] = migrationCode;
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/prem-v1/migrate"), apiPayload, responseBody);
if (errorCode == ErrorCode::NoError) {
auto responseObject = QJsonDocument::fromJson(responseBody).object();
QString premiumV2VpnKey = responseObject.value(apiDefs::key::config).toString();
emit importPremiumV2VpnKey(premiumV2VpnKey);
} else {
emit errorOccurred(ErrorCode::ApiMigrationError);
}
}
bool ApiPremV1MigrationController::isPremV1MigrationReminderActive()
{
return m_settings->isPremV1MigrationReminderActive();
}
void ApiPremV1MigrationController::disablePremV1MigrationReminder()
{
m_settings->disablePremV1MigrationReminder();
}

View File

@@ -1,50 +0,0 @@
#ifndef APIPREMV1MIGRATIONCONTROLLER_H
#define APIPREMV1MIGRATIONCONTROLLER_H
#include <QObject>
#include "ui/models/servers_model.h"
class ApiPremV1MigrationController : public QObject
{
Q_OBJECT
public:
ApiPremV1MigrationController(const QSharedPointer<ServersModel> &serversModel, const std::shared_ptr<Settings> &settings,
QObject *parent = nullptr);
Q_PROPERTY(QJsonArray subscriptionsModel READ getSubscriptionModel NOTIFY subscriptionsModelChanged)
public slots:
bool hasConfigsToMigration();
void getSubscriptionList(const QString &email);
QJsonArray getSubscriptionModel();
void sendMigrationCode(const int subscriptionIndex);
void migrate(const QString &migrationCode);
bool isPremV1MigrationReminderActive();
void disablePremV1MigrationReminder();
signals:
void subscriptionsModelChanged();
void otpSuccessfullySent();
void importPremiumV2VpnKey(const QString &vpnKey);
void errorOccurred(ErrorCode errorCode);
void showMigrationDrawer();
void migrationFinished();
void noSubscriptionToMigrate();
private:
QSharedPointer<ServersModel> m_serversModel;
std::shared_ptr<Settings> m_settings;
QJsonArray m_subscriptionsModel;
int m_subscriptionIndex;
QString m_email;
};
#endif // APIPREMV1MIGRATIONCONTROLLER_H

View File

@@ -451,6 +451,13 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
containerConfig[config_key::transportPacketMagicHeader] =
serverConfigMap.value(config_key::transportPacketMagicHeader);
// hack to parse i1-i5 from commented lines in server config
containerConfig[config_key::specialJunk1] = serverConfigMap.value(QString("# ") + config_key::specialJunk1);
containerConfig[config_key::specialJunk2] = serverConfigMap.value(QString("# ") + config_key::specialJunk2);
containerConfig[config_key::specialJunk3] = serverConfigMap.value(QString("# ") + config_key::specialJunk3);
containerConfig[config_key::specialJunk4] = serverConfigMap.value(QString("# ") + config_key::specialJunk4);
containerConfig[config_key::specialJunk5] = serverConfigMap.value(QString("# ") + config_key::specialJunk5);
if (container == DockerContainer::Awg2) {
containerConfig[config_key::protocolVersion] = "2";
containerConfig[config_key::cookieReplyPacketJunkSize] =

View File

@@ -1,194 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtCore
import PageEnum 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
DrawerType2 {
id: root
expandedHeight: parent.height * 0.9
Connections {
target: ApiPremV1MigrationController
function onErrorOccurred(error, goToPageHome) {
PageController.showErrorMessage(error)
root.closeTriggered()
}
}
expandedStateContent: Item {
implicitHeight: root.expandedHeight
ListViewType {
id: listView
anchors.fill: parent
model: 1 // fake model to force the ListView to be created without a model
snapMode: ListView.NoSnap
header: ColumnLayout {
width: listView.width
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Switch to the new Amnezia Premium subscription")
}
}
delegate: ColumnLayout {
width: listView.width
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
horizontalAlignment: Text.AlignLeft
textFormat: Text.RichText
text: {
var str = qsTr("We'll preserve all remaining days of your current subscription and give you an extra month as a thank you. ")
str += qsTr("This new subscription type will be actively developed with more locations and features added regularly. Currently available:")
str += "<ul style='margin-left: -16px;'>"
str += qsTr("<li>20 locations (with more coming soon)</li>")
str += qsTr("<li>Easier switching between countries in the app</li>")
str += qsTr("<li>Personal dashboard to manage your subscription</li>")
str += "</ul>"
str += qsTr("Old keys will be deactivated after switching.")
}
}
TextFieldWithHeaderType {
id: emailLabel
Layout.fillWidth: true
borderColor: AmneziaStyle.color.mutedGray
headerTextColor: AmneziaStyle.color.paleGray
headerText: qsTr("Email")
textField.placeholderText: qsTr("mail@example.com")
textField.onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
}
Connections {
target: ApiPremV1MigrationController
function onNoSubscriptionToMigrate() {
emailLabel.errorText = qsTr("No old format subscriptions for a given email")
}
}
}
CaptionTextType {
Layout.fillWidth: true
Layout.topMargin: 16
color: AmneziaStyle.color.mutedGray
text: qsTr("Enter the email you used for your current subscription")
}
ApiPremV1SubListDrawer {
id: apiPremV1SubListDrawer
parent: root
anchors.fill: parent
}
OtpCodeDrawer {
id: otpCodeDrawer
parent: root
anchors.fill: parent
}
BasicButtonType {
id: yesButton
Layout.fillWidth: true
Layout.topMargin: 32
text: qsTr("Continue")
clickedFunc: function() {
PageController.showBusyIndicator(true)
ApiPremV1MigrationController.getSubscriptionList(emailLabel.textField.text)
PageController.showBusyIndicator(false)
}
}
BasicButtonType {
id: noButton
Layout.fillWidth: true
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.paleGray
borderWidth: 1
text: qsTr("Remind me later")
clickedFunc: function() {
root.closeTriggered()
}
}
BasicButtonType {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 32
Layout.bottomMargin: 32
implicitHeight: 32
defaultColor: "transparent"
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
textColor: AmneziaStyle.color.vibrantRed
text: qsTr("Don't remind me again")
clickedFunc: function() {
var headerText = qsTr("No more reminders? You can always switch to the new format in the server settings")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
ApiPremV1MigrationController.disablePremV1MigrationReminder()
root.closeTriggered()
}
var noButtonFunction = function() {
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
}
}
}
}

View File

@@ -1,89 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Style 1.0
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
DrawerType2 {
id: root
Connections {
target: ApiPremV1MigrationController
function onSubscriptionsModelChanged() {
if (ApiPremV1MigrationController.subscriptionsModel.length > 1) {
root.openTriggered()
} else {
sendMigrationCode(0)
}
}
}
function sendMigrationCode(index) {
PageController.showBusyIndicator(true)
ApiPremV1MigrationController.sendMigrationCode(index)
root.closeTriggered()
PageController.showBusyIndicator(false)
}
expandedHeight: parent.height * 0.9
expandedStateContent: Item {
implicitHeight: root.expandedHeight
ListViewType {
id: listView
anchors.fill: parent
model: ApiPremV1MigrationController.subscriptionsModel
header: ColumnLayout {
width: listView.width
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Choose Subscription")
}
}
delegate: Item {
implicitWidth: listView.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelWithButtonType {
id: server
Layout.fillWidth: true
text: qsTr("Order ID: ") + modelData.id
descriptionText: qsTr("Purchase Date: ") + Qt.formatDateTime(new Date(modelData.created_at), "dd.MM.yyyy hh:mm")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
sendMigrationCode(index)
}
}
DividerType {}
}
}
}
}
}

View File

@@ -1,77 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Style 1.0
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
DrawerType2 {
id: root
Connections {
target: ApiPremV1MigrationController
function onOtpSuccessfullySent() {
root.openTriggered()
}
}
expandedHeight: parent.height * 0.6
expandedStateContent: Item {
implicitHeight: root.expandedHeight
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 20
headerText: qsTr("OTP code was sent to your email")
}
TextFieldWithHeaderType {
id: otpFiled
borderColor: AmneziaStyle.color.mutedGray
headerTextColor: AmneziaStyle.color.paleGray
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("OTP Code")
textField.maximumLength: 30
checkEmptyText: true
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Continue")
clickedFunc: function() {
PageController.showBusyIndicator(true)
ApiPremV1MigrationController.migrate(otpFiled.textField.text)
PageController.showBusyIndicator(false)
root.closeTriggered()
}
}
}
}
}

View File

@@ -48,30 +48,6 @@ PageType {
}
}
Connections {
target: ApiPremV1MigrationController
function onMigrationFinished() {
apiPremV1MigrationDrawer.closeTriggered()
var headerText = qsTr("You've successfully switched to the new Amnezia Premium subscription!")
var descriptionText = qsTr("Old keys will no longer work. Please use your new subscription key to connect. \nThank you for staying with us!")
var yesButtonText = qsTr("Continue")
var noButtonText = ""
var yesButtonFunction = function() {
}
var noButtonFunction = function() {
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
function onShowMigrationDrawer() {
apiPremV1MigrationDrawer.openTriggered()
}
}
Item {
objectName: "homeColumnItem"
@@ -500,9 +476,4 @@ PageType {
}
}
}
ApiPremV1MigrationDrawer {
id: apiPremV1MigrationDrawer
anchors.fill: parent
}
}

View File

@@ -101,7 +101,6 @@ PageType {
remove,
clear,
reset,
switch_to_premium,
]
QtObject {
@@ -237,16 +236,4 @@ PageType {
}
}
QtObject {
id: switch_to_premium
property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium
readonly property string title: qsTr("Switch to the new Amnezia Premium subscription")
readonly property string description: ""
readonly property var tColor: AmneziaStyle.color.vibrantRed
readonly property var clickedHandler: function() {
PageController.goToPageHome()
ApiPremV1MigrationController.showMigrationDrawer()
}
}
}