Merge branch 'dev' of github-amnezia:amnezia-vpn/amnezia-client into integrate-mtproxy

This commit is contained in:
vkamn
2026-05-15 21:33:04 +08:00
140 changed files with 3758 additions and 3134 deletions
@@ -34,7 +34,6 @@
#include "core/protocols/protocolUtils.h"
#include "core/utils/constants/configKeys.h"
#include "core/utils/constants/protocolConstants.h"
#include "core/models/serverConfig.h"
#include "core/models/containerConfig.h"
#include "core/models/protocols/mtProxyProtocolConfig.h"
#include "core/models/protocols/awgProtocolConfig.h"
@@ -146,20 +145,32 @@ ErrorCode InstallController::setupContainer(const ServerCredentials &credentials
return startupContainerWorker(credentials, container, config, sshSession);
}
ErrorCode InstallController::updateContainer(int serverIndex, DockerContainer container, const ContainerConfig &oldConfig,
ErrorCode InstallController::updateContainer(const QString &serverId, DockerContainer container, const ContainerConfig &oldConfig,
ContainerConfig &newConfig)
{
if (!isUpdateDockerContainerRequired(container, oldConfig, newConfig)) {
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
if (!adminConfig.has_value()) {
return ErrorCode::InternalError;
}
if (container == DockerContainer::MtProxy) {
ServerCredentials credentials = m_serversRepository->serverCredentials(serverIndex);
ServerCredentials credentials = adminConfig->credentials();
SshSession sshSession(this);
MtProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
}
m_serversRepository->setContainerConfig(serverIndex, container, newConfig);
adminConfig->updateContainerConfig(container, newConfig);
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
return ErrorCode::NoError;
}
ServerCredentials credentials = m_serversRepository->serverCredentials(serverIndex);
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
if (!adminConfig.has_value()) {
return ErrorCode::InternalError;
}
ServerCredentials credentials = adminConfig->credentials();
if (!credentials.isValid()) {
return ErrorCode::InternalError;
}
SshSession sshSession(this);
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
@@ -179,42 +190,51 @@ ErrorCode InstallController::updateContainer(int serverIndex, DockerContainer co
if (container == DockerContainer::MtProxy) {
MtProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
}
clearCachedProfile(serverIndex, container);
m_serversRepository->setContainerConfig(serverIndex, container, newConfig);
clearCachedProfile(serverId, container);
adminConfig->updateContainerConfig(container, newConfig);
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
}
return errorCode;
}
void InstallController::clearCachedProfile(int serverIndex, DockerContainer container)
void InstallController::clearCachedProfile(const QString &serverId, DockerContainer container)
{
if (ContainerUtils::containerService(container) == ServiceType::Other) {
return;
}
ContainerConfig containerConfigModel = m_serversRepository->containerConfig(serverIndex, container);
m_serversRepository->clearLastConnectionConfig(serverIndex, container);
emit clientRevocationRequested(serverIndex, containerConfigModel, container);
}
ErrorCode InstallController::validateAndPrepareConfig(int serverIndex)
{
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
if (serverConfigModel.isApiConfig()) {
return ErrorCode::NoError;
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
if (!adminConfig.has_value()) {
return;
}
DockerContainer container = serverConfigModel.defaultContainer();
adminConfig->clearCachedClientProfile(container);
const ContainerConfig containerConfigModel = adminConfig->containerConfig(container);
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
emit clientRevocationRequested(serverId, containerConfigModel, container);
}
ErrorCode InstallController::validateAndPrepareConfig(const QString &serverId)
{
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
if (!adminConfig.has_value()) {
return ErrorCode::InternalError;
}
DockerContainer container = adminConfig->defaultContainer;
if (container == DockerContainer::None) {
return ErrorCode::NoInstalledContainersError;
}
ContainerConfig containerConfig = m_serversRepository->containerConfig(serverIndex, container);
ServerCredentials credentials = m_serversRepository->serverCredentials(serverIndex);
ContainerConfig containerConfig = adminConfig->containerConfig(container);
ServerCredentials credentials = adminConfig->credentials();
if (!credentials.isValid()) {
return ErrorCode::InternalError;
}
SshSession sshSession;
auto isProtocolConfigExists = [](const ContainerConfig &cfg) {
@@ -223,20 +243,21 @@ ErrorCode InstallController::validateAndPrepareConfig(int serverIndex)
if (!isProtocolConfigExists(containerConfig)) {
QString clientName = QString("Admin [%1]").arg(QSysInfo::prettyProductName());
ErrorCode errorCode = processContainerForAdmin(container, containerConfig, credentials, sshSession, serverIndex, clientName);
ErrorCode errorCode = processContainerForAdmin(container, containerConfig, credentials, sshSession, serverId, clientName);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
m_serversRepository->setContainerConfig(serverIndex, container, containerConfig);
adminConfig->updateContainerConfig(container, containerConfig);
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
}
return ErrorCode::NoError;
}
void InstallController::validateConfig(int serverIndex)
void InstallController::validateConfig(const QString &serverId)
{
QFuture<ErrorCode> future = QtConcurrent::run([this, serverIndex]() {
return validateAndPrepareConfig(serverIndex);
QFuture<ErrorCode> future = QtConcurrent::run([this, serverId]() {
return validateAndPrepareConfig(serverId);
});
auto *watcher = new QFutureWatcher<ErrorCode>(this);
@@ -255,6 +276,21 @@ void InstallController::validateConfig(int serverIndex)
watcher->setFuture(future);
}
void InstallController::addEmptyServer(const ServerCredentials &credentials)
{
SelfHostedAdminServerConfig serverConfig;
serverConfig.hostName = credentials.hostName;
serverConfig.userName = credentials.userName;
serverConfig.password = credentials.secretData;
serverConfig.port = credentials.port;
serverConfig.description = m_appSettingsRepository->nextAvailableServerName();
serverConfig.displayName = serverConfig.description.isEmpty() ? serverConfig.hostName : serverConfig.description;
serverConfig.defaultContainer = DockerContainer::None;
m_serversRepository->addServer(QString(), serverConfig.toJson(),
serverConfigUtils::ConfigType::SelfHostedAdmin);
}
ErrorCode InstallController::prepareContainerConfig(DockerContainer container, const ServerCredentials &credentials, ContainerConfig &containerConfig, SshSession &sshSession)
{
if (!ContainerUtils::isSupportedByCurrentPlatform(container)) {
@@ -282,7 +318,7 @@ ErrorCode InstallController::prepareContainerConfig(DockerContainer container, c
return ErrorCode::NoError;
}
void InstallController::adminAppendRequested(int serverIndex, DockerContainer container,
void InstallController::adminAppendRequested(const QString &serverId, DockerContainer container,
const ContainerConfig &containerConfig, const QString &clientName)
{
if (ContainerUtils::containerService(container) == ServiceType::Other
@@ -291,13 +327,13 @@ void InstallController::adminAppendRequested(int serverIndex, DockerContainer co
}
QString clientId = containerConfig.protocolConfig.clientId();
if (!clientId.isEmpty()) {
emit clientAppendRequested(serverIndex, clientId, clientName, container);
emit clientAppendRequested(serverId, clientId, clientName, container);
}
}
ErrorCode InstallController::processContainerForAdmin(DockerContainer container, ContainerConfig &containerConfig,
const ServerCredentials &credentials, SshSession &sshSession,
int serverIndex, const QString &clientName)
const QString &serverId, const QString &clientName)
{
if (ContainerUtils::isSupportedByCurrentPlatform(container)) {
ErrorCode errorCode = prepareContainerConfig(container, credentials, containerConfig, sshSession);
@@ -305,7 +341,7 @@ ErrorCode InstallController::processContainerForAdmin(DockerContainer container,
return errorCode;
}
}
adminAppendRequested(serverIndex, container, containerConfig, clientName);
adminAppendRequested(serverId, container, containerConfig, clientName);
return ErrorCode::NoError;
}
@@ -752,9 +788,16 @@ ErrorCode InstallController::setupServerFirewall(const ServerCredentials &creden
amnezia::genBaseVars(credentials, DockerContainer::None, QString(), QString())));
}
ErrorCode InstallController::rebootServer(int serverIndex)
ErrorCode InstallController::rebootServer(const QString &serverId)
{
auto credentials = m_serversRepository->serverCredentials(serverIndex);
const auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
if (!adminConfig.has_value()) {
return ErrorCode::InternalError;
}
ServerCredentials credentials = adminConfig->credentials();
if (!credentials.isValid()) {
return ErrorCode::InternalError;
}
SshSession sshSession(this);
QString script = QString("sudo reboot");
@@ -773,27 +816,38 @@ ErrorCode InstallController::rebootServer(int serverIndex)
return sshSession.runScript(credentials, script, cbReadStdOut, cbReadStdErr);
}
ErrorCode InstallController::removeAllContainers(int serverIndex)
ErrorCode InstallController::removeAllContainers(const QString &serverId)
{
auto credentials = m_serversRepository->serverCredentials(serverIndex);
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
if (!adminConfig.has_value()) {
return ErrorCode::InternalError;
}
ServerCredentials credentials = adminConfig->credentials();
if (!credentials.isValid()) {
return ErrorCode::InternalError;
}
SshSession sshSession(this);
ErrorCode errorCode = sshSession.runScript(credentials, amnezia::scriptData(SharedScriptType::remove_all_containers));
if (errorCode == ErrorCode::NoError) {
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
serverConfigModel.visit([](auto& arg) {
arg.containers.clear();
arg.defaultContainer = DockerContainer::None;
});
m_serversRepository->editServer(serverIndex, serverConfigModel);
adminConfig->containers.clear();
adminConfig->defaultContainer = DockerContainer::None;
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
}
return errorCode;
}
ErrorCode InstallController::removeContainer(int serverIndex, DockerContainer container)
ErrorCode InstallController::removeContainer(const QString &serverId, DockerContainer container)
{
auto credentials = m_serversRepository->serverCredentials(serverIndex);
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
if (!adminConfig.has_value()) {
return ErrorCode::InternalError;
}
ServerCredentials credentials = adminConfig->credentials();
if (!credentials.isValid()) {
return ErrorCode::InternalError;
}
SshSession sshSession(this);
ErrorCode errorCode = sshSession.runScript(
credentials,
@@ -801,11 +855,10 @@ ErrorCode InstallController::removeContainer(int serverIndex, DockerContainer co
amnezia::genBaseVars(credentials, container, QString(), QString())));
if (errorCode == ErrorCode::NoError) {
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
QMap<DockerContainer, ContainerConfig> containers = serverConfigModel.containers();
QMap<DockerContainer, ContainerConfig> containers = adminConfig->containers;
containers.remove(container);
DockerContainer defaultContainer = serverConfigModel.defaultContainer();
DockerContainer defaultContainer = adminConfig->defaultContainer;
if (defaultContainer == container) {
if (containers.isEmpty()) {
defaultContainer = DockerContainer::None;
@@ -813,12 +866,10 @@ ErrorCode InstallController::removeContainer(int serverIndex, DockerContainer co
defaultContainer = containers.begin().key();
}
}
serverConfigModel.visit([&containers, defaultContainer](auto& arg) {
arg.containers = containers;
arg.defaultContainer = defaultContainer;
});
m_serversRepository->editServer(serverIndex, serverConfigModel);
adminConfig->containers = containers;
adminConfig->defaultContainer = defaultContainer;
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
}
return errorCode;
@@ -887,9 +938,16 @@ bool InstallController::isUpdateDockerContainerRequired(DockerContainer containe
return true;
}
ErrorCode InstallController::scanServerForInstalledContainers(int serverIndex)
ErrorCode InstallController::scanServerForInstalledContainers(const QString &serverId)
{
ServerCredentials credentials = m_serversRepository->serverCredentials(serverIndex);
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
if (!adminConfig.has_value()) {
return ErrorCode::InternalError;
}
ServerCredentials credentials = adminConfig->credentials();
if (!credentials.isValid()) {
return ErrorCode::InternalError;
}
SshSession sshSession(this);
QMap<DockerContainer, ContainerConfig> installedContainers;
@@ -898,8 +956,7 @@ ErrorCode InstallController::scanServerForInstalledContainers(int serverIndex)
return errorCode;
}
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
QMap<DockerContainer, ContainerConfig> containers = serverConfigModel.containers();
QMap<DockerContainer, ContainerConfig> containers = adminConfig->containers;
bool hasNewContainers = false;
QString clientName = QString("Admin [%1]").arg(QSysInfo::prettyProductName());
@@ -907,29 +964,25 @@ ErrorCode InstallController::scanServerForInstalledContainers(int serverIndex)
if (!containers.contains(iterator.key())) {
ContainerConfig containerConfig = iterator.value();
errorCode = processContainerForAdmin(iterator.key(), containerConfig, credentials, sshSession,
serverIndex, clientName);
serverId, clientName);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
containers.insert(iterator.key(), containerConfig);
hasNewContainers = true;
DockerContainer defaultContainer = serverConfigModel.defaultContainer();
DockerContainer defaultContainer = adminConfig->defaultContainer;
if (defaultContainer == DockerContainer::None
&& ContainerUtils::containerService(iterator.key()) != ServiceType::Other
&& ContainerUtils::isSupportedByCurrentPlatform(iterator.key())) {
serverConfigModel.visit([iterator](auto& arg) {
arg.defaultContainer = iterator.key();
});
adminConfig->defaultContainer = iterator.key();
}
}
}
if (hasNewContainers) {
serverConfigModel.visit([&containers](auto& arg) {
arg.containers = containers;
});
m_serversRepository->editServer(serverIndex, serverConfigModel);
adminConfig->containers = containers;
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
}
return ErrorCode::NoError;
@@ -971,7 +1024,7 @@ ErrorCode InstallController::installServer(const ServerCredentials &credentials,
preparedContainers.insert(container, containerConfig);
}
SelfHostedServerConfig serverConfig;
SelfHostedAdminServerConfig serverConfig;
serverConfig.hostName = credentials.hostName;
serverConfig.userName = credentials.userName;
serverConfig.password = credentials.secretData;
@@ -984,21 +1037,29 @@ ErrorCode InstallController::installServer(const ServerCredentials &credentials,
serverConfig.defaultContainer = container;
m_serversRepository->addServer(ServerConfig(serverConfig));
serverConfig.displayName = serverConfig.description.isEmpty() ? serverConfig.hostName : serverConfig.description;
int serverIndex = m_serversRepository->serversCount() - 1;
const QString newServerId = m_serversRepository->addServer(QString(), serverConfig.toJson(),
serverConfigUtils::ConfigType::SelfHostedAdmin);
QString clientName = QString("Admin [%1]").arg(QSysInfo::prettyProductName());
for (auto iterator = preparedContainers.begin(); iterator != preparedContainers.end(); iterator++) {
adminAppendRequested(serverIndex, iterator.key(), iterator.value(), clientName);
adminAppendRequested(newServerId, iterator.key(), iterator.value(), clientName);
}
return ErrorCode::NoError;
}
ErrorCode InstallController::installContainer(int serverIndex, DockerContainer container, int port,
ErrorCode InstallController::installContainer(const QString &serverId, DockerContainer container, int port,
TransportProto transportProto, bool &wasContainerInstalled)
{
ServerCredentials credentials = m_serversRepository->serverCredentials(serverIndex);
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
if (!adminConfig.has_value()) {
return ErrorCode::InternalError;
}
ServerCredentials credentials = adminConfig->credentials();
if (!credentials.isValid()) {
return ErrorCode::InternalError;
}
SshSession sshSession(this);
QMap<DockerContainer, ContainerConfig> installedContainers;
@@ -1021,15 +1082,17 @@ ErrorCode InstallController::installContainer(int serverIndex, DockerContainer c
QString clientName = QString("Admin [%1]").arg(QSysInfo::prettyProductName());
for (auto iterator = installedContainers.begin(); iterator != installedContainers.end(); iterator++) {
ContainerConfig existingConfigModel = m_serversRepository->containerConfig(serverIndex, iterator.key());
ContainerConfig existingConfigModel = adminConfig->containerConfig(iterator.key());
if (existingConfigModel.container == DockerContainer::None) {
ContainerConfig containerConfig = iterator.value();
errorCode = processContainerForAdmin(iterator.key(), containerConfig, credentials, sshSession,
serverIndex, clientName);
serverId, clientName);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
m_serversRepository->setContainerConfig(serverIndex, iterator.key(), containerConfig);
adminConfig->updateContainerConfig(iterator.key(), containerConfig);
m_serversRepository->editServer(serverId, adminConfig->toJson(),
serverConfigUtils::ConfigType::SelfHostedAdmin);
}
}
@@ -1065,7 +1128,15 @@ bool InstallController::isServerAlreadyExists(const ServerCredentials &credentia
{
int serversCount = m_serversRepository->serversCount();
for (int i = 0; i < serversCount; i++) {
const ServerCredentials existingCredentials = m_serversRepository->serverCredentials(i);
const QString existingServerId = m_serversRepository->serverIdAt(i);
const auto adminConfig = m_serversRepository->selfHostedAdminConfig(existingServerId);
if (!adminConfig.has_value()) {
continue;
}
const ServerCredentials existingCredentials = adminConfig->credentials();
if (!existingCredentials.isValid()) {
continue;
}
if (credentials.hostName == existingCredentials.hostName && credentials.port == existingCredentials.port) {
existingServerIndex = i;
return true;