mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-23 02:00:20 +07:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 470c736571 | |||
| de5205aa6f | |||
| 56ab82f87f | |||
| 3984acbb44 | |||
| cc404378f9 | |||
| 6d121776a3 | |||
| 940b3a2f2b | |||
| 34a63e7d11 | |||
| 73e0c9b92e | |||
| 476f16d027 |
@@ -22,7 +22,6 @@ set(HEADERS ${HEADERS}
|
|||||||
${CLIENT_ROOT_DIR}/core/controllers/coreSignalHandlers.h
|
${CLIENT_ROOT_DIR}/core/controllers/coreSignalHandlers.h
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/gatewayController.h
|
${CLIENT_ROOT_DIR}/core/controllers/gatewayController.h
|
||||||
${CLIENT_ROOT_DIR}/core/utils/selfhosted/sshSession.h
|
${CLIENT_ROOT_DIR}/core/utils/selfhosted/sshSession.h
|
||||||
${CLIENT_ROOT_DIR}/core/utils/selfhosted/sshExecutor.h
|
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/serversController.h
|
${CLIENT_ROOT_DIR}/core/controllers/serversController.h
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/usersController.h
|
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/usersController.h
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/installController.h
|
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/installController.h
|
||||||
@@ -100,7 +99,6 @@ set(SOURCES ${SOURCES}
|
|||||||
${CLIENT_ROOT_DIR}/core/controllers/coreSignalHandlers.cpp
|
${CLIENT_ROOT_DIR}/core/controllers/coreSignalHandlers.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/gatewayController.cpp
|
${CLIENT_ROOT_DIR}/core/controllers/gatewayController.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/utils/selfhosted/sshSession.cpp
|
${CLIENT_ROOT_DIR}/core/utils/selfhosted/sshSession.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/utils/selfhosted/sshExecutor.cpp
|
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/serversController.cpp
|
${CLIENT_ROOT_DIR}/core/controllers/serversController.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/usersController.cpp
|
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/usersController.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/installController.cpp
|
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/installController.cpp
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "core/utils/selfhosted/sshSession.h"
|
#include "core/utils/selfhosted/sshSession.h"
|
||||||
#include "core/utils/selfhosted/sshExecutor.h"
|
|
||||||
#include "core/utils/errorCodes.h"
|
#include "core/utils/errorCodes.h"
|
||||||
#include "core/utils/routeModes.h"
|
#include "core/utils/routeModes.h"
|
||||||
#include "core/controllers/coreController.h"
|
#include "core/controllers/coreController.h"
|
||||||
@@ -145,10 +144,8 @@ void CoreSignalHandlers::initExportControllerHandler()
|
|||||||
});
|
});
|
||||||
connect(m_coreController->m_exportController, &ExportController::revokeClientRequested, this,
|
connect(m_coreController->m_exportController, &ExportController::revokeClientRequested, this,
|
||||||
[this](const QString &serverId, int row, DockerContainer container) {
|
[this](const QString &serverId, int row, DockerContainer container) {
|
||||||
SshExecutor::instance().run(serverId, [this, serverId, row, container]() {
|
|
||||||
m_coreController->m_usersController->revokeClient(serverId, 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](const QString &serverId, int row, const QString &clientName, DockerContainer container) {
|
[this](const QString &serverId, int row, const QString &clientName, DockerContainer container) {
|
||||||
m_coreController->m_usersController->renameClient(serverId, row, clientName, container);
|
m_coreController->m_usersController->renameClient(serverId, row, clientName, container);
|
||||||
@@ -205,10 +202,8 @@ void CoreSignalHandlers::initAdminConfigRevokedHandler()
|
|||||||
{
|
{
|
||||||
connect(m_coreController->m_installController, &InstallController::clientRevocationRequested, this,
|
connect(m_coreController->m_installController, &InstallController::clientRevocationRequested, this,
|
||||||
[this](const QString &serverId, const ContainerConfig &containerConfig, DockerContainer container) {
|
[this](const QString &serverId, const ContainerConfig &containerConfig, DockerContainer container) {
|
||||||
SshExecutor::instance().run(serverId, [this, serverId, containerConfig, container]() {
|
|
||||||
m_coreController->m_usersController->revokeClient(serverId, 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](const QString &serverId, const QString &clientId, const QString &clientName, DockerContainer container) {
|
[this](const QString &serverId, const QString &clientId, const QString &clientName, DockerContainer container) {
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
#include <QRegularExpressionMatch>
|
#include <QRegularExpressionMatch>
|
||||||
#include <QRegularExpressionMatchIterator>
|
#include <QRegularExpressionMatchIterator>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QUrlQuery>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QTimer>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "core/utils/containerEnum.h"
|
#include "core/utils/containerEnum.h"
|
||||||
@@ -377,6 +380,209 @@ int ImportController::qrChunksTotal() const
|
|||||||
return m_totalQrCodeChunksCount;
|
return m_totalQrCodeChunksCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImportController::ImportResult ImportController::importLink(const QUrl &url)
|
||||||
|
{
|
||||||
|
ImportResult result;
|
||||||
|
|
||||||
|
if (!url.isValid()) {
|
||||||
|
qWarning() << "Invalid URL:" << url;
|
||||||
|
result.errorCode = ErrorCode::ImportInvalidConfigError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkAccessManager manager;
|
||||||
|
|
||||||
|
QNetworkRequest request(url);
|
||||||
|
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||||
|
|
||||||
|
QNetworkReply *reply = manager.get(request);
|
||||||
|
|
||||||
|
QEventLoop loop;
|
||||||
|
QTimer timer;
|
||||||
|
|
||||||
|
timer.setSingleShot(true);
|
||||||
|
|
||||||
|
bool timedOut = false;
|
||||||
|
|
||||||
|
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||||
|
QObject::connect(&timer, &QTimer::timeout, &loop, [&]() {
|
||||||
|
timedOut = true;
|
||||||
|
reply->abort();
|
||||||
|
loop.quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
timer.start(10000);
|
||||||
|
loop.exec();
|
||||||
|
|
||||||
|
if (timedOut) {
|
||||||
|
qWarning() << "Request timed out";
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
result.errorCode = ErrorCode::ImportInvalidConfigError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
qWarning() << "Network error:" << reply->errorString();
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
result.errorCode = ErrorCode::ImportInvalidConfigError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (data.isEmpty()) {
|
||||||
|
qWarning() << "Empty response";
|
||||||
|
result.errorCode = ErrorCode::ImportInvalidConfigError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray decoded;
|
||||||
|
QString text;
|
||||||
|
|
||||||
|
if (isValidBase64(data)) {
|
||||||
|
decoded = QByteArray::fromBase64(data);
|
||||||
|
text = QString::fromUtf8(decoded).trimmed();
|
||||||
|
} else {
|
||||||
|
data.replace('\r', "");
|
||||||
|
text = QString::fromUtf8(data).trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
qWarning() << "Decoded text is empty";
|
||||||
|
result.errorCode = ErrorCode::ImportInvalidConfigError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList configs = text.split('\n', Qt::SkipEmptyParts);
|
||||||
|
|
||||||
|
QJsonArray configStrings;
|
||||||
|
QJsonArray configNames;
|
||||||
|
|
||||||
|
for (const QString &cfg : configs) {
|
||||||
|
|
||||||
|
bool supported = true;
|
||||||
|
|
||||||
|
if (!(cfg.startsWith("vless://") || cfg.startsWith("vmess://") || cfg.startsWith("trojan://")
|
||||||
|
|| cfg.startsWith("ss://") || cfg.startsWith("ssd://"))) {
|
||||||
|
supported = false;
|
||||||
|
qWarning() << "Unknown protocol:" << cfg.left(20);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl url(cfg);
|
||||||
|
QUrlQuery query(url);
|
||||||
|
|
||||||
|
QString name = QUrl::fromPercentEncoding(url.fragment().toUtf8());
|
||||||
|
|
||||||
|
name.isEmpty() ? name = "Unnamed" : name = "[" + name.replace(" /", "]");
|
||||||
|
|
||||||
|
if (!name.contains("v2ray") && supported) {
|
||||||
|
configStrings.append(cfg);
|
||||||
|
configNames.append(name);
|
||||||
|
} else {
|
||||||
|
qWarning() << "Config unsupported";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configStrings.isEmpty()) {
|
||||||
|
qWarning() << "No valid configs found";
|
||||||
|
result.errorCode = ErrorCode::ImportInvalidConfigError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString firstConfig = configStrings.first().toString();
|
||||||
|
result = extractConfigFromData(firstConfig);
|
||||||
|
|
||||||
|
QJsonObject serverConfig;
|
||||||
|
|
||||||
|
for (auto it = result.config.begin(); it != result.config.end(); ++it) {
|
||||||
|
serverConfig.insert(it.key(), it.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
serverConfig.insert(configKey::description, m_serversRepository->nextAvailableServerName());
|
||||||
|
serverConfig[configKey::xraySubscriptionLink] = url.toString();
|
||||||
|
serverConfig[configKey::xraySubscriptionConfig] = configStrings;
|
||||||
|
serverConfig[configKey::xraySubscriptionConfigName] = configNames;
|
||||||
|
serverConfig[configKey::xraySubscriptionConfigCurrent] = 0;
|
||||||
|
|
||||||
|
result.config = serverConfig;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportController::ImportResult ImportController::editServerConfigWithData(const QString &serverId, QString data, const QJsonObject& uiConfig)
|
||||||
|
{
|
||||||
|
ImportResult result = extractConfigFromData(data);
|
||||||
|
|
||||||
|
if (result.errorCode != ErrorCode::NoError)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
QJsonObject editedConfig = result.config;
|
||||||
|
|
||||||
|
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
|
||||||
|
switch (kind) {
|
||||||
|
case serverConfigUtils::ConfigType::XRaySubscription: {
|
||||||
|
auto cfg = m_serversRepository->xraySubscriptionConfig(serverId);
|
||||||
|
if (!cfg.has_value()) {
|
||||||
|
result.errorCode = ErrorCode::ImportInvalidConfigError;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject currentConfig = cfg->toJson();
|
||||||
|
|
||||||
|
for (auto it = uiConfig.begin(); it != uiConfig.end(); ++it) {
|
||||||
|
editedConfig.insert(it.key(), it.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
editedConfig.insert(configKey::description, currentConfig.value(configKey::description));
|
||||||
|
editedConfig.insert(configKey::xraySubscriptionLink, currentConfig.value(configKey::xraySubscriptionLink));
|
||||||
|
editedConfig.insert(configKey::xraySubscriptionConfig, currentConfig.value(configKey::xraySubscriptionConfig));
|
||||||
|
editedConfig.insert(configKey::xraySubscriptionConfigName, currentConfig.value(configKey::xraySubscriptionConfigName));
|
||||||
|
editedConfig.insert(configKey::xraySubscriptionConfigCurrent, currentConfig.value(configKey::xraySubscriptionConfigCurrent));
|
||||||
|
|
||||||
|
m_serversRepository->editServer(serverId, editedConfig, kind);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default: result.errorCode = ErrorCode::ImportInvalidConfigError;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.config = editedConfig;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImportController::isValidBase64(const QByteArray &input)
|
||||||
|
{
|
||||||
|
QByteArray data = input;
|
||||||
|
data = data.trimmed();
|
||||||
|
|
||||||
|
if (data.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
static QRegularExpression base64Regex("^[A-Za-z0-9+/=_\\r\\n-]+$");
|
||||||
|
|
||||||
|
if (!base64Regex.match(QString::fromLatin1(data)).hasMatch())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data.replace("\r", "");
|
||||||
|
data.replace("\n", "");
|
||||||
|
|
||||||
|
if (data.size() % 4 != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QByteArray decoded = QByteArray::fromBase64(data, QByteArray::Base64UrlEncoding);
|
||||||
|
|
||||||
|
if (decoded.isEmpty())
|
||||||
|
decoded = QByteArray::fromBase64(data);
|
||||||
|
|
||||||
|
return !decoded.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
void ImportController::importConfig(const QJsonObject &config)
|
void ImportController::importConfig(const QJsonObject &config)
|
||||||
{
|
{
|
||||||
ServerCredentials credentials;
|
ServerCredentials credentials;
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ public:
|
|||||||
int qrChunksReceived() const;
|
int qrChunksReceived() const;
|
||||||
int qrChunksTotal() const;
|
int qrChunksTotal() const;
|
||||||
|
|
||||||
|
ImportResult importLink(const QUrl &url);
|
||||||
|
ImportResult editServerConfigWithData(const QString &serverId, QString data, const QJsonObject &uiConfig);
|
||||||
|
bool isValidBase64(const QByteArray &input);
|
||||||
|
|
||||||
void importConfig(const QJsonObject &config);
|
void importConfig(const QJsonObject &config);
|
||||||
QJsonObject processNativeWireGuardConfig(const QJsonObject &config);
|
QJsonObject processNativeWireGuardConfig(const QJsonObject &config);
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,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/utils/selfhosted/sshSession.h"
|
#include "core/utils/selfhosted/sshSession.h"
|
||||||
#include "core/utils/selfhosted/sshExecutor.h"
|
|
||||||
#include "core/installers/awgInstaller.h"
|
#include "core/installers/awgInstaller.h"
|
||||||
#include "core/installers/installerBase.h"
|
#include "core/installers/installerBase.h"
|
||||||
#include "core/installers/openvpnInstaller.h"
|
#include "core/installers/openvpnInstaller.h"
|
||||||
@@ -104,7 +103,7 @@ ErrorCode InstallController::setupContainer(const ServerCredentials &credentials
|
|||||||
bool isUpdate)
|
bool isUpdate)
|
||||||
{
|
{
|
||||||
qDebug().noquote() << "InstallController::setupContainer" << ContainerUtils::containerToString(container);
|
qDebug().noquote() << "InstallController::setupContainer" << ContainerUtils::containerToString(container);
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
ErrorCode e = ErrorCode::NoError;
|
ErrorCode e = ErrorCode::NoError;
|
||||||
|
|
||||||
e = isUserInSudo(credentials, sshSession);
|
e = isUserInSudo(credentials, sshSession);
|
||||||
@@ -169,11 +168,11 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
|
|||||||
}
|
}
|
||||||
if (container == DockerContainer::MtProxy) {
|
if (container == DockerContainer::MtProxy) {
|
||||||
ServerCredentials credentials = adminConfig->credentials();
|
ServerCredentials credentials = adminConfig->credentials();
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
MtProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
MtProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||||
} else if (container == DockerContainer::Telemt) {
|
} else if (container == DockerContainer::Telemt) {
|
||||||
ServerCredentials credentials = adminConfig->credentials();
|
ServerCredentials credentials = adminConfig->credentials();
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
TelemtInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
TelemtInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||||
}
|
}
|
||||||
adminConfig->updateContainerConfig(container, newConfig);
|
adminConfig->updateContainerConfig(container, newConfig);
|
||||||
@@ -189,7 +188,7 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
|
|||||||
if (!credentials.isValid()) {
|
if (!credentials.isValid()) {
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
|
|
||||||
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
|
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
|
||||||
qDebug() << "InstallController::updateServerConfig for container" << container << "reinstall required is" << reinstallRequired;
|
qDebug() << "InstallController::updateServerConfig for container" << container << "reinstall required is" << reinstallRequired;
|
||||||
@@ -373,7 +372,7 @@ ErrorCode InstallController::validateAndPrepareConfig(const QString &serverId)
|
|||||||
|
|
||||||
void InstallController::validateConfig(const QString &serverId)
|
void InstallController::validateConfig(const QString &serverId)
|
||||||
{
|
{
|
||||||
QFuture<ErrorCode> future = SshExecutor::instance().run(serverId, [this, serverId]() {
|
QFuture<ErrorCode> future = QtConcurrent::run([this, serverId]() {
|
||||||
return validateAndPrepareConfig(serverId);
|
return validateAndPrepareConfig(serverId);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -837,8 +836,8 @@ ErrorCode InstallController::installDockerWorker(const ServerCredentials &creden
|
|||||||
qDebug().noquote() << "InstallController::installDockerWorker" << stdOut;
|
qDebug().noquote() << "InstallController::installDockerWorker" << stdOut;
|
||||||
|
|
||||||
if (container == DockerContainer::Awg2) {
|
if (container == DockerContainer::Awg2) {
|
||||||
QRegularExpression regex(R"(Linux\s+(\d+)\.(\d+)[^\d]*)");
|
QRegularExpression kernelVersionRegex(R"(Linux\s+(\d+)\.(\d+)[^\d]*)");
|
||||||
QRegularExpressionMatch match = regex.match(stdOut);
|
QRegularExpressionMatch match = kernelVersionRegex.match(stdOut);
|
||||||
if (match.hasMatch()) {
|
if (match.hasMatch()) {
|
||||||
int majorVersion = match.captured(1).toInt();
|
int majorVersion = match.captured(1).toInt();
|
||||||
int minorVersion = match.captured(2).toInt();
|
int minorVersion = match.captured(2).toInt();
|
||||||
@@ -851,8 +850,19 @@ ErrorCode InstallController::installDockerWorker(const ServerCredentials &creden
|
|||||||
|
|
||||||
if (stdOut.contains("lock"))
|
if (stdOut.contains("lock"))
|
||||||
return ErrorCode::ServerPacketManagerError;
|
return ErrorCode::ServerPacketManagerError;
|
||||||
if (stdOut.contains("command not found"))
|
if (stdOut.contains("Container runtime is not supported"))
|
||||||
|
return ErrorCode::ServerContainerRuntimeNotSupported;
|
||||||
|
|
||||||
|
QRegularExpression notFoundRegex(
|
||||||
|
R"(^.*(?:sudo:|docker:).*not found.*$)",
|
||||||
|
QRegularExpression::MultilineOption);
|
||||||
|
|
||||||
|
if (notFoundRegex.match(stdOut).hasMatch()) {
|
||||||
return ErrorCode::ServerDockerFailedError;
|
return ErrorCode::ServerDockerFailedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stdOut.contains("Container runtime service not running"))
|
||||||
|
return ErrorCode::ContainerRuntimeServiceNotRunning;
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -889,7 +899,7 @@ ErrorCode InstallController::isUserInSudo(const ServerCredentials &credentials,
|
|||||||
return ErrorCode::ServerUserNotInSudo;
|
return ErrorCode::ServerUserNotInSudo;
|
||||||
if (stdOut.contains("can't cd to") || stdOut.contains("Permission denied") || stdOut.contains("No such file or directory"))
|
if (stdOut.contains("can't cd to") || stdOut.contains("Permission denied") || stdOut.contains("No such file or directory"))
|
||||||
return ErrorCode::ServerUserDirectoryNotAccessible;
|
return ErrorCode::ServerUserDirectoryNotAccessible;
|
||||||
if (stdOut.contains("sudoers") || stdOut.contains("is not allowed to run sudo on"))
|
if (stdOut.contains(QRegularExpression(R"(\bsudoers\b)")) || stdOut.contains("is not allowed to") || stdOut.contains("can't do that"))
|
||||||
return ErrorCode::ServerUserNotAllowedInSudoers;
|
return ErrorCode::ServerUserNotAllowedInSudoers;
|
||||||
if (stdOut.contains("password is required") || stdOut.contains("authentication is required"))
|
if (stdOut.contains("password is required") || stdOut.contains("authentication is required"))
|
||||||
return ErrorCode::ServerUserPasswordRequired;
|
return ErrorCode::ServerUserPasswordRequired;
|
||||||
@@ -971,7 +981,7 @@ ErrorCode InstallController::rebootServer(const QString &serverId)
|
|||||||
if (!credentials.isValid()) {
|
if (!credentials.isValid()) {
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
|
|
||||||
QString script = QString("sudo reboot");
|
QString script = QString("sudo reboot");
|
||||||
|
|
||||||
@@ -999,7 +1009,7 @@ ErrorCode InstallController::removeAllContainers(const QString &serverId)
|
|||||||
if (!credentials.isValid()) {
|
if (!credentials.isValid()) {
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
SshSession sshSession;
|
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) {
|
||||||
@@ -1021,7 +1031,7 @@ ErrorCode InstallController::removeContainer(const QString &serverId, DockerCont
|
|||||||
if (!credentials.isValid()) {
|
if (!credentials.isValid()) {
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
const amnezia::ScriptVars removeContainerVars =
|
const amnezia::ScriptVars removeContainerVars =
|
||||||
amnezia::genBaseVars(credentials, container, QString(), QString());
|
amnezia::genBaseVars(credentials, container, QString(), QString());
|
||||||
const bool removeDataVolume = (container == DockerContainer::MtProxy || container == DockerContainer::Telemt);
|
const bool removeDataVolume = (container == DockerContainer::MtProxy || container == DockerContainer::Telemt);
|
||||||
@@ -1130,7 +1140,7 @@ ErrorCode InstallController::scanServerForInstalledContainers(const QString &ser
|
|||||||
if (!credentials.isValid()) {
|
if (!credentials.isValid()) {
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
|
|
||||||
QMap<DockerContainer, ContainerConfig> installedContainers;
|
QMap<DockerContainer, ContainerConfig> installedContainers;
|
||||||
ErrorCode errorCode = getAlreadyInstalledContainers(credentials, installedContainers, sshSession);
|
ErrorCode errorCode = getAlreadyInstalledContainers(credentials, installedContainers, sshSession);
|
||||||
@@ -1173,7 +1183,7 @@ ErrorCode InstallController::scanServerForInstalledContainers(const QString &ser
|
|||||||
ErrorCode InstallController::installServer(const ServerCredentials &credentials, DockerContainer container, int port,
|
ErrorCode InstallController::installServer(const ServerCredentials &credentials, DockerContainer container, int port,
|
||||||
TransportProto transportProto, bool &wasContainerInstalled)
|
TransportProto transportProto, bool &wasContainerInstalled)
|
||||||
{
|
{
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
QMap<DockerContainer, ContainerConfig> installedContainers;
|
QMap<DockerContainer, ContainerConfig> installedContainers;
|
||||||
ErrorCode errorCode = getAlreadyInstalledContainers(credentials, installedContainers, sshSession);
|
ErrorCode errorCode = getAlreadyInstalledContainers(credentials, installedContainers, sshSession);
|
||||||
if (errorCode) {
|
if (errorCode) {
|
||||||
@@ -1242,7 +1252,7 @@ ErrorCode InstallController::installContainer(const QString &serverId, DockerCon
|
|||||||
if (!credentials.isValid()) {
|
if (!credentials.isValid()) {
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
|
|
||||||
QMap<DockerContainer, ContainerConfig> installedContainers;
|
QMap<DockerContainer, ContainerConfig> installedContainers;
|
||||||
ErrorCode errorCode = getAlreadyInstalledContainers(credentials, installedContainers, sshSession);
|
ErrorCode errorCode = getAlreadyInstalledContainers(credentials, installedContainers, sshSession);
|
||||||
@@ -1284,7 +1294,7 @@ ErrorCode InstallController::installContainer(const QString &serverId, DockerCon
|
|||||||
ErrorCode InstallController::checkSshConnection(ServerCredentials &credentials, QString &output,
|
ErrorCode InstallController::checkSshConnection(ServerCredentials &credentials, QString &output,
|
||||||
std::function<QString()> passphraseCallback)
|
std::function<QString()> passphraseCallback)
|
||||||
{
|
{
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
ErrorCode errorCode = ErrorCode::NoError;
|
ErrorCode errorCode = ErrorCode::NoError;
|
||||||
|
|
||||||
if (credentials.secretData.contains("BEGIN") && credentials.secretData.contains("PRIVATE KEY")) {
|
if (credentials.secretData.contains("BEGIN") && credentials.secretData.contains("PRIVATE KEY")) {
|
||||||
@@ -1565,7 +1575,7 @@ ErrorCode InstallController::setDockerContainerEnabledState(const QString &serve
|
|||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
const QString containerName = ContainerUtils::containerToString(container);
|
const QString containerName = ContainerUtils::containerToString(container);
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
const QString script = enabled ? QStringLiteral("sudo docker start %1").arg(containerName)
|
const QString script = enabled ? QStringLiteral("sudo docker start %1").arg(containerName)
|
||||||
: QStringLiteral("sudo docker stop %1").arg(containerName);
|
: QStringLiteral("sudo docker stop %1").arg(containerName);
|
||||||
const ErrorCode runError = sshSession.runScript(credentials, script);
|
const ErrorCode runError = sshSession.runScript(credentials, script);
|
||||||
@@ -1605,7 +1615,7 @@ ErrorCode InstallController::queryDockerContainerStatus(const QString &serverId,
|
|||||||
stdOut += data;
|
stdOut += data;
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
};
|
};
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
const QString script = QStringLiteral(
|
const QString script = QStringLiteral(
|
||||||
"sudo docker inspect --format '{{.State.Status}}' %1 2>/dev/null || echo 'not_found'")
|
"sudo docker inspect --format '{{.State.Status}}' %1 2>/dev/null || echo 'not_found'")
|
||||||
.arg(containerName);
|
.arg(containerName);
|
||||||
@@ -1639,7 +1649,7 @@ ErrorCode InstallController::queryMtProxyDiagnostics(const QString &serverId, Do
|
|||||||
if (!credentials.isValid()) {
|
if (!credentials.isValid()) {
|
||||||
return ErrorCode::InternalError;
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
return MtProxyInstaller::queryDiagnostics(sshSession, credentials, container, listenPort, out);
|
return MtProxyInstaller::queryDiagnostics(sshSession, credentials, container, listenPort, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1662,7 +1672,7 @@ QString InstallController::fetchDockerContainerSecret(const QString &serverId, D
|
|||||||
stdOut += data;
|
stdOut += data;
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
};
|
};
|
||||||
SshSession sshSession;
|
SshSession sshSession(this);
|
||||||
const QString path = QStringLiteral("/data/secret");
|
const QString path = QStringLiteral("/data/secret");
|
||||||
const QString cmd = QStringLiteral("sudo docker exec %1 cat %2").arg(containerName, path);
|
const QString cmd = QStringLiteral("sudo docker exec %1 cat %2").arg(containerName, path);
|
||||||
const ErrorCode errorCode = sshSession.runScript(credentials, cmd, cbReadStdOut);
|
const ErrorCode errorCode = sshSession.runScript(credentials, cmd, cbReadStdOut);
|
||||||
|
|||||||
@@ -64,6 +64,13 @@ bool ServersController::renameServer(const QString &serverId, const QString &nam
|
|||||||
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case serverConfigUtils::ConfigType::XRaySubscription: {
|
||||||
|
auto cfg = m_serversRepository->xraySubscriptionConfig(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::AmneziaPremiumV2:
|
||||||
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
||||||
case serverConfigUtils::ConfigType::ExternalPremium: {
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
||||||
@@ -118,6 +125,13 @@ void ServersController::setDefaultContainer(const QString &serverId, DockerConta
|
|||||||
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case serverConfigUtils::ConfigType::XRaySubscription: {
|
||||||
|
auto cfg = m_serversRepository->xraySubscriptionConfig(serverId);
|
||||||
|
if (!cfg.has_value()) return;
|
||||||
|
cfg->defaultContainer = container;
|
||||||
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
|
return;
|
||||||
|
}
|
||||||
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
||||||
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
||||||
case serverConfigUtils::ConfigType::ExternalPremium: {
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
||||||
@@ -135,6 +149,88 @@ void ServersController::setDefaultContainer(const QString &serverId, DockerConta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ServersController::getSubLink(const QString &serverId) const
|
||||||
|
{
|
||||||
|
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
|
||||||
|
switch (kind) {
|
||||||
|
case serverConfigUtils::ConfigType::XRaySubscription: {
|
||||||
|
auto cfg = m_serversRepository->xraySubscriptionConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->subLink : QString();
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default: return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ServersController::getConfigString(const QString &serverId, const int index) const
|
||||||
|
{
|
||||||
|
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
|
||||||
|
switch (kind) {
|
||||||
|
case serverConfigUtils::ConfigType::XRaySubscription: {
|
||||||
|
auto cfg = m_serversRepository->xraySubscriptionConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->configString.at(index).toString() : QString();
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default: return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ServersController::getConfigName(const QString &serverId, const int index) const
|
||||||
|
{
|
||||||
|
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
|
||||||
|
switch (kind) {
|
||||||
|
case serverConfigUtils::ConfigType::XRaySubscription: {
|
||||||
|
auto cfg = m_serversRepository->xraySubscriptionConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->configName.at(index).toString() : QString();
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default: return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray ServersController::getConfigNames(const QString &serverId) const
|
||||||
|
{
|
||||||
|
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
|
||||||
|
switch (kind) {
|
||||||
|
case serverConfigUtils::ConfigType::XRaySubscription: {
|
||||||
|
auto cfg = m_serversRepository->xraySubscriptionConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->configName : QJsonArray();
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default: return QJsonArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ServersController::getCurrentConfigIndex(const QString &serverId) const
|
||||||
|
{
|
||||||
|
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
|
||||||
|
switch (kind) {
|
||||||
|
case serverConfigUtils::ConfigType::XRaySubscription: {
|
||||||
|
auto cfg = m_serversRepository->xraySubscriptionConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->currentConfig : int();
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default: return int();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServersController::setCurrentConfigIndex(const QString &serverId, const int index)
|
||||||
|
{
|
||||||
|
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
|
||||||
|
switch (kind) {
|
||||||
|
case serverConfigUtils::ConfigType::XRaySubscription: {
|
||||||
|
auto cfg = m_serversRepository->xraySubscriptionConfig(serverId);
|
||||||
|
if (!cfg.has_value())
|
||||||
|
return;
|
||||||
|
cfg->currentConfig = index;
|
||||||
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QVector<ServerDescription> ServersController::buildServerDescriptions(bool isAmneziaDnsEnabled) const
|
QVector<ServerDescription> ServersController::buildServerDescriptions(bool isAmneziaDnsEnabled) const
|
||||||
{
|
{
|
||||||
QVector<ServerDescription> out;
|
QVector<ServerDescription> out;
|
||||||
@@ -170,6 +266,14 @@ QVector<ServerDescription> ServersController::buildServerDescriptions(bool isAmn
|
|||||||
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Kind::XRaySubscription: {
|
||||||
|
const auto cfg = m_serversRepository->xraySubscriptionConfig(id);
|
||||||
|
if (!cfg) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Kind::AmneziaPremiumV2:
|
case Kind::AmneziaPremiumV2:
|
||||||
case Kind::AmneziaFreeV3:
|
case Kind::AmneziaFreeV3:
|
||||||
case Kind::ExternalPremium: {
|
case Kind::ExternalPremium: {
|
||||||
@@ -215,6 +319,10 @@ QMap<DockerContainer, ContainerConfig> ServersController::getServerContainersMap
|
|||||||
const auto cfg = m_serversRepository->nativeConfig(serverId);
|
const auto cfg = m_serversRepository->nativeConfig(serverId);
|
||||||
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig> {};
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig> {};
|
||||||
}
|
}
|
||||||
|
case serverConfigUtils::ConfigType::XRaySubscription: {
|
||||||
|
const auto cfg = m_serversRepository->xraySubscriptionConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig> {};
|
||||||
|
}
|
||||||
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
||||||
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
||||||
case serverConfigUtils::ConfigType::ExternalPremium: {
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
||||||
@@ -227,8 +335,7 @@ QMap<DockerContainer, ContainerConfig> ServersController::getServerContainersMap
|
|||||||
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig> {};
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig> {};
|
||||||
}
|
}
|
||||||
case serverConfigUtils::ConfigType::Invalid:
|
case serverConfigUtils::ConfigType::Invalid:
|
||||||
default:
|
default: return {};
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,6 +354,10 @@ DockerContainer ServersController::getDefaultContainer(const QString &serverId)
|
|||||||
const auto cfg = m_serversRepository->nativeConfig(serverId);
|
const auto cfg = m_serversRepository->nativeConfig(serverId);
|
||||||
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
||||||
}
|
}
|
||||||
|
case serverConfigUtils::ConfigType::XRaySubscription: {
|
||||||
|
const auto cfg = m_serversRepository->xraySubscriptionConfig(serverId);
|
||||||
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
||||||
|
}
|
||||||
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
||||||
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
||||||
case serverConfigUtils::ConfigType::ExternalPremium: {
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
||||||
@@ -326,6 +437,14 @@ QString ServersController::notificationDisplayName(const QString &serverId) cons
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Kind::XRaySubscription: {
|
||||||
|
if (const auto cfg = m_serversRepository->xraySubscriptionConfig(serverId)) {
|
||||||
|
if (!cfg->displayName.isEmpty()) {
|
||||||
|
return cfg->displayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Kind::AmneziaPremiumV2:
|
case Kind::AmneziaPremiumV2:
|
||||||
case Kind::AmneziaFreeV3:
|
case Kind::AmneziaFreeV3:
|
||||||
case Kind::ExternalPremium: {
|
case Kind::ExternalPremium: {
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ public:
|
|||||||
// Container management
|
// Container management
|
||||||
void setDefaultContainer(const QString &serverId, DockerContainer container);
|
void setDefaultContainer(const QString &serverId, DockerContainer container);
|
||||||
|
|
||||||
|
// XRay subscription config getters/setters
|
||||||
|
QString getSubLink(const QString &serverId) const;
|
||||||
|
QString getConfigString(const QString &serverId, const int index) const;
|
||||||
|
QString getConfigName(const QString &serverId, const int index) const;
|
||||||
|
QJsonArray getConfigNames(const QString &serverId) const;
|
||||||
|
int getCurrentConfigIndex(const QString &serverId) const;
|
||||||
|
void setCurrentConfigIndex(const QString &serverId, int index);
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
QVector<ServerDescription> buildServerDescriptions(bool isAmneziaDnsEnabled) const;
|
QVector<ServerDescription> buildServerDescriptions(bool isAmneziaDnsEnabled) const;
|
||||||
int getDefaultServerIndex() const;
|
int getDefaultServerIndex() const;
|
||||||
|
|||||||
@@ -5,7 +5,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"
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
#include "xraySubscriptionConfig.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"
|
||||||
|
|
||||||
|
namespace amnezia
|
||||||
|
{
|
||||||
|
|
||||||
|
using namespace ContainerEnumNS;
|
||||||
|
|
||||||
|
bool XRaySubscriptionConfig::hasContainers() const
|
||||||
|
{
|
||||||
|
return !containers.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContainerConfig XRaySubscriptionConfig::containerConfig(DockerContainer container) const
|
||||||
|
{
|
||||||
|
if (!containers.contains(container)) {
|
||||||
|
return ContainerConfig {};
|
||||||
|
}
|
||||||
|
return containers.value(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject XRaySubscriptionConfig::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 (!subLink.isEmpty()) {
|
||||||
|
obj[configKey::xraySubscriptionLink] = subLink;
|
||||||
|
}
|
||||||
|
if (!configString.isEmpty()) {
|
||||||
|
obj[configKey::xraySubscriptionConfig] = configString;
|
||||||
|
}
|
||||||
|
if (!configName.isEmpty()) {
|
||||||
|
obj[configKey::xraySubscriptionConfigName] = configName;
|
||||||
|
}
|
||||||
|
if (currentConfig > -1) {
|
||||||
|
obj[configKey::xraySubscriptionConfigCurrent] = currentConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
XRaySubscriptionConfig XRaySubscriptionConfig::fromJson(const QJsonObject &json)
|
||||||
|
{
|
||||||
|
XRaySubscriptionConfig 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 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();
|
||||||
|
|
||||||
|
if (config.displayName.isEmpty()) {
|
||||||
|
config.displayName = config.description.isEmpty() ? config.hostName : config.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.subLink = json.value(configKey::xraySubscriptionLink).toString();
|
||||||
|
config.configString = json.value(configKey::xraySubscriptionConfig).toArray();
|
||||||
|
config.configName = json.value(configKey::xraySubscriptionConfigName).toArray();
|
||||||
|
config.currentConfig = json.value(configKey::xraySubscriptionConfigCurrent).toInt();
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef XRAYSUBSCRIPTIONCONFIG_H
|
||||||
|
#define XRAYSUBSCRIPTIONCONFIG_H
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QMap>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "core/models/containerConfig.h"
|
||||||
|
#include "core/utils/containerEnum.h"
|
||||||
|
#include "core/utils/containers/containerUtils.h"
|
||||||
|
#include "core/utils/protocolEnum.h"
|
||||||
|
|
||||||
|
namespace amnezia
|
||||||
|
{
|
||||||
|
|
||||||
|
using namespace ContainerEnumNS;
|
||||||
|
|
||||||
|
struct XRaySubscriptionConfig
|
||||||
|
{
|
||||||
|
QString description;
|
||||||
|
QString displayName;
|
||||||
|
QString hostName;
|
||||||
|
QMap<DockerContainer, ContainerConfig> containers;
|
||||||
|
DockerContainer defaultContainer;
|
||||||
|
QString dns1;
|
||||||
|
QString dns2;
|
||||||
|
|
||||||
|
QString subLink;
|
||||||
|
QJsonArray configString;
|
||||||
|
QJsonArray configName;
|
||||||
|
int currentConfig;
|
||||||
|
|
||||||
|
bool hasContainers() const;
|
||||||
|
ContainerConfig containerConfig(DockerContainer container) const;
|
||||||
|
QJsonObject toJson() const;
|
||||||
|
static XRaySubscriptionConfig fromJson(const QJsonObject &json);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace amnezia
|
||||||
|
|
||||||
|
#endif // XRAYSUBSCRIPTIONCONFIG_H
|
||||||
@@ -130,6 +130,20 @@ ServerDescription buildServerDescription(const NativeServerConfig &server, bool
|
|||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServerDescription buildServerDescription(const XRaySubscriptionConfig &server, bool isAmneziaDnsEnabled)
|
||||||
|
{
|
||||||
|
ServerDescription row = buildBaseDescription(server);
|
||||||
|
row.hasWriteAccess = false;
|
||||||
|
row.isXRaySubscription = true;
|
||||||
|
|
||||||
|
row.serverName = server.displayName;
|
||||||
|
row.baseDescription = getBaseDescription(server.containers, isAmneziaDnsEnabled, row.hasWriteAccess, row.primaryDnsIsAmnezia);
|
||||||
|
|
||||||
|
row.expandedServerDescription = row.baseDescription + server.configName.at(server.currentConfig).toString();
|
||||||
|
row.collapsedServerDescription = row.baseDescription + server.configName.at(server.currentConfig).toString();
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
ServerDescription buildServerDescription(const LegacyApiServerConfig &server, bool /*isAmneziaDnsEnabled*/)
|
ServerDescription buildServerDescription(const LegacyApiServerConfig &server, bool /*isAmneziaDnsEnabled*/)
|
||||||
{
|
{
|
||||||
ServerDescription row = buildBaseDescription(server);
|
ServerDescription row = buildBaseDescription(server);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "core/models/selfhosted/selfHostedAdminServerConfig.h"
|
#include "core/models/selfhosted/selfHostedAdminServerConfig.h"
|
||||||
#include "core/models/selfhosted/selfHostedUserServerConfig.h"
|
#include "core/models/selfhosted/selfHostedUserServerConfig.h"
|
||||||
#include "core/models/selfhosted/nativeServerConfig.h"
|
#include "core/models/selfhosted/nativeServerConfig.h"
|
||||||
|
#include "core/models/selfhosted/xraySubscriptionConfig.h"
|
||||||
#include "core/models/api/legacyApiServerConfig.h"
|
#include "core/models/api/legacyApiServerConfig.h"
|
||||||
#include "core/models/api/apiV2ServerConfig.h"
|
#include "core/models/api/apiV2ServerConfig.h"
|
||||||
|
|
||||||
@@ -32,6 +33,8 @@ struct ServerDescription
|
|||||||
DockerContainer defaultContainer = DockerContainer::None;
|
DockerContainer defaultContainer = DockerContainer::None;
|
||||||
bool hasInstalledVpnContainers = false;
|
bool hasInstalledVpnContainers = false;
|
||||||
|
|
||||||
|
bool isXRaySubscription = false;
|
||||||
|
|
||||||
bool isApiV1 = false;
|
bool isApiV1 = false;
|
||||||
bool isApiV2 = false;
|
bool isApiV2 = false;
|
||||||
bool isServerFromGatewayApi = false;
|
bool isServerFromGatewayApi = false;
|
||||||
@@ -56,6 +59,7 @@ struct ServerDescription
|
|||||||
ServerDescription buildServerDescription(const SelfHostedAdminServerConfig &server, bool isAmneziaDnsEnabled);
|
ServerDescription buildServerDescription(const SelfHostedAdminServerConfig &server, bool isAmneziaDnsEnabled);
|
||||||
ServerDescription buildServerDescription(const SelfHostedUserServerConfig &server, bool isAmneziaDnsEnabled);
|
ServerDescription buildServerDescription(const SelfHostedUserServerConfig &server, bool isAmneziaDnsEnabled);
|
||||||
ServerDescription buildServerDescription(const NativeServerConfig &server, bool isAmneziaDnsEnabled);
|
ServerDescription buildServerDescription(const NativeServerConfig &server, bool isAmneziaDnsEnabled);
|
||||||
|
ServerDescription buildServerDescription(const XRaySubscriptionConfig &server, bool isAmneziaDnsEnabled);
|
||||||
ServerDescription buildServerDescription(const LegacyApiServerConfig &server, bool isAmneziaDnsEnabled);
|
ServerDescription buildServerDescription(const LegacyApiServerConfig &server, bool isAmneziaDnsEnabled);
|
||||||
ServerDescription buildServerDescription(const ApiV2ServerConfig &server, bool isAmneziaDnsEnabled);
|
ServerDescription buildServerDescription(const ApiV2ServerConfig &server, bool isAmneziaDnsEnabled);
|
||||||
|
|
||||||
|
|||||||
@@ -348,6 +348,19 @@ std::optional<NativeServerConfig> SecureServersRepository::nativeConfig(const QS
|
|||||||
return NativeServerConfig::fromJson(strippedJson);
|
return NativeServerConfig::fromJson(strippedJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<XRaySubscriptionConfig> SecureServersRepository::xraySubscriptionConfig(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::XRaySubscription) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return XRaySubscriptionConfig::fromJson(strippedJson);
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<ApiV2ServerConfig> SecureServersRepository::apiV2Config(const QString &serverId) const
|
std::optional<ApiV2ServerConfig> SecureServersRepository::apiV2Config(const QString &serverId) const
|
||||||
{
|
{
|
||||||
const auto it = m_serverJsonById.constFind(serverId);
|
const auto it = m_serverJsonById.constFind(serverId);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "core/models/selfhosted/selfHostedAdminServerConfig.h"
|
#include "core/models/selfhosted/selfHostedAdminServerConfig.h"
|
||||||
#include "core/models/selfhosted/selfHostedUserServerConfig.h"
|
#include "core/models/selfhosted/selfHostedUserServerConfig.h"
|
||||||
#include "core/models/selfhosted/nativeServerConfig.h"
|
#include "core/models/selfhosted/nativeServerConfig.h"
|
||||||
|
#include "core/models/selfhosted/xraySubscriptionConfig.h"
|
||||||
#include "core/models/api/apiV2ServerConfig.h"
|
#include "core/models/api/apiV2ServerConfig.h"
|
||||||
#include "core/models/api/legacyApiServerConfig.h"
|
#include "core/models/api/legacyApiServerConfig.h"
|
||||||
#include "core/models/containerConfig.h"
|
#include "core/models/containerConfig.h"
|
||||||
@@ -34,6 +35,7 @@ public:
|
|||||||
std::optional<SelfHostedAdminServerConfig> selfHostedAdminConfig(const QString &serverId) const;
|
std::optional<SelfHostedAdminServerConfig> selfHostedAdminConfig(const QString &serverId) const;
|
||||||
std::optional<SelfHostedUserServerConfig> selfHostedUserConfig(const QString &serverId) const;
|
std::optional<SelfHostedUserServerConfig> selfHostedUserConfig(const QString &serverId) const;
|
||||||
std::optional<NativeServerConfig> nativeConfig(const QString &serverId) const;
|
std::optional<NativeServerConfig> nativeConfig(const QString &serverId) const;
|
||||||
|
std::optional<XRaySubscriptionConfig> xraySubscriptionConfig(const QString &serverId) const;
|
||||||
std::optional<ApiV2ServerConfig> apiV2Config(const QString &serverId) const;
|
std::optional<ApiV2ServerConfig> apiV2Config(const QString &serverId) const;
|
||||||
std::optional<LegacyApiServerConfig> legacyApiConfig(const QString &serverId) const;
|
std::optional<LegacyApiServerConfig> legacyApiConfig(const QString &serverId) const;
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ namespace amnezia
|
|||||||
constexpr QLatin1String protocol("protocol");
|
constexpr QLatin1String protocol("protocol");
|
||||||
constexpr QLatin1String protocols("protocols");
|
constexpr QLatin1String protocols("protocols");
|
||||||
|
|
||||||
|
constexpr QLatin1String xraySubscriptionLink("xray_subscription_link");
|
||||||
|
constexpr QLatin1String xraySubscriptionConfig("xray_subscription_config");
|
||||||
|
constexpr QLatin1String xraySubscriptionConfigName("xray_subscription_config_name");
|
||||||
|
constexpr QLatin1String xraySubscriptionConfigCurrent("xray_subscription_config_current");
|
||||||
|
|
||||||
constexpr QLatin1String remote("remote");
|
constexpr QLatin1String remote("remote");
|
||||||
constexpr QLatin1String transportProto("transport_proto");
|
constexpr QLatin1String transportProto("transport_proto");
|
||||||
constexpr QLatin1String cipher("cipher");
|
constexpr QLatin1String cipher("cipher");
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ namespace amnezia
|
|||||||
XrayServerConfigInvalid = 215,
|
XrayServerConfigInvalid = 215,
|
||||||
XrayServerNoVlessClients = 216,
|
XrayServerNoVlessClients = 216,
|
||||||
XrayRealityKeysReadFailed = 217,
|
XrayRealityKeysReadFailed = 217,
|
||||||
|
ServerContainerRuntimeNotSupported = 218,
|
||||||
|
ContainerRuntimeServiceNotRunning = 219,
|
||||||
|
|
||||||
// Ssh connection errors
|
// Ssh connection errors
|
||||||
SshRequestDeniedError = 300,
|
SshRequestDeniedError = 300,
|
||||||
@@ -124,5 +126,3 @@ namespace amnezia
|
|||||||
Q_DECLARE_METATYPE(amnezia::ErrorCode)
|
Q_DECLARE_METATYPE(amnezia::ErrorCode)
|
||||||
|
|
||||||
#endif // ERRORCODES_H
|
#endif // ERRORCODES_H
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ QString errorString(ErrorCode code) {
|
|||||||
case(ErrorCode::XrayRealityKeysReadFailed):
|
case(ErrorCode::XrayRealityKeysReadFailed):
|
||||||
errorMessage = QObject::tr("Server error: failed to read XRay Reality keys from the server");
|
errorMessage = QObject::tr("Server error: failed to read XRay Reality keys from the server");
|
||||||
break;
|
break;
|
||||||
|
case(ErrorCode::ServerContainerRuntimeNotSupported): errorMessage = QObject::tr("Server error: The default container runtime available for installation on this server is not supported.\n Install Docker Engine on the server manually and try again."); break;
|
||||||
|
case(ErrorCode::ContainerRuntimeServiceNotRunning): errorMessage = QObject::tr("Container runtime error: The container runtime service is not running.\n Check the container runtime service on the server, or wait about a minute and try again."); break;
|
||||||
|
|
||||||
// Libssh errors
|
// Libssh errors
|
||||||
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;
|
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
#include "sshExecutor.h"
|
|
||||||
|
|
||||||
SshExecutor &SshExecutor::instance()
|
|
||||||
{
|
|
||||||
static SshExecutor executor;
|
|
||||||
return executor;
|
|
||||||
}
|
|
||||||
|
|
||||||
SshExecutor::~SshExecutor()
|
|
||||||
{
|
|
||||||
QMutexLocker lock(&m_mutex);
|
|
||||||
for (QThreadPool *pool : std::as_const(m_pools)) {
|
|
||||||
pool->waitForDone();
|
|
||||||
delete pool;
|
|
||||||
}
|
|
||||||
m_pools.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
QThreadPool *SshExecutor::poolFor(const QString &serverId)
|
|
||||||
{
|
|
||||||
QMutexLocker lock(&m_mutex);
|
|
||||||
|
|
||||||
auto it = m_pools.find(serverId);
|
|
||||||
if (it != m_pools.end()) {
|
|
||||||
return it.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *pool = new QThreadPool();
|
|
||||||
pool->setMaxThreadCount(1); // serialize all SSH ops for this server
|
|
||||||
pool->setExpiryTimeout(-1); // keep the single worker thread alive between ops
|
|
||||||
m_pools.insert(serverId, pool);
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#ifndef SSHEXECUTOR_H
|
|
||||||
#define SSHEXECUTOR_H
|
|
||||||
|
|
||||||
#include <QHash>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QString>
|
|
||||||
#include <QThreadPool>
|
|
||||||
#include <QtConcurrent>
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
// Per-server serial executor for long-running self-hosted SSH operations.
|
|
||||||
//
|
|
||||||
// All SSH work for a given serverId is queued onto a dedicated single-thread
|
|
||||||
// pool, so operations to the same server run strictly one at a time (no
|
|
||||||
// concurrent SSH sessions to one host => no races, and a natural guard against
|
|
||||||
// double-run). Operations to different servers still run in parallel.
|
|
||||||
//
|
|
||||||
// NOTE: do NOT route nested workers that are awaited from within an already
|
|
||||||
// queued operation (e.g. InstallController::isServerDpkgBusy) through the same
|
|
||||||
// per-server pool — the single worker thread would block waiting on itself.
|
|
||||||
// Such nested helpers must keep using the global QThreadPool.
|
|
||||||
class SshExecutor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static SshExecutor &instance();
|
|
||||||
|
|
||||||
SshExecutor(const SshExecutor &) = delete;
|
|
||||||
SshExecutor &operator=(const SshExecutor &) = delete;
|
|
||||||
|
|
||||||
template <typename Functor>
|
|
||||||
auto run(const QString &serverId, Functor &&functor)
|
|
||||||
{
|
|
||||||
return QtConcurrent::run(poolFor(serverId), std::forward<Functor>(functor));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
SshExecutor() = default;
|
|
||||||
~SshExecutor();
|
|
||||||
|
|
||||||
QThreadPool *poolFor(const QString &serverId);
|
|
||||||
|
|
||||||
QHash<QString, QThreadPool *> m_pools;
|
|
||||||
QMutex m_mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SSHEXECUTOR_H
|
|
||||||
@@ -29,6 +29,12 @@ bool hasThirdPartyConfig(const QJsonObject &json)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasXrayConfigs(const QJsonObject &json)
|
||||||
|
{
|
||||||
|
const QJsonArray configsArray = json.value(amnezia::configKey::xraySubscriptionConfig).toArray();
|
||||||
|
return !configsArray.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace serverConfigUtils
|
namespace serverConfigUtils
|
||||||
@@ -93,6 +99,10 @@ ConfigType configTypeFromJson(const QJsonObject &serverConfigObject)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasXrayConfigs(serverConfigObject)) {
|
||||||
|
return ConfigType::XRaySubscription;
|
||||||
|
}
|
||||||
|
|
||||||
if (hasThirdPartyConfig(serverConfigObject)) {
|
if (hasThirdPartyConfig(serverConfigObject)) {
|
||||||
return ConfigType::Native;
|
return ConfigType::Native;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ enum ConfigType {
|
|||||||
SelfHostedAdmin = 8,
|
SelfHostedAdmin = 8,
|
||||||
SelfHostedUser,
|
SelfHostedUser,
|
||||||
Native,
|
Native,
|
||||||
|
XRaySubscription,
|
||||||
Invalid
|
Invalid
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9 3.75V14.25" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M14.25 9L9 14.25L3.75 9" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 327 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9 14.25V3.75" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M3.75 9L9 3.75L14.25 9" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 326 B |
@@ -9,8 +9,10 @@
|
|||||||
<file>controls/amnezia.svg</file>
|
<file>controls/amnezia.svg</file>
|
||||||
<file>controls/app.svg</file>
|
<file>controls/app.svg</file>
|
||||||
<file>controls/archive-restore.svg</file>
|
<file>controls/archive-restore.svg</file>
|
||||||
|
<file>controls/arrow-down.svg</file>
|
||||||
<file>controls/arrow-left.svg</file>
|
<file>controls/arrow-left.svg</file>
|
||||||
<file>controls/arrow-right.svg</file>
|
<file>controls/arrow-right.svg</file>
|
||||||
|
<file>controls/arrow-up.svg</file>
|
||||||
<file>controls/bug.svg</file>
|
<file>controls/bug.svg</file>
|
||||||
<file>controls/check.svg</file>
|
<file>controls/check.svg</file>
|
||||||
<file>controls/chevron-down.svg</file>
|
<file>controls/chevron-down.svg</file>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
if which apt-get > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/lib/dpkg/lock-frontend";\
|
if which apt-get > /dev/null 2>&1 || command -v apt-get > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/lib/dpkg/lock-frontend";\
|
||||||
elif which dnf > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/cache/dnf/* /var/run/dnf/* /var/lib/dnf/* /var/lib/rpm/*";\
|
elif which dnf > /dev/null 2>&1 || command -v dnf > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/cache/dnf/* /var/run/dnf/* /var/lib/dnf/* /var/lib/rpm/*";\
|
||||||
elif which yum > /dev/null 2>&1; then LOCK_CMD="cat"; LOCK_FILE="/var/run/yum.pid";\
|
elif which yum > /dev/null 2>&1 || command -v yum > /dev/null 2>&1; then LOCK_CMD="cat"; LOCK_FILE="/var/run/yum.pid";\
|
||||||
elif which zypper > /dev/null 2>&1; then LOCK_CMD="cat"; LOCK_FILE="/var/run/zypp.pid";\
|
elif which zypper > /dev/null 2>&1 || command -v zypper > /dev/null 2>&1; then LOCK_CMD="cat"; LOCK_FILE="/var/run/zypp.pid";\
|
||||||
elif which pacman > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/lib/pacman/db.lck";\
|
elif which pacman > /dev/null 2>&1 || command -v pacman > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/lib/pacman/db.lck";\
|
||||||
else echo "Packet manager not found"; echo "Internal error"; exit 1; fi;\
|
else echo "Packet manager not found"; echo "Internal error"; exit 1;\
|
||||||
if command -v $LOCK_CMD > /dev/null 2>&1; then sudo $LOCK_CMD $LOCK_FILE 2>/dev/null; else echo "$LOCK_CMD not installed"; fi
|
fi;\
|
||||||
|
if sudo -n which $LOCK_CMD > /dev/null 2>&1 || command -v $LOCK_CMD > /dev/null 2>&1; then sudo -n $LOCK_CMD $LOCK_FILE 2>/dev/null; else echo "$LOCK_CMD not installed"; fi
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); opt="--version";\
|
if pm=$(which apt-get 2>/dev/null || command -v apt-get 2>/dev/null); then opt="--version";\
|
||||||
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); opt="--version";\
|
elif pm=$(which dnf 2>/dev/null || command -v dnf 2>/dev/null); then opt="--version";\
|
||||||
elif which yum > /dev/null 2>&1; then pm=$(which yum); opt="--version";\
|
elif pm=$(which yum 2>/dev/null || command -v yum 2>/dev/null); then opt="--version";\
|
||||||
elif which zypper > /dev/null 2>&1; then pm=$(which zypper); opt="--version";\
|
elif pm=$(which zypper 2>/dev/null || command -v zypper 2>/dev/null); then opt="--version";\
|
||||||
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); opt="--version";\
|
elif pm=$(which pacman 2>/dev/null || command -v pacman 2>/dev/null); then opt="--version";\
|
||||||
else pm="uname"; opt="-a";\
|
else pm="uname"; opt="-a";\
|
||||||
fi;\
|
fi;\
|
||||||
CUR_USER=$(whoami 2>/dev/null || echo $HOME | sed 's/.*\///');\
|
CUR_USER=$(whoami 2>/dev/null || echo $HOME | sed 's/.*\///');\
|
||||||
|
|||||||
@@ -1,25 +1,34 @@
|
|||||||
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";\
|
if pm=$(which apt-get 2>/dev/null || command -v apt-get 2>/dev/null); then silent_inst="-yq install --install-recommends"; what_pkg="-s install"; 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 pm=$(which dnf 2>/dev/null || command -v dnf 2>/dev/null); then silent_inst="-yq install"; what_pkg="--assumeno install --setopt=tsflags=test"; 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 pm=$(which yum 2>/dev/null || command -v yum 2>/dev/null); then silent_inst="-y -q install"; what_pkg="--assumeno install --setopt=tsflags=test"; 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 pm=$(which zypper 2>/dev/null || command -v zypper 2>/dev/null); then silent_inst="-nq install"; what_pkg="--dry-run install"; check_pkgs="-nq refresh"; docker_pkg="docker"; dist="suse";\
|
||||||
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="-Sup"; docker_pkg="docker"; dist="archlinux";\
|
elif pm=$(which pacman 2>/dev/null || command -v pacman 2>/dev/null); then silent_inst="-S --noconfirm --noprogressbar --quiet"; what_pkg="-Sp"; check_pkgs="-Sup"; docker_pkg="docker"; dist="archlinux";\
|
||||||
else echo "Packet manager not found"; exit 1; fi;\
|
fi;\
|
||||||
echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, Docker pkg: $docker_pkg";\
|
echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, What pkg command: $what_pkg, Check pkgs command: $check_pkgs, Docker pkg: $docker_pkg, Language: $LANG";\
|
||||||
|
echo $LANG | grep -qE '^(en_US.UTF-8|C.UTF-8|C)$' || export LC_ALL=C;\
|
||||||
if [ "$dist" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive; fi;\
|
if [ "$dist" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive; fi;\
|
||||||
if ! command -v sudo > /dev/null 2>&1; then $pm $check_pkgs; $pm $silent_inst sudo; fi;\
|
if ! command -v sudo > /dev/null 2>&1; then $pm $check_pkgs; $pm $silent_inst sudo; fi;\
|
||||||
if ! command -v fuser > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst psmisc; fi;\
|
if ! sudo -n sh -c 'command -v which > /dev/null 2>&1'; then sudo -n $pm $check_pkgs; sudo -n $pm $silent_inst which; fi;\
|
||||||
if ! command -v lsof > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst lsof; fi;\
|
if ! sudo -n sh -c 'command -v fuser > /dev/null 2>&1'; then sudo -n $pm $check_pkgs; sudo -n $pm $silent_inst psmisc; fi;\
|
||||||
if ! command -v docker > /dev/null 2>&1; then \
|
if ! sudo -n sh -c 'command -v lsof > /dev/null 2>&1'; then sudo -n $pm $check_pkgs; sudo -n $pm $silent_inst lsof; fi;\
|
||||||
sudo $pm $check_pkgs; sudo $pm $silent_inst $docker_pkg;\
|
if ! sudo -n sh -c 'command -v docker > /dev/null 2>&1'; then \
|
||||||
sleep 5; sudo systemctl enable --now docker; sleep 5;\
|
sudo -n $pm $check_pkgs;\
|
||||||
|
if ! sudo -n $pm $what_pkg $docker_pkg 2>/dev/null | grep -qi podman; then \
|
||||||
|
sudo -n $pm $silent_inst $docker_pkg;\
|
||||||
|
sleep 5; sudo -n systemctl enable --now docker; sleep 5;\
|
||||||
|
else \
|
||||||
|
echo "Container runtime is not supported";\
|
||||||
|
exit 1;\
|
||||||
fi;\
|
fi;\
|
||||||
if [ "$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = "Y" ]; then \
|
|
||||||
if ! command -v apparmor_parser > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst apparmor; fi;\
|
|
||||||
fi;\
|
fi;\
|
||||||
if [ "$(systemctl is-active docker)" != "active" ]; then \
|
if [ "$(sudo -n cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = "Y" ]; then \
|
||||||
sudo $pm $check_pkgs; sudo $pm $silent_inst $docker_pkg;\
|
if ! sudo -n sh -c 'command -v apparmor_parser > /dev/null 2>&1'; then \
|
||||||
sleep 5; sudo systemctl start docker; sleep 5;\
|
sudo -n $pm $check_pkgs; sudo -n $pm $silent_inst apparmor;\
|
||||||
fi;\
|
fi;\
|
||||||
if ! command -v sudo > /dev/null 2>&1; then echo "Failed to install sudo, command not found"; exit 1; fi;\
|
fi;\
|
||||||
docker --version;\
|
if [ "$(sudo -n systemctl is-active docker)" != "active" ]; then \
|
||||||
|
sleep 5; sudo -n systemctl start docker; sleep 5;\
|
||||||
|
if [ "$(sudo -n systemctl is-active docker)" != "active" ]; then echo "Container runtime service not running"; fi;\
|
||||||
|
fi;\
|
||||||
|
sudo -n docker --version || docker --version;\
|
||||||
uname -sr
|
uname -sr
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
sudo docker ps -a | grep amnezia | awk '{print $1}' | xargs sudo docker stop;\
|
sudo docker ps -a | grep amnezia | awk '{print $1}' | xargs sudo docker stop;\
|
||||||
sudo docker ps -a | grep amnezia | awk '{print $1}' | xargs sudo docker rm -fv;\
|
sudo docker ps -a | grep amnezia | awk '{print $1}' | xargs sudo docker rm -fv;\
|
||||||
sudo docker images -a --format table | grep amnezia | awk '{print $3, $1 ":" $2}' | xargs sudo docker rmi;\
|
sudo docker images -a --format table | grep amnezia | awk '{print $3, $1 ":" $2}' | xargs sudo docker rmi;\
|
||||||
sudo docker volume ls | grep amnezia | awk '{print $2}' | xargs sudo docker volume rm -f;\
|
sudo docker volume ls --format '{{.Name}}' | grep '^amnezia-' | xargs -r sudo docker volume rm -f;\
|
||||||
sudo docker network ls | grep amnezia-dns-net | awk '{print $1}' | xargs sudo docker network rm;\
|
sudo docker network ls | grep amnezia-dns-net | awk '{print $1}' | xargs sudo docker network rm;\
|
||||||
sudo rm -frd /opt/amnezia
|
sudo rm -frd /opt/amnezia
|
||||||
|
|||||||
@@ -31,6 +31,41 @@ ImportUiController::ImportUiController(ImportController* importController, QObje
|
|||||||
connect(m_importController, &ImportController::restoreAppConfig, this, &ImportUiController::restoreAppConfig);
|
connect(m_importController, &ImportController::restoreAppConfig, this, &ImportUiController::restoreAppConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ImportUiController::importLink(const QUrl &url)
|
||||||
|
{
|
||||||
|
auto result = m_importController->importLink(url);
|
||||||
|
|
||||||
|
if (result.errorCode != ErrorCode::NoError) {
|
||||||
|
emit importErrorOccurred(result.errorCode, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_config = result.config;
|
||||||
|
m_configFileName = result.configFileName;
|
||||||
|
m_maliciousWarningText = result.maliciousWarningText;
|
||||||
|
m_isNativeWireGuardConfig = result.isNativeWireGuardConfig;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImportUiController::editServerConfigWithData(const QString &serverId, QString data)
|
||||||
|
{
|
||||||
|
auto result = m_importController->editServerConfigWithData(serverId, data, m_config);
|
||||||
|
|
||||||
|
if (result.errorCode != ErrorCode::NoError) {
|
||||||
|
emit importErrorOccurred(result.errorCode, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_config = result.config;
|
||||||
|
m_configFileName = result.configFileName;
|
||||||
|
m_maliciousWarningText = result.maliciousWarningText;
|
||||||
|
m_isNativeWireGuardConfig = result.isNativeWireGuardConfig;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ImportUiController::extractConfigFromFile(const QString &fileName)
|
bool ImportUiController::extractConfigFromFile(const QString &fileName)
|
||||||
{
|
{
|
||||||
QString data;
|
QString data;
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void importConfig();
|
void importConfig();
|
||||||
void clearConfigFileName();
|
void clearConfigFileName();
|
||||||
|
bool importLink(const QUrl &url);
|
||||||
|
bool editServerConfigWithData(const QString &serverId, QString data);
|
||||||
bool extractConfigFromFile(const QString &fileName);
|
bool extractConfigFromFile(const QString &fileName);
|
||||||
bool extractConfigFromData(QString data);
|
bool extractConfigFromData(QString data);
|
||||||
bool extractConfigFromQr(const QByteArray &data);
|
bool extractConfigFromQr(const QByteArray &data);
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ namespace PageLoader
|
|||||||
PageSettingsApiNativeConfigs,
|
PageSettingsApiNativeConfigs,
|
||||||
PageSettingsApiDevices,
|
PageSettingsApiDevices,
|
||||||
PageSettingsApiSubscriptionKey,
|
PageSettingsApiSubscriptionKey,
|
||||||
|
PageSettingsXRayAvailableConfigs,
|
||||||
|
PageSettingsXRayServerInfo,
|
||||||
PageSettingsKillSwitchExceptions,
|
PageSettingsKillSwitchExceptions,
|
||||||
|
|
||||||
PageServiceSftpSettings,
|
PageServiceSftpSettings,
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
#include "core/utils/api/apiUtils.h"
|
#include "core/utils/api/apiUtils.h"
|
||||||
#include "core/utils/selfhosted/sshExecutor.h"
|
|
||||||
#include "core/controllers/selfhosted/installController.h"
|
#include "core/controllers/selfhosted/installController.h"
|
||||||
#include "core/controllers/connectionController.h"
|
#include "core/controllers/connectionController.h"
|
||||||
#include "core/utils/networkUtilities.h"
|
#include "core/utils/networkUtilities.h"
|
||||||
@@ -331,7 +330,7 @@ void InstallUiController::updateServerConfig(const QString &serverId, int contai
|
|||||||
ContainerConfig oldConfigCopy = oldContainerConfig;
|
ContainerConfig oldConfigCopy = oldContainerConfig;
|
||||||
InstallController *installController = m_installController;
|
InstallController *installController = m_installController;
|
||||||
QFuture<ErrorCode> future =
|
QFuture<ErrorCode> future =
|
||||||
SshExecutor::instance().run(serverId, [installController, serverId, container, oldConfigCopy,
|
QtConcurrent::run([installController, serverId, container, oldConfigCopy,
|
||||||
newConfigCopy]() mutable -> ErrorCode {
|
newConfigCopy]() mutable -> ErrorCode {
|
||||||
return installController->updateServerConfig(serverId, container, oldConfigCopy, newConfigCopy);
|
return installController->updateServerConfig(serverId, container, oldConfigCopy, newConfigCopy);
|
||||||
});
|
});
|
||||||
@@ -479,7 +478,7 @@ void InstallUiController::removeContainer(const QString &serverId, int container
|
|||||||
});
|
});
|
||||||
|
|
||||||
InstallController *installController = m_installController;
|
InstallController *installController = m_installController;
|
||||||
QFuture<ErrorCode> future = SshExecutor::instance().run(serverId,
|
QFuture<ErrorCode> future = QtConcurrent::run(
|
||||||
[installController, serverId, container]() -> ErrorCode {
|
[installController, serverId, container]() -> ErrorCode {
|
||||||
return installController->removeContainer(serverId, container);
|
return installController->removeContainer(serverId, container);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -276,6 +276,17 @@ bool ServersUiController::hasServerWithWriteAccess() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ServersUiController::isDefaultServerContainXRayConfigs() const
|
||||||
|
{
|
||||||
|
const QString defaultServerId = m_serversController->getDefaultServerId();
|
||||||
|
for (const auto &description : m_orderedServerDescriptions) {
|
||||||
|
if (description.serverId == defaultServerId) {
|
||||||
|
return description.isXRaySubscription;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QString ServersUiController::serverName(const QString &serverId) const
|
QString ServersUiController::serverName(const QString &serverId) const
|
||||||
{
|
{
|
||||||
return serverDescriptionById(serverId).serverName;
|
return serverDescriptionById(serverId).serverName;
|
||||||
@@ -332,6 +343,11 @@ bool ServersUiController::isServerSubscriptionExpiringSoon(const QString &server
|
|||||||
return serverDescriptionById(serverId).isSubscriptionExpiringSoon;
|
return serverDescriptionById(serverId).isSubscriptionExpiringSoon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ServersUiController::isServerContainXRayConfigs(const QString &serverId) const
|
||||||
|
{
|
||||||
|
return serverDescriptionById(serverId).isXRaySubscription;
|
||||||
|
}
|
||||||
|
|
||||||
int ServersUiController::getProcessedContainerIndex() const
|
int ServersUiController::getProcessedContainerIndex() const
|
||||||
{
|
{
|
||||||
return m_processedContainerIndex;
|
return m_processedContainerIndex;
|
||||||
@@ -470,6 +486,36 @@ int ServersUiController::getServersCount() const
|
|||||||
return m_orderedServerDescriptions.size();
|
return m_orderedServerDescriptions.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ServersUiController::getSubLink() const
|
||||||
|
{
|
||||||
|
return m_serversController->getSubLink(m_processedServerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ServersUiController::getConfigString(const int index) const
|
||||||
|
{
|
||||||
|
return m_serversController->getConfigString(m_processedServerId, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ServersUiController::getConfigName(const int index) const
|
||||||
|
{
|
||||||
|
return m_serversController->getConfigName(m_processedServerId, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray ServersUiController::getConfigNames() const
|
||||||
|
{
|
||||||
|
return m_serversController->getConfigNames(m_processedServerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ServersUiController::getCurrentConfigIndex() const
|
||||||
|
{
|
||||||
|
return m_serversController->getCurrentConfigIndex(m_processedServerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServersUiController::setCurrentConfigIndex(const int index)
|
||||||
|
{
|
||||||
|
m_serversController->setCurrentConfigIndex(m_processedServerId, index);
|
||||||
|
}
|
||||||
|
|
||||||
void ServersUiController::updateContainersModel()
|
void ServersUiController::updateContainersModel()
|
||||||
{
|
{
|
||||||
if (m_processedServerId.isEmpty()) {
|
if (m_processedServerId.isEmpty()) {
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ class ServersUiController : public QObject
|
|||||||
Q_PROPERTY(bool isDefaultServerDefaultContainerHasSplitTunneling READ isDefaultServerDefaultContainerHasSplitTunneling NOTIFY defaultServerIdChanged)
|
Q_PROPERTY(bool isDefaultServerDefaultContainerHasSplitTunneling READ isDefaultServerDefaultContainerHasSplitTunneling NOTIFY defaultServerIdChanged)
|
||||||
Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIdChanged)
|
Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIdChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(bool isDefaultServerContainXRayConfigs READ isDefaultServerContainXRayConfigs NOTIFY defaultServerIdChanged)
|
||||||
|
|
||||||
Q_PROPERTY(QString processedServerId READ getProcessedServerId WRITE setProcessedServerId NOTIFY processedServerIdChanged)
|
Q_PROPERTY(QString processedServerId READ getProcessedServerId WRITE setProcessedServerId NOTIFY processedServerIdChanged)
|
||||||
Q_PROPERTY(int processedContainerIndex READ getProcessedContainerIndex WRITE setProcessedContainerIndex NOTIFY processedContainerIndexChanged)
|
Q_PROPERTY(int processedContainerIndex READ getProcessedContainerIndex WRITE setProcessedContainerIndex NOTIFY processedContainerIndexChanged)
|
||||||
Q_PROPERTY(bool processedServerIsPremium READ processedServerIsPremium NOTIFY processedServerIdChanged)
|
Q_PROPERTY(bool processedServerIsPremium READ processedServerIsPremium NOTIFY processedServerIdChanged)
|
||||||
@@ -70,6 +72,8 @@ public slots:
|
|||||||
QString getDefaultServerDescriptionExpanded() const;
|
QString getDefaultServerDescriptionExpanded() const;
|
||||||
bool isDefaultServerDefaultContainerHasSplitTunneling() const;
|
bool isDefaultServerDefaultContainerHasSplitTunneling() const;
|
||||||
bool isDefaultServerFromApi() const;
|
bool isDefaultServerFromApi() const;
|
||||||
|
bool isDefaultServerContainXRayConfigs() const;
|
||||||
|
|
||||||
bool hasServerWithWriteAccess() const;
|
bool hasServerWithWriteAccess() const;
|
||||||
|
|
||||||
QString serverName(const QString &serverId) const;
|
QString serverName(const QString &serverId) const;
|
||||||
@@ -84,6 +88,8 @@ public slots:
|
|||||||
bool isServerSubscriptionExpired(const QString &serverId) const;
|
bool isServerSubscriptionExpired(const QString &serverId) const;
|
||||||
bool isServerSubscriptionExpiringSoon(const QString &serverId) const;
|
bool isServerSubscriptionExpiringSoon(const QString &serverId) const;
|
||||||
|
|
||||||
|
bool isServerContainXRayConfigs(const QString &serverId) const;
|
||||||
|
|
||||||
QString getProcessedServerId() const;
|
QString getProcessedServerId() const;
|
||||||
void setProcessedServerId(const QString &serverId);
|
void setProcessedServerId(const QString &serverId);
|
||||||
|
|
||||||
@@ -100,6 +106,13 @@ public slots:
|
|||||||
QString adHeader() const;
|
QString adHeader() const;
|
||||||
QString adDescription() const;
|
QString adDescription() const;
|
||||||
|
|
||||||
|
QString getSubLink() const;
|
||||||
|
QString getConfigString(const int index) const;
|
||||||
|
QString getConfigName(const int index) const;
|
||||||
|
QJsonArray getConfigNames() const;
|
||||||
|
int getCurrentConfigIndex() const;
|
||||||
|
void setCurrentConfigIndex(int index);
|
||||||
|
|
||||||
QString getServerId(int index) const;
|
QString getServerId(int index) const;
|
||||||
int getServerIndexById(const QString &serverId) const;
|
int getServerIndexById(const QString &serverId) const;
|
||||||
int getServersCount() const;
|
int getServersCount() const;
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
|
|||||||
return row.isSubscriptionExpired;
|
return row.isSubscriptionExpired;
|
||||||
case IsSubscriptionExpiringSoonRole:
|
case IsSubscriptionExpiringSoonRole:
|
||||||
return row.isSubscriptionExpiringSoon;
|
return row.isSubscriptionExpiringSoon;
|
||||||
|
case IsXRayConfigSelectionAvailableRole:
|
||||||
|
return row.isXRaySubscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@@ -142,6 +144,8 @@ QHash<int, QByteArray> ServersModel::roleNames() const
|
|||||||
roles[IsSubscriptionExpiredRole] = "isSubscriptionExpired";
|
roles[IsSubscriptionExpiredRole] = "isSubscriptionExpired";
|
||||||
roles[IsSubscriptionExpiringSoonRole] = "isSubscriptionExpiringSoon";
|
roles[IsSubscriptionExpiringSoonRole] = "isSubscriptionExpiringSoon";
|
||||||
|
|
||||||
|
roles[IsXRayConfigSelectionAvailableRole] = "isXRayConfigSelectionAvailable";
|
||||||
|
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ public:
|
|||||||
IsServerFromGatewayApiRole,
|
IsServerFromGatewayApiRole,
|
||||||
IsSubscriptionExpiredRole,
|
IsSubscriptionExpiredRole,
|
||||||
IsSubscriptionExpiringSoonRole,
|
IsSubscriptionExpiringSoonRole,
|
||||||
|
|
||||||
|
IsXRayConfigSelectionAvailableRole
|
||||||
};
|
};
|
||||||
|
|
||||||
ServersModel(QObject *parent = nullptr);
|
ServersModel(QObject *parent = nullptr);
|
||||||
|
|||||||
@@ -121,6 +121,8 @@ ListViewType {
|
|||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
|
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
|
||||||
}
|
}
|
||||||
|
} else if (ServersUiController.isServerContainXRayConfigs(ServersUiController.processedServerId)) {
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsXRayAvailableConfigs)
|
||||||
} else {
|
} else {
|
||||||
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -311,11 +311,11 @@ PageType {
|
|||||||
objectName: "rowLayoutLabel"
|
objectName: "rowLayoutLabel"
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
Layout.topMargin: 8
|
Layout.topMargin: 8
|
||||||
Layout.bottomMargin: drawer.isCollapsedStateActive ? 44 : ServersUiController.isDefaultServerFromApi ? 61 : 16
|
Layout.bottomMargin: drawer.isCollapsedStateActive ? 44 : (ServersUiController.isDefaultServerFromApi || ServersUiController.isDefaultServerContainXRayConfigs) ? 61 : 16
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
enabled: (ServersUiController.defaultServerImagePathCollapsed !== "") && drawer.isCollapsedStateActive
|
enabled: (ServersUiController.defaultServerImagePathCollapsed !== "" || ServersUiController.isDefaultServerContainXRayConfigs) && drawer.isCollapsedStateActive
|
||||||
hoverEnabled: enabled
|
hoverEnabled: enabled
|
||||||
|
|
||||||
implicitHeight: 36
|
implicitHeight: 36
|
||||||
@@ -359,6 +359,8 @@ PageType {
|
|||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
|
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
|
||||||
}
|
}
|
||||||
|
} else if (ServersUiController.isServerContainXRayConfigs(ServersUiController.processedServerId)) {
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsXRayAvailableConfigs)
|
||||||
} else {
|
} else {
|
||||||
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
||||||
}
|
}
|
||||||
@@ -379,7 +381,7 @@ PageType {
|
|||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
visible: !ServersUiController.isDefaultServerFromApi
|
visible: !ServersUiController.isDefaultServerFromApi && !ServersUiController.isDefaultServerContainXRayConfigs
|
||||||
|
|
||||||
DropDownType {
|
DropDownType {
|
||||||
id: containersDropDown
|
id: containersDropDown
|
||||||
|
|||||||
@@ -97,6 +97,8 @@ PageType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
|
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
|
||||||
|
} else if (ServersModel.getProcessedServerData("isXRayConfigSelectionAvailable")) {
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsXRayServerInfo)
|
||||||
} else {
|
} else {
|
||||||
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Dialogs
|
||||||
|
|
||||||
|
import SortFilterProxyModel 0.2
|
||||||
|
|
||||||
|
import PageEnum 1.0
|
||||||
|
import Style 1.0
|
||||||
|
|
||||||
|
import "./"
|
||||||
|
import "../Controls2"
|
||||||
|
import "../Controls2/TextTypes"
|
||||||
|
import "../Config"
|
||||||
|
import "../Components"
|
||||||
|
|
||||||
|
PageType {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var processedServer
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: PageController
|
||||||
|
|
||||||
|
function onGoToPageSettingsServerServices() {
|
||||||
|
tabBar.setCurrentIndex(root.pageSettingsServerServices)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: ServersUiController
|
||||||
|
|
||||||
|
function onProcessedServerIdChanged() {
|
||||||
|
root.processedServer = proxyServersModel.get(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: ServersModel
|
||||||
|
|
||||||
|
function onModelReset() {
|
||||||
|
root.processedServer = proxyServersModel.get(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SortFilterProxyModel {
|
||||||
|
id: proxyServersModel
|
||||||
|
objectName: "proxyServersModel"
|
||||||
|
|
||||||
|
sourceModel: ServersModel
|
||||||
|
filters: [
|
||||||
|
ValueFilter {
|
||||||
|
roleName: "serverId"
|
||||||
|
value: ServersUiController.processedServerId
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
root.processedServer = proxyServersModel.get(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListViewType {
|
||||||
|
id: menuContent
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
model: xrayConfigs
|
||||||
|
|
||||||
|
currentIndex: 0
|
||||||
|
|
||||||
|
ButtonGroup {
|
||||||
|
id: containersRadioButtonGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
header: ColumnLayout {
|
||||||
|
width: menuContent.width
|
||||||
|
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
BackButtonType {
|
||||||
|
id: backButton
|
||||||
|
objectName: "backButton"
|
||||||
|
|
||||||
|
Layout.topMargin: 20 + PageController.safeAreaTopMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderTypeWithButton {
|
||||||
|
id: headerContent
|
||||||
|
objectName: "headerContent"
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 10
|
||||||
|
|
||||||
|
actionButtonImage: "qrc:/images/controls/settings.svg"
|
||||||
|
|
||||||
|
headerText: root.processedServer.name
|
||||||
|
|
||||||
|
actionButtonFunction: function() {
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsXRayServerInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: ColumnLayout {
|
||||||
|
id: content
|
||||||
|
|
||||||
|
width: menuContent.width
|
||||||
|
height: content.implicitHeight
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
VerticalRadioButton {
|
||||||
|
id: containerRadioButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
|
||||||
|
text: model.title
|
||||||
|
|
||||||
|
ButtonGroup.group: containersRadioButtonGroup
|
||||||
|
|
||||||
|
imageSource: "qrc:/images/controls/download.svg"
|
||||||
|
|
||||||
|
checked: index === ServersUiController.getCurrentConfigIndex()
|
||||||
|
checkable: !ConnectionController.isConnected
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (ConnectionController.isConnectionInProgress) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Unable change config while trying to make an active connection"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (ConnectionController.isConnected) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Unable change config while there is an active connection"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index !== ServersUiController.getCurrentConfigIndex()) {
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
ServersUiController.setCurrentConfigIndex(index)
|
||||||
|
ImportController.editServerConfigWithData(ServersUiController.getProcessedServerId(), ServersUiController.getConfigString(index))
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onEnterPressed: {
|
||||||
|
if (checkable) {
|
||||||
|
checked = true
|
||||||
|
}
|
||||||
|
containerRadioButton.clicked()
|
||||||
|
}
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
if (checkable) {
|
||||||
|
checked = true
|
||||||
|
}
|
||||||
|
containerRadioButton.clicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: xrayConfigs
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
xrayConfigs.clear()
|
||||||
|
const names = ServersUiController.getConfigNames()
|
||||||
|
|
||||||
|
for (let i = 0; i < names.length; ++i) {
|
||||||
|
xrayConfigs.append({ title: names[i] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Dialogs
|
||||||
|
|
||||||
|
import SortFilterProxyModel 0.2
|
||||||
|
|
||||||
|
import PageEnum 1.0
|
||||||
|
import Style 1.0
|
||||||
|
|
||||||
|
import "./"
|
||||||
|
import "../Controls2"
|
||||||
|
import "../Controls2/TextTypes"
|
||||||
|
import "../Config"
|
||||||
|
import "../Components"
|
||||||
|
|
||||||
|
PageType {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var processedServer
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: PageController
|
||||||
|
|
||||||
|
function onGoToPageSettingsServerServices() {
|
||||||
|
tabBar.setCurrentIndex(root.pageSettingsServerServices)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: ServersUiController
|
||||||
|
|
||||||
|
function onProcessedServerIdChanged() {
|
||||||
|
root.processedServer = proxyServersModel.get(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: ServersModel
|
||||||
|
|
||||||
|
function onModelReset() {
|
||||||
|
root.processedServer = proxyServersModel.get(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SortFilterProxyModel {
|
||||||
|
id: proxyServersModel
|
||||||
|
objectName: "proxyServersModel"
|
||||||
|
|
||||||
|
sourceModel: ServersModel
|
||||||
|
filters: [
|
||||||
|
ValueFilter {
|
||||||
|
roleName: "serverId"
|
||||||
|
value: ServersUiController.processedServerId
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
root.processedServer = proxyServersModel.get(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListViewType {
|
||||||
|
id: listView
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
model: 1
|
||||||
|
|
||||||
|
header: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
BackButtonType {
|
||||||
|
id: backButton
|
||||||
|
objectName: "backButton"
|
||||||
|
|
||||||
|
Layout.topMargin: 20 + PageController.safeAreaTopMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderTypeWithButton {
|
||||||
|
id: headerContent
|
||||||
|
objectName: "headerContent"
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 10
|
||||||
|
|
||||||
|
actionButtonImage: "qrc:/images/controls/edit-3.svg"
|
||||||
|
|
||||||
|
headerText: root.processedServer.name
|
||||||
|
|
||||||
|
actionButtonFunction: function() {
|
||||||
|
serverNameEditDrawer.openTriggered()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: ColumnLayout {
|
||||||
|
id: footer
|
||||||
|
|
||||||
|
width: listView.width
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: resetButton
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
Layout.leftMargin: 8
|
||||||
|
implicitHeight: 32
|
||||||
|
|
||||||
|
defaultColor: "transparent"
|
||||||
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
|
pressedColor: AmneziaStyle.color.sheerWhite
|
||||||
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
|
text: qsTr("Reload config")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
var headerText = qsTr("Reload config?")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ServersUiController.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Cannot reload config during active connection"))
|
||||||
|
} else {
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
if (!ImportController.importLink(ServersUiController.getSubLink()) &&
|
||||||
|
!ImportController.editServerConfigWithData(ServersUiController.getProcessedServerId(), ServersUiController.getConfigString(ServersUiController.getCurrentConfigIndex()))) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Error during config reload"))
|
||||||
|
}
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: removeButton
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
Layout.leftMargin: 8
|
||||||
|
implicitHeight: 32
|
||||||
|
|
||||||
|
defaultColor: "transparent"
|
||||||
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
|
pressedColor: AmneziaStyle.color.sheerWhite
|
||||||
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
|
text: qsTr("Remove from application")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
var headerText = qsTr("Remove from application?")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ServersUiController.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Cannot remove server during active connection"))
|
||||||
|
} else {
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
InstallController.removeServer(ServersUiController.getProcessedServerId())
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RenameServerDrawer {
|
||||||
|
id: serverNameEditDrawer
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
expandedHeight: parent.height * 0.35
|
||||||
|
|
||||||
|
serverNameText: root.processedServer.name
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -187,8 +187,19 @@ PageType {
|
|||||||
|
|
||||||
text: qsTr("Continue")
|
text: qsTr("Continue")
|
||||||
|
|
||||||
|
function isValidUrl(text) {
|
||||||
|
try {
|
||||||
|
var u = new URL(text)
|
||||||
|
return u.protocol === "http:" || u.protocol === "https:"
|
||||||
|
} catch(e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
if (ImportController.extractConfigFromData(textKey.textField.text)) {
|
if (isValidUrl(textKey.textField.text) && ImportController.importLink(textKey.textField.text)) {
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||||
|
}else if (ImportController.extractConfigFromData(textKey.textField.text)) {
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,8 @@
|
|||||||
<file>Pages2/PageSettingsServerServices.qml</file>
|
<file>Pages2/PageSettingsServerServices.qml</file>
|
||||||
<file>Pages2/PageSettingsServersList.qml</file>
|
<file>Pages2/PageSettingsServersList.qml</file>
|
||||||
<file>Pages2/PageSettingsSplitTunneling.qml</file>
|
<file>Pages2/PageSettingsSplitTunneling.qml</file>
|
||||||
|
<file>Pages2/PageSettingsXRayAvailableConfigs.qml</file>
|
||||||
|
<file>Pages2/PageSettingsXRayServerInfo.qml</file>
|
||||||
<file>Pages2/PageSettingsNewsNotifications.qml</file>
|
<file>Pages2/PageSettingsNewsNotifications.qml</file>
|
||||||
<file>Pages2/PageSettingsNewsDetail.qml</file>
|
<file>Pages2/PageSettingsNewsDetail.qml</file>
|
||||||
<file>Pages2/PageProtocolAwgClientSettings.qml</file>
|
<file>Pages2/PageProtocolAwgClientSettings.qml</file>
|
||||||
|
|||||||
@@ -650,6 +650,9 @@ class OpenSSLConan(ConanFile):
|
|||||||
if self._use_nmake:
|
if self._use_nmake:
|
||||||
self.cpp_info.components["ssl"].libs = ["libssl"]
|
self.cpp_info.components["ssl"].libs = ["libssl"]
|
||||||
self.cpp_info.components["crypto"].libs = ["libcrypto"]
|
self.cpp_info.components["crypto"].libs = ["libcrypto"]
|
||||||
|
elif self.settings.os == "Android" and self.options.shared:
|
||||||
|
self.cpp_info.components["ssl"].libs = ["ssl_3"]
|
||||||
|
self.cpp_info.components["crypto"].libs = ["crypto_3"]
|
||||||
else:
|
else:
|
||||||
self.cpp_info.components["ssl"].libs = ["ssl"]
|
self.cpp_info.components["ssl"].libs = ["ssl"]
|
||||||
self.cpp_info.components["crypto"].libs = ["crypto"]
|
self.cpp_info.components["crypto"].libs = ["crypto"]
|
||||||
|
|||||||
Reference in New Issue
Block a user