mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1e8fc5f89 | |||
| 277b295fd8 | |||
| 39e4c52fb3 | |||
| 8c33779fc3 | |||
| f0299ca9fe | |||
| 72196484a7 | |||
| 05ce813c23 | |||
| 0945366587 | |||
| c7b1c2809f | |||
| c9ed0baf3b | |||
| 2a3e3126ac | |||
| 98771027b7 | |||
| 0433e03bdc | |||
| cb48667b91 | |||
| d0a1af0381 | |||
| fd0c773918 | |||
| 06372c8fd7 | |||
| b7c502e7ed | |||
| 4b8ddf7236 | |||
| a0145475f2 | |||
| 9f3359e1e8 | |||
| 485d0c848a |
@@ -1,6 +1,5 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/client_scripts">
|
<qresource prefix="/client_scripts">
|
||||||
<file>linux_installer.sh</file>
|
|
||||||
<file>mac_installer.sh</file>
|
<file>mac_installer.sh</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
EXTRACT_DIR="$1"
|
|
||||||
INSTALLER_PATH="$2"
|
|
||||||
|
|
||||||
# Create and clean extract directory
|
|
||||||
rm -rf "$EXTRACT_DIR"
|
|
||||||
mkdir -p "$EXTRACT_DIR"
|
|
||||||
|
|
||||||
# Extract TAR archive
|
|
||||||
tar -xf "$INSTALLER_PATH" -C "$EXTRACT_DIR"
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo 'Failed to extract TAR archive'
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Find and run installer
|
|
||||||
INSTALLER=$(find "$EXTRACT_DIR" -type f -executable)
|
|
||||||
if [ -z "$INSTALLER" ]; then
|
|
||||||
echo 'Installer not found'
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
"$INSTALLER"
|
|
||||||
EXIT_CODE=$?
|
|
||||||
|
|
||||||
# Cleanup
|
|
||||||
rm -rf "$EXTRACT_DIR"
|
|
||||||
exit $EXIT_CODE
|
|
||||||
@@ -15,7 +15,6 @@ set(HEADERS ${HEADERS}
|
|||||||
${CLIENT_ROOT_DIR}/core/utils/constants/protocolConstants.h
|
${CLIENT_ROOT_DIR}/core/utils/constants/protocolConstants.h
|
||||||
${CLIENT_ROOT_DIR}/core/utils/constants/apiKeys.h
|
${CLIENT_ROOT_DIR}/core/utils/constants/apiKeys.h
|
||||||
${CLIENT_ROOT_DIR}/core/utils/constants/apiConstants.h
|
${CLIENT_ROOT_DIR}/core/utils/constants/apiConstants.h
|
||||||
${CLIENT_ROOT_DIR}/core/utils/api/apiEnums.h
|
|
||||||
${CLIENT_ROOT_DIR}/core/utils/errorStrings.h
|
${CLIENT_ROOT_DIR}/core/utils/errorStrings.h
|
||||||
${CLIENT_ROOT_DIR}/core/utils/selfhosted/scriptsRegistry.h
|
${CLIENT_ROOT_DIR}/core/utils/selfhosted/scriptsRegistry.h
|
||||||
${CLIENT_ROOT_DIR}/core/utils/qrCodeUtils.h
|
${CLIENT_ROOT_DIR}/core/utils/qrCodeUtils.h
|
||||||
@@ -36,6 +35,8 @@ set(HEADERS ${HEADERS}
|
|||||||
${CLIENT_ROOT_DIR}/core/installers/torInstaller.h
|
${CLIENT_ROOT_DIR}/core/installers/torInstaller.h
|
||||||
${CLIENT_ROOT_DIR}/core/installers/sftpInstaller.h
|
${CLIENT_ROOT_DIR}/core/installers/sftpInstaller.h
|
||||||
${CLIENT_ROOT_DIR}/core/installers/socks5Installer.h
|
${CLIENT_ROOT_DIR}/core/installers/socks5Installer.h
|
||||||
|
${CLIENT_ROOT_DIR}/core/installers/mtProxyInstaller.h
|
||||||
|
${CLIENT_ROOT_DIR}/core/installers/telemtInstaller.h
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/appSplitTunnelingController.h
|
${CLIENT_ROOT_DIR}/core/controllers/appSplitTunnelingController.h
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/ipSplitTunnelingController.h
|
${CLIENT_ROOT_DIR}/core/controllers/ipSplitTunnelingController.h
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/allowedDnsController.h
|
${CLIENT_ROOT_DIR}/core/controllers/allowedDnsController.h
|
||||||
@@ -111,6 +112,8 @@ set(SOURCES ${SOURCES}
|
|||||||
${CLIENT_ROOT_DIR}/core/installers/torInstaller.cpp
|
${CLIENT_ROOT_DIR}/core/installers/torInstaller.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/installers/sftpInstaller.cpp
|
${CLIENT_ROOT_DIR}/core/installers/sftpInstaller.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/installers/socks5Installer.cpp
|
${CLIENT_ROOT_DIR}/core/installers/socks5Installer.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/core/installers/mtProxyInstaller.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/core/installers/telemtInstaller.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/appSplitTunnelingController.cpp
|
${CLIENT_ROOT_DIR}/core/controllers/appSplitTunnelingController.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/ipSplitTunnelingController.cpp
|
${CLIENT_ROOT_DIR}/core/controllers/ipSplitTunnelingController.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/allowedDnsController.cpp
|
${CLIENT_ROOT_DIR}/core/controllers/allowedDnsController.cpp
|
||||||
@@ -138,6 +141,7 @@ set(SOURCES ${SOURCES}
|
|||||||
${CLIENT_ROOT_DIR}/../common/logger/logger.cpp
|
${CLIENT_ROOT_DIR}/../common/logger/logger.cpp
|
||||||
${CLIENT_ROOT_DIR}/ui/utils/qmlUtils.cpp
|
${CLIENT_ROOT_DIR}/ui/utils/qmlUtils.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/utils/api/apiUtils.cpp
|
${CLIENT_ROOT_DIR}/core/utils/api/apiUtils.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/core/utils/serverConfigUtils.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/utils/osSignalHandler.cpp
|
${CLIENT_ROOT_DIR}/core/utils/osSignalHandler.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/utils/utilities.cpp
|
${CLIENT_ROOT_DIR}/core/utils/utilities.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/utils/managementServer.cpp
|
${CLIENT_ROOT_DIR}/core/utils/managementServer.cpp
|
||||||
@@ -201,12 +205,14 @@ file(GLOB UI_MODELS_H CONFIGURE_DEPENDS
|
|||||||
${CLIENT_ROOT_DIR}/ui/models/*.h
|
${CLIENT_ROOT_DIR}/ui/models/*.h
|
||||||
${CLIENT_ROOT_DIR}/ui/models/protocols/*.h
|
${CLIENT_ROOT_DIR}/ui/models/protocols/*.h
|
||||||
${CLIENT_ROOT_DIR}/ui/models/services/*.h
|
${CLIENT_ROOT_DIR}/ui/models/services/*.h
|
||||||
|
${CLIENT_ROOT_DIR}/ui/models/utils/*.h
|
||||||
${CLIENT_ROOT_DIR}/ui/models/api/*.h
|
${CLIENT_ROOT_DIR}/ui/models/api/*.h
|
||||||
)
|
)
|
||||||
file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
|
file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
|
||||||
${CLIENT_ROOT_DIR}/ui/models/*.cpp
|
${CLIENT_ROOT_DIR}/ui/models/*.cpp
|
||||||
${CLIENT_ROOT_DIR}/ui/models/protocols/*.cpp
|
${CLIENT_ROOT_DIR}/ui/models/protocols/*.cpp
|
||||||
${CLIENT_ROOT_DIR}/ui/models/services/*.cpp
|
${CLIENT_ROOT_DIR}/ui/models/services/*.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/ui/models/utils/*.cpp
|
||||||
${CLIENT_ROOT_DIR}/ui/models/api/*.cpp
|
${CLIENT_ROOT_DIR}/ui/models/api/*.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,51 +1,93 @@
|
|||||||
#include "newsController.h"
|
#include "newsController.h"
|
||||||
|
|
||||||
#include "core/controllers/gatewayController.h"
|
#include "core/controllers/gatewayController.h"
|
||||||
#include "core/utils/api/apiEnums.h"
|
#include "core/repositories/secureServersRepository.h"
|
||||||
#include "core/utils/constants/apiKeys.h"
|
#include "core/utils/constants/apiKeys.h"
|
||||||
#include "core/utils/constants/apiConstants.h"
|
#include "core/utils/constants/apiConstants.h"
|
||||||
#include "core/utils/constants/configKeys.h"
|
|
||||||
#include <QtConcurrent/QtConcurrent>
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QSet>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
|
||||||
using namespace amnezia;
|
using namespace amnezia;
|
||||||
|
|
||||||
NewsController::NewsController(SecureAppSettingsRepository* appSettingsRepository,
|
NewsController::NewsController(SecureAppSettingsRepository *appSettingsRepository,
|
||||||
ServersController* serversController)
|
SecureServersRepository *serversRepository)
|
||||||
: m_appSettingsRepository(appSettingsRepository), m_serversController(serversController)
|
: m_appSettingsRepository(appSettingsRepository),
|
||||||
|
m_serversRepository(serversRepository)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject NewsController::getServicesList() const
|
||||||
|
{
|
||||||
|
if (!m_serversRepository) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
QSet<QString> userCountryCodes;
|
||||||
|
QSet<QString> serviceTypes;
|
||||||
|
const QVector<QString> ids = m_serversRepository->orderedServerIds();
|
||||||
|
for (const QString &id : ids) {
|
||||||
|
const auto apiV2 = m_serversRepository->apiV2Config(id);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!apiV2->apiConfig.userCountryCode.isEmpty()) {
|
||||||
|
userCountryCodes.insert(apiV2->apiConfig.userCountryCode);
|
||||||
|
}
|
||||||
|
const QString serviceType = apiV2->serviceType();
|
||||||
|
if (!serviceType.isEmpty()) {
|
||||||
|
serviceTypes.insert(serviceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (userCountryCodes.isEmpty() && serviceTypes.isEmpty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
QJsonObject json;
|
||||||
|
|
||||||
|
QJsonArray userCountryCodesArray;
|
||||||
|
for (const QString &code : userCountryCodes) {
|
||||||
|
userCountryCodesArray.append(code);
|
||||||
|
}
|
||||||
|
json[apiDefs::key::userCountryCode] = userCountryCodesArray;
|
||||||
|
|
||||||
|
QJsonArray serviceTypesArray;
|
||||||
|
for (const QString &type : serviceTypes) {
|
||||||
|
serviceTypesArray.append(type);
|
||||||
|
}
|
||||||
|
json[apiDefs::key::serviceType] = serviceTypesArray;
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
QFuture<QPair<ErrorCode, QJsonArray>> NewsController::fetchNews()
|
QFuture<QPair<ErrorCode, QJsonArray>> NewsController::fetchNews()
|
||||||
{
|
{
|
||||||
if (!m_serversController) {
|
if (!m_serversRepository) {
|
||||||
qWarning() << "ServersController is null, skip fetchNews";
|
qWarning() << "SecureServersRepository is null, skip fetchNews";
|
||||||
return QtFuture::makeReadyFuture(qMakePair(ErrorCode::InternalError, QJsonArray()));
|
return QtFuture::makeReadyFuture(qMakePair(ErrorCode::InternalError, QJsonArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto stacks = m_serversController->gatewayStacks();
|
const QJsonObject services = getServicesList();
|
||||||
if (stacks.isEmpty()) {
|
if (services.isEmpty()) {
|
||||||
qDebug() << "No Gateway stacks, skip fetchNews";
|
qDebug() << "No Gateway stacks, skip fetchNews";
|
||||||
return QtFuture::makeReadyFuture(qMakePair(ErrorCode::NoError, QJsonArray()));
|
return QtFuture::makeReadyFuture(qMakePair(ErrorCode::NoError, QJsonArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto gatewayController = QSharedPointer<GatewayController>::create(
|
auto gatewayController = QSharedPointer<GatewayController>::create(
|
||||||
m_appSettingsRepository->getGatewayEndpoint(),
|
m_appSettingsRepository->getGatewayEndpoint(),
|
||||||
m_appSettingsRepository->isDevGatewayEnv(),
|
m_appSettingsRepository->isDevGatewayEnv(),
|
||||||
apiDefs::requestTimeoutMsecs,
|
apiDefs::requestTimeoutMsecs,
|
||||||
m_appSettingsRepository->isStrictKillSwitchEnabled());
|
m_appSettingsRepository->isStrictKillSwitchEnabled());
|
||||||
|
|
||||||
QJsonObject payload;
|
QJsonObject payload;
|
||||||
payload.insert("locale", m_appSettingsRepository->getAppLanguage().name().split("_").first());
|
payload.insert("locale", m_appSettingsRepository->getAppLanguage().name().split("_").first());
|
||||||
|
|
||||||
const QJsonObject stacksJson = stacks.toJson();
|
if (services.contains(apiDefs::key::userCountryCode)) {
|
||||||
if (stacksJson.contains(apiDefs::key::userCountryCode)) {
|
payload.insert(apiDefs::key::userCountryCode, services.value(apiDefs::key::userCountryCode));
|
||||||
payload.insert(apiDefs::key::userCountryCode, stacksJson.value(apiDefs::key::userCountryCode));
|
|
||||||
}
|
}
|
||||||
if (stacksJson.contains(apiDefs::key::serviceType)) {
|
if (services.contains(apiDefs::key::serviceType)) {
|
||||||
payload.insert(apiDefs::key::serviceType, stacksJson.value(apiDefs::key::serviceType));
|
payload.insert(apiDefs::key::serviceType, services.value(apiDefs::key::serviceType));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto future = gatewayController->postAsync(QString("%1v1/news"), payload);
|
auto future = gatewayController->postAsync(QString("%1v1/news"), payload);
|
||||||
@@ -69,4 +111,3 @@ QFuture<QPair<ErrorCode, QJsonArray>> NewsController::fetchNews()
|
|||||||
return qMakePair(ErrorCode::NoError, newsArray);
|
return qMakePair(ErrorCode::NoError, newsArray);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,26 +3,28 @@
|
|||||||
|
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
|
||||||
#include "core/utils/errorCodes.h"
|
#include "core/utils/errorCodes.h"
|
||||||
#include "core/utils/routeModes.h"
|
#include "core/utils/routeModes.h"
|
||||||
#include "core/utils/commonStructs.h"
|
#include "core/utils/commonStructs.h"
|
||||||
#include "core/repositories/secureAppSettingsRepository.h"
|
#include "core/repositories/secureAppSettingsRepository.h"
|
||||||
#include "core/controllers/serversController.h"
|
#include "core/repositories/secureServersRepository.h"
|
||||||
|
|
||||||
class NewsController
|
class NewsController
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NewsController(SecureAppSettingsRepository* appSettingsRepository,
|
explicit NewsController(SecureAppSettingsRepository* appSettingsRepository,
|
||||||
ServersController* serversController);
|
SecureServersRepository* serversRepository);
|
||||||
|
|
||||||
QFuture<QPair<ErrorCode, QJsonArray>> fetchNews();
|
QFuture<QPair<ErrorCode, QJsonArray>> fetchNews();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QJsonObject getServicesList() const;
|
||||||
|
|
||||||
SecureAppSettingsRepository* m_appSettingsRepository;
|
SecureAppSettingsRepository* m_appSettingsRepository;
|
||||||
ServersController* m_serversController;
|
SecureServersRepository* m_serversRepository;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NEWSCONTROLLER_H
|
#endif // NEWSCONTROLLER_H
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include "core/controllers/gatewayController.h"
|
#include "core/controllers/gatewayController.h"
|
||||||
#include "core/utils/api/apiEnums.h"
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/utils/constants/apiKeys.h"
|
#include "core/utils/constants/apiKeys.h"
|
||||||
#include "core/utils/constants/apiConstants.h"
|
#include "core/utils/constants/apiConstants.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
#include "core/utils/containerEnum.h"
|
#include "core/utils/containerEnum.h"
|
||||||
#include "core/utils/containers/containerUtils.h"
|
#include "core/utils/containers/containerUtils.h"
|
||||||
#include "core/utils/protocolEnum.h"
|
#include "core/utils/protocolEnum.h"
|
||||||
#include "core/utils/api/apiEnums.h"
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/utils/constants/apiKeys.h"
|
#include "core/utils/constants/apiKeys.h"
|
||||||
#include "core/utils/constants/apiConstants.h"
|
#include "core/utils/constants/apiConstants.h"
|
||||||
#include "core/utils/api/apiUtils.h"
|
#include "core/utils/api/apiUtils.h"
|
||||||
@@ -26,7 +26,6 @@
|
|||||||
#include "core/utils/constants/configKeys.h"
|
#include "core/utils/constants/configKeys.h"
|
||||||
#include "core/utils/constants/protocolConstants.h"
|
#include "core/utils/constants/protocolConstants.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "core/models/serverConfig.h"
|
|
||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
#include "core/models/api/apiConfig.h"
|
#include "core/models/api/apiConfig.h"
|
||||||
|
|
||||||
@@ -196,7 +195,7 @@ void SubscriptionController::updateApiConfigInJson(QJsonObject &serverConfigJson
|
|||||||
apiConfig[apiDefs::key::serviceProtocol] = serviceProtocol;
|
apiConfig[apiDefs::key::serviceProtocol] = serviceProtocol;
|
||||||
apiConfig[apiDefs::key::userCountryCode] = userCountryCode;
|
apiConfig[apiDefs::key::userCountryCode] = userCountryCode;
|
||||||
|
|
||||||
if (serverConfigJson.value(configKey::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) {
|
if (serverConfigJson.value(configKey::configVersion).toInt() == serverConfigUtils::ConfigSource::AmneziaGateway) {
|
||||||
QJsonObject responseObj = QJsonDocument::fromJson(apiResponseBody).object();
|
QJsonObject responseObj = QJsonDocument::fromJson(apiResponseBody).object();
|
||||||
if (responseObj.contains(apiDefs::key::supportedProtocols)) {
|
if (responseObj.contains(apiDefs::key::supportedProtocols)) {
|
||||||
apiConfig.insert(apiDefs::key::supportedProtocols, responseObj.value(apiDefs::key::supportedProtocols).toArray());
|
apiConfig.insert(apiDefs::key::supportedProtocols, responseObj.value(apiDefs::key::supportedProtocols).toArray());
|
||||||
@@ -217,8 +216,7 @@ ErrorCode SubscriptionController::executeRequest(const QString &endpoint, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::importServiceFromGateway(const QString &userCountryCode, const QString &serviceType,
|
ErrorCode SubscriptionController::importServiceFromGateway(const QString &userCountryCode, const QString &serviceType,
|
||||||
const QString &serviceProtocol, const ProtocolData &protocolData,
|
const QString &serviceProtocol, const ProtocolData &protocolData)
|
||||||
ServerConfig &serverConfig)
|
|
||||||
{
|
{
|
||||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||||
QString(APP_VERSION),
|
QString(APP_VERSION),
|
||||||
@@ -247,20 +245,18 @@ ErrorCode SubscriptionController::importServiceFromGateway(const QString &userCo
|
|||||||
|
|
||||||
updateApiConfigInJson(serverConfigJson, serviceType, serviceProtocol, userCountryCode, responseBody);
|
updateApiConfigInJson(serverConfigJson, serviceType, serviceProtocol, userCountryCode, responseBody);
|
||||||
|
|
||||||
ServerConfig serverConfigModel = ServerConfig::fromJson(serverConfigJson);
|
if (serverConfigJson.value(configKey::configVersion).toInt() != serverConfigUtils::ConfigSource::AmneziaGateway) {
|
||||||
|
|
||||||
if (!serverConfigModel.isApiV2()) {
|
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_serversRepository->addServer(serverConfigModel);
|
ApiV2ServerConfig apiV2ServerConfig = ApiV2ServerConfig::fromJson(serverConfigJson);
|
||||||
serverConfig = serverConfigModel;
|
m_serversRepository->addServer(QString(), apiV2ServerConfig.toJson(),
|
||||||
|
serverConfigUtils::configTypeFromJson(apiV2ServerConfig.toJson()));
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::importTrialFromGateway(const QString &userCountryCode, const QString &serviceType,
|
ErrorCode SubscriptionController::importTrialFromGateway(const QString &userCountryCode, const QString &serviceType,
|
||||||
const QString &serviceProtocol, const QString &email,
|
const QString &serviceProtocol, const QString &email)
|
||||||
ServerConfig &serverConfig)
|
|
||||||
{
|
{
|
||||||
const QString trimmedEmail = email.trimmed();
|
const QString trimmedEmail = email.trimmed();
|
||||||
if (trimmedEmail.isEmpty()) {
|
if (trimmedEmail.isEmpty()) {
|
||||||
@@ -306,16 +302,19 @@ ErrorCode SubscriptionController::importTrialFromGateway(const QString &userCoun
|
|||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject configObject = QJsonDocument::fromJson(configBytes).object();
|
QJsonObject configObject = QJsonDocument::fromJson(configBytes).object();
|
||||||
ServerConfig serverConfigModel = ServerConfig::fromJson(configObject);
|
if (configObject.value(configKey::configVersion).toInt() != serverConfigUtils::ConfigSource::AmneziaGateway) {
|
||||||
m_serversRepository->addServer(serverConfigModel);
|
return ErrorCode::InternalError;
|
||||||
serverConfig = serverConfigModel;
|
}
|
||||||
|
|
||||||
|
ApiV2ServerConfig apiV2ServerConfig = ApiV2ServerConfig::fromJson(configObject);
|
||||||
|
m_serversRepository->addServer(QString(), apiV2ServerConfig.toJson(),
|
||||||
|
serverConfigUtils::configTypeFromJson(apiV2ServerConfig.toJson()));
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::importServiceFromAppStore(const QString &userCountryCode, const QString &serviceType,
|
ErrorCode SubscriptionController::importServiceFromAppStore(const QString &userCountryCode, const QString &serviceType,
|
||||||
const QString &serviceProtocol, const ProtocolData &protocolData,
|
const QString &serviceProtocol, const ProtocolData &protocolData,
|
||||||
const QString &transactionId, bool isTestPurchase,
|
const QString &transactionId, bool isTestPurchase,
|
||||||
ServerConfig &serverConfig,
|
|
||||||
int *duplicateServerIndex)
|
int *duplicateServerIndex)
|
||||||
{
|
{
|
||||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||||
@@ -351,15 +350,8 @@ ErrorCode SubscriptionController::importServiceFromAppStore(const QString &userC
|
|||||||
|
|
||||||
// Check if server with this VPN key already exists
|
// Check if server with this VPN key already exists
|
||||||
for (int i = 0; i < m_serversRepository->serversCount(); ++i) {
|
for (int i = 0; i < m_serversRepository->serversCount(); ++i) {
|
||||||
ServerConfig existingServerConfig = m_serversRepository->server(i);
|
const auto apiV2 = m_serversRepository->apiV2Config(m_serversRepository->serverIdAt(i));
|
||||||
QString existingVpnKey;
|
QString existingVpnKey = apiV2.has_value() ? apiV2->vpnKey() : QString();
|
||||||
if (existingServerConfig.isApiV1()) {
|
|
||||||
const ApiV1ServerConfig* apiV1 = existingServerConfig.as<ApiV1ServerConfig>();
|
|
||||||
existingVpnKey = apiV1 ? apiV1->vpnKey() : QString();
|
|
||||||
} else if (existingServerConfig.isApiV2()) {
|
|
||||||
const ApiV2ServerConfig* apiV2 = existingServerConfig.as<ApiV2ServerConfig>();
|
|
||||||
existingVpnKey = apiV2 ? apiV2->vpnKey() : QString();
|
|
||||||
}
|
|
||||||
existingVpnKey.replace(QStringLiteral("vpn://"), QString());
|
existingVpnKey.replace(QStringLiteral("vpn://"), QString());
|
||||||
if (!existingVpnKey.isEmpty() && existingVpnKey == normalizedKey) {
|
if (!existingVpnKey.isEmpty() && existingVpnKey == normalizedKey) {
|
||||||
if (duplicateServerIndex) {
|
if (duplicateServerIndex) {
|
||||||
@@ -385,38 +377,28 @@ ErrorCode SubscriptionController::importServiceFromAppStore(const QString &userC
|
|||||||
|
|
||||||
quint16 crc = qChecksum(QJsonDocument(configObject).toJson());
|
quint16 crc = qChecksum(QJsonDocument(configObject).toJson());
|
||||||
|
|
||||||
ServerConfig serverConfigModel = ServerConfig::fromJson(configObject);
|
if (configObject.value(configKey::configVersion).toInt() != serverConfigUtils::ConfigSource::AmneziaGateway) {
|
||||||
|
|
||||||
if (!serverConfigModel.isApiV2()) {
|
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
ApiV2ServerConfig apiV2ServerConfig = ApiV2ServerConfig::fromJson(configObject);
|
||||||
if (!apiV2) {
|
ApiV2ServerConfig* apiV2 = &apiV2ServerConfig;
|
||||||
return ErrorCode::InternalError;
|
|
||||||
}
|
|
||||||
apiV2->apiConfig.vpnKey = normalizedKey;
|
apiV2->apiConfig.vpnKey = normalizedKey;
|
||||||
apiV2->apiConfig.isTestPurchase = isTestPurchase;
|
apiV2->apiConfig.isTestPurchase = isTestPurchase;
|
||||||
apiV2->apiConfig.isInAppPurchase = true;
|
apiV2->apiConfig.isInAppPurchase = true;
|
||||||
apiV2->apiConfig.subscriptionExpiredByServer = false;
|
apiV2->apiConfig.subscriptionExpiredByServer = false;
|
||||||
apiV2->crc = crc;
|
apiV2->crc = crc;
|
||||||
|
|
||||||
m_serversRepository->addServer(serverConfigModel);
|
m_serversRepository->addServer(QString(), apiV2ServerConfig.toJson(),
|
||||||
serverConfig = serverConfigModel;
|
serverConfigUtils::configTypeFromJson(apiV2ServerConfig.toJson()));
|
||||||
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::updateServiceFromGateway(int serverIndex, const QString &newCountryCode, bool isConnectEvent)
|
ErrorCode SubscriptionController::updateServiceFromGateway(const QString &serverId, const QString &newCountryCode, bool isConnectEvent)
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
if (!serverConfigModel.isApiV2()) {
|
|
||||||
return ErrorCode::InternalError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
|
||||||
if (!apiV2) {
|
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
const bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
|
const bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
|
||||||
@@ -445,12 +427,10 @@ ErrorCode SubscriptionController::updateServiceFromGateway(int serverIndex, cons
|
|||||||
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody, isTestPurchase);
|
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody, isTestPurchase);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
if (errorCode == ErrorCode::ApiSubscriptionExpiredError && !apiV2->apiConfig.isInAppPurchase) {
|
if (errorCode == ErrorCode::ApiSubscriptionExpiredError && !apiV2->apiConfig.isInAppPurchase) {
|
||||||
ServerConfig expiredServerConfig = serverConfigModel;
|
ApiV2ServerConfig expiredApiV2 = *apiV2;
|
||||||
ApiV2ServerConfig *expiredApiV2 = expiredServerConfig.as<ApiV2ServerConfig>();
|
expiredApiV2.apiConfig.subscriptionExpiredByServer = true;
|
||||||
if (expiredApiV2) {
|
m_serversRepository->editServer(serverId, expiredApiV2.toJson(),
|
||||||
expiredApiV2->apiConfig.subscriptionExpiredByServer = true;
|
serverConfigUtils::configTypeFromJson(expiredApiV2.toJson()));
|
||||||
m_serversRepository->editServer(serverIndex, expiredServerConfig);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
@@ -463,16 +443,12 @@ ErrorCode SubscriptionController::updateServiceFromGateway(int serverIndex, cons
|
|||||||
|
|
||||||
updateApiConfigInJson(serverConfigJson, apiV2->apiConfig.serviceType, serviceProtocol, apiV2->apiConfig.userCountryCode, responseBody);
|
updateApiConfigInJson(serverConfigJson, apiV2->apiConfig.serviceType, serviceProtocol, apiV2->apiConfig.userCountryCode, responseBody);
|
||||||
|
|
||||||
ServerConfig newServerConfigModel = ServerConfig::fromJson(serverConfigJson);
|
if (serverConfigJson.value(configKey::configVersion).toInt() != serverConfigUtils::ConfigSource::AmneziaGateway) {
|
||||||
|
|
||||||
if (!newServerConfigModel.isApiV2()) {
|
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiV2ServerConfig* newApiV2 = newServerConfigModel.as<ApiV2ServerConfig>();
|
ApiV2ServerConfig newApiV2Config = ApiV2ServerConfig::fromJson(serverConfigJson);
|
||||||
if (!newApiV2) {
|
ApiV2ServerConfig* newApiV2 = &newApiV2Config;
|
||||||
return ErrorCode::InternalError;
|
|
||||||
}
|
|
||||||
|
|
||||||
newApiV2->apiConfig.vpnKey = apiV2->apiConfig.vpnKey;
|
newApiV2->apiConfig.vpnKey = apiV2->apiConfig.vpnKey;
|
||||||
newApiV2->apiConfig.isTestPurchase = apiV2->apiConfig.isTestPurchase;
|
newApiV2->apiConfig.isTestPurchase = apiV2->apiConfig.isTestPurchase;
|
||||||
@@ -487,20 +463,15 @@ ErrorCode SubscriptionController::updateServiceFromGateway(int serverIndex, cons
|
|||||||
newApiV2->nameOverriddenByUser = true;
|
newApiV2->nameOverriddenByUser = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_serversRepository->editServer(serverIndex, newServerConfigModel);
|
m_serversRepository->editServer(serverId, newApiV2Config.toJson(),
|
||||||
|
serverConfigUtils::configTypeFromJson(newApiV2Config.toJson()));
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::deactivateDevice(int serverIndex)
|
ErrorCode SubscriptionController::deactivateDevice(const QString &serverId)
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
if (!serverConfigModel.isApiV2()) {
|
|
||||||
return ErrorCode::NoError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
|
||||||
if (!apiV2) {
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,23 +499,16 @@ ErrorCode SubscriptionController::deactivateDevice(int serverIndex)
|
|||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConfigModel.visit([](auto& arg) {
|
apiV2->containers.clear();
|
||||||
arg.containers.clear();
|
m_serversRepository->editServer(serverId, apiV2->toJson(),
|
||||||
});
|
serverConfigUtils::configTypeFromJson(apiV2->toJson()));
|
||||||
m_serversRepository->editServer(serverIndex, serverConfigModel);
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::deactivateExternalDevice(int serverIndex, const QString &uuid, const QString &serverCountryCode)
|
ErrorCode SubscriptionController::deactivateExternalDevice(const QString &serverId, const QString &uuid, const QString &serverCountryCode)
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
if (!serverConfigModel.isApiV2()) {
|
|
||||||
return ErrorCode::NoError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
|
||||||
if (!apiV2) {
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,25 +537,18 @@ ErrorCode SubscriptionController::deactivateExternalDevice(int serverIndex, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (uuid == m_appSettingsRepository->getInstallationUuid(true)) {
|
if (uuid == m_appSettingsRepository->getInstallationUuid(true)) {
|
||||||
serverConfigModel.visit([](auto& arg) {
|
apiV2->containers.clear();
|
||||||
arg.containers.clear();
|
m_serversRepository->editServer(serverId, apiV2->toJson(),
|
||||||
});
|
serverConfigUtils::configTypeFromJson(apiV2->toJson()));
|
||||||
m_serversRepository->editServer(serverIndex, serverConfigModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::exportNativeConfig(int serverIndex, const QString &serverCountryCode, QString &nativeConfig)
|
ErrorCode SubscriptionController::exportNativeConfig(const QString &serverId, const QString &serverCountryCode, QString &nativeConfig)
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
if (!serverConfigModel.isApiV2()) {
|
|
||||||
return ErrorCode::InternalError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
|
||||||
if (!apiV2) {
|
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
const bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
|
const bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
|
||||||
@@ -624,16 +581,10 @@ ErrorCode SubscriptionController::exportNativeConfig(int serverIndex, const QStr
|
|||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::revokeNativeConfig(int serverIndex, const QString &serverCountryCode)
|
ErrorCode SubscriptionController::revokeNativeConfig(const QString &serverId, const QString &serverCountryCode)
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
if (!serverConfigModel.isApiV2()) {
|
|
||||||
return ErrorCode::InternalError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
|
||||||
if (!apiV2) {
|
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
const bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
|
const bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
|
||||||
@@ -661,126 +612,54 @@ ErrorCode SubscriptionController::revokeNativeConfig(int serverIndex, const QStr
|
|||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::updateServiceFromTelegram(int serverIndex)
|
ErrorCode SubscriptionController::prepareVpnKeyExport(const QString &serverId, QString &vpnKey)
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
if (!serverConfigModel.isApiV1()) {
|
|
||||||
return ErrorCode::InternalError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ApiV1ServerConfig* apiV1 = serverConfigModel.as<ApiV1ServerConfig>();
|
|
||||||
if (!apiV1) {
|
|
||||||
return ErrorCode::InternalError;
|
|
||||||
}
|
|
||||||
QString serviceProtocol = apiV1->protocol;
|
|
||||||
ProtocolData protocolData = generateProtocolData(serviceProtocol);
|
|
||||||
QString installationUuid = m_appSettingsRepository->getInstallationUuid(true);
|
|
||||||
|
|
||||||
GatewayController gatewayController(m_appSettingsRepository->getGatewayEndpoint(), m_appSettingsRepository->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
|
||||||
m_appSettingsRepository->isStrictKillSwitchEnabled());
|
|
||||||
|
|
||||||
QJsonObject apiPayload;
|
|
||||||
appendProtocolDataToApiPayload(serviceProtocol, protocolData, apiPayload);
|
|
||||||
apiPayload[apiDefs::key::uuid] = installationUuid;
|
|
||||||
apiPayload[apiDefs::key::osVersion] = QSysInfo::productType();
|
|
||||||
apiPayload[apiDefs::key::appVersion] = QString(APP_VERSION);
|
|
||||||
apiPayload[configKey::accessToken] = apiV1->apiKey;
|
|
||||||
apiPayload[apiDefs::key::apiEndpoint] = apiV1->apiEndpoint;
|
|
||||||
|
|
||||||
QByteArray responseBody;
|
|
||||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/proxy_config"), apiPayload, responseBody);
|
|
||||||
if (errorCode != ErrorCode::NoError) {
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject serverConfigJson;
|
|
||||||
errorCode = extractServerConfigJsonFromResponse(responseBody, serviceProtocol, protocolData, serverConfigJson);
|
|
||||||
if (errorCode != ErrorCode::NoError) {
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerConfig newServerConfigModel = ServerConfig::fromJson(serverConfigJson);
|
|
||||||
|
|
||||||
if (!newServerConfigModel.isApiV1()) {
|
|
||||||
return ErrorCode::InternalError;
|
|
||||||
}
|
|
||||||
|
|
||||||
ApiV1ServerConfig* newApiV1 = newServerConfigModel.as<ApiV1ServerConfig>();
|
|
||||||
if (!newApiV1) {
|
|
||||||
return ErrorCode::InternalError;
|
|
||||||
}
|
|
||||||
newApiV1->apiKey = apiV1->apiKey;
|
|
||||||
newApiV1->apiEndpoint = apiV1->apiEndpoint;
|
|
||||||
newApiV1->crc = apiV1->crc;
|
|
||||||
|
|
||||||
m_serversRepository->editServer(serverIndex, newServerConfigModel);
|
|
||||||
return ErrorCode::NoError;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorCode SubscriptionController::prepareVpnKeyExport(int serverIndex, QString &vpnKey)
|
|
||||||
{
|
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
|
||||||
|
|
||||||
if (serverConfigModel.isApiV1()) {
|
|
||||||
const ApiV1ServerConfig* apiV1 = serverConfigModel.as<ApiV1ServerConfig>();
|
|
||||||
vpnKey = apiV1 ? apiV1->vpnKey() : QString();
|
|
||||||
} else if (serverConfigModel.isApiV2()) {
|
|
||||||
ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
|
||||||
vpnKey = apiV2 ? apiV2->vpnKey() : QString();
|
|
||||||
if (vpnKey.isEmpty()) {
|
|
||||||
QJsonObject serverJson = serverConfigModel.toJson();
|
|
||||||
vpnKey = apiUtils::getPremiumV2VpnKey(serverJson);
|
|
||||||
if (vpnKey.isEmpty()) {
|
|
||||||
return ErrorCode::ApiConfigEmptyError;
|
|
||||||
}
|
|
||||||
apiV2->apiConfig.vpnKey = vpnKey;
|
|
||||||
m_serversRepository->editServer(serverIndex, serverConfigModel);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return ErrorCode::ApiConfigEmptyError;
|
return ErrorCode::ApiConfigEmptyError;
|
||||||
}
|
}
|
||||||
|
vpnKey = apiV2->vpnKey();
|
||||||
|
if (vpnKey.isEmpty()) {
|
||||||
|
vpnKey = apiUtils::getPremiumV2VpnKey(apiV2->toJson());
|
||||||
|
if (vpnKey.isEmpty()) {
|
||||||
|
return ErrorCode::ApiConfigEmptyError;
|
||||||
|
}
|
||||||
|
apiV2->apiConfig.vpnKey = vpnKey;
|
||||||
|
m_serversRepository->editServer(serverId, apiV2->toJson(),
|
||||||
|
serverConfigUtils::configTypeFromJson(apiV2->toJson()));
|
||||||
|
}
|
||||||
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::validateAndUpdateConfig(int serverIndex, bool hasInstalledContainers)
|
ErrorCode SubscriptionController::validateAndUpdateConfig(const QString &serverId, bool hasInstalledContainers)
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
if (!m_serversRepository->apiV2Config(serverId).has_value()) {
|
||||||
|
|
||||||
apiDefs::ConfigSource configSource;
|
|
||||||
if (serverConfigModel.isApiV1()) {
|
|
||||||
configSource = apiDefs::ConfigSource::Telegram;
|
|
||||||
} else if (serverConfigModel.isApiV2()) {
|
|
||||||
configSource = apiDefs::ConfigSource::AmneziaGateway;
|
|
||||||
} else {
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configSource == apiDefs::ConfigSource::Telegram && !hasInstalledContainers) {
|
if (!hasInstalledContainers) {
|
||||||
removeApiConfig(serverIndex);
|
return updateServiceFromGateway(serverId, "", true);
|
||||||
return updateServiceFromTelegram(serverIndex);
|
|
||||||
} else if (configSource == apiDefs::ConfigSource::AmneziaGateway && !hasInstalledContainers) {
|
|
||||||
return updateServiceFromGateway(serverIndex, "", true);
|
|
||||||
} else if (configSource && isApiKeyExpired(serverIndex)) {
|
|
||||||
qDebug() << "attempt to update api config by expires_at event";
|
|
||||||
if (configSource == apiDefs::ConfigSource::AmneziaGateway) {
|
|
||||||
return updateServiceFromGateway(serverIndex, "", true);
|
|
||||||
} else {
|
|
||||||
removeApiConfig(serverIndex);
|
|
||||||
return updateServiceFromTelegram(serverIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isApiKeyExpired(serverId)) {
|
||||||
|
qDebug() << "attempt to update api config by expires_at event";
|
||||||
|
return updateServiceFromGateway(serverId, "", true);
|
||||||
|
}
|
||||||
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubscriptionController::removeApiConfig(int serverIndex)
|
void SubscriptionController::removeApiConfig(const QString &serverId)
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||||
QString description = serverConfigModel.description();
|
QString description = apiV2->description;
|
||||||
QString hostName = serverConfigModel.hostName();
|
QString hostName = apiV2->hostName;
|
||||||
QString vpncName = QString("%1 (%2) %3")
|
QString vpncName = QString("%1 (%2) %3")
|
||||||
.arg(description)
|
.arg(description)
|
||||||
.arg(hostName)
|
.arg(hostName)
|
||||||
@@ -789,34 +668,42 @@ void SubscriptionController::removeApiConfig(int serverIndex)
|
|||||||
AmneziaVPN::removeVPNC(vpncName.toStdString());
|
AmneziaVPN::removeVPNC(vpncName.toStdString());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
serverConfigModel.visit([](auto& arg) {
|
apiV2->dns1.clear();
|
||||||
arg.dns1.clear();
|
apiV2->dns2.clear();
|
||||||
arg.dns2.clear();
|
apiV2->containers.clear();
|
||||||
arg.containers.clear();
|
apiV2->hostName.clear();
|
||||||
arg.hostName.clear();
|
apiV2->defaultContainer = DockerContainer::None;
|
||||||
arg.defaultContainer = DockerContainer::None;
|
apiV2->apiConfig.publicKey = ApiConfig::PublicKeyInfo{};
|
||||||
});
|
|
||||||
|
|
||||||
if (serverConfigModel.isApiV2()) {
|
m_serversRepository->editServer(serverId, apiV2->toJson(),
|
||||||
ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
serverConfigUtils::configTypeFromJson(apiV2->toJson()));
|
||||||
if (apiV2) {
|
|
||||||
apiV2->apiConfig.publicKey = ApiConfig::PublicKeyInfo{};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_serversRepository->editServer(serverIndex, serverConfigModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SubscriptionController::isApiKeyExpired(int serverIndex) const
|
bool SubscriptionController::removeServer(const QString &serverId)
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
if (serverId.isEmpty()) {
|
||||||
|
|
||||||
if (!serverConfigModel.isApiV2()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
if (!m_serversRepository->apiV2Config(serverId).has_value()) {
|
||||||
if (!apiV2) {
|
qWarning().noquote() << "SubscriptionController::removeServer: not an Api V2 server, id" << serverId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ErrorCode revokeError = deactivateDevice(serverId);
|
||||||
|
if (revokeError != ErrorCode::NoError && revokeError != ErrorCode::ApiNotFoundError) {
|
||||||
|
qWarning().noquote() << "SubscriptionController::removeServer: deactivateDevice failed (error"
|
||||||
|
<< static_cast<int>(revokeError) << "); removing locally anyway.";
|
||||||
|
}
|
||||||
|
|
||||||
|
m_serversRepository->removeServer(serverId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SubscriptionController::isApiKeyExpired(const QString &serverId) const
|
||||||
|
{
|
||||||
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const QString expiresAt = apiV2->apiConfig.publicKey.expiresAt;
|
const QString expiresAt = apiV2->apiConfig.publicKey.expiresAt;
|
||||||
@@ -833,31 +720,24 @@ bool SubscriptionController::isApiKeyExpired(int serverIndex) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubscriptionController::setCurrentProtocol(int serverIndex, const QString &protocolName)
|
void SubscriptionController::setCurrentProtocol(const QString &serverId, const QString &protocolName)
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
if (serverConfigModel.isApiV2()) {
|
if (apiV2.has_value()) {
|
||||||
ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
apiV2->apiConfig.serviceProtocol = protocolName;
|
||||||
if (apiV2) {
|
m_serversRepository->editServer(serverId, apiV2->toJson(),
|
||||||
apiV2->apiConfig.serviceProtocol = protocolName;
|
serverConfigUtils::configTypeFromJson(apiV2->toJson()));
|
||||||
}
|
|
||||||
m_serversRepository->editServer(serverIndex, serverConfigModel);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SubscriptionController::isVlessProtocol(int serverIndex) const
|
bool SubscriptionController::isVlessProtocol(const QString &serverId) const
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
if (serverConfigModel.isApiV2()) {
|
return apiV2.has_value() && apiV2->serviceProtocol() == "vless";
|
||||||
const ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
|
||||||
return apiV2 && apiV2->serviceProtocol() == "vless";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::processAppStorePurchase(const QString &userCountryCode, const QString &serviceType,
|
ErrorCode SubscriptionController::processAppStorePurchase(const QString &userCountryCode, const QString &serviceType,
|
||||||
const QString &serviceProtocol, const QString &productId,
|
const QString &serviceProtocol, const QString &productId,
|
||||||
ServerConfig &serverConfig,
|
|
||||||
int *duplicateServerIndex)
|
int *duplicateServerIndex)
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||||
@@ -891,13 +771,12 @@ ErrorCode SubscriptionController::processAppStorePurchase(const QString &userCou
|
|||||||
|
|
||||||
ProtocolData protocolData = generateProtocolData(serviceProtocol);
|
ProtocolData protocolData = generateProtocolData(serviceProtocol);
|
||||||
return importServiceFromAppStore(userCountryCode, serviceType, serviceProtocol, protocolData,
|
return importServiceFromAppStore(userCountryCode, serviceType, serviceProtocol, protocolData,
|
||||||
originalTransactionId, isTestPurchase, serverConfig, duplicateServerIndex);
|
originalTransactionId, isTestPurchase, duplicateServerIndex);
|
||||||
#else
|
#else
|
||||||
Q_UNUSED(userCountryCode);
|
Q_UNUSED(userCountryCode);
|
||||||
Q_UNUSED(serviceType);
|
Q_UNUSED(serviceType);
|
||||||
Q_UNUSED(serviceProtocol);
|
Q_UNUSED(serviceProtocol);
|
||||||
Q_UNUSED(productId);
|
Q_UNUSED(productId);
|
||||||
Q_UNUSED(serverConfig);
|
|
||||||
return ErrorCode::ApiPurchaseError;
|
return ErrorCode::ApiPurchaseError;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -956,10 +835,9 @@ SubscriptionController::AppStoreRestoreResult SubscriptionController::processApp
|
|||||||
<< "originalTransactionId =" << originalTransactionId << "productId =" << transactionProductId;
|
<< "originalTransactionId =" << originalTransactionId << "productId =" << transactionProductId;
|
||||||
|
|
||||||
ProtocolData protocolData = generateProtocolData(serviceProtocol);
|
ProtocolData protocolData = generateProtocolData(serviceProtocol);
|
||||||
ServerConfig serverConfig;
|
|
||||||
int currentDuplicateServerIndex = -1;
|
int currentDuplicateServerIndex = -1;
|
||||||
ErrorCode errorCode = importServiceFromAppStore(userCountryCode, serviceType, serviceProtocol, protocolData,
|
ErrorCode errorCode = importServiceFromAppStore(userCountryCode, serviceType, serviceProtocol, protocolData,
|
||||||
originalTransactionId, isTestPurchase, serverConfig,
|
originalTransactionId, isTestPurchase,
|
||||||
¤tDuplicateServerIndex);
|
¤tDuplicateServerIndex);
|
||||||
|
|
||||||
if (errorCode == ErrorCode::ApiConfigAlreadyAdded) {
|
if (errorCode == ErrorCode::ApiConfigAlreadyAdded) {
|
||||||
@@ -991,16 +869,10 @@ SubscriptionController::AppStoreRestoreResult SubscriptionController::processApp
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SubscriptionController::getAccountInfo(int serverIndex, QJsonObject &accountInfo)
|
ErrorCode SubscriptionController::getAccountInfo(const QString &serverId, QJsonObject &accountInfo)
|
||||||
{
|
{
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
if (!serverConfigModel.isApiV2()) {
|
|
||||||
return ErrorCode::InternalError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ApiV2ServerConfig* apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
|
||||||
if (!apiV2) {
|
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
|
bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
|
||||||
@@ -1030,20 +902,13 @@ ErrorCode SubscriptionController::getAccountInfo(int serverIndex, QJsonObject &a
|
|||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<QPair<ErrorCode, QString>> SubscriptionController::getRenewalLink(int serverIndex)
|
QFuture<QPair<ErrorCode, QString>> SubscriptionController::getRenewalLink(const QString &serverId)
|
||||||
{
|
{
|
||||||
auto promise = QSharedPointer<QPromise<QPair<ErrorCode, QString>>>::create();
|
auto promise = QSharedPointer<QPromise<QPair<ErrorCode, QString>>>::create();
|
||||||
promise->start();
|
promise->start();
|
||||||
|
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
auto apiV2 = m_serversRepository->apiV2Config(serverId);
|
||||||
if (!serverConfigModel.isApiV2()) {
|
if (!apiV2.has_value()) {
|
||||||
promise->addResult(qMakePair(ErrorCode::InternalError, QString()));
|
|
||||||
promise->finish();
|
|
||||||
return promise->future();
|
|
||||||
}
|
|
||||||
|
|
||||||
const ApiV2ServerConfig *apiV2 = serverConfigModel.as<ApiV2ServerConfig>();
|
|
||||||
if (!apiV2) {
|
|
||||||
promise->addResult(qMakePair(ErrorCode::InternalError, QString()));
|
promise->addResult(qMakePair(ErrorCode::InternalError, QString()));
|
||||||
promise->finish();
|
promise->finish();
|
||||||
return promise->future();
|
return promise->future();
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "core/utils/commonStructs.h"
|
#include "core/utils/commonStructs.h"
|
||||||
#include "core/repositories/secureServersRepository.h"
|
#include "core/repositories/secureServersRepository.h"
|
||||||
#include "core/repositories/secureAppSettingsRepository.h"
|
#include "core/repositories/secureAppSettingsRepository.h"
|
||||||
#include "core/models/serverConfig.h"
|
|
||||||
|
|
||||||
class ServersController;
|
class ServersController;
|
||||||
|
|
||||||
@@ -48,44 +47,40 @@ public:
|
|||||||
|
|
||||||
ProtocolData generateProtocolData(const QString &protocol);
|
ProtocolData generateProtocolData(const QString &protocol);
|
||||||
void appendProtocolDataToApiPayload(const QString &protocol, const ProtocolData &protocolData, QJsonObject &apiPayload);
|
void appendProtocolDataToApiPayload(const QString &protocol, const ProtocolData &protocolData, QJsonObject &apiPayload);
|
||||||
ErrorCode fillServerConfig(const QJsonObject &serverConfigJson, ServerConfig &serverConfig);
|
|
||||||
|
|
||||||
ErrorCode importServiceFromGateway(const QString &userCountryCode, const QString &serviceType,
|
ErrorCode importServiceFromGateway(const QString &userCountryCode, const QString &serviceType,
|
||||||
const QString &serviceProtocol, const ProtocolData &protocolData,
|
const QString &serviceProtocol, const ProtocolData &protocolData);
|
||||||
ServerConfig &serverConfig);
|
|
||||||
ErrorCode importTrialFromGateway(const QString &userCountryCode, const QString &serviceType,
|
ErrorCode importTrialFromGateway(const QString &userCountryCode, const QString &serviceType,
|
||||||
const QString &serviceProtocol, const QString &email,
|
const QString &serviceProtocol, const QString &email);
|
||||||
ServerConfig &serverConfig);
|
|
||||||
|
|
||||||
ErrorCode importServiceFromAppStore(const QString &userCountryCode, const QString &serviceType,
|
ErrorCode importServiceFromAppStore(const QString &userCountryCode, const QString &serviceType,
|
||||||
const QString &serviceProtocol, const ProtocolData &protocolData,
|
const QString &serviceProtocol, const ProtocolData &protocolData,
|
||||||
const QString &transactionId, bool isTestPurchase,
|
const QString &transactionId, bool isTestPurchase,
|
||||||
ServerConfig &serverConfig,
|
|
||||||
int *duplicateServerIndex = nullptr);
|
int *duplicateServerIndex = nullptr);
|
||||||
|
|
||||||
ErrorCode updateServiceFromGateway(int serverIndex, const QString &newCountryCode, bool isConnectEvent);
|
ErrorCode updateServiceFromGateway(const QString &serverId, const QString &newCountryCode, bool isConnectEvent);
|
||||||
|
|
||||||
ErrorCode deactivateDevice(int serverIndex);
|
ErrorCode deactivateDevice(const QString &serverId);
|
||||||
|
|
||||||
ErrorCode deactivateExternalDevice(int serverIndex, const QString &uuid, const QString &serverCountryCode);
|
ErrorCode deactivateExternalDevice(const QString &serverId, const QString &uuid, const QString &serverCountryCode);
|
||||||
|
|
||||||
ErrorCode exportNativeConfig(int serverIndex, const QString &serverCountryCode, QString &nativeConfig);
|
ErrorCode exportNativeConfig(const QString &serverId, const QString &serverCountryCode, QString &nativeConfig);
|
||||||
|
|
||||||
ErrorCode revokeNativeConfig(int serverIndex, const QString &serverCountryCode);
|
ErrorCode revokeNativeConfig(const QString &serverId, const QString &serverCountryCode);
|
||||||
|
|
||||||
ErrorCode updateServiceFromTelegram(int serverIndex);
|
ErrorCode prepareVpnKeyExport(const QString &serverId, QString &vpnKey);
|
||||||
|
|
||||||
ErrorCode prepareVpnKeyExport(int serverIndex, QString &vpnKey);
|
ErrorCode validateAndUpdateConfig(const QString &serverId, bool hasInstalledContainers);
|
||||||
|
|
||||||
ErrorCode validateAndUpdateConfig(int serverIndex, bool hasInstalledContainers);
|
void removeApiConfig(const QString &serverId);
|
||||||
|
|
||||||
void removeApiConfig(int serverIndex);
|
bool removeServer(const QString &serverId);
|
||||||
|
|
||||||
void setCurrentProtocol(int serverIndex, const QString &protocolName);
|
void setCurrentProtocol(const QString &serverId, const QString &protocolName);
|
||||||
bool isVlessProtocol(int serverIndex) const;
|
bool isVlessProtocol(const QString &serverId) const;
|
||||||
|
|
||||||
ErrorCode getAccountInfo(int serverIndex, QJsonObject &accountInfo);
|
ErrorCode getAccountInfo(const QString &serverId, QJsonObject &accountInfo);
|
||||||
QFuture<QPair<ErrorCode, QString>> getRenewalLink(int serverIndex);
|
QFuture<QPair<ErrorCode, QString>> getRenewalLink(const QString &serverId);
|
||||||
|
|
||||||
struct AppStoreRestoreResult
|
struct AppStoreRestoreResult
|
||||||
{
|
{
|
||||||
@@ -98,7 +93,6 @@ public:
|
|||||||
|
|
||||||
ErrorCode processAppStorePurchase(const QString &userCountryCode, const QString &serviceType,
|
ErrorCode processAppStorePurchase(const QString &userCountryCode, const QString &serviceType,
|
||||||
const QString &serviceProtocol, const QString &productId,
|
const QString &serviceProtocol, const QString &productId,
|
||||||
ServerConfig &serverConfig,
|
|
||||||
int *duplicateServerIndex = nullptr);
|
int *duplicateServerIndex = nullptr);
|
||||||
|
|
||||||
AppStoreRestoreResult processAppStoreRestore(const QString &userCountryCode, const QString &serviceType,
|
AppStoreRestoreResult processAppStoreRestore(const QString &userCountryCode, const QString &serviceType,
|
||||||
@@ -106,7 +100,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ErrorCode executeRequest(const QString &endpoint, const QJsonObject &apiPayload, QByteArray &responseBody, bool isTestPurchase = false);
|
ErrorCode executeRequest(const QString &endpoint, const QJsonObject &apiPayload, QByteArray &responseBody, bool isTestPurchase = false);
|
||||||
bool isApiKeyExpired(int serverIndex) const;
|
bool isApiKeyExpired(const QString &serverId) const;
|
||||||
|
|
||||||
ErrorCode extractServerConfigJsonFromResponse(const QByteArray &apiResponseBody, const QString &protocol,
|
ErrorCode extractServerConfigJsonFromResponse(const QByteArray &apiResponseBody, const QString &protocol,
|
||||||
const ProtocolData &protocolData, QJsonObject &serverConfigJson);
|
const ProtocolData &protocolData, QJsonObject &serverConfigJson);
|
||||||
|
|||||||
@@ -9,11 +9,11 @@
|
|||||||
#include "core/utils/constants/protocolConstants.h"
|
#include "core/utils/constants/protocolConstants.h"
|
||||||
#include "core/utils/utilities.h"
|
#include "core/utils/utilities.h"
|
||||||
#include "core/utils/networkUtilities.h"
|
#include "core/utils/networkUtilities.h"
|
||||||
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "core/utils/containerEnum.h"
|
#include "core/utils/containerEnum.h"
|
||||||
#include "core/utils/containers/containerUtils.h"
|
#include "core/utils/containers/containerUtils.h"
|
||||||
#include "core/utils/protocolEnum.h"
|
#include "core/utils/protocolEnum.h"
|
||||||
#include "core/models/serverConfig.h"
|
|
||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
#include "core/models/protocolConfig.h"
|
#include "core/models/protocolConfig.h"
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ void ConnectionController::setConnectionState(Vpn::ConnectionState state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ConnectionController::prepareConnection(int serverIndex,
|
ErrorCode ConnectionController::prepareConnection(const QString &serverId,
|
||||||
QJsonObject& vpnConfiguration,
|
QJsonObject& vpnConfiguration,
|
||||||
DockerContainer& container)
|
DockerContainer& container)
|
||||||
{
|
{
|
||||||
@@ -59,35 +59,98 @@ ErrorCode ConnectionController::prepareConnection(int serverIndex,
|
|||||||
return ErrorCode::AmneziaServiceNotRunning;
|
return ErrorCode::AmneziaServiceNotRunning;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
ContainerConfig containerConfigModel;
|
||||||
container = serverConfigModel.defaultContainer();
|
QPair<QString, QString> dns;
|
||||||
|
QString hostName;
|
||||||
|
QString description;
|
||||||
|
int configVersion = 0;
|
||||||
|
bool isApiConfig = false;
|
||||||
|
|
||||||
|
const auto kind = m_serversRepository->serverKind(serverId);
|
||||||
|
switch (kind) {
|
||||||
|
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
|
||||||
|
const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!cfg.has_value()) return ErrorCode::InternalError;
|
||||||
|
container = cfg->defaultContainer;
|
||||||
|
containerConfigModel = cfg->containerConfig(container);
|
||||||
|
dns = { cfg->dns1, cfg->dns2 };
|
||||||
|
hostName = cfg->hostName;
|
||||||
|
description = cfg->description;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::SelfHostedUser: {
|
||||||
|
const auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
|
||||||
|
if (!cfg.has_value()) return ErrorCode::InternalError;
|
||||||
|
container = cfg->defaultContainer;
|
||||||
|
containerConfigModel = cfg->containerConfig(container);
|
||||||
|
dns = { cfg->dns1, cfg->dns2 };
|
||||||
|
hostName = cfg->hostName;
|
||||||
|
description = cfg->description;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Native: {
|
||||||
|
const auto cfg = m_serversRepository->nativeConfig(serverId);
|
||||||
|
if (!cfg.has_value()) return ErrorCode::InternalError;
|
||||||
|
container = cfg->defaultContainer;
|
||||||
|
containerConfigModel = cfg->containerConfig(container);
|
||||||
|
dns = { cfg->dns1, cfg->dns2 };
|
||||||
|
hostName = cfg->hostName;
|
||||||
|
description = cfg->description;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
||||||
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
||||||
|
const auto cfg = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!cfg.has_value()) return ErrorCode::InternalError;
|
||||||
|
container = cfg->defaultContainer;
|
||||||
|
containerConfigModel = cfg->containerConfig(container);
|
||||||
|
dns = { cfg->dns1, cfg->dns2 };
|
||||||
|
hostName = cfg->hostName;
|
||||||
|
description = cfg->description;
|
||||||
|
configVersion = serverConfigUtils::ConfigSource::AmneziaGateway;
|
||||||
|
isApiConfig = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaFreeV2:
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default:
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isContainerSupported(container)) {
|
if (!isContainerSupported(container)) {
|
||||||
return ErrorCode::NotSupportedOnThisPlatform;
|
return ErrorCode::NotSupportedOnThisPlatform;
|
||||||
}
|
}
|
||||||
|
if (dns.first.isEmpty() || !NetworkUtilities::checkIPv4Format(dns.first)) {
|
||||||
|
if (m_appSettingsRepository->useAmneziaDns()) {
|
||||||
|
dns.first = protocols::dns::amneziaDnsIp;
|
||||||
|
} else {
|
||||||
|
dns.first = m_appSettingsRepository->primaryDns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dns.second.isEmpty() || !NetworkUtilities::checkIPv4Format(dns.second)) {
|
||||||
|
dns.second = m_appSettingsRepository->secondaryDns();
|
||||||
|
}
|
||||||
|
|
||||||
ContainerConfig containerConfigModel = m_serversRepository->containerConfig(serverIndex, container);
|
vpnConfiguration = createConnectionConfiguration(dns, isApiConfig, hostName, description, configVersion,
|
||||||
|
containerConfigModel, container);
|
||||||
auto dns = serverConfigModel.getDnsPair(m_appSettingsRepository->useAmneziaDns(),
|
|
||||||
m_appSettingsRepository->primaryDns(),
|
|
||||||
m_appSettingsRepository->secondaryDns());
|
|
||||||
|
|
||||||
vpnConfiguration = createConnectionConfiguration(dns, serverConfigModel, containerConfigModel, container);
|
|
||||||
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ConnectionController::openConnection(int serverIndex)
|
ErrorCode ConnectionController::openConnection(const QString &serverId)
|
||||||
{
|
{
|
||||||
QJsonObject vpnConfiguration;
|
QJsonObject vpnConfiguration;
|
||||||
DockerContainer container;
|
DockerContainer container;
|
||||||
|
|
||||||
ErrorCode errorCode = prepareConnection(serverIndex, vpnConfiguration, container);
|
ErrorCode errorCode = prepareConnection(serverId, vpnConfiguration, container);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit openConnectionRequested(serverIndex, container, vpnConfiguration);
|
emit openConnectionRequested(serverId, container, vpnConfiguration);
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +183,10 @@ ErrorCode ConnectionController::lastConnectionError() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject ConnectionController::createConnectionConfiguration(const QPair<QString, QString> &dns,
|
QJsonObject ConnectionController::createConnectionConfiguration(const QPair<QString, QString> &dns,
|
||||||
const ServerConfig &serverConfig,
|
bool isApiConfig,
|
||||||
|
const QString &hostName,
|
||||||
|
const QString &description,
|
||||||
|
int configVersion,
|
||||||
const ContainerConfig &containerConfig,
|
const ContainerConfig &containerConfig,
|
||||||
DockerContainer container)
|
DockerContainer container)
|
||||||
{
|
{
|
||||||
@@ -134,7 +200,7 @@ QJsonObject ConnectionController::createConnectionConfiguration(const QPair<QStr
|
|||||||
|
|
||||||
ConnectionSettings connectionSettings = {
|
ConnectionSettings connectionSettings = {
|
||||||
{ dns.first, dns.second },
|
{ dns.first, dns.second },
|
||||||
serverConfig.isApiConfig(),
|
isApiConfig,
|
||||||
{
|
{
|
||||||
m_appSettingsRepository->isSitesSplitTunnelingEnabled(),
|
m_appSettingsRepository->isSitesSplitTunnelingEnabled(),
|
||||||
m_appSettingsRepository->routeMode()
|
m_appSettingsRepository->routeMode()
|
||||||
@@ -160,10 +226,9 @@ QJsonObject ConnectionController::createConnectionConfiguration(const QPair<QStr
|
|||||||
vpnConfiguration[configKey::dns1] = dns.first;
|
vpnConfiguration[configKey::dns1] = dns.first;
|
||||||
vpnConfiguration[configKey::dns2] = dns.second;
|
vpnConfiguration[configKey::dns2] = dns.second;
|
||||||
|
|
||||||
vpnConfiguration[configKey::hostName] = serverConfig.hostName();
|
vpnConfiguration[configKey::hostName] = hostName;
|
||||||
vpnConfiguration[configKey::description] = serverConfig.description();
|
vpnConfiguration[configKey::description] = description;
|
||||||
|
vpnConfiguration[configKey::configVersion] = configVersion;
|
||||||
vpnConfiguration[configKey::configVersion] = serverConfig.configVersion();
|
|
||||||
|
|
||||||
return vpnConfiguration;
|
return vpnConfiguration;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,11 @@ public:
|
|||||||
QObject* parent = nullptr);
|
QObject* parent = nullptr);
|
||||||
~ConnectionController() = default;
|
~ConnectionController() = default;
|
||||||
|
|
||||||
ErrorCode prepareConnection(int serverIndex,
|
ErrorCode prepareConnection(const QString &serverId,
|
||||||
QJsonObject& vpnConfiguration,
|
QJsonObject& vpnConfiguration,
|
||||||
DockerContainer& container);
|
DockerContainer& container);
|
||||||
|
|
||||||
ErrorCode openConnection(int serverIndex);
|
ErrorCode openConnection(const QString &serverId);
|
||||||
|
|
||||||
void closeConnection();
|
void closeConnection();
|
||||||
|
|
||||||
@@ -50,7 +50,10 @@ public:
|
|||||||
void setConnectionState(Vpn::ConnectionState state);
|
void setConnectionState(Vpn::ConnectionState state);
|
||||||
|
|
||||||
QJsonObject createConnectionConfiguration(const QPair<QString, QString> &dns,
|
QJsonObject createConnectionConfiguration(const QPair<QString, QString> &dns,
|
||||||
const ServerConfig &serverConfig,
|
bool isApiConfig,
|
||||||
|
const QString &hostName,
|
||||||
|
const QString &description,
|
||||||
|
int configVersion,
|
||||||
const ContainerConfig &containerConfig,
|
const ContainerConfig &containerConfig,
|
||||||
DockerContainer container);
|
DockerContainer container);
|
||||||
|
|
||||||
@@ -60,7 +63,7 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void connectionStateChanged(Vpn::ConnectionState state);
|
void connectionStateChanged(Vpn::ConnectionState state);
|
||||||
void openConnectionRequested(int serverIndex, DockerContainer container, const QJsonObject &vpnConfiguration);
|
void openConnectionRequested(const QString &serverId, DockerContainer container, const QJsonObject &vpnConfiguration);
|
||||||
void closeConnectionRequested();
|
void closeConnectionRequested();
|
||||||
void setConnectionStateRequested(Vpn::ConnectionState state);
|
void setConnectionStateRequested(Vpn::ConnectionState state);
|
||||||
void killSwitchModeChangedRequested(bool enabled);
|
void killSwitchModeChangedRequested(bool enabled);
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "core/controllers/selfhosted/installController.h"
|
#include "core/controllers/selfhosted/installController.h"
|
||||||
#include "core/controllers/selfhosted/importController.h"
|
#include "core/controllers/selfhosted/importController.h"
|
||||||
#include "core/controllers/coreSignalHandlers.h"
|
#include "core/controllers/coreSignalHandlers.h"
|
||||||
#include "core/models/serverConfig.h"
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "secureQSettings.h"
|
#include "secureQSettings.h"
|
||||||
|
|
||||||
@@ -101,6 +100,12 @@ void CoreController::initModels()
|
|||||||
m_socks5ConfigModel = new Socks5ProxyConfigModel(this);
|
m_socks5ConfigModel = new Socks5ProxyConfigModel(this);
|
||||||
setQmlContextProperty("Socks5ProxyConfigModel", m_socks5ConfigModel);
|
setQmlContextProperty("Socks5ProxyConfigModel", m_socks5ConfigModel);
|
||||||
|
|
||||||
|
m_mtProxyConfigModel = new MtProxyConfigModel(this);
|
||||||
|
setQmlContextProperty("MtProxyConfigModel", m_mtProxyConfigModel);
|
||||||
|
|
||||||
|
m_telemtConfigModel = new TelemtConfigModel(this);
|
||||||
|
setQmlContextProperty("TelemtConfigModel", m_telemtConfigModel);
|
||||||
|
|
||||||
m_clientManagementModel = new ClientManagementModel(this);
|
m_clientManagementModel = new ClientManagementModel(this);
|
||||||
setQmlContextProperty("ClientManagementModel", m_clientManagementModel);
|
setQmlContextProperty("ClientManagementModel", m_clientManagementModel);
|
||||||
|
|
||||||
@@ -145,7 +150,7 @@ void CoreController::initCoreControllers()
|
|||||||
m_allowedDnsController = new AllowedDnsController(m_appSettingsRepository);
|
m_allowedDnsController = new AllowedDnsController(m_appSettingsRepository);
|
||||||
m_servicesCatalogController = new ServicesCatalogController(m_appSettingsRepository);
|
m_servicesCatalogController = new ServicesCatalogController(m_appSettingsRepository);
|
||||||
m_subscriptionController = new SubscriptionController(m_serversRepository, m_appSettingsRepository);
|
m_subscriptionController = new SubscriptionController(m_serversRepository, m_appSettingsRepository);
|
||||||
m_newsController = new NewsController(m_appSettingsRepository, m_serversController);
|
m_newsController = new NewsController(m_appSettingsRepository, m_serversRepository);
|
||||||
m_updateController = new UpdateController(m_appSettingsRepository, this);
|
m_updateController = new UpdateController(m_appSettingsRepository, this);
|
||||||
|
|
||||||
m_installController = new InstallController(m_serversRepository, m_appSettingsRepository, this);
|
m_installController = new InstallController(m_serversRepository, m_appSettingsRepository, this);
|
||||||
@@ -165,12 +170,12 @@ void CoreController::initControllers()
|
|||||||
setQmlContextProperty("FocusController", m_focusController);
|
setQmlContextProperty("FocusController", m_focusController);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_installUiController = new InstallUiController(m_installController, m_serversController, m_settingsController, m_protocolsModel, m_usersController,
|
m_installUiController = new InstallUiController(m_installController, m_serversController, m_settingsController, m_protocolsModel, m_usersController,
|
||||||
m_awgConfigModel, m_wireGuardConfigModel, m_openVpnConfigModel, m_xrayConfigModel, m_torConfigModel,
|
m_awgConfigModel, m_wireGuardConfigModel, m_openVpnConfigModel, m_xrayConfigModel, m_torConfigModel,
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
m_ikev2ConfigModel,
|
m_ikev2ConfigModel,
|
||||||
#endif
|
#endif
|
||||||
m_sftpConfigModel, m_socks5ConfigModel, this);
|
m_sftpConfigModel, m_socks5ConfigModel, m_mtProxyConfigModel, m_telemtConfigModel, this);
|
||||||
setQmlContextProperty("InstallController", m_installUiController);
|
setQmlContextProperty("InstallController", m_installUiController);
|
||||||
|
|
||||||
m_importController = new ImportUiController(m_importCoreController, this);
|
m_importController = new ImportUiController(m_importCoreController, this);
|
||||||
@@ -203,6 +208,10 @@ void CoreController::initControllers()
|
|||||||
m_systemController = new SystemController(this);
|
m_systemController = new SystemController(this);
|
||||||
setQmlContextProperty("SystemController", m_systemController);
|
setQmlContextProperty("SystemController", m_systemController);
|
||||||
|
|
||||||
|
m_networkReachabilityController = new NetworkReachabilityController(this);
|
||||||
|
m_engine->rootContext()->setContextProperty("NetworkReachabilityController", m_networkReachabilityController);
|
||||||
|
m_engine->rootContext()->setContextProperty("NetworkReachability", m_networkReachabilityController);
|
||||||
|
|
||||||
m_servicesCatalogUiController = new ServicesCatalogUiController(m_servicesCatalogController, m_apiServicesModel, this);
|
m_servicesCatalogUiController = new ServicesCatalogUiController(m_servicesCatalogController, m_apiServicesModel, this);
|
||||||
setQmlContextProperty("ServicesCatalogUiController", m_servicesCatalogUiController);
|
setQmlContextProperty("ServicesCatalogUiController", m_servicesCatalogUiController);
|
||||||
|
|
||||||
@@ -262,9 +271,12 @@ void CoreController::initSignalHandlers()
|
|||||||
{
|
{
|
||||||
m_signalHandlers = new CoreSignalHandlers(this, this);
|
m_signalHandlers = new CoreSignalHandlers(this, this);
|
||||||
m_signalHandlers->initAllHandlers();
|
m_signalHandlers->initAllHandlers();
|
||||||
|
|
||||||
// Trigger initial update after handlers are connected
|
// Trigger initial update after handlers are connected
|
||||||
m_serversUiController->updateModel();
|
m_serversUiController->updateModel();
|
||||||
|
if (m_serversUiController->hasServersFromGatewayApi()) {
|
||||||
|
m_apiNewsUiController->fetchNews(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreController::updateTranslator(const QLocale &locale)
|
void CoreController::updateTranslator(const QLocale &locale)
|
||||||
@@ -322,11 +334,16 @@ PageController* CoreController::pageController() const
|
|||||||
|
|
||||||
void CoreController::openConnectionByIndex(int serverIndex)
|
void CoreController::openConnectionByIndex(int serverIndex)
|
||||||
{
|
{
|
||||||
|
const QString serverId =
|
||||||
|
m_serversUiController ? m_serversUiController->getServerId(serverIndex) : QString();
|
||||||
|
if (serverId.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (m_serversModel) {
|
if (m_serversModel) {
|
||||||
m_serversModel->setProcessedServerIndex(serverIndex);
|
m_serversModel->setProcessedServerIndex(serverIndex);
|
||||||
}
|
}
|
||||||
if (m_serversController) {
|
if (m_serversController) {
|
||||||
m_serversController->setDefaultServerIndex(serverIndex);
|
m_serversController->setDefaultServer(serverId);
|
||||||
}
|
}
|
||||||
m_connectionUiController->toggleConnection();
|
m_connectionUiController->toggleConnection();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "ui/controllers/languageUiController.h"
|
#include "ui/controllers/languageUiController.h"
|
||||||
#include "ui/controllers/updateUiController.h"
|
#include "ui/controllers/updateUiController.h"
|
||||||
#include "ui/controllers/api/servicesCatalogUiController.h"
|
#include "ui/controllers/api/servicesCatalogUiController.h"
|
||||||
|
#include "ui/controllers/networkReachabilityController.h"
|
||||||
|
|
||||||
#include "core/controllers/serversController.h"
|
#include "core/controllers/serversController.h"
|
||||||
#include "core/controllers/selfhosted/usersController.h"
|
#include "core/controllers/selfhosted/usersController.h"
|
||||||
@@ -69,6 +70,9 @@
|
|||||||
#include "ui/models/serversModel.h"
|
#include "ui/models/serversModel.h"
|
||||||
#include "ui/models/services/sftpConfigModel.h"
|
#include "ui/models/services/sftpConfigModel.h"
|
||||||
#include "ui/models/services/socks5ProxyConfigModel.h"
|
#include "ui/models/services/socks5ProxyConfigModel.h"
|
||||||
|
#include "ui/models/services/mtProxyConfigModel.h"
|
||||||
|
#include "ui/models/services/telemtConfigModel.h"
|
||||||
|
|
||||||
#include "ui/models/ipSplitTunnelingModel.h"
|
#include "ui/models/ipSplitTunnelingModel.h"
|
||||||
#include "ui/models/newsModel.h"
|
#include "ui/models/newsModel.h"
|
||||||
|
|
||||||
@@ -84,7 +88,6 @@ class TestDefaultServerChange;
|
|||||||
class TestServerEdgeCases;
|
class TestServerEdgeCases;
|
||||||
class TestSignalOrder;
|
class TestSignalOrder;
|
||||||
class TestServersModelSync;
|
class TestServersModelSync;
|
||||||
class TestGatewayStacks;
|
|
||||||
class TestComplexOperations;
|
class TestComplexOperations;
|
||||||
class TestSettingsSignals;
|
class TestSettingsSignals;
|
||||||
class TestUiServersModelAndController;
|
class TestUiServersModelAndController;
|
||||||
@@ -101,7 +104,6 @@ class CoreController : public QObject
|
|||||||
friend class TestServerEdgeCases;
|
friend class TestServerEdgeCases;
|
||||||
friend class TestSignalOrder;
|
friend class TestSignalOrder;
|
||||||
friend class TestServersModelSync;
|
friend class TestServersModelSync;
|
||||||
friend class TestGatewayStacks;
|
|
||||||
friend class TestComplexOperations;
|
friend class TestComplexOperations;
|
||||||
friend class TestSettingsSignals;
|
friend class TestSettingsSignals;
|
||||||
friend class TestUiServersModelAndController;
|
friend class TestUiServersModelAndController;
|
||||||
@@ -158,6 +160,7 @@ private:
|
|||||||
ServersUiController* m_serversUiController;
|
ServersUiController* m_serversUiController;
|
||||||
IpSplitTunnelingUiController* m_ipSplitTunnelingUiController;
|
IpSplitTunnelingUiController* m_ipSplitTunnelingUiController;
|
||||||
SystemController* m_systemController;
|
SystemController* m_systemController;
|
||||||
|
NetworkReachabilityController* m_networkReachabilityController;
|
||||||
AppSplitTunnelingUiController* m_appSplitTunnelingUiController;
|
AppSplitTunnelingUiController* m_appSplitTunnelingUiController;
|
||||||
AllowedDnsUiController* m_allowedDnsUiController;
|
AllowedDnsUiController* m_allowedDnsUiController;
|
||||||
LanguageUiController* m_languageUiController;
|
LanguageUiController* m_languageUiController;
|
||||||
@@ -210,6 +213,8 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
SftpConfigModel* m_sftpConfigModel;
|
SftpConfigModel* m_sftpConfigModel;
|
||||||
Socks5ProxyConfigModel* m_socks5ConfigModel;
|
Socks5ProxyConfigModel* m_socks5ConfigModel;
|
||||||
|
MtProxyConfigModel* m_mtProxyConfigModel;
|
||||||
|
TelemtConfigModel* m_telemtConfigModel;
|
||||||
|
|
||||||
CoreSignalHandlers* m_signalHandlers;
|
CoreSignalHandlers* m_signalHandlers;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "core/utils/routeModes.h"
|
#include "core/utils/routeModes.h"
|
||||||
#include "core/controllers/coreController.h"
|
#include "core/controllers/coreController.h"
|
||||||
#include "core/repositories/secureServersRepository.h"
|
#include "core/repositories/secureServersRepository.h"
|
||||||
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/repositories/secureAppSettingsRepository.h"
|
#include "core/repositories/secureAppSettingsRepository.h"
|
||||||
#include "vpnConnection.h"
|
#include "vpnConnection.h"
|
||||||
#include "ui/controllers/qml/pageController.h"
|
#include "ui/controllers/qml/pageController.h"
|
||||||
@@ -65,7 +66,6 @@ void CoreSignalHandlers::initAllHandlers()
|
|||||||
initImportControllerHandler();
|
initImportControllerHandler();
|
||||||
initApiCountryModelUpdateHandler();
|
initApiCountryModelUpdateHandler();
|
||||||
initSubscriptionRefreshHandler();
|
initSubscriptionRefreshHandler();
|
||||||
initContainerModelUpdateHandler();
|
|
||||||
initAdminConfigRevokedHandler();
|
initAdminConfigRevokedHandler();
|
||||||
initPassphraseRequestHandler();
|
initPassphraseRequestHandler();
|
||||||
initTranslationsUpdatedHandler();
|
initTranslationsUpdatedHandler();
|
||||||
@@ -78,6 +78,7 @@ void CoreSignalHandlers::initAllHandlers()
|
|||||||
initAllowedDnsModelUpdateHandler();
|
initAllowedDnsModelUpdateHandler();
|
||||||
initAppSplitTunnelingModelUpdateHandler();
|
initAppSplitTunnelingModelUpdateHandler();
|
||||||
initPrepareConfigHandler();
|
initPrepareConfigHandler();
|
||||||
|
initUnsupportedConnectDrawerHandler();
|
||||||
initStrictKillSwitchHandler();
|
initStrictKillSwitchHandler();
|
||||||
initAndroidSettingsHandler();
|
initAndroidSettingsHandler();
|
||||||
initAndroidConnectionHandler();
|
initAndroidConnectionHandler();
|
||||||
@@ -124,11 +125,9 @@ void CoreSignalHandlers::initInstallControllerHandler()
|
|||||||
{
|
{
|
||||||
connect(m_coreController->m_installController, &InstallController::serverIsBusy, m_coreController->m_installUiController, &InstallUiController::serverIsBusy);
|
connect(m_coreController->m_installController, &InstallController::serverIsBusy, m_coreController->m_installUiController, &InstallUiController::serverIsBusy);
|
||||||
connect(m_coreController->m_installUiController, &InstallUiController::cancelInstallation, m_coreController->m_installController, &InstallController::cancelInstallation);
|
connect(m_coreController->m_installUiController, &InstallUiController::cancelInstallation, m_coreController->m_installController, &InstallController::cancelInstallation);
|
||||||
connect(m_coreController->m_installUiController, &InstallUiController::currentContainerUpdated, m_coreController->m_connectionUiController,
|
|
||||||
&ConnectionUiController::onCurrentContainerUpdated);
|
|
||||||
connect(m_coreController->m_serversUiController, &ServersUiController::processedServerIndexChanged,
|
connect(m_coreController->m_serversUiController, &ServersUiController::processedServerIndexChanged,
|
||||||
m_coreController->m_installUiController, [this](int index) {
|
m_coreController->m_installUiController, [this](int serverIndex) {
|
||||||
if (index >= 0) {
|
if (serverIndex >= 0) {
|
||||||
m_coreController->m_installUiController->clearProcessedServerCredentials();
|
m_coreController->m_installUiController->clearProcessedServerCredentials();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -137,20 +136,20 @@ void CoreSignalHandlers::initInstallControllerHandler()
|
|||||||
void CoreSignalHandlers::initExportControllerHandler()
|
void CoreSignalHandlers::initExportControllerHandler()
|
||||||
{
|
{
|
||||||
connect(m_coreController->m_exportController, &ExportController::appendClientRequested, this,
|
connect(m_coreController->m_exportController, &ExportController::appendClientRequested, this,
|
||||||
[this](int serverIndex, const QString &clientId, const QString &clientName, DockerContainer container) {
|
[this](const QString &serverId, const QString &clientId, const QString &clientName, DockerContainer container) {
|
||||||
m_coreController->m_usersController->appendClient(serverIndex, clientId, clientName, container);
|
m_coreController->m_usersController->appendClient(serverId, clientId, clientName, container);
|
||||||
});
|
});
|
||||||
connect(m_coreController->m_exportController, &ExportController::updateClientsRequested, this,
|
connect(m_coreController->m_exportController, &ExportController::updateClientsRequested, this,
|
||||||
[this](int serverIndex, DockerContainer container) {
|
[this](const QString &serverId, DockerContainer container) {
|
||||||
m_coreController->m_usersController->updateClients(serverIndex, container);
|
m_coreController->m_usersController->updateClients(serverId, container);
|
||||||
});
|
});
|
||||||
connect(m_coreController->m_exportController, &ExportController::revokeClientRequested, this,
|
connect(m_coreController->m_exportController, &ExportController::revokeClientRequested, this,
|
||||||
[this](int serverIndex, int row, DockerContainer container) {
|
[this](const QString &serverId, int row, DockerContainer container) {
|
||||||
m_coreController->m_usersController->revokeClient(serverIndex, row, container);
|
m_coreController->m_usersController->revokeClient(serverId, row, container);
|
||||||
});
|
});
|
||||||
connect(m_coreController->m_exportController, &ExportController::renameClientRequested, this,
|
connect(m_coreController->m_exportController, &ExportController::renameClientRequested, this,
|
||||||
[this](int serverIndex, int row, const QString &clientName, DockerContainer container) {
|
[this](const QString &serverId, int row, const QString &clientName, DockerContainer container) {
|
||||||
m_coreController->m_usersController->renameClient(serverIndex, row, clientName, container);
|
m_coreController->m_usersController->renameClient(serverId, row, clientName, container);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,9 +158,12 @@ void CoreSignalHandlers::initImportControllerHandler()
|
|||||||
connect(m_coreController->m_importCoreController, &ImportController::importFinished, this, [this]() {
|
connect(m_coreController->m_importCoreController, &ImportController::importFinished, this, [this]() {
|
||||||
if (!m_coreController->m_connectionController->isConnected()) {
|
if (!m_coreController->m_connectionController->isConnected()) {
|
||||||
int newServerIndex = m_coreController->m_serversController->getServersCount() - 1;
|
int newServerIndex = m_coreController->m_serversController->getServersCount() - 1;
|
||||||
m_coreController->m_serversController->setDefaultServerIndex(newServerIndex);
|
const QString serverId = m_coreController->m_serversController->getServerId(newServerIndex);
|
||||||
|
if (!serverId.isEmpty()) {
|
||||||
|
m_coreController->m_serversController->setDefaultServer(serverId);
|
||||||
|
}
|
||||||
if (m_coreController->m_serversUiController) {
|
if (m_coreController->m_serversUiController) {
|
||||||
m_coreController->m_serversUiController->setProcessedServerIndex(newServerIndex);
|
m_coreController->m_serversUiController->setProcessedServerId(serverId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -170,21 +172,18 @@ void CoreSignalHandlers::initImportControllerHandler()
|
|||||||
void CoreSignalHandlers::initApiCountryModelUpdateHandler()
|
void CoreSignalHandlers::initApiCountryModelUpdateHandler()
|
||||||
{
|
{
|
||||||
connect(m_coreController->m_serversUiController, &ServersUiController::updateApiCountryModel, this, [this]() {
|
connect(m_coreController->m_serversUiController, &ServersUiController::updateApiCountryModel, this, [this]() {
|
||||||
int processedIndex = m_coreController->m_serversUiController->getProcessedServerIndex();
|
const QString processedServerId = m_coreController->m_serversUiController->getProcessedServerId();
|
||||||
if (processedIndex < 0 || processedIndex >= m_coreController->m_serversRepository->serversCount()) {
|
if (processedServerId.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerConfig server = m_coreController->m_serversRepository->server(processedIndex);
|
|
||||||
QJsonArray availableCountries;
|
QJsonArray availableCountries;
|
||||||
QString serverCountryCode;
|
QString serverCountryCode;
|
||||||
|
|
||||||
if (server.isApiV2()) {
|
const auto apiV2 = m_coreController->m_serversRepository->apiV2Config(processedServerId);
|
||||||
const ApiV2ServerConfig* apiV2 = server.as<ApiV2ServerConfig>();
|
if (apiV2.has_value()) {
|
||||||
if (apiV2) {
|
availableCountries = apiV2->apiConfig.availableCountries;
|
||||||
availableCountries = apiV2->apiConfig.availableCountries;
|
serverCountryCode = apiV2->apiConfig.serverCountryCode;
|
||||||
serverCountryCode = apiV2->apiConfig.serverCountryCode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_coreController->m_apiCountryModel->updateModel(availableCountries, serverCountryCode);
|
m_coreController->m_apiCountryModel->updateModel(availableCountries, serverCountryCode);
|
||||||
@@ -194,18 +193,9 @@ void CoreSignalHandlers::initApiCountryModelUpdateHandler()
|
|||||||
void CoreSignalHandlers::initSubscriptionRefreshHandler()
|
void CoreSignalHandlers::initSubscriptionRefreshHandler()
|
||||||
{
|
{
|
||||||
connect(m_coreController->m_subscriptionUiController, &SubscriptionUiController::subscriptionRefreshNeeded, this, [this]() {
|
connect(m_coreController->m_subscriptionUiController, &SubscriptionUiController::subscriptionRefreshNeeded, this, [this]() {
|
||||||
const int defaultServerIndex = m_coreController->m_serversController->getDefaultServerIndex();
|
const QString defaultServerId = m_coreController->m_serversController->getDefaultServerId();
|
||||||
if (defaultServerIndex >= 0) {
|
if (!defaultServerId.isEmpty()) {
|
||||||
m_coreController->m_subscriptionUiController->getAccountInfo(defaultServerIndex, false);
|
m_coreController->m_subscriptionUiController->getAccountInfo(defaultServerId, false);
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreSignalHandlers::initContainerModelUpdateHandler()
|
|
||||||
{
|
|
||||||
connect(m_coreController->m_serversController, &ServersController::gatewayStacksExpanded, this, [this]() {
|
|
||||||
if (m_coreController->m_serversUiController->hasServersFromGatewayApi()) {
|
|
||||||
m_coreController->m_apiNewsUiController->fetchNews(false);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -213,17 +203,17 @@ void CoreSignalHandlers::initContainerModelUpdateHandler()
|
|||||||
void CoreSignalHandlers::initAdminConfigRevokedHandler()
|
void CoreSignalHandlers::initAdminConfigRevokedHandler()
|
||||||
{
|
{
|
||||||
connect(m_coreController->m_installController, &InstallController::clientRevocationRequested, this,
|
connect(m_coreController->m_installController, &InstallController::clientRevocationRequested, this,
|
||||||
[this](int serverIndex, const ContainerConfig &containerConfig, DockerContainer container) {
|
[this](const QString &serverId, const ContainerConfig &containerConfig, DockerContainer container) {
|
||||||
m_coreController->m_usersController->revokeClient(serverIndex, containerConfig, container);
|
m_coreController->m_usersController->revokeClient(serverId, containerConfig, container);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_coreController->m_installController, &InstallController::clientAppendRequested, this,
|
connect(m_coreController->m_installController, &InstallController::clientAppendRequested, this,
|
||||||
[this](int serverIndex, const QString &clientId, const QString &clientName, DockerContainer container) {
|
[this](const QString &serverId, const QString &clientId, const QString &clientName, DockerContainer container) {
|
||||||
m_coreController->m_usersController->appendClient(serverIndex, clientId, clientName, container);
|
m_coreController->m_usersController->appendClient(serverId, clientId, clientName, container);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_coreController->m_usersController, &UsersController::adminConfigRevoked, m_coreController->m_serversController,
|
connect(m_coreController->m_usersController, &UsersController::adminConfigRevoked, m_coreController->m_installController,
|
||||||
&ServersController::clearCachedProfile);
|
&InstallController::clearCachedProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreSignalHandlers::initPassphraseRequestHandler()
|
void CoreSignalHandlers::initPassphraseRequestHandler()
|
||||||
@@ -251,7 +241,8 @@ void CoreSignalHandlers::initLanguageHandler()
|
|||||||
|
|
||||||
void CoreSignalHandlers::initAutoConnectHandler()
|
void CoreSignalHandlers::initAutoConnectHandler()
|
||||||
{
|
{
|
||||||
if (m_coreController->m_settingsUiController->isAutoConnectEnabled() && m_coreController->m_serversController->getDefaultServerIndex() >= 0) {
|
if (m_coreController->m_settingsUiController->isAutoConnectEnabled()
|
||||||
|
&& !m_coreController->m_serversController->getDefaultServerId().isEmpty()) {
|
||||||
QTimer::singleShot(1000, this, [this]() { m_coreController->m_connectionUiController->openConnection(); });
|
QTimer::singleShot(1000, this, [this]() { m_coreController->m_connectionUiController->openConnection(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,16 +262,20 @@ void CoreSignalHandlers::initServersModelUpdateHandler()
|
|||||||
m_coreController->m_serversUiController, &ServersUiController::updateModel);
|
m_coreController->m_serversUiController, &ServersUiController::updateModel);
|
||||||
connect(m_coreController->m_serversRepository, &SecureServersRepository::defaultServerChanged,
|
connect(m_coreController->m_serversRepository, &SecureServersRepository::defaultServerChanged,
|
||||||
m_coreController->m_serversUiController, &ServersUiController::onDefaultServerChanged);
|
m_coreController->m_serversUiController, &ServersUiController::onDefaultServerChanged);
|
||||||
|
|
||||||
connect(m_coreController->m_serversRepository, &SecureServersRepository::serverAdded,
|
connect(m_coreController->m_serversRepository, &SecureServersRepository::serverAdded, this,
|
||||||
m_coreController->m_serversController, &ServersController::recomputeGatewayStacks);
|
[this](const QString &serverId) {
|
||||||
connect(m_coreController->m_serversRepository, &SecureServersRepository::serverEdited,
|
if (m_coreController->m_serversRepository->apiV2Config(serverId).has_value()) {
|
||||||
m_coreController->m_serversController, &ServersController::recomputeGatewayStacks);
|
m_coreController->m_apiNewsUiController->fetchNews(false);
|
||||||
connect(m_coreController->m_serversRepository, &SecureServersRepository::serverRemoved,
|
}
|
||||||
m_coreController->m_serversController, &ServersController::recomputeGatewayStacks);
|
});
|
||||||
|
|
||||||
connect(m_coreController->m_settingsUiController, &SettingsUiController::restoreBackupFinished,
|
connect(m_coreController->m_settingsUiController, &SettingsUiController::restoreBackupFinished, this, [this]() {
|
||||||
m_coreController->m_serversUiController, &ServersUiController::updateModel);
|
m_coreController->m_serversUiController->updateModel();
|
||||||
|
if (m_coreController->m_serversUiController->hasServersFromGatewayApi()) {
|
||||||
|
m_coreController->m_apiNewsUiController->fetchNews(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreSignalHandlers::initClientManagementModelUpdateHandler()
|
void CoreSignalHandlers::initClientManagementModelUpdateHandler()
|
||||||
@@ -315,7 +310,19 @@ void CoreSignalHandlers::initPrepareConfigHandler()
|
|||||||
connect(m_coreController->m_connectionUiController, &ConnectionUiController::prepareConfig, this, [this]() {
|
connect(m_coreController->m_connectionUiController, &ConnectionUiController::prepareConfig, this, [this]() {
|
||||||
m_coreController->m_connectionController->setConnectionState(Vpn::ConnectionState::Preparing);
|
m_coreController->m_connectionController->setConnectionState(Vpn::ConnectionState::Preparing);
|
||||||
|
|
||||||
m_coreController->m_subscriptionUiController->validateConfig();
|
const QString serverId = m_coreController->m_serversController->getDefaultServerId();
|
||||||
|
if (serverId.isEmpty()) {
|
||||||
|
m_coreController->m_connectionController->setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverConfigUtils::ConfigType kind = m_coreController->m_serversRepository->serverKind(serverId);
|
||||||
|
|
||||||
|
if (serverConfigUtils::isApiV2Subscription(kind) || serverConfigUtils::isLegacyApiSubscription(kind)) {
|
||||||
|
m_coreController->m_subscriptionUiController->validateConfig();
|
||||||
|
} else {
|
||||||
|
m_coreController->m_installUiController->validateConfig();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_coreController->m_subscriptionUiController, &SubscriptionUiController::configValidated, this, [this](bool isValid) {
|
connect(m_coreController->m_subscriptionUiController, &SubscriptionUiController::configValidated, this, [this](bool isValid) {
|
||||||
@@ -324,7 +331,7 @@ void CoreSignalHandlers::initPrepareConfigHandler()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_coreController->m_installUiController->validateConfig();
|
m_coreController->m_connectionUiController->openConnection();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_coreController->m_installUiController, &InstallUiController::configValidated, this, [this](bool isValid) {
|
connect(m_coreController->m_installUiController, &InstallUiController::configValidated, this, [this](bool isValid) {
|
||||||
@@ -337,6 +344,12 @@ void CoreSignalHandlers::initPrepareConfigHandler()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CoreSignalHandlers::initUnsupportedConnectDrawerHandler()
|
||||||
|
{
|
||||||
|
connect(m_coreController->m_subscriptionUiController, &SubscriptionUiController::unsupportedConnectDrawerRequested,
|
||||||
|
m_coreController->m_pageController, &PageController::unsupportedConnectDrawerRequested);
|
||||||
|
}
|
||||||
|
|
||||||
void CoreSignalHandlers::initStrictKillSwitchHandler()
|
void CoreSignalHandlers::initStrictKillSwitchHandler()
|
||||||
{
|
{
|
||||||
connect(m_coreController->m_settingsUiController, &SettingsUiController::strictKillSwitchEnabledChanged, m_coreController->m_connectionController,
|
connect(m_coreController->m_settingsUiController, &SettingsUiController::strictKillSwitchEnabledChanged, m_coreController->m_connectionController,
|
||||||
@@ -348,7 +361,10 @@ void CoreSignalHandlers::initAndroidSettingsHandler()
|
|||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
connect(m_coreController->m_appSettingsRepository, &SecureAppSettingsRepository::saveLogsChanged, AndroidController::instance(), &AndroidController::setSaveLogs);
|
connect(m_coreController->m_appSettingsRepository, &SecureAppSettingsRepository::saveLogsChanged, AndroidController::instance(), &AndroidController::setSaveLogs);
|
||||||
connect(m_coreController->m_appSettingsRepository, &SecureAppSettingsRepository::screenshotsEnabledChanged, AndroidController::instance(), &AndroidController::setScreenshotsEnabled);
|
connect(m_coreController->m_appSettingsRepository, &SecureAppSettingsRepository::screenshotsEnabledChanged, AndroidController::instance(), &AndroidController::setScreenshotsEnabled);
|
||||||
connect(m_coreController->m_serversRepository, &SecureServersRepository::serverRemoved, AndroidController::instance(), &AndroidController::resetLastServer);
|
connect(m_coreController->m_serversRepository, &SecureServersRepository::serverRemoved, this,
|
||||||
|
[](const QString &/*serverId*/, int removedIndex) {
|
||||||
|
AndroidController::instance()->resetLastServer(removedIndex);
|
||||||
|
});
|
||||||
connect(m_coreController->m_appSettingsRepository, &SecureAppSettingsRepository::settingsCleared, []() { AndroidController::instance()->resetLastServer(-1); });
|
connect(m_coreController->m_appSettingsRepository, &SecureAppSettingsRepository::settingsCleared, []() { AndroidController::instance()->resetLastServer(-1); });
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ private:
|
|||||||
void initImportControllerHandler();
|
void initImportControllerHandler();
|
||||||
void initApiCountryModelUpdateHandler();
|
void initApiCountryModelUpdateHandler();
|
||||||
void initSubscriptionRefreshHandler();
|
void initSubscriptionRefreshHandler();
|
||||||
void initContainerModelUpdateHandler();
|
|
||||||
void initAdminConfigRevokedHandler();
|
void initAdminConfigRevokedHandler();
|
||||||
void initPassphraseRequestHandler();
|
void initPassphraseRequestHandler();
|
||||||
void initTranslationsUpdatedHandler();
|
void initTranslationsUpdatedHandler();
|
||||||
@@ -34,6 +33,7 @@ private:
|
|||||||
void initAllowedDnsModelUpdateHandler();
|
void initAllowedDnsModelUpdateHandler();
|
||||||
void initAppSplitTunnelingModelUpdateHandler();
|
void initAppSplitTunnelingModelUpdateHandler();
|
||||||
void initPrepareConfigHandler();
|
void initPrepareConfigHandler();
|
||||||
|
void initUnsupportedConnectDrawerHandler();
|
||||||
void initStrictKillSwitchHandler();
|
void initStrictKillSwitchHandler();
|
||||||
void initAndroidSettingsHandler();
|
void initAndroidSettingsHandler();
|
||||||
void initAndroidConnectionHandler();
|
void initAndroidConnectionHandler();
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ QFuture<QPair<ErrorCode, QByteArray>> GatewayController::postAsync(const QString
|
|||||||
|
|
||||||
connect(reply, &QNetworkReply::sslErrors, [sslErrors](const QList<QSslError> &errors) { *sslErrors = errors; });
|
connect(reply, &QNetworkReply::sslErrors, [sslErrors](const QList<QSslError> &errors) { *sslErrors = errors; });
|
||||||
|
|
||||||
connect(reply, &QNetworkReply::finished, reply, [promise, sslErrors, encRequestData, endpoint, apiPayload, reply, this]() mutable {
|
connect(reply, &QNetworkReply::finished, this, [promise, sslErrors, encRequestData, endpoint, apiPayload, reply, this]() mutable {
|
||||||
QByteArray encryptedResponseBody = reply->readAll();
|
QByteArray encryptedResponseBody = reply->readAll();
|
||||||
QString replyErrorString = reply->errorString();
|
QString replyErrorString = reply->errorString();
|
||||||
auto replyError = reply->error();
|
auto replyError = reply->error();
|
||||||
|
|||||||
@@ -5,14 +5,13 @@
|
|||||||
|
|
||||||
#include "core/configurators/configuratorBase.h"
|
#include "core/configurators/configuratorBase.h"
|
||||||
#include "core/utils/selfhosted/sshSession.h"
|
#include "core/utils/selfhosted/sshSession.h"
|
||||||
#include "core/utils/networkUtilities.h"
|
|
||||||
#include "core/utils/qrCodeUtils.h"
|
#include "core/utils/qrCodeUtils.h"
|
||||||
#include "core/utils/serialization/serialization.h"
|
#include "core/utils/serialization/serialization.h"
|
||||||
#include "core/utils/protocolEnum.h"
|
#include "core/utils/protocolEnum.h"
|
||||||
#include "core/protocols/protocolUtils.h"
|
#include "core/protocols/protocolUtils.h"
|
||||||
#include "core/utils/constants/configKeys.h"
|
#include "core/utils/constants/configKeys.h"
|
||||||
#include "core/utils/constants/protocolConstants.h"
|
#include "core/utils/constants/protocolConstants.h"
|
||||||
#include "core/models/serverConfig.h"
|
#include "core/models/selfhosted/selfHostedAdminServerConfig.h"
|
||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
#include "core/models/protocolConfig.h"
|
#include "core/models/protocolConfig.h"
|
||||||
|
|
||||||
@@ -27,18 +26,20 @@ ExportController::ExportController(SecureServersRepository* serversRepository,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportController::ExportResult ExportController::generateFullAccessConfig(int serverIndex)
|
ExportController::ExportResult ExportController::generateFullAccessConfig(const QString &serverId)
|
||||||
{
|
{
|
||||||
ExportResult result;
|
ExportResult result;
|
||||||
|
|
||||||
ServerConfig serverConfig = m_serversRepository->server(serverIndex);
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
serverConfig.visit([](auto& arg) {
|
if (!adminConfig.has_value()) {
|
||||||
for (auto it = arg.containers.begin(); it != arg.containers.end(); ++it) {
|
result.errorCode = ErrorCode::InternalError;
|
||||||
it.value().protocolConfig.clearClientConfig();
|
return result;
|
||||||
}
|
}
|
||||||
});
|
for (auto it = adminConfig->containers.begin(); it != adminConfig->containers.end(); ++it) {
|
||||||
|
it.value().protocolConfig.clearClientConfig();
|
||||||
|
}
|
||||||
|
|
||||||
QJsonObject serverJson = serverConfig.toJson();
|
QJsonObject serverJson = adminConfig->toJson();
|
||||||
QByteArray compressedConfig = QJsonDocument(serverJson).toJson();
|
QByteArray compressedConfig = QJsonDocument(serverJson).toJson();
|
||||||
compressedConfig = qCompress(compressedConfig, 8);
|
compressedConfig = qCompress(compressedConfig, 8);
|
||||||
result.config = generateVpnUrl(compressedConfig);
|
result.config = generateVpnUrl(compressedConfig);
|
||||||
@@ -47,13 +48,22 @@ ExportController::ExportResult ExportController::generateFullAccessConfig(int se
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportController::ExportResult ExportController::generateConnectionConfig(int serverIndex, int containerIndex, const QString &clientName)
|
ExportController::ExportResult ExportController::generateConnectionConfig(const QString &serverId, int containerIndex, const QString &clientName)
|
||||||
{
|
{
|
||||||
ExportResult result;
|
ExportResult result;
|
||||||
|
|
||||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||||
ServerCredentials credentials = m_serversRepository->serverCredentials(serverIndex);
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
ContainerConfig containerConfig = m_serversRepository->containerConfig(serverIndex, container);
|
if (!adminConfig.has_value()) {
|
||||||
|
result.errorCode = ErrorCode::InternalError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const ServerCredentials credentials = adminConfig->credentials();
|
||||||
|
if (!credentials.isValid()) {
|
||||||
|
result.errorCode = ErrorCode::InternalError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
ContainerConfig containerConfig = adminConfig->containerConfig(container);
|
||||||
|
|
||||||
if (ContainerUtils::containerService(container) != ServiceType::Other) {
|
if (ContainerUtils::containerService(container) != ServiceType::Other) {
|
||||||
SshSession sshSession;
|
SshSession sshSession;
|
||||||
@@ -74,35 +84,25 @@ ExportController::ExportResult ExportController::generateConnectionConfig(int se
|
|||||||
|
|
||||||
QString clientId = newProtocolConfig.clientId();
|
QString clientId = newProtocolConfig.clientId();
|
||||||
if (!clientId.isEmpty()) {
|
if (!clientId.isEmpty()) {
|
||||||
emit appendClientRequested(serverIndex, clientId, clientName, container);
|
emit appendClientRequested(serverId, clientId, clientName, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerConfig serverConfig = m_serversRepository->server(serverIndex);
|
const QPair<QString, QString> dns = adminConfig->getDnsPair(m_appSettingsRepository->useAmneziaDns(),
|
||||||
serverConfig.visit([container, containerConfig](auto& arg) {
|
m_appSettingsRepository->primaryDns(),
|
||||||
arg.containers.clear();
|
m_appSettingsRepository->secondaryDns());
|
||||||
arg.containers[container] = containerConfig;
|
|
||||||
arg.defaultContainer = container;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (serverConfig.isSelfHosted()) {
|
adminConfig->containers.clear();
|
||||||
SelfHostedServerConfig* selfHosted = serverConfig.as<SelfHostedServerConfig>();
|
adminConfig->containers[container] = containerConfig;
|
||||||
if (selfHosted) {
|
adminConfig->defaultContainer = container;
|
||||||
selfHosted->userName.reset();
|
adminConfig->userName.clear();
|
||||||
selfHosted->password.reset();
|
adminConfig->password.clear();
|
||||||
selfHosted->port.reset();
|
adminConfig->port = 0;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dns = serverConfig.getDnsPair(m_appSettingsRepository->useAmneziaDns(),
|
adminConfig->dns1 = dns.first;
|
||||||
m_appSettingsRepository->primaryDns(),
|
adminConfig->dns2 = dns.second;
|
||||||
m_appSettingsRepository->secondaryDns());
|
|
||||||
serverConfig.visit([&dns](auto& arg) {
|
|
||||||
arg.dns1 = dns.first;
|
|
||||||
arg.dns2 = dns.second;
|
|
||||||
});
|
|
||||||
|
|
||||||
QJsonObject serverJson = serverConfig.toJson();
|
QJsonObject serverJson = adminConfig->toJson();
|
||||||
QByteArray compressedConfig = QJsonDocument(serverJson).toJson();
|
QByteArray compressedConfig = QJsonDocument(serverJson).toJson();
|
||||||
compressedConfig = qCompress(compressedConfig, 8);
|
compressedConfig = qCompress(compressedConfig, 8);
|
||||||
result.config = generateVpnUrl(compressedConfig);
|
result.config = generateVpnUrl(compressedConfig);
|
||||||
@@ -111,7 +111,7 @@ ExportController::ExportResult ExportController::generateConnectionConfig(int se
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportController::NativeConfigResult ExportController::generateNativeConfig(int serverIndex, DockerContainer container,
|
ExportController::NativeConfigResult ExportController::generateNativeConfig(const QString &serverId, DockerContainer container,
|
||||||
const ContainerConfig &containerConfig,
|
const ContainerConfig &containerConfig,
|
||||||
const QString &clientName)
|
const QString &clientName)
|
||||||
{
|
{
|
||||||
@@ -123,11 +123,19 @@ ExportController::NativeConfigResult ExportController::generateNativeConfig(int
|
|||||||
|
|
||||||
Proto protocol = ContainerUtils::defaultProtocol(container);
|
Proto protocol = ContainerUtils::defaultProtocol(container);
|
||||||
|
|
||||||
ServerCredentials credentials = m_serversRepository->serverCredentials(serverIndex);
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
ServerConfig serverConfig = m_serversRepository->server(serverIndex);
|
if (!adminConfig.has_value()) {
|
||||||
auto dns = serverConfig.getDnsPair(m_appSettingsRepository->useAmneziaDns(),
|
result.errorCode = ErrorCode::InternalError;
|
||||||
m_appSettingsRepository->primaryDns(),
|
return result;
|
||||||
m_appSettingsRepository->secondaryDns());
|
}
|
||||||
|
const ServerCredentials credentials = adminConfig->credentials();
|
||||||
|
if (!credentials.isValid()) {
|
||||||
|
result.errorCode = ErrorCode::InternalError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const QPair<QString, QString> dns = adminConfig->getDnsPair(m_appSettingsRepository->useAmneziaDns(),
|
||||||
|
m_appSettingsRepository->primaryDns(),
|
||||||
|
m_appSettingsRepository->secondaryDns());
|
||||||
|
|
||||||
ContainerConfig modifiedContainerConfig = containerConfig;
|
ContainerConfig modifiedContainerConfig = containerConfig;
|
||||||
modifiedContainerConfig.container = container;
|
modifiedContainerConfig.container = container;
|
||||||
@@ -157,20 +165,25 @@ ExportController::NativeConfigResult ExportController::generateNativeConfig(int
|
|||||||
if (protocol == Proto::OpenVpn || protocol == Proto::WireGuard || protocol == Proto::Awg || protocol == Proto::Xray) {
|
if (protocol == Proto::OpenVpn || protocol == Proto::WireGuard || protocol == Proto::Awg || protocol == Proto::Xray) {
|
||||||
QString clientId = newProtocolConfig.clientId();
|
QString clientId = newProtocolConfig.clientId();
|
||||||
if (!clientId.isEmpty()) {
|
if (!clientId.isEmpty()) {
|
||||||
emit appendClientRequested(serverIndex, clientId, clientName, container);
|
emit appendClientRequested(serverId, clientId, clientName, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportController::ExportResult ExportController::generateOpenVpnConfig(int serverIndex, const QString &clientName)
|
ExportController::ExportResult ExportController::generateOpenVpnConfig(const QString &serverId, const QString &clientName)
|
||||||
{
|
{
|
||||||
ExportResult result;
|
ExportResult result;
|
||||||
|
|
||||||
DockerContainer container = DockerContainer::OpenVpn;
|
DockerContainer container = DockerContainer::OpenVpn;
|
||||||
ContainerConfig containerConfig = m_serversRepository->containerConfig(serverIndex, container);
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!adminConfig.has_value()) {
|
||||||
|
result.errorCode = ErrorCode::InternalError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
ContainerConfig containerConfig = adminConfig->containerConfig(container);
|
||||||
|
|
||||||
auto nativeResult = generateNativeConfig(serverIndex, container, containerConfig, clientName);
|
auto nativeResult = generateNativeConfig(serverId, container, containerConfig, clientName);
|
||||||
if (nativeResult.errorCode != ErrorCode::NoError) {
|
if (nativeResult.errorCode != ErrorCode::NoError) {
|
||||||
result.errorCode = nativeResult.errorCode;
|
result.errorCode = nativeResult.errorCode;
|
||||||
return result;
|
return result;
|
||||||
@@ -185,13 +198,18 @@ ExportController::ExportResult ExportController::generateOpenVpnConfig(int serve
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportController::ExportResult ExportController::generateWireGuardConfig(int serverIndex, const QString &clientName)
|
ExportController::ExportResult ExportController::generateWireGuardConfig(const QString &serverId, const QString &clientName)
|
||||||
{
|
{
|
||||||
ExportResult result;
|
ExportResult result;
|
||||||
|
|
||||||
ContainerConfig containerConfig = m_serversRepository->containerConfig(serverIndex, DockerContainer::WireGuard);
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!adminConfig.has_value()) {
|
||||||
|
result.errorCode = ErrorCode::InternalError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
ContainerConfig containerConfig = adminConfig->containerConfig(DockerContainer::WireGuard);
|
||||||
|
|
||||||
auto nativeResult = generateNativeConfig(serverIndex, DockerContainer::WireGuard, containerConfig, clientName);
|
auto nativeResult = generateNativeConfig(serverId, DockerContainer::WireGuard, containerConfig, clientName);
|
||||||
if (nativeResult.errorCode != ErrorCode::NoError) {
|
if (nativeResult.errorCode != ErrorCode::NoError) {
|
||||||
result.errorCode = nativeResult.errorCode;
|
result.errorCode = nativeResult.errorCode;
|
||||||
return result;
|
return result;
|
||||||
@@ -206,7 +224,7 @@ ExportController::ExportResult ExportController::generateWireGuardConfig(int ser
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportController::ExportResult ExportController::generateAwgConfig(int serverIndex, int containerIndex, const QString &clientName)
|
ExportController::ExportResult ExportController::generateAwgConfig(const QString &serverId, int containerIndex, const QString &clientName)
|
||||||
{
|
{
|
||||||
ExportResult result;
|
ExportResult result;
|
||||||
|
|
||||||
@@ -215,9 +233,14 @@ ExportController::ExportResult ExportController::generateAwgConfig(int serverInd
|
|||||||
result.errorCode = ErrorCode::InternalError;
|
result.errorCode = ErrorCode::InternalError;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
ContainerConfig containerConfig = m_serversRepository->containerConfig(serverIndex, container);
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!adminConfig.has_value()) {
|
||||||
|
result.errorCode = ErrorCode::InternalError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
ContainerConfig containerConfig = adminConfig->containerConfig(container);
|
||||||
|
|
||||||
auto nativeResult = generateNativeConfig(serverIndex, container, containerConfig, clientName);
|
auto nativeResult = generateNativeConfig(serverId, container, containerConfig, clientName);
|
||||||
if (nativeResult.errorCode != ErrorCode::NoError) {
|
if (nativeResult.errorCode != ErrorCode::NoError) {
|
||||||
result.errorCode = nativeResult.errorCode;
|
result.errorCode = nativeResult.errorCode;
|
||||||
return result;
|
return result;
|
||||||
@@ -233,13 +256,18 @@ ExportController::ExportResult ExportController::generateAwgConfig(int serverInd
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ExportController::ExportResult ExportController::generateXrayConfig(int serverIndex, const QString &clientName)
|
ExportController::ExportResult ExportController::generateXrayConfig(const QString &serverId, const QString &clientName)
|
||||||
{
|
{
|
||||||
ExportResult result;
|
ExportResult result;
|
||||||
|
|
||||||
ContainerConfig containerConfig = m_serversRepository->containerConfig(serverIndex, DockerContainer::Xray);
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!adminConfig.has_value()) {
|
||||||
|
result.errorCode = ErrorCode::InternalError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
ContainerConfig containerConfig = adminConfig->containerConfig(DockerContainer::Xray);
|
||||||
|
|
||||||
auto nativeResult = generateNativeConfig(serverIndex, DockerContainer::Xray, containerConfig, clientName);
|
auto nativeResult = generateNativeConfig(serverId, DockerContainer::Xray, containerConfig, clientName);
|
||||||
if (nativeResult.errorCode != ErrorCode::NoError) {
|
if (nativeResult.errorCode != ErrorCode::NoError) {
|
||||||
result.errorCode = nativeResult.errorCode;
|
result.errorCode = nativeResult.errorCode;
|
||||||
return result;
|
return result;
|
||||||
@@ -302,22 +330,22 @@ ExportController::ExportResult ExportController::generateXrayConfig(int serverIn
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportController::updateClientManagementModel(int serverIndex, int containerIndex)
|
void ExportController::updateClientManagementModel(const QString &serverId, int containerIndex)
|
||||||
{
|
{
|
||||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||||
emit updateClientsRequested(serverIndex, container);
|
emit updateClientsRequested(serverId, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportController::revokeConfig(int row, int serverIndex, int containerIndex)
|
void ExportController::revokeConfig(int row, const QString &serverId, int containerIndex)
|
||||||
{
|
{
|
||||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||||
emit revokeClientRequested(serverIndex, row, container);
|
emit revokeClientRequested(serverId, row, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportController::renameClient(int row, const QString &clientName, int serverIndex, int containerIndex)
|
void ExportController::renameClient(int row, const QString &clientName, const QString &serverId, int containerIndex)
|
||||||
{
|
{
|
||||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||||
emit renameClientRequested(serverIndex, row, clientName, container);
|
emit renameClientRequested(serverId, row, clientName, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ExportController::generateVpnUrl(const QByteArray &compressedConfig)
|
QString ExportController::generateVpnUrl(const QByteArray &compressedConfig)
|
||||||
|
|||||||
@@ -37,23 +37,23 @@ public:
|
|||||||
SecureAppSettingsRepository* appSettingsRepository,
|
SecureAppSettingsRepository* appSettingsRepository,
|
||||||
QObject *parent = nullptr);
|
QObject *parent = nullptr);
|
||||||
|
|
||||||
ExportResult generateFullAccessConfig(int serverIndex);
|
ExportResult generateFullAccessConfig(const QString &serverId);
|
||||||
ExportResult generateConnectionConfig(int serverIndex, int containerIndex, const QString &clientName);
|
ExportResult generateConnectionConfig(const QString &serverId, int containerIndex, const QString &clientName);
|
||||||
ExportResult generateOpenVpnConfig(int serverIndex, const QString &clientName);
|
ExportResult generateOpenVpnConfig(const QString &serverId, const QString &clientName);
|
||||||
ExportResult generateWireGuardConfig(int serverIndex, const QString &clientName);
|
ExportResult generateWireGuardConfig(const QString &serverId, const QString &clientName);
|
||||||
ExportResult generateAwgConfig(int serverIndex, int containerIndex, const QString &clientName);
|
ExportResult generateAwgConfig(const QString &serverId, int containerIndex, const QString &clientName);
|
||||||
ExportResult generateXrayConfig(int serverIndex, const QString &clientName);
|
ExportResult generateXrayConfig(const QString &serverId, const QString &clientName);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void appendClientRequested(int serverIndex, const QString &clientId, const QString &clientName, DockerContainer container);
|
void appendClientRequested(const QString &serverId, const QString &clientId, const QString &clientName, DockerContainer container);
|
||||||
void updateClientsRequested(int serverIndex, DockerContainer container);
|
void updateClientsRequested(const QString &serverId, DockerContainer container);
|
||||||
void revokeClientRequested(int serverIndex, int row, DockerContainer container);
|
void revokeClientRequested(const QString &serverId, int row, DockerContainer container);
|
||||||
void renameClientRequested(int serverIndex, int row, const QString &clientName, DockerContainer container);
|
void renameClientRequested(const QString &serverId, int row, const QString &clientName, DockerContainer container);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateClientManagementModel(int serverIndex, int containerIndex);
|
void updateClientManagementModel(const QString &serverId, int containerIndex);
|
||||||
void revokeConfig(int row, int serverIndex, int containerIndex);
|
void revokeConfig(int row, const QString &serverId, int containerIndex);
|
||||||
void renameClient(int row, const QString &clientName, int serverIndex, int containerIndex);
|
void renameClient(int row, const QString &clientName, const QString &serverId, int containerIndex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct NativeConfigResult
|
struct NativeConfigResult
|
||||||
@@ -62,7 +62,7 @@ private:
|
|||||||
QJsonObject jsonNativeConfig;
|
QJsonObject jsonNativeConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
NativeConfigResult generateNativeConfig(int serverIndex, DockerContainer container,
|
NativeConfigResult generateNativeConfig(const QString &serverId, DockerContainer container,
|
||||||
const ContainerConfig &containerConfig,
|
const ContainerConfig &containerConfig,
|
||||||
const QString &clientName);
|
const QString &clientName);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
#include "core/utils/containerEnum.h"
|
#include "core/utils/containerEnum.h"
|
||||||
#include "core/utils/containers/containerUtils.h"
|
#include "core/utils/containers/containerUtils.h"
|
||||||
#include "core/utils/protocolEnum.h"
|
#include "core/utils/protocolEnum.h"
|
||||||
#include "core/utils/api/apiEnums.h"
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/utils/constants/apiKeys.h"
|
#include "core/utils/constants/apiKeys.h"
|
||||||
#include "core/utils/constants/apiConstants.h"
|
#include "core/utils/constants/apiConstants.h"
|
||||||
#include "core/utils/api/apiUtils.h"
|
#include "core/utils/api/apiUtils.h"
|
||||||
@@ -27,7 +27,6 @@
|
|||||||
#include "core/utils/constants/configKeys.h"
|
#include "core/utils/constants/configKeys.h"
|
||||||
#include "core/utils/constants/protocolConstants.h"
|
#include "core/utils/constants/protocolConstants.h"
|
||||||
#include "core/utils/qrCodeUtils.h"
|
#include "core/utils/qrCodeUtils.h"
|
||||||
#include "core/models/serverConfig.h"
|
|
||||||
|
|
||||||
using namespace amnezia;
|
using namespace amnezia;
|
||||||
using namespace ProtocolUtils;
|
using namespace ProtocolUtils;
|
||||||
@@ -208,12 +207,18 @@ ImportController::ImportResult ImportController::extractConfigFromData(const QSt
|
|||||||
case ConfigTypes::Amnezia: {
|
case ConfigTypes::Amnezia: {
|
||||||
result.config = QJsonDocument::fromJson(config.toUtf8()).object();
|
result.config = QJsonDocument::fromJson(config.toUtf8()).object();
|
||||||
|
|
||||||
if (apiUtils::isServerFromApi(result.config)) {
|
if (serverConfigUtils::isServerFromApi(result.config)) {
|
||||||
auto apiConfig = result.config.value(apiDefs::key::apiConfig).toObject();
|
auto apiConfig = result.config.value(apiDefs::key::apiConfig).toObject();
|
||||||
apiConfig[apiDefs::key::vpnKey] = data;
|
apiConfig[apiDefs::key::vpnKey] = data;
|
||||||
result.config[apiDefs::key::apiConfig] = apiConfig;
|
result.config[apiDefs::key::apiConfig] = apiConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (serverConfigUtils::isLegacyApiSubscription(serverConfigUtils::configTypeFromJson(result.config))) {
|
||||||
|
result.errorCode = ErrorCode::LegacyApiV1NotSupportedError;
|
||||||
|
result.config = {};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
processAmneziaConfig(result.config);
|
processAmneziaConfig(result.config);
|
||||||
if (!result.config.empty()) {
|
if (!result.config.empty()) {
|
||||||
checkForMaliciousStrings(result.config, result.maliciousWarningText);
|
checkForMaliciousStrings(result.config, result.maliciousWarningText);
|
||||||
@@ -381,18 +386,29 @@ void ImportController::importConfig(const QJsonObject &config)
|
|||||||
credentials.secretData = config.value(configKey::password).toString();
|
credentials.secretData = config.value(configKey::password).toString();
|
||||||
|
|
||||||
if (credentials.isValid() || config.contains(configKey::containers)) {
|
if (credentials.isValid() || config.contains(configKey::containers)) {
|
||||||
ServerConfig serverConfig = ServerConfig::fromJson(config);
|
m_serversRepository->addServer(QString(), config, serverConfigUtils::configTypeFromJson(config));
|
||||||
m_serversRepository->addServer(serverConfig);
|
|
||||||
emit importFinished();
|
emit importFinished();
|
||||||
} else if (config.contains(configKey::configVersion)) {
|
} else if (config.contains(configKey::configVersion)) {
|
||||||
quint16 crc = qChecksum(QJsonDocument(config).toJson());
|
quint16 crc = qChecksum(QJsonDocument(config).toJson());
|
||||||
if (m_serversRepository->hasServerWithCrc(crc)) {
|
bool hasServerWithCrc = false;
|
||||||
|
const QVector<QString> ids = m_serversRepository->orderedServerIds();
|
||||||
|
for (const QString &id : ids) {
|
||||||
|
const auto apiV2 = m_serversRepository->apiV2Config(id);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (static_cast<quint16>(apiV2->crc) == crc) {
|
||||||
|
hasServerWithCrc = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasServerWithCrc) {
|
||||||
emit importErrorOccurred(ErrorCode::ApiConfigAlreadyAdded, true);
|
emit importErrorOccurred(ErrorCode::ApiConfigAlreadyAdded, true);
|
||||||
} else {
|
} else {
|
||||||
QJsonObject configWithCrc = config;
|
QJsonObject configWithCrc = config;
|
||||||
configWithCrc.insert(configKey::crc, crc);
|
configWithCrc.insert(configKey::crc, crc);
|
||||||
ServerConfig serverConfig = ServerConfig::fromJson(configWithCrc);
|
m_serversRepository->addServer(QString(), configWithCrc, serverConfigUtils::configTypeFromJson(configWithCrc));
|
||||||
m_serversRepository->addServer(serverConfig);
|
|
||||||
emit importFinished();
|
emit importFinished();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#include "core/installers/openvpnInstaller.h"
|
#include "core/installers/openvpnInstaller.h"
|
||||||
#include "core/installers/sftpInstaller.h"
|
#include "core/installers/sftpInstaller.h"
|
||||||
#include "core/installers/socks5Installer.h"
|
#include "core/installers/socks5Installer.h"
|
||||||
|
#include "core/installers/mtProxyInstaller.h"
|
||||||
|
#include "core/installers/telemtInstaller.h"
|
||||||
#include "core/installers/torInstaller.h"
|
#include "core/installers/torInstaller.h"
|
||||||
#include "core/installers/wireguardInstaller.h"
|
#include "core/installers/wireguardInstaller.h"
|
||||||
#include "core/installers/xrayInstaller.h"
|
#include "core/installers/xrayInstaller.h"
|
||||||
@@ -33,8 +35,8 @@
|
|||||||
#include "core/protocols/protocolUtils.h"
|
#include "core/protocols/protocolUtils.h"
|
||||||
#include "core/utils/constants/configKeys.h"
|
#include "core/utils/constants/configKeys.h"
|
||||||
#include "core/utils/constants/protocolConstants.h"
|
#include "core/utils/constants/protocolConstants.h"
|
||||||
#include "core/models/serverConfig.h"
|
|
||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
|
#include "core/models/protocols/mtProxyProtocolConfig.h"
|
||||||
#include "core/models/protocols/awgProtocolConfig.h"
|
#include "core/models/protocols/awgProtocolConfig.h"
|
||||||
#include "ui/models/protocols/wireguardConfigModel.h"
|
#include "ui/models/protocols/wireguardConfigModel.h"
|
||||||
#include "core/utils/utilities.h"
|
#include "core/utils/utilities.h"
|
||||||
@@ -54,6 +56,21 @@ using namespace ProtocolUtils;
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
Logger logger("InstallController");
|
Logger logger("InstallController");
|
||||||
|
|
||||||
|
bool dockerDaemonContainerMissing(const QString &out, const QString &containerDockerName)
|
||||||
|
{
|
||||||
|
if (!out.contains(QLatin1String("Error response from daemon"), Qt::CaseInsensitive)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (out.contains(QLatin1String("No such container"), Qt::CaseInsensitive)
|
||||||
|
&& out.contains(containerDockerName, Qt::CaseInsensitive)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (out.size() < 700 && out.contains(QLatin1String("is not running"), Qt::CaseInsensitive)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallController::InstallController(SecureServersRepository *serversRepository,
|
InstallController::InstallController(SecureServersRepository *serversRepository,
|
||||||
@@ -129,15 +146,36 @@ ErrorCode InstallController::setupContainer(const ServerCredentials &credentials
|
|||||||
return startupContainerWorker(credentials, container, config, sshSession);
|
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)
|
ContainerConfig &newConfig)
|
||||||
{
|
{
|
||||||
if (!isUpdateDockerContainerRequired(container, oldConfig, newConfig)) {
|
if (!isUpdateDockerContainerRequired(container, oldConfig, newConfig)) {
|
||||||
m_serversRepository->setContainerConfig(serverIndex, container, newConfig);
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!adminConfig.has_value()) {
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
}
|
||||||
|
if (container == DockerContainer::MtProxy) {
|
||||||
|
ServerCredentials credentials = adminConfig->credentials();
|
||||||
|
SshSession sshSession(this);
|
||||||
|
MtProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||||
|
} else if (container == DockerContainer::Telemt) {
|
||||||
|
ServerCredentials credentials = adminConfig->credentials();
|
||||||
|
SshSession sshSession(this);
|
||||||
|
TelemtInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||||
|
}
|
||||||
|
adminConfig->updateContainerConfig(container, newConfig);
|
||||||
|
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||||
return ErrorCode::NoError;
|
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);
|
SshSession sshSession(this);
|
||||||
|
|
||||||
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
|
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
|
||||||
@@ -154,42 +192,56 @@ ErrorCode InstallController::updateContainer(int serverIndex, DockerContainer co
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (errorCode == ErrorCode::NoError) {
|
if (errorCode == ErrorCode::NoError) {
|
||||||
clearCachedProfile(serverIndex, container);
|
if (container == DockerContainer::MtProxy) {
|
||||||
m_serversRepository->setContainerConfig(serverIndex, container, newConfig);
|
MtProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||||
|
} else if (container == DockerContainer::Telemt) {
|
||||||
|
TelemtInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||||
|
}
|
||||||
|
clearCachedProfile(serverId, container);
|
||||||
|
adminConfig->updateContainerConfig(container, newConfig);
|
||||||
|
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstallController::clearCachedProfile(int serverIndex, DockerContainer container)
|
void InstallController::clearCachedProfile(const QString &serverId, DockerContainer container)
|
||||||
{
|
{
|
||||||
if (ContainerUtils::containerService(container) == ServiceType::Other) {
|
if (ContainerUtils::containerService(container) == ServiceType::Other) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContainerConfig containerConfigModel = m_serversRepository->containerConfig(serverIndex, container);
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!adminConfig.has_value()) {
|
||||||
m_serversRepository->clearLastConnectionConfig(serverIndex, container);
|
return;
|
||||||
|
|
||||||
emit clientRevocationRequested(serverIndex, containerConfigModel, container);
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorCode InstallController::validateAndPrepareConfig(int serverIndex)
|
|
||||||
{
|
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
|
||||||
|
|
||||||
if (serverConfigModel.isApiConfig()) {
|
|
||||||
return ErrorCode::NoError;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if (container == DockerContainer::None) {
|
||||||
return ErrorCode::NoInstalledContainersError;
|
return ErrorCode::NoInstalledContainersError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContainerConfig containerConfig = m_serversRepository->containerConfig(serverIndex, container);
|
ContainerConfig containerConfig = adminConfig->containerConfig(container);
|
||||||
ServerCredentials credentials = m_serversRepository->serverCredentials(serverIndex);
|
ServerCredentials credentials = adminConfig->credentials();
|
||||||
|
if (!credentials.isValid()) {
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
}
|
||||||
SshSession sshSession;
|
SshSession sshSession;
|
||||||
|
|
||||||
auto isProtocolConfigExists = [](const ContainerConfig &cfg) {
|
auto isProtocolConfigExists = [](const ContainerConfig &cfg) {
|
||||||
@@ -198,20 +250,21 @@ ErrorCode InstallController::validateAndPrepareConfig(int serverIndex)
|
|||||||
|
|
||||||
if (!isProtocolConfigExists(containerConfig)) {
|
if (!isProtocolConfigExists(containerConfig)) {
|
||||||
QString clientName = QString("Admin [%1]").arg(QSysInfo::prettyProductName());
|
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) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
m_serversRepository->setContainerConfig(serverIndex, container, containerConfig);
|
adminConfig->updateContainerConfig(container, containerConfig);
|
||||||
|
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstallController::validateConfig(int serverIndex)
|
void InstallController::validateConfig(const QString &serverId)
|
||||||
{
|
{
|
||||||
QFuture<ErrorCode> future = QtConcurrent::run([this, serverIndex]() {
|
QFuture<ErrorCode> future = QtConcurrent::run([this, serverId]() {
|
||||||
return validateAndPrepareConfig(serverIndex);
|
return validateAndPrepareConfig(serverId);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto *watcher = new QFutureWatcher<ErrorCode>(this);
|
auto *watcher = new QFutureWatcher<ErrorCode>(this);
|
||||||
@@ -230,6 +283,21 @@ void InstallController::validateConfig(int serverIndex)
|
|||||||
watcher->setFuture(future);
|
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)
|
ErrorCode InstallController::prepareContainerConfig(DockerContainer container, const ServerCredentials &credentials, ContainerConfig &containerConfig, SshSession &sshSession)
|
||||||
{
|
{
|
||||||
if (!ContainerUtils::isSupportedByCurrentPlatform(container)) {
|
if (!ContainerUtils::isSupportedByCurrentPlatform(container)) {
|
||||||
@@ -257,7 +325,7 @@ ErrorCode InstallController::prepareContainerConfig(DockerContainer container, c
|
|||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstallController::adminAppendRequested(int serverIndex, DockerContainer container,
|
void InstallController::adminAppendRequested(const QString &serverId, DockerContainer container,
|
||||||
const ContainerConfig &containerConfig, const QString &clientName)
|
const ContainerConfig &containerConfig, const QString &clientName)
|
||||||
{
|
{
|
||||||
if (ContainerUtils::containerService(container) == ServiceType::Other
|
if (ContainerUtils::containerService(container) == ServiceType::Other
|
||||||
@@ -266,13 +334,13 @@ void InstallController::adminAppendRequested(int serverIndex, DockerContainer co
|
|||||||
}
|
}
|
||||||
QString clientId = containerConfig.protocolConfig.clientId();
|
QString clientId = containerConfig.protocolConfig.clientId();
|
||||||
if (!clientId.isEmpty()) {
|
if (!clientId.isEmpty()) {
|
||||||
emit clientAppendRequested(serverIndex, clientId, clientName, container);
|
emit clientAppendRequested(serverId, clientId, clientName, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode InstallController::processContainerForAdmin(DockerContainer container, ContainerConfig &containerConfig,
|
ErrorCode InstallController::processContainerForAdmin(DockerContainer container, ContainerConfig &containerConfig,
|
||||||
const ServerCredentials &credentials, SshSession &sshSession,
|
const ServerCredentials &credentials, SshSession &sshSession,
|
||||||
int serverIndex, const QString &clientName)
|
const QString &serverId, const QString &clientName)
|
||||||
{
|
{
|
||||||
if (ContainerUtils::isSupportedByCurrentPlatform(container)) {
|
if (ContainerUtils::isSupportedByCurrentPlatform(container)) {
|
||||||
ErrorCode errorCode = prepareContainerConfig(container, credentials, containerConfig, sshSession);
|
ErrorCode errorCode = prepareContainerConfig(container, credentials, containerConfig, sshSession);
|
||||||
@@ -280,7 +348,7 @@ ErrorCode InstallController::processContainerForAdmin(DockerContainer container,
|
|||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
adminAppendRequested(serverIndex, container, containerConfig, clientName);
|
adminAppendRequested(serverId, container, containerConfig, clientName);
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,9 +440,24 @@ ErrorCode InstallController::configureContainerWorker(const ServerCredentials &c
|
|||||||
sshSession.replaceVars(amnezia::scriptData(ProtocolScriptType::configure_container, container), baseVars),
|
sshSession.replaceVars(amnezia::scriptData(ProtocolScriptType::configure_container, container), baseVars),
|
||||||
cbReadStdOut, cbReadStdErr);
|
cbReadStdOut, cbReadStdErr);
|
||||||
|
|
||||||
|
if (e != ErrorCode::NoError) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dockerDaemonContainerMissing(stdOut, ContainerUtils::containerToString(container))) {
|
||||||
|
qDebug() << "configureContainerWorker: Docker daemon reports container missing/stopped, output:" << stdOut;
|
||||||
|
return ErrorCode::ServerContainerMissingError;
|
||||||
|
}
|
||||||
|
|
||||||
updateContainerConfigAfterInstallation(container, config, stdOut);
|
updateContainerConfigAfterInstallation(container, config, stdOut);
|
||||||
|
|
||||||
return e;
|
if (container == DockerContainer::MtProxy) {
|
||||||
|
MtProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, config);
|
||||||
|
} else if (container == DockerContainer::Telemt) {
|
||||||
|
TelemtInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode InstallController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &config, SshSession &sshSession)
|
ErrorCode InstallController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &config, SshSession &sshSession)
|
||||||
@@ -527,6 +610,79 @@ bool InstallController::isReinstallContainerRequired(DockerContainer container,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (container == DockerContainer::MtProxy) {
|
||||||
|
const auto *oldMt = oldConfig.getMtProxyProtocolConfig();
|
||||||
|
const auto *newMt = newConfig.getMtProxyProtocolConfig();
|
||||||
|
if (oldMt && newMt) {
|
||||||
|
const QString oldPort =
|
||||||
|
oldMt->port.isEmpty() ? QString(protocols::mtProxy::defaultPort) : oldMt->port;
|
||||||
|
const QString newPort =
|
||||||
|
newMt->port.isEmpty() ? QString(protocols::mtProxy::defaultPort) : newMt->port;
|
||||||
|
if (oldPort != newPort) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const QString oldTransport = oldMt->transportMode.isEmpty() ? QString(
|
||||||
|
protocols::mtProxy::transportModeStandard)
|
||||||
|
: oldMt->transportMode;
|
||||||
|
const QString newTransport = newMt->transportMode.isEmpty() ? QString(
|
||||||
|
protocols::mtProxy::transportModeStandard)
|
||||||
|
: newMt->transportMode;
|
||||||
|
if (oldTransport != newTransport) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (oldMt->tlsDomain != newMt->tlsDomain) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (container == DockerContainer::Telemt) {
|
||||||
|
const auto *oldT = oldConfig.getTelemtProtocolConfig();
|
||||||
|
const auto *newT = newConfig.getTelemtProtocolConfig();
|
||||||
|
if (oldT && newT) {
|
||||||
|
const QString oldPort =
|
||||||
|
oldT->port.isEmpty() ? QString(protocols::telemt::defaultPort) : oldT->port;
|
||||||
|
const QString newPort =
|
||||||
|
newT->port.isEmpty() ? QString(protocols::telemt::defaultPort) : newT->port;
|
||||||
|
if (oldPort != newPort) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const QString oldTransport = oldT->transportMode.isEmpty()
|
||||||
|
? QString(protocols::telemt::transportModeStandard)
|
||||||
|
: oldT->transportMode;
|
||||||
|
const QString newTransport = newT->transportMode.isEmpty()
|
||||||
|
? QString(protocols::telemt::transportModeStandard)
|
||||||
|
: newT->transportMode;
|
||||||
|
if (oldTransport != newTransport) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (oldT->tlsDomain != newT->tlsDomain) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (oldT->maskEnabled != newT->maskEnabled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (oldT->tlsEmulation != newT->tlsEmulation) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (oldT->useMiddleProxy != newT->useMiddleProxy) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (oldT->tag != newT->tag) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const QString oldUser = oldT->userName.isEmpty()
|
||||||
|
? QString::fromUtf8(protocols::telemt::defaultUserName)
|
||||||
|
: oldT->userName;
|
||||||
|
const QString newUser = newT->userName.isEmpty()
|
||||||
|
? QString::fromUtf8(protocols::telemt::defaultUserName)
|
||||||
|
: newT->userName;
|
||||||
|
if (oldUser != newUser) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (container == DockerContainer::Socks5Proxy) {
|
if (container == DockerContainer::Socks5Proxy) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -618,7 +774,7 @@ ErrorCode InstallController::isUserInSudo(const ServerCredentials &credentials,
|
|||||||
return ErrorCode::ServerUserDirectoryNotAccessible;
|
return ErrorCode::ServerUserDirectoryNotAccessible;
|
||||||
if (stdOut.contains("sudoers") || stdOut.contains("is not allowed to run sudo on"))
|
if (stdOut.contains("sudoers") || stdOut.contains("is not allowed to run sudo on"))
|
||||||
return ErrorCode::ServerUserNotAllowedInSudoers;
|
return ErrorCode::ServerUserNotAllowedInSudoers;
|
||||||
if (stdOut.contains("password is required"))
|
if (stdOut.contains("password is required") || stdOut.contains("authentication is required"))
|
||||||
return ErrorCode::ServerUserPasswordRequired;
|
return ErrorCode::ServerUserPasswordRequired;
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
@@ -688,9 +844,16 @@ ErrorCode InstallController::setupServerFirewall(const ServerCredentials &creden
|
|||||||
amnezia::genBaseVars(credentials, DockerContainer::None, QString(), QString())));
|
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);
|
SshSession sshSession(this);
|
||||||
|
|
||||||
QString script = QString("sudo reboot");
|
QString script = QString("sudo reboot");
|
||||||
@@ -709,27 +872,38 @@ ErrorCode InstallController::rebootServer(int serverIndex)
|
|||||||
return sshSession.runScript(credentials, script, cbReadStdOut, cbReadStdErr);
|
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);
|
SshSession sshSession(this);
|
||||||
ErrorCode errorCode = sshSession.runScript(credentials, amnezia::scriptData(SharedScriptType::remove_all_containers));
|
ErrorCode errorCode = sshSession.runScript(credentials, amnezia::scriptData(SharedScriptType::remove_all_containers));
|
||||||
|
|
||||||
if (errorCode == ErrorCode::NoError) {
|
if (errorCode == ErrorCode::NoError) {
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
adminConfig->containers.clear();
|
||||||
serverConfigModel.visit([](auto& arg) {
|
adminConfig->defaultContainer = DockerContainer::None;
|
||||||
arg.containers.clear();
|
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||||
arg.defaultContainer = DockerContainer::None;
|
|
||||||
});
|
|
||||||
m_serversRepository->editServer(serverIndex, serverConfigModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorCode;
|
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);
|
SshSession sshSession(this);
|
||||||
ErrorCode errorCode = sshSession.runScript(
|
ErrorCode errorCode = sshSession.runScript(
|
||||||
credentials,
|
credentials,
|
||||||
@@ -737,11 +911,10 @@ ErrorCode InstallController::removeContainer(int serverIndex, DockerContainer co
|
|||||||
amnezia::genBaseVars(credentials, container, QString(), QString())));
|
amnezia::genBaseVars(credentials, container, QString(), QString())));
|
||||||
|
|
||||||
if (errorCode == ErrorCode::NoError) {
|
if (errorCode == ErrorCode::NoError) {
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
QMap<DockerContainer, ContainerConfig> containers = adminConfig->containers;
|
||||||
QMap<DockerContainer, ContainerConfig> containers = serverConfigModel.containers();
|
|
||||||
containers.remove(container);
|
containers.remove(container);
|
||||||
|
|
||||||
DockerContainer defaultContainer = serverConfigModel.defaultContainer();
|
DockerContainer defaultContainer = adminConfig->defaultContainer;
|
||||||
if (defaultContainer == container) {
|
if (defaultContainer == container) {
|
||||||
if (containers.isEmpty()) {
|
if (containers.isEmpty()) {
|
||||||
defaultContainer = DockerContainer::None;
|
defaultContainer = DockerContainer::None;
|
||||||
@@ -749,12 +922,10 @@ ErrorCode InstallController::removeContainer(int serverIndex, DockerContainer co
|
|||||||
defaultContainer = containers.begin().key();
|
defaultContainer = containers.begin().key();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConfigModel.visit([&containers, defaultContainer](auto& arg) {
|
adminConfig->containers = containers;
|
||||||
arg.containers = containers;
|
adminConfig->defaultContainer = defaultContainer;
|
||||||
arg.defaultContainer = defaultContainer;
|
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||||
});
|
|
||||||
m_serversRepository->editServer(serverIndex, serverConfigModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorCode;
|
return errorCode;
|
||||||
@@ -772,6 +943,8 @@ QScopedPointer<InstallerBase> InstallController::createInstaller(DockerContainer
|
|||||||
case DockerContainer::TorWebSite: return QScopedPointer<InstallerBase>(new TorInstaller(this));
|
case DockerContainer::TorWebSite: return QScopedPointer<InstallerBase>(new TorInstaller(this));
|
||||||
case DockerContainer::Sftp: return QScopedPointer<InstallerBase>(new SftpInstaller(this));
|
case DockerContainer::Sftp: return QScopedPointer<InstallerBase>(new SftpInstaller(this));
|
||||||
case DockerContainer::Socks5Proxy: return QScopedPointer<InstallerBase>(new Socks5Installer(this));
|
case DockerContainer::Socks5Proxy: return QScopedPointer<InstallerBase>(new Socks5Installer(this));
|
||||||
|
case DockerContainer::MtProxy: return QScopedPointer<InstallerBase>(new MtProxyInstaller(this));
|
||||||
|
case DockerContainer::Telemt: return QScopedPointer<InstallerBase>(new TelemtInstaller(this));
|
||||||
default: return QScopedPointer<InstallerBase>(new InstallerBase(this));
|
default: return QScopedPointer<InstallerBase>(new InstallerBase(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -810,14 +983,35 @@ bool InstallController::isUpdateDockerContainerRequired(DockerContainer containe
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (container == DockerContainer::MtProxy) {
|
||||||
|
const auto *oldMt = oldConfig.getMtProxyProtocolConfig();
|
||||||
|
const auto *newMt = newConfig.getMtProxyProtocolConfig();
|
||||||
|
if (!oldMt || !newMt) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !oldMt->equalsDockerDeploymentSettings(*newMt);
|
||||||
|
} else if (container == DockerContainer::Telemt) {
|
||||||
|
const auto *oldT = oldConfig.getTelemtProtocolConfig();
|
||||||
|
const auto *newT = newConfig.getTelemtProtocolConfig();
|
||||||
|
if (!oldT || !newT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !oldT->equalsDockerDeploymentSettings(*newT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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);
|
SshSession sshSession(this);
|
||||||
|
|
||||||
QMap<DockerContainer, ContainerConfig> installedContainers;
|
QMap<DockerContainer, ContainerConfig> installedContainers;
|
||||||
@@ -826,8 +1020,7 @@ ErrorCode InstallController::scanServerForInstalledContainers(int serverIndex)
|
|||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerConfig serverConfigModel = m_serversRepository->server(serverIndex);
|
QMap<DockerContainer, ContainerConfig> containers = adminConfig->containers;
|
||||||
QMap<DockerContainer, ContainerConfig> containers = serverConfigModel.containers();
|
|
||||||
bool hasNewContainers = false;
|
bool hasNewContainers = false;
|
||||||
|
|
||||||
QString clientName = QString("Admin [%1]").arg(QSysInfo::prettyProductName());
|
QString clientName = QString("Admin [%1]").arg(QSysInfo::prettyProductName());
|
||||||
@@ -835,29 +1028,25 @@ ErrorCode InstallController::scanServerForInstalledContainers(int serverIndex)
|
|||||||
if (!containers.contains(iterator.key())) {
|
if (!containers.contains(iterator.key())) {
|
||||||
ContainerConfig containerConfig = iterator.value();
|
ContainerConfig containerConfig = iterator.value();
|
||||||
errorCode = processContainerForAdmin(iterator.key(), containerConfig, credentials, sshSession,
|
errorCode = processContainerForAdmin(iterator.key(), containerConfig, credentials, sshSession,
|
||||||
serverIndex, clientName);
|
serverId, clientName);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
containers.insert(iterator.key(), containerConfig);
|
containers.insert(iterator.key(), containerConfig);
|
||||||
hasNewContainers = true;
|
hasNewContainers = true;
|
||||||
|
|
||||||
DockerContainer defaultContainer = serverConfigModel.defaultContainer();
|
DockerContainer defaultContainer = adminConfig->defaultContainer;
|
||||||
if (defaultContainer == DockerContainer::None
|
if (defaultContainer == DockerContainer::None
|
||||||
&& ContainerUtils::containerService(iterator.key()) != ServiceType::Other
|
&& ContainerUtils::containerService(iterator.key()) != ServiceType::Other
|
||||||
&& ContainerUtils::isSupportedByCurrentPlatform(iterator.key())) {
|
&& ContainerUtils::isSupportedByCurrentPlatform(iterator.key())) {
|
||||||
serverConfigModel.visit([iterator](auto& arg) {
|
adminConfig->defaultContainer = iterator.key();
|
||||||
arg.defaultContainer = iterator.key();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasNewContainers) {
|
if (hasNewContainers) {
|
||||||
serverConfigModel.visit([&containers](auto& arg) {
|
adminConfig->containers = containers;
|
||||||
arg.containers = containers;
|
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||||
});
|
|
||||||
m_serversRepository->editServer(serverIndex, serverConfigModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
@@ -899,7 +1088,7 @@ ErrorCode InstallController::installServer(const ServerCredentials &credentials,
|
|||||||
preparedContainers.insert(container, containerConfig);
|
preparedContainers.insert(container, containerConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
SelfHostedServerConfig serverConfig;
|
SelfHostedAdminServerConfig serverConfig;
|
||||||
serverConfig.hostName = credentials.hostName;
|
serverConfig.hostName = credentials.hostName;
|
||||||
serverConfig.userName = credentials.userName;
|
serverConfig.userName = credentials.userName;
|
||||||
serverConfig.password = credentials.secretData;
|
serverConfig.password = credentials.secretData;
|
||||||
@@ -912,21 +1101,29 @@ ErrorCode InstallController::installServer(const ServerCredentials &credentials,
|
|||||||
|
|
||||||
serverConfig.defaultContainer = container;
|
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());
|
QString clientName = QString("Admin [%1]").arg(QSysInfo::prettyProductName());
|
||||||
for (auto iterator = preparedContainers.begin(); iterator != preparedContainers.end(); iterator++) {
|
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;
|
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)
|
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);
|
SshSession sshSession(this);
|
||||||
|
|
||||||
QMap<DockerContainer, ContainerConfig> installedContainers;
|
QMap<DockerContainer, ContainerConfig> installedContainers;
|
||||||
@@ -949,15 +1146,17 @@ ErrorCode InstallController::installContainer(int serverIndex, DockerContainer c
|
|||||||
|
|
||||||
QString clientName = QString("Admin [%1]").arg(QSysInfo::prettyProductName());
|
QString clientName = QString("Admin [%1]").arg(QSysInfo::prettyProductName());
|
||||||
for (auto iterator = installedContainers.begin(); iterator != installedContainers.end(); iterator++) {
|
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) {
|
if (existingConfigModel.container == DockerContainer::None) {
|
||||||
ContainerConfig containerConfig = iterator.value();
|
ContainerConfig containerConfig = iterator.value();
|
||||||
errorCode = processContainerForAdmin(iterator.key(), containerConfig, credentials, sshSession,
|
errorCode = processContainerForAdmin(iterator.key(), containerConfig, credentials, sshSession,
|
||||||
serverIndex, clientName);
|
serverId, clientName);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
m_serversRepository->setContainerConfig(serverIndex, iterator.key(), containerConfig);
|
adminConfig->updateContainerConfig(iterator.key(), containerConfig);
|
||||||
|
m_serversRepository->editServer(serverId, adminConfig->toJson(),
|
||||||
|
serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -993,7 +1192,15 @@ bool InstallController::isServerAlreadyExists(const ServerCredentials &credentia
|
|||||||
{
|
{
|
||||||
int serversCount = m_serversRepository->serversCount();
|
int serversCount = m_serversRepository->serversCount();
|
||||||
for (int i = 0; i < serversCount; i++) {
|
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) {
|
if (credentials.hostName == existingCredentials.hostName && credentials.port == existingCredentials.port) {
|
||||||
existingServerIndex = i;
|
existingServerIndex = i;
|
||||||
return true;
|
return true;
|
||||||
@@ -1093,6 +1300,56 @@ void InstallController::updateContainerConfigAfterInstallation(DockerContainer c
|
|||||||
onion.replace("\n", "");
|
onion.replace("\n", "");
|
||||||
torProtocolConfig->serverConfig.site = onion;
|
torProtocolConfig->serverConfig.site = onion;
|
||||||
}
|
}
|
||||||
|
} else if (container == DockerContainer::MtProxy) {
|
||||||
|
if (auto* mtProxyConfig = containerConfig.getMtProxyProtocolConfig()) {
|
||||||
|
qDebug() << "amnezia mtproxy" << stdOut;
|
||||||
|
|
||||||
|
static const QRegularExpression reSecret(
|
||||||
|
QStringLiteral(R"(\[\*\]\s+Secret:\s+([0-9a-fA-F]{32}))"),
|
||||||
|
QRegularExpression::CaseInsensitiveOption);
|
||||||
|
static const QRegularExpression reTgLink(QStringLiteral(R"(\[\*\]\s+tg://\s+link:\s+(tg://proxy\?[^\s]+))"));
|
||||||
|
static const QRegularExpression reTmeLink(
|
||||||
|
QStringLiteral(R"(\[\*\]\s+t\.me\s+link:\s+(https://t\.me/proxy\?[^\s]+))"));
|
||||||
|
|
||||||
|
const QRegularExpressionMatch mSecret = reSecret.match(stdOut);
|
||||||
|
const QRegularExpressionMatch mTgLink = reTgLink.match(stdOut);
|
||||||
|
const QRegularExpressionMatch mTmeLink = reTmeLink.match(stdOut);
|
||||||
|
|
||||||
|
if (mSecret.hasMatch()) {
|
||||||
|
mtProxyConfig->secret = mSecret.captured(1);
|
||||||
|
}
|
||||||
|
if (mTgLink.hasMatch()) {
|
||||||
|
mtProxyConfig->tgLink = mTgLink.captured(1);
|
||||||
|
}
|
||||||
|
if (mTmeLink.hasMatch()) {
|
||||||
|
mtProxyConfig->tmeLink = mTmeLink.captured(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (container == DockerContainer::Telemt) {
|
||||||
|
if (auto *telemtConfig = containerConfig.getTelemtProtocolConfig()) {
|
||||||
|
qDebug() << "amnezia-telemt configure stdout" << stdOut;
|
||||||
|
|
||||||
|
static const QRegularExpression reSecret(
|
||||||
|
QStringLiteral(R"(\[\*\]\s+Secret:\s+([0-9a-fA-F]{32}))"),
|
||||||
|
QRegularExpression::CaseInsensitiveOption);
|
||||||
|
static const QRegularExpression reTgLink(QStringLiteral(R"(\[\*\]\s+tg://\s+link:\s+(tg://proxy\?[^\s]+))"));
|
||||||
|
static const QRegularExpression reTmeLink(
|
||||||
|
QStringLiteral(R"(\[\*\]\s+t\.me\s+link:\s+(https://t\.me/proxy\?[^\s]+))"));
|
||||||
|
|
||||||
|
const QRegularExpressionMatch mSecret = reSecret.match(stdOut);
|
||||||
|
const QRegularExpressionMatch mTgLink = reTgLink.match(stdOut);
|
||||||
|
const QRegularExpressionMatch mTmeLink = reTmeLink.match(stdOut);
|
||||||
|
|
||||||
|
if (mSecret.hasMatch()) {
|
||||||
|
telemtConfig->secret = mSecret.captured(1);
|
||||||
|
}
|
||||||
|
if (mTgLink.hasMatch()) {
|
||||||
|
telemtConfig->tgLink = mTgLink.captured(1);
|
||||||
|
}
|
||||||
|
if (mTmeLink.hasMatch()) {
|
||||||
|
telemtConfig->tmeLink = mTmeLink.captured(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1177,3 +1434,126 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
|||||||
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorCode InstallController::setDockerContainerEnabledState(const QString &serverId, DockerContainer container, bool enabled)
|
||||||
|
{
|
||||||
|
if (container != DockerContainer::MtProxy && container != DockerContainer::Telemt) {
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
}
|
||||||
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!adminConfig.has_value()) {
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
}
|
||||||
|
ServerCredentials credentials = adminConfig->credentials();
|
||||||
|
if (!credentials.isValid()) {
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
}
|
||||||
|
const QString containerName = ContainerUtils::containerToString(container);
|
||||||
|
SshSession sshSession(this);
|
||||||
|
const QString script = enabled ? QStringLiteral("sudo docker start %1").arg(containerName)
|
||||||
|
: QStringLiteral("sudo docker stop %1").arg(containerName);
|
||||||
|
const ErrorCode runError = sshSession.runScript(credentials, script);
|
||||||
|
if (runError != ErrorCode::NoError) {
|
||||||
|
return runError;
|
||||||
|
}
|
||||||
|
ContainerConfig currentConfig = adminConfig->containerConfig(container);
|
||||||
|
bool persist = false;
|
||||||
|
if (auto *mtConfig = currentConfig.getMtProxyProtocolConfig()) {
|
||||||
|
mtConfig->isEnabled = enabled;
|
||||||
|
persist = true;
|
||||||
|
} else if (auto *telemtConfig = currentConfig.getTelemtProtocolConfig()) {
|
||||||
|
telemtConfig->isEnabled = enabled;
|
||||||
|
persist = true;
|
||||||
|
}
|
||||||
|
if (persist) {
|
||||||
|
adminConfig->updateContainerConfig(container, currentConfig);
|
||||||
|
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||||
|
}
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode InstallController::queryDockerContainerStatus(const QString &serverId, DockerContainer container, int &statusOut)
|
||||||
|
{
|
||||||
|
statusOut = 3;
|
||||||
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!adminConfig.has_value()) {
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
}
|
||||||
|
ServerCredentials credentials = adminConfig->credentials();
|
||||||
|
if (!credentials.isValid()) {
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
}
|
||||||
|
const QString containerName = ContainerUtils::containerToString(container);
|
||||||
|
QString stdOut;
|
||||||
|
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||||
|
stdOut += data;
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
};
|
||||||
|
SshSession sshSession(this);
|
||||||
|
const QString script = QStringLiteral(
|
||||||
|
"sudo docker inspect --format '{{.State.Status}}' %1 2>/dev/null || echo 'not_found'")
|
||||||
|
.arg(containerName);
|
||||||
|
const ErrorCode errorCode = sshSession.runScript(credentials, script, cbReadStdOut);
|
||||||
|
if (errorCode != ErrorCode::NoError) {
|
||||||
|
return errorCode;
|
||||||
|
}
|
||||||
|
const QString status = stdOut.trimmed();
|
||||||
|
if (status == QLatin1String("running")) {
|
||||||
|
statusOut = 1;
|
||||||
|
} else if (status == QLatin1String("not_found") || status.isEmpty()) {
|
||||||
|
statusOut = 0;
|
||||||
|
} else if (status == QLatin1String("exited") || status == QLatin1String("created")
|
||||||
|
|| status == QLatin1String("paused")) {
|
||||||
|
statusOut = 2;
|
||||||
|
} else {
|
||||||
|
statusOut = 3;
|
||||||
|
}
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode InstallController::queryMtProxyDiagnostics(const QString &serverId, DockerContainer container, int listenPort,
|
||||||
|
MtProxyContainerDiagnostics &out)
|
||||||
|
{
|
||||||
|
out = {};
|
||||||
|
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);
|
||||||
|
return MtProxyInstaller::queryDiagnostics(sshSession, credentials, container, listenPort, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString InstallController::fetchDockerContainerSecret(const QString &serverId, DockerContainer container)
|
||||||
|
{
|
||||||
|
if (container != DockerContainer::MtProxy && container != DockerContainer::Telemt) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!adminConfig.has_value()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
ServerCredentials credentials = adminConfig->credentials();
|
||||||
|
if (!credentials.isValid()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const QString containerName = ContainerUtils::containerToString(container);
|
||||||
|
QString stdOut;
|
||||||
|
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||||
|
stdOut += data;
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
};
|
||||||
|
SshSession sshSession(this);
|
||||||
|
const QString path = QStringLiteral("/data/secret");
|
||||||
|
const QString cmd = QStringLiteral("sudo docker exec %1 cat %2").arg(containerName, path);
|
||||||
|
const ErrorCode errorCode = sshSession.runScript(credentials, cmd, cbReadStdOut);
|
||||||
|
if (errorCode != ErrorCode::NoError) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const QString secret = stdOut.trimmed();
|
||||||
|
static const QRegularExpression hex32(QStringLiteral("^[0-9a-fA-F]{32}$"));
|
||||||
|
return hex32.match(secret).hasMatch() ? secret : QString();
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
#include "core/repositories/secureServersRepository.h"
|
#include "core/repositories/secureServersRepository.h"
|
||||||
#include "core/repositories/secureAppSettingsRepository.h"
|
#include "core/repositories/secureAppSettingsRepository.h"
|
||||||
|
#include "core/installers/mtProxyInstaller.h"
|
||||||
|
|
||||||
class SshSession;
|
class SshSession;
|
||||||
class InstallerBase;
|
class InstallerBase;
|
||||||
@@ -33,22 +34,32 @@ public:
|
|||||||
~InstallController();
|
~InstallController();
|
||||||
|
|
||||||
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, ContainerConfig &config, bool isUpdate = false);
|
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, ContainerConfig &config, bool isUpdate = false);
|
||||||
ErrorCode updateContainer(int serverIndex, DockerContainer container, const ContainerConfig &oldConfig, ContainerConfig &newConfig);
|
ErrorCode updateContainer(const QString &serverId, DockerContainer container, const ContainerConfig &oldConfig, ContainerConfig &newConfig);
|
||||||
|
|
||||||
ErrorCode rebootServer(int serverIndex);
|
ErrorCode rebootServer(const QString &serverId);
|
||||||
ErrorCode removeAllContainers(int serverIndex);
|
ErrorCode removeAllContainers(const QString &serverId);
|
||||||
ErrorCode removeContainer(int serverIndex, DockerContainer container);
|
ErrorCode removeContainer(const QString &serverId, DockerContainer container);
|
||||||
|
|
||||||
|
ErrorCode setDockerContainerEnabledState(const QString &serverId, DockerContainer container, bool enabled);
|
||||||
|
|
||||||
|
/// statusOut: 0 = not deployed, 1 = running, 2 = stopped, 3 = error
|
||||||
|
ErrorCode queryDockerContainerStatus(const QString &serverId, DockerContainer container, int &statusOut);
|
||||||
|
|
||||||
|
ErrorCode queryMtProxyDiagnostics(const QString &serverId, DockerContainer container, int listenPort,
|
||||||
|
MtProxyContainerDiagnostics &out);
|
||||||
|
|
||||||
|
QString fetchDockerContainerSecret(const QString &serverId, DockerContainer container);
|
||||||
|
|
||||||
ContainerConfig generateConfig(DockerContainer container, int port, TransportProto transportProto);
|
ContainerConfig generateConfig(DockerContainer container, int port, TransportProto transportProto);
|
||||||
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, ContainerConfig> &installedContainers, SshSession &sshSession);
|
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, ContainerConfig> &installedContainers, SshSession &sshSession);
|
||||||
|
|
||||||
ErrorCode scanServerForInstalledContainers(int serverIndex);
|
ErrorCode scanServerForInstalledContainers(const QString &serverId);
|
||||||
|
|
||||||
ErrorCode installContainer(const ServerCredentials &credentials, DockerContainer container, int port, TransportProto transportProto, ContainerConfig &config);
|
ErrorCode installContainer(const ServerCredentials &credentials, DockerContainer container, int port, TransportProto transportProto, ContainerConfig &config);
|
||||||
|
|
||||||
ErrorCode installServer(const ServerCredentials &credentials, DockerContainer container, int port, TransportProto transportProto,
|
ErrorCode installServer(const ServerCredentials &credentials, DockerContainer container, int port, TransportProto transportProto,
|
||||||
bool &wasContainerInstalled);
|
bool &wasContainerInstalled);
|
||||||
ErrorCode installContainer(int serverIndex, DockerContainer container, int port, TransportProto transportProto,
|
ErrorCode installContainer(const QString &serverId, DockerContainer container, int port, TransportProto transportProto,
|
||||||
bool &wasContainerInstalled);
|
bool &wasContainerInstalled);
|
||||||
|
|
||||||
bool isUpdateDockerContainerRequired(DockerContainer container, const ContainerConfig &oldConfig, const ContainerConfig &newConfig);
|
bool isUpdateDockerContainerRequired(DockerContainer container, const ContainerConfig &oldConfig, const ContainerConfig &newConfig);
|
||||||
@@ -62,11 +73,13 @@ public:
|
|||||||
|
|
||||||
void cancelInstallation();
|
void cancelInstallation();
|
||||||
|
|
||||||
void clearCachedProfile(int serverIndex, DockerContainer container);
|
void clearCachedProfile(const QString &serverId, DockerContainer container);
|
||||||
|
|
||||||
ErrorCode validateAndPrepareConfig(int serverIndex);
|
ErrorCode validateAndPrepareConfig(const QString &serverId);
|
||||||
|
|
||||||
void validateConfig(int serverIndex);
|
void validateConfig(const QString &serverId);
|
||||||
|
|
||||||
|
void addEmptyServer(const ServerCredentials &credentials);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void configValidated(bool isValid);
|
void configValidated(bool isValid);
|
||||||
@@ -74,8 +87,8 @@ signals:
|
|||||||
|
|
||||||
void serverIsBusy(const bool isBusy);
|
void serverIsBusy(const bool isBusy);
|
||||||
void cancelInstallationRequested();
|
void cancelInstallationRequested();
|
||||||
void clientRevocationRequested(int serverIndex, const ContainerConfig &containerConfig, DockerContainer container);
|
void clientRevocationRequested(const QString &serverId, const ContainerConfig &containerConfig, DockerContainer container);
|
||||||
void clientAppendRequested(int serverIndex, const QString &clientId, const QString &clientName, DockerContainer container);
|
void clientAppendRequested(const QString &serverId, const QString &clientId, const QString &clientName, DockerContainer container);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container, SshSession &sshSession);
|
ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container, SshSession &sshSession);
|
||||||
@@ -95,9 +108,9 @@ private:
|
|||||||
|
|
||||||
ErrorCode processContainerForAdmin(DockerContainer container, ContainerConfig &containerConfig,
|
ErrorCode processContainerForAdmin(DockerContainer container, ContainerConfig &containerConfig,
|
||||||
const ServerCredentials &credentials, SshSession &sshSession,
|
const ServerCredentials &credentials, SshSession &sshSession,
|
||||||
int serverIndex, const QString &clientName);
|
const QString &serverId, const QString &clientName);
|
||||||
|
|
||||||
void adminAppendRequested(int serverIndex, DockerContainer container,
|
void adminAppendRequested(const QString &serverId, DockerContainer container,
|
||||||
const ContainerConfig &containerConfig, const QString &clientName);
|
const ContainerConfig &containerConfig, const QString &clientName);
|
||||||
|
|
||||||
static void updateContainerConfigAfterInstallation(DockerContainer container, ContainerConfig &containerConfig, const QString &stdOut);
|
static void updateContainerConfigAfterInstallation(DockerContainer container, ContainerConfig &containerConfig, const QString &stdOut);
|
||||||
@@ -114,4 +127,3 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif // INSTALLCONTROLLER_H
|
#endif // INSTALLCONTROLLER_H
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include "core/protocols/protocolUtils.h"
|
#include "core/protocols/protocolUtils.h"
|
||||||
#include "core/utils/constants/configKeys.h"
|
#include "core/utils/constants/configKeys.h"
|
||||||
#include "core/utils/constants/protocolConstants.h"
|
#include "core/utils/constants/protocolConstants.h"
|
||||||
#include "core/models/serverConfig.h"
|
|
||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
|
|
||||||
using namespace amnezia;
|
using namespace amnezia;
|
||||||
@@ -292,11 +291,18 @@ ErrorCode UsersController::getXrayClients(const DockerContainer container, const
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode UsersController::updateClients(int serverIndex, const DockerContainer container)
|
ErrorCode UsersController::updateClients(const QString &serverId, const DockerContainer container)
|
||||||
{
|
{
|
||||||
ErrorCode error = ErrorCode::NoError;
|
ErrorCode error = ErrorCode::NoError;
|
||||||
SshSession sshSession;
|
SshSession sshSession;
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable");
|
QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable");
|
||||||
if (container == DockerContainer::OpenVpn) {
|
if (container == DockerContainer::OpenVpn) {
|
||||||
@@ -381,20 +387,27 @@ ErrorCode UsersController::updateClients(int serverIndex, const DockerContainer
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ErrorCode UsersController::appendClient(int serverIndex, const QString &clientId, const QString &clientName, const DockerContainer container)
|
ErrorCode UsersController::appendClient(const QString &serverId, const QString &clientId, const QString &clientName, const DockerContainer container)
|
||||||
{
|
{
|
||||||
ErrorCode error = ErrorCode::NoError;
|
ErrorCode error = ErrorCode::NoError;
|
||||||
SshSession sshSession;
|
SshSession sshSession;
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
error = updateClients(serverIndex, container);
|
error = updateClients(serverId, container);
|
||||||
if (error != ErrorCode::NoError) {
|
if (error != ErrorCode::NoError) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int existingIndex = clientIndexById(clientId, m_clientsTable);
|
int existingIndex = clientIndexById(clientId, m_clientsTable);
|
||||||
if (existingIndex >= 0) {
|
if (existingIndex >= 0) {
|
||||||
return renameClient(serverIndex, existingIndex, clientName, container, true);
|
return renameClient(serverId, existingIndex, clientName, container, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject client;
|
QJsonObject client;
|
||||||
@@ -426,7 +439,7 @@ ErrorCode UsersController::appendClient(int serverIndex, const QString &clientId
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode UsersController::renameClient(int serverIndex, const int row, const QString &clientName,
|
ErrorCode UsersController::renameClient(const QString &serverId, const int row, const QString &clientName,
|
||||||
const DockerContainer container, bool addTimeStamp)
|
const DockerContainer container, bool addTimeStamp)
|
||||||
{
|
{
|
||||||
if (row < 0 || row >= m_clientsTable.size()) {
|
if (row < 0 || row >= m_clientsTable.size()) {
|
||||||
@@ -434,7 +447,14 @@ ErrorCode UsersController::renameClient(int serverIndex, const int row, const QS
|
|||||||
}
|
}
|
||||||
|
|
||||||
SshSession sshSession;
|
SshSession sshSession;
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
auto client = m_clientsTable.at(row).toObject();
|
auto client = m_clientsTable.at(row).toObject();
|
||||||
auto userData = client[configKey::userData].toObject();
|
auto userData = client[configKey::userData].toObject();
|
||||||
@@ -470,7 +490,7 @@ ErrorCode UsersController::renameClient(int serverIndex, const int row, const QS
|
|||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode UsersController::revokeOpenVpn(const int row, const DockerContainer container, const ServerCredentials &credentials,
|
ErrorCode UsersController::revokeOpenVpn(const int row, const DockerContainer container, const ServerCredentials &credentials,
|
||||||
const int serverIndex, SshSession* sshSession, QJsonArray &clientsTable)
|
SshSession* sshSession, QJsonArray &clientsTable)
|
||||||
{
|
{
|
||||||
if (row < 0 || row >= clientsTable.size()) {
|
if (row < 0 || row >= clientsTable.size()) {
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
@@ -689,14 +709,21 @@ ErrorCode UsersController::revokeXray(const int row,
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode UsersController::revokeClient(int serverIndex, const int index, const DockerContainer container)
|
ErrorCode UsersController::revokeClient(const QString &serverId, const int index, const DockerContainer container)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= m_clientsTable.size()) {
|
if (index < 0 || index >= m_clientsTable.size()) {
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
SshSession sshSession;
|
SshSession sshSession;
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
QString clientId = m_clientsTable.at(index).toObject().value(configKey::clientId).toString();
|
QString clientId = m_clientsTable.at(index).toObject().value(configKey::clientId).toString();
|
||||||
ErrorCode errorCode = ErrorCode::NoError;
|
ErrorCode errorCode = ErrorCode::NoError;
|
||||||
@@ -704,7 +731,7 @@ ErrorCode UsersController::revokeClient(int serverIndex, const int index, const
|
|||||||
switch(container)
|
switch(container)
|
||||||
{
|
{
|
||||||
case DockerContainer::OpenVpn: {
|
case DockerContainer::OpenVpn: {
|
||||||
errorCode = revokeOpenVpn(index, container, credentials, serverIndex, &sshSession, m_clientsTable);
|
errorCode = revokeOpenVpn(index, container, credentials, &sshSession, m_clientsTable);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DockerContainer::WireGuard:
|
case DockerContainer::WireGuard:
|
||||||
@@ -724,12 +751,15 @@ ErrorCode UsersController::revokeClient(int serverIndex, const int index, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (errorCode == ErrorCode::NoError) {
|
if (errorCode == ErrorCode::NoError) {
|
||||||
ServerConfig serverConfig = m_serversRepository->server(serverIndex);
|
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
ContainerConfig containerCfg = m_serversRepository->containerConfig(serverIndex, container);
|
if (!adminConfig.has_value()) {
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
}
|
||||||
|
ContainerConfig containerCfg = adminConfig->containerConfig(container);
|
||||||
QString containerClientId = containerCfg.protocolConfig.clientId();
|
QString containerClientId = containerCfg.protocolConfig.clientId();
|
||||||
|
|
||||||
if (!clientId.isEmpty() && !containerClientId.isEmpty() && containerClientId.contains(clientId)) {
|
if (!clientId.isEmpty() && !containerClientId.isEmpty() && containerClientId.contains(clientId)) {
|
||||||
emit adminConfigRevoked(serverIndex, container);
|
emit adminConfigRevoked(serverId, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit clientRevoked(index);
|
emit clientRevoked(index);
|
||||||
@@ -739,13 +769,20 @@ ErrorCode UsersController::revokeClient(int serverIndex, const int index, const
|
|||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode UsersController::revokeClient(int serverIndex, const ContainerConfig &containerConfig, const DockerContainer container)
|
ErrorCode UsersController::revokeClient(const QString &serverId, const ContainerConfig &containerConfig, const DockerContainer container)
|
||||||
{
|
{
|
||||||
SshSession sshSession;
|
SshSession sshSession;
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
ErrorCode errorCode = ErrorCode::NoError;
|
ErrorCode errorCode = ErrorCode::NoError;
|
||||||
errorCode = updateClients(serverIndex, container);
|
errorCode = updateClients(serverId, container);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
@@ -778,7 +815,7 @@ ErrorCode UsersController::revokeClient(int serverIndex, const ContainerConfig &
|
|||||||
switch (container)
|
switch (container)
|
||||||
{
|
{
|
||||||
case DockerContainer::OpenVpn: {
|
case DockerContainer::OpenVpn: {
|
||||||
errorCode = revokeOpenVpn(row, container, credentials, serverIndex, &sshSession, m_clientsTable);
|
errorCode = revokeOpenVpn(row, container, credentials, &sshSession, m_clientsTable);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DockerContainer::WireGuard:
|
case DockerContainer::WireGuard:
|
||||||
@@ -797,7 +834,7 @@ ErrorCode UsersController::revokeClient(int serverIndex, const ContainerConfig &
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (errorCode == ErrorCode::NoError) {
|
if (errorCode == ErrorCode::NoError) {
|
||||||
emit adminConfigRevoked(serverIndex, container);
|
emit adminConfigRevoked(serverId, container);
|
||||||
emit clientRevoked(row);
|
emit clientRevoked(row);
|
||||||
emit clientsUpdated(m_clientsTable);
|
emit clientsUpdated(m_clientsTable);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,21 +37,21 @@ signals:
|
|||||||
void clientAdded(const QJsonObject &client);
|
void clientAdded(const QJsonObject &client);
|
||||||
void clientRenamed(int row, const QString &newName);
|
void clientRenamed(int row, const QString &newName);
|
||||||
void clientRevoked(int row);
|
void clientRevoked(int row);
|
||||||
void adminConfigRevoked(int serverIndex, DockerContainer container);
|
void adminConfigRevoked(const QString &serverId, DockerContainer container);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
ErrorCode updateClients(int serverIndex, const DockerContainer container);
|
ErrorCode updateClients(const QString &serverId, const DockerContainer container);
|
||||||
ErrorCode appendClient(int serverIndex, const QString &clientId, const QString &clientName, const DockerContainer container);
|
ErrorCode appendClient(const QString &serverId, const QString &clientId, const QString &clientName, const DockerContainer container);
|
||||||
ErrorCode renameClient(int serverIndex, const int row, const QString &userName, const DockerContainer container, bool addTimeStamp = false);
|
ErrorCode renameClient(const QString &serverId, const int row, const QString &userName, const DockerContainer container, bool addTimeStamp = false);
|
||||||
ErrorCode revokeClient(int serverIndex, const int index, const DockerContainer container);
|
ErrorCode revokeClient(const QString &serverId, const int index, const DockerContainer container);
|
||||||
ErrorCode revokeClient(int serverIndex, const ContainerConfig &containerConfig, const DockerContainer container);
|
ErrorCode revokeClient(const QString &serverId, const ContainerConfig &containerConfig, const DockerContainer container);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isClientExists(const QString &clientId, const QJsonArray &clientsTable);
|
bool isClientExists(const QString &clientId, const QJsonArray &clientsTable);
|
||||||
int clientIndexById(const QString &clientId, const QJsonArray &clientsTable);
|
int clientIndexById(const QString &clientId, const QJsonArray &clientsTable);
|
||||||
void migration(const QByteArray &clientsTableString, QJsonArray &clientsTable);
|
void migration(const QByteArray &clientsTableString, QJsonArray &clientsTable);
|
||||||
|
|
||||||
ErrorCode revokeOpenVpn(const int row, const DockerContainer container, const ServerCredentials &credentials, const int serverIndex,
|
ErrorCode revokeOpenVpn(const int row, const DockerContainer container, const ServerCredentials &credentials,
|
||||||
SshSession* sshSession, QJsonArray &clientsTable);
|
SshSession* sshSession, QJsonArray &clientsTable);
|
||||||
ErrorCode revokeWireGuard(const int row, const DockerContainer container, const ServerCredentials &credentials,
|
ErrorCode revokeWireGuard(const int row, const DockerContainer container, const ServerCredentials &credentials,
|
||||||
SshSession* sshSession, QJsonArray &clientsTable);
|
SshSession* sshSession, QJsonArray &clientsTable);
|
||||||
@@ -73,4 +73,3 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif // USERSCONTROLLER_H
|
#endif // USERSCONTROLLER_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,81 +1,268 @@
|
|||||||
#include "serversController.h"
|
#include "serversController.h"
|
||||||
#include "core/utils/networkUtilities.h"
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/utils/api/apiEnums.h"
|
|
||||||
#include "core/utils/constants/apiKeys.h"
|
|
||||||
#include "core/utils/constants/apiConstants.h"
|
|
||||||
#include "core/utils/protocolEnum.h"
|
#include "core/utils/protocolEnum.h"
|
||||||
#include "core/protocols/protocolUtils.h"
|
#include "core/protocols/protocolUtils.h"
|
||||||
#include "core/utils/constants/configKeys.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/containerConfig.h"
|
||||||
|
|
||||||
|
#include "core/models/serverDescription.h"
|
||||||
|
|
||||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||||
#include <AmneziaVPN-Swift.h>
|
#include <AmneziaVPN-Swift.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
ServersController::ServersController(SecureServersRepository* serversRepository,
|
ServersController::ServersController(SecureServersRepository *serversRepository,
|
||||||
SecureAppSettingsRepository* appSettingsRepository,
|
SecureAppSettingsRepository *appSettingsRepository, QObject *parent)
|
||||||
QObject *parent)
|
|
||||||
: QObject(parent), m_serversRepository(serversRepository), m_appSettingsRepository(appSettingsRepository)
|
: QObject(parent), m_serversRepository(serversRepository), m_appSettingsRepository(appSettingsRepository)
|
||||||
{
|
{
|
||||||
recomputeGatewayStacks();
|
ensureDefaultServerValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersController::addServer(const ServerConfig &server)
|
void ServersController::ensureDefaultServerValid()
|
||||||
{
|
{
|
||||||
m_serversRepository->addServer(server);
|
if (!getServersCount()) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
void ServersController::editServer(int index, const ServerConfig &server)
|
|
||||||
{
|
const QString defaultId = getDefaultServerId();
|
||||||
m_serversRepository->editServer(index, server);
|
if (!defaultId.isEmpty() && indexOfServerId(defaultId) >= 0) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
void ServersController::removeServer(int index)
|
|
||||||
{
|
const QString firstId = getServerId(0);
|
||||||
m_serversRepository->removeServer(index);
|
if (!firstId.isEmpty()) {
|
||||||
}
|
setDefaultServer(firstId);
|
||||||
|
|
||||||
void ServersController::setDefaultServerIndex(int index)
|
|
||||||
{
|
|
||||||
m_serversRepository->setDefaultServer(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServersController::setDefaultContainer(int serverIndex, DockerContainer container)
|
|
||||||
{
|
|
||||||
m_serversRepository->setDefaultContainer(serverIndex, container);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServersController::updateContainerConfig(int serverIndex, DockerContainer container, const ContainerConfig &config)
|
|
||||||
{
|
|
||||||
m_serversRepository->setContainerConfig(serverIndex, container, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServersController::clearCachedProfile(int serverIndex, DockerContainer container)
|
|
||||||
{
|
|
||||||
m_serversRepository->clearLastConnectionConfig(serverIndex, container);
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray ServersController::getServersArray() const
|
|
||||||
{
|
|
||||||
QJsonArray result;
|
|
||||||
QVector<ServerConfig> servers = m_serversRepository->servers();
|
|
||||||
for (const ServerConfig& server : servers) {
|
|
||||||
result.append(server.toJson());
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<ServerConfig> ServersController::getServers() const
|
bool ServersController::renameServer(const QString &serverId, const QString &name)
|
||||||
{
|
{
|
||||||
return m_serversRepository->servers();
|
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
|
||||||
|
switch (kind) {
|
||||||
|
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
|
||||||
|
auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!cfg.has_value()) return false;
|
||||||
|
cfg->description = name;
|
||||||
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::SelfHostedUser: {
|
||||||
|
auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
|
||||||
|
if (!cfg.has_value()) return false;
|
||||||
|
cfg->description = name;
|
||||||
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Native: {
|
||||||
|
auto cfg = m_serversRepository->nativeConfig(serverId);
|
||||||
|
if (!cfg.has_value()) return false;
|
||||||
|
cfg->description = name;
|
||||||
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
||||||
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
||||||
|
auto cfg = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!cfg.has_value()) return false;
|
||||||
|
cfg->name = name;
|
||||||
|
cfg->nameOverriddenByUser = true;
|
||||||
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaFreeV2:
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContainerConfig ServersController::getContainerConfig(int serverIndex, DockerContainer container) const
|
void ServersController::removeServer(const QString &serverId)
|
||||||
{
|
{
|
||||||
return m_serversRepository->containerConfig(serverIndex, container);
|
m_serversRepository->removeServer(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServersController::setDefaultServer(const QString &serverId)
|
||||||
|
{
|
||||||
|
m_serversRepository->setDefaultServer(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServersController::setDefaultContainer(const QString &serverId, DockerContainer container)
|
||||||
|
{
|
||||||
|
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
|
||||||
|
switch (kind) {
|
||||||
|
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
|
||||||
|
auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (!cfg.has_value()) return;
|
||||||
|
cfg->defaultContainer = container;
|
||||||
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::SelfHostedUser: {
|
||||||
|
auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
|
||||||
|
if (!cfg.has_value()) return;
|
||||||
|
cfg->defaultContainer = container;
|
||||||
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Native: {
|
||||||
|
auto cfg = m_serversRepository->nativeConfig(serverId);
|
||||||
|
if (!cfg.has_value()) return;
|
||||||
|
cfg->defaultContainer = container;
|
||||||
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
||||||
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
||||||
|
auto cfg = m_serversRepository->apiV2Config(serverId);
|
||||||
|
if (!cfg.has_value()) return;
|
||||||
|
cfg->defaultContainer = container;
|
||||||
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaFreeV2:
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<ServerDescription> ServersController::buildServerDescriptions(bool isAmneziaDnsEnabled) const
|
||||||
|
{
|
||||||
|
QVector<ServerDescription> out;
|
||||||
|
const QVector<QString> ids = m_serversRepository->orderedServerIds();
|
||||||
|
out.reserve(ids.size());
|
||||||
|
|
||||||
|
for (const QString &id : ids) {
|
||||||
|
ServerDescription d;
|
||||||
|
using Kind = serverConfigUtils::ConfigType;
|
||||||
|
const Kind kind = m_serversRepository->serverKind(id);
|
||||||
|
switch (kind) {
|
||||||
|
case Kind::SelfHostedAdmin: {
|
||||||
|
const auto cfg = m_serversRepository->selfHostedAdminConfig(id);
|
||||||
|
if (!cfg) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Kind::SelfHostedUser: {
|
||||||
|
const auto cfg = m_serversRepository->selfHostedUserConfig(id);
|
||||||
|
if (!cfg) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Kind::Native: {
|
||||||
|
const auto cfg = m_serversRepository->nativeConfig(id);
|
||||||
|
if (!cfg) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Kind::AmneziaPremiumV2:
|
||||||
|
case Kind::AmneziaFreeV3:
|
||||||
|
case Kind::ExternalPremium: {
|
||||||
|
const auto cfg = m_serversRepository->apiV2Config(id);
|
||||||
|
if (!cfg) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Kind::AmneziaPremiumV1:
|
||||||
|
case Kind::AmneziaFreeV2: {
|
||||||
|
const auto cfg = m_serversRepository->legacyApiConfig(id);
|
||||||
|
if (!cfg) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Kind::Invalid:
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.serverId = id;
|
||||||
|
out.append(d);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<DockerContainer, ContainerConfig> ServersController::getServerContainersMap(const QString &serverId) const
|
||||||
|
{
|
||||||
|
switch (m_serversRepository->serverKind(serverId)) {
|
||||||
|
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
|
||||||
|
const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::SelfHostedUser: {
|
||||||
|
const auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Native: {
|
||||||
|
const auto cfg = m_serversRepository->nativeConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
||||||
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
||||||
|
const auto cfg = m_serversRepository->apiV2Config(serverId);
|
||||||
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaFreeV2: {
|
||||||
|
const auto cfg = m_serversRepository->legacyApiConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DockerContainer ServersController::getDefaultContainer(const QString &serverId) const
|
||||||
|
{
|
||||||
|
switch (m_serversRepository->serverKind(serverId)) {
|
||||||
|
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
|
||||||
|
const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::SelfHostedUser: {
|
||||||
|
const auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Native: {
|
||||||
|
const auto cfg = m_serversRepository->nativeConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
||||||
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
||||||
|
const auto cfg = m_serversRepository->apiV2Config(serverId);
|
||||||
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
|
||||||
|
case serverConfigUtils::ConfigType::AmneziaFreeV2: {
|
||||||
|
const auto cfg = m_serversRepository->legacyApiConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default:
|
||||||
|
return DockerContainer::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContainerConfig ServersController::getContainerConfig(const QString &serverId, DockerContainer container) const
|
||||||
|
{
|
||||||
|
return getServerContainersMap(serverId).value(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ServersController::getDefaultServerIndex() const
|
int ServersController::getDefaultServerIndex() const
|
||||||
@@ -83,114 +270,131 @@ int ServersController::getDefaultServerIndex() const
|
|||||||
return m_serversRepository->defaultServerIndex();
|
return m_serversRepository->defaultServerIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ServersController::getDefaultServerId() const
|
||||||
|
{
|
||||||
|
return m_serversRepository->defaultServerId();
|
||||||
|
}
|
||||||
|
|
||||||
int ServersController::getServersCount() const
|
int ServersController::getServersCount() const
|
||||||
{
|
{
|
||||||
return m_serversRepository->serversCount();
|
return m_serversRepository->serversCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerConfig ServersController::getServerConfig(int serverIndex) const
|
QString ServersController::getServerId(int serverIndex) const
|
||||||
{
|
{
|
||||||
return m_serversRepository->server(serverIndex);
|
return m_serversRepository->serverIdAt(serverIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerCredentials ServersController::getServerCredentials(int serverIndex) const
|
int ServersController::indexOfServerId(const QString &serverId) const
|
||||||
{
|
{
|
||||||
return m_serversRepository->serverCredentials(serverIndex);
|
return m_serversRepository->indexOfServerId(serverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<QString, QString> ServersController::getDnsPair(int serverIndex, bool isAmneziaDnsEnabled) const
|
QString ServersController::notificationDisplayName(const QString &serverId) const
|
||||||
{
|
{
|
||||||
ServerConfig serverConfig = m_serversRepository->server(serverIndex);
|
if (serverId.isEmpty()) {
|
||||||
return serverConfig.getDnsPair(isAmneziaDnsEnabled,
|
return {};
|
||||||
m_appSettingsRepository->primaryDns(),
|
}
|
||||||
m_appSettingsRepository->secondaryDns());
|
|
||||||
}
|
|
||||||
|
|
||||||
ServersController::GatewayStacksData ServersController::gatewayStacks() const
|
using Kind = serverConfigUtils::ConfigType;
|
||||||
{
|
switch (m_serversRepository->serverKind(serverId)) {
|
||||||
return m_gatewayStacks;
|
case Kind::SelfHostedAdmin: {
|
||||||
}
|
if (const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId)) {
|
||||||
|
if (!cfg->displayName.isEmpty()) {
|
||||||
void ServersController::recomputeGatewayStacks()
|
return cfg->displayName;
|
||||||
{
|
|
||||||
GatewayStacksData computed;
|
|
||||||
bool hasNewTags = false;
|
|
||||||
QVector<ServerConfig> servers = m_serversRepository->servers();
|
|
||||||
|
|
||||||
for (const ServerConfig& serverConfig : servers) {
|
|
||||||
if (serverConfig.isApiV2()) {
|
|
||||||
const ApiV2ServerConfig* apiV2 = serverConfig.as<ApiV2ServerConfig>();
|
|
||||||
if (!apiV2) continue;
|
|
||||||
const QString userCountryCode = apiV2->apiConfig.userCountryCode;
|
|
||||||
const QString serviceType = apiV2->serviceType();
|
|
||||||
|
|
||||||
if (!userCountryCode.isEmpty()) {
|
|
||||||
if (!m_gatewayStacks.userCountryCodes.contains(userCountryCode)) {
|
|
||||||
hasNewTags = true;
|
|
||||||
}
|
|
||||||
computed.userCountryCodes.insert(userCountryCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serviceType.isEmpty()) {
|
|
||||||
if (!m_gatewayStacks.serviceTypes.contains(serviceType)) {
|
|
||||||
hasNewTags = true;
|
|
||||||
}
|
|
||||||
computed.serviceTypes.insert(serviceType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case Kind::SelfHostedUser: {
|
||||||
m_gatewayStacks = std::move(computed);
|
if (const auto cfg = m_serversRepository->selfHostedUserConfig(serverId)) {
|
||||||
if (hasNewTags) {
|
if (!cfg->displayName.isEmpty()) {
|
||||||
emit gatewayStacksExpanded();
|
return cfg->displayName;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServersController::GatewayStacksData::operator==(const GatewayStacksData &other) const
|
|
||||||
{
|
|
||||||
return userCountryCodes == other.userCountryCodes && serviceTypes == other.serviceTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject ServersController::GatewayStacksData::toJson() const
|
|
||||||
{
|
|
||||||
QJsonObject json;
|
|
||||||
|
|
||||||
QJsonArray userCountryCodesArray;
|
|
||||||
for (const QString &code : userCountryCodes) {
|
|
||||||
userCountryCodesArray.append(code);
|
|
||||||
}
|
|
||||||
json[apiDefs::key::userCountryCode] = userCountryCodesArray;
|
|
||||||
|
|
||||||
QJsonArray serviceTypesArray;
|
|
||||||
for (const QString &type : serviceTypes) {
|
|
||||||
serviceTypesArray.append(type);
|
|
||||||
}
|
|
||||||
json[apiDefs::key::serviceType] = serviceTypesArray;
|
|
||||||
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServersController::isServerFromApiAlreadyExists(const QString &userCountryCode, const QString &serviceType, const QString &serviceProtocol) const
|
|
||||||
{
|
|
||||||
QVector<ServerConfig> servers = m_serversRepository->servers();
|
|
||||||
for (const ServerConfig& serverConfig : servers) {
|
|
||||||
if (serverConfig.isApiV2()) {
|
|
||||||
const ApiV2ServerConfig* apiV2 = serverConfig.as<ApiV2ServerConfig>();
|
|
||||||
if (!apiV2) return false;
|
|
||||||
if (apiV2->apiConfig.userCountryCode == userCountryCode
|
|
||||||
&& apiV2->serviceType() == serviceType
|
|
||||||
&& apiV2->serviceProtocol() == serviceProtocol) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Kind::Native: {
|
||||||
|
if (const auto cfg = m_serversRepository->nativeConfig(serverId)) {
|
||||||
|
if (!cfg->displayName.isEmpty()) {
|
||||||
|
return cfg->displayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Kind::AmneziaPremiumV2:
|
||||||
|
case Kind::AmneziaFreeV3:
|
||||||
|
case Kind::ExternalPremium: {
|
||||||
|
if (const auto cfg = m_serversRepository->apiV2Config(serverId)) {
|
||||||
|
if (!cfg->displayName.isEmpty()) {
|
||||||
|
return cfg->displayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Kind::AmneziaPremiumV1:
|
||||||
|
case Kind::AmneziaFreeV2: {
|
||||||
|
if (const auto cfg = m_serversRepository->legacyApiConfig(serverId)) {
|
||||||
|
if (!cfg->displayName.isEmpty()) {
|
||||||
|
return cfg->displayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int idx = indexOfServerId(serverId);
|
||||||
|
if (idx >= 0) {
|
||||||
|
return QString::number(idx + 1);
|
||||||
|
}
|
||||||
|
return serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ApiV2ServerConfig> ServersController::apiV2Config(const QString &serverId) const
|
||||||
|
{
|
||||||
|
return m_serversRepository->apiV2Config(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<SelfHostedAdminServerConfig> ServersController::selfHostedAdminConfig(const QString &serverId) const
|
||||||
|
{
|
||||||
|
return m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerCredentials ServersController::getServerCredentials(const QString &serverId) const
|
||||||
|
{
|
||||||
|
const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
if (cfg.has_value()) {
|
||||||
|
const ServerCredentials creds = cfg->credentials();
|
||||||
|
if (creds.isValid()) {
|
||||||
|
return creds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ServerCredentials {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ServersController::isServerFromApiAlreadyExists(const QString &userCountryCode, const QString &serviceType,
|
||||||
|
const QString &serviceProtocol) const
|
||||||
|
{
|
||||||
|
const QVector<QString> ids = m_serversRepository->orderedServerIds();
|
||||||
|
for (const QString &id : ids) {
|
||||||
|
const auto apiV2 = m_serversRepository->apiV2Config(id);
|
||||||
|
if (!apiV2.has_value()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (apiV2->apiConfig.userCountryCode == userCountryCode && apiV2->serviceType() == serviceType
|
||||||
|
&& apiV2->serviceProtocol() == serviceProtocol) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ServersController::hasInstalledContainers(int serverIndex) const
|
bool ServersController::hasInstalledContainers(const QString &serverId) const
|
||||||
{
|
{
|
||||||
ServerConfig serverConfig = m_serversRepository->server(serverIndex);
|
const QMap<DockerContainer, ContainerConfig> containers = getServerContainersMap(serverId);
|
||||||
QMap<DockerContainer, ContainerConfig> containers = serverConfig.containers();
|
|
||||||
for (auto it = containers.begin(); it != containers.end(); ++it) {
|
for (auto it = containers.begin(); it != containers.end(); ++it) {
|
||||||
DockerContainer container = it.key();
|
DockerContainer container = it.key();
|
||||||
if (ContainerUtils::containerService(container) == ServiceType::Vpn) {
|
if (ContainerUtils::containerService(container) == ServiceType::Vpn) {
|
||||||
@@ -203,3 +407,8 @@ bool ServersController::hasInstalledContainers(int serverIndex) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ServersController::isLegacyApiV1Server(const QString &serverId) const
|
||||||
|
{
|
||||||
|
return !serverId.isEmpty()
|
||||||
|
&& serverConfigUtils::isLegacyApiSubscription(m_serversRepository->serverKind(serverId));
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#ifndef SERVERSCONTROLLER_H
|
#ifndef SERVERSCONTROLLER_H
|
||||||
#define SERVERSCONTROLLER_H
|
#define SERVERSCONTROLLER_H
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QSet>
|
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
|
||||||
@@ -17,34 +17,18 @@
|
|||||||
#include "core/utils/commonStructs.h"
|
#include "core/utils/commonStructs.h"
|
||||||
#include "core/repositories/secureServersRepository.h"
|
#include "core/repositories/secureServersRepository.h"
|
||||||
#include "core/repositories/secureAppSettingsRepository.h"
|
#include "core/repositories/secureAppSettingsRepository.h"
|
||||||
#include "core/models/serverConfig.h"
|
|
||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
|
#include "core/models/serverDescription.h"
|
||||||
|
|
||||||
class SshSession;
|
class SshSession;
|
||||||
class InstallController;
|
class InstallController;
|
||||||
|
|
||||||
using namespace amnezia;
|
using namespace amnezia;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Core business logic controller for server operations
|
|
||||||
*
|
|
||||||
* This controller contains pure business logic for managing servers.
|
|
||||||
*/
|
|
||||||
class ServersController : public QObject
|
class ServersController : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
|
||||||
struct GatewayStacksData
|
|
||||||
{
|
|
||||||
QSet<QString> userCountryCodes;
|
|
||||||
QSet<QString> serviceTypes;
|
|
||||||
|
|
||||||
bool isEmpty() const { return userCountryCodes.isEmpty() && serviceTypes.isEmpty(); }
|
|
||||||
bool operator==(const GatewayStacksData &other) const;
|
|
||||||
QJsonObject toJson() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ServersController(SecureServersRepository* serversRepository,
|
explicit ServersController(SecureServersRepository* serversRepository,
|
||||||
SecureAppSettingsRepository* appSettingsRepository = nullptr,
|
SecureAppSettingsRepository* appSettingsRepository = nullptr,
|
||||||
@@ -52,44 +36,38 @@ public:
|
|||||||
~ServersController() = default;
|
~ServersController() = default;
|
||||||
|
|
||||||
// Server management
|
// Server management
|
||||||
void addServer(const ServerConfig &server);
|
bool renameServer(const QString &serverId, const QString &name);
|
||||||
void editServer(int index, const ServerConfig &server);
|
void removeServer(const QString &serverId);
|
||||||
void removeServer(int index);
|
void setDefaultServer(const QString &serverId);
|
||||||
void setDefaultServerIndex(int index);
|
|
||||||
|
|
||||||
// Container management
|
// Container management
|
||||||
void setDefaultContainer(int serverIndex, DockerContainer container);
|
void setDefaultContainer(const QString &serverId, DockerContainer container);
|
||||||
void updateContainerConfig(int serverIndex, DockerContainer container, const ContainerConfig &config);
|
|
||||||
|
|
||||||
// Cache management
|
|
||||||
void clearCachedProfile(int serverIndex, DockerContainer container);
|
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
QJsonArray getServersArray() const;
|
QVector<ServerDescription> buildServerDescriptions(bool isAmneziaDnsEnabled) const;
|
||||||
QVector<ServerConfig> getServers() const;
|
|
||||||
int getDefaultServerIndex() const;
|
int getDefaultServerIndex() const;
|
||||||
|
QString getDefaultServerId() const;
|
||||||
int getServersCount() const;
|
int getServersCount() const;
|
||||||
ServerConfig getServerConfig(int serverIndex) const;
|
QString getServerId(int serverIndex) const;
|
||||||
ServerCredentials getServerCredentials(int serverIndex) const;
|
int indexOfServerId(const QString &serverId) const;
|
||||||
ContainerConfig getContainerConfig(int serverIndex, DockerContainer container) const;
|
QString notificationDisplayName(const QString &serverId) const;
|
||||||
QPair<QString, QString> getDnsPair(int serverIndex, bool isAmneziaDnsEnabled) const;
|
std::optional<ApiV2ServerConfig> apiV2Config(const QString &serverId) const;
|
||||||
|
std::optional<SelfHostedAdminServerConfig> selfHostedAdminConfig(const QString &serverId) const;
|
||||||
GatewayStacksData gatewayStacks() const;
|
ServerCredentials getServerCredentials(const QString &serverId) const;
|
||||||
|
QMap<DockerContainer, ContainerConfig> getServerContainersMap(const QString &serverId) const;
|
||||||
|
DockerContainer getDefaultContainer(const QString &serverId) const;
|
||||||
|
ContainerConfig getContainerConfig(const QString &serverId, DockerContainer container) const;
|
||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
bool isServerFromApiAlreadyExists(const QString &userCountryCode, const QString &serviceType, const QString &serviceProtocol) const;
|
bool isServerFromApiAlreadyExists(const QString &userCountryCode, const QString &serviceType, const QString &serviceProtocol) const;
|
||||||
bool hasInstalledContainers(int serverIndex) const;
|
bool hasInstalledContainers(const QString &serverId) const;
|
||||||
|
bool isLegacyApiV1Server(const QString &serverId) const;
|
||||||
signals:
|
|
||||||
void gatewayStacksExpanded();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void recomputeGatewayStacks();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ensureDefaultServerValid();
|
||||||
|
|
||||||
SecureServersRepository* m_serversRepository;
|
SecureServersRepository* m_serversRepository;
|
||||||
SecureAppSettingsRepository* m_appSettingsRepository;
|
SecureAppSettingsRepository* m_appSettingsRepository;
|
||||||
GatewayStacksData m_gatewayStacks;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SERVERSCONTROLLER_H
|
#endif // SERVERSCONTROLLER_H
|
||||||
|
|||||||
@@ -179,12 +179,9 @@ QString SettingsController::getAppVersion() const
|
|||||||
|
|
||||||
void SettingsController::clearSettings()
|
void SettingsController::clearSettings()
|
||||||
{
|
{
|
||||||
int serverCount = m_serversRepository->serversCount();
|
|
||||||
|
|
||||||
m_appSettingsRepository->clearSettings();
|
m_appSettingsRepository->clearSettings();
|
||||||
|
|
||||||
m_serversRepository->setServersArray(QJsonArray());
|
m_serversRepository->clearServers();
|
||||||
m_serversRepository->setDefaultServer(0);
|
|
||||||
|
|
||||||
emit siteSplitTunnelingRouteModeChanged(RouteMode::VpnOnlyForwardSites);
|
emit siteSplitTunnelingRouteModeChanged(RouteMode::VpnOnlyForwardSites);
|
||||||
emit siteSplitTunnelingToggled(false);
|
emit siteSplitTunnelingToggled(false);
|
||||||
|
|||||||
@@ -21,14 +21,14 @@ namespace
|
|||||||
Logger logger("UpdateController");
|
Logger logger("UpdateController");
|
||||||
|
|
||||||
#if defined(Q_OS_WINDOWS)
|
#if defined(Q_OS_WINDOWS)
|
||||||
const QLatin1String kInstallerRemoteFileNamePattern("AmneziaVPN_%1_x64.exe");
|
const QLatin1String kInstallerRemoteFileNamePattern("AmneziaVPN-%1-win64.exe");
|
||||||
const QString kInstallerLocalPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN_installer.exe";
|
const QString kInstallerLocalPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN_installer.exe";
|
||||||
#elif defined(Q_OS_MACOS)
|
#elif defined(Q_OS_MACOS)
|
||||||
const QLatin1String kInstallerRemoteFileNamePattern("AmneziaVPN_%1_macos.pkg");
|
const QLatin1String kInstallerRemoteFileNamePattern("AmneziaVPN-%1-Darwin.pkg");
|
||||||
const QString kInstallerLocalPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN.pkg";
|
const QString kInstallerLocalPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN.pkg";
|
||||||
#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||||
const QLatin1String kInstallerRemoteFileNamePattern("AmneziaVPN_%1_linux_x64.tar");
|
const QLatin1String kInstallerRemoteFileNamePattern("AmneziaVPN-%1-Linux.run");
|
||||||
const QString kInstallerLocalPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN.tar";
|
const QString kInstallerLocalPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN.run";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,36 +346,10 @@ int UpdateController::runMacInstaller(const QString &installerPath)
|
|||||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||||
int UpdateController::runLinuxInstaller(const QString &installerPath)
|
int UpdateController::runLinuxInstaller(const QString &installerPath)
|
||||||
{
|
{
|
||||||
// Create temporary directory for extraction
|
QFile::setPermissions(installerPath, QFile::permissions(installerPath) | QFile::ExeUser);
|
||||||
QTemporaryDir extractDir;
|
|
||||||
extractDir.setAutoRemove(false);
|
|
||||||
if (!extractDir.isValid()) {
|
|
||||||
logger.error() << "Failed to create temporary directory";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
logger.info() << "Temporary directory created:" << extractDir.path();
|
|
||||||
|
|
||||||
// Create script file in the temporary directory
|
|
||||||
QString scriptPath = extractDir.path() + "/installer.sh";
|
|
||||||
QFile scriptFile(scriptPath);
|
|
||||||
if (!scriptFile.open(QIODevice::WriteOnly)) {
|
|
||||||
logger.error() << "Failed to create script file";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get script content from registry
|
|
||||||
QString scriptContent = amnezia::scriptData(amnezia::ClientScriptType::linux_installer);
|
|
||||||
scriptFile.write(scriptContent.toUtf8());
|
|
||||||
scriptFile.close();
|
|
||||||
logger.info() << "Script file created:" << scriptPath;
|
|
||||||
|
|
||||||
// Make script executable
|
|
||||||
QFile::setPermissions(scriptPath, QFile::permissions(scriptPath) | QFile::ExeUser);
|
|
||||||
|
|
||||||
// Start detached process
|
|
||||||
qint64 pid;
|
qint64 pid;
|
||||||
bool success =
|
bool success = QProcess::startDetached(installerPath, QStringList(), QString(), &pid);
|
||||||
QProcess::startDetached("/bin/bash", QStringList() << scriptPath << extractDir.path() << installerPath, extractDir.path(), &pid);
|
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
logger.info() << "Installation process started with PID:" << pid;
|
logger.info() << "Installation process started with PID:" << pid;
|
||||||
@@ -387,5 +361,3 @@ int UpdateController::runLinuxInstaller(const QString &installerPath)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef CONTAINERDIAGNOSTICS_H
|
||||||
|
#define CONTAINERDIAGNOSTICS_H
|
||||||
|
|
||||||
|
namespace amnezia
|
||||||
|
{
|
||||||
|
struct ContainerDiagnostics
|
||||||
|
{
|
||||||
|
bool available = false;
|
||||||
|
bool portReachable = false;
|
||||||
|
|
||||||
|
virtual ~ContainerDiagnostics() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
|
|
||||||
|
#endif // CONTAINERDIAGNOSTICS_H
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef MTPROXYDIAGNOSTICS_H
|
||||||
|
#define MTPROXYDIAGNOSTICS_H
|
||||||
|
|
||||||
|
#include "containerDiagnostics.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace amnezia {
|
||||||
|
struct MtProxyDiagnostics : ContainerDiagnostics {
|
||||||
|
bool upstreamReachable = false;
|
||||||
|
int clientsConnected = -1;
|
||||||
|
QString lastConfigRefresh;
|
||||||
|
QString statsEndpoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
|
|
||||||
|
#endif // MTPROXYDIAGNOSTICS_H
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef TELEMTDIAGNOSTICS_H
|
||||||
|
#define TELEMTDIAGNOSTICS_H
|
||||||
|
|
||||||
|
#include "containerDiagnostics.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace amnezia
|
||||||
|
{
|
||||||
|
struct TelemtDiagnostics : ContainerDiagnostics
|
||||||
|
{
|
||||||
|
bool upstreamReachable = false;
|
||||||
|
int clientsConnected = -1;
|
||||||
|
QString lastConfigRefresh;
|
||||||
|
QString statsEndpoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
|
|
||||||
|
#endif // TELEMTDIAGNOSTICS_H
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
#include "core/models/protocols/xrayProtocolConfig.h"
|
#include "core/models/protocols/xrayProtocolConfig.h"
|
||||||
#include "core/models/protocols/sftpProtocolConfig.h"
|
#include "core/models/protocols/sftpProtocolConfig.h"
|
||||||
#include "core/models/protocols/socks5ProxyProtocolConfig.h"
|
#include "core/models/protocols/socks5ProxyProtocolConfig.h"
|
||||||
|
#include "core/models/protocols/mtProxyProtocolConfig.h"
|
||||||
|
#include "core/models/protocols/telemtProtocolConfig.h"
|
||||||
#include "core/models/protocols/ikev2ProtocolConfig.h"
|
#include "core/models/protocols/ikev2ProtocolConfig.h"
|
||||||
#include "core/models/protocols/torProtocolConfig.h"
|
#include "core/models/protocols/torProtocolConfig.h"
|
||||||
|
|
||||||
@@ -91,6 +93,18 @@ ContainerConfig InstallerBase::createBaseConfig(DockerContainer container, int p
|
|||||||
config.protocolConfig = socks5Config;
|
config.protocolConfig = socks5Config;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Proto::MtProxy: {
|
||||||
|
MtProxyProtocolConfig mtConfig;
|
||||||
|
mtConfig.port = portStr;
|
||||||
|
config.protocolConfig = mtConfig;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Proto::Telemt: {
|
||||||
|
TelemtProtocolConfig telemtConfig;
|
||||||
|
telemtConfig.port = portStr;
|
||||||
|
config.protocolConfig = telemtConfig;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Proto::Ikev2: {
|
case Proto::Ikev2: {
|
||||||
Ikev2ProtocolConfig ikev2Config;
|
Ikev2ProtocolConfig ikev2Config;
|
||||||
config.protocolConfig = ikev2Config;
|
config.protocolConfig = ikev2Config;
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
#include "mtProxyInstaller.h"
|
||||||
|
|
||||||
|
#include "core/utils/containerEnum.h"
|
||||||
|
#include "core/utils/containers/containerUtils.h"
|
||||||
|
#include "core/utils/protocolEnum.h"
|
||||||
|
#include "core/utils/selfhosted/sshSession.h"
|
||||||
|
#include "core/models/containerConfig.h"
|
||||||
|
#include "core/models/protocols/mtProxyProtocolConfig.h"
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
using namespace amnezia;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr QLatin1String kMtProxyClientJsonPath("/data/amnezia-mtproxy-client.json");
|
||||||
|
constexpr QLatin1String kMtProxyClientJsonUploadPath("data/amnezia-mtproxy-client.json");
|
||||||
|
constexpr QLatin1String kMtProxySecretPath("/data/secret");
|
||||||
|
}
|
||||||
|
|
||||||
|
MtProxyInstaller::MtProxyInstaller(QObject *parent)
|
||||||
|
: InstallerBase(parent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode MtProxyInstaller::extractConfigFromContainer(DockerContainer container, const ServerCredentials &credentials,
|
||||||
|
SshSession *sshSession, ContainerConfig &config) {
|
||||||
|
if (container != DockerContainer::MtProxy || !sshSession) {
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
MtProxyProtocolConfig *mt = config.getMtProxyProtocolConfig();
|
||||||
|
if (!mt) {
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode jsonErr = ErrorCode::NoError;
|
||||||
|
const QByteArray jsonRaw =
|
||||||
|
sshSession->getTextFileFromContainer(container, credentials, QString(kMtProxyClientJsonPath), jsonErr);
|
||||||
|
if (jsonErr == ErrorCode::NoError && !jsonRaw.trimmed().isEmpty()) {
|
||||||
|
QJsonParseError parseError;
|
||||||
|
const QJsonDocument doc = QJsonDocument::fromJson(jsonRaw.trimmed(), &parseError);
|
||||||
|
if (parseError.error == QJsonParseError::NoError && doc.isObject()) {
|
||||||
|
QJsonObject merged = mt->toJson();
|
||||||
|
const QJsonObject snap = doc.object();
|
||||||
|
for (auto it = snap.constBegin(); it != snap.constEnd(); ++it) {
|
||||||
|
merged.insert(it.key(), it.value());
|
||||||
|
}
|
||||||
|
*mt = MtProxyProtocolConfig::fromJson(merged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode secretErr = ErrorCode::NoError;
|
||||||
|
const QByteArray secretRaw =
|
||||||
|
sshSession->getTextFileFromContainer(container, credentials, QString(kMtProxySecretPath), secretErr);
|
||||||
|
const QString sec = QString::fromUtf8(secretRaw).trimmed();
|
||||||
|
if (sec.length() == 32) {
|
||||||
|
static const QRegularExpression hex32(QStringLiteral("^[0-9a-fA-F]{32}$"));
|
||||||
|
if (hex32.match(sec).hasMatch()) {
|
||||||
|
mt->secret = sec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode MtProxyInstaller::queryDiagnostics(SshSession &sshSession, const ServerCredentials &credentials,
|
||||||
|
DockerContainer container, int listenPort,
|
||||||
|
MtProxyContainerDiagnostics &out)
|
||||||
|
{
|
||||||
|
out = {};
|
||||||
|
if (container != DockerContainer::MtProxy && container != DockerContainer::Telemt) {
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
}
|
||||||
|
const QString containerName = ContainerUtils::containerToString(container);
|
||||||
|
const QString script =
|
||||||
|
QStringLiteral(
|
||||||
|
"PORT_OK=$(sudo docker exec %1 sh -c 'ss -tlnp 2>/dev/null | grep -q :%2 && echo yes || echo no' 2>/dev/null || echo no); "
|
||||||
|
"TG_OK=$(curl -s --max-time 5 -o /dev/null -w '%%{http_code}' https://core.telegram.org/getProxySecret 2>/dev/null | grep -q '200' && echo yes || echo no); "
|
||||||
|
"CLIENTS=$(sudo docker exec amnezia-mtproxy sh -c 'curl -s --max-time 3 http://localhost:2398/stats 2>/dev/null | grep -o \"total_special_connections:[0-9]*\" | cut -d: -f2' 2>/dev/null); "
|
||||||
|
"CONF_TIME=$(sudo docker exec amnezia-mtproxy sh -c 'stat -c \"%%y\" /data/proxy-multi.conf 2>/dev/null | cut -d. -f1' 2>/dev/null || echo unknown); "
|
||||||
|
"echo \"PORT_OK=${PORT_OK}\"; "
|
||||||
|
"echo \"TG_OK=${TG_OK}\"; "
|
||||||
|
"echo \"CLIENTS=${CLIENTS:-0}\"; "
|
||||||
|
"echo \"CONF_TIME=${CONF_TIME}\"; "
|
||||||
|
"echo \"STATS=http://localhost:2398/stats\";")
|
||||||
|
.arg(containerName)
|
||||||
|
.arg(listenPort);
|
||||||
|
|
||||||
|
QString stdOut;
|
||||||
|
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||||
|
stdOut += data;
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
};
|
||||||
|
const ErrorCode errorCode = sshSession.runScript(credentials, script, cbReadStdOut);
|
||||||
|
if (errorCode != ErrorCode::NoError) {
|
||||||
|
return errorCode;
|
||||||
|
}
|
||||||
|
for (const QString &line : stdOut.split('\n', Qt::SkipEmptyParts)) {
|
||||||
|
if (line.startsWith(QLatin1String("PORT_OK="))) {
|
||||||
|
out.portReachable = line.mid(8).trimmed() == QLatin1String("yes");
|
||||||
|
} else if (line.startsWith(QLatin1String("TG_OK="))) {
|
||||||
|
out.upstreamReachable = line.mid(6).trimmed() == QLatin1String("yes");
|
||||||
|
} else if (line.startsWith(QLatin1String("CLIENTS="))) {
|
||||||
|
out.clientsConnected = line.mid(8).trimmed().toInt();
|
||||||
|
} else if (line.startsWith(QLatin1String("CONF_TIME="))) {
|
||||||
|
out.lastConfigRefresh = line.mid(10).trimmed();
|
||||||
|
} else if (line.startsWith(QLatin1String("STATS="))) {
|
||||||
|
out.statsEndpoint = line.mid(6).trimmed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MtProxyInstaller::uploadClientSettingsSnapshot(SshSession &sshSession, const ServerCredentials &credentials,
|
||||||
|
DockerContainer container, const ContainerConfig &config) {
|
||||||
|
const MtProxyProtocolConfig *mt = config.getMtProxyProtocolConfig();
|
||||||
|
if (!mt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QByteArray payload = QJsonDocument(mt->toJson()).toJson(QJsonDocument::Compact);
|
||||||
|
const ErrorCode err = sshSession.uploadTextFileToContainer(container, credentials, QString::fromUtf8(payload),
|
||||||
|
QString(kMtProxyClientJsonUploadPath));
|
||||||
|
if (err != ErrorCode::NoError) {
|
||||||
|
qWarning() << "MtProxyInstaller::uploadClientSettingsSnapshot failed" << err;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef MTPROXYINSTALLER_H
|
||||||
|
#define MTPROXYINSTALLER_H
|
||||||
|
|
||||||
|
#include "installerBase.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
struct MtProxyContainerDiagnostics {
|
||||||
|
bool portReachable = false;
|
||||||
|
bool upstreamReachable = false;
|
||||||
|
int clientsConnected = -1;
|
||||||
|
QString lastConfigRefresh;
|
||||||
|
QString statsEndpoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MtProxyInstaller : public InstallerBase {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit MtProxyInstaller(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
amnezia::ErrorCode
|
||||||
|
extractConfigFromContainer(amnezia::DockerContainer container, const amnezia::ServerCredentials &credentials,
|
||||||
|
SshSession *sshSession, amnezia::ContainerConfig &config) override;
|
||||||
|
|
||||||
|
static void uploadClientSettingsSnapshot(SshSession &sshSession, const amnezia::ServerCredentials &credentials,
|
||||||
|
amnezia::DockerContainer container,
|
||||||
|
const amnezia::ContainerConfig &config);
|
||||||
|
|
||||||
|
static amnezia::ErrorCode queryDiagnostics(SshSession &sshSession, const amnezia::ServerCredentials &credentials,
|
||||||
|
amnezia::DockerContainer container, int listenPort,
|
||||||
|
MtProxyContainerDiagnostics &out);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MTPROXYINSTALLER_H
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#include "telemtInstaller.h"
|
||||||
|
|
||||||
|
#include "core/utils/containerEnum.h"
|
||||||
|
#include "core/utils/containers/containerUtils.h"
|
||||||
|
#include "core/utils/selfhosted/sshSession.h"
|
||||||
|
#include "core/models/containerConfig.h"
|
||||||
|
#include "core/models/protocols/telemtProtocolConfig.h"
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
using namespace amnezia;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr QLatin1String kTelemtClientJsonPath("/data/amnezia-telemt-client.json");
|
||||||
|
constexpr QLatin1String kTelemtClientJsonUploadPath("data/amnezia-telemt-client.json");
|
||||||
|
constexpr QLatin1String kTelemtSecretPath("/data/secret");
|
||||||
|
}
|
||||||
|
|
||||||
|
TelemtInstaller::TelemtInstaller(QObject *parent) : InstallerBase(parent) {}
|
||||||
|
|
||||||
|
ErrorCode TelemtInstaller::extractConfigFromContainer(DockerContainer container, const ServerCredentials &credentials,
|
||||||
|
SshSession *sshSession, ContainerConfig &config) {
|
||||||
|
if (container != DockerContainer::Telemt || !sshSession) {
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
TelemtProtocolConfig *tc = config.getTelemtProtocolConfig();
|
||||||
|
if (!tc) {
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode jsonErr = ErrorCode::NoError;
|
||||||
|
const QByteArray jsonRaw =
|
||||||
|
sshSession->getTextFileFromContainer(container, credentials, QString(kTelemtClientJsonPath), jsonErr);
|
||||||
|
if (jsonErr == ErrorCode::NoError && !jsonRaw.trimmed().isEmpty()) {
|
||||||
|
QJsonParseError parseError;
|
||||||
|
const QJsonDocument doc = QJsonDocument::fromJson(jsonRaw.trimmed(), &parseError);
|
||||||
|
if (parseError.error == QJsonParseError::NoError && doc.isObject()) {
|
||||||
|
QJsonObject merged = tc->toJson();
|
||||||
|
const QJsonObject snap = doc.object();
|
||||||
|
for (auto it = snap.constBegin(); it != snap.constEnd(); ++it) {
|
||||||
|
merged.insert(it.key(), it.value());
|
||||||
|
}
|
||||||
|
*tc = TelemtProtocolConfig::fromJson(merged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode secretErr = ErrorCode::NoError;
|
||||||
|
const QByteArray secretRaw =
|
||||||
|
sshSession->getTextFileFromContainer(container, credentials, QString(kTelemtSecretPath), secretErr);
|
||||||
|
const QString sec = QString::fromUtf8(secretRaw).trimmed();
|
||||||
|
if (sec.length() == 32) {
|
||||||
|
static const QRegularExpression hex32(QStringLiteral("^[0-9a-fA-F]{32}$"));
|
||||||
|
if (hex32.match(sec).hasMatch()) {
|
||||||
|
tc->secret = sec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TelemtInstaller::uploadClientSettingsSnapshot(SshSession &sshSession, const ServerCredentials &credentials,
|
||||||
|
DockerContainer container, const ContainerConfig &config) {
|
||||||
|
const TelemtProtocolConfig *tc = config.getTelemtProtocolConfig();
|
||||||
|
if (!tc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QByteArray payload = QJsonDocument(tc->toJson()).toJson(QJsonDocument::Compact);
|
||||||
|
const ErrorCode err = sshSession.uploadTextFileToContainer(container, credentials, QString::fromUtf8(payload),
|
||||||
|
QString(kTelemtClientJsonUploadPath));
|
||||||
|
if (err != ErrorCode::NoError) {
|
||||||
|
qWarning() << "TelemtInstaller::uploadClientSettingsSnapshot failed" << err;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef TELEMTINSTALLER_H
|
||||||
|
#define TELEMTINSTALLER_H
|
||||||
|
|
||||||
|
#include "installerBase.h"
|
||||||
|
|
||||||
|
class TelemtInstaller : public InstallerBase {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit TelemtInstaller(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
amnezia::ErrorCode
|
||||||
|
extractConfigFromContainer(amnezia::DockerContainer container, const amnezia::ServerCredentials &credentials,
|
||||||
|
SshSession *sshSession, amnezia::ContainerConfig &config) override;
|
||||||
|
|
||||||
|
static void uploadClientSettingsSnapshot(SshSession &sshSession, const amnezia::ServerCredentials &credentials,
|
||||||
|
amnezia::DockerContainer container,
|
||||||
|
const amnezia::ContainerConfig &config);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TELEMTINSTALLER_H
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
#include "core/utils/api/apiEnums.h"
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/utils/constants/apiKeys.h"
|
#include "core/utils/constants/apiKeys.h"
|
||||||
#include "core/utils/constants/apiConstants.h"
|
#include "core/utils/constants/apiConstants.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,140 +0,0 @@
|
|||||||
#include "apiV1ServerConfig.h"
|
|
||||||
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
|
|
||||||
#include "core/utils/containerEnum.h"
|
|
||||||
#include "core/utils/containers/containerUtils.h"
|
|
||||||
#include "core/utils/protocolEnum.h"
|
|
||||||
#include "core/utils/protocolEnum.h"
|
|
||||||
#include "core/protocols/protocolUtils.h"
|
|
||||||
#include "core/utils/constants/apiKeys.h"
|
|
||||||
#include "core/utils/constants/configKeys.h"
|
|
||||||
#include "core/utils/constants/protocolConstants.h"
|
|
||||||
#include "core/utils/api/apiUtils.h"
|
|
||||||
|
|
||||||
namespace amnezia
|
|
||||||
{
|
|
||||||
|
|
||||||
using namespace ContainerEnumNS;
|
|
||||||
|
|
||||||
bool ApiV1ServerConfig::isPremium() const
|
|
||||||
{
|
|
||||||
constexpr QLatin1String premiumV1Endpoint(PREM_V1_ENDPOINT);
|
|
||||||
return apiEndpoint.contains(premiumV1Endpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ApiV1ServerConfig::isFree() const
|
|
||||||
{
|
|
||||||
constexpr QLatin1String freeV2Endpoint(FREE_V2_ENDPOINT);
|
|
||||||
return apiEndpoint.contains(freeV2Endpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ApiV1ServerConfig::vpnKey() const
|
|
||||||
{
|
|
||||||
QJsonObject json = toJson();
|
|
||||||
return apiUtils::getPremiumV1VpnKey(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ApiV1ServerConfig::hasContainers() const
|
|
||||||
{
|
|
||||||
return !containers.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
ContainerConfig ApiV1ServerConfig::containerConfig(DockerContainer container) const
|
|
||||||
{
|
|
||||||
if (!containers.contains(container)) {
|
|
||||||
return ContainerConfig{};
|
|
||||||
}
|
|
||||||
return containers.value(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject ApiV1ServerConfig::toJson() const
|
|
||||||
{
|
|
||||||
QJsonObject obj;
|
|
||||||
|
|
||||||
if (!name.isEmpty()) {
|
|
||||||
obj[configKey::name] = name;
|
|
||||||
}
|
|
||||||
if (!description.isEmpty()) {
|
|
||||||
obj[configKey::description] = description;
|
|
||||||
}
|
|
||||||
if (!protocol.isEmpty()) {
|
|
||||||
obj[apiDefs::key::protocol] = protocol;
|
|
||||||
}
|
|
||||||
if (!apiEndpoint.isEmpty()) {
|
|
||||||
obj[apiDefs::key::apiEndpoint] = apiEndpoint;
|
|
||||||
}
|
|
||||||
if (!apiKey.isEmpty()) {
|
|
||||||
obj[apiDefs::key::apiKey] = apiKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj[configKey::configVersion] = configVersion;
|
|
||||||
|
|
||||||
if (!hostName.isEmpty()) {
|
|
||||||
obj[configKey::hostName] = hostName;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray containersArray;
|
|
||||||
for (auto it = containers.begin(); it != containers.end(); ++it) {
|
|
||||||
QJsonObject containerObj = it.value().toJson();
|
|
||||||
containersArray.append(containerObj);
|
|
||||||
}
|
|
||||||
if (!containersArray.isEmpty()) {
|
|
||||||
obj[configKey::containers] = containersArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultContainer != DockerContainer::None) {
|
|
||||||
obj[configKey::defaultContainer] = ContainerUtils::containerToString(defaultContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dns1.isEmpty()) {
|
|
||||||
obj[configKey::dns1] = dns1;
|
|
||||||
}
|
|
||||||
if (!dns2.isEmpty()) {
|
|
||||||
obj[configKey::dns2] = dns2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crc > 0) {
|
|
||||||
obj[configKey::crc] = crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
ApiV1ServerConfig ApiV1ServerConfig::fromJson(const QJsonObject& json)
|
|
||||||
{
|
|
||||||
ApiV1ServerConfig config;
|
|
||||||
|
|
||||||
config.name = json.value(configKey::name).toString();
|
|
||||||
config.description = json.value(configKey::description).toString();
|
|
||||||
config.protocol = json.value(apiDefs::key::protocol).toString();
|
|
||||||
config.apiEndpoint = json.value(apiDefs::key::apiEndpoint).toString();
|
|
||||||
config.apiKey = json.value(apiDefs::key::apiKey).toString();
|
|
||||||
config.configVersion = json.value(configKey::configVersion).toInt(1);
|
|
||||||
config.hostName = json.value(configKey::hostName).toString();
|
|
||||||
|
|
||||||
QJsonArray containersArray = json.value(configKey::containers).toArray();
|
|
||||||
for (const QJsonValue& val : containersArray) {
|
|
||||||
QJsonObject containerObj = val.toObject();
|
|
||||||
ContainerConfig containerConfig = ContainerConfig::fromJson(containerObj);
|
|
||||||
|
|
||||||
QString containerStr = containerObj.value(configKey::container).toString();
|
|
||||||
DockerContainer container = ContainerUtils::containerFromString(containerStr);
|
|
||||||
|
|
||||||
config.containers.insert(container, containerConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString defaultContainerStr = json.value(configKey::defaultContainer).toString();
|
|
||||||
config.defaultContainer = ContainerUtils::containerFromString(defaultContainerStr);
|
|
||||||
|
|
||||||
config.dns1 = json.value(configKey::dns1).toString();
|
|
||||||
config.dns2 = json.value(configKey::dns2).toString();
|
|
||||||
|
|
||||||
config.crc = json.value(configKey::crc).toInt(0);
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace amnezia
|
|
||||||
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#ifndef APIV1SERVERCONFIG_H
|
|
||||||
#define APIV1SERVERCONFIG_H
|
|
||||||
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
#include "core/utils/containerEnum.h"
|
|
||||||
#include "core/utils/containers/containerUtils.h"
|
|
||||||
#include "core/utils/protocolEnum.h"
|
|
||||||
#include "core/models/containerConfig.h"
|
|
||||||
#include "core/utils/api/apiEnums.h"
|
|
||||||
#include "core/utils/constants/apiKeys.h"
|
|
||||||
#include "core/utils/constants/apiConstants.h"
|
|
||||||
|
|
||||||
namespace amnezia
|
|
||||||
{
|
|
||||||
|
|
||||||
using namespace ContainerEnumNS;
|
|
||||||
|
|
||||||
struct ApiV1ServerConfig {
|
|
||||||
QString description;
|
|
||||||
QString hostName;
|
|
||||||
QMap<DockerContainer, ContainerConfig> containers;
|
|
||||||
DockerContainer defaultContainer;
|
|
||||||
QString dns1;
|
|
||||||
QString dns2;
|
|
||||||
|
|
||||||
QString name;
|
|
||||||
QString protocol;
|
|
||||||
QString apiEndpoint;
|
|
||||||
QString apiKey;
|
|
||||||
int crc;
|
|
||||||
int configVersion;
|
|
||||||
|
|
||||||
bool isPremium() const;
|
|
||||||
bool isFree() const;
|
|
||||||
QString vpnKey() const;
|
|
||||||
bool hasContainers() const;
|
|
||||||
ContainerConfig containerConfig(DockerContainer container) const;
|
|
||||||
QJsonObject toJson() const;
|
|
||||||
static ApiV1ServerConfig fromJson(const QJsonObject& json);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace amnezia
|
|
||||||
|
|
||||||
#endif // APIV1SERVERCONFIG_H
|
|
||||||
|
|
||||||
@@ -80,6 +80,9 @@ QJsonObject ApiV2ServerConfig::toJson() const
|
|||||||
if (!description.isEmpty()) {
|
if (!description.isEmpty()) {
|
||||||
obj[configKey::description] = description;
|
obj[configKey::description] = description;
|
||||||
}
|
}
|
||||||
|
if (!displayName.isEmpty()) {
|
||||||
|
obj[configKey::displayName] = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
obj[configKey::configVersion] = configVersion;
|
obj[configKey::configVersion] = configVersion;
|
||||||
|
|
||||||
@@ -131,6 +134,7 @@ ApiV2ServerConfig ApiV2ServerConfig::fromJson(const QJsonObject& json)
|
|||||||
config.name = json.value(configKey::name).toString();
|
config.name = json.value(configKey::name).toString();
|
||||||
config.nameOverriddenByUser = json.value(configKey::nameOverriddenByUser).toBool(false);
|
config.nameOverriddenByUser = json.value(configKey::nameOverriddenByUser).toBool(false);
|
||||||
config.description = json.value(configKey::description).toString();
|
config.description = json.value(configKey::description).toString();
|
||||||
|
config.displayName = json.value(configKey::displayName).toString();
|
||||||
config.configVersion = json.value(configKey::configVersion).toInt(2);
|
config.configVersion = json.value(configKey::configVersion).toInt(2);
|
||||||
config.hostName = json.value(configKey::hostName).toString();
|
config.hostName = json.value(configKey::hostName).toString();
|
||||||
|
|
||||||
@@ -163,6 +167,10 @@ ApiV2ServerConfig ApiV2ServerConfig::fromJson(const QJsonObject& json)
|
|||||||
config.authData = AuthData::fromJson(authDataObj);
|
config.authData = AuthData::fromJson(authDataObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.displayName.isEmpty()) {
|
||||||
|
config.displayName = config.name.isEmpty() ? config.description : config.name;
|
||||||
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
#include "core/models/api/apiConfig.h"
|
#include "core/models/api/apiConfig.h"
|
||||||
#include "core/models/api/authData.h"
|
#include "core/models/api/authData.h"
|
||||||
#include "core/utils/api/apiEnums.h"
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/utils/constants/apiKeys.h"
|
#include "core/utils/constants/apiKeys.h"
|
||||||
#include "core/utils/constants/apiConstants.h"
|
#include "core/utils/constants/apiConstants.h"
|
||||||
|
|
||||||
@@ -21,6 +21,7 @@ using namespace ContainerEnumNS;
|
|||||||
|
|
||||||
struct ApiV2ServerConfig {
|
struct ApiV2ServerConfig {
|
||||||
QString description;
|
QString description;
|
||||||
|
QString displayName;
|
||||||
QString hostName;
|
QString hostName;
|
||||||
QMap<DockerContainer, ContainerConfig> containers;
|
QMap<DockerContainer, ContainerConfig> containers;
|
||||||
DockerContainer defaultContainer;
|
DockerContainer defaultContainer;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include "core/utils/api/apiEnums.h"
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/utils/constants/apiKeys.h"
|
#include "core/utils/constants/apiKeys.h"
|
||||||
#include "core/utils/constants/apiConstants.h"
|
#include "core/utils/constants/apiConstants.h"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include "legacyApiServerConfig.h"
|
||||||
|
|
||||||
|
#include "core/utils/constants/apiKeys.h"
|
||||||
|
#include "core/utils/constants/configKeys.h"
|
||||||
|
|
||||||
|
namespace amnezia
|
||||||
|
{
|
||||||
|
|
||||||
|
bool LegacyApiServerConfig::hasContainers() const
|
||||||
|
{
|
||||||
|
return !containers.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContainerConfig LegacyApiServerConfig::containerConfig(DockerContainer container) const
|
||||||
|
{
|
||||||
|
if (!containers.contains(container)) {
|
||||||
|
return ContainerConfig{};
|
||||||
|
}
|
||||||
|
return containers.value(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
LegacyApiServerConfig LegacyApiServerConfig::fromJson(const QJsonObject &json)
|
||||||
|
{
|
||||||
|
LegacyApiServerConfig config;
|
||||||
|
|
||||||
|
config.name = json.value(configKey::name).toString();
|
||||||
|
config.description = json.value(configKey::description).toString();
|
||||||
|
config.displayName = json.value(configKey::displayName).toString();
|
||||||
|
config.hostName = json.value(configKey::hostName).toString();
|
||||||
|
|
||||||
|
config.crc = json.value(configKey::crc).toInt(0);
|
||||||
|
|
||||||
|
config.configVersion = json.value(configKey::configVersion).toInt(1);
|
||||||
|
config.apiEndpoint = json.value(apiDefs::key::apiEndpoint).toString();
|
||||||
|
|
||||||
|
if (config.displayName.isEmpty()) {
|
||||||
|
config.displayName = config.name.isEmpty() ? config.description : config.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef LEGACYAPISERVERCONFIG_H
|
||||||
|
#define LEGACYAPISERVERCONFIG_H
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
#include "core/utils/containerEnum.h"
|
||||||
|
#include "core/utils/protocolEnum.h"
|
||||||
|
#include "core/models/containerConfig.h"
|
||||||
|
|
||||||
|
namespace amnezia
|
||||||
|
{
|
||||||
|
|
||||||
|
using namespace ContainerEnumNS;
|
||||||
|
|
||||||
|
struct LegacyApiServerConfig {
|
||||||
|
QString description;
|
||||||
|
QString displayName;
|
||||||
|
QString hostName;
|
||||||
|
QMap<DockerContainer, ContainerConfig> containers;
|
||||||
|
DockerContainer defaultContainer = DockerContainer::None;
|
||||||
|
QString dns1;
|
||||||
|
QString dns2;
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
int crc = 0;
|
||||||
|
|
||||||
|
int configVersion = 0;
|
||||||
|
QString apiEndpoint;
|
||||||
|
|
||||||
|
bool hasContainers() const;
|
||||||
|
ContainerConfig containerConfig(DockerContainer container) const;
|
||||||
|
static LegacyApiServerConfig fromJson(const QJsonObject &json);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
|
|
||||||
|
#endif // LEGACYAPISERVERCONFIG_H
|
||||||
@@ -113,6 +113,26 @@ const Socks5ProxyProtocolConfig* ContainerConfig::getSocks5ProxyProtocolConfig()
|
|||||||
return protocolConfig.as<Socks5ProxyProtocolConfig>();
|
return protocolConfig.as<Socks5ProxyProtocolConfig>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MtProxyProtocolConfig* ContainerConfig::getMtProxyProtocolConfig()
|
||||||
|
{
|
||||||
|
return protocolConfig.as<MtProxyProtocolConfig>();
|
||||||
|
}
|
||||||
|
|
||||||
|
const MtProxyProtocolConfig* ContainerConfig::getMtProxyProtocolConfig() const
|
||||||
|
{
|
||||||
|
return protocolConfig.as<MtProxyProtocolConfig>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TelemtProtocolConfig* ContainerConfig::getTelemtProtocolConfig()
|
||||||
|
{
|
||||||
|
return protocolConfig.as<TelemtProtocolConfig>();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TelemtProtocolConfig* ContainerConfig::getTelemtProtocolConfig() const
|
||||||
|
{
|
||||||
|
return protocolConfig.as<TelemtProtocolConfig>();
|
||||||
|
}
|
||||||
|
|
||||||
Ikev2ProtocolConfig* ContainerConfig::getIkev2ProtocolConfig()
|
Ikev2ProtocolConfig* ContainerConfig::getIkev2ProtocolConfig()
|
||||||
{
|
{
|
||||||
return protocolConfig.as<Ikev2ProtocolConfig>();
|
return protocolConfig.as<Ikev2ProtocolConfig>();
|
||||||
|
|||||||
@@ -57,6 +57,12 @@ struct ContainerConfig {
|
|||||||
Socks5ProxyProtocolConfig* getSocks5ProxyProtocolConfig();
|
Socks5ProxyProtocolConfig* getSocks5ProxyProtocolConfig();
|
||||||
const Socks5ProxyProtocolConfig* getSocks5ProxyProtocolConfig() const;
|
const Socks5ProxyProtocolConfig* getSocks5ProxyProtocolConfig() const;
|
||||||
|
|
||||||
|
MtProxyProtocolConfig* getMtProxyProtocolConfig();
|
||||||
|
const MtProxyProtocolConfig* getMtProxyProtocolConfig() const;
|
||||||
|
|
||||||
|
TelemtProtocolConfig* getTelemtProtocolConfig();
|
||||||
|
const TelemtProtocolConfig* getTelemtProtocolConfig() const;
|
||||||
|
|
||||||
Ikev2ProtocolConfig* getIkev2ProtocolConfig();
|
Ikev2ProtocolConfig* getIkev2ProtocolConfig();
|
||||||
const Ikev2ProtocolConfig* getIkev2ProtocolConfig() const;
|
const Ikev2ProtocolConfig* getIkev2ProtocolConfig() const;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include "core/utils/protocolEnum.h"
|
#include "core/utils/protocolEnum.h"
|
||||||
#include "core/models/protocols/ikev2ProtocolConfig.h"
|
#include "core/models/protocols/ikev2ProtocolConfig.h"
|
||||||
#include "core/models/protocols/dnsProtocolConfig.h"
|
#include "core/models/protocols/dnsProtocolConfig.h"
|
||||||
|
#include "core/models/protocols/mtProxyProtocolConfig.h"
|
||||||
|
#include "core/models/protocols/telemtProtocolConfig.h"
|
||||||
|
|
||||||
namespace amnezia
|
namespace amnezia
|
||||||
{
|
{
|
||||||
@@ -38,6 +40,10 @@ Proto ProtocolConfig::type() const
|
|||||||
return Proto::TorWebSite;
|
return Proto::TorWebSite;
|
||||||
} else if constexpr (std::is_same_v<T, DnsProtocolConfig>) {
|
} else if constexpr (std::is_same_v<T, DnsProtocolConfig>) {
|
||||||
return Proto::Dns;
|
return Proto::Dns;
|
||||||
|
} else if constexpr (std::is_same_v<T, MtProxyProtocolConfig>) {
|
||||||
|
return Proto::MtProxy;
|
||||||
|
} else if constexpr (std::is_same_v<T, TelemtProtocolConfig>) {
|
||||||
|
return Proto::Telemt;
|
||||||
}
|
}
|
||||||
return Proto::Unknown;
|
return Proto::Unknown;
|
||||||
}, data);
|
}, data);
|
||||||
@@ -65,6 +71,10 @@ QString ProtocolConfig::port() const
|
|||||||
return QString();
|
return QString();
|
||||||
} else if constexpr (std::is_same_v<T, DnsProtocolConfig>) {
|
} else if constexpr (std::is_same_v<T, DnsProtocolConfig>) {
|
||||||
return QString();
|
return QString();
|
||||||
|
} else if constexpr (std::is_same_v<T, MtProxyProtocolConfig>) {
|
||||||
|
return arg.port.isEmpty() ? QString(protocols::mtProxy::defaultPort) : arg.port;
|
||||||
|
} else if constexpr (std::is_same_v<T, TelemtProtocolConfig>) {
|
||||||
|
return arg.port.isEmpty() ? QString(protocols::telemt::defaultPort) : arg.port;
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
}, data);
|
}, data);
|
||||||
@@ -88,6 +98,10 @@ QString ProtocolConfig::transportProto() const
|
|||||||
return QString();
|
return QString();
|
||||||
} else if constexpr (std::is_same_v<T, DnsProtocolConfig>) {
|
} else if constexpr (std::is_same_v<T, DnsProtocolConfig>) {
|
||||||
return QString();
|
return QString();
|
||||||
|
} else if constexpr (std::is_same_v<T, MtProxyProtocolConfig>) {
|
||||||
|
return QStringLiteral("tcp");
|
||||||
|
} else if constexpr (std::is_same_v<T, TelemtProtocolConfig>) {
|
||||||
|
return QStringLiteral("tcp");
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
}, data);
|
}, data);
|
||||||
@@ -299,6 +313,10 @@ ProtocolConfig ProtocolConfig::fromJson(const QJsonObject& json, Proto type)
|
|||||||
return ProtocolConfig{TorProtocolConfig::fromJson(json)};
|
return ProtocolConfig{TorProtocolConfig::fromJson(json)};
|
||||||
case Proto::Dns:
|
case Proto::Dns:
|
||||||
return ProtocolConfig{DnsProtocolConfig::fromJson(json)};
|
return ProtocolConfig{DnsProtocolConfig::fromJson(json)};
|
||||||
|
case Proto::MtProxy:
|
||||||
|
return ProtocolConfig{MtProxyProtocolConfig::fromJson(json)};
|
||||||
|
case Proto::Telemt:
|
||||||
|
return ProtocolConfig{TelemtProtocolConfig::fromJson(json)};
|
||||||
default:
|
default:
|
||||||
return ProtocolConfig{AwgProtocolConfig{}};
|
return ProtocolConfig{AwgProtocolConfig{}};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#include "core/models/protocols/ikev2ProtocolConfig.h"
|
#include "core/models/protocols/ikev2ProtocolConfig.h"
|
||||||
#include "core/models/protocols/torProtocolConfig.h"
|
#include "core/models/protocols/torProtocolConfig.h"
|
||||||
#include "core/models/protocols/dnsProtocolConfig.h"
|
#include "core/models/protocols/dnsProtocolConfig.h"
|
||||||
|
#include "core/models/protocols/mtProxyProtocolConfig.h"
|
||||||
|
#include "core/models/protocols/telemtProtocolConfig.h"
|
||||||
|
|
||||||
namespace amnezia
|
namespace amnezia
|
||||||
{
|
{
|
||||||
@@ -36,6 +38,8 @@ struct ProtocolConfig {
|
|||||||
XrayProtocolConfig,
|
XrayProtocolConfig,
|
||||||
SftpProtocolConfig,
|
SftpProtocolConfig,
|
||||||
Socks5ProxyProtocolConfig,
|
Socks5ProxyProtocolConfig,
|
||||||
|
MtProxyProtocolConfig,
|
||||||
|
TelemtProtocolConfig,
|
||||||
Ikev2ProtocolConfig,
|
Ikev2ProtocolConfig,
|
||||||
TorProtocolConfig,
|
TorProtocolConfig,
|
||||||
DnsProtocolConfig
|
DnsProtocolConfig
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
#include "mtProxyProtocolConfig.h"
|
||||||
|
|
||||||
|
#include "../../../core/utils/protocolEnum.h"
|
||||||
|
#include "../../../core/protocols/protocolUtils.h"
|
||||||
|
#include "../../../core/utils/constants/configKeys.h"
|
||||||
|
#include "../../../core/utils/constants/protocolConstants.h"
|
||||||
|
#include <QJsonArray>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
using namespace amnezia;
|
||||||
|
|
||||||
|
namespace amnezia {
|
||||||
|
|
||||||
|
QJsonObject MtProxyProtocolConfig::toJson() const {
|
||||||
|
QJsonObject obj;
|
||||||
|
|
||||||
|
if (!port.isEmpty()) {
|
||||||
|
obj[configKey::port] = port;
|
||||||
|
}
|
||||||
|
if (!secret.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::secretKey] = secret;
|
||||||
|
}
|
||||||
|
if (!tag.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::tagKey] = tag;
|
||||||
|
}
|
||||||
|
if (!tgLink.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::tgLinkKey] = tgLink;
|
||||||
|
}
|
||||||
|
if (!tmeLink.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::tmeLinkKey] = tmeLink;
|
||||||
|
}
|
||||||
|
obj[protocols::mtProxy::isEnabledKey] = isEnabled;
|
||||||
|
if (!publicHost.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::publicHostKey] = publicHost;
|
||||||
|
}
|
||||||
|
if (!transportMode.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::transportModeKey] = transportMode;
|
||||||
|
}
|
||||||
|
if (!tlsDomain.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::tlsDomainKey] = tlsDomain;
|
||||||
|
}
|
||||||
|
if (!additionalSecrets.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::additionalSecretsKey] = QJsonArray::fromStringList(additionalSecrets);
|
||||||
|
}
|
||||||
|
if (!workersMode.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::workersModeKey] = workersMode;
|
||||||
|
}
|
||||||
|
if (!workers.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::workersKey] = workers;
|
||||||
|
}
|
||||||
|
obj[protocols::mtProxy::natEnabledKey] = natEnabled;
|
||||||
|
if (!natInternalIp.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::natInternalIpKey] = natInternalIp;
|
||||||
|
}
|
||||||
|
if (!natExternalIp.isEmpty()) {
|
||||||
|
obj[protocols::mtProxy::natExternalIpKey] = natExternalIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
MtProxyProtocolConfig MtProxyProtocolConfig::fromJson(const QJsonObject &json) {
|
||||||
|
MtProxyProtocolConfig config;
|
||||||
|
|
||||||
|
config.port = json.value(configKey::port).toString();
|
||||||
|
config.secret = json.value(protocols::mtProxy::secretKey).toString();
|
||||||
|
config.tag = json.value(protocols::mtProxy::tagKey).toString();
|
||||||
|
config.tgLink = json.value(protocols::mtProxy::tgLinkKey).toString();
|
||||||
|
config.tmeLink = json.value(protocols::mtProxy::tmeLinkKey).toString();
|
||||||
|
config.isEnabled = json.value(protocols::mtProxy::isEnabledKey).toBool(true);
|
||||||
|
config.publicHost = json.value(protocols::mtProxy::publicHostKey).toString();
|
||||||
|
config.transportMode = json.value(protocols::mtProxy::transportModeKey).toString();
|
||||||
|
config.tlsDomain = json.value(protocols::mtProxy::tlsDomainKey).toString();
|
||||||
|
for (const auto &v: json.value(protocols::mtProxy::additionalSecretsKey).toArray()) {
|
||||||
|
const QString s = v.toString();
|
||||||
|
if (!s.isEmpty()) {
|
||||||
|
config.additionalSecrets.append(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.workersMode = json.value(protocols::mtProxy::workersModeKey).toString();
|
||||||
|
config.workers = json.value(protocols::mtProxy::workersKey).toString();
|
||||||
|
config.natEnabled = json.value(protocols::mtProxy::natEnabledKey).toBool(false);
|
||||||
|
config.natInternalIp = json.value(protocols::mtProxy::natInternalIpKey).toString();
|
||||||
|
config.natExternalIp = json.value(protocols::mtProxy::natExternalIpKey).toString();
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MtProxyProtocolConfig::equalsDockerDeploymentSettings(const MtProxyProtocolConfig &other) const {
|
||||||
|
const auto normPort = [](const QString &p) {
|
||||||
|
return p.isEmpty() ? QString(protocols::mtProxy::defaultPort) : p;
|
||||||
|
};
|
||||||
|
const auto normTransport = [](const QString &t) {
|
||||||
|
return t.isEmpty() ? QString(protocols::mtProxy::transportModeStandard) : t;
|
||||||
|
};
|
||||||
|
const auto normWorkersMode = [](const QString &m) {
|
||||||
|
return m.isEmpty() ? QString(protocols::mtProxy::workersModeAuto) : m;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (normPort(port) != normPort(other.port)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (normTransport(transportMode) != normTransport(other.transportMode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tlsDomain != other.tlsDomain) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (secret != other.secret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tag != other.tag) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (publicHost != other.publicHost) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (normWorkersMode(workersMode) != normWorkersMode(other.workersMode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (workers != other.workers) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (natEnabled != other.natEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (natInternalIp != other.natInternalIp) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (natExternalIp != other.natExternalIp) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isEnabled != other.isEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList aa = additionalSecrets;
|
||||||
|
QStringList bb = other.additionalSecrets;
|
||||||
|
aa.removeAll(QString());
|
||||||
|
bb.removeAll(QString());
|
||||||
|
std::sort(aa.begin(), aa.end());
|
||||||
|
std::sort(bb.begin(), bb.end());
|
||||||
|
return aa == bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef MTPROXYPROTOCOLCONFIG_H
|
||||||
|
#define MTPROXYPROTOCOLCONFIG_H
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
namespace amnezia {
|
||||||
|
|
||||||
|
struct MtProxyProtocolConfig {
|
||||||
|
QString port;
|
||||||
|
QString secret;
|
||||||
|
QString tag;
|
||||||
|
QString tgLink;
|
||||||
|
QString tmeLink;
|
||||||
|
bool isEnabled = true;
|
||||||
|
QString publicHost;
|
||||||
|
QString transportMode;
|
||||||
|
QString tlsDomain;
|
||||||
|
QStringList additionalSecrets;
|
||||||
|
QString workersMode;
|
||||||
|
QString workers;
|
||||||
|
bool natEnabled = false;
|
||||||
|
QString natInternalIp;
|
||||||
|
QString natExternalIp;
|
||||||
|
|
||||||
|
QJsonObject toJson() const;
|
||||||
|
|
||||||
|
static MtProxyProtocolConfig fromJson(const QJsonObject &json);
|
||||||
|
|
||||||
|
// Port, transport, TLS, secrets, NAT, workers, isEnabled, additionalSecrets (order-independent).
|
||||||
|
// Ignores tgLink / tmeLink (derived / display).
|
||||||
|
bool equalsDockerDeploymentSettings(const MtProxyProtocolConfig &other) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
|
|
||||||
|
#endif // MTPROXYPROTOCOLCONFIG_H
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
#include "telemtProtocolConfig.h"
|
||||||
|
|
||||||
|
#include "core/utils/constants/configKeys.h"
|
||||||
|
#include "core/utils/constants/protocolConstants.h"
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
using namespace amnezia;
|
||||||
|
|
||||||
|
QJsonObject TelemtProtocolConfig::toJson() const
|
||||||
|
{
|
||||||
|
QJsonObject obj;
|
||||||
|
if (!port.isEmpty()) {
|
||||||
|
obj[QString(configKey::port)] = port;
|
||||||
|
}
|
||||||
|
if (!secret.isEmpty()) {
|
||||||
|
obj[protocols::telemt::secretKey] = secret;
|
||||||
|
}
|
||||||
|
if (!tag.isEmpty()) {
|
||||||
|
obj[protocols::telemt::tagKey] = tag;
|
||||||
|
}
|
||||||
|
if (!tgLink.isEmpty()) {
|
||||||
|
obj[protocols::telemt::tgLinkKey] = tgLink;
|
||||||
|
}
|
||||||
|
if (!tmeLink.isEmpty()) {
|
||||||
|
obj[protocols::telemt::tmeLinkKey] = tmeLink;
|
||||||
|
}
|
||||||
|
obj[protocols::telemt::isEnabledKey] = isEnabled;
|
||||||
|
if (!publicHost.isEmpty()) {
|
||||||
|
obj[protocols::telemt::publicHostKey] = publicHost;
|
||||||
|
}
|
||||||
|
if (!transportMode.isEmpty()) {
|
||||||
|
obj[protocols::telemt::transportModeKey] = transportMode;
|
||||||
|
}
|
||||||
|
if (!tlsDomain.isEmpty()) {
|
||||||
|
obj[protocols::telemt::tlsDomainKey] = tlsDomain;
|
||||||
|
}
|
||||||
|
obj[protocols::telemt::maskEnabledKey] = maskEnabled;
|
||||||
|
obj[protocols::telemt::tlsEmulationKey] = tlsEmulation;
|
||||||
|
obj[protocols::telemt::useMiddleProxyKey] = useMiddleProxy;
|
||||||
|
if (!userName.isEmpty()) {
|
||||||
|
obj[protocols::telemt::userNameKey] = userName;
|
||||||
|
}
|
||||||
|
if (!additionalSecrets.isEmpty()) {
|
||||||
|
obj[protocols::telemt::additionalSecretsKey] = QJsonArray::fromStringList(additionalSecrets);
|
||||||
|
}
|
||||||
|
if (!workersMode.isEmpty()) {
|
||||||
|
obj[protocols::telemt::workersModeKey] = workersMode;
|
||||||
|
}
|
||||||
|
if (!workers.isEmpty()) {
|
||||||
|
obj[protocols::telemt::workersKey] = workers;
|
||||||
|
}
|
||||||
|
obj[protocols::telemt::natEnabledKey] = natEnabled;
|
||||||
|
if (!natInternalIp.isEmpty()) {
|
||||||
|
obj[protocols::telemt::natInternalIpKey] = natInternalIp;
|
||||||
|
}
|
||||||
|
if (!natExternalIp.isEmpty()) {
|
||||||
|
obj[protocols::telemt::natExternalIpKey] = natExternalIp;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
TelemtProtocolConfig TelemtProtocolConfig::fromJson(const QJsonObject &json)
|
||||||
|
{
|
||||||
|
TelemtProtocolConfig c;
|
||||||
|
c.port = json.value(QString(configKey::port)).toString();
|
||||||
|
c.secret = json.value(protocols::telemt::secretKey).toString();
|
||||||
|
c.tag = json.value(protocols::telemt::tagKey).toString();
|
||||||
|
c.tgLink = json.value(protocols::telemt::tgLinkKey).toString();
|
||||||
|
c.tmeLink = json.value(protocols::telemt::tmeLinkKey).toString();
|
||||||
|
c.isEnabled = json.value(protocols::telemt::isEnabledKey).toBool(true);
|
||||||
|
c.publicHost = json.value(protocols::telemt::publicHostKey).toString();
|
||||||
|
c.transportMode = json.value(protocols::telemt::transportModeKey).toString();
|
||||||
|
c.tlsDomain = json.value(protocols::telemt::tlsDomainKey).toString();
|
||||||
|
c.maskEnabled = json.value(protocols::telemt::maskEnabledKey).toBool(true);
|
||||||
|
c.tlsEmulation = json.value(protocols::telemt::tlsEmulationKey).toBool(false);
|
||||||
|
c.useMiddleProxy = json.value(protocols::telemt::useMiddleProxyKey).toBool(true);
|
||||||
|
c.userName = json.value(protocols::telemt::userNameKey).toString();
|
||||||
|
for (const auto &v : json.value(protocols::telemt::additionalSecretsKey).toArray()) {
|
||||||
|
const QString s = v.toString();
|
||||||
|
if (!s.isEmpty()) {
|
||||||
|
c.additionalSecrets.append(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.workersMode = json.value(protocols::telemt::workersModeKey).toString();
|
||||||
|
c.workers = json.value(protocols::telemt::workersKey).toString();
|
||||||
|
c.natEnabled = json.value(protocols::telemt::natEnabledKey).toBool(false);
|
||||||
|
c.natInternalIp = json.value(protocols::telemt::natInternalIpKey).toString();
|
||||||
|
c.natExternalIp = json.value(protocols::telemt::natExternalIpKey).toString();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TelemtProtocolConfig::equalsDockerDeploymentSettings(const TelemtProtocolConfig &other) const
|
||||||
|
{
|
||||||
|
const auto normPort = [](const QString &p) {
|
||||||
|
return p.isEmpty() ? QString(protocols::telemt::defaultPort) : p;
|
||||||
|
};
|
||||||
|
const auto normTransport = [](const QString &t) {
|
||||||
|
return t.isEmpty() ? QString(protocols::telemt::transportModeStandard) : t;
|
||||||
|
};
|
||||||
|
const auto normWorkersMode = [](const QString &m) {
|
||||||
|
return m.isEmpty() ? QString(protocols::telemt::workersModeAuto) : m;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (normPort(port) != normPort(other.port)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (normTransport(transportMode) != normTransport(other.transportMode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tlsDomain != other.tlsDomain) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (secret != other.secret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tag != other.tag) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (publicHost != other.publicHost) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (maskEnabled != other.maskEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tlsEmulation != other.tlsEmulation) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (useMiddleProxy != other.useMiddleProxy) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (userName != other.userName) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (normWorkersMode(workersMode) != normWorkersMode(other.workersMode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (workers != other.workers) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (natEnabled != other.natEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (natInternalIp != other.natInternalIp) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (natExternalIp != other.natExternalIp) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isEnabled != other.isEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList aa = additionalSecrets;
|
||||||
|
QStringList bb = other.additionalSecrets;
|
||||||
|
aa.removeAll(QString());
|
||||||
|
bb.removeAll(QString());
|
||||||
|
std::sort(aa.begin(), aa.end());
|
||||||
|
std::sort(bb.begin(), bb.end());
|
||||||
|
return aa == bb;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef TELEMTPROTOCOLCONFIG_H
|
||||||
|
#define TELEMTPROTOCOLCONFIG_H
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
namespace amnezia {
|
||||||
|
|
||||||
|
struct TelemtProtocolConfig {
|
||||||
|
QString port;
|
||||||
|
QString secret;
|
||||||
|
QString tag;
|
||||||
|
QString tgLink;
|
||||||
|
QString tmeLink;
|
||||||
|
bool isEnabled = true;
|
||||||
|
QString publicHost;
|
||||||
|
QString transportMode;
|
||||||
|
QString tlsDomain;
|
||||||
|
bool maskEnabled = true;
|
||||||
|
bool tlsEmulation = false;
|
||||||
|
bool useMiddleProxy = true;
|
||||||
|
QString userName;
|
||||||
|
QStringList additionalSecrets;
|
||||||
|
QString workersMode;
|
||||||
|
QString workers;
|
||||||
|
bool natEnabled = false;
|
||||||
|
QString natInternalIp;
|
||||||
|
QString natExternalIp;
|
||||||
|
|
||||||
|
QJsonObject toJson() const;
|
||||||
|
static TelemtProtocolConfig fromJson(const QJsonObject &json);
|
||||||
|
bool equalsDockerDeploymentSettings(const TelemtProtocolConfig &other) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
|
|
||||||
|
#endif // TELEMTPROTOCOLCONFIG_H
|
||||||
@@ -35,6 +35,9 @@ QJsonObject NativeServerConfig::toJson() const
|
|||||||
if (!description.isEmpty()) {
|
if (!description.isEmpty()) {
|
||||||
obj[configKey::description] = this->description;
|
obj[configKey::description] = this->description;
|
||||||
}
|
}
|
||||||
|
if (!displayName.isEmpty()) {
|
||||||
|
obj[configKey::displayName] = displayName;
|
||||||
|
}
|
||||||
if (!hostName.isEmpty()) {
|
if (!hostName.isEmpty()) {
|
||||||
obj[configKey::hostName] = hostName;
|
obj[configKey::hostName] = hostName;
|
||||||
}
|
}
|
||||||
@@ -67,6 +70,7 @@ NativeServerConfig NativeServerConfig::fromJson(const QJsonObject& json)
|
|||||||
NativeServerConfig config;
|
NativeServerConfig config;
|
||||||
|
|
||||||
config.description = json.value(configKey::description).toString();
|
config.description = json.value(configKey::description).toString();
|
||||||
|
config.displayName = json.value(configKey::displayName).toString();
|
||||||
config.hostName = json.value(configKey::hostName).toString();
|
config.hostName = json.value(configKey::hostName).toString();
|
||||||
|
|
||||||
QJsonArray containersArray = json.value(configKey::containers).toArray();
|
QJsonArray containersArray = json.value(configKey::containers).toArray();
|
||||||
@@ -86,6 +90,10 @@ NativeServerConfig NativeServerConfig::fromJson(const QJsonObject& json)
|
|||||||
config.dns1 = json.value(configKey::dns1).toString();
|
config.dns1 = json.value(configKey::dns1).toString();
|
||||||
config.dns2 = json.value(configKey::dns2).toString();
|
config.dns2 = json.value(configKey::dns2).toString();
|
||||||
|
|
||||||
|
if (config.displayName.isEmpty()) {
|
||||||
|
config.displayName = config.description.isEmpty() ? config.hostName : config.description;
|
||||||
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using namespace ContainerEnumNS;
|
|||||||
|
|
||||||
struct NativeServerConfig {
|
struct NativeServerConfig {
|
||||||
QString description;
|
QString description;
|
||||||
|
QString displayName;
|
||||||
QString hostName;
|
QString hostName;
|
||||||
QMap<DockerContainer, ContainerConfig> containers;
|
QMap<DockerContainer, ContainerConfig> containers;
|
||||||
DockerContainer defaultContainer;
|
DockerContainer defaultContainer;
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
#include "selfHostedAdminServerConfig.h"
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
|
||||||
|
#include "core/protocols/protocolUtils.h"
|
||||||
|
#include "core/utils/constants/configKeys.h"
|
||||||
|
#include "core/utils/constants/protocolConstants.h"
|
||||||
|
#include "core/utils/containerEnum.h"
|
||||||
|
#include "core/utils/containers/containerUtils.h"
|
||||||
|
#include "core/utils/protocolEnum.h"
|
||||||
|
#include "core/utils/networkUtilities.h"
|
||||||
|
|
||||||
|
namespace amnezia
|
||||||
|
{
|
||||||
|
|
||||||
|
using namespace ContainerEnumNS;
|
||||||
|
|
||||||
|
bool SelfHostedAdminServerConfig::hasCredentials() const
|
||||||
|
{
|
||||||
|
return !userName.isEmpty() && !password.isEmpty() && port > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelfHostedAdminServerConfig::isReadOnly() const
|
||||||
|
{
|
||||||
|
return !hasCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerCredentials SelfHostedAdminServerConfig::credentials() const
|
||||||
|
{
|
||||||
|
ServerCredentials creds;
|
||||||
|
creds.hostName = hostName;
|
||||||
|
creds.userName = userName;
|
||||||
|
creds.secretData = password;
|
||||||
|
creds.port = port;
|
||||||
|
return creds;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelfHostedAdminServerConfig::hasContainers() const
|
||||||
|
{
|
||||||
|
return !containers.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContainerConfig SelfHostedAdminServerConfig::containerConfig(DockerContainer container) const
|
||||||
|
{
|
||||||
|
if (!containers.contains(container)) {
|
||||||
|
return ContainerConfig{};
|
||||||
|
}
|
||||||
|
return containers.value(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelfHostedAdminServerConfig::updateContainerConfig(DockerContainer container, const ContainerConfig &config)
|
||||||
|
{
|
||||||
|
containers[container] = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelfHostedAdminServerConfig::clearCachedClientProfile(DockerContainer container)
|
||||||
|
{
|
||||||
|
if (ContainerUtils::containerService(container) == ServiceType::Other) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContainerConfig cleared = containerConfig(container);
|
||||||
|
cleared.protocolConfig.clearClientConfig();
|
||||||
|
containers[container] = cleared;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPair<QString, QString> SelfHostedAdminServerConfig::getDnsPair(bool isAmneziaDnsEnabled, const QString &primaryDns,
|
||||||
|
const QString &secondaryDns) const
|
||||||
|
{
|
||||||
|
QString d1 = dns1;
|
||||||
|
QString d2 = dns2;
|
||||||
|
const bool dnsOnServer = containers.contains(DockerContainer::Dns);
|
||||||
|
|
||||||
|
if (d1.isEmpty() || !NetworkUtilities::checkIPv4Format(d1)) {
|
||||||
|
d1 = (isAmneziaDnsEnabled && dnsOnServer) ? protocols::dns::amneziaDnsIp : primaryDns;
|
||||||
|
}
|
||||||
|
if (d2.isEmpty() || !NetworkUtilities::checkIPv4Format(d2)) {
|
||||||
|
d2 = secondaryDns;
|
||||||
|
}
|
||||||
|
return { d1, d2 };
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject SelfHostedAdminServerConfig::toJson() const
|
||||||
|
{
|
||||||
|
QJsonObject obj;
|
||||||
|
|
||||||
|
if (!description.isEmpty()) {
|
||||||
|
obj[configKey::description] = this->description;
|
||||||
|
}
|
||||||
|
if (!displayName.isEmpty()) {
|
||||||
|
obj[configKey::displayName] = displayName;
|
||||||
|
}
|
||||||
|
if (!hostName.isEmpty()) {
|
||||||
|
obj[configKey::hostName] = hostName;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray containersArray;
|
||||||
|
for (auto it = containers.begin(); it != containers.end(); ++it) {
|
||||||
|
QJsonObject containerObj = it.value().toJson();
|
||||||
|
containersArray.append(containerObj);
|
||||||
|
}
|
||||||
|
if (!containersArray.isEmpty()) {
|
||||||
|
obj[configKey::containers] = containersArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defaultContainer != DockerContainer::None) {
|
||||||
|
obj[configKey::defaultContainer] = ContainerUtils::containerToString(defaultContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dns1.isEmpty()) {
|
||||||
|
obj[configKey::dns1] = dns1;
|
||||||
|
}
|
||||||
|
if (!dns2.isEmpty()) {
|
||||||
|
obj[configKey::dns2] = dns2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userName.isEmpty()) {
|
||||||
|
obj[configKey::userName] = userName;
|
||||||
|
}
|
||||||
|
if (!password.isEmpty()) {
|
||||||
|
obj[configKey::password] = password;
|
||||||
|
}
|
||||||
|
if (port > 0) {
|
||||||
|
obj[configKey::port] = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelfHostedAdminServerConfig SelfHostedAdminServerConfig::fromJson(const QJsonObject &json)
|
||||||
|
{
|
||||||
|
SelfHostedAdminServerConfig config;
|
||||||
|
|
||||||
|
config.description = json.value(configKey::description).toString();
|
||||||
|
config.displayName = json.value(configKey::displayName).toString();
|
||||||
|
config.hostName = json.value(configKey::hostName).toString();
|
||||||
|
|
||||||
|
QJsonArray containersArray = json.value(configKey::containers).toArray();
|
||||||
|
for (const QJsonValue &val : containersArray) {
|
||||||
|
QJsonObject containerObj = val.toObject();
|
||||||
|
ContainerConfig cc = ContainerConfig::fromJson(containerObj);
|
||||||
|
|
||||||
|
QString containerStr = containerObj.value(configKey::container).toString();
|
||||||
|
DockerContainer container = ContainerUtils::containerFromString(containerStr);
|
||||||
|
|
||||||
|
config.containers.insert(container, cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString defaultContainerStr = json.value(configKey::defaultContainer).toString();
|
||||||
|
config.defaultContainer = ContainerUtils::containerFromString(defaultContainerStr);
|
||||||
|
|
||||||
|
config.dns1 = json.value(configKey::dns1).toString();
|
||||||
|
config.dns2 = json.value(configKey::dns2).toString();
|
||||||
|
|
||||||
|
config.userName = json.value(configKey::userName).toString();
|
||||||
|
config.password = json.value(configKey::password).toString();
|
||||||
|
if (json.contains(configKey::port)) {
|
||||||
|
config.port = json.value(configKey::port).toInt();
|
||||||
|
} else {
|
||||||
|
config.port = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.displayName.isEmpty()) {
|
||||||
|
config.displayName = config.description.isEmpty() ? config.hostName : config.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef SELFHOSTEDADMINSERVERCONFIG_H
|
||||||
|
#define SELFHOSTEDADMINSERVERCONFIG_H
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QPair>
|
||||||
|
|
||||||
|
#include "core/utils/containerEnum.h"
|
||||||
|
#include "core/utils/containers/containerUtils.h"
|
||||||
|
#include "core/utils/protocolEnum.h"
|
||||||
|
#include "core/models/containerConfig.h"
|
||||||
|
#include "core/utils/errorCodes.h"
|
||||||
|
#include "core/utils/routeModes.h"
|
||||||
|
#include "core/utils/commonStructs.h"
|
||||||
|
|
||||||
|
namespace amnezia
|
||||||
|
{
|
||||||
|
|
||||||
|
using namespace ContainerEnumNS;
|
||||||
|
|
||||||
|
struct SelfHostedAdminServerConfig {
|
||||||
|
QString description;
|
||||||
|
QString displayName;
|
||||||
|
QString hostName;
|
||||||
|
QMap<DockerContainer, ContainerConfig> containers;
|
||||||
|
DockerContainer defaultContainer;
|
||||||
|
QString dns1;
|
||||||
|
QString dns2;
|
||||||
|
|
||||||
|
QString userName;
|
||||||
|
QString password;
|
||||||
|
int port = 0;
|
||||||
|
|
||||||
|
bool hasCredentials() const;
|
||||||
|
bool isReadOnly() const;
|
||||||
|
ServerCredentials credentials() const;
|
||||||
|
bool hasContainers() const;
|
||||||
|
ContainerConfig containerConfig(DockerContainer container) const;
|
||||||
|
|
||||||
|
void updateContainerConfig(DockerContainer container, const ContainerConfig &config);
|
||||||
|
|
||||||
|
void clearCachedClientProfile(DockerContainer container);
|
||||||
|
|
||||||
|
QPair<QString, QString> getDnsPair(bool isAmneziaDnsEnabled, const QString &primaryDns,
|
||||||
|
const QString &secondaryDns) const;
|
||||||
|
|
||||||
|
QJsonObject toJson() const;
|
||||||
|
static SelfHostedAdminServerConfig fromJson(const QJsonObject &json);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
|
|
||||||
|
#endif // SELFHOSTEDADMINSERVERCONFIG_H
|
||||||
+37
-63
@@ -1,53 +1,40 @@
|
|||||||
#include "selfHostedServerConfig.h"
|
#include "selfHostedUserServerConfig.h"
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include "core/utils/containerEnum.h"
|
|
||||||
#include "core/utils/containers/containerUtils.h"
|
|
||||||
#include "core/utils/protocolEnum.h"
|
|
||||||
#include "core/utils/protocolEnum.h"
|
|
||||||
#include "core/protocols/protocolUtils.h"
|
#include "core/protocols/protocolUtils.h"
|
||||||
#include "core/utils/constants/configKeys.h"
|
#include "core/utils/constants/configKeys.h"
|
||||||
#include "core/utils/constants/protocolConstants.h"
|
#include "core/utils/constants/protocolConstants.h"
|
||||||
|
#include "core/utils/containerEnum.h"
|
||||||
|
#include "core/utils/containers/containerUtils.h"
|
||||||
|
#include "core/utils/protocolEnum.h"
|
||||||
|
|
||||||
namespace amnezia
|
namespace amnezia
|
||||||
{
|
{
|
||||||
|
|
||||||
using namespace ContainerEnumNS;
|
using namespace ContainerEnumNS;
|
||||||
|
|
||||||
bool SelfHostedServerConfig::hasCredentials() const
|
bool SelfHostedUserServerConfig::hasCredentials() const
|
||||||
{
|
{
|
||||||
return userName.has_value() && password.has_value() && port.has_value();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SelfHostedServerConfig::isReadOnly() const
|
bool SelfHostedUserServerConfig::isReadOnly() const
|
||||||
{
|
{
|
||||||
return !hasCredentials();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ServerCredentials> SelfHostedServerConfig::credentials() const
|
std::optional<ServerCredentials> SelfHostedUserServerConfig::credentials() const
|
||||||
{
|
{
|
||||||
if (!hasCredentials()) {
|
return std::nullopt;
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerCredentials creds;
|
|
||||||
creds.hostName = hostName;
|
|
||||||
creds.userName = userName.value();
|
|
||||||
creds.secretData = password.value();
|
|
||||||
creds.port = port.value();
|
|
||||||
|
|
||||||
return creds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SelfHostedServerConfig::hasContainers() const
|
bool SelfHostedUserServerConfig::hasContainers() const
|
||||||
{
|
{
|
||||||
return !containers.isEmpty();
|
return !containers.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
ContainerConfig SelfHostedServerConfig::containerConfig(DockerContainer container) const
|
ContainerConfig SelfHostedUserServerConfig::containerConfig(DockerContainer container) const
|
||||||
{
|
{
|
||||||
if (!containers.contains(container)) {
|
if (!containers.contains(container)) {
|
||||||
return ContainerConfig{};
|
return ContainerConfig{};
|
||||||
@@ -55,17 +42,20 @@ ContainerConfig SelfHostedServerConfig::containerConfig(DockerContainer containe
|
|||||||
return containers.value(container);
|
return containers.value(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject SelfHostedServerConfig::toJson() const
|
QJsonObject SelfHostedUserServerConfig::toJson() const
|
||||||
{
|
{
|
||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
|
|
||||||
if (!description.isEmpty()) {
|
if (!description.isEmpty()) {
|
||||||
obj[configKey::description] = this->description;
|
obj[configKey::description] = this->description;
|
||||||
}
|
}
|
||||||
|
if (!displayName.isEmpty()) {
|
||||||
|
obj[configKey::displayName] = displayName;
|
||||||
|
}
|
||||||
if (!hostName.isEmpty()) {
|
if (!hostName.isEmpty()) {
|
||||||
obj[configKey::hostName] = hostName;
|
obj[configKey::hostName] = hostName;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonArray containersArray;
|
QJsonArray containersArray;
|
||||||
for (auto it = containers.begin(); it != containers.end(); ++it) {
|
for (auto it = containers.begin(); it != containers.end(); ++it) {
|
||||||
QJsonObject containerObj = it.value().toJson();
|
QJsonObject containerObj = it.value().toJson();
|
||||||
@@ -74,67 +64,51 @@ QJsonObject SelfHostedServerConfig::toJson() const
|
|||||||
if (!containersArray.isEmpty()) {
|
if (!containersArray.isEmpty()) {
|
||||||
obj[configKey::containers] = containersArray;
|
obj[configKey::containers] = containersArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultContainer != DockerContainer::None) {
|
if (defaultContainer != DockerContainer::None) {
|
||||||
obj[configKey::defaultContainer] = ContainerUtils::containerToString(defaultContainer);
|
obj[configKey::defaultContainer] = ContainerUtils::containerToString(defaultContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dns1.isEmpty()) {
|
if (!dns1.isEmpty()) {
|
||||||
obj[configKey::dns1] = dns1;
|
obj[configKey::dns1] = dns1;
|
||||||
}
|
}
|
||||||
if (!dns2.isEmpty()) {
|
if (!dns2.isEmpty()) {
|
||||||
obj[configKey::dns2] = dns2;
|
obj[configKey::dns2] = dns2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userName.has_value()) {
|
|
||||||
obj[configKey::userName] = userName.value();
|
|
||||||
}
|
|
||||||
if (password.has_value()) {
|
|
||||||
obj[configKey::password] = password.value();
|
|
||||||
}
|
|
||||||
if (port.has_value()) {
|
|
||||||
obj[configKey::port] = port.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
SelfHostedServerConfig SelfHostedServerConfig::fromJson(const QJsonObject& json)
|
SelfHostedUserServerConfig SelfHostedUserServerConfig::fromJson(const QJsonObject &json)
|
||||||
{
|
{
|
||||||
SelfHostedServerConfig config;
|
SelfHostedUserServerConfig config;
|
||||||
|
|
||||||
config.description = json.value(configKey::description).toString();
|
config.description = json.value(configKey::description).toString();
|
||||||
|
config.displayName = json.value(configKey::displayName).toString();
|
||||||
config.hostName = json.value(configKey::hostName).toString();
|
config.hostName = json.value(configKey::hostName).toString();
|
||||||
|
|
||||||
QJsonArray containersArray = json.value(configKey::containers).toArray();
|
QJsonArray containersArray = json.value(configKey::containers).toArray();
|
||||||
for (const QJsonValue& val : containersArray) {
|
for (const QJsonValue &val : containersArray) {
|
||||||
QJsonObject containerObj = val.toObject();
|
QJsonObject containerObj = val.toObject();
|
||||||
ContainerConfig containerConfig = ContainerConfig::fromJson(containerObj);
|
ContainerConfig cc = ContainerConfig::fromJson(containerObj);
|
||||||
|
|
||||||
QString containerStr = containerObj.value(configKey::container).toString();
|
QString containerStr = containerObj.value(configKey::container).toString();
|
||||||
DockerContainer container = ContainerUtils::containerFromString(containerStr);
|
DockerContainer container = ContainerUtils::containerFromString(containerStr);
|
||||||
|
|
||||||
config.containers.insert(container, containerConfig);
|
config.containers.insert(container, cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString defaultContainerStr = json.value(configKey::defaultContainer).toString();
|
QString defaultContainerStr = json.value(configKey::defaultContainer).toString();
|
||||||
config.defaultContainer = ContainerUtils::containerFromString(defaultContainerStr);
|
config.defaultContainer = ContainerUtils::containerFromString(defaultContainerStr);
|
||||||
|
|
||||||
config.dns1 = json.value(configKey::dns1).toString();
|
config.dns1 = json.value(configKey::dns1).toString();
|
||||||
config.dns2 = json.value(configKey::dns2).toString();
|
config.dns2 = json.value(configKey::dns2).toString();
|
||||||
|
|
||||||
if (json.contains(configKey::userName)) {
|
if (config.displayName.isEmpty()) {
|
||||||
config.userName = json.value(configKey::userName).toString();
|
config.displayName = config.description.isEmpty() ? config.hostName : config.description;
|
||||||
}
|
}
|
||||||
if (json.contains(configKey::password)) {
|
|
||||||
config.password = json.value(configKey::password).toString();
|
|
||||||
}
|
|
||||||
if (json.contains(configKey::port)) {
|
|
||||||
config.port = json.value(configKey::port).toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace amnezia
|
} // namespace amnezia
|
||||||
|
|
||||||
+7
-13
@@ -1,5 +1,5 @@
|
|||||||
#ifndef SELFHOSTEDSERVERCONFIG_H
|
#ifndef SELFHOSTEDUSERSERVERCONFIG_H
|
||||||
#define SELFHOSTEDSERVERCONFIG_H
|
#define SELFHOSTEDUSERSERVERCONFIG_H
|
||||||
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
@@ -9,8 +9,6 @@
|
|||||||
#include "core/utils/containers/containerUtils.h"
|
#include "core/utils/containers/containerUtils.h"
|
||||||
#include "core/utils/protocolEnum.h"
|
#include "core/utils/protocolEnum.h"
|
||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
#include "core/utils/errorCodes.h"
|
|
||||||
#include "core/utils/routeModes.h"
|
|
||||||
#include "core/utils/commonStructs.h"
|
#include "core/utils/commonStructs.h"
|
||||||
|
|
||||||
namespace amnezia
|
namespace amnezia
|
||||||
@@ -18,28 +16,24 @@ namespace amnezia
|
|||||||
|
|
||||||
using namespace ContainerEnumNS;
|
using namespace ContainerEnumNS;
|
||||||
|
|
||||||
struct SelfHostedServerConfig {
|
struct SelfHostedUserServerConfig {
|
||||||
QString description;
|
QString description;
|
||||||
|
QString displayName;
|
||||||
QString hostName;
|
QString hostName;
|
||||||
QMap<DockerContainer, ContainerConfig> containers;
|
QMap<DockerContainer, ContainerConfig> containers;
|
||||||
DockerContainer defaultContainer;
|
DockerContainer defaultContainer;
|
||||||
QString dns1;
|
QString dns1;
|
||||||
QString dns2;
|
QString dns2;
|
||||||
|
|
||||||
std::optional<QString> userName;
|
|
||||||
std::optional<QString> password;
|
|
||||||
std::optional<int> port;
|
|
||||||
|
|
||||||
bool hasCredentials() const;
|
bool hasCredentials() const;
|
||||||
bool isReadOnly() const;
|
bool isReadOnly() const;
|
||||||
std::optional<ServerCredentials> credentials() const;
|
std::optional<ServerCredentials> credentials() const;
|
||||||
bool hasContainers() const;
|
bool hasContainers() const;
|
||||||
ContainerConfig containerConfig(DockerContainer container) const;
|
ContainerConfig containerConfig(DockerContainer container) const;
|
||||||
QJsonObject toJson() const;
|
QJsonObject toJson() const;
|
||||||
static SelfHostedServerConfig fromJson(const QJsonObject& json);
|
static SelfHostedUserServerConfig fromJson(const QJsonObject &json);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace amnezia
|
} // namespace amnezia
|
||||||
|
|
||||||
#endif // SELFHOSTEDSERVERCONFIG_H
|
#endif // SELFHOSTEDUSERSERVERCONFIG_H
|
||||||
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
#include "serverConfig.h"
|
|
||||||
|
|
||||||
#include "core/utils/api/apiUtils.h"
|
|
||||||
#include "core/utils/networkUtilities.h"
|
|
||||||
#include "core/models/selfhosted/selfHostedServerConfig.h"
|
|
||||||
#include "core/models/selfhosted/nativeServerConfig.h"
|
|
||||||
#include "core/models/api/apiV1ServerConfig.h"
|
|
||||||
#include "core/models/api/apiV2ServerConfig.h"
|
|
||||||
#include "core/utils/protocolEnum.h"
|
|
||||||
#include "core/protocols/protocolUtils.h"
|
|
||||||
#include "core/utils/constants/configKeys.h"
|
|
||||||
#include "core/utils/constants/protocolConstants.h"
|
|
||||||
|
|
||||||
namespace amnezia
|
|
||||||
{
|
|
||||||
|
|
||||||
using namespace ContainerEnumNS;
|
|
||||||
|
|
||||||
QString ServerConfig::description() const
|
|
||||||
{
|
|
||||||
return std::visit([](const auto& v) { return v.description; }, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ServerConfig::hostName() const
|
|
||||||
{
|
|
||||||
return std::visit([](const auto& v) { return v.hostName; }, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ServerConfig::displayName() const
|
|
||||||
{
|
|
||||||
if (isApiV1()) {
|
|
||||||
const auto *apiV1 = as<ApiV1ServerConfig>();
|
|
||||||
return apiV1 ? apiV1->name : description();
|
|
||||||
}
|
|
||||||
if (isApiV2()) {
|
|
||||||
const auto *apiV2 = as<ApiV2ServerConfig>();
|
|
||||||
return apiV2 ? apiV2->name : description();
|
|
||||||
}
|
|
||||||
QString name = description();
|
|
||||||
return name.isEmpty() ? hostName() : name;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMap<DockerContainer, ContainerConfig> ServerConfig::containers() const
|
|
||||||
{
|
|
||||||
return std::visit([](const auto& v) { return v.containers; }, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
DockerContainer ServerConfig::defaultContainer() const
|
|
||||||
{
|
|
||||||
return std::visit([](const auto& v) { return v.defaultContainer; }, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ServerConfig::dns1() const
|
|
||||||
{
|
|
||||||
return std::visit([](const auto& v) { return v.dns1; }, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ServerConfig::dns2() const
|
|
||||||
{
|
|
||||||
return std::visit([](const auto& v) { return v.dns2; }, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerConfig::hasContainers() const
|
|
||||||
{
|
|
||||||
return std::visit([](const auto& v) { return v.hasContainers(); }, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
ContainerConfig ServerConfig::containerConfig(DockerContainer container) const
|
|
||||||
{
|
|
||||||
return std::visit([container](const auto& v) { return v.containerConfig(container); }, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ServerConfig::crc() const
|
|
||||||
{
|
|
||||||
return std::visit([](const auto& v) -> int {
|
|
||||||
using T = std::decay_t<decltype(v)>;
|
|
||||||
if constexpr (std::is_same_v<T, ApiV1ServerConfig> ||
|
|
||||||
std::is_same_v<T, ApiV2ServerConfig>) {
|
|
||||||
return v.crc;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ServerConfig::configVersion() const
|
|
||||||
{
|
|
||||||
return std::visit([](const auto& v) -> int {
|
|
||||||
using T = std::decay_t<decltype(v)>;
|
|
||||||
if constexpr (std::is_same_v<T, ApiV1ServerConfig>) {
|
|
||||||
return apiDefs::ConfigSource::Telegram;
|
|
||||||
} else if constexpr (std::is_same_v<T, ApiV2ServerConfig>) {
|
|
||||||
return apiDefs::ConfigSource::AmneziaGateway;
|
|
||||||
}
|
|
||||||
return 0; // SelfHostedServerConfig or NativeServerConfig
|
|
||||||
}, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerConfig::isSelfHosted() const
|
|
||||||
{
|
|
||||||
return std::holds_alternative<SelfHostedServerConfig>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerConfig::isNative() const
|
|
||||||
{
|
|
||||||
return std::holds_alternative<NativeServerConfig>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerConfig::isApiV1() const
|
|
||||||
{
|
|
||||||
return std::holds_alternative<ApiV1ServerConfig>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerConfig::isApiV2() const
|
|
||||||
{
|
|
||||||
return std::holds_alternative<ApiV2ServerConfig>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerConfig::isApiConfig() const
|
|
||||||
{
|
|
||||||
return isApiV1() || isApiV2();
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject ServerConfig::toJson() const
|
|
||||||
{
|
|
||||||
return std::visit([](const auto& v) { return v.toJson(); }, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerConfig ServerConfig::fromJson(const QJsonObject& json)
|
|
||||||
{
|
|
||||||
apiDefs::ConfigType configType = apiUtils::getConfigType(json);
|
|
||||||
|
|
||||||
switch (configType) {
|
|
||||||
case apiDefs::ConfigType::SelfHosted: {
|
|
||||||
bool hasThirdPartyConfig = false;
|
|
||||||
QJsonArray containersArray = json.value(configKey::containers).toArray();
|
|
||||||
for (const QJsonValue& val : containersArray) {
|
|
||||||
QJsonObject containerObj = val.toObject();
|
|
||||||
for (auto it = containerObj.begin(); it != containerObj.end(); ++it) {
|
|
||||||
QString key = it.key();
|
|
||||||
if (key != configKey::container) {
|
|
||||||
QJsonObject protocolObj = it.value().toObject();
|
|
||||||
if (protocolObj.contains(configKey::isThirdPartyConfig) &&
|
|
||||||
protocolObj.value(configKey::isThirdPartyConfig).toBool()) {
|
|
||||||
hasThirdPartyConfig = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasThirdPartyConfig) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasThirdPartyConfig) {
|
|
||||||
return ServerConfig{NativeServerConfig::fromJson(json)};
|
|
||||||
} else {
|
|
||||||
return ServerConfig{SelfHostedServerConfig::fromJson(json)};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case apiDefs::ConfigType::AmneziaPremiumV1:
|
|
||||||
case apiDefs::ConfigType::AmneziaFreeV2:
|
|
||||||
return ServerConfig{ApiV1ServerConfig::fromJson(json)};
|
|
||||||
case apiDefs::ConfigType::AmneziaPremiumV2:
|
|
||||||
case apiDefs::ConfigType::AmneziaFreeV3:
|
|
||||||
case apiDefs::ConfigType::ExternalPremium:
|
|
||||||
return ServerConfig{ApiV2ServerConfig::fromJson(json)};
|
|
||||||
default: {
|
|
||||||
// Check if any container has isThirdPartyConfig
|
|
||||||
bool hasThirdPartyConfig = false;
|
|
||||||
QJsonArray containersArray = json.value(configKey::containers).toArray();
|
|
||||||
for (const QJsonValue& val : containersArray) {
|
|
||||||
QJsonObject containerObj = val.toObject();
|
|
||||||
// Check all protocol keys in the container object
|
|
||||||
for (auto it = containerObj.begin(); it != containerObj.end(); ++it) {
|
|
||||||
QString key = it.key();
|
|
||||||
if (key != configKey::container) {
|
|
||||||
QJsonObject protocolObj = it.value().toObject();
|
|
||||||
if (protocolObj.contains(configKey::isThirdPartyConfig) &&
|
|
||||||
protocolObj.value(configKey::isThirdPartyConfig).toBool()) {
|
|
||||||
hasThirdPartyConfig = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasThirdPartyConfig) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasThirdPartyConfig) {
|
|
||||||
return ServerConfig{NativeServerConfig::fromJson(json)};
|
|
||||||
} else {
|
|
||||||
return ServerConfig{SelfHostedServerConfig::fromJson(json)};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QPair<QString, QString> ServerConfig::getDnsPair(bool isAmneziaDnsEnabled,
|
|
||||||
const QString &primaryDns,
|
|
||||||
const QString &secondaryDns) const
|
|
||||||
{
|
|
||||||
QPair<QString, QString> dns;
|
|
||||||
|
|
||||||
QMap<DockerContainer, ContainerConfig> serverContainers = containers();
|
|
||||||
|
|
||||||
bool isDnsContainerInstalled = false;
|
|
||||||
for (auto it = serverContainers.begin(); it != serverContainers.end(); ++it) {
|
|
||||||
if (it.key() == DockerContainer::Dns) {
|
|
||||||
isDnsContainerInstalled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dns.first = dns1();
|
|
||||||
dns.second = dns2();
|
|
||||||
|
|
||||||
if (dns.first.isEmpty() || !NetworkUtilities::checkIPv4Format(dns.first)) {
|
|
||||||
if (isAmneziaDnsEnabled && isDnsContainerInstalled) {
|
|
||||||
dns.first = protocols::dns::amneziaDnsIp;
|
|
||||||
} else {
|
|
||||||
dns.first = primaryDns;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dns.second.isEmpty() || !NetworkUtilities::checkIPv4Format(dns.second)) {
|
|
||||||
dns.second = secondaryDns;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dns;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace amnezia
|
|
||||||
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
#ifndef SERVERCONFIG_H
|
|
||||||
#define SERVERCONFIG_H
|
|
||||||
|
|
||||||
#include <variant>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
#include "core/utils/containerEnum.h"
|
|
||||||
#include "core/utils/containers/containerUtils.h"
|
|
||||||
#include "core/utils/protocolEnum.h"
|
|
||||||
#include "core/models/selfhosted/selfHostedServerConfig.h"
|
|
||||||
#include "core/models/selfhosted/nativeServerConfig.h"
|
|
||||||
#include "core/models/api/apiV1ServerConfig.h"
|
|
||||||
#include "core/models/api/apiV2ServerConfig.h"
|
|
||||||
#include "core/models/containerConfig.h"
|
|
||||||
|
|
||||||
namespace amnezia
|
|
||||||
{
|
|
||||||
|
|
||||||
using namespace ContainerEnumNS;
|
|
||||||
|
|
||||||
struct ServerConfig {
|
|
||||||
using Variant = std::variant<
|
|
||||||
SelfHostedServerConfig,
|
|
||||||
NativeServerConfig,
|
|
||||||
ApiV1ServerConfig,
|
|
||||||
ApiV2ServerConfig
|
|
||||||
>;
|
|
||||||
|
|
||||||
Variant data;
|
|
||||||
|
|
||||||
ServerConfig() = default;
|
|
||||||
ServerConfig(const Variant& v) : data(v) {}
|
|
||||||
ServerConfig(Variant&& v) : data(std::move(v)) {}
|
|
||||||
|
|
||||||
template<typename T, typename = std::enable_if_t<!std::is_same<std::remove_cv_t<std::remove_reference_t<T>>, ServerConfig>::value>>
|
|
||||||
ServerConfig(const T& v) : data(v) {}
|
|
||||||
|
|
||||||
template<typename T, typename = std::enable_if_t<!std::is_same<std::remove_cv_t<std::remove_reference_t<T>>, ServerConfig>::value>>
|
|
||||||
ServerConfig(T&& v) : data(std::forward<T>(v)) {}
|
|
||||||
|
|
||||||
QString description() const;
|
|
||||||
QString hostName() const;
|
|
||||||
QString displayName() const;
|
|
||||||
QMap<DockerContainer, ContainerConfig> containers() const;
|
|
||||||
DockerContainer defaultContainer() const;
|
|
||||||
QString dns1() const;
|
|
||||||
QString dns2() const;
|
|
||||||
bool hasContainers() const;
|
|
||||||
ContainerConfig containerConfig(DockerContainer container) const;
|
|
||||||
|
|
||||||
int crc() const;
|
|
||||||
int configVersion() const;
|
|
||||||
|
|
||||||
bool isSelfHosted() const;
|
|
||||||
bool isNative() const;
|
|
||||||
bool isApiV1() const;
|
|
||||||
bool isApiV2() const;
|
|
||||||
bool isApiConfig() const;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T* as() {
|
|
||||||
return std::get_if<T>(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const T* as() const {
|
|
||||||
return std::get_if<T>(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject toJson() const;
|
|
||||||
static ServerConfig fromJson(const QJsonObject& json);
|
|
||||||
|
|
||||||
template<typename Visitor>
|
|
||||||
auto visit(Visitor&& visitor) {
|
|
||||||
return std::visit(std::forward<Visitor>(visitor), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Visitor>
|
|
||||||
auto visit(Visitor&& visitor) const {
|
|
||||||
return std::visit(std::forward<Visitor>(visitor), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
QPair<QString, QString> getDnsPair(bool isAmneziaDnsEnabled,
|
|
||||||
const QString &primaryDns,
|
|
||||||
const QString &secondaryDns) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace amnezia
|
|
||||||
|
|
||||||
#endif // SERVERCONFIG_H
|
|
||||||
|
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
#include "serverDescription.h"
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
#include "core/utils/serverConfigUtils.h"
|
||||||
|
#include "core/utils/constants/apiKeys.h"
|
||||||
|
#include "core/utils/constants/apiConstants.h"
|
||||||
|
#include "core/utils/constants/protocolConstants.h"
|
||||||
|
#include "core/utils/api/apiUtils.h"
|
||||||
|
#include "core/utils/containers/containerUtils.h"
|
||||||
|
#include "core/protocols/protocolUtils.h"
|
||||||
|
#include "core/models/protocols/awgProtocolConfig.h"
|
||||||
|
|
||||||
|
using namespace amnezia;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
bool computeHasInstalledVpnContainers(const QMap<DockerContainer, ContainerConfig> &containers)
|
||||||
|
{
|
||||||
|
for (auto it = containers.begin(); it != containers.end(); ++it) {
|
||||||
|
const DockerContainer container = it.key();
|
||||||
|
if (ContainerUtils::containerService(container) == ServiceType::Vpn || container == DockerContainer::SSXray) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ServerDescription buildBaseDescription(const T &server)
|
||||||
|
{
|
||||||
|
ServerDescription row;
|
||||||
|
row.hostName = server.hostName;
|
||||||
|
row.defaultContainer = server.defaultContainer;
|
||||||
|
row.primaryDnsIsAmnezia = (server.dns1 == protocols::dns::amneziaDnsIp);
|
||||||
|
row.hasInstalledVpnContainers = computeHasInstalledVpnContainers(server.containers);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getBaseDescription(const QMap<DockerContainer, ContainerConfig> &containers,
|
||||||
|
bool isAmneziaDnsEnabled,
|
||||||
|
bool hasWriteAccess,
|
||||||
|
bool primaryDnsIsAmnezia)
|
||||||
|
{
|
||||||
|
QString description;
|
||||||
|
if (hasWriteAccess) {
|
||||||
|
const bool isDnsInstalled = containers.contains(DockerContainer::Dns);
|
||||||
|
if (isAmneziaDnsEnabled && isDnsInstalled) {
|
||||||
|
description += QStringLiteral("Amnezia DNS | ");
|
||||||
|
}
|
||||||
|
} else if (primaryDnsIsAmnezia) {
|
||||||
|
description += QStringLiteral("Amnezia DNS | ");
|
||||||
|
}
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getProtocolName(DockerContainer defaultContainer, const QMap<DockerContainer, ContainerConfig> &containers)
|
||||||
|
{
|
||||||
|
QString containerName = ContainerUtils::containerHumanNames().value(defaultContainer);
|
||||||
|
QString protocolVersion;
|
||||||
|
|
||||||
|
if (ContainerUtils::isAwgContainer(defaultContainer)) {
|
||||||
|
const auto it = containers.constFind(defaultContainer);
|
||||||
|
if (it != containers.cend()) {
|
||||||
|
if (const AwgProtocolConfig *awg = it->getAwgProtocolConfig()) {
|
||||||
|
protocolVersion = ProtocolUtils::getProtocolVersionString(awg->toJson());
|
||||||
|
if (defaultContainer == DockerContainer::Awg && !awg->serverConfig.isThirdPartyConfig) {
|
||||||
|
containerName = QStringLiteral("AmneziaWG Legacy");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return containerName + protocolVersion + QStringLiteral(" | ");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace amnezia
|
||||||
|
{
|
||||||
|
|
||||||
|
ServerDescription buildServerDescription(const SelfHostedAdminServerConfig &server, bool isAmneziaDnsEnabled)
|
||||||
|
{
|
||||||
|
ServerDescription row = buildBaseDescription(server);
|
||||||
|
row.selfHostedSshCredentials.hostName = server.hostName;
|
||||||
|
row.selfHostedSshCredentials.userName = server.userName;
|
||||||
|
row.selfHostedSshCredentials.secretData = server.password;
|
||||||
|
row.selfHostedSshCredentials.port = server.port > 0 ? server.port : 22;
|
||||||
|
|
||||||
|
row.hasWriteAccess = !row.selfHostedSshCredentials.userName.isEmpty()
|
||||||
|
&& !row.selfHostedSshCredentials.secretData.isEmpty();
|
||||||
|
|
||||||
|
row.serverName = server.displayName;
|
||||||
|
row.baseDescription = getBaseDescription(server.containers, isAmneziaDnsEnabled, row.hasWriteAccess, row.primaryDnsIsAmnezia);
|
||||||
|
|
||||||
|
const QString protocolName = getProtocolName(server.defaultContainer, server.containers);
|
||||||
|
row.expandedServerDescription = row.baseDescription + row.hostName;
|
||||||
|
row.collapsedServerDescription = row.baseDescription + protocolName + row.hostName;
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerDescription buildServerDescription(const SelfHostedUserServerConfig &server, bool isAmneziaDnsEnabled)
|
||||||
|
{
|
||||||
|
ServerDescription row = buildBaseDescription(server);
|
||||||
|
row.selfHostedSshCredentials.hostName = server.hostName;
|
||||||
|
row.selfHostedSshCredentials.port = 22;
|
||||||
|
row.hasWriteAccess = false;
|
||||||
|
|
||||||
|
row.serverName = server.displayName;
|
||||||
|
row.baseDescription = getBaseDescription(server.containers, isAmneziaDnsEnabled, row.hasWriteAccess, row.primaryDnsIsAmnezia);
|
||||||
|
|
||||||
|
const QString protocolName = getProtocolName(server.defaultContainer, server.containers);
|
||||||
|
row.expandedServerDescription = row.baseDescription + row.hostName;
|
||||||
|
row.collapsedServerDescription = row.baseDescription + protocolName + row.hostName;
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerDescription buildServerDescription(const NativeServerConfig &server, bool isAmneziaDnsEnabled)
|
||||||
|
{
|
||||||
|
ServerDescription row = buildBaseDescription(server);
|
||||||
|
row.hasWriteAccess = false;
|
||||||
|
|
||||||
|
row.serverName = server.displayName;
|
||||||
|
row.baseDescription = getBaseDescription(server.containers, isAmneziaDnsEnabled, row.hasWriteAccess, row.primaryDnsIsAmnezia);
|
||||||
|
|
||||||
|
const QString protocolName = getProtocolName(server.defaultContainer, server.containers);
|
||||||
|
row.expandedServerDescription = row.baseDescription + row.hostName;
|
||||||
|
row.collapsedServerDescription = row.baseDescription + protocolName + row.hostName;
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerDescription buildServerDescription(const LegacyApiServerConfig &server, bool /*isAmneziaDnsEnabled*/)
|
||||||
|
{
|
||||||
|
ServerDescription row = buildBaseDescription(server);
|
||||||
|
row.configVersion = serverConfigUtils::ConfigSource::Telegram;
|
||||||
|
row.isApiV1 = true;
|
||||||
|
row.isServerFromGatewayApi = false;
|
||||||
|
row.hasWriteAccess = false;
|
||||||
|
|
||||||
|
row.serverName = server.displayName;
|
||||||
|
row.baseDescription = server.description;
|
||||||
|
|
||||||
|
const QString fullDescriptionForCollapsed = row.baseDescription;
|
||||||
|
row.collapsedServerDescription = fullDescriptionForCollapsed;
|
||||||
|
row.expandedServerDescription = fullDescriptionForCollapsed;
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerDescription buildServerDescription(const ApiV2ServerConfig &server, bool /*isAmneziaDnsEnabled*/)
|
||||||
|
{
|
||||||
|
ServerDescription row = buildBaseDescription(server);
|
||||||
|
row.configVersion = serverConfigUtils::ConfigSource::AmneziaGateway;
|
||||||
|
row.isApiV2 = true;
|
||||||
|
row.isServerFromGatewayApi = true;
|
||||||
|
row.isPremium = server.isPremium() || server.isExternalPremium();
|
||||||
|
row.hasWriteAccess = false;
|
||||||
|
|
||||||
|
row.serverName = server.displayName;
|
||||||
|
row.baseDescription = server.apiConfig.serverCountryCode.isEmpty() ? server.description : server.apiConfig.serverCountryName;
|
||||||
|
|
||||||
|
row.isCountrySelectionAvailable = !server.apiConfig.availableCountries.isEmpty();
|
||||||
|
row.apiAvailableCountries = server.apiConfig.availableCountries;
|
||||||
|
row.apiServerCountryCode = server.apiConfig.serverCountryCode;
|
||||||
|
|
||||||
|
row.isAdVisible = server.apiConfig.serviceInfo.isAdVisible;
|
||||||
|
row.adHeader = server.apiConfig.serviceInfo.adHeader;
|
||||||
|
row.adDescription = server.apiConfig.serviceInfo.adDescription;
|
||||||
|
row.adEndpoint = server.apiConfig.serviceInfo.adEndpoint;
|
||||||
|
row.isRenewalAvailable = server.apiConfig.serviceInfo.isRenewalAvailable;
|
||||||
|
|
||||||
|
if (!server.apiConfig.isInAppPurchase) {
|
||||||
|
if (server.apiConfig.subscriptionExpiredByServer) {
|
||||||
|
row.isSubscriptionExpired = true;
|
||||||
|
} else if (!server.apiConfig.subscription.endDate.isEmpty()) {
|
||||||
|
row.isSubscriptionExpired = apiUtils::isSubscriptionExpired(server.apiConfig.subscription.endDate);
|
||||||
|
row.isSubscriptionExpiringSoon = apiUtils::isSubscriptionExpiringSoon(server.apiConfig.subscription.endDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString fullDescriptionForCollapsed = row.baseDescription;
|
||||||
|
row.collapsedServerDescription = fullDescriptionForCollapsed;
|
||||||
|
row.expandedServerDescription = fullDescriptionForCollapsed;
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#ifndef SERVERDESCRIPTION_H
|
||||||
|
#define SERVERDESCRIPTION_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QJsonArray>
|
||||||
|
|
||||||
|
#include "core/utils/containerEnum.h"
|
||||||
|
#include "core/utils/selfhosted/sshSession.h"
|
||||||
|
#include "core/models/selfhosted/selfHostedAdminServerConfig.h"
|
||||||
|
#include "core/models/selfhosted/selfHostedUserServerConfig.h"
|
||||||
|
#include "core/models/selfhosted/nativeServerConfig.h"
|
||||||
|
#include "core/models/api/legacyApiServerConfig.h"
|
||||||
|
#include "core/models/api/apiV2ServerConfig.h"
|
||||||
|
|
||||||
|
namespace amnezia
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ServerDescription
|
||||||
|
{
|
||||||
|
QString serverId;
|
||||||
|
|
||||||
|
QString serverName;
|
||||||
|
QString baseDescription;
|
||||||
|
QString hostName;
|
||||||
|
|
||||||
|
int configVersion = 0;
|
||||||
|
|
||||||
|
ServerCredentials selfHostedSshCredentials;
|
||||||
|
bool hasWriteAccess = false;
|
||||||
|
|
||||||
|
bool primaryDnsIsAmnezia = false;
|
||||||
|
DockerContainer defaultContainer = DockerContainer::None;
|
||||||
|
bool hasInstalledVpnContainers = false;
|
||||||
|
|
||||||
|
bool isApiV1 = false;
|
||||||
|
bool isApiV2 = false;
|
||||||
|
bool isServerFromGatewayApi = false;
|
||||||
|
bool isPremium = false;
|
||||||
|
|
||||||
|
bool isCountrySelectionAvailable = false;
|
||||||
|
QJsonArray apiAvailableCountries;
|
||||||
|
QString apiServerCountryCode;
|
||||||
|
|
||||||
|
bool isAdVisible = false;
|
||||||
|
QString adHeader;
|
||||||
|
QString adDescription;
|
||||||
|
QString adEndpoint;
|
||||||
|
bool isRenewalAvailable = false;
|
||||||
|
bool isSubscriptionExpired = false;
|
||||||
|
bool isSubscriptionExpiringSoon = false;
|
||||||
|
|
||||||
|
QString collapsedServerDescription;
|
||||||
|
QString expandedServerDescription;
|
||||||
|
};
|
||||||
|
|
||||||
|
ServerDescription buildServerDescription(const SelfHostedAdminServerConfig &server, bool isAmneziaDnsEnabled);
|
||||||
|
ServerDescription buildServerDescription(const SelfHostedUserServerConfig &server, bool isAmneziaDnsEnabled);
|
||||||
|
ServerDescription buildServerDescription(const NativeServerConfig &server, bool isAmneziaDnsEnabled);
|
||||||
|
ServerDescription buildServerDescription(const LegacyApiServerConfig &server, bool isAmneziaDnsEnabled);
|
||||||
|
ServerDescription buildServerDescription(const ApiV2ServerConfig &server, bool isAmneziaDnsEnabled);
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -68,7 +68,10 @@ QMap<Proto, QString> ProtocolUtils::protocolHumanNames()
|
|||||||
{ Proto::TorWebSite, "Website in Tor network" },
|
{ Proto::TorWebSite, "Website in Tor network" },
|
||||||
{ Proto::Dns, "DNS Service" },
|
{ Proto::Dns, "DNS Service" },
|
||||||
{ Proto::Sftp, QObject::tr("SFTP service") },
|
{ Proto::Sftp, QObject::tr("SFTP service") },
|
||||||
{ Proto::Socks5Proxy, QObject::tr("SOCKS5 proxy server") } };
|
{ Proto::Socks5Proxy, QObject::tr("SOCKS5 proxy server") },
|
||||||
|
{ Proto::MtProxy, QObject::tr("MTProxy (Telegram)") },
|
||||||
|
{ Proto::Telemt, QObject::tr("Telemt (Telegram)") },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<Proto, QString> ProtocolUtils::protocolDescriptions()
|
QMap<Proto, QString> ProtocolUtils::protocolDescriptions()
|
||||||
@@ -92,6 +95,8 @@ ServiceType ProtocolUtils::protocolService(Proto p)
|
|||||||
case Proto::Dns: return ServiceType::Other;
|
case Proto::Dns: return ServiceType::Other;
|
||||||
case Proto::Sftp: return ServiceType::Other;
|
case Proto::Sftp: return ServiceType::Other;
|
||||||
case Proto::Socks5Proxy: return ServiceType::Other;
|
case Proto::Socks5Proxy: return ServiceType::Other;
|
||||||
|
case Proto::MtProxy: return ServiceType::Other;
|
||||||
|
case Proto::Telemt: return ServiceType::Other;
|
||||||
default: return ServiceType::Other;
|
default: return ServiceType::Other;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,6 +109,8 @@ int ProtocolUtils::getPortForInstall(Proto p)
|
|||||||
case OpenVpn:
|
case OpenVpn:
|
||||||
case Socks5Proxy:
|
case Socks5Proxy:
|
||||||
return QRandomGenerator::global()->bounded(30000, 50000);
|
return QRandomGenerator::global()->bounded(30000, 50000);
|
||||||
|
case MtProxy:
|
||||||
|
case Telemt:
|
||||||
default:
|
default:
|
||||||
return defaultPort(p);
|
return defaultPort(p);
|
||||||
}
|
}
|
||||||
@@ -123,6 +130,8 @@ int ProtocolUtils::defaultPort(Proto p)
|
|||||||
case Proto::Dns: return 53;
|
case Proto::Dns: return 53;
|
||||||
case Proto::Sftp: return 222;
|
case Proto::Sftp: return 222;
|
||||||
case Proto::Socks5Proxy: return 38080;
|
case Proto::Socks5Proxy: return 38080;
|
||||||
|
case Proto::MtProxy: return QString(protocols::mtProxy::defaultPort).toInt();
|
||||||
|
case Proto::Telemt: return QString(protocols::telemt::defaultPort).toInt();
|
||||||
default: return -1;
|
default: return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,6 +150,8 @@ bool ProtocolUtils::defaultPortChangeable(Proto p)
|
|||||||
case Proto::Dns: return false;
|
case Proto::Dns: return false;
|
||||||
case Proto::Sftp: return true;
|
case Proto::Sftp: return true;
|
||||||
case Proto::Socks5Proxy: return true;
|
case Proto::Socks5Proxy: return true;
|
||||||
|
case Proto::MtProxy: return true;
|
||||||
|
case Proto::Telemt: return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,6 +172,8 @@ TransportProto ProtocolUtils::defaultTransportProto(Proto p)
|
|||||||
case Proto::Dns: return TransportProto::Udp;
|
case Proto::Dns: return TransportProto::Udp;
|
||||||
case Proto::Sftp: return TransportProto::Tcp;
|
case Proto::Sftp: return TransportProto::Tcp;
|
||||||
case Proto::Socks5Proxy: return TransportProto::Tcp;
|
case Proto::Socks5Proxy: return TransportProto::Tcp;
|
||||||
|
case Proto::MtProxy: return TransportProto::Tcp;
|
||||||
|
case Proto::Telemt: return TransportProto::Tcp;
|
||||||
default: return TransportProto::Udp;
|
default: return TransportProto::Udp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,9 +193,10 @@ bool ProtocolUtils::defaultTransportProtoChangeable(Proto p)
|
|||||||
case Proto::Dns: return false;
|
case Proto::Dns: return false;
|
||||||
case Proto::Sftp: return false;
|
case Proto::Sftp: return false;
|
||||||
case Proto::Socks5Proxy: return false;
|
case Proto::Socks5Proxy: return false;
|
||||||
|
case Proto::MtProxy: return false;
|
||||||
|
case Proto::Telemt: return false;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ProtocolUtils::key_proto_config_data(Proto p)
|
QString ProtocolUtils::key_proto_config_data(Proto p)
|
||||||
@@ -208,4 +222,3 @@ QString ProtocolUtils::getProtocolVersionString(const QJsonObject &protocolConfi
|
|||||||
if (version == protocols::awg::awgV1_5) return QObject::tr(" (version 1.5)");
|
if (version == protocols::awg::awgV1_5) return QObject::tr(" (version 1.5)");
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,16 @@
|
|||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
#include "core/utils/errorCodes.h"
|
#include "core/utils/errorCodes.h"
|
||||||
#include "core/utils/routeModes.h"
|
#include "core/utils/routeModes.h"
|
||||||
#include "core/utils/commonStructs.h"
|
#include "core/utils/commonStructs.h"
|
||||||
#include "core/utils/api/apiEnums.h"
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/utils/constants/apiKeys.h"
|
#include "core/utils/constants/apiKeys.h"
|
||||||
#include "core/utils/constants/apiConstants.h"
|
#include "core/utils/constants/apiConstants.h"
|
||||||
#include "core/models/serverConfig.h"
|
#include "core/utils/constants/configKeys.h"
|
||||||
#include "core/utils/networkUtilities.h"
|
#include "core/utils/networkUtilities.h"
|
||||||
|
|
||||||
using namespace amnezia;
|
using namespace amnezia;
|
||||||
|
|||||||
@@ -1,26 +1,44 @@
|
|||||||
#include "secureServersRepository.h"
|
#include "secureServersRepository.h"
|
||||||
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonValue>
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
#include "core/utils/api/apiEnums.h"
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/utils/constants/apiKeys.h"
|
#include "core/utils/constants/apiKeys.h"
|
||||||
#include "core/utils/constants/apiConstants.h"
|
|
||||||
#include "core/models/serverConfig.h"
|
|
||||||
#include "core/models/containerConfig.h"
|
|
||||||
#include "core/utils/protocolEnum.h"
|
|
||||||
#include "core/protocols/protocolUtils.h"
|
|
||||||
#include "core/utils/constants/configKeys.h"
|
#include "core/utils/constants/configKeys.h"
|
||||||
#include "core/utils/constants/protocolConstants.h"
|
|
||||||
|
|
||||||
SecureServersRepository::SecureServersRepository(SecureQSettings* settings, QObject *parent)
|
using namespace amnezia;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
QString readStorageServerId(const QJsonObject &json)
|
||||||
|
{
|
||||||
|
return json.value(QString(configKey::storageServerId)).toString().trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject withoutStorageServerId(const QJsonObject &json)
|
||||||
|
{
|
||||||
|
QJsonObject o = json;
|
||||||
|
o.remove(QString(configKey::storageServerId));
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject embedStorageServerId(const QString &serverId, const QJsonObject &payloadSansId)
|
||||||
|
{
|
||||||
|
QJsonObject o = payloadSansId;
|
||||||
|
o.insert(QString(configKey::storageServerId), serverId);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
SecureServersRepository::SecureServersRepository(SecureQSettings *settings, QObject *parent)
|
||||||
: QObject(parent), m_settings(settings)
|
: QObject(parent), m_settings(settings)
|
||||||
{
|
{
|
||||||
QJsonArray arr = QJsonDocument::fromJson(value("Servers/serversList").toByteArray()).array();
|
loadFromStorage();
|
||||||
for (const QJsonValue &val : arr) {
|
persistDefaultServerFields();
|
||||||
m_servers.append(ServerConfig::fromJson(val.toObject()));
|
|
||||||
}
|
|
||||||
m_defaultServerIndex = value("Servers/defaultServerIndex", 0).toInt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant SecureServersRepository::value(const QString &key, const QVariant &defaultValue) const
|
QVariant SecureServersRepository::value(const QString &key, const QVariant &defaultValue) const
|
||||||
@@ -33,216 +51,322 @@ void SecureServersRepository::setValue(const QString &key, const QVariant &value
|
|||||||
m_settings->setValue(key, value);
|
m_settings->setValue(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SecureServersRepository::clearServerStateMaps()
|
||||||
|
{
|
||||||
|
m_serverJsonById.clear();
|
||||||
|
m_orderedServerIds.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SecureServersRepository::normalizedOrGeneratedServerId(const QString &candidateId) const
|
||||||
|
{
|
||||||
|
const QString trimmed = candidateId.trimmed();
|
||||||
|
if (!trimmed.isEmpty() && !m_serverJsonById.contains(trimmed)) {
|
||||||
|
return trimmed;
|
||||||
|
}
|
||||||
|
return QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecureServersRepository::updateDefaultServerFromStorage()
|
||||||
|
{
|
||||||
|
const QString storedDefaultId = value(QStringLiteral("Servers/defaultServerId"), QString()).toString();
|
||||||
|
if (!storedDefaultId.isEmpty() && m_serverJsonById.contains(storedDefaultId)) {
|
||||||
|
m_defaultServerId = storedDefaultId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int storedDefaultIndex = value("Servers/defaultServerIndex", 0).toInt();
|
||||||
|
if (storedDefaultIndex >= 0 && storedDefaultIndex < m_orderedServerIds.size()) {
|
||||||
|
m_defaultServerId = m_orderedServerIds.at(storedDefaultIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_orderedServerIds.isEmpty()) {
|
||||||
|
m_defaultServerId = m_orderedServerIds.first();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_defaultServerId.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecureServersRepository::persistDefaultServerFields()
|
||||||
|
{
|
||||||
|
if (m_orderedServerIds.isEmpty()) {
|
||||||
|
m_defaultServerId.clear();
|
||||||
|
} else if (!m_orderedServerIds.contains(m_defaultServerId)) {
|
||||||
|
m_defaultServerId = m_orderedServerIds.first();
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue("Servers/defaultServerId", m_defaultServerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecureServersRepository::loadFromStorage()
|
||||||
|
{
|
||||||
|
clearServerStateMaps();
|
||||||
|
|
||||||
|
const QJsonArray serversArray =
|
||||||
|
QJsonDocument::fromJson(value(QStringLiteral("Servers/serversList"), QByteArray()).toByteArray())
|
||||||
|
.array();
|
||||||
|
|
||||||
|
for (int i = 0; i < serversArray.size(); ++i) {
|
||||||
|
const QJsonObject json = serversArray.at(i).toObject();
|
||||||
|
const QString candidateId = readStorageServerId(json);
|
||||||
|
const QString serverId = normalizedOrGeneratedServerId(candidateId);
|
||||||
|
const QJsonObject strippedJson = withoutStorageServerId(json);
|
||||||
|
const serverConfigUtils::ConfigType kind = serverConfigUtils::configTypeFromJson(strippedJson);
|
||||||
|
|
||||||
|
if (m_serverJsonById.contains(serverId) || kind == serverConfigUtils::ConfigType::Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_serverJsonById.insert(serverId, embedStorageServerId(serverId, strippedJson));
|
||||||
|
m_orderedServerIds.append(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDefaultServerFromStorage();
|
||||||
|
}
|
||||||
|
|
||||||
void SecureServersRepository::syncToStorage()
|
void SecureServersRepository::syncToStorage()
|
||||||
{
|
{
|
||||||
QJsonArray arr;
|
QJsonArray serversArray;
|
||||||
for (const ServerConfig &cfg : m_servers) {
|
|
||||||
arr.append(cfg.toJson());
|
for (const QString &serverId : m_orderedServerIds) {
|
||||||
|
if (!m_serverJsonById.contains(serverId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
serversArray.append(m_serverJsonById.value(serverId));
|
||||||
}
|
}
|
||||||
setValue("Servers/serversList", QJsonDocument(arr).toJson());
|
|
||||||
|
setValue("Servers/serversList", QJsonDocument(serversArray).toJson());
|
||||||
|
persistDefaultServerFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SecureServersRepository::invalidateCache()
|
void SecureServersRepository::invalidateCache()
|
||||||
{
|
{
|
||||||
m_servers.clear();
|
loadFromStorage();
|
||||||
QJsonArray arr = QJsonDocument::fromJson(value("Servers/serversList").toByteArray()).array();
|
|
||||||
for (const QJsonValue &val : arr) {
|
|
||||||
m_servers.append(ServerConfig::fromJson(val.toObject()));
|
|
||||||
}
|
|
||||||
m_defaultServerIndex = value("Servers/defaultServerIndex", 0).toInt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SecureServersRepository::setServersArray(const QJsonArray &servers)
|
void SecureServersRepository::clearServers()
|
||||||
{
|
{
|
||||||
m_servers.clear();
|
clearServerStateMaps();
|
||||||
for (const QJsonValue &val : servers) {
|
|
||||||
m_servers.append(ServerConfig::fromJson(val.toObject()));
|
m_defaultServerId.clear();
|
||||||
}
|
|
||||||
syncToStorage();
|
syncToStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SecureServersRepository::addServer(const ServerConfig &server)
|
QString SecureServersRepository::addServer(const QString &serverId, const QJsonObject &serverJson, serverConfigUtils::ConfigType kind)
|
||||||
{
|
{
|
||||||
m_servers.append(server);
|
const QString id = normalizedOrGeneratedServerId(serverId);
|
||||||
|
if (m_serverJsonById.contains(id) || kind == serverConfigUtils::ConfigType::Invalid) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
const QJsonObject strippedJson = withoutStorageServerId(serverJson);
|
||||||
|
if (serverConfigUtils::configTypeFromJson(strippedJson) != kind) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
m_serverJsonById.insert(id, embedStorageServerId(id, strippedJson));
|
||||||
|
|
||||||
|
m_orderedServerIds.append(id);
|
||||||
|
|
||||||
|
if (m_defaultServerId.isEmpty()) {
|
||||||
|
m_defaultServerId = id;
|
||||||
|
}
|
||||||
|
|
||||||
syncToStorage();
|
syncToStorage();
|
||||||
emit serverAdded(server);
|
emit serverAdded(id);
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SecureServersRepository::editServer(int index, const ServerConfig &server)
|
void SecureServersRepository::editServer(const QString &serverId, const QJsonObject &serverJson, serverConfigUtils::ConfigType kind)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= m_servers.size()) {
|
if (indexOfServerId(serverId) < 0 || kind == serverConfigUtils::ConfigType::Invalid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_servers.replace(index, server);
|
if (!m_serverJsonById.contains(serverId)) {
|
||||||
syncToStorage();
|
|
||||||
emit serverEdited(index, server);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecureServersRepository::removeServer(int index)
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= m_servers.size()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int defaultIndex = m_defaultServerIndex;
|
|
||||||
m_servers.removeAt(index);
|
|
||||||
|
|
||||||
if (defaultIndex == index) {
|
const QJsonObject oldJson = m_serverJsonById.value(serverId);
|
||||||
setDefaultServer(0);
|
const serverConfigUtils::ConfigType oldKind = serverConfigUtils::configTypeFromJson(withoutStorageServerId(oldJson));
|
||||||
} else if (defaultIndex > index) {
|
|
||||||
setDefaultServer(defaultIndex - 1);
|
m_serverJsonById.remove(serverId);
|
||||||
|
|
||||||
|
const QJsonObject strippedNew = withoutStorageServerId(serverJson);
|
||||||
|
if (serverConfigUtils::configTypeFromJson(strippedNew) != kind) {
|
||||||
|
const QJsonObject strippedOld = withoutStorageServerId(oldJson);
|
||||||
|
if (oldKind != serverConfigUtils::ConfigType::Invalid && serverConfigUtils::configTypeFromJson(strippedOld) == oldKind) {
|
||||||
|
m_serverJsonById.insert(serverId, embedStorageServerId(serverId, strippedOld));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_serverJsonById.insert(serverId, embedStorageServerId(serverId, strippedNew));
|
||||||
|
|
||||||
|
syncToStorage();
|
||||||
|
emit serverEdited(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecureServersRepository::removeServer(const QString &serverId)
|
||||||
|
{
|
||||||
|
const int removedIndex = indexOfServerId(serverId);
|
||||||
|
if (removedIndex < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!m_serverJsonById.contains(serverId)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_servers.isEmpty()) {
|
const QString previousDefaultId = m_defaultServerId;
|
||||||
setDefaultServer(0);
|
const int previousDefaultIndex = defaultServerIndex();
|
||||||
|
|
||||||
|
m_serverJsonById.remove(serverId);
|
||||||
|
m_orderedServerIds.removeAt(removedIndex);
|
||||||
|
|
||||||
|
if (m_orderedServerIds.isEmpty()) {
|
||||||
|
m_defaultServerId.clear();
|
||||||
|
} else if (m_defaultServerId == serverId) {
|
||||||
|
const int fallbackIndex = qMin(removedIndex, m_orderedServerIds.size() - 1);
|
||||||
|
m_defaultServerId = m_orderedServerIds.at(fallbackIndex);
|
||||||
|
} else if (!m_orderedServerIds.contains(m_defaultServerId)) {
|
||||||
|
m_defaultServerId = m_orderedServerIds.first();
|
||||||
|
}
|
||||||
|
|
||||||
|
const int newDefaultIndex = defaultServerIndex();
|
||||||
|
if (previousDefaultId != m_defaultServerId || previousDefaultIndex != newDefaultIndex) {
|
||||||
|
emit defaultServerChanged(m_defaultServerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
syncToStorage();
|
syncToStorage();
|
||||||
emit serverRemoved(index);
|
emit serverRemoved(serverId, removedIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerConfig SecureServersRepository::server(int index) const
|
serverConfigUtils::ConfigType SecureServersRepository::serverKind(const QString &serverId) const
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= m_servers.size()) {
|
const auto it = m_serverJsonById.constFind(serverId);
|
||||||
return SelfHostedServerConfig{};
|
if (it == m_serverJsonById.constEnd()) {
|
||||||
|
return serverConfigUtils::ConfigType::Invalid;
|
||||||
}
|
}
|
||||||
return m_servers.at(index);
|
return serverConfigUtils::configTypeFromJson(withoutStorageServerId(it.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<ServerConfig> SecureServersRepository::servers() const
|
std::optional<SelfHostedAdminServerConfig> SecureServersRepository::selfHostedAdminConfig(const QString &serverId) const
|
||||||
{
|
{
|
||||||
return m_servers;
|
const auto it = m_serverJsonById.constFind(serverId);
|
||||||
|
if (it == m_serverJsonById.constEnd()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
const QJsonObject strippedJson = withoutStorageServerId(it.value());
|
||||||
|
if (serverConfigUtils::configTypeFromJson(strippedJson) != serverConfigUtils::ConfigType::SelfHostedAdmin) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return SelfHostedAdminServerConfig::fromJson(strippedJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<SelfHostedUserServerConfig> SecureServersRepository::selfHostedUserConfig(const QString &serverId) const
|
||||||
|
{
|
||||||
|
const auto it = m_serverJsonById.constFind(serverId);
|
||||||
|
if (it == m_serverJsonById.constEnd()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
const QJsonObject strippedJson = withoutStorageServerId(it.value());
|
||||||
|
if (serverConfigUtils::configTypeFromJson(strippedJson) != serverConfigUtils::ConfigType::SelfHostedUser) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return SelfHostedUserServerConfig::fromJson(strippedJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<NativeServerConfig> SecureServersRepository::nativeConfig(const QString &serverId) const
|
||||||
|
{
|
||||||
|
const auto it = m_serverJsonById.constFind(serverId);
|
||||||
|
if (it == m_serverJsonById.constEnd()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
const QJsonObject strippedJson = withoutStorageServerId(it.value());
|
||||||
|
if (serverConfigUtils::configTypeFromJson(strippedJson) != serverConfigUtils::ConfigType::Native) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return NativeServerConfig::fromJson(strippedJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ApiV2ServerConfig> SecureServersRepository::apiV2Config(const QString &serverId) const
|
||||||
|
{
|
||||||
|
const auto it = m_serverJsonById.constFind(serverId);
|
||||||
|
if (it == m_serverJsonById.constEnd()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
const QJsonObject strippedJson = withoutStorageServerId(it.value());
|
||||||
|
if (!serverConfigUtils::isApiV2Subscription(serverConfigUtils::configTypeFromJson(strippedJson))) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return ApiV2ServerConfig::fromJson(strippedJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<LegacyApiServerConfig> SecureServersRepository::legacyApiConfig(const QString &serverId) const
|
||||||
|
{
|
||||||
|
const auto it = m_serverJsonById.constFind(serverId);
|
||||||
|
if (it == m_serverJsonById.constEnd()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
const QJsonObject strippedJson = withoutStorageServerId(it.value());
|
||||||
|
if (!serverConfigUtils::isLegacyApiSubscription(serverConfigUtils::configTypeFromJson(strippedJson))) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return LegacyApiServerConfig::fromJson(strippedJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SecureServersRepository::serversCount() const
|
int SecureServersRepository::serversCount() const
|
||||||
{
|
{
|
||||||
return m_servers.size();
|
return m_orderedServerIds.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SecureServersRepository::serverIdAt(int index) const
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= m_orderedServerIds.size()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return m_orderedServerIds.at(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<QString> SecureServersRepository::orderedServerIds() const
|
||||||
|
{
|
||||||
|
return m_orderedServerIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SecureServersRepository::indexOfServerId(const QString &serverId) const
|
||||||
|
{
|
||||||
|
return m_orderedServerIds.indexOf(serverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SecureServersRepository::defaultServerIndex() const
|
int SecureServersRepository::defaultServerIndex() const
|
||||||
{
|
{
|
||||||
return m_defaultServerIndex;
|
if (m_orderedServerIds.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const int idx = m_orderedServerIds.indexOf(m_defaultServerId);
|
||||||
|
return idx >= 0 ? idx : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SecureServersRepository::setDefaultServer(int index)
|
QString SecureServersRepository::defaultServerId() const
|
||||||
{
|
{
|
||||||
if (index < 0) {
|
return m_defaultServerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecureServersRepository::setDefaultServer(const QString &serverId)
|
||||||
|
{
|
||||||
|
if (m_orderedServerIds.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_servers.size() > 0 && index >= m_servers.size()) {
|
if (!m_serverJsonById.contains(serverId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_servers.isEmpty() && index != 0) {
|
|
||||||
|
if (indexOfServerId(serverId) < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_defaultServerIndex == index) {
|
|
||||||
|
if (m_defaultServerId == serverId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_defaultServerIndex = index;
|
|
||||||
setValue("Servers/defaultServerIndex", index);
|
|
||||||
emit defaultServerChanged(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecureServersRepository::setDefaultContainer(int serverIndex, DockerContainer container)
|
m_defaultServerId = serverId;
|
||||||
{
|
persistDefaultServerFields();
|
||||||
ServerConfig config = server(serverIndex);
|
emit defaultServerChanged(m_defaultServerId);
|
||||||
config.visit([container](auto& arg) {
|
|
||||||
arg.defaultContainer = container;
|
|
||||||
});
|
|
||||||
editServer(serverIndex, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
ContainerConfig SecureServersRepository::containerConfig(int serverIndex, DockerContainer container) const
|
|
||||||
{
|
|
||||||
ServerConfig config = server(serverIndex);
|
|
||||||
return config.containerConfig(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecureServersRepository::setContainerConfig(int serverIndex, DockerContainer container, const ContainerConfig &config)
|
|
||||||
{
|
|
||||||
ServerConfig serverConfig = server(serverIndex);
|
|
||||||
serverConfig.visit([container, &config](auto& arg) {
|
|
||||||
arg.containers[container] = config;
|
|
||||||
});
|
|
||||||
editServer(serverIndex, serverConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecureServersRepository::clearLastConnectionConfig(int serverIndex, DockerContainer container)
|
|
||||||
{
|
|
||||||
ServerConfig serverConfig = server(serverIndex);
|
|
||||||
ContainerConfig containerCfg = serverConfig.containerConfig(container);
|
|
||||||
|
|
||||||
containerCfg.protocolConfig.clearClientConfig();
|
|
||||||
|
|
||||||
setContainerConfig(serverIndex, container, containerCfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerCredentials SecureServersRepository::serverCredentials(int index) const
|
|
||||||
{
|
|
||||||
ServerConfig config = server(index);
|
|
||||||
|
|
||||||
if (config.isSelfHosted()) {
|
|
||||||
const SelfHostedServerConfig* selfHosted = config.as<SelfHostedServerConfig>();
|
|
||||||
if (!selfHosted) return ServerCredentials();
|
|
||||||
auto creds = selfHosted->credentials();
|
|
||||||
if (creds.has_value()) {
|
|
||||||
return creds.value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ServerCredentials{};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SecureServersRepository::hasServerWithVpnKey(const QString &vpnKey) const
|
|
||||||
{
|
|
||||||
QString normalizedInput = vpnKey.trimmed();
|
|
||||||
if (normalizedInput.startsWith(QStringLiteral("vpn://"), Qt::CaseInsensitive)) {
|
|
||||||
normalizedInput = normalizedInput.mid(QStringLiteral("vpn://").size());
|
|
||||||
}
|
|
||||||
if (normalizedInput.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<ServerConfig> serversList = servers();
|
|
||||||
for (const ServerConfig& serverConfig : serversList) {
|
|
||||||
if (serverConfig.isApiV1()) {
|
|
||||||
const ApiV1ServerConfig* apiV1 = serverConfig.as<ApiV1ServerConfig>();
|
|
||||||
if (!apiV1) continue;
|
|
||||||
QString storedKey = apiV1->vpnKey();
|
|
||||||
if (storedKey.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
QString normalizedStored = storedKey.trimmed();
|
|
||||||
if (normalizedStored.startsWith(QStringLiteral("vpn://"), Qt::CaseInsensitive)) {
|
|
||||||
normalizedStored = normalizedStored.mid(QStringLiteral("vpn://").size());
|
|
||||||
}
|
|
||||||
if (normalizedInput == normalizedStored) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (serverConfig.isApiV2()) {
|
|
||||||
const ApiV2ServerConfig* apiV2 = serverConfig.as<ApiV2ServerConfig>();
|
|
||||||
if (!apiV2) continue;
|
|
||||||
QString storedKey = apiV2->vpnKey();
|
|
||||||
if (storedKey.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
QString normalizedStored = storedKey.trimmed();
|
|
||||||
if (normalizedStored.startsWith(QStringLiteral("vpn://"), Qt::CaseInsensitive)) {
|
|
||||||
normalizedStored = normalizedStored.mid(QStringLiteral("vpn://").size());
|
|
||||||
}
|
|
||||||
if (normalizedInput == normalizedStored) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SecureServersRepository::hasServerWithCrc(quint16 crc) const
|
|
||||||
{
|
|
||||||
for (const ServerConfig& serverConfig : m_servers) {
|
|
||||||
if (static_cast<quint16>(serverConfig.crc()) == crc) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
#ifndef SECURESERVERSREPOSITORY_H
|
#ifndef SECURESERVERSREPOSITORY_H
|
||||||
#define SECURESERVERSREPOSITORY_H
|
#define SECURESERVERSREPOSITORY_H
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QJsonObject>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "core/models/serverConfig.h"
|
#include "core/models/selfhosted/selfHostedAdminServerConfig.h"
|
||||||
|
#include "core/models/selfhosted/selfHostedUserServerConfig.h"
|
||||||
|
#include "core/models/selfhosted/nativeServerConfig.h"
|
||||||
|
#include "core/models/api/apiV2ServerConfig.h"
|
||||||
|
#include "core/models/api/legacyApiServerConfig.h"
|
||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "secureQSettings.h"
|
#include "secureQSettings.h"
|
||||||
|
|
||||||
using namespace amnezia;
|
using namespace amnezia;
|
||||||
@@ -18,47 +24,57 @@ class SecureServersRepository : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SecureServersRepository(SecureQSettings* settings, QObject *parent = nullptr);
|
explicit SecureServersRepository(SecureQSettings *settings, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QString addServer(const QString &serverId, const QJsonObject &serverJson, serverConfigUtils::ConfigType kind);
|
||||||
|
void editServer(const QString &serverId, const QJsonObject &serverJson, serverConfigUtils::ConfigType kind);
|
||||||
|
void removeServer(const QString &serverId);
|
||||||
|
serverConfigUtils::ConfigType serverKind(const QString &serverId) const;
|
||||||
|
|
||||||
|
std::optional<SelfHostedAdminServerConfig> selfHostedAdminConfig(const QString &serverId) const;
|
||||||
|
std::optional<SelfHostedUserServerConfig> selfHostedUserConfig(const QString &serverId) const;
|
||||||
|
std::optional<NativeServerConfig> nativeConfig(const QString &serverId) const;
|
||||||
|
std::optional<ApiV2ServerConfig> apiV2Config(const QString &serverId) const;
|
||||||
|
std::optional<LegacyApiServerConfig> legacyApiConfig(const QString &serverId) const;
|
||||||
|
|
||||||
void addServer(const ServerConfig &server);
|
|
||||||
void editServer(int index, const ServerConfig &server);
|
|
||||||
void removeServer(int index);
|
|
||||||
ServerConfig server(int index) const;
|
|
||||||
QVector<ServerConfig> servers() const;
|
|
||||||
int serversCount() const;
|
int serversCount() const;
|
||||||
|
int indexOfServerId(const QString &serverId) const;
|
||||||
|
QString serverIdAt(int index) const;
|
||||||
|
QVector<QString> orderedServerIds() const;
|
||||||
|
|
||||||
int defaultServerIndex() const;
|
int defaultServerIndex() const;
|
||||||
void setDefaultServer(int index);
|
QString defaultServerId() const;
|
||||||
|
void setDefaultServer(const QString &serverId);
|
||||||
|
|
||||||
void setDefaultContainer(int serverIndex, DockerContainer container);
|
void clearServers();
|
||||||
ContainerConfig containerConfig(int serverIndex, DockerContainer container) const;
|
|
||||||
void setContainerConfig(int serverIndex, DockerContainer container, const ContainerConfig &config);
|
|
||||||
void clearLastConnectionConfig(int serverIndex, DockerContainer container);
|
|
||||||
|
|
||||||
ServerCredentials serverCredentials(int index) const;
|
|
||||||
bool hasServerWithVpnKey(const QString &vpnKey) const;
|
|
||||||
bool hasServerWithCrc(quint16 crc) const;
|
|
||||||
|
|
||||||
void setServersArray(const QJsonArray &servers);
|
|
||||||
|
|
||||||
void invalidateCache();
|
void invalidateCache();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void serverAdded(ServerConfig config);
|
void serverAdded(const QString &serverId);
|
||||||
void serverEdited(int index, ServerConfig config);
|
void serverEdited(const QString &serverId);
|
||||||
void serverRemoved(int index);
|
void serverRemoved(const QString &serverId, int removedIndex);
|
||||||
void defaultServerChanged(int index);
|
void defaultServerChanged(const QString &defaultServerId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void loadFromStorage();
|
||||||
|
void updateDefaultServerFromStorage();
|
||||||
|
void persistDefaultServerFields();
|
||||||
|
|
||||||
|
QString normalizedOrGeneratedServerId(const QString &candidateId) const;
|
||||||
|
|
||||||
void syncToStorage();
|
void syncToStorage();
|
||||||
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
|
QVariant value(const QString &key, const QVariant &defaultValue) const;
|
||||||
void setValue(const QString &key, const QVariant &value);
|
void setValue(const QString &key, const QVariant &value);
|
||||||
|
|
||||||
SecureQSettings* m_settings;
|
void clearServerStateMaps();
|
||||||
|
|
||||||
QVector<ServerConfig> m_servers;
|
SecureQSettings *m_settings;
|
||||||
int m_defaultServerIndex = 0;
|
|
||||||
|
QHash<QString, QJsonObject> m_serverJsonById;
|
||||||
|
QVector<QString> m_orderedServerIds;
|
||||||
|
|
||||||
|
QString m_defaultServerId;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SECURESERVERSREPOSITORY_H
|
#endif // SECURESERVERSREPOSITORY_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
#ifndef APIENUMS_H
|
|
||||||
#define APIENUMS_H
|
|
||||||
|
|
||||||
namespace apiDefs
|
|
||||||
{
|
|
||||||
enum ConfigType {
|
|
||||||
AmneziaFreeV2 = 0,
|
|
||||||
AmneziaFreeV3,
|
|
||||||
AmneziaPremiumV1,
|
|
||||||
AmneziaPremiumV2,
|
|
||||||
AmneziaTrialV2,
|
|
||||||
SelfHosted,
|
|
||||||
ExternalPremium,
|
|
||||||
ExternalTrial
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ConfigSource {
|
|
||||||
Telegram = 1,
|
|
||||||
AmneziaGateway
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // APIENUMS_H
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "apiUtils.h"
|
#include "apiUtils.h"
|
||||||
|
|
||||||
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/utils/constants/configKeys.h"
|
#include "core/utils/constants/configKeys.h"
|
||||||
|
#include <QLatin1Char>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
@@ -75,63 +77,6 @@ bool apiUtils::isSubscriptionExpiringSoon(const QString &subscriptionEndDate, in
|
|||||||
return endDate <= nowUtc.addDays(withinDays);
|
return endDate <= nowUtc.addDays(withinDays);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool apiUtils::isServerFromApi(const QJsonObject &serverConfigObject)
|
|
||||||
{
|
|
||||||
auto configVersion = serverConfigObject.value(configKey::configVersion).toInt();
|
|
||||||
switch (configVersion) {
|
|
||||||
case apiDefs::ConfigSource::Telegram: return true;
|
|
||||||
case apiDefs::ConfigSource::AmneziaGateway: return true;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apiDefs::ConfigType apiUtils::getConfigType(const QJsonObject &serverConfigObject)
|
|
||||||
{
|
|
||||||
auto configVersion = serverConfigObject.value(configKey::configVersion).toInt();
|
|
||||||
|
|
||||||
switch (configVersion) {
|
|
||||||
case apiDefs::ConfigSource::Telegram: {
|
|
||||||
constexpr QLatin1String freeV2Endpoint(FREE_V2_ENDPOINT);
|
|
||||||
constexpr QLatin1String premiumV1Endpoint(PREM_V1_ENDPOINT);
|
|
||||||
|
|
||||||
auto apiEndpoint = serverConfigObject.value(apiDefs::key::apiEndpoint).toString();
|
|
||||||
|
|
||||||
if (apiEndpoint.contains(premiumV1Endpoint)) {
|
|
||||||
return apiDefs::ConfigType::AmneziaPremiumV1;
|
|
||||||
} else if (apiEndpoint.contains(freeV2Endpoint)) {
|
|
||||||
return apiDefs::ConfigType::AmneziaFreeV2;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
case apiDefs::ConfigSource::AmneziaGateway: {
|
|
||||||
constexpr QLatin1String servicePremium("amnezia-premium");
|
|
||||||
constexpr QLatin1String serviceFree("amnezia-free");
|
|
||||||
constexpr QLatin1String serviceExternalPremium("external-premium");
|
|
||||||
constexpr QLatin1String serviceExternalTrial("external-trial");
|
|
||||||
|
|
||||||
auto apiConfigObject = serverConfigObject.value(apiDefs::key::apiConfig).toObject();
|
|
||||||
auto serviceType = apiConfigObject.value(apiDefs::key::serviceType).toString();
|
|
||||||
|
|
||||||
if (serviceType == servicePremium) {
|
|
||||||
return apiDefs::ConfigType::AmneziaPremiumV2;
|
|
||||||
} else if (serviceType == serviceFree) {
|
|
||||||
return apiDefs::ConfigType::AmneziaFreeV3;
|
|
||||||
} else if (serviceType == serviceExternalPremium) {
|
|
||||||
return apiDefs::ConfigType::ExternalPremium;
|
|
||||||
} else if (serviceType == serviceExternalTrial) {
|
|
||||||
return apiDefs::ConfigType::ExternalTrial;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
return apiDefs::ConfigType::SelfHosted;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
apiDefs::ConfigSource apiUtils::getConfigSource(const QJsonObject &serverConfigObject)
|
|
||||||
{
|
|
||||||
return static_cast<apiDefs::ConfigSource>(serverConfigObject.value(configKey::configVersion).toInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
amnezia::ErrorCode apiUtils::checkNetworkReplyErrors(const QList<QSslError> &sslErrors, const QString &replyErrorString,
|
amnezia::ErrorCode apiUtils::checkNetworkReplyErrors(const QList<QSslError> &sslErrors, const QString &replyErrorString,
|
||||||
const QNetworkReply::NetworkError &replyError, const int httpStatusCode,
|
const QNetworkReply::NetworkError &replyError, const int httpStatusCode,
|
||||||
const QByteArray &responseBody)
|
const QByteArray &responseBody)
|
||||||
@@ -197,14 +142,14 @@ amnezia::ErrorCode apiUtils::checkNetworkReplyErrors(const QList<QSslError> &ssl
|
|||||||
|
|
||||||
bool apiUtils::isPremiumServer(const QJsonObject &serverConfigObject)
|
bool apiUtils::isPremiumServer(const QJsonObject &serverConfigObject)
|
||||||
{
|
{
|
||||||
static const QSet<apiDefs::ConfigType> premiumTypes = { apiDefs::ConfigType::AmneziaPremiumV1, apiDefs::ConfigType::AmneziaPremiumV2,
|
static const QSet<serverConfigUtils::ConfigType> premiumTypes = { serverConfigUtils::ConfigType::AmneziaPremiumV1, serverConfigUtils::ConfigType::AmneziaPremiumV2,
|
||||||
apiDefs::ConfigType::ExternalPremium, apiDefs::ConfigType::ExternalTrial };
|
serverConfigUtils::ConfigType::ExternalPremium };
|
||||||
return premiumTypes.contains(getConfigType(serverConfigObject));
|
return premiumTypes.contains(serverConfigUtils::configTypeFromJson(serverConfigObject));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString apiUtils::getPremiumV1VpnKey(const QJsonObject &serverConfigObject)
|
QString apiUtils::getPremiumV1VpnKey(const QJsonObject &serverConfigObject)
|
||||||
{
|
{
|
||||||
if (apiUtils::getConfigType(serverConfigObject) != apiDefs::ConfigType::AmneziaPremiumV1) {
|
if (serverConfigUtils::configTypeFromJson(serverConfigObject) != serverConfigUtils::ConfigType::AmneziaPremiumV1) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,9 +187,8 @@ QString apiUtils::getPremiumV1VpnKey(const QJsonObject &serverConfigObject)
|
|||||||
|
|
||||||
QString apiUtils::getPremiumV2VpnKey(const QJsonObject &serverConfigObject)
|
QString apiUtils::getPremiumV2VpnKey(const QJsonObject &serverConfigObject)
|
||||||
{
|
{
|
||||||
auto configType = apiUtils::getConfigType(serverConfigObject);
|
auto configType = serverConfigUtils::configTypeFromJson(serverConfigObject);
|
||||||
if (configType != apiDefs::ConfigType::AmneziaPremiumV2 && configType != apiDefs::ConfigType::ExternalPremium
|
if (configType != serverConfigUtils::ConfigType::AmneziaPremiumV2 && configType != serverConfigUtils::ConfigType::ExternalPremium) {
|
||||||
&& configType != apiDefs::ConfigType::ExternalTrial) {
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,3 +233,18 @@ QString apiUtils::getPremiumV2VpnKey(const QJsonObject &serverConfigObject)
|
|||||||
|
|
||||||
return vpnKeyText;
|
return vpnKeyText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString apiUtils::countryCodeBaseForFlag(const QString &fullCountryCode)
|
||||||
|
{
|
||||||
|
const QString trimmed = fullCountryCode.trimmed();
|
||||||
|
if (trimmed.isEmpty()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
const int dashIdx = trimmed.indexOf(QLatin1Char('-'));
|
||||||
|
const QString base = dashIdx < 0 ? trimmed : trimmed.left(dashIdx);
|
||||||
|
const QString normalized = base.trimmed();
|
||||||
|
if (normalized.isEmpty()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return normalized.toUpper();
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "core/utils/api/apiEnums.h"
|
#include "core/utils/serverConfigUtils.h"
|
||||||
#include "core/utils/constants/apiKeys.h"
|
#include "core/utils/constants/apiKeys.h"
|
||||||
#include "core/utils/constants/apiConstants.h"
|
#include "core/utils/constants/apiConstants.h"
|
||||||
#include "core/utils/errorCodes.h"
|
#include "core/utils/errorCodes.h"
|
||||||
@@ -13,23 +13,21 @@
|
|||||||
|
|
||||||
namespace apiUtils
|
namespace apiUtils
|
||||||
{
|
{
|
||||||
bool isServerFromApi(const QJsonObject &serverConfigObject);
|
|
||||||
|
|
||||||
bool isSubscriptionExpired(const QString &subscriptionEndDate);
|
bool isSubscriptionExpired(const QString &subscriptionEndDate);
|
||||||
|
|
||||||
bool isSubscriptionExpiringSoon(const QString &subscriptionEndDate, int withinDays = 30);
|
bool isSubscriptionExpiringSoon(const QString &subscriptionEndDate, int withinDays = 30);
|
||||||
|
|
||||||
bool isPremiumServer(const QJsonObject &serverConfigObject);
|
bool isPremiumServer(const QJsonObject &serverConfigObject);
|
||||||
|
|
||||||
apiDefs::ConfigType getConfigType(const QJsonObject &serverConfigObject);
|
|
||||||
apiDefs::ConfigSource getConfigSource(const QJsonObject &serverConfigObject);
|
|
||||||
|
|
||||||
amnezia::ErrorCode checkNetworkReplyErrors(const QList<QSslError> &sslErrors, const QString &replyErrorString,
|
amnezia::ErrorCode checkNetworkReplyErrors(const QList<QSslError> &sslErrors, const QString &replyErrorString,
|
||||||
const QNetworkReply::NetworkError &replyError, const int httpStatusCode,
|
const QNetworkReply::NetworkError &replyError, const int httpStatusCode,
|
||||||
const QByteArray &responseBody);
|
const QByteArray &responseBody);
|
||||||
|
|
||||||
QString getPremiumV1VpnKey(const QJsonObject &serverConfigObject);
|
QString getPremiumV1VpnKey(const QJsonObject &serverConfigObject);
|
||||||
QString getPremiumV2VpnKey(const QJsonObject &serverConfigObject);
|
QString getPremiumV2VpnKey(const QJsonObject &serverConfigObject);
|
||||||
|
|
||||||
|
// ISO2-style segment for flagKit assets (e.g. US-WEST -> US). Do not use in API request bodies.
|
||||||
|
QString countryCodeBaseForFlag(const QString &fullCountryCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // APIUTILS_H
|
#endif // APIUTILS_H
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
namespace apiDefs
|
namespace apiDefs
|
||||||
{
|
{
|
||||||
const int requestTimeoutMsecs = 12 * 1000; // 12 secs
|
|
||||||
}
|
constexpr int requestTimeoutMsecs = 12 * 1000; // 12 secs
|
||||||
|
|
||||||
|
} // namespace apiDefs
|
||||||
|
|
||||||
#endif // APICONSTANTS_H
|
#endif // APICONSTANTS_H
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#define APIKEYS_H
|
#define APIKEYS_H
|
||||||
|
|
||||||
#include <QLatin1String>
|
#include <QLatin1String>
|
||||||
#include "core/utils/api/apiEnums.h"
|
|
||||||
|
|
||||||
namespace apiDefs
|
namespace apiDefs
|
||||||
{
|
{
|
||||||
@@ -82,7 +81,7 @@ namespace apiDefs
|
|||||||
constexpr QLatin1String expiresAt("expires_at");
|
constexpr QLatin1String expiresAt("expires_at");
|
||||||
constexpr QLatin1String isConnectEvent("is_connect_event");
|
constexpr QLatin1String isConnectEvent("is_connect_event");
|
||||||
constexpr QLatin1String certificate("certificate");
|
constexpr QLatin1String certificate("certificate");
|
||||||
}
|
} // namespace key
|
||||||
}
|
} // namespace apiDefs
|
||||||
|
|
||||||
#endif // APIKEYS_H
|
#endif // APIKEYS_H
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ namespace amnezia
|
|||||||
|
|
||||||
constexpr QLatin1String serverIndex("serverIndex");
|
constexpr QLatin1String serverIndex("serverIndex");
|
||||||
constexpr QLatin1String description("description");
|
constexpr QLatin1String description("description");
|
||||||
|
constexpr QLatin1String displayName("displayName");
|
||||||
constexpr QLatin1String name("name");
|
constexpr QLatin1String name("name");
|
||||||
constexpr QLatin1String cert("cert");
|
constexpr QLatin1String cert("cert");
|
||||||
constexpr QLatin1String accessToken("api_key");
|
constexpr QLatin1String accessToken("api_key");
|
||||||
@@ -92,6 +93,8 @@ namespace amnezia
|
|||||||
constexpr QLatin1String xray("xray");
|
constexpr QLatin1String xray("xray");
|
||||||
constexpr QLatin1String ssxray("ssxray");
|
constexpr QLatin1String ssxray("ssxray");
|
||||||
constexpr QLatin1String socks5proxy("socks5proxy");
|
constexpr QLatin1String socks5proxy("socks5proxy");
|
||||||
|
constexpr QLatin1String mtproxy("mtproxy");
|
||||||
|
constexpr QLatin1String telemt("telemt");
|
||||||
|
|
||||||
constexpr QLatin1String splitTunnelSites("splitTunnelSites");
|
constexpr QLatin1String splitTunnelSites("splitTunnelSites");
|
||||||
constexpr QLatin1String splitTunnelType("splitTunnelType");
|
constexpr QLatin1String splitTunnelType("splitTunnelType");
|
||||||
@@ -121,6 +124,8 @@ namespace amnezia
|
|||||||
constexpr QLatin1String latestHandshake("latestHandshake");
|
constexpr QLatin1String latestHandshake("latestHandshake");
|
||||||
constexpr QLatin1String dataReceived("dataReceived");
|
constexpr QLatin1String dataReceived("dataReceived");
|
||||||
constexpr QLatin1String dataSent("dataSent");
|
constexpr QLatin1String dataSent("dataSent");
|
||||||
|
|
||||||
|
constexpr QLatin1String storageServerId("storageServerId");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
namespace amnezia
|
namespace amnezia
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace protocols
|
namespace protocols
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -174,9 +175,71 @@ namespace amnezia
|
|||||||
constexpr char proxyConfigPath[] = "/usr/local/3proxy/conf/3proxy.cfg";
|
constexpr char proxyConfigPath[] = "/usr/local/3proxy/conf/3proxy.cfg";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace mtProxy
|
||||||
|
{
|
||||||
|
constexpr char secretKey[] = "mtproxy_secret";
|
||||||
|
constexpr char tagKey[] = "mtproxy_tag";
|
||||||
|
constexpr char tgLinkKey[] = "mtproxy_tg_link";
|
||||||
|
constexpr char tmeLinkKey[] = "mtproxy_tme_link";
|
||||||
|
constexpr char isEnabledKey[] = "mtproxy_is_enabled";
|
||||||
|
constexpr char publicHostKey[] = "mtproxy_public_host";
|
||||||
|
constexpr char transportModeKey[] = "mtproxy_transport_mode";
|
||||||
|
constexpr char tlsDomainKey[] = "mtproxy_tls_domain";
|
||||||
|
constexpr char additionalSecretsKey[] = "mtproxy_additional_secrets";
|
||||||
|
constexpr char workersKey[] = "mtproxy_workers";
|
||||||
|
constexpr char workersModeKey[] = "mtproxy_workers_mode";
|
||||||
|
constexpr char natEnabledKey[] = "mtproxy_nat_enabled";
|
||||||
|
constexpr char natInternalIpKey[] = "mtproxy_nat_internal_ip";
|
||||||
|
constexpr char natExternalIpKey[] = "mtproxy_nat_external_ip";
|
||||||
|
|
||||||
|
constexpr char transportModeStandard[] = "standard";
|
||||||
|
constexpr char transportModeFakeTLS[] = "faketls";
|
||||||
|
|
||||||
|
constexpr char workersModeAuto[] = "auto";
|
||||||
|
constexpr char workersModeManual[] = "manual";
|
||||||
|
|
||||||
|
constexpr char defaultPort[] = "443";
|
||||||
|
constexpr char defaultWorkers[] = "2";
|
||||||
|
constexpr int maxWorkers = 32;
|
||||||
|
constexpr int botTagHexLength = 32;
|
||||||
|
constexpr char defaultTlsDomain[] = "googletagmanager.com";
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace telemt
|
||||||
|
{
|
||||||
|
constexpr char secretKey[] = "telemt_secret";
|
||||||
|
constexpr char tagKey[] = "telemt_tag";
|
||||||
|
constexpr char tgLinkKey[] = "telemt_tg_link";
|
||||||
|
constexpr char tmeLinkKey[] = "telemt_tme_link";
|
||||||
|
constexpr char isEnabledKey[] = "telemt_is_enabled";
|
||||||
|
constexpr char publicHostKey[] = "telemt_public_host";
|
||||||
|
constexpr char transportModeKey[] = "telemt_transport_mode";
|
||||||
|
constexpr char tlsDomainKey[] = "telemt_tls_domain";
|
||||||
|
constexpr char maskEnabledKey[] = "telemt_mask_enabled";
|
||||||
|
constexpr char tlsEmulationKey[] = "telemt_tls_emulation";
|
||||||
|
constexpr char useMiddleProxyKey[] = "telemt_use_middle_proxy";
|
||||||
|
constexpr char userNameKey[] = "telemt_user_name";
|
||||||
|
// Stored for UI only (Telemt server ignores these; same controls as MTProxy page)
|
||||||
|
constexpr char additionalSecretsKey[] = "telemt_additional_secrets";
|
||||||
|
constexpr char workersKey[] = "telemt_workers";
|
||||||
|
constexpr char workersModeKey[] = "telemt_workers_mode";
|
||||||
|
constexpr char natEnabledKey[] = "telemt_nat_enabled";
|
||||||
|
constexpr char natInternalIpKey[] = "telemt_nat_internal_ip";
|
||||||
|
constexpr char natExternalIpKey[] = "telemt_nat_external_ip";
|
||||||
|
|
||||||
|
constexpr char transportModeStandard[] = "standard";
|
||||||
|
constexpr char transportModeFakeTLS[] = "faketls";
|
||||||
|
|
||||||
|
constexpr char defaultPort[] = "443";
|
||||||
|
constexpr char defaultTlsDomain[] = "googletagmanager.com";
|
||||||
|
constexpr char defaultUserName[] = "amnezia";
|
||||||
|
constexpr char defaultWorkers[] = "2";
|
||||||
|
constexpr char workersModeAuto[] = "auto";
|
||||||
|
constexpr char workersModeManual[] = "manual";
|
||||||
|
constexpr int maxWorkers = 32;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace protocols
|
} // namespace protocols
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // PROTOCOLCONSTANTS_H
|
#endif // PROTOCOLCONSTANTS_H
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ namespace amnezia
|
|||||||
TorWebSite,
|
TorWebSite,
|
||||||
Dns,
|
Dns,
|
||||||
Sftp,
|
Sftp,
|
||||||
Socks5Proxy
|
Socks5Proxy,
|
||||||
|
MtProxy,
|
||||||
|
Telemt,
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(DockerContainer)
|
Q_ENUM_NS(DockerContainer)
|
||||||
} // namespace ContainerEnumNS
|
} // namespace ContainerEnumNS
|
||||||
|
|||||||
@@ -72,7 +72,10 @@ QMap<DockerContainer, QString> ContainerUtils::containerHumanNames()
|
|||||||
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
|
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
|
||||||
{ DockerContainer::Dns, QObject::tr("AmneziaDNS") },
|
{ DockerContainer::Dns, QObject::tr("AmneziaDNS") },
|
||||||
{ DockerContainer::Sftp, QObject::tr("SFTP file sharing service") },
|
{ DockerContainer::Sftp, QObject::tr("SFTP file sharing service") },
|
||||||
{ DockerContainer::Socks5Proxy, QObject::tr("SOCKS5 proxy server") } };
|
{ DockerContainer::Socks5Proxy, QObject::tr("SOCKS5 proxy server") },
|
||||||
|
{ DockerContainer::MtProxy, QObject::tr("MTProxy (Telegram)") },
|
||||||
|
{ DockerContainer::Telemt, QObject::tr("Telemt (Telegram)") },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<DockerContainer, QString> ContainerUtils::containerDescriptions()
|
QMap<DockerContainer, QString> ContainerUtils::containerDescriptions()
|
||||||
@@ -102,7 +105,12 @@ QMap<DockerContainer, QString> ContainerUtils::containerDescriptions()
|
|||||||
{ DockerContainer::Sftp,
|
{ DockerContainer::Sftp,
|
||||||
QObject::tr("Create a file vault on your server to securely store and transfer files.") },
|
QObject::tr("Create a file vault on your server to securely store and transfer files.") },
|
||||||
{ DockerContainer::Socks5Proxy,
|
{ DockerContainer::Socks5Proxy,
|
||||||
QObject::tr("") } };
|
QObject::tr("") },
|
||||||
|
{ DockerContainer::MtProxy,
|
||||||
|
QObject::tr("Telegram MTProto proxy server") },
|
||||||
|
{ DockerContainer::Telemt,
|
||||||
|
QObject::tr("Telegram MTProto proxy (Telemt, Rust)") },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<DockerContainer, QString> ContainerUtils::containerDetailedDescriptions()
|
QMap<DockerContainer, QString> ContainerUtils::containerDetailedDescriptions()
|
||||||
@@ -172,7 +180,15 @@ QMap<DockerContainer, QString> ContainerUtils::containerDetailedDescriptions()
|
|||||||
"You will be able to access it using\n FileZilla or other SFTP clients, "
|
"You will be able to access it using\n FileZilla or other SFTP clients, "
|
||||||
"as well as mount the disk on your device to access\n it directly from your device.\n\n"
|
"as well as mount the disk on your device to access\n it directly from your device.\n\n"
|
||||||
"For more detailed information, you can\n find it in the support section under \"Create SFTP file storage.\" ") },
|
"For more detailed information, you can\n find it in the support section under \"Create SFTP file storage.\" ") },
|
||||||
{ DockerContainer::Socks5Proxy, QObject::tr("SOCKS5 proxy server") }
|
{ DockerContainer::Socks5Proxy, QObject::tr("SOCKS5 proxy server") },
|
||||||
|
{ DockerContainer::MtProxy,
|
||||||
|
QObject::tr("Telegram MTProto proxy server. "
|
||||||
|
"Allows Telegram clients to connect through your server "
|
||||||
|
"using the MTProto protocol. Supports FakeTLS mode for "
|
||||||
|
"bypassing DPI-based blocking.") },
|
||||||
|
{ DockerContainer::Telemt,
|
||||||
|
QObject::tr("Telegram MTProto proxy powered by Telemt (Rust). "
|
||||||
|
"Supports secure and TLS fronting modes with optional traffic masking.") },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +213,8 @@ Proto ContainerUtils::defaultProtocol(DockerContainer c)
|
|||||||
case DockerContainer::Dns: return Proto::Dns;
|
case DockerContainer::Dns: return Proto::Dns;
|
||||||
case DockerContainer::Sftp: return Proto::Sftp;
|
case DockerContainer::Sftp: return Proto::Sftp;
|
||||||
case DockerContainer::Socks5Proxy: return Proto::Socks5Proxy;
|
case DockerContainer::Socks5Proxy: return Proto::Socks5Proxy;
|
||||||
|
case DockerContainer::MtProxy: return Proto::MtProxy;
|
||||||
|
case DockerContainer::Telemt: return Proto::Telemt;
|
||||||
default: return Proto::Unknown;
|
default: return Proto::Unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,6 +242,8 @@ bool ContainerUtils::isSupportedByCurrentPlatform(DockerContainer c)
|
|||||||
case DockerContainer::Awg: return true;
|
case DockerContainer::Awg: return true;
|
||||||
case DockerContainer::Xray: return true;
|
case DockerContainer::Xray: return true;
|
||||||
case DockerContainer::SSXray: return true;
|
case DockerContainer::SSXray: return true;
|
||||||
|
case DockerContainer::MtProxy: return true;
|
||||||
|
case DockerContainer::Telemt: return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -237,7 +257,8 @@ bool ContainerUtils::isSupportedByCurrentPlatform(DockerContainer c)
|
|||||||
case DockerContainer::Awg: return true;
|
case DockerContainer::Awg: return true;
|
||||||
case DockerContainer::Xray: return true;
|
case DockerContainer::Xray: return true;
|
||||||
case DockerContainer::SSXray: return true;
|
case DockerContainer::SSXray: return true;
|
||||||
return false;
|
case DockerContainer::MtProxy: return true;
|
||||||
|
case DockerContainer::Telemt: return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -256,6 +277,8 @@ bool ContainerUtils::isSupportedByCurrentPlatform(DockerContainer c)
|
|||||||
case DockerContainer::Awg: return true;
|
case DockerContainer::Awg: return true;
|
||||||
case DockerContainer::Xray: return true;
|
case DockerContainer::Xray: return true;
|
||||||
case DockerContainer::SSXray: return true;
|
case DockerContainer::SSXray: return true;
|
||||||
|
case DockerContainer::MtProxy: return true;
|
||||||
|
case DockerContainer::Telemt: return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,6 +341,8 @@ bool ContainerUtils::isShareable(DockerContainer container)
|
|||||||
case DockerContainer::Dns: return false;
|
case DockerContainer::Dns: return false;
|
||||||
case DockerContainer::Sftp: return false;
|
case DockerContainer::Sftp: return false;
|
||||||
case DockerContainer::Socks5Proxy: return false;
|
case DockerContainer::Socks5Proxy: return false;
|
||||||
|
case DockerContainer::MtProxy: return false;
|
||||||
|
case DockerContainer::Telemt: return false;
|
||||||
default: return true;
|
default: return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -346,8 +371,10 @@ int ContainerUtils::installPageOrder(DockerContainer container)
|
|||||||
case DockerContainer::Xray: return 3;
|
case DockerContainer::Xray: return 3;
|
||||||
case DockerContainer::Ipsec: return 7;
|
case DockerContainer::Ipsec: return 7;
|
||||||
case DockerContainer::SSXray: return 8;
|
case DockerContainer::SSXray: return 8;
|
||||||
|
case DockerContainer::MtProxy:
|
||||||
|
case DockerContainer::Telemt:
|
||||||
|
return 20;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -71,10 +71,11 @@ namespace amnezia
|
|||||||
|
|
||||||
// import and install errors
|
// import and install errors
|
||||||
ImportInvalidConfigError = 900,
|
ImportInvalidConfigError = 900,
|
||||||
ImportBackupFileUseRestoreInstead = 903,
|
|
||||||
RestoreBackupInvalidError = 904,
|
|
||||||
ImportOpenConfigError = 901,
|
ImportOpenConfigError = 901,
|
||||||
NoInstalledContainersError = 902,
|
NoInstalledContainersError = 902,
|
||||||
|
ImportBackupFileUseRestoreInstead = 903,
|
||||||
|
RestoreBackupInvalidError = 904,
|
||||||
|
LegacyApiV1NotSupportedError = 905,
|
||||||
|
|
||||||
// Android errors
|
// Android errors
|
||||||
AndroidError = 1000,
|
AndroidError = 1000,
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ QString errorString(ErrorCode code) {
|
|||||||
case (ErrorCode::ImportInvalidConfigError): errorMessage = QObject::tr("The config does not contain any containers and credentials for connecting to the server"); break;
|
case (ErrorCode::ImportInvalidConfigError): errorMessage = QObject::tr("The config does not contain any containers and credentials for connecting to the server"); break;
|
||||||
case (ErrorCode::ImportBackupFileUseRestoreInstead): errorMessage = QObject::tr("Backup files cannot be imported here. Use 'Restore from backup' instead."); break;
|
case (ErrorCode::ImportBackupFileUseRestoreInstead): errorMessage = QObject::tr("Backup files cannot be imported here. Use 'Restore from backup' instead."); break;
|
||||||
case (ErrorCode::RestoreBackupInvalidError): errorMessage = QObject::tr("Backup file is corrupted or has invalid format"); break;
|
case (ErrorCode::RestoreBackupInvalidError): errorMessage = QObject::tr("Backup file is corrupted or has invalid format"); break;
|
||||||
|
case (ErrorCode::LegacyApiV1NotSupportedError): errorMessage = QObject::tr("This legacy Amnezia subscription format is no longer supported"); break;
|
||||||
case (ErrorCode::ImportOpenConfigError): errorMessage = QObject::tr("Unable to open config file"); break;
|
case (ErrorCode::ImportOpenConfigError): errorMessage = QObject::tr("Unable to open config file"); break;
|
||||||
case (ErrorCode::NoInstalledContainersError): errorMessage = QObject::tr("VPN Protocols is not installed.\n Please install VPN container at first"); break;
|
case (ErrorCode::NoInstalledContainersError): errorMessage = QObject::tr("VPN Protocols is not installed.\n Please install VPN container at first"); break;
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ namespace amnezia
|
|||||||
TorWebSite,
|
TorWebSite,
|
||||||
Dns,
|
Dns,
|
||||||
Sftp,
|
Sftp,
|
||||||
Socks5Proxy
|
Socks5Proxy,
|
||||||
|
MtProxy,
|
||||||
|
Telemt,
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(Proto)
|
Q_ENUM_NS(Proto)
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include "core/utils/containerEnum.h"
|
#include "core/utils/containerEnum.h"
|
||||||
#include "core/utils/containers/containerUtils.h"
|
#include "core/utils/containers/containerUtils.h"
|
||||||
#include "core/utils/protocolEnum.h"
|
#include "core/utils/protocolEnum.h"
|
||||||
#include "core/utils/protocolEnum.h"
|
|
||||||
#include "core/protocols/protocolUtils.h"
|
#include "core/protocols/protocolUtils.h"
|
||||||
#include "core/utils/constants/configKeys.h"
|
#include "core/utils/constants/configKeys.h"
|
||||||
#include "core/utils/constants/protocolConstants.h"
|
#include "core/utils/constants/protocolConstants.h"
|
||||||
@@ -20,6 +19,8 @@
|
|||||||
#include "core/models/protocols/xrayProtocolConfig.h"
|
#include "core/models/protocols/xrayProtocolConfig.h"
|
||||||
#include "core/models/protocols/sftpProtocolConfig.h"
|
#include "core/models/protocols/sftpProtocolConfig.h"
|
||||||
#include "core/models/protocols/socks5ProxyProtocolConfig.h"
|
#include "core/models/protocols/socks5ProxyProtocolConfig.h"
|
||||||
|
#include "core/models/protocols/mtProxyProtocolConfig.h"
|
||||||
|
#include "core/models/protocols/telemtProtocolConfig.h"
|
||||||
|
|
||||||
using namespace amnezia;
|
using namespace amnezia;
|
||||||
using namespace ProtocolUtils;
|
using namespace ProtocolUtils;
|
||||||
@@ -38,6 +39,8 @@ QString amnezia::scriptFolder(amnezia::DockerContainer container)
|
|||||||
case DockerContainer::Dns: return QLatin1String("dns");
|
case DockerContainer::Dns: return QLatin1String("dns");
|
||||||
case DockerContainer::Sftp: return QLatin1String("sftp");
|
case DockerContainer::Sftp: return QLatin1String("sftp");
|
||||||
case DockerContainer::Socks5Proxy: return QLatin1String("socks5_proxy");
|
case DockerContainer::Socks5Proxy: return QLatin1String("socks5_proxy");
|
||||||
|
case DockerContainer::MtProxy: return QLatin1String("mtproxy");
|
||||||
|
case DockerContainer::Telemt: return QLatin1String("telemt");
|
||||||
default: return QString();
|
default: return QString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +79,6 @@ QString amnezia::scriptName(ProtocolScriptType type)
|
|||||||
QString amnezia::scriptName(ClientScriptType type)
|
QString amnezia::scriptName(ClientScriptType type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ClientScriptType::linux_installer: return QLatin1String("linux_installer.sh");
|
|
||||||
case ClientScriptType::mac_installer: return QLatin1String("mac_installer.sh");
|
case ClientScriptType::mac_installer: return QLatin1String("mac_installer.sh");
|
||||||
default: return QString();
|
default: return QString();
|
||||||
}
|
}
|
||||||
@@ -285,6 +287,86 @@ amnezia::ScriptVars amnezia::genSocks5ProxyVars(const ContainerConfig &container
|
|||||||
return vars;
|
return vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
amnezia::ScriptVars amnezia::genMtProxyVars(const ContainerConfig &containerConfig) {
|
||||||
|
ScriptVars vars;
|
||||||
|
|
||||||
|
if (auto *mtProxyProtocolConfig = containerConfig.getMtProxyProtocolConfig()) {
|
||||||
|
const MtProxyProtocolConfig &c = *mtProxyProtocolConfig;
|
||||||
|
|
||||||
|
vars.append({{"$MTPROXY_PORT", c.port.isEmpty() ? QString(protocols::mtProxy::defaultPort) : c.port}});
|
||||||
|
vars.append({{"$MTPROXY_SECRET", c.secret}});
|
||||||
|
vars.append({{"$MTPROXY_TAG", c.tag}});
|
||||||
|
vars.append({{"$MTPROXY_TRANSPORT_MODE",
|
||||||
|
c.transportMode.isEmpty() ? QString(protocols::mtProxy::transportModeStandard)
|
||||||
|
: c.transportMode}});
|
||||||
|
|
||||||
|
QString tlsDomain = c.tlsDomain;
|
||||||
|
if (tlsDomain.isEmpty()) {
|
||||||
|
tlsDomain = QString(protocols::mtProxy::defaultTlsDomain);
|
||||||
|
}
|
||||||
|
vars.append({{"$MTPROXY_TLS_DOMAIN", tlsDomain}});
|
||||||
|
vars.append({{"$MTPROXY_PUBLIC_HOST", c.publicHost}});
|
||||||
|
|
||||||
|
QStringList additionalList;
|
||||||
|
for (const QString &s: c.additionalSecrets) {
|
||||||
|
if (!s.isEmpty()) {
|
||||||
|
additionalList << s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vars.append({{"$MTPROXY_ADDITIONAL_SECRETS", additionalList.join(QLatin1Char(','))}});
|
||||||
|
|
||||||
|
const QString workersMode = c.workersMode.isEmpty() ? QString(protocols::mtProxy::workersModeAuto)
|
||||||
|
: c.workersMode;
|
||||||
|
QString workers;
|
||||||
|
if (workersMode == QLatin1String(protocols::mtProxy::workersModeManual)) {
|
||||||
|
workers = c.workers.isEmpty() ? QString(protocols::mtProxy::defaultWorkers) : c.workers;
|
||||||
|
} else {
|
||||||
|
const QString transportMode =
|
||||||
|
c.transportMode.isEmpty() ? QString(protocols::mtProxy::transportModeStandard) : c.transportMode;
|
||||||
|
workers = (transportMode == QLatin1String(protocols::mtProxy::transportModeFakeTLS)) ? QStringLiteral("0")
|
||||||
|
: QStringLiteral("2");
|
||||||
|
}
|
||||||
|
vars.append({{"$MTPROXY_WORKERS", workers}});
|
||||||
|
|
||||||
|
vars.append({{"$MTPROXY_NAT_ENABLED", c.natEnabled ? QStringLiteral("1") : QStringLiteral("0")}});
|
||||||
|
vars.append({{"$MTPROXY_NAT_INTERNAL_IP", c.natInternalIp}});
|
||||||
|
vars.append({{"$MTPROXY_NAT_EXTERNAL_IP", c.natExternalIp}});
|
||||||
|
}
|
||||||
|
|
||||||
|
return vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
amnezia::ScriptVars amnezia::genTelemtVars(const ContainerConfig &containerConfig)
|
||||||
|
{
|
||||||
|
ScriptVars vars;
|
||||||
|
|
||||||
|
if (auto *telemtProtocolConfig = containerConfig.getTelemtProtocolConfig()) {
|
||||||
|
const TelemtProtocolConfig &c = *telemtProtocolConfig;
|
||||||
|
|
||||||
|
const QString transport = c.transportMode.isEmpty() ? QString(protocols::telemt::transportModeStandard)
|
||||||
|
: c.transportMode;
|
||||||
|
const bool faketls = (transport == QLatin1String(protocols::telemt::transportModeFakeTLS));
|
||||||
|
vars.append({ { "$TELEMT_TOML_SECURE", faketls ? QLatin1String("false") : QLatin1String("true") } });
|
||||||
|
vars.append({ { "$TELEMT_TOML_TLS", faketls ? QLatin1String("true") : QLatin1String("false") } });
|
||||||
|
vars.append({ { "$TELEMT_PORT", c.port.isEmpty() ? QString(protocols::telemt::defaultPort) : c.port } });
|
||||||
|
vars.append({ { "$TELEMT_SECRET", c.secret } });
|
||||||
|
vars.append({ { "$TELEMT_TAG", c.tag } });
|
||||||
|
QString tlsDomain = c.tlsDomain;
|
||||||
|
if (tlsDomain.isEmpty()) {
|
||||||
|
tlsDomain = QString(protocols::telemt::defaultTlsDomain);
|
||||||
|
}
|
||||||
|
vars.append({ { "$TELEMT_TLS_DOMAIN", tlsDomain } });
|
||||||
|
vars.append({ { "$TELEMT_PUBLIC_HOST", c.publicHost } });
|
||||||
|
vars.append({ { "$TELEMT_USER_NAME",
|
||||||
|
c.userName.isEmpty() ? QString::fromUtf8(protocols::telemt::defaultUserName) : c.userName } });
|
||||||
|
vars.append({ { "$TELEMT_USE_MIDDLE_PROXY", c.useMiddleProxy ? QLatin1String("true") : QLatin1String("false") } });
|
||||||
|
vars.append({ { "$TELEMT_MASK", c.maskEnabled ? QLatin1String("true") : QLatin1String("false") } });
|
||||||
|
vars.append({ { "$TELEMT_TLS_EMULATION", c.tlsEmulation ? QLatin1String("true") : QLatin1String("false") } });
|
||||||
|
}
|
||||||
|
|
||||||
|
return vars;
|
||||||
|
}
|
||||||
|
|
||||||
amnezia::ScriptVars amnezia::genProtocolVarsForContainer(DockerContainer container, const ContainerConfig &containerConfig)
|
amnezia::ScriptVars amnezia::genProtocolVarsForContainer(DockerContainer container, const ContainerConfig &containerConfig)
|
||||||
{
|
{
|
||||||
ScriptVars vars;
|
ScriptVars vars;
|
||||||
@@ -309,6 +391,12 @@ amnezia::ScriptVars amnezia::genProtocolVarsForContainer(DockerContainer contain
|
|||||||
case Proto::Socks5Proxy:
|
case Proto::Socks5Proxy:
|
||||||
vars.append(genSocks5ProxyVars(containerConfig));
|
vars.append(genSocks5ProxyVars(containerConfig));
|
||||||
break;
|
break;
|
||||||
|
case Proto::MtProxy:
|
||||||
|
vars.append(genMtProxyVars(containerConfig));
|
||||||
|
break;
|
||||||
|
case Proto::Telemt:
|
||||||
|
vars.append(genTelemtVars(containerConfig));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ enum ProtocolScriptType {
|
|||||||
|
|
||||||
enum ClientScriptType {
|
enum ClientScriptType {
|
||||||
// Client-side scripts
|
// Client-side scripts
|
||||||
linux_installer,
|
|
||||||
mac_installer
|
mac_installer
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -68,6 +67,8 @@ ScriptVars genWireGuardVars(const ContainerConfig &containerConfig);
|
|||||||
ScriptVars genAwgVars(const ContainerConfig &containerConfig);
|
ScriptVars genAwgVars(const ContainerConfig &containerConfig);
|
||||||
ScriptVars genSftpVars(const ContainerConfig &containerConfig);
|
ScriptVars genSftpVars(const ContainerConfig &containerConfig);
|
||||||
ScriptVars genSocks5ProxyVars(const ContainerConfig &containerConfig);
|
ScriptVars genSocks5ProxyVars(const ContainerConfig &containerConfig);
|
||||||
|
ScriptVars genMtProxyVars(const ContainerConfig &containerConfig);
|
||||||
|
ScriptVars genTelemtVars(const ContainerConfig &containerConfig);
|
||||||
|
|
||||||
ScriptVars genProtocolVarsForContainer(DockerContainer container, const ContainerConfig &containerConfig);
|
ScriptVars genProtocolVarsForContainer(DockerContainer container, const ContainerConfig &containerConfig);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ namespace libssh {
|
|||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, &wait, &QEventLoop::quit);
|
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, &wait, &QEventLoop::quit);
|
||||||
watcher.setFuture(future);
|
watcher.setFuture(future);
|
||||||
wait.exec();
|
wait.exec(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
|
||||||
int connectionResult = watcher.result();
|
int connectionResult = watcher.result();
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ namespace libssh {
|
|||||||
|
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
QObject::connect(this, &Client::writeToChannelFinished, &wait, &QEventLoop::quit);
|
QObject::connect(this, &Client::writeToChannelFinished, &wait, &QEventLoop::quit);
|
||||||
wait.exec();
|
wait.exec(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
|
||||||
return watcher.result();
|
return watcher.result();
|
||||||
}
|
}
|
||||||
@@ -284,7 +284,7 @@ namespace libssh {
|
|||||||
|
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
QObject::connect(this, &Client::scpFileCopyFinished, &wait, &QEventLoop::quit);
|
QObject::connect(this, &Client::scpFileCopyFinished, &wait, &QEventLoop::quit);
|
||||||
wait.exec();
|
wait.exec(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
|
||||||
closeScpSession();
|
closeScpSession();
|
||||||
return watcher.result();
|
return watcher.result();
|
||||||
|
|||||||
@@ -103,8 +103,8 @@ ErrorCode SshSession::runContainerScript(const ServerCredentials &credentials, D
|
|||||||
if (e)
|
if (e)
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
QString runner =
|
const bool useSh = container == DockerContainer::Socks5Proxy || container == DockerContainer::MtProxy || container == DockerContainer::Telemt;
|
||||||
QString("sudo docker exec -i $CONTAINER_NAME %2 %1 ").arg(fileName, (container == DockerContainer::Socks5Proxy ? "sh" : "bash"));
|
QString runner = QString("sudo docker exec -i $CONTAINER_NAME %2 %1 ").arg(fileName, useSh ? "sh" : "bash");
|
||||||
e = runScript(credentials, replaceVars(runner, amnezia::genBaseVars(credentials, container, QString(), QString())), cbReadStdOut, cbReadStdErr);
|
e = runScript(credentials, replaceVars(runner, amnezia::genBaseVars(credentials, container, QString(), QString())), cbReadStdOut, cbReadStdErr);
|
||||||
|
|
||||||
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
|
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
#include "serverConfigUtils.h"
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonValue>
|
||||||
|
|
||||||
|
#include "core/models/selfhosted/selfHostedAdminServerConfig.h"
|
||||||
|
#include "core/utils/constants/apiKeys.h"
|
||||||
|
#include "core/utils/constants/configKeys.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
bool hasThirdPartyConfig(const QJsonObject &json)
|
||||||
|
{
|
||||||
|
const QJsonArray containersArray = json.value(amnezia::configKey::containers).toArray();
|
||||||
|
for (const QJsonValue &val : containersArray) {
|
||||||
|
const QJsonObject containerObj = val.toObject();
|
||||||
|
for (auto it = containerObj.begin(); it != containerObj.end(); ++it) {
|
||||||
|
if (it.key() == amnezia::configKey::container) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const QJsonObject protocolObj = it.value().toObject();
|
||||||
|
if (protocolObj.contains(amnezia::configKey::isThirdPartyConfig)
|
||||||
|
&& protocolObj.value(amnezia::configKey::isThirdPartyConfig).toBool()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace serverConfigUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
bool isServerFromApi(const QJsonObject &serverConfigObject)
|
||||||
|
{
|
||||||
|
const int configVersion = serverConfigObject.value(amnezia::configKey::configVersion).toInt();
|
||||||
|
switch (configVersion) {
|
||||||
|
case ConfigSource::Telegram:
|
||||||
|
case ConfigSource::AmneziaGateway:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigSource getConfigSource(const QJsonObject &serverConfigObject)
|
||||||
|
{
|
||||||
|
return static_cast<ConfigSource>(serverConfigObject.value(amnezia::configKey::configVersion).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigType configTypeFromJson(const QJsonObject &serverConfigObject)
|
||||||
|
{
|
||||||
|
const int configVersion = serverConfigObject.value(amnezia::configKey::configVersion).toInt();
|
||||||
|
|
||||||
|
switch (configVersion) {
|
||||||
|
case ConfigSource::Telegram: {
|
||||||
|
constexpr QLatin1String freeV2Endpoint(FREE_V2_ENDPOINT);
|
||||||
|
constexpr QLatin1String premiumV1Endpoint(PREM_V1_ENDPOINT);
|
||||||
|
|
||||||
|
const QString apiEndpointValue = serverConfigObject.value(apiDefs::key::apiEndpoint).toString();
|
||||||
|
|
||||||
|
if (apiEndpointValue.contains(premiumV1Endpoint)) {
|
||||||
|
return ConfigType::AmneziaPremiumV1;
|
||||||
|
}
|
||||||
|
if (apiEndpointValue.contains(freeV2Endpoint)) {
|
||||||
|
return ConfigType::AmneziaFreeV2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[[fallthrough]];
|
||||||
|
case ConfigSource::AmneziaGateway: {
|
||||||
|
constexpr QLatin1String servicePremium("amnezia-premium");
|
||||||
|
constexpr QLatin1String serviceFree("amnezia-free");
|
||||||
|
constexpr QLatin1String serviceExternalPremium("external-premium");
|
||||||
|
|
||||||
|
const QJsonObject apiConfigObject = serverConfigObject.value(apiDefs::key::apiConfig).toObject();
|
||||||
|
const QString serviceTypeStr = apiConfigObject.value(apiDefs::key::serviceType).toString();
|
||||||
|
|
||||||
|
if (serviceTypeStr == servicePremium) {
|
||||||
|
return ConfigType::AmneziaPremiumV2;
|
||||||
|
}
|
||||||
|
if (serviceTypeStr == serviceFree) {
|
||||||
|
return ConfigType::AmneziaFreeV3;
|
||||||
|
}
|
||||||
|
if (serviceTypeStr == serviceExternalPremium) {
|
||||||
|
return ConfigType::ExternalPremium;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasThirdPartyConfig(serverConfigObject)) {
|
||||||
|
return ConfigType::Native;
|
||||||
|
}
|
||||||
|
|
||||||
|
const amnezia::SelfHostedAdminServerConfig adminProbe =
|
||||||
|
amnezia::SelfHostedAdminServerConfig::fromJson(serverConfigObject);
|
||||||
|
return adminProbe.hasCredentials() ? ConfigType::SelfHostedAdmin : ConfigType::SelfHostedUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isLegacyApiSubscription(ConfigType configType)
|
||||||
|
{
|
||||||
|
return configType == ConfigType::AmneziaPremiumV1 || configType == ConfigType::AmneziaFreeV2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isApiV2Subscription(ConfigType configType)
|
||||||
|
{
|
||||||
|
switch (configType) {
|
||||||
|
case ConfigType::AmneziaPremiumV2:
|
||||||
|
case ConfigType::AmneziaFreeV3:
|
||||||
|
case ConfigType::ExternalPremium:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace serverConfigUtils
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef SERVERCONFIGUTILS_H
|
||||||
|
#define SERVERCONFIGUTILS_H
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
namespace serverConfigUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
enum ConfigType {
|
||||||
|
AmneziaFreeV2 = 0,
|
||||||
|
AmneziaFreeV3,
|
||||||
|
AmneziaPremiumV1,
|
||||||
|
AmneziaPremiumV2,
|
||||||
|
SelfHosted,
|
||||||
|
ExternalPremium,
|
||||||
|
|
||||||
|
SelfHostedAdmin = 8,
|
||||||
|
SelfHostedUser,
|
||||||
|
Native,
|
||||||
|
Invalid
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ConfigSource {
|
||||||
|
Telegram = 1,
|
||||||
|
AmneziaGateway
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isServerFromApi(const QJsonObject &serverConfigObject);
|
||||||
|
|
||||||
|
ConfigSource getConfigSource(const QJsonObject &serverConfigObject);
|
||||||
|
|
||||||
|
ConfigType configTypeFromJson(const QJsonObject &serverConfigObject);
|
||||||
|
|
||||||
|
bool isLegacyApiSubscription(ConfigType configType);
|
||||||
|
|
||||||
|
bool isApiV2Subscription(ConfigType configType);
|
||||||
|
|
||||||
|
} // namespace serverConfigUtils
|
||||||
|
|
||||||
|
#endif // SERVERCONFIGUTILS_H
|
||||||
@@ -977,7 +977,9 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
|||||||
}
|
}
|
||||||
#if !MACOS_NE
|
#if !MACOS_NE
|
||||||
UIViewController *qtController = getViewController();
|
UIViewController *qtController = getViewController();
|
||||||
if (!qtController) return;
|
if (!qtController) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian";\
|
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install --install-recommends"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian";\
|
||||||
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora";\
|
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora";\
|
||||||
elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos";\
|
elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos";\
|
||||||
elif which zypper > /dev/null 2>&1; then pm=$(which zypper); silent_inst="-nq install"; check_pkgs="-nq refresh"; docker_pkg="docker"; dist="opensuse";\
|
elif which zypper > /dev/null 2>&1; then pm=$(which zypper); silent_inst="-nq install"; check_pkgs="-nq refresh"; docker_pkg="docker"; dist="opensuse";\
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
FROM amneziavpn/mtproxy:latest
|
||||||
|
|
||||||
|
RUN mkdir -p /opt/amnezia /data
|
||||||
|
RUN printf '#!/bin/sh\ntail -f /dev/null\n' > /opt/amnezia/start.sh && \
|
||||||
|
chmod a+x /opt/amnezia/start.sh
|
||||||
|
|
||||||
|
VOLUME /data
|
||||||
|
ENTRYPOINT ["/bin/sh", "/opt/amnezia/start.sh"]
|
||||||
|
CMD [""]
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Download Telegram config files
|
||||||
|
curl -s https://core.telegram.org/getProxySecret -o /data/proxy-secret
|
||||||
|
curl -s https://core.telegram.org/getProxyConfig -o /data/proxy-multi.conf
|
||||||
|
|
||||||
|
# Determine secret: env var -> saved file -> generate new
|
||||||
|
if [ -n "$MTPROXY_SECRET" ]; then
|
||||||
|
SECRET="$MTPROXY_SECRET"
|
||||||
|
elif [ -f /data/secret ]; then
|
||||||
|
SECRET=$(cat /data/secret)
|
||||||
|
else
|
||||||
|
SECRET=$(openssl rand -hex 16)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate: must be exactly 32 hex chars
|
||||||
|
echo "$SECRET" | grep -qE '^[0-9a-fA-F]{32}$' || SECRET=$(openssl rand -hex 16)
|
||||||
|
|
||||||
|
# Persist secret for start.sh restarts
|
||||||
|
echo "$SECRET" > /data/secret
|
||||||
|
|
||||||
|
# Detect external IP
|
||||||
|
IP=$(curl -s --max-time 5 https://api.ipify.org 2>/dev/null)
|
||||||
|
[ -z "$IP" ] && IP=$(curl -s --max-time 5 https://ifconfig.me 2>/dev/null)
|
||||||
|
[ -z "$IP" ] && IP=$(curl -s --max-time 5 https://icanhazip.com 2>/dev/null)
|
||||||
|
|
||||||
|
# Use custom public host/domain if provided, otherwise fall back to detected IP
|
||||||
|
if [ -n "$MTPROXY_PUBLIC_HOST" ]; then
|
||||||
|
LINK_HOST="$MTPROXY_PUBLIC_HOST"
|
||||||
|
else
|
||||||
|
LINK_HOST="$IP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PORT=$MTPROXY_PORT
|
||||||
|
|
||||||
|
# Transport mode is substituted by replaceVars — plain variable, no curly braces
|
||||||
|
TRANSPORT_MODE=$MTPROXY_TRANSPORT_MODE
|
||||||
|
|
||||||
|
PADDED_SECRET="dd${SECRET}"
|
||||||
|
|
||||||
|
if [ "$TRANSPORT_MODE" = "faketls" ] && [ -n "$MTPROXY_TLS_DOMAIN" ]; then
|
||||||
|
DOMAIN_HEX=$(echo -n "$MTPROXY_TLS_DOMAIN" | od -A n -t x1 | tr -d ' \n')
|
||||||
|
FAKETLS_SECRET="ee${SECRET}${DOMAIN_HEX}"
|
||||||
|
else
|
||||||
|
FAKETLS_SECRET=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Active link secret depends on transport mode
|
||||||
|
if [ "$TRANSPORT_MODE" = "faketls" ] && [ -n "$FAKETLS_SECRET" ]; then
|
||||||
|
LINK_SECRET="$FAKETLS_SECRET"
|
||||||
|
else
|
||||||
|
LINK_SECRET="$PADDED_SECRET"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Output stable markers — parsed by updateContainerConfigAfterInstallation()
|
||||||
|
echo "[*] MTProxy configuration"
|
||||||
|
echo "[*] Secret: ${SECRET}"
|
||||||
|
echo "[*] FakeTLS: ${FAKETLS_SECRET}"
|
||||||
|
echo "[*] tg:// link: tg://proxy?server=${LINK_HOST}&port=${PORT}&secret=${LINK_SECRET}"
|
||||||
|
echo "[*] t.me link: https://t.me/proxy?server=${LINK_HOST}&port=${PORT}&secret=${LINK_SECRET}"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Run container
|
||||||
|
sudo docker run -d \
|
||||||
|
--log-driver none \
|
||||||
|
--restart always \
|
||||||
|
-p $MTPROXY_PORT:$MTPROXY_PORT/tcp \
|
||||||
|
-v amnezia-mtproxy-data:/data \
|
||||||
|
--name $CONTAINER_NAME \
|
||||||
|
$CONTAINER_NAME
|
||||||
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "Container startup"
|
||||||
|
|
||||||
|
# Read persisted secret
|
||||||
|
SECRET=""
|
||||||
|
if [ -f /data/secret ]; then
|
||||||
|
SECRET=$(cat /data/secret)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$SECRET" ]; then
|
||||||
|
echo "ERROR: /data/secret not found — run configure_container first"
|
||||||
|
tail -f /dev/null
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build tag argument
|
||||||
|
TAG_ARG=""
|
||||||
|
if [ -n "$MTPROXY_TAG" ]; then
|
||||||
|
TAG_ARG="-P $MTPROXY_TAG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build domain argument for FakeTLS mode
|
||||||
|
DOMAIN_ARG=""
|
||||||
|
if [ "$MTPROXY_TRANSPORT_MODE" = "faketls" ] && [ -n "$MTPROXY_TLS_DOMAIN" ]; then
|
||||||
|
DOMAIN_ARG="--domain $MTPROXY_TLS_DOMAIN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
WORKERS=$MTPROXY_WORKERS
|
||||||
|
STATS_PORT=2398
|
||||||
|
LISTEN_PORT=$MTPROXY_PORT
|
||||||
|
|
||||||
|
NAT_FLAG=""
|
||||||
|
NAT_VALUE=""
|
||||||
|
if [ "$MTPROXY_NAT_ENABLED" = "1" ] && [ -n "$MTPROXY_NAT_INTERNAL_IP" ] && [ -n "$MTPROXY_NAT_EXTERNAL_IP" ]; then
|
||||||
|
NAT_FLAG="--nat-info"
|
||||||
|
NAT_VALUE="$MTPROXY_NAT_INTERNAL_IP:$MTPROXY_NAT_EXTERNAL_IP"
|
||||||
|
else
|
||||||
|
INTERNAL_IP=$(hostname -i 2>/dev/null | awk '{print $1}')
|
||||||
|
EXTERNAL_IP=$(curl -s --max-time 5 https://api.ipify.org 2>/dev/null)
|
||||||
|
[ -z "$EXTERNAL_IP" ] && EXTERNAL_IP=$(curl -s --max-time 5 https://ifconfig.me 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -n "$INTERNAL_IP" ] && [ -n "$EXTERNAL_IP" ] && [ "$INTERNAL_IP" != "$EXTERNAL_IP" ]; then
|
||||||
|
NAT_FLAG="--nat-info"
|
||||||
|
NAT_VALUE="${INTERNAL_IP}:${EXTERNAL_IP}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build additional secrets arguments
|
||||||
|
ADDITIONAL_SECRETS_ARG=""
|
||||||
|
if [ -n "$MTPROXY_ADDITIONAL_SECRETS" ]; then
|
||||||
|
for S in $(echo "$MTPROXY_ADDITIONAL_SECRETS" | tr ',' ' '); do
|
||||||
|
ADDITIONAL_SECRETS_ARG="$ADDITIONAL_SECRETS_ARG -S $S"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start proxy (foreground)
|
||||||
|
exec mtproto-proxy \
|
||||||
|
-u root \
|
||||||
|
-p ${STATS_PORT} \
|
||||||
|
-H ${LISTEN_PORT} \
|
||||||
|
-S ${SECRET} \
|
||||||
|
${ADDITIONAL_SECRETS_ARG} \
|
||||||
|
--aes-pwd /data/proxy-secret \
|
||||||
|
-M ${WORKERS} \
|
||||||
|
-C 60000 \
|
||||||
|
--allow-skip-dh \
|
||||||
|
${NAT_FLAG:+${NAT_FLAG} ${NAT_VALUE}} \
|
||||||
|
${TAG_ARG} \
|
||||||
|
${DOMAIN_ARG} \
|
||||||
|
/data/proxy-multi.conf
|
||||||
@@ -24,6 +24,14 @@
|
|||||||
<file>ipsec/run_container.sh</file>
|
<file>ipsec/run_container.sh</file>
|
||||||
<file>ipsec/start.sh</file>
|
<file>ipsec/start.sh</file>
|
||||||
<file>ipsec/strongswan.profile</file>
|
<file>ipsec/strongswan.profile</file>
|
||||||
|
<file>mtproxy/configure_container.sh</file>
|
||||||
|
<file>mtproxy/Dockerfile</file>
|
||||||
|
<file>mtproxy/run_container.sh</file>
|
||||||
|
<file>mtproxy/start.sh</file>
|
||||||
|
<file>telemt/configure_container.sh</file>
|
||||||
|
<file>telemt/Dockerfile</file>
|
||||||
|
<file>telemt/run_container.sh</file>
|
||||||
|
<file>telemt/start.sh</file>
|
||||||
<file>openvpn/configure_container.sh</file>
|
<file>openvpn/configure_container.sh</file>
|
||||||
<file>openvpn/Dockerfile</file>
|
<file>openvpn/Dockerfile</file>
|
||||||
<file>openvpn/run_container.sh</file>
|
<file>openvpn/run_container.sh</file>
|
||||||
@@ -55,4 +63,3 @@
|
|||||||
<file>xray/template.json</file>
|
<file>xray/template.json</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
# Debian-based image with Telemt binary (shell + jq for Amnezia configure scripts).
|
||||||
|
# Binary from https://github.com/telemt/telemt releases (same pattern as upstream Dockerfile minimal stage).
|
||||||
|
|
||||||
|
FROM debian:12-slim
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
binutils \
|
||||||
|
ca-certificates \
|
||||||
|
curl \
|
||||||
|
jq \
|
||||||
|
openssl \
|
||||||
|
tar \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Use machine arch (works with classic `docker build`; TARGETARCH is only set with BuildKit).
|
||||||
|
RUN set -eux; \
|
||||||
|
ARCH="$(uname -m)"; \
|
||||||
|
case "$ARCH" in \
|
||||||
|
x86_64) ASSET="telemt-x86_64-linux-musl.tar.gz" ;; \
|
||||||
|
aarch64|arm64) ASSET="telemt-aarch64-linux-musl.tar.gz" ;; \
|
||||||
|
*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; \
|
||||||
|
esac; \
|
||||||
|
curl -fL --retry 5 --retry-delay 3 --connect-timeout 10 --max-time 120 \
|
||||||
|
-o "/tmp/${ASSET}" "https://github.com/telemt/telemt/releases/latest/download/${ASSET}"; \
|
||||||
|
curl -fL --retry 5 --retry-delay 3 --connect-timeout 10 --max-time 120 \
|
||||||
|
-o "/tmp/${ASSET}.sha256" "https://github.com/telemt/telemt/releases/latest/download/${ASSET}.sha256"; \
|
||||||
|
cd /tmp && sha256sum -c "${ASSET}.sha256"; \
|
||||||
|
tar -xzf "${ASSET}" -C /tmp; \
|
||||||
|
test -f /tmp/telemt; \
|
||||||
|
install -m 0755 /tmp/telemt /usr/local/bin/telemt; \
|
||||||
|
strip --strip-unneeded /usr/local/bin/telemt || true; \
|
||||||
|
rm -f "/tmp/${ASSET}" "/tmp/${ASSET}.sha256" /tmp/telemt
|
||||||
|
|
||||||
|
RUN mkdir -p /opt/amnezia /data
|
||||||
|
RUN printf '#!/bin/sh\ntail -f /dev/null\n' > /opt/amnezia/start.sh && \
|
||||||
|
chmod a+x /opt/amnezia/start.sh
|
||||||
|
|
||||||
|
VOLUME /data
|
||||||
|
ENTRYPOINT ["/bin/sh", "/opt/amnezia/start.sh"]
|
||||||
|
CMD [""]
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Do not use set -e: Telemt / curl / kill edge cases should not abort the whole configure step.
|
||||||
|
|
||||||
|
echo "[*] Amnezia Telemt: configure script start"
|
||||||
|
mkdir -p /data/tlsfront
|
||||||
|
|
||||||
|
# Secret: substituted $TELEMT_SECRET -> saved file -> openssl (same rules as MTProxy configure)
|
||||||
|
if [ -n "$TELEMT_SECRET" ]; then
|
||||||
|
SECRET="$TELEMT_SECRET"
|
||||||
|
elif [ -f /data/secret ]; then
|
||||||
|
SECRET=$(cat /data/secret)
|
||||||
|
else
|
||||||
|
SECRET=$(openssl rand -hex 16)
|
||||||
|
fi
|
||||||
|
# Must be exactly 32 hex chars
|
||||||
|
echo "$SECRET" | grep -qE '^[0-9a-fA-F]{32}$' || SECRET=$(openssl rand -hex 16)
|
||||||
|
|
||||||
|
# Build config.toml (other variables substituted on the host by Amnezia before upload)
|
||||||
|
rm -f /data/config.toml
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "### Amnezia Telemt — generated"
|
||||||
|
echo "[general]"
|
||||||
|
echo "use_middle_proxy = $TELEMT_USE_MIDDLE_PROXY"
|
||||||
|
echo "log_level = \"normal\""
|
||||||
|
if [ -n "$TELEMT_TAG" ]; then
|
||||||
|
echo "ad_tag = \"$TELEMT_TAG\""
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
echo "[general.modes]"
|
||||||
|
echo "classic = false"
|
||||||
|
echo "secure = $TELEMT_TOML_SECURE"
|
||||||
|
echo "tls = $TELEMT_TOML_TLS"
|
||||||
|
echo ""
|
||||||
|
echo "[general.links]"
|
||||||
|
echo "show = \"*\""
|
||||||
|
if [ -n "$TELEMT_PUBLIC_HOST" ]; then
|
||||||
|
echo "public_host = \"$TELEMT_PUBLIC_HOST\""
|
||||||
|
fi
|
||||||
|
echo "public_port = $TELEMT_PORT"
|
||||||
|
echo ""
|
||||||
|
echo "[server]"
|
||||||
|
echo "port = $TELEMT_PORT"
|
||||||
|
echo ""
|
||||||
|
echo "[server.api]"
|
||||||
|
echo "enabled = true"
|
||||||
|
echo "listen = \"0.0.0.0:9091\""
|
||||||
|
# Match upstream Telemt default: localhost API only (curl in this script uses 127.0.0.1).
|
||||||
|
echo "whitelist = [\"127.0.0.0/8\"]"
|
||||||
|
echo ""
|
||||||
|
echo "[[server.listeners]]"
|
||||||
|
echo "ip = \"0.0.0.0\""
|
||||||
|
echo ""
|
||||||
|
echo "[censorship]"
|
||||||
|
echo "tls_domain = \"$TELEMT_TLS_DOMAIN\""
|
||||||
|
echo "mask = $TELEMT_MASK"
|
||||||
|
echo "tls_emulation = $TELEMT_TLS_EMULATION"
|
||||||
|
echo "tls_front_dir = \"/data/tlsfront\""
|
||||||
|
echo ""
|
||||||
|
echo "[access.users]"
|
||||||
|
echo "$TELEMT_USER_NAME = \"$SECRET\""
|
||||||
|
} > /data/config.toml
|
||||||
|
|
||||||
|
echo "$SECRET" > /data/secret
|
||||||
|
chmod 600 /data/secret 2>/dev/null || true
|
||||||
|
|
||||||
|
# Do not start telemt here: a long-lived process + curl loop inside `docker exec` can confuse SSH/Docker
|
||||||
|
# timing and is unnecessary — start.sh runs telemt after configure. Links can be empty until the service
|
||||||
|
# is up; the client still parses Secret below.
|
||||||
|
echo "[*] Telemt configuration"
|
||||||
|
echo "[*] Secret: $SECRET"
|
||||||
|
echo "[*] tg:// link: "
|
||||||
|
echo "[*] t.me link: "
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Run container (ulimit per Telemt docs — avoids "Too many open files" under load)
|
||||||
|
sudo docker run -d \
|
||||||
|
--log-driver none \
|
||||||
|
--restart always \
|
||||||
|
--ulimit nofile=65536:65536 \
|
||||||
|
-p $TELEMT_PORT:$TELEMT_PORT/tcp \
|
||||||
|
-v amnezia-telemt-data:/data \
|
||||||
|
--name $CONTAINER_NAME \
|
||||||
|
$CONTAINER_NAME
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "Container startup (Telemt)"
|
||||||
|
|
||||||
|
if [ ! -f /data/config.toml ]; then
|
||||||
|
echo "ERROR: /data/config.toml not found — run configure_container first"
|
||||||
|
tail -f /dev/null
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p /data/tlsfront
|
||||||
|
exec /usr/local/bin/telemt /data/config.toml
|
||||||
@@ -95,15 +95,6 @@ target_link_libraries(test_servers_model_sync PRIVATE
|
|||||||
test_common
|
test_common
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(test_gateway_stacks
|
|
||||||
testGatewayStacks.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(test_gateway_stacks PRIVATE
|
|
||||||
Qt6::Test
|
|
||||||
test_common
|
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(test_complex_operations
|
add_executable(test_complex_operations
|
||||||
testComplexOperations.cpp
|
testComplexOperations.cpp
|
||||||
)
|
)
|
||||||
@@ -148,7 +139,6 @@ add_test(NAME DefaultServerChangeTest COMMAND test_default_server_change)
|
|||||||
add_test(NAME ServerEdgeCasesTest COMMAND test_server_edge_cases)
|
add_test(NAME ServerEdgeCasesTest COMMAND test_server_edge_cases)
|
||||||
add_test(NAME SignalOrderTest COMMAND test_signal_order)
|
add_test(NAME SignalOrderTest COMMAND test_signal_order)
|
||||||
add_test(NAME ServersModelSyncTest COMMAND test_servers_model_sync)
|
add_test(NAME ServersModelSyncTest COMMAND test_servers_model_sync)
|
||||||
add_test(NAME GatewayStacksTest COMMAND test_gateway_stacks)
|
|
||||||
add_test(NAME ComplexOperationsTest COMMAND test_complex_operations)
|
add_test(NAME ComplexOperationsTest COMMAND test_complex_operations)
|
||||||
add_test(NAME SettingsSignalsTest COMMAND test_settings_signals)
|
add_test(NAME SettingsSignalsTest COMMAND test_settings_signals)
|
||||||
add_test(NAME UiServersModelAndControllerTest COMMAND test_ui_servers_model_and_controller)
|
add_test(NAME UiServersModelAndControllerTest COMMAND test_ui_servers_model_and_controller)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include <QSignalSpy>
|
#include <QSignalSpy>
|
||||||
|
|
||||||
#include "core/controllers/coreController.h"
|
#include "core/controllers/coreController.h"
|
||||||
#include "core/models/serverConfig.h"
|
#include "core/utils/constants/configKeys.h"
|
||||||
#include "vpnConnection.h"
|
#include "vpnConnection.h"
|
||||||
#include "secureQSettings.h"
|
#include "secureQSettings.h"
|
||||||
|
|
||||||
@@ -117,8 +117,8 @@ private slots:
|
|||||||
QVERIFY2(defaultServerChangedSpy.count() == 0, "defaultServerChanged signal should NOT be emitted (default is already 0)");
|
QVERIFY2(defaultServerChangedSpy.count() == 0, "defaultServerChanged signal should NOT be emitted (default is already 0)");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->serversCount() > 0, "Server should be added");
|
QVERIFY2(m_coreController->m_serversRepository->serversCount() > 0, "Server should be added");
|
||||||
|
|
||||||
int serverIndex = m_coreController->m_serversRepository->defaultServerIndex();
|
const QString serverId = m_coreController->m_serversRepository->defaultServerId();
|
||||||
auto exportResult = m_coreController->m_exportController->generateFullAccessConfig(serverIndex);
|
auto exportResult = m_coreController->m_exportController->generateFullAccessConfig(serverId);
|
||||||
|
|
||||||
QVERIFY2(exportResult.errorCode == ErrorCode::NoError, "Export should succeed");
|
QVERIFY2(exportResult.errorCode == ErrorCode::NoError, "Export should succeed");
|
||||||
QVERIFY2(!exportResult.config.isEmpty(), "Exported config should not be empty");
|
QVERIFY2(!exportResult.config.isEmpty(), "Exported config should not be empty");
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
#include <QSignalSpy>
|
#include <QSignalSpy>
|
||||||
|
|
||||||
#include "core/controllers/coreController.h"
|
#include "core/controllers/coreController.h"
|
||||||
#include "core/models/serverConfig.h"
|
#include "core/models/serverDescription.h"
|
||||||
|
#include "tests/testServerRepositoryHelpers.h"
|
||||||
#include "vpnConnection.h"
|
#include "vpnConnection.h"
|
||||||
#include "secureQSettings.h"
|
#include "secureQSettings.h"
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ private slots:
|
|||||||
void init() {
|
void init() {
|
||||||
m_settings->clearSettings();
|
m_settings->clearSettings();
|
||||||
if (m_coreController->m_serversModel) {
|
if (m_coreController->m_serversModel) {
|
||||||
m_coreController->m_serversModel->updateModel(QVector<ServerConfig>(), -1, false);
|
m_coreController->m_serversModel->updateModel(QVector<ServerDescription>(), -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,35 +66,33 @@ private slots:
|
|||||||
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 3, "Should have 3 servers");
|
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 3, "Should have 3 servers");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 2, "Default should be index 2");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 2, "Default should be index 2");
|
||||||
|
|
||||||
ServerConfig server0 = m_coreController->m_serversController->getServerConfig(0);
|
amnezia::test::setServerDescription(m_coreController->m_serversRepository,
|
||||||
server0.visit([](auto& arg) {
|
m_coreController->m_serversController->getServerId(0),
|
||||||
arg.description = "Edited First Server";
|
QStringLiteral("Edited First Server"));
|
||||||
});
|
|
||||||
m_coreController->m_serversController->editServer(0, server0);
|
|
||||||
|
|
||||||
QVERIFY2(serverEditedSpy.count() == 1, "serverEdited should be emitted");
|
QVERIFY2(serverEditedSpy.count() == 1, "serverEdited should be emitted");
|
||||||
QString editedDesc0 = m_coreController->m_serversRepository->server(0).description();
|
QString editedDesc0 = amnezia::test::serverDescription(m_coreController->m_serversRepository,
|
||||||
|
m_coreController->m_serversRepository->serverIdAt(0));
|
||||||
QVERIFY2(editedDesc0 == "Edited First Server", "First server should be edited");
|
QVERIFY2(editedDesc0 == "Edited First Server", "First server should be edited");
|
||||||
|
|
||||||
m_coreController->m_serversController->removeServer(1);
|
m_coreController->m_serversController->removeServer(m_coreController->m_serversController->getServerId(1));
|
||||||
|
|
||||||
QVERIFY2(serverRemovedSpy.count() == 1, "serverRemoved should be emitted");
|
QVERIFY2(serverRemovedSpy.count() == 1, "serverRemoved should be emitted");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 2, "Should have 2 servers");
|
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 2, "Should have 2 servers");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 1, "Default should be index 1 (was 2, removed 1)");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 1, "Default should be index 1 (was 2, removed 1)");
|
||||||
|
|
||||||
m_coreController->m_serversController->setDefaultServerIndex(0);
|
m_coreController->m_serversController->setDefaultServer(m_coreController->m_serversController->getServerId(0));
|
||||||
|
|
||||||
QVERIFY2(defaultServerChangedSpy.count() == 4, "defaultServerChanged should be emitted again");
|
QVERIFY2(defaultServerChangedSpy.count() == 4, "defaultServerChanged should be emitted again");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "Default should be index 0");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "Default should be index 0");
|
||||||
|
|
||||||
ServerConfig server0After = m_coreController->m_serversController->getServerConfig(0);
|
amnezia::test::setServerDescription(m_coreController->m_serversRepository,
|
||||||
server0After.visit([](auto& arg) {
|
m_coreController->m_serversController->getServerId(0),
|
||||||
arg.description = "Final Edited Server";
|
QStringLiteral("Final Edited Server"));
|
||||||
});
|
|
||||||
m_coreController->m_serversController->editServer(0, server0After);
|
|
||||||
|
|
||||||
QVERIFY2(serverEditedSpy.count() == 2, "serverEdited should be emitted again");
|
QVERIFY2(serverEditedSpy.count() == 2, "serverEdited should be emitted again");
|
||||||
QString finalDesc0 = m_coreController->m_serversRepository->server(0).description();
|
QString finalDesc0 = amnezia::test::serverDescription(m_coreController->m_serversRepository,
|
||||||
|
m_coreController->m_serversRepository->serverIdAt(0));
|
||||||
QVERIFY2(finalDesc0 == "Final Edited Server", "First server should be edited again");
|
QVERIFY2(finalDesc0 == "Final Edited Server", "First server should be edited again");
|
||||||
|
|
||||||
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 2, "Final servers count should be 2");
|
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 2, "Final servers count should be 2");
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
#include <QSignalSpy>
|
#include <QSignalSpy>
|
||||||
|
|
||||||
#include "core/controllers/coreController.h"
|
#include "core/controllers/coreController.h"
|
||||||
#include "core/models/serverConfig.h"
|
#include "core/models/serverDescription.h"
|
||||||
|
#include "tests/testServerRepositoryHelpers.h"
|
||||||
#include "ui/models/serversModel.h"
|
#include "ui/models/serversModel.h"
|
||||||
#include "vpnConnection.h"
|
#include "vpnConnection.h"
|
||||||
#include "secureQSettings.h"
|
#include "secureQSettings.h"
|
||||||
@@ -39,7 +40,7 @@ private slots:
|
|||||||
m_settings->clearSettings();
|
m_settings->clearSettings();
|
||||||
m_coreController->m_serversRepository->invalidateCache();
|
m_coreController->m_serversRepository->invalidateCache();
|
||||||
if (m_coreController->m_serversModel) {
|
if (m_coreController->m_serversModel) {
|
||||||
m_coreController->m_serversModel->updateModel(QVector<ServerConfig>(), -1, false);
|
m_coreController->m_serversModel->updateModel(QVector<ServerDescription>(), -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,9 +61,10 @@ private slots:
|
|||||||
|
|
||||||
QSignalSpy defaultServerChangedSpy(m_coreController->m_serversRepository, &SecureServersRepository::defaultServerChanged);
|
QSignalSpy defaultServerChangedSpy(m_coreController->m_serversRepository, &SecureServersRepository::defaultServerChanged);
|
||||||
|
|
||||||
m_coreController->m_serversController->setDefaultServerIndex(0);
|
m_coreController->m_serversController->setDefaultServer(m_coreController->m_serversController->getServerId(0));
|
||||||
QVERIFY2(defaultServerChangedSpy.count() == 1, "defaultServerChanged signal should be emitted");
|
QVERIFY2(defaultServerChangedSpy.count() == 1, "defaultServerChanged signal should be emitted");
|
||||||
QVERIFY2(defaultServerChangedSpy.at(0).at(0).toInt() == 0, "defaultServerChanged should emit index 0");
|
QVERIFY2(defaultServerChangedSpy.at(0).at(0).toString() == m_coreController->m_serversController->getServerId(0),
|
||||||
|
"defaultServerChanged should emit new default server id");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "Default server index should be 0");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "Default server index should be 0");
|
||||||
|
|
||||||
if (m_coreController->m_serversModel) {
|
if (m_coreController->m_serversModel) {
|
||||||
@@ -70,9 +72,10 @@ private slots:
|
|||||||
QVERIFY2(modelDefaultIndex == 0, "Model should reflect default server");
|
QVERIFY2(modelDefaultIndex == 0, "Model should reflect default server");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_coreController->m_serversController->setDefaultServerIndex(2);
|
m_coreController->m_serversController->setDefaultServer(m_coreController->m_serversController->getServerId(2));
|
||||||
QVERIFY2(defaultServerChangedSpy.count() == 2, "defaultServerChanged signal should be emitted again");
|
QVERIFY2(defaultServerChangedSpy.count() == 2, "defaultServerChanged signal should be emitted again");
|
||||||
QVERIFY2(defaultServerChangedSpy.at(1).at(0).toInt() == 2, "defaultServerChanged should emit index 2");
|
QVERIFY2(defaultServerChangedSpy.at(1).at(0).toString() == m_coreController->m_serversController->getServerId(2),
|
||||||
|
"defaultServerChanged should emit new default server id");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 2, "Default server index should be 2");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 2, "Default server index should be 2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,28 +97,28 @@ private slots:
|
|||||||
QSignalSpy defaultServerChangedSpy(m_coreController->m_serversRepository, &SecureServersRepository::defaultServerChanged);
|
QSignalSpy defaultServerChangedSpy(m_coreController->m_serversRepository, &SecureServersRepository::defaultServerChanged);
|
||||||
QSignalSpy serverRemovedSpy(m_coreController->m_serversRepository, &SecureServersRepository::serverRemoved);
|
QSignalSpy serverRemovedSpy(m_coreController->m_serversRepository, &SecureServersRepository::serverRemoved);
|
||||||
|
|
||||||
m_coreController->m_serversController->removeServer(0);
|
m_coreController->m_serversController->removeServer(m_coreController->m_serversController->getServerId(0));
|
||||||
QVERIFY2(serverRemovedSpy.count() == 1, "serverRemoved signal should be emitted");
|
QVERIFY2(serverRemovedSpy.count() == 1, "serverRemoved signal should be emitted");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 2, "Should have 2 servers");
|
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 2, "Should have 2 servers");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 1, "Default should be index 1 (was 2, removed 0)");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 1, "Default should be index 1 (was 2, removed 0)");
|
||||||
|
|
||||||
ServerConfig remainingServer1 = m_coreController->m_serversRepository->server(0);
|
QString desc1 = amnezia::test::serverDescription(m_coreController->m_serversRepository,
|
||||||
ServerConfig remainingServer2 = m_coreController->m_serversRepository->server(1);
|
m_coreController->m_serversRepository->serverIdAt(0));
|
||||||
QString desc1 = remainingServer1.description();
|
QString desc2 = amnezia::test::serverDescription(m_coreController->m_serversRepository,
|
||||||
QString desc2 = remainingServer2.description();
|
m_coreController->m_serversRepository->serverIdAt(1));
|
||||||
QVERIFY2(desc1 == "Xray Server", "First remaining server should be Xray");
|
QVERIFY2(desc1 == "Xray Server", "First remaining server should be Xray");
|
||||||
QVERIFY2(desc2 == "WireGuard Server", "Second remaining server should be WireGuard");
|
QVERIFY2(desc2 == "WireGuard Server", "Second remaining server should be WireGuard");
|
||||||
|
|
||||||
defaultServerChangedSpy.clear();
|
defaultServerChangedSpy.clear();
|
||||||
serverRemovedSpy.clear();
|
serverRemovedSpy.clear();
|
||||||
|
|
||||||
m_coreController->m_serversController->removeServer(0);
|
m_coreController->m_serversController->removeServer(m_coreController->m_serversController->getServerId(0));
|
||||||
QVERIFY2(serverRemovedSpy.count() == 1, "serverRemoved signal should be emitted");
|
QVERIFY2(serverRemovedSpy.count() == 1, "serverRemoved signal should be emitted");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 1, "Should have 1 server");
|
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 1, "Should have 1 server");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "Default should be index 0 (was 1, removed 0)");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "Default should be index 0 (was 1, removed 0)");
|
||||||
|
|
||||||
ServerConfig lastServer = m_coreController->m_serversRepository->server(0);
|
QString lastDesc = amnezia::test::serverDescription(m_coreController->m_serversRepository,
|
||||||
QString lastDesc = lastServer.description();
|
m_coreController->m_serversRepository->serverIdAt(0));
|
||||||
QVERIFY2(lastDesc == "WireGuard Server", "Last server should be WireGuard");
|
QVERIFY2(lastDesc == "WireGuard Server", "Last server should be WireGuard");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
#include <QTest>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QUuid>
|
|
||||||
#include <QSignalSpy>
|
|
||||||
|
|
||||||
#include "core/controllers/coreController.h"
|
|
||||||
#include "core/models/serverConfig.h"
|
|
||||||
#include "vpnConnection.h"
|
|
||||||
#include "secureQSettings.h"
|
|
||||||
|
|
||||||
using namespace amnezia;
|
|
||||||
|
|
||||||
class TestGatewayStacks : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
private:
|
|
||||||
CoreController* m_coreController;
|
|
||||||
SecureQSettings* m_settings;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void initTestCase() {
|
|
||||||
QString testOrg = "AmneziaVPN-Test-" + QUuid::createUuid().toString();
|
|
||||||
m_settings = new SecureQSettings(testOrg, "amnezia-client", nullptr, false);
|
|
||||||
|
|
||||||
auto vpnConnection = QSharedPointer<VpnConnection>::create(nullptr, nullptr);
|
|
||||||
m_coreController = new CoreController(vpnConnection, m_settings, nullptr, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cleanupTestCase() {
|
|
||||||
m_settings->clearSettings();
|
|
||||||
delete m_coreController;
|
|
||||||
delete m_settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init() {
|
|
||||||
m_settings->clearSettings();
|
|
||||||
if (m_coreController->m_serversModel) {
|
|
||||||
m_coreController->m_serversModel->updateModel(QVector<ServerConfig>(), -1, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testGatewayStacksRecomputeOnServerOperations() {
|
|
||||||
QString awgKey = "vpn://AAABFHjadZBBT4QwEIX_ipkzS2wBJdyMB1cPXvbgwRgyQnclgZa0RTYS_rszXRa52Mt77TfzOu0EldEeG62sg-J9AhxPUEywF1CAuF3WTl4dRLCXhJIVpVuUEMpWdLdFKaH7FeUb9Mx3scpFk0XTRbOLvlSkKZsOz-Gi4BsdRiV_EGEydhwlg0tWynEZmd5Yz1bkoaK3xpvKtOU3_UFjOE3SsRs-tfIl1rVVzoWQOI9FzC3eonYcU4ZmgkPdwxz9fSYdYafVT4M7-lEJ80cEtTri0PrH_2q4wlW26f1lioe3p5uDsjQWoS_j_Ct2ipvGU6zO2PWtiivT8RPQudHYmqBXzl-3Yn2slBEMTtklgYt4C_Mv3ROMwA";
|
|
||||||
|
|
||||||
QSignalSpy gatewayStacksExpandedSpy(m_coreController->m_serversController, &ServersController::gatewayStacksExpanded);
|
|
||||||
QSignalSpy serverAddedSpy(m_coreController->m_serversRepository, &SecureServersRepository::serverAdded);
|
|
||||||
QSignalSpy serverEditedSpy(m_coreController->m_serversRepository, &SecureServersRepository::serverEdited);
|
|
||||||
QSignalSpy serverRemovedSpy(m_coreController->m_serversRepository, &SecureServersRepository::serverRemoved);
|
|
||||||
|
|
||||||
auto importResult = m_coreController->m_importCoreController->extractConfigFromData(awgKey);
|
|
||||||
m_coreController->m_importCoreController->importConfig(importResult.config);
|
|
||||||
|
|
||||||
QVERIFY2(serverAddedSpy.count() == 1, "serverAdded signal should be emitted");
|
|
||||||
QVERIFY2(m_coreController->m_serversController->gatewayStacks().isEmpty(), "Gateway stacks should be empty for self-hosted servers");
|
|
||||||
|
|
||||||
ServerConfig serverConfig = m_coreController->m_serversController->getServerConfig(0);
|
|
||||||
serverConfig.visit([](auto& arg) {
|
|
||||||
arg.description = "Edited Server";
|
|
||||||
});
|
|
||||||
m_coreController->m_serversController->editServer(0, serverConfig);
|
|
||||||
|
|
||||||
QVERIFY2(serverEditedSpy.count() == 1, "serverEdited signal should be emitted");
|
|
||||||
|
|
||||||
m_coreController->m_serversController->removeServer(0);
|
|
||||||
|
|
||||||
QVERIFY2(serverRemovedSpy.count() == 1, "serverRemoved signal should be emitted");
|
|
||||||
QVERIFY2(m_coreController->m_serversController->gatewayStacks().isEmpty(), "Gateway stacks should remain empty");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
QTEST_MAIN(TestGatewayStacks)
|
|
||||||
#include "testGatewayStacks.moc"
|
|
||||||
|
|
||||||
@@ -6,7 +6,8 @@
|
|||||||
#include <QSignalSpy>
|
#include <QSignalSpy>
|
||||||
|
|
||||||
#include "core/controllers/coreController.h"
|
#include "core/controllers/coreController.h"
|
||||||
#include "core/models/serverConfig.h"
|
#include "core/models/serverDescription.h"
|
||||||
|
#include "tests/testServerRepositoryHelpers.h"
|
||||||
#include "vpnConnection.h"
|
#include "vpnConnection.h"
|
||||||
#include "secureQSettings.h"
|
#include "secureQSettings.h"
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ private slots:
|
|||||||
m_settings->clearSettings();
|
m_settings->clearSettings();
|
||||||
m_coreController->m_serversRepository->invalidateCache();
|
m_coreController->m_serversRepository->invalidateCache();
|
||||||
if (m_coreController->m_serversModel) {
|
if (m_coreController->m_serversModel) {
|
||||||
m_coreController->m_serversModel->updateModel(QVector<ServerConfig>(), -1, false);
|
m_coreController->m_serversModel->updateModel(QVector<ServerDescription>(), -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,8 +71,8 @@ private slots:
|
|||||||
}
|
}
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "First server should be default");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "First server should be default");
|
||||||
|
|
||||||
ServerConfig server1 = m_coreController->m_serversRepository->server(0);
|
QString desc1 = amnezia::test::serverDescription(m_coreController->m_serversRepository,
|
||||||
QString desc1 = server1.description();
|
m_coreController->m_serversRepository->serverIdAt(0));
|
||||||
QVERIFY2(desc1 == "AWG Server", "First server description should match");
|
QVERIFY2(desc1 == "AWG Server", "First server description should match");
|
||||||
|
|
||||||
if (m_coreController->m_serversModel) {
|
if (m_coreController->m_serversModel) {
|
||||||
@@ -92,8 +93,8 @@ private slots:
|
|||||||
}
|
}
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 1, "Second server should be default");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 1, "Second server should be default");
|
||||||
|
|
||||||
ServerConfig server2 = m_coreController->m_serversRepository->server(1);
|
QString desc2 = amnezia::test::serverDescription(m_coreController->m_serversRepository,
|
||||||
QString desc2 = server2.description();
|
m_coreController->m_serversRepository->serverIdAt(1));
|
||||||
QVERIFY2(desc2 == "Xray Server", "Second server description should match");
|
QVERIFY2(desc2 == "Xray Server", "Second server description should match");
|
||||||
|
|
||||||
if (m_coreController->m_serversModel) {
|
if (m_coreController->m_serversModel) {
|
||||||
@@ -114,8 +115,8 @@ private slots:
|
|||||||
}
|
}
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 2, "Third server should be default");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 2, "Third server should be default");
|
||||||
|
|
||||||
ServerConfig server3 = m_coreController->m_serversRepository->server(2);
|
QString desc3 = amnezia::test::serverDescription(m_coreController->m_serversRepository,
|
||||||
QString desc3 = server3.description();
|
m_coreController->m_serversRepository->serverIdAt(2));
|
||||||
QVERIFY2(desc3 == "WireGuard Server", "Third server description should match");
|
QVERIFY2(desc3 == "WireGuard Server", "Third server description should match");
|
||||||
|
|
||||||
if (m_coreController->m_serversModel) {
|
if (m_coreController->m_serversModel) {
|
||||||
@@ -147,25 +148,25 @@ private slots:
|
|||||||
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 2, "After two imports servers count should be 2");
|
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 2, "After two imports servers count should be 2");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 1, "Second server should be default");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 1, "Second server should be default");
|
||||||
|
|
||||||
ServerConfig server0 = m_coreController->m_serversRepository->server(0);
|
QString desc0 = amnezia::test::serverDescription(m_coreController->m_serversRepository,
|
||||||
ServerConfig server1 = m_coreController->m_serversRepository->server(1);
|
m_coreController->m_serversRepository->serverIdAt(0));
|
||||||
QString desc0 = server0.description();
|
QString desc1 = amnezia::test::serverDescription(m_coreController->m_serversRepository,
|
||||||
QString desc1 = server1.description();
|
m_coreController->m_serversRepository->serverIdAt(1));
|
||||||
QVERIFY2(desc0 == "AWG Server", "First server description should match");
|
QVERIFY2(desc0 == "AWG Server", "First server description should match");
|
||||||
QVERIFY2(desc1 == "Xray Server", "Second server description should match");
|
QVERIFY2(desc1 == "Xray Server", "Second server description should match");
|
||||||
|
|
||||||
defaultServerChangedSpy.clear();
|
defaultServerChangedSpy.clear();
|
||||||
serverRemovedSpy.clear();
|
serverRemovedSpy.clear();
|
||||||
|
|
||||||
m_coreController->m_serversController->removeServer(0);
|
m_coreController->m_serversController->removeServer(m_coreController->m_serversController->getServerId(0));
|
||||||
|
|
||||||
QVERIFY2(serverRemovedSpy.count() == 1, "serverRemoved signal should be emitted");
|
QVERIFY2(serverRemovedSpy.count() == 1, "serverRemoved signal should be emitted");
|
||||||
QVERIFY2(serverRemovedSpy.at(0).at(0).toInt() == 0, "serverRemoved should emit index 0");
|
QVERIFY2(serverRemovedSpy.at(0).at(1).toInt() == 0, "serverRemoved should emit removed index 0");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 1, "After removing first server, servers count should be 1");
|
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 1, "After removing first server, servers count should be 1");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "After removing first server, default index should be 0");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "After removing first server, default index should be 0");
|
||||||
|
|
||||||
ServerConfig remainingServer = m_coreController->m_serversRepository->server(0);
|
QString remainingDesc = amnezia::test::serverDescription(m_coreController->m_serversRepository,
|
||||||
QString remainingDesc = remainingServer.description();
|
m_coreController->m_serversRepository->serverIdAt(0));
|
||||||
QVERIFY2(remainingDesc == "Xray Server", "Remaining server should be Xray Server");
|
QVERIFY2(remainingDesc == "Xray Server", "Remaining server should be Xray Server");
|
||||||
|
|
||||||
if (m_coreController->m_serversModel) {
|
if (m_coreController->m_serversModel) {
|
||||||
@@ -177,10 +178,10 @@ private slots:
|
|||||||
defaultServerChangedSpy.clear();
|
defaultServerChangedSpy.clear();
|
||||||
serverRemovedSpy.clear();
|
serverRemovedSpy.clear();
|
||||||
|
|
||||||
m_coreController->m_serversController->removeServer(0);
|
m_coreController->m_serversController->removeServer(m_coreController->m_serversController->getServerId(0));
|
||||||
|
|
||||||
QVERIFY2(serverRemovedSpy.count() == 1, "serverRemoved signal should be emitted");
|
QVERIFY2(serverRemovedSpy.count() == 1, "serverRemoved signal should be emitted");
|
||||||
QVERIFY2(serverRemovedSpy.at(0).at(0).toInt() == 0, "serverRemoved should emit index 0");
|
QVERIFY2(serverRemovedSpy.at(0).at(1).toInt() == 0, "serverRemoved should emit removed index 0");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 0, "After removing last server, servers count should be 0");
|
QVERIFY2(m_coreController->m_serversRepository->serversCount() == 0, "After removing last server, servers count should be 0");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "After removing last server, default index should be 0");
|
QVERIFY2(m_coreController->m_serversRepository->defaultServerIndex() == 0, "After removing last server, default index should be 0");
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "core/controllers/coreController.h"
|
#include "core/controllers/coreController.h"
|
||||||
#include "core/models/serverConfig.h"
|
#include "core/models/serverDescription.h"
|
||||||
#include "core/models/selfhosted/selfHostedServerConfig.h"
|
#include "core/models/selfhosted/selfHostedAdminServerConfig.h"
|
||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
#include "core/models/protocols/awgProtocolConfig.h"
|
#include "core/models/protocols/awgProtocolConfig.h"
|
||||||
#include "core/models/protocols/dnsProtocolConfig.h"
|
#include "core/models/protocols/dnsProtocolConfig.h"
|
||||||
@@ -60,21 +60,24 @@ private:
|
|||||||
qDebug() << "SSH connection successful. Output:" << sshOutput;
|
qDebug() << "SSH connection successful. Output:" << sshOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
void verifyAdminAccess(int serverIndex) {
|
void verifyAdminAccess(int serverIndex)
|
||||||
ServerConfig server = m_coreController->m_serversRepository->server(serverIndex);
|
{
|
||||||
const SelfHostedServerConfig* selfHosted = server.as<SelfHostedServerConfig>();
|
const QString serverId = m_coreController->m_serversRepository->serverIdAt(serverIndex);
|
||||||
QVERIFY2(selfHosted != nullptr, "Server config should be SelfHostedServerConfig");
|
const auto adminCfg = m_coreController->m_serversRepository->selfHostedAdminConfig(serverId);
|
||||||
|
QVERIFY2(adminCfg.has_value(), "Server config should be SelfHostedAdminServerConfig");
|
||||||
|
|
||||||
|
const SelfHostedAdminServerConfig &selfHosted = *adminCfg;
|
||||||
|
|
||||||
QVERIFY2(selfHosted->hasCredentials(),
|
QVERIFY2(selfHosted.hasCredentials(),
|
||||||
"Server should have credentials (admin access)");
|
"Server should have credentials (admin access)");
|
||||||
|
|
||||||
QVERIFY2(selfHosted->userName.has_value() && !selfHosted->userName.value().isEmpty(),
|
QVERIFY2(!selfHosted.userName.isEmpty(),
|
||||||
"Server should have userName for admin access");
|
"Server should have userName for admin access");
|
||||||
|
|
||||||
QVERIFY2(selfHosted->password.has_value() && !selfHosted->password.value().isEmpty(),
|
QVERIFY2(!selfHosted.password.isEmpty(),
|
||||||
"Server should have password for admin access");
|
"Server should have password for admin access");
|
||||||
|
|
||||||
QVERIFY2(!selfHosted->isReadOnly(),
|
QVERIFY2(!selfHosted.isReadOnly(),
|
||||||
"Server should not be read-only (should have admin access)");
|
"Server should not be read-only (should have admin access)");
|
||||||
|
|
||||||
if (m_coreController->m_serversModel) {
|
if (m_coreController->m_serversModel) {
|
||||||
@@ -143,7 +146,7 @@ private slots:
|
|||||||
void init() {
|
void init() {
|
||||||
m_settings->clearSettings();
|
m_settings->clearSettings();
|
||||||
if (m_coreController->m_serversModel) {
|
if (m_coreController->m_serversModel) {
|
||||||
m_coreController->m_serversModel->updateModel(QVector<ServerConfig>(), -1, false);
|
m_coreController->m_serversModel->updateModel(QVector<ServerDescription>(), -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,10 +180,10 @@ private slots:
|
|||||||
int serverIndex = m_coreController->m_serversRepository->serversCount() - 1;
|
int serverIndex = m_coreController->m_serversRepository->serversCount() - 1;
|
||||||
qDebug() << "Server with Awg container added at index:" << serverIndex;
|
qDebug() << "Server with Awg container added at index:" << serverIndex;
|
||||||
|
|
||||||
ServerConfig serverAfterAwg = m_coreController->m_serversRepository->server(serverIndex);
|
const auto adminAfterAwg = m_coreController->m_serversRepository->selfHostedAdminConfig(
|
||||||
QVERIFY2(serverAfterAwg.isSelfHosted(), "Server should be self-hosted");
|
m_coreController->m_serversRepository->serverIdAt(serverIndex));
|
||||||
const SelfHostedServerConfig* selfHostedAfterAwg = serverAfterAwg.as<SelfHostedServerConfig>();
|
QVERIFY2(adminAfterAwg.has_value(), "Server should be self-hosted (admin)");
|
||||||
QVERIFY2(selfHostedAfterAwg != nullptr, "Server config should be SelfHostedServerConfig");
|
const SelfHostedAdminServerConfig *selfHostedAfterAwg = &(*adminAfterAwg);
|
||||||
QVERIFY2(selfHostedAfterAwg->defaultContainer == DockerContainer::Awg, "Default container should be Awg");
|
QVERIFY2(selfHostedAfterAwg->defaultContainer == DockerContainer::Awg, "Default container should be Awg");
|
||||||
QVERIFY2(selfHostedAfterAwg->containers.contains(DockerContainer::Awg), "Server should have Awg container");
|
QVERIFY2(selfHostedAfterAwg->containers.contains(DockerContainer::Awg), "Server should have Awg container");
|
||||||
|
|
||||||
@@ -198,8 +201,9 @@ private slots:
|
|||||||
TransportProto dnsTransportProto = TransportProto::Udp;
|
TransportProto dnsTransportProto = TransportProto::Udp;
|
||||||
bool wasDnsInstalled = false;
|
bool wasDnsInstalled = false;
|
||||||
|
|
||||||
|
const QString serverIdForOps = m_coreController->m_serversRepository->serverIdAt(serverIndex);
|
||||||
ErrorCode installContainerError = m_coreController->m_installController->installContainer(
|
ErrorCode installContainerError = m_coreController->m_installController->installContainer(
|
||||||
serverIndex, DockerContainer::Dns, dnsPort, dnsTransportProto, wasDnsInstalled);
|
serverIdForOps, DockerContainer::Dns, dnsPort, dnsTransportProto, wasDnsInstalled);
|
||||||
|
|
||||||
QVERIFY2(installContainerError == ErrorCode::NoError,
|
QVERIFY2(installContainerError == ErrorCode::NoError,
|
||||||
QString("installContainer for Dns should succeed. Error: %1")
|
QString("installContainer for Dns should succeed. Error: %1")
|
||||||
@@ -207,9 +211,10 @@ private slots:
|
|||||||
.toUtf8().constData());
|
.toUtf8().constData());
|
||||||
qDebug() << "Dns container installed:" << wasDnsInstalled;
|
qDebug() << "Dns container installed:" << wasDnsInstalled;
|
||||||
|
|
||||||
ServerConfig serverAfterDns = m_coreController->m_serversRepository->server(serverIndex);
|
const auto adminAfterDns = m_coreController->m_serversRepository->selfHostedAdminConfig(
|
||||||
const SelfHostedServerConfig* selfHostedAfterDns = serverAfterDns.as<SelfHostedServerConfig>();
|
m_coreController->m_serversRepository->serverIdAt(serverIndex));
|
||||||
QVERIFY2(selfHostedAfterDns != nullptr, "Server config should be SelfHostedServerConfig");
|
QVERIFY2(adminAfterDns.has_value(), "Server config should be SelfHostedAdminServerConfig");
|
||||||
|
const SelfHostedAdminServerConfig *selfHostedAfterDns = &(*adminAfterDns);
|
||||||
QVERIFY2(selfHostedAfterDns->containers.contains(DockerContainer::Awg), "Server should still have Awg container");
|
QVERIFY2(selfHostedAfterDns->containers.contains(DockerContainer::Awg), "Server should still have Awg container");
|
||||||
QVERIFY2(selfHostedAfterDns->containers.contains(DockerContainer::Dns), "Server should have Dns container");
|
QVERIFY2(selfHostedAfterDns->containers.contains(DockerContainer::Dns), "Server should have Dns container");
|
||||||
QVERIFY2(selfHostedAfterDns->containers.size() == 2,
|
QVERIFY2(selfHostedAfterDns->containers.size() == 2,
|
||||||
@@ -242,16 +247,18 @@ private slots:
|
|||||||
|
|
||||||
verifySshConnection(credentials);
|
verifySshConnection(credentials);
|
||||||
|
|
||||||
SelfHostedServerConfig serverConfig;
|
SelfHostedAdminServerConfig serverConfig;
|
||||||
serverConfig.hostName = credentials.hostName;
|
serverConfig.hostName = credentials.hostName;
|
||||||
serverConfig.userName = credentials.userName;
|
serverConfig.userName = credentials.userName;
|
||||||
serverConfig.password = credentials.secretData;
|
serverConfig.password = credentials.secretData;
|
||||||
serverConfig.port = credentials.port;
|
serverConfig.port = credentials.port;
|
||||||
serverConfig.description = m_coreController->m_appSettingsRepository->nextAvailableServerName();
|
serverConfig.description = m_coreController->m_appSettingsRepository->nextAvailableServerName();
|
||||||
|
serverConfig.displayName = serverConfig.description.isEmpty() ? serverConfig.hostName : serverConfig.description;
|
||||||
serverConfig.defaultContainer = DockerContainer::None;
|
serverConfig.defaultContainer = DockerContainer::None;
|
||||||
|
|
||||||
QSignalSpy serverAddedSpy(m_coreController->m_serversRepository, &SecureServersRepository::serverAdded);
|
QSignalSpy serverAddedSpy(m_coreController->m_serversRepository, &SecureServersRepository::serverAdded);
|
||||||
m_coreController->m_serversController->addServer(ServerConfig(serverConfig));
|
m_coreController->m_serversRepository->addServer(QString(), serverConfig.toJson(),
|
||||||
|
serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||||
|
|
||||||
QVERIFY2(serverAddedSpy.count() == 1, "serverAdded signal should be emitted");
|
QVERIFY2(serverAddedSpy.count() == 1, "serverAdded signal should be emitted");
|
||||||
QVERIFY2(m_coreController->m_serversRepository->serversCount() > 0, "Server should be added");
|
QVERIFY2(m_coreController->m_serversRepository->serversCount() > 0, "Server should be added");
|
||||||
@@ -259,23 +266,25 @@ private slots:
|
|||||||
int serverIndex = m_coreController->m_serversRepository->serversCount() - 1;
|
int serverIndex = m_coreController->m_serversRepository->serversCount() - 1;
|
||||||
qDebug() << "Empty server added at index:" << serverIndex;
|
qDebug() << "Empty server added at index:" << serverIndex;
|
||||||
|
|
||||||
ServerConfig addedServer = m_coreController->m_serversRepository->server(serverIndex);
|
const auto addedAdmin = m_coreController->m_serversRepository->selfHostedAdminConfig(
|
||||||
QVERIFY2(addedServer.isSelfHosted(), "Added server should be self-hosted");
|
m_coreController->m_serversRepository->serverIdAt(serverIndex));
|
||||||
const SelfHostedServerConfig* selfHosted = addedServer.as<SelfHostedServerConfig>();
|
QVERIFY2(addedAdmin.has_value(), "Added server should be self-hosted admin");
|
||||||
QVERIFY2(selfHosted != nullptr, "Server config should be SelfHostedServerConfig");
|
const SelfHostedAdminServerConfig *selfHosted = &(*addedAdmin);
|
||||||
QVERIFY2(selfHosted->containers.isEmpty(), "Server should have no containers initially");
|
QVERIFY2(selfHosted->containers.isEmpty(), "Server should have no containers initially");
|
||||||
QVERIFY2(selfHosted->defaultContainer == DockerContainer::None, "Default container should be None");
|
QVERIFY2(selfHosted->defaultContainer == DockerContainer::None, "Default container should be None");
|
||||||
|
|
||||||
ErrorCode scanError = m_coreController->m_installController->scanServerForInstalledContainers(serverIndex);
|
const QString scanServerId = m_coreController->m_serversRepository->serverIdAt(serverIndex);
|
||||||
|
ErrorCode scanError = m_coreController->m_installController->scanServerForInstalledContainers(scanServerId);
|
||||||
QVERIFY2(scanError == ErrorCode::NoError,
|
QVERIFY2(scanError == ErrorCode::NoError,
|
||||||
QString("Server scan should succeed. Error: %1")
|
QString("Server scan should succeed. Error: %1")
|
||||||
.arg(static_cast<int>(scanError))
|
.arg(static_cast<int>(scanError))
|
||||||
.toUtf8().constData());
|
.toUtf8().constData());
|
||||||
qDebug() << "Server scan completed successfully";
|
qDebug() << "Server scan completed successfully";
|
||||||
|
|
||||||
ServerConfig scannedServer = m_coreController->m_serversRepository->server(serverIndex);
|
const auto scannedAdmin = m_coreController->m_serversRepository->selfHostedAdminConfig(
|
||||||
const SelfHostedServerConfig* scannedSelfHosted = scannedServer.as<SelfHostedServerConfig>();
|
m_coreController->m_serversRepository->serverIdAt(serverIndex));
|
||||||
QVERIFY2(scannedSelfHosted != nullptr, "Scanned server config should be SelfHostedServerConfig");
|
QVERIFY2(scannedAdmin.has_value(), "Scanned server config should be SelfHostedAdminServerConfig");
|
||||||
|
const SelfHostedAdminServerConfig *scannedSelfHosted = &(*scannedAdmin);
|
||||||
|
|
||||||
QMap<DockerContainer, ContainerConfig> containers = scannedSelfHosted->containers;
|
QMap<DockerContainer, ContainerConfig> containers = scannedSelfHosted->containers;
|
||||||
int containersCount = containers.size();
|
int containersCount = containers.size();
|
||||||
@@ -336,24 +345,27 @@ private slots:
|
|||||||
int serverIndex = m_coreController->m_serversRepository->serversCount() - 1;
|
int serverIndex = m_coreController->m_serversRepository->serversCount() - 1;
|
||||||
qDebug() << "Server with Awg container added at index:" << serverIndex;
|
qDebug() << "Server with Awg container added at index:" << serverIndex;
|
||||||
|
|
||||||
ServerConfig serverBeforeRemoval = m_coreController->m_serversRepository->server(serverIndex);
|
const auto adminBeforeRemoval = m_coreController->m_serversRepository->selfHostedAdminConfig(
|
||||||
const SelfHostedServerConfig* selfHostedBeforeRemoval = serverBeforeRemoval.as<SelfHostedServerConfig>();
|
m_coreController->m_serversRepository->serverIdAt(serverIndex));
|
||||||
QVERIFY2(selfHostedBeforeRemoval != nullptr, "Server config should be SelfHostedServerConfig");
|
QVERIFY2(adminBeforeRemoval.has_value(), "Server config should be SelfHostedAdminServerConfig");
|
||||||
|
const SelfHostedAdminServerConfig *selfHostedBeforeRemoval = &(*adminBeforeRemoval);
|
||||||
QVERIFY2(!selfHostedBeforeRemoval->containers.isEmpty(), "Server should have containers before removal");
|
QVERIFY2(!selfHostedBeforeRemoval->containers.isEmpty(), "Server should have containers before removal");
|
||||||
QVERIFY2(selfHostedBeforeRemoval->defaultContainer != DockerContainer::None, "Server should have default container before removal");
|
QVERIFY2(selfHostedBeforeRemoval->defaultContainer != DockerContainer::None, "Server should have default container before removal");
|
||||||
|
|
||||||
qDebug() << "Containers before removal:" << selfHostedBeforeRemoval->containers.size();
|
qDebug() << "Containers before removal:" << selfHostedBeforeRemoval->containers.size();
|
||||||
|
|
||||||
ErrorCode removeError = m_coreController->m_installController->removeAllContainers(serverIndex);
|
const QString removeServerId = m_coreController->m_serversRepository->serverIdAt(serverIndex);
|
||||||
|
ErrorCode removeError = m_coreController->m_installController->removeAllContainers(removeServerId);
|
||||||
QVERIFY2(removeError == ErrorCode::NoError,
|
QVERIFY2(removeError == ErrorCode::NoError,
|
||||||
QString("removeAllContainers should succeed. Error: %1")
|
QString("removeAllContainers should succeed. Error: %1")
|
||||||
.arg(static_cast<int>(removeError))
|
.arg(static_cast<int>(removeError))
|
||||||
.toUtf8().constData());
|
.toUtf8().constData());
|
||||||
qDebug() << "All containers removed successfully";
|
qDebug() << "All containers removed successfully";
|
||||||
|
|
||||||
ServerConfig serverAfterRemoval = m_coreController->m_serversRepository->server(serverIndex);
|
const auto adminAfterRemoval = m_coreController->m_serversRepository->selfHostedAdminConfig(
|
||||||
const SelfHostedServerConfig* selfHostedAfterRemoval = serverAfterRemoval.as<SelfHostedServerConfig>();
|
m_coreController->m_serversRepository->serverIdAt(serverIndex));
|
||||||
QVERIFY2(selfHostedAfterRemoval != nullptr, "Server config should be SelfHostedServerConfig");
|
QVERIFY2(adminAfterRemoval.has_value(), "Server config should be SelfHostedAdminServerConfig");
|
||||||
|
const SelfHostedAdminServerConfig *selfHostedAfterRemoval = &(*adminAfterRemoval);
|
||||||
|
|
||||||
QVERIFY2(selfHostedAfterRemoval->containers.isEmpty(),
|
QVERIFY2(selfHostedAfterRemoval->containers.isEmpty(),
|
||||||
"Server should have no containers after removal");
|
"Server should have no containers after removal");
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user