mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-11-12 07:23:19 +09:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc02c8910b |
No files matched your search
@@ -38,6 +38,7 @@ set(HEADERS ${HEADERS}
|
||||
${CLIENT_ROOT_DIR}/core/installers/mtProxyInstaller.h
|
||||
${CLIENT_ROOT_DIR}/core/installers/telemtInstaller.h
|
||||
${CLIENT_ROOT_DIR}/core/installers/tProxyInstaller.h
|
||||
${CLIENT_ROOT_DIR}/core/installers/whatsAppProxyInstaller.h
|
||||
${CLIENT_ROOT_DIR}/core/controllers/appSplitTunnelingController.h
|
||||
${CLIENT_ROOT_DIR}/core/controllers/ipSplitTunnelingController.h
|
||||
${CLIENT_ROOT_DIR}/core/controllers/allowedDnsController.h
|
||||
@@ -128,6 +129,7 @@ set(SOURCES ${SOURCES}
|
||||
${CLIENT_ROOT_DIR}/core/installers/mtProxyInstaller.cpp
|
||||
${CLIENT_ROOT_DIR}/core/installers/telemtInstaller.cpp
|
||||
${CLIENT_ROOT_DIR}/core/installers/tProxyInstaller.cpp
|
||||
${CLIENT_ROOT_DIR}/core/installers/whatsAppProxyInstaller.cpp
|
||||
${CLIENT_ROOT_DIR}/core/controllers/appSplitTunnelingController.cpp
|
||||
${CLIENT_ROOT_DIR}/core/controllers/ipSplitTunnelingController.cpp
|
||||
${CLIENT_ROOT_DIR}/core/controllers/allowedDnsController.cpp
|
||||
|
||||
@@ -120,6 +120,9 @@ void CoreController::initModels()
|
||||
m_tProxyConfigModel = new TProxyConfigModel(this);
|
||||
setQmlContextProperty("TProxyConfigModel", m_tProxyConfigModel);
|
||||
|
||||
m_whatsAppProxyConfigModel = new WhatsAppProxyConfigModel(this);
|
||||
setQmlContextProperty("WhatsAppProxyConfigModel", m_whatsAppProxyConfigModel);
|
||||
|
||||
m_clientManagementModel = new ClientManagementModel(this);
|
||||
setQmlContextProperty("ClientManagementModel", m_clientManagementModel);
|
||||
|
||||
@@ -197,7 +200,7 @@ void CoreController::initControllers()
|
||||
m_ikev2ConfigModel,
|
||||
#endif
|
||||
m_sftpConfigModel, m_socks5ConfigModel, m_mtProxyConfigModel, m_telemtConfigModel,
|
||||
m_tProxyConfigModel,
|
||||
m_tProxyConfigModel, m_whatsAppProxyConfigModel,
|
||||
m_connectionController, this);
|
||||
setQmlContextProperty("InstallController", m_installUiController);
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
#include "ui/models/services/mtProxyConfigModel.h"
|
||||
#include "ui/models/services/telemtConfigModel.h"
|
||||
#include "ui/models/services/tProxyConfigModel.h"
|
||||
#include "ui/models/services/whatsAppProxyConfigModel.h"
|
||||
|
||||
#include "ui/models/ipSplitTunnelingModel.h"
|
||||
#include "ui/models/newsModel.h"
|
||||
@@ -246,6 +247,7 @@ private:
|
||||
MtProxyConfigModel* m_mtProxyConfigModel;
|
||||
TelemtConfigModel* m_telemtConfigModel;
|
||||
TProxyConfigModel* m_tProxyConfigModel;
|
||||
WhatsAppProxyConfigModel* m_whatsAppProxyConfigModel;
|
||||
|
||||
CoreSignalHandlers* m_signalHandlers;
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "core/installers/mtProxyInstaller.h"
|
||||
#include "core/installers/telemtInstaller.h"
|
||||
#include "core/installers/tProxyInstaller.h"
|
||||
#include "core/installers/whatsAppProxyInstaller.h"
|
||||
#include "core/installers/torInstaller.h"
|
||||
#include "core/installers/wireguardInstaller.h"
|
||||
#include "core/installers/xrayInstaller.h"
|
||||
@@ -145,6 +146,7 @@ namespace
|
||||
return container == DockerContainer::MtProxy
|
||||
|| container == DockerContainer::Telemt
|
||||
|| container == DockerContainer::TProxy
|
||||
|| container == DockerContainer::WhatsAppProxy
|
||||
|| container == DockerContainer::Xray;
|
||||
}
|
||||
|
||||
@@ -315,6 +317,8 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
|
||||
ServerCredentials credentials = adminConfig->credentials();
|
||||
SshSession sshSession;
|
||||
TProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||
} else if (container == DockerContainer::WhatsAppProxy) {
|
||||
WhatsAppProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||
}
|
||||
adminConfig->updateContainerConfig(container, newConfig);
|
||||
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||
@@ -372,6 +376,8 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
|
||||
TelemtInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||
} else if (container == DockerContainer::TProxy) {
|
||||
TProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||
} else if (container == DockerContainer::WhatsAppProxy) {
|
||||
WhatsAppProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||
}
|
||||
if (reinstallRequired) {
|
||||
if (container != DockerContainer::Xray) {
|
||||
@@ -729,6 +735,8 @@ ErrorCode InstallController::configureContainerWorker(const ServerCredentials &c
|
||||
TelemtInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, config);
|
||||
} else if (container == DockerContainer::TProxy) {
|
||||
TProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, config);
|
||||
} else if (container == DockerContainer::WhatsAppProxy) {
|
||||
WhatsAppProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, config);
|
||||
}
|
||||
|
||||
return ErrorCode::NoError;
|
||||
@@ -910,6 +918,14 @@ ErrorCode InstallController::isServerPortBusy(const ServerCredentials &credentia
|
||||
}
|
||||
}
|
||||
}
|
||||
if (container == DockerContainer::WhatsAppProxy) {
|
||||
if (const auto *whatsAppProxyConfig = config.getWhatsAppProxyProtocolConfig()) {
|
||||
const QString mediaPort = whatsAppProxyConfig->effectiveMediaPort();
|
||||
if (!fixedPorts.contains(mediaPort) && mediaPort != port) {
|
||||
fixedPorts.append(mediaPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
QString transportProto = config.protocolConfig.transportProto();
|
||||
if (transportProto.isEmpty()) {
|
||||
transportProto = ProtocolUtils::transportProtoToString(ProtocolUtils::defaultTransportProto(protocol), protocol);
|
||||
@@ -1085,6 +1101,14 @@ bool InstallController::isReinstallContainerRequired(DockerContainer container,
|
||||
}
|
||||
}
|
||||
|
||||
if (container == DockerContainer::WhatsAppProxy) {
|
||||
const auto *oldW = oldConfig.getWhatsAppProxyProtocolConfig();
|
||||
const auto *newW = newConfig.getWhatsAppProxyProtocolConfig();
|
||||
if (oldW && newW && !oldW->equalsDockerDeploymentSettings(*newW)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (container == DockerContainer::Socks5Proxy) {
|
||||
return true;
|
||||
}
|
||||
@@ -1122,7 +1146,7 @@ ErrorCode InstallController::installDockerWorker(const ServerCredentials &creden
|
||||
qDebug().noquote() << "InstallController::installDockerWorker" << stdOut;
|
||||
|
||||
if (container == DockerContainer::MtProxy || container == DockerContainer::Telemt
|
||||
|| container == DockerContainer::TProxy) {
|
||||
|| container == DockerContainer::TProxy || container == DockerContainer::WhatsAppProxy) {
|
||||
QString conntrackOut;
|
||||
auto cbConntrack = [&](const QString &data, libssh::Client &) {
|
||||
conntrackOut += data + "\n";
|
||||
@@ -1422,6 +1446,7 @@ QScopedPointer<InstallerBase> InstallController::createInstaller(DockerContainer
|
||||
case DockerContainer::MtProxy: return QScopedPointer<InstallerBase>(new MtProxyInstaller(this));
|
||||
case DockerContainer::Telemt: return QScopedPointer<InstallerBase>(new TelemtInstaller(this));
|
||||
case DockerContainer::TProxy: return QScopedPointer<InstallerBase>(new TProxyInstaller(this));
|
||||
case DockerContainer::WhatsAppProxy: return QScopedPointer<InstallerBase>(new WhatsAppProxyInstaller(this));
|
||||
default: return QScopedPointer<InstallerBase>(new InstallerBase(this));
|
||||
}
|
||||
}
|
||||
@@ -1456,6 +1481,14 @@ ErrorCode InstallController::installContainer(const ServerCredentials &credentia
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
}
|
||||
if (container == DockerContainer::WhatsAppProxy) {
|
||||
if (auto *whatsAppProxyConfig = config.getWhatsAppProxyProtocolConfig()) {
|
||||
if (!m_whatsAppProxyInstallMediaPort.isEmpty()) {
|
||||
whatsAppProxyConfig->mediaPort = m_whatsAppProxyInstallMediaPort;
|
||||
}
|
||||
}
|
||||
m_whatsAppProxyInstallMediaPort.clear();
|
||||
}
|
||||
return setupContainer(credentials, container, config, false);
|
||||
}
|
||||
|
||||
@@ -1465,6 +1498,11 @@ void InstallController::setTProxyInstallHints(const QString &hostname, const QSt
|
||||
m_tproxyInstallEmail = email;
|
||||
}
|
||||
|
||||
void InstallController::setWhatsAppProxyInstallHints(const QString &mediaPort)
|
||||
{
|
||||
m_whatsAppProxyInstallMediaPort = mediaPort;
|
||||
}
|
||||
|
||||
|
||||
bool InstallController::isUpdateDockerContainerRequired(DockerContainer container, const ContainerConfig &oldConfig, const ContainerConfig &newConfig)
|
||||
{
|
||||
@@ -1514,6 +1552,13 @@ bool InstallController::isUpdateDockerContainerRequired(DockerContainer containe
|
||||
return true;
|
||||
}
|
||||
return !oldP->equalsDockerDeploymentSettings(*newP);
|
||||
} else if (container == DockerContainer::WhatsAppProxy) {
|
||||
const auto *oldW = oldConfig.getWhatsAppProxyProtocolConfig();
|
||||
const auto *newW = newConfig.getWhatsAppProxyProtocolConfig();
|
||||
if (!oldW || !newW) {
|
||||
return true;
|
||||
}
|
||||
return !oldW->equalsDockerDeploymentSettings(*newW);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1945,6 +1990,11 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
||||
TProxyInstaller::applyDockerPublishedPorts(containerInfo, *tProxyConfig);
|
||||
}
|
||||
}
|
||||
if (container == DockerContainer::WhatsAppProxy) {
|
||||
if (auto *whatsAppProxyConfig = config.getWhatsAppProxyProtocolConfig()) {
|
||||
WhatsAppProxyInstaller::applyDockerPublishedPorts(containerInfo, *whatsAppProxyConfig);
|
||||
}
|
||||
}
|
||||
ErrorCode extractError = installer->extractConfigFromContainer(container, credentials, &sshSession, config);
|
||||
|
||||
if (extractError != ErrorCode::NoError && extractError != ErrorCode::ServerContainerMissingError) {
|
||||
@@ -1975,6 +2025,11 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
||||
TProxyInstaller::applyDockerPublishedPorts(containerInfo, *tProxyConfig);
|
||||
}
|
||||
}
|
||||
if (container == DockerContainer::WhatsAppProxy) {
|
||||
if (auto *whatsAppProxyConfig = config.getWhatsAppProxyProtocolConfig()) {
|
||||
WhatsAppProxyInstaller::applyDockerPublishedPorts(containerInfo, *whatsAppProxyConfig);
|
||||
}
|
||||
}
|
||||
ErrorCode extractError = installer->extractConfigFromContainer(container, credentials, &sshSession, config);
|
||||
|
||||
if (extractError != ErrorCode::NoError && extractError != ErrorCode::ServerContainerMissingError) {
|
||||
@@ -1991,7 +2046,7 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
||||
ErrorCode InstallController::setDockerContainerEnabledState(const QString &serverId, DockerContainer container, bool enabled)
|
||||
{
|
||||
if (container != DockerContainer::MtProxy && container != DockerContainer::Telemt
|
||||
&& container != DockerContainer::TProxy) {
|
||||
&& container != DockerContainer::TProxy && container != DockerContainer::WhatsAppProxy) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||
@@ -2021,6 +2076,9 @@ ErrorCode InstallController::setDockerContainerEnabledState(const QString &serve
|
||||
} else if (auto *tProxyConfig = currentConfig.getTProxyProtocolConfig()) {
|
||||
tProxyConfig->isEnabled = enabled;
|
||||
persist = true;
|
||||
} else if (auto *whatsAppProxyConfig = currentConfig.getWhatsAppProxyProtocolConfig()) {
|
||||
whatsAppProxyConfig->isEnabled = enabled;
|
||||
persist = true;
|
||||
}
|
||||
if (persist) {
|
||||
adminConfig->updateContainerConfig(container, currentConfig);
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
QString fetchDockerContainerSecret(const QString &serverId, DockerContainer container);
|
||||
|
||||
void setTProxyInstallHints(const QString &hostname, const QString &email);
|
||||
void setWhatsAppProxyInstallHints(const QString &mediaPort);
|
||||
|
||||
ContainerConfig generateConfig(DockerContainer container, int port, TransportProto transportProto);
|
||||
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, ContainerConfig> &installedContainers, SshSession &sshSession);
|
||||
@@ -136,6 +137,7 @@ private:
|
||||
bool m_cancelInstallation = false;
|
||||
QString m_tproxyInstallHostname;
|
||||
QString m_tproxyInstallEmail;
|
||||
QString m_whatsAppProxyInstallMediaPort;
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
QList<QSharedPointer<QProcess>> m_sftpMountProcesses;
|
||||
|
||||
@@ -125,6 +125,13 @@ ContainerConfig InstallerBase::createBaseConfig(DockerContainer container, int p
|
||||
config.protocolConfig = tProxyConfig;
|
||||
break;
|
||||
}
|
||||
case Proto::WhatsAppProxy: {
|
||||
WhatsAppProxyProtocolConfig whatsAppProxyConfig;
|
||||
whatsAppProxyConfig.port = portStr.isEmpty() ? QString(protocols::whatsAppProxy::defaultPort) : portStr;
|
||||
whatsAppProxyConfig.mediaPort = QString(protocols::whatsAppProxy::defaultMediaPort);
|
||||
config.protocolConfig = whatsAppProxyConfig;
|
||||
break;
|
||||
}
|
||||
case Proto::Ikev2: {
|
||||
Ikev2ProtocolConfig ikev2Config;
|
||||
config.protocolConfig = ikev2Config;
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#include "whatsAppProxyInstaller.h"
|
||||
|
||||
#include "core/models/containerConfig.h"
|
||||
#include "core/utils/containerEnum.h"
|
||||
#include "core/utils/selfhosted/sshSession.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonParseError>
|
||||
#include <QRegularExpression>
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr QLatin1String kClientJsonPath("/data/amnezia-whatsappproxy-client.json");
|
||||
constexpr QLatin1String kClientJsonUploadPath("data/amnezia-whatsappproxy-client.json");
|
||||
}
|
||||
|
||||
void WhatsAppProxyInstaller::applyDockerPublishedPorts(const QString &dockerPsPortsLine,
|
||||
WhatsAppProxyProtocolConfig &config)
|
||||
{
|
||||
static const QRegularExpression chatRe(QStringLiteral(":(\\d+)->443/tcp"));
|
||||
static const QRegularExpression mediaRe(QStringLiteral(":(\\d+)->587/tcp"));
|
||||
const QRegularExpressionMatch chatMatch = chatRe.match(dockerPsPortsLine);
|
||||
const QRegularExpressionMatch mediaMatch = mediaRe.match(dockerPsPortsLine);
|
||||
if (chatMatch.hasMatch()) {
|
||||
config.port = chatMatch.captured(1);
|
||||
}
|
||||
if (mediaMatch.hasMatch()) {
|
||||
config.mediaPort = mediaMatch.captured(1);
|
||||
}
|
||||
}
|
||||
|
||||
WhatsAppProxyInstaller::WhatsAppProxyInstaller(QObject *parent) : InstallerBase(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorCode WhatsAppProxyInstaller::extractConfigFromContainer(DockerContainer container,
|
||||
const ServerCredentials &credentials,
|
||||
SshSession *sshSession, ContainerConfig &config)
|
||||
{
|
||||
if (container != DockerContainer::WhatsAppProxy || !sshSession) {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
WhatsAppProxyProtocolConfig *wc = config.getWhatsAppProxyProtocolConfig();
|
||||
if (!wc) {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
ErrorCode jsonErr = ErrorCode::NoError;
|
||||
const QByteArray jsonRaw =
|
||||
sshSession->getTextFileFromContainer(container, credentials, QString(kClientJsonPath), jsonErr);
|
||||
if (jsonErr != ErrorCode::NoError || jsonRaw.trimmed().isEmpty()) {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
QJsonParseError parseError;
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(jsonRaw.trimmed(), &parseError);
|
||||
if (parseError.error != QJsonParseError::NoError || !doc.isObject()) {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
const WhatsAppProxyProtocolConfig snapshot = WhatsAppProxyProtocolConfig::fromJson(doc.object());
|
||||
wc->publicHost = snapshot.publicHost;
|
||||
wc->isEnabled = snapshot.isEnabled;
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
void WhatsAppProxyInstaller::uploadClientSettingsSnapshot(SshSession &sshSession, const ServerCredentials &credentials,
|
||||
DockerContainer container, const ContainerConfig &config)
|
||||
{
|
||||
const WhatsAppProxyProtocolConfig *wc = config.getWhatsAppProxyProtocolConfig();
|
||||
if (!wc) {
|
||||
return;
|
||||
}
|
||||
const QByteArray payload = QJsonDocument(wc->toJson()).toJson(QJsonDocument::Compact);
|
||||
const ErrorCode err = sshSession.uploadTextFileToContainer(container, credentials, QString::fromUtf8(payload),
|
||||
QString(kClientJsonUploadPath));
|
||||
if (err != ErrorCode::NoError) {
|
||||
qWarning() << "WhatsAppProxyInstaller::uploadClientSettingsSnapshot failed" << err;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef WHATSAPPPROXYINSTALLER_H
|
||||
#define WHATSAPPPROXYINSTALLER_H
|
||||
|
||||
#include "installerBase.h"
|
||||
|
||||
#include "core/models/protocols/whatsAppProxyProtocolConfig.h"
|
||||
|
||||
class WhatsAppProxyInstaller : public InstallerBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WhatsAppProxyInstaller(QObject *parent = nullptr);
|
||||
|
||||
amnezia::ErrorCode extractConfigFromContainer(amnezia::DockerContainer container,
|
||||
const amnezia::ServerCredentials &credentials, SshSession *sshSession,
|
||||
amnezia::ContainerConfig &config) override;
|
||||
|
||||
static void applyDockerPublishedPorts(const QString &dockerPsPortsLine, amnezia::WhatsAppProxyProtocolConfig &config);
|
||||
|
||||
static void uploadClientSettingsSnapshot(SshSession &sshSession, const amnezia::ServerCredentials &credentials,
|
||||
amnezia::DockerContainer container, const amnezia::ContainerConfig &config);
|
||||
};
|
||||
|
||||
#endif // WHATSAPPPROXYINSTALLER_H
|
||||
@@ -143,6 +143,16 @@ const TProxyProtocolConfig* ContainerConfig::getTProxyProtocolConfig() const
|
||||
return protocolConfig.as<TProxyProtocolConfig>();
|
||||
}
|
||||
|
||||
WhatsAppProxyProtocolConfig* ContainerConfig::getWhatsAppProxyProtocolConfig()
|
||||
{
|
||||
return protocolConfig.as<WhatsAppProxyProtocolConfig>();
|
||||
}
|
||||
|
||||
const WhatsAppProxyProtocolConfig* ContainerConfig::getWhatsAppProxyProtocolConfig() const
|
||||
{
|
||||
return protocolConfig.as<WhatsAppProxyProtocolConfig>();
|
||||
}
|
||||
|
||||
Ikev2ProtocolConfig* ContainerConfig::getIkev2ProtocolConfig()
|
||||
{
|
||||
return protocolConfig.as<Ikev2ProtocolConfig>();
|
||||
|
||||
@@ -66,6 +66,9 @@ struct ContainerConfig {
|
||||
TProxyProtocolConfig* getTProxyProtocolConfig();
|
||||
const TProxyProtocolConfig* getTProxyProtocolConfig() const;
|
||||
|
||||
WhatsAppProxyProtocolConfig* getWhatsAppProxyProtocolConfig();
|
||||
const WhatsAppProxyProtocolConfig* getWhatsAppProxyProtocolConfig() const;
|
||||
|
||||
Ikev2ProtocolConfig* getIkev2ProtocolConfig();
|
||||
const Ikev2ProtocolConfig* getIkev2ProtocolConfig() const;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "core/models/protocols/mtProxyProtocolConfig.h"
|
||||
#include "core/models/protocols/telemtProtocolConfig.h"
|
||||
#include "core/models/protocols/tProxyProtocolConfig.h"
|
||||
#include "core/models/protocols/whatsAppProxyProtocolConfig.h"
|
||||
|
||||
namespace amnezia
|
||||
{
|
||||
@@ -47,6 +48,8 @@ Proto ProtocolConfig::type() const
|
||||
return Proto::Telemt;
|
||||
} else if constexpr (std::is_same_v<T, TProxyProtocolConfig>) {
|
||||
return Proto::TProxy;
|
||||
} else if constexpr (std::is_same_v<T, WhatsAppProxyProtocolConfig>) {
|
||||
return Proto::WhatsAppProxy;
|
||||
}
|
||||
return Proto::Unknown;
|
||||
}, data);
|
||||
@@ -80,6 +83,8 @@ QString ProtocolConfig::port() const
|
||||
return arg.port.isEmpty() ? QString(protocols::telemt::defaultPort) : arg.port;
|
||||
} else if constexpr (std::is_same_v<T, TProxyProtocolConfig>) {
|
||||
return arg.port.isEmpty() ? QString(protocols::tProxy::defaultPort) : arg.port;
|
||||
} else if constexpr (std::is_same_v<T, WhatsAppProxyProtocolConfig>) {
|
||||
return arg.effectivePort();
|
||||
}
|
||||
return QString();
|
||||
}, data);
|
||||
@@ -109,6 +114,8 @@ QString ProtocolConfig::transportProto() const
|
||||
return QStringLiteral("tcp");
|
||||
} else if constexpr (std::is_same_v<T, TProxyProtocolConfig>) {
|
||||
return QStringLiteral("tcp");
|
||||
} else if constexpr (std::is_same_v<T, WhatsAppProxyProtocolConfig>) {
|
||||
return QStringLiteral("tcp");
|
||||
}
|
||||
return QString();
|
||||
}, data);
|
||||
@@ -326,6 +333,8 @@ ProtocolConfig ProtocolConfig::fromJson(const QJsonObject& json, Proto type)
|
||||
return ProtocolConfig{TelemtProtocolConfig::fromJson(json)};
|
||||
case Proto::TProxy:
|
||||
return ProtocolConfig{TProxyProtocolConfig::fromJson(json)};
|
||||
case Proto::WhatsAppProxy:
|
||||
return ProtocolConfig{WhatsAppProxyProtocolConfig::fromJson(json)};
|
||||
default:
|
||||
return ProtocolConfig{AwgProtocolConfig{}};
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "core/models/protocols/mtProxyProtocolConfig.h"
|
||||
#include "core/models/protocols/telemtProtocolConfig.h"
|
||||
#include "core/models/protocols/tProxyProtocolConfig.h"
|
||||
#include "core/models/protocols/whatsAppProxyProtocolConfig.h"
|
||||
|
||||
namespace amnezia
|
||||
{
|
||||
@@ -42,6 +43,7 @@ struct ProtocolConfig {
|
||||
MtProxyProtocolConfig,
|
||||
TelemtProtocolConfig,
|
||||
TProxyProtocolConfig,
|
||||
WhatsAppProxyProtocolConfig,
|
||||
Ikev2ProtocolConfig,
|
||||
TorProtocolConfig,
|
||||
DnsProtocolConfig
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "whatsAppProxyProtocolConfig.h"
|
||||
|
||||
#include "core/utils/constants/configKeys.h"
|
||||
#include "core/utils/constants/protocolConstants.h"
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
QString WhatsAppProxyProtocolConfig::effectivePort() const
|
||||
{
|
||||
return port.isEmpty() ? QString(protocols::whatsAppProxy::defaultPort) : port;
|
||||
}
|
||||
|
||||
QString WhatsAppProxyProtocolConfig::effectiveMediaPort() const
|
||||
{
|
||||
return mediaPort.isEmpty() ? QString(protocols::whatsAppProxy::defaultMediaPort) : mediaPort;
|
||||
}
|
||||
|
||||
QJsonObject WhatsAppProxyProtocolConfig::toJson() const
|
||||
{
|
||||
QJsonObject obj;
|
||||
if (!port.isEmpty()) {
|
||||
obj[QString(configKey::port)] = port;
|
||||
}
|
||||
if (!mediaPort.isEmpty()) {
|
||||
obj[protocols::whatsAppProxy::mediaPortKey] = mediaPort;
|
||||
}
|
||||
if (!publicHost.isEmpty()) {
|
||||
obj[protocols::whatsAppProxy::publicHostKey] = publicHost;
|
||||
}
|
||||
obj[protocols::whatsAppProxy::isEnabledKey] = isEnabled;
|
||||
return obj;
|
||||
}
|
||||
|
||||
WhatsAppProxyProtocolConfig WhatsAppProxyProtocolConfig::fromJson(const QJsonObject &json)
|
||||
{
|
||||
WhatsAppProxyProtocolConfig c;
|
||||
c.port = json.value(QString(configKey::port)).toString();
|
||||
c.mediaPort = json.value(protocols::whatsAppProxy::mediaPortKey).toString();
|
||||
c.publicHost = json.value(protocols::whatsAppProxy::publicHostKey).toString();
|
||||
c.isEnabled = json.value(protocols::whatsAppProxy::isEnabledKey).toBool(true);
|
||||
return c;
|
||||
}
|
||||
|
||||
bool WhatsAppProxyProtocolConfig::equalsDockerDeploymentSettings(const WhatsAppProxyProtocolConfig &other) const
|
||||
{
|
||||
return effectivePort() == other.effectivePort() && effectiveMediaPort() == other.effectiveMediaPort();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef WHATSAPPPROXYPROTOCOLCONFIG_H
|
||||
#define WHATSAPPPROXYPROTOCOLCONFIG_H
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QString>
|
||||
|
||||
namespace amnezia
|
||||
{
|
||||
|
||||
struct WhatsAppProxyProtocolConfig
|
||||
{
|
||||
QString port;
|
||||
QString mediaPort;
|
||||
QString publicHost;
|
||||
bool isEnabled = true;
|
||||
|
||||
QString effectivePort() const;
|
||||
QString effectiveMediaPort() const;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
static WhatsAppProxyProtocolConfig fromJson(const QJsonObject &json);
|
||||
bool equalsDockerDeploymentSettings(const WhatsAppProxyProtocolConfig &other) const;
|
||||
};
|
||||
|
||||
} // namespace amnezia
|
||||
|
||||
#endif // WHATSAPPPROXYPROTOCOLCONFIG_H
|
||||
@@ -72,6 +72,7 @@ QMap<Proto, QString> ProtocolUtils::protocolHumanNames()
|
||||
{ Proto::MtProxy, QObject::tr("MTProxy (Telegram)") },
|
||||
{ Proto::Telemt, QObject::tr("Telemt (Telegram)") },
|
||||
{ Proto::TProxy, QObject::tr("TProxy (Telegram WEB)") },
|
||||
{ Proto::WhatsAppProxy, QObject::tr("WhatsApp proxy") },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -99,6 +100,7 @@ ServiceType ProtocolUtils::protocolService(Proto p)
|
||||
case Proto::MtProxy: return ServiceType::Other;
|
||||
case Proto::Telemt: return ServiceType::Other;
|
||||
case Proto::TProxy: return ServiceType::Other;
|
||||
case Proto::WhatsAppProxy: return ServiceType::Other;
|
||||
default: return ServiceType::Other;
|
||||
}
|
||||
}
|
||||
@@ -114,6 +116,7 @@ int ProtocolUtils::getPortForInstall(Proto p)
|
||||
case MtProxy:
|
||||
case Telemt:
|
||||
case TProxy:
|
||||
case WhatsAppProxy:
|
||||
default:
|
||||
return defaultPort(p);
|
||||
}
|
||||
@@ -136,6 +139,7 @@ int ProtocolUtils::defaultPort(Proto p)
|
||||
case Proto::MtProxy: return QString(protocols::mtProxy::defaultPort).toInt();
|
||||
case Proto::Telemt: return QString(protocols::telemt::defaultPort).toInt();
|
||||
case Proto::TProxy: return QString(protocols::tProxy::defaultPort).toInt();
|
||||
case Proto::WhatsAppProxy: return QString(protocols::whatsAppProxy::defaultPort).toInt();
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
@@ -157,6 +161,7 @@ bool ProtocolUtils::defaultPortChangeable(Proto p)
|
||||
case Proto::MtProxy: return true;
|
||||
case Proto::Telemt: return true;
|
||||
case Proto::TProxy: return true;
|
||||
case Proto::WhatsAppProxy: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
@@ -180,6 +185,7 @@ TransportProto ProtocolUtils::defaultTransportProto(Proto p)
|
||||
case Proto::MtProxy: return TransportProto::Tcp;
|
||||
case Proto::Telemt: return TransportProto::Tcp;
|
||||
case Proto::TProxy: return TransportProto::Tcp;
|
||||
case Proto::WhatsAppProxy: return TransportProto::Tcp;
|
||||
default: return TransportProto::Udp;
|
||||
}
|
||||
}
|
||||
@@ -202,6 +208,7 @@ bool ProtocolUtils::defaultTransportProtoChangeable(Proto p)
|
||||
case Proto::MtProxy: return false;
|
||||
case Proto::Telemt: return false;
|
||||
case Proto::TProxy: return false;
|
||||
case Proto::WhatsAppProxy: return false;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ namespace amnezia
|
||||
constexpr QLatin1String mtproxy("mtproxy");
|
||||
constexpr QLatin1String telemt("telemt");
|
||||
constexpr QLatin1String tproxy("tproxy");
|
||||
constexpr QLatin1String whatsappproxy("whatsappproxy");
|
||||
|
||||
constexpr QLatin1String splitTunnelSites("splitTunnelSites");
|
||||
constexpr QLatin1String splitTunnelType("splitTunnelType");
|
||||
|
||||
@@ -413,6 +413,16 @@ namespace amnezia
|
||||
constexpr int maxWorkers = 32;
|
||||
}
|
||||
|
||||
namespace whatsAppProxy
|
||||
{
|
||||
constexpr char mediaPortKey[] = "whatsapp_proxy_media_port";
|
||||
constexpr char publicHostKey[] = "whatsapp_proxy_public_host";
|
||||
constexpr char isEnabledKey[] = "whatsapp_proxy_is_enabled";
|
||||
|
||||
constexpr char defaultPort[] = "443";
|
||||
constexpr char defaultMediaPort[] = "587";
|
||||
}
|
||||
|
||||
} // namespace protocols
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace amnezia
|
||||
MtProxy,
|
||||
Telemt,
|
||||
TProxy,
|
||||
WhatsAppProxy,
|
||||
};
|
||||
Q_ENUM_NS(DockerContainer)
|
||||
} // namespace ContainerEnumNS
|
||||
|
||||
@@ -80,6 +80,7 @@ QMap<DockerContainer, QString> ContainerUtils::containerHumanNames()
|
||||
{ DockerContainer::MtProxy, QObject::tr("MTProxy (Telegram)") },
|
||||
{ DockerContainer::Telemt, QObject::tr("Telemt (Telegram)") },
|
||||
{ DockerContainer::TProxy, QObject::tr("TProxy (Telegram WEB)") },
|
||||
{ DockerContainer::WhatsAppProxy, QObject::tr("WhatsApp proxy") },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -120,6 +121,8 @@ QMap<DockerContainer, QString> ContainerUtils::containerDescriptions()
|
||||
QObject::tr("Telegram MTProto proxy (Telemt, Rust)") },
|
||||
{ DockerContainer::TProxy,
|
||||
QObject::tr("Telegram WEB proxy (tproxy-server)") },
|
||||
{ DockerContainer::WhatsAppProxy,
|
||||
QObject::tr("WhatsApp chat and media proxy") },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -203,6 +206,11 @@ QMap<DockerContainer, QString> ContainerUtils::containerDetailedDescriptions()
|
||||
QObject::tr("Telegram WEB proxy. Clients connect over HTTPS to a hostname; "
|
||||
"the server relays traffic to official MTProxy. Requires a domain, "
|
||||
"ports 80 and 443, and a WEB-capable Telegram app.") },
|
||||
{ DockerContainer::WhatsAppProxy,
|
||||
QObject::tr("WhatsApp proxy based on the official Meta implementation. "
|
||||
"Relays chat traffic through the chat port and media through the media port. "
|
||||
"Users enter the server address and both ports in WhatsApp settings. "
|
||||
"Calls are not proxied.") },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -235,6 +243,7 @@ Proto ContainerUtils::defaultProtocol(DockerContainer c)
|
||||
case DockerContainer::MtProxy: return Proto::MtProxy;
|
||||
case DockerContainer::Telemt: return Proto::Telemt;
|
||||
case DockerContainer::TProxy: return Proto::TProxy;
|
||||
case DockerContainer::WhatsAppProxy: return Proto::WhatsAppProxy;
|
||||
default: return Proto::Unknown;
|
||||
}
|
||||
}
|
||||
@@ -265,6 +274,7 @@ bool ContainerUtils::isSupportedByCurrentPlatform(DockerContainer c)
|
||||
case DockerContainer::MtProxy: return true;
|
||||
case DockerContainer::Telemt: return true;
|
||||
case DockerContainer::TProxy: return true;
|
||||
case DockerContainer::WhatsAppProxy: return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -283,6 +293,7 @@ bool ContainerUtils::isSupportedByCurrentPlatform(DockerContainer c)
|
||||
case DockerContainer::MtProxy: return true;
|
||||
case DockerContainer::Telemt: return true;
|
||||
case DockerContainer::TProxy: return true;
|
||||
case DockerContainer::WhatsAppProxy: return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -304,6 +315,7 @@ bool ContainerUtils::isSupportedByCurrentPlatform(DockerContainer c)
|
||||
case DockerContainer::MtProxy: return true;
|
||||
case DockerContainer::Telemt: return true;
|
||||
case DockerContainer::TProxy: return true;
|
||||
case DockerContainer::WhatsAppProxy: return true;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
@@ -373,6 +385,7 @@ bool ContainerUtils::isShareable(DockerContainer container)
|
||||
case DockerContainer::MtProxy: return false;
|
||||
case DockerContainer::Telemt: return false;
|
||||
case DockerContainer::TProxy: return false;
|
||||
case DockerContainer::WhatsAppProxy: return false;
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
@@ -409,6 +422,7 @@ int ContainerUtils::installPageOrder(DockerContainer container)
|
||||
case DockerContainer::MtProxy:
|
||||
case DockerContainer::Telemt:
|
||||
case DockerContainer::TProxy:
|
||||
case DockerContainer::WhatsAppProxy:
|
||||
return 20;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace amnezia
|
||||
MtProxy,
|
||||
Telemt,
|
||||
TProxy,
|
||||
WhatsAppProxy,
|
||||
};
|
||||
Q_ENUM_NS(Proto)
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "core/models/protocols/mtProxyProtocolConfig.h"
|
||||
#include "core/models/protocols/telemtProtocolConfig.h"
|
||||
#include "core/models/protocols/tProxyProtocolConfig.h"
|
||||
#include "core/models/protocols/whatsAppProxyProtocolConfig.h"
|
||||
|
||||
using namespace amnezia;
|
||||
using namespace ProtocolUtils;
|
||||
@@ -43,6 +44,7 @@ QString amnezia::scriptFolder(amnezia::DockerContainer container)
|
||||
case DockerContainer::MtProxy: return QLatin1String("mtproxy");
|
||||
case DockerContainer::Telemt: return QLatin1String("telemt");
|
||||
case DockerContainer::TProxy: return QLatin1String("tproxy");
|
||||
case DockerContainer::WhatsAppProxy: return QLatin1String("whatsapp_proxy");
|
||||
default: return QString();
|
||||
}
|
||||
}
|
||||
@@ -428,6 +430,18 @@ amnezia::ScriptVars amnezia::genTProxyVars(const ContainerConfig &containerConfi
|
||||
return vars;
|
||||
}
|
||||
|
||||
amnezia::ScriptVars amnezia::genWhatsAppProxyVars(const ContainerConfig &containerConfig)
|
||||
{
|
||||
ScriptVars vars;
|
||||
|
||||
if (auto *whatsAppProxyConfig = containerConfig.getWhatsAppProxyProtocolConfig()) {
|
||||
vars.append({ { "$WHATSAPP_PROXY_CHAT_PORT", whatsAppProxyConfig->effectivePort() } });
|
||||
vars.append({ { "$WHATSAPP_PROXY_MEDIA_PORT", whatsAppProxyConfig->effectiveMediaPort() } });
|
||||
}
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
amnezia::ScriptVars amnezia::genProtocolVarsForContainer(DockerContainer container, const ContainerConfig &containerConfig)
|
||||
{
|
||||
ScriptVars vars;
|
||||
@@ -461,6 +475,9 @@ amnezia::ScriptVars amnezia::genProtocolVarsForContainer(DockerContainer contain
|
||||
case Proto::TProxy:
|
||||
vars.append(genTProxyVars(containerConfig));
|
||||
break;
|
||||
case Proto::WhatsAppProxy:
|
||||
vars.append(genWhatsAppProxyVars(containerConfig));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ ScriptVars genSocks5ProxyVars(const ContainerConfig &containerConfig);
|
||||
ScriptVars genMtProxyVars(const ContainerConfig &containerConfig);
|
||||
ScriptVars genTelemtVars(const ContainerConfig &containerConfig);
|
||||
ScriptVars genTProxyVars(const ContainerConfig &containerConfig);
|
||||
ScriptVars genWhatsAppProxyVars(const ContainerConfig &containerConfig);
|
||||
|
||||
ScriptVars genProtocolVarsForContainer(DockerContainer container, const ContainerConfig &containerConfig);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,8 @@ ErrorCode SshSession::runContainerScript(const ServerCredentials &credentials, D
|
||||
return e;
|
||||
|
||||
const bool useSh = container == DockerContainer::Socks5Proxy || container == DockerContainer::MtProxy
|
||||
|| container == DockerContainer::Telemt || container == DockerContainer::TProxy;
|
||||
|| container == DockerContainer::Telemt || container == DockerContainer::TProxy
|
||||
|| container == DockerContainer::WhatsAppProxy;
|
||||
QString runner = QString("sudo docker exec -i $CONTAINER_NAME %2 %1 ").arg(fileName, useSh ? "sh" : "bash");
|
||||
e = runScript(credentials, replaceVars(runner, amnezia::genBaseVars(credentials, container, QString(), QString())), cbReadStdOut, cbReadStdErr);
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
<file>tproxy/Dockerfile</file>
|
||||
<file>tproxy/run_container.sh</file>
|
||||
<file>tproxy/start.sh</file>
|
||||
<file>whatsapp_proxy/configure_container.sh</file>
|
||||
<file>whatsapp_proxy/Dockerfile</file>
|
||||
<file>whatsapp_proxy/run_container.sh</file>
|
||||
<file>whatsapp_proxy/start.sh</file>
|
||||
<file>openvpn/configure_container.sh</file>
|
||||
<file>openvpn/Dockerfile</file>
|
||||
<file>openvpn/run_container.sh</file>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
FROM haproxy:lts-alpine
|
||||
|
||||
USER root
|
||||
RUN apk add --no-cache openssl
|
||||
|
||||
RUN mkdir -p /opt/amnezia /data
|
||||
RUN printf '#!/bin/sh\ntail -f /dev/null\n' > /opt/amnezia/start.sh && \
|
||||
chmod a+x /opt/amnezia/start.sh
|
||||
|
||||
VOLUME /data
|
||||
ENTRYPOINT ["/bin/sh", "/opt/amnezia/start.sh"]
|
||||
CMD [""]
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
|
||||
mkdir -p /data
|
||||
|
||||
if [ ! -s /data/proxy.pem ]; then
|
||||
openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
|
||||
-subj "/CN=$(openssl rand -hex 8).net" \
|
||||
-keyout /data/proxy.key -out /data/proxy.crt 2>/dev/null
|
||||
cat /data/proxy.key /data/proxy.crt > /data/proxy.pem
|
||||
rm -f /data/proxy.key /data/proxy.crt
|
||||
chmod 600 /data/proxy.pem
|
||||
fi
|
||||
|
||||
cat > /data/haproxy.cfg << EOF_CFG
|
||||
global
|
||||
tune.bufsize 4096
|
||||
maxconn 27500
|
||||
spread-checks 5
|
||||
ssl-server-verify none
|
||||
|
||||
defaults
|
||||
mode tcp
|
||||
timeout client-fin 1s
|
||||
timeout server-fin 1s
|
||||
timeout connect 5s
|
||||
timeout client 200s
|
||||
timeout server 200s
|
||||
default-server inter 10s fastinter 1s downinter 3s error-limit 50
|
||||
|
||||
frontend chat
|
||||
bind ipv4@*:443 ssl crt /data/proxy.pem
|
||||
default_backend wa_chat
|
||||
|
||||
frontend media
|
||||
bind ipv4@*:587
|
||||
default_backend wa_media
|
||||
|
||||
backend wa_chat
|
||||
default-server check inter 60000 observe layer4 send-proxy
|
||||
server g_whatsapp_net_5222 g.whatsapp.net:5222
|
||||
|
||||
backend wa_media
|
||||
default-server check inter 60000 observe layer4
|
||||
server whatsapp_net_443 whatsapp.net:443
|
||||
EOF_CFG
|
||||
|
||||
echo "[*] WhatsApp proxy configuration"
|
||||
echo "[*] Chat port: $WHATSAPP_PROXY_CHAT_PORT"
|
||||
echo "[*] Media port: $WHATSAPP_PROXY_MEDIA_PORT"
|
||||
@@ -0,0 +1,8 @@
|
||||
sudo docker run -d \
|
||||
--log-driver none \
|
||||
--restart always \
|
||||
-p $WHATSAPP_PROXY_CHAT_PORT:443/tcp \
|
||||
-p $WHATSAPP_PROXY_MEDIA_PORT:587/tcp \
|
||||
-v amnezia-whatsappproxy-data:/data \
|
||||
--name $CONTAINER_NAME \
|
||||
$CONTAINER_NAME
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -f /data/haproxy.cfg ] || [ ! -s /data/proxy.pem ]; then
|
||||
echo "ERROR: /data/haproxy.cfg not found — run configure_container first"
|
||||
tail -f /dev/null
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec haproxy -W -db -f /data/haproxy.cfg
|
||||
@@ -55,6 +55,7 @@ InstallUiController::InstallUiController(InstallController *installController,
|
||||
MtProxyConfigModel* mtConfigModel,
|
||||
TelemtConfigModel *telemtConfigModel,
|
||||
TProxyConfigModel *tProxyConfigModel,
|
||||
WhatsAppProxyConfigModel *whatsAppProxyConfigModel,
|
||||
ConnectionController *connectionController,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
@@ -76,6 +77,7 @@ InstallUiController::InstallUiController(InstallController *installController,
|
||||
m_mtProxyConfigModel(mtConfigModel),
|
||||
m_telemtConfigModel(telemtConfigModel),
|
||||
m_tProxyConfigModel(tProxyConfigModel),
|
||||
m_whatsAppProxyConfigModel(whatsAppProxyConfigModel),
|
||||
m_connectionController(connectionController)
|
||||
{
|
||||
connect(m_installController, &InstallController::configValidated, this, &InstallUiController::configValidated);
|
||||
@@ -92,6 +94,9 @@ void InstallUiController::install(DockerContainer container, int port, Transport
|
||||
m_installController->setTProxyInstallHints(m_tProxyConfigModel->getHostname(),
|
||||
m_tProxyConfigModel->getAcmeEmail());
|
||||
}
|
||||
if (container == DockerContainer::WhatsAppProxy && m_whatsAppProxyConfigModel) {
|
||||
m_installController->setWhatsAppProxyInstallHints(m_whatsAppProxyConfigModel->getMediaPort());
|
||||
}
|
||||
|
||||
const bool isNewServer = serverId.isEmpty();
|
||||
|
||||
@@ -269,6 +274,10 @@ bool InstallUiController::buildContainerConfigFromModel(int containerIndex, int
|
||||
containerConfig.protocolConfig = m_tProxyConfigModel->getProtocolConfig();
|
||||
break;
|
||||
}
|
||||
case Proto::WhatsAppProxy: {
|
||||
containerConfig.protocolConfig = m_whatsAppProxyConfigModel->getProtocolConfig();
|
||||
break;
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
case Proto::Ikev2: {
|
||||
containerConfig.protocolConfig = m_ikev2ConfigModel->getProtocolConfig();
|
||||
@@ -325,7 +334,7 @@ void InstallUiController::updateServerConfig(const QString &serverId, int contai
|
||||
ContainerConfig oldContainerConfig = m_serversController->getContainerConfig(serverId, container);
|
||||
|
||||
const bool asyncUpdate = container == DockerContainer::MtProxy || container == DockerContainer::Telemt
|
||||
|| container == DockerContainer::TProxy
|
||||
|| container == DockerContainer::TProxy || container == DockerContainer::WhatsAppProxy
|
||||
|| container == DockerContainer::Xray || container == DockerContainer::SSXray;
|
||||
|
||||
|
||||
@@ -336,7 +345,7 @@ void InstallUiController::updateServerConfig(const QString &serverId, int contai
|
||||
m_serverConfigUpdateInProgress = true;
|
||||
|
||||
const bool emitBusy = container == DockerContainer::MtProxy || container == DockerContainer::Telemt
|
||||
|| container == DockerContainer::TProxy;
|
||||
|| container == DockerContainer::TProxy || container == DockerContainer::WhatsAppProxy;
|
||||
if (emitBusy)
|
||||
emit serverIsBusy(true);
|
||||
auto *watcher = new QFutureWatcher<ErrorCode>(this);
|
||||
@@ -391,7 +400,7 @@ void InstallUiController::setContainerEnabled(const QString &serverId, int conta
|
||||
{
|
||||
const DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||
if (container != DockerContainer::MtProxy && container != DockerContainer::Telemt
|
||||
&& container != DockerContainer::TProxy) {
|
||||
&& container != DockerContainer::TProxy && container != DockerContainer::WhatsAppProxy) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -423,7 +432,7 @@ void InstallUiController::refreshContainerStatus(const QString &serverId, int co
|
||||
{
|
||||
const DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||
if (container != DockerContainer::MtProxy && container != DockerContainer::Telemt
|
||||
&& container != DockerContainer::TProxy) {
|
||||
&& container != DockerContainer::TProxy && container != DockerContainer::WhatsAppProxy) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -759,6 +768,7 @@ void InstallUiController::updateProtocolConfigModel(const QString &serverId, int
|
||||
case Proto::MtProxy: updateIfPresent(m_mtProxyConfigModel, containerConfig.getMtProxyProtocolConfig()); break;
|
||||
case Proto::Telemt: updateIfPresent(m_telemtConfigModel, containerConfig.getTelemtProtocolConfig()); break;
|
||||
case Proto::TProxy: updateIfPresent(m_tProxyConfigModel, containerConfig.getTProxyProtocolConfig()); break;
|
||||
case Proto::WhatsAppProxy: updateIfPresent(m_whatsAppProxyConfigModel, containerConfig.getWhatsAppProxyProtocolConfig()); break;
|
||||
#ifdef Q_OS_WINDOWS
|
||||
case Proto::Ikev2: updateIfPresent(m_ikev2ConfigModel, containerConfig.getIkev2ProtocolConfig()); break;
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "ui/models/services/mtProxyConfigModel.h"
|
||||
#include "ui/models/services/telemtConfigModel.h"
|
||||
#include "ui/models/services/tProxyConfigModel.h"
|
||||
#include "ui/models/services/whatsAppProxyConfigModel.h"
|
||||
|
||||
class InstallUiController : public QObject
|
||||
{
|
||||
@@ -55,6 +56,7 @@ public:
|
||||
MtProxyConfigModel* mtConfigModel,
|
||||
TelemtConfigModel* telemtConfigModel,
|
||||
TProxyConfigModel* tProxyConfigModel,
|
||||
WhatsAppProxyConfigModel* whatsAppProxyConfigModel,
|
||||
ConnectionController* connectionController,
|
||||
QObject *parent = nullptr);
|
||||
~InstallUiController();
|
||||
@@ -163,6 +165,7 @@ private:
|
||||
MtProxyConfigModel* m_mtProxyConfigModel;
|
||||
TelemtConfigModel* m_telemtConfigModel;
|
||||
TProxyConfigModel* m_tProxyConfigModel;
|
||||
WhatsAppProxyConfigModel* m_whatsAppProxyConfigModel;
|
||||
ConnectionController* m_connectionController;
|
||||
|
||||
ServerCredentials m_processedServerCredentials;
|
||||
|
||||
@@ -576,6 +576,8 @@ QStringList ServersUiController::getAllInstalledServicesName(int serverIndex) co
|
||||
servicesName.append("Telemt");
|
||||
} else if (container == DockerContainer::TProxy) {
|
||||
servicesName.append("TProxy");
|
||||
} else if (container == DockerContainer::WhatsAppProxy) {
|
||||
servicesName.append("WhatsApp");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ QVariant ContainersModel::data(const QModelIndex &index, int role) const
|
||||
case IsMtProxyRole: return container == DockerContainer::MtProxy;
|
||||
case IsTelemtRole: return container == DockerContainer::Telemt;
|
||||
case IsTProxyRole: return container == DockerContainer::TProxy;
|
||||
case IsWhatsAppProxyRole: return container == DockerContainer::WhatsAppProxy;
|
||||
case InstallPageOrderRole: return ContainerUtils::installPageOrder(container);
|
||||
}
|
||||
|
||||
@@ -193,5 +194,6 @@ QHash<int, QByteArray> ContainersModel::roleNames() const
|
||||
roles[IsMtProxyRole] = "isMtProxy";
|
||||
roles[IsTelemtRole] = "isTelemt";
|
||||
roles[IsTProxyRole] = "isTProxy";
|
||||
roles[IsWhatsAppProxyRole] = "isWhatsAppProxy";
|
||||
return roles;
|
||||
}
|
||||
@@ -54,6 +54,7 @@ public:
|
||||
IsMtProxyRole,
|
||||
IsTelemtRole,
|
||||
IsTProxyRole,
|
||||
IsWhatsAppProxyRole,
|
||||
};
|
||||
|
||||
Q_INVOKABLE void openContainerSettings(int containerIndex);
|
||||
|
||||
@@ -45,6 +45,7 @@ QHash<int, QByteArray> ProtocolsModel::roleNames() const
|
||||
roles[IsMtProxyRole] = "isMtProxy";
|
||||
roles[IsTelemtRole] = "isTelemt";
|
||||
roles[IsTProxyRole] = "isTProxy";
|
||||
roles[IsWhatsAppProxyRole] = "isWhatsAppProxy";
|
||||
|
||||
return roles;
|
||||
}
|
||||
@@ -77,6 +78,7 @@ QVariant ProtocolsModel::data(const QModelIndex &index, int role) const
|
||||
case IsMtProxyRole: return proto == Proto::MtProxy;
|
||||
case IsTelemtRole: return proto == Proto::Telemt;
|
||||
case IsTProxyRole: return proto == Proto::TProxy;
|
||||
case IsWhatsAppProxyRole: return proto == Proto::WhatsAppProxy;
|
||||
case RawConfigRole:
|
||||
return getRawConfig();
|
||||
case IsClientProtocolExistsRole:
|
||||
@@ -133,6 +135,7 @@ PageLoader::PageEnum ProtocolsModel::serverProtocolPage(Proto protocol) const
|
||||
case Proto::MtProxy: return PageLoader::PageEnum::PageServiceMtProxySettings;
|
||||
case Proto::Telemt: return PageLoader::PageEnum::PageServiceTelemtSettings;
|
||||
case Proto::TProxy: return PageLoader::PageEnum::PageServiceTProxySettings;
|
||||
case Proto::WhatsAppProxy: return PageLoader::PageEnum::PageServiceWhatsAppProxySettings;
|
||||
default: return PageLoader::PageEnum::PageProtocolOpenVpnSettings;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
IsMtProxyRole,
|
||||
IsTelemtRole,
|
||||
IsTProxyRole,
|
||||
IsWhatsAppProxyRole,
|
||||
};
|
||||
|
||||
explicit ProtocolsModel(QObject *parent = nullptr);
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
#include "whatsAppProxyConfigModel.h"
|
||||
|
||||
#include "core/utils/constants/configKeys.h"
|
||||
#include "core/utils/constants/protocolConstants.h"
|
||||
#include "core/utils/networkUtilities.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QRegularExpression>
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
namespace
|
||||
{
|
||||
const QRegularExpression kHostnameRe(
|
||||
QStringLiteral("^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)+$"));
|
||||
}
|
||||
|
||||
WhatsAppProxyConfigModel::WhatsAppProxyConfigModel(QObject *parent) : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool WhatsAppProxyConfigModel::isEnabled() const
|
||||
{
|
||||
return m_protocolConfig.isEnabled;
|
||||
}
|
||||
|
||||
void WhatsAppProxyConfigModel::updateModel(DockerContainer container, const WhatsAppProxyProtocolConfig &protocolConfig)
|
||||
{
|
||||
m_container = container;
|
||||
m_protocolConfig = protocolConfig;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void WhatsAppProxyConfigModel::updateModel(const QJsonObject &config)
|
||||
{
|
||||
m_fullConfig = config;
|
||||
m_protocolConfig = WhatsAppProxyProtocolConfig::fromJson(config.value(configKey::whatsappproxy).toObject());
|
||||
m_protocolConfig.port = m_protocolConfig.effectivePort();
|
||||
m_protocolConfig.mediaPort = m_protocolConfig.effectiveMediaPort();
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QJsonObject WhatsAppProxyConfigModel::getConfig()
|
||||
{
|
||||
m_fullConfig.insert(configKey::whatsappproxy, m_protocolConfig.toJson());
|
||||
return m_fullConfig;
|
||||
}
|
||||
|
||||
WhatsAppProxyProtocolConfig WhatsAppProxyConfigModel::getProtocolConfig()
|
||||
{
|
||||
return m_protocolConfig;
|
||||
}
|
||||
|
||||
void WhatsAppProxyConfigModel::setPort(const QString &port)
|
||||
{
|
||||
const QString p = sanitizePortFieldText(port);
|
||||
if (m_protocolConfig.port == p) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.port = p;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void WhatsAppProxyConfigModel::setMediaPort(const QString &port)
|
||||
{
|
||||
const QString p = sanitizePortFieldText(port);
|
||||
if (m_protocolConfig.mediaPort == p) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.mediaPort = p;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void WhatsAppProxyConfigModel::setPublicHost(const QString &host)
|
||||
{
|
||||
const QString h = host.trimmed();
|
||||
if (!isValidPublicHost(h) || m_protocolConfig.publicHost == h) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.publicHost = h;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void WhatsAppProxyConfigModel::setEnabled(bool enabled)
|
||||
{
|
||||
if (m_protocolConfig.isEnabled == enabled) {
|
||||
return;
|
||||
}
|
||||
m_protocolConfig.isEnabled = enabled;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString WhatsAppProxyConfigModel::getPort() const
|
||||
{
|
||||
return m_protocolConfig.effectivePort();
|
||||
}
|
||||
|
||||
QString WhatsAppProxyConfigModel::getMediaPort() const
|
||||
{
|
||||
return m_protocolConfig.effectiveMediaPort();
|
||||
}
|
||||
|
||||
QString WhatsAppProxyConfigModel::getPublicHost() const
|
||||
{
|
||||
return m_protocolConfig.publicHost;
|
||||
}
|
||||
|
||||
QString WhatsAppProxyConfigModel::defaultPort() const
|
||||
{
|
||||
return QString(protocols::whatsAppProxy::defaultPort);
|
||||
}
|
||||
|
||||
QString WhatsAppProxyConfigModel::defaultMediaPort() const
|
||||
{
|
||||
return QString(protocols::whatsAppProxy::defaultMediaPort);
|
||||
}
|
||||
|
||||
bool WhatsAppProxyConfigModel::isValidPort(const QString &port) const
|
||||
{
|
||||
bool ok = false;
|
||||
const int n = port.toInt(&ok);
|
||||
return ok && n >= 1 && n <= 65535;
|
||||
}
|
||||
|
||||
bool WhatsAppProxyConfigModel::isValidPublicHost(const QString &host) const
|
||||
{
|
||||
const QString t = host.trimmed();
|
||||
if (t.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (t.length() > 253) {
|
||||
return false;
|
||||
}
|
||||
const QHostAddress address(t);
|
||||
if (address.protocol() == QHostAddress::IPv4Protocol) {
|
||||
return NetworkUtilities::checkIPv4Format(t);
|
||||
}
|
||||
if (address.protocol() == QHostAddress::IPv6Protocol) {
|
||||
return !address.isNull() && !address.isLoopback();
|
||||
}
|
||||
return kHostnameRe.match(t).hasMatch();
|
||||
}
|
||||
|
||||
QString WhatsAppProxyConfigModel::sanitizePortFieldText(const QString &input) const
|
||||
{
|
||||
QString out;
|
||||
out.reserve(qMin(input.size(), 5));
|
||||
for (const QChar &c : input) {
|
||||
const ushort u = c.unicode();
|
||||
if (u >= '0' && u <= '9' && out.size() < 5) {
|
||||
out.append(c);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef WHATSAPPPROXYCONFIGMODEL_H
|
||||
#define WHATSAPPPROXYCONFIGMODEL_H
|
||||
|
||||
#include "core/models/protocols/whatsAppProxyProtocolConfig.h"
|
||||
#include "core/utils/containerEnum.h"
|
||||
#include <QJsonObject>
|
||||
#include <QObject>
|
||||
|
||||
class WhatsAppProxyConfigModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString port READ getPort WRITE setPort NOTIFY changed)
|
||||
Q_PROPERTY(QString mediaPort READ getMediaPort WRITE setMediaPort NOTIFY changed)
|
||||
Q_PROPERTY(QString publicHost READ getPublicHost WRITE setPublicHost NOTIFY changed)
|
||||
Q_PROPERTY(bool isEnabled READ isEnabled WRITE setEnabled NOTIFY changed)
|
||||
|
||||
public:
|
||||
explicit WhatsAppProxyConfigModel(QObject *parent = nullptr);
|
||||
|
||||
bool isEnabled() const;
|
||||
|
||||
public slots:
|
||||
void updateModel(amnezia::DockerContainer container, const amnezia::WhatsAppProxyProtocolConfig &protocolConfig);
|
||||
void updateModel(const QJsonObject &config);
|
||||
|
||||
QJsonObject getConfig();
|
||||
amnezia::WhatsAppProxyProtocolConfig getProtocolConfig();
|
||||
|
||||
Q_INVOKABLE void setPort(const QString &port);
|
||||
Q_INVOKABLE void setMediaPort(const QString &port);
|
||||
Q_INVOKABLE void setPublicHost(const QString &host);
|
||||
Q_INVOKABLE void setEnabled(bool enabled);
|
||||
|
||||
Q_INVOKABLE QString getPort() const;
|
||||
Q_INVOKABLE QString getMediaPort() const;
|
||||
Q_INVOKABLE QString getPublicHost() const;
|
||||
|
||||
Q_INVOKABLE QString defaultPort() const;
|
||||
Q_INVOKABLE QString defaultMediaPort() const;
|
||||
|
||||
Q_INVOKABLE bool isValidPort(const QString &port) const;
|
||||
Q_INVOKABLE bool isValidPublicHost(const QString &host) const;
|
||||
Q_INVOKABLE QString sanitizePortFieldText(const QString &input) const;
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
private:
|
||||
amnezia::DockerContainer m_container;
|
||||
QJsonObject m_fullConfig;
|
||||
amnezia::WhatsAppProxyProtocolConfig m_protocolConfig;
|
||||
};
|
||||
|
||||
#endif // WHATSAPPPROXYCONFIGMODEL_H
|
||||
@@ -76,6 +76,9 @@ ListViewType {
|
||||
} else if (isTProxy) {
|
||||
TProxyConfigModel.updateModel(config)
|
||||
PageController.goToPage(PageEnum.PageServiceTProxySettings, false)
|
||||
} else if (isWhatsAppProxy) {
|
||||
WhatsAppProxyConfigModel.updateModel(config)
|
||||
PageController.goToPage(PageEnum.PageServiceWhatsAppProxySettings, false)
|
||||
} else {
|
||||
InstallController.updateProtocols(ServersUiController.processedServerId, containerIndex)
|
||||
PageController.goToPage(PageEnum.PageSettingsServerProtocol)
|
||||
|
||||
@@ -0,0 +1,567 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import PageEnum 1.0
|
||||
import ProtocolEnum 1.0
|
||||
import Style 1.0
|
||||
import MtProxyConfig 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
property int containerStatus: 1
|
||||
property int statusErrorCode: 0
|
||||
property bool isUpdating: false
|
||||
property bool isCheckingStatus: false
|
||||
property bool previousEnabled: true
|
||||
property int previousContainerStatus: 1
|
||||
property string savedPublicHost: ""
|
||||
property string savedPort: ""
|
||||
property string savedMediaPort: ""
|
||||
property bool pendingUpdateAfterEnable: false
|
||||
property bool remoteOperationBusy: false
|
||||
|
||||
readonly property bool networkBlocked: !NetworkReachabilityController.hasInternetAccess
|
||||
readonly property bool pageBusy: isCheckingStatus || isUpdating || remoteOperationBusy
|
||||
readonly property bool navigationBlockedWhileBusy: pageBusy
|
||||
|
||||
property bool pageOpenHandled: false
|
||||
property bool busyIndicatorShown: false
|
||||
property bool containerStatusRefreshCallPending: false
|
||||
|
||||
readonly property bool fieldsEditable: WhatsAppProxyConfigModel.isEnabled && containerStatus === 1 && !root.pageBusy
|
||||
|
||||
function effectiveHost() {
|
||||
return root.savedPublicHost !== "" ? root.savedPublicHost : ServersUiController.serverHostName(ServersUiController.processedServerId)
|
||||
}
|
||||
|
||||
function shareText() {
|
||||
return qsTr("WhatsApp proxy") + "\n"
|
||||
+ qsTr("Proxy address: %1").arg(root.effectiveHost()) + "\n"
|
||||
+ qsTr("Chat port: %1 (TLS on)").arg(root.savedPort) + "\n"
|
||||
+ qsTr("Media port: %1").arg(root.savedMediaPort) + "\n"
|
||||
+ qsTr("WhatsApp: Settings > Storage and data > Proxy")
|
||||
}
|
||||
|
||||
function saveCurrentValues() {
|
||||
savedPublicHost = WhatsAppProxyConfigModel.getPublicHost()
|
||||
savedPort = WhatsAppProxyConfigModel.getPort()
|
||||
savedMediaPort = WhatsAppProxyConfigModel.getMediaPort()
|
||||
}
|
||||
|
||||
function syncPageBusyIndicator() {
|
||||
if (!root.pageOpenHandled) {
|
||||
return
|
||||
}
|
||||
var wantBusy = root.pageBusy
|
||||
if (wantBusy === root.busyIndicatorShown) {
|
||||
return
|
||||
}
|
||||
root.busyIndicatorShown = wantBusy
|
||||
PageController.showBusyIndicator(wantBusy)
|
||||
}
|
||||
|
||||
onPageBusyChanged: syncPageBusyIndicator()
|
||||
|
||||
function requestContainerStatusRefresh() {
|
||||
if (!NetworkReachabilityController.hasInternetAccess) {
|
||||
isCheckingStatus = false
|
||||
syncPageBusyIndicator()
|
||||
return
|
||||
}
|
||||
isCheckingStatus = true
|
||||
syncPageBusyIndicator()
|
||||
InstallController.refreshContainerStatus(ServersUiController.processedServerId,
|
||||
ServersUiController.processedContainerIndex)
|
||||
}
|
||||
|
||||
function scheduleContainerStatusRefresh() {
|
||||
if (containerStatusRefreshCallPending) {
|
||||
return
|
||||
}
|
||||
containerStatusRefreshCallPending = true
|
||||
Qt.callLater(function () {
|
||||
containerStatusRefreshCallPending = false
|
||||
root.requestContainerStatusRefresh()
|
||||
})
|
||||
}
|
||||
|
||||
function onPageShown() {
|
||||
if (root.pageOpenHandled) {
|
||||
return
|
||||
}
|
||||
root.pageOpenHandled = true
|
||||
|
||||
PageController.disableControls(navigationBlockedWhileBusy)
|
||||
|
||||
isCheckingStatus = NetworkReachabilityController.hasInternetAccess
|
||||
syncPageBusyIndicator()
|
||||
root.scheduleContainerStatusRefresh()
|
||||
}
|
||||
|
||||
function scheduleUpdate() {
|
||||
Qt.callLater(function () {
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId,
|
||||
ServersUiController.processedContainerIndex, ProtocolEnum.WhatsAppProxy, false)
|
||||
})
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: InstallController
|
||||
|
||||
function onUpdateContainerFinished(message, closePage) {
|
||||
if (!root.visible) {
|
||||
isUpdating = false
|
||||
isCheckingStatus = false
|
||||
return
|
||||
}
|
||||
isUpdating = false
|
||||
containerStatus = 1
|
||||
root.saveCurrentValues()
|
||||
PageController.showNotificationMessage(message)
|
||||
}
|
||||
function onInstallationErrorOccurred() {
|
||||
if (!root.visible) {
|
||||
isUpdating = false
|
||||
isCheckingStatus = false
|
||||
return
|
||||
}
|
||||
isUpdating = false
|
||||
containerStatus = previousContainerStatus
|
||||
WhatsAppProxyConfigModel.setEnabled(previousEnabled)
|
||||
WhatsAppProxyConfigModel.setPublicHost(savedPublicHost)
|
||||
WhatsAppProxyConfigModel.setPort(savedPort)
|
||||
WhatsAppProxyConfigModel.setMediaPort(savedMediaPort)
|
||||
}
|
||||
function onSetContainerEnabledFinished(enabled) {
|
||||
if (!root.visible) {
|
||||
isUpdating = false
|
||||
return
|
||||
}
|
||||
if (enabled && root.pendingUpdateAfterEnable) {
|
||||
root.pendingUpdateAfterEnable = false
|
||||
isUpdating = true
|
||||
root.scheduleUpdate()
|
||||
return
|
||||
}
|
||||
isUpdating = false
|
||||
containerStatus = enabled ? 1 : 2
|
||||
PageController.showNotificationMessage(enabled ? qsTr("WhatsApp proxy started") : qsTr("WhatsApp proxy stopped"))
|
||||
}
|
||||
function onServerIsBusy(busy) {
|
||||
root.remoteOperationBusy = busy
|
||||
}
|
||||
function onContainerStatusRefreshed(status, errorCode) {
|
||||
if (!root.visible) {
|
||||
isCheckingStatus = false
|
||||
return
|
||||
}
|
||||
containerStatus = status
|
||||
root.statusErrorCode = errorCode
|
||||
if (status === 3 && errorCode !== 0) {
|
||||
PageController.showNotificationMessage(
|
||||
qsTr("Settings locked: connection timed out (error code %1). Re-open the page to retry.").arg(errorCode))
|
||||
}
|
||||
|
||||
root.saveCurrentValues()
|
||||
if (status === 1) {
|
||||
WhatsAppProxyConfigModel.setEnabled(true)
|
||||
} else if (status === 2) {
|
||||
WhatsAppProxyConfigModel.setEnabled(false)
|
||||
}
|
||||
isCheckingStatus = false
|
||||
syncPageBusyIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.saveCurrentValues()
|
||||
Qt.callLater(root.onPageShown)
|
||||
}
|
||||
|
||||
onNavigationBlockedWhileBusyChanged: {
|
||||
if (root.visible) {
|
||||
PageController.disableControls(navigationBlockedWhileBusy)
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
root.pageOpenHandled = false
|
||||
containerStatusRefreshCallPending = false
|
||||
isCheckingStatus = false
|
||||
busyIndicatorShown = false
|
||||
statusErrorCode = 0
|
||||
PageController.disableControls(false)
|
||||
PageController.showBusyIndicator(false)
|
||||
} else {
|
||||
root.onPageShown()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: NetworkReachabilityController
|
||||
|
||||
function onHasInternetAccessChanged() {
|
||||
if (!root.visible) {
|
||||
return
|
||||
}
|
||||
if (NetworkReachabilityController.hasInternetAccess) {
|
||||
root.scheduleContainerStatusRefresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: contentLayer
|
||||
anchors.fill: parent
|
||||
enabled: !root.pageBusy
|
||||
|
||||
ColumnLayout {
|
||||
id: pageHeader
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
spacing: 0
|
||||
|
||||
NavigationBarType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
title: qsTr("WhatsApp proxy settings")
|
||||
}
|
||||
|
||||
LinkButtonType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
size: LinkButtonType.Medium
|
||||
horizontalPadding: 14
|
||||
verticalPadding: 8
|
||||
|
||||
text: qsTr("Read more about WhatsApp proxy")
|
||||
|
||||
onClicked: Qt.openUrlExternally("https://github.com/WhatsApp/proxy")
|
||||
}
|
||||
|
||||
SmallTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 12
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: root.networkBlocked
|
||||
text: qsTr("No internet connection. Connect to the internet to change WhatsApp proxy settings.")
|
||||
}
|
||||
}
|
||||
|
||||
TabsType {
|
||||
id: mainTabBar
|
||||
|
||||
anchors.top: pageHeader.bottom
|
||||
anchors.topMargin: 24
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
TabButtonType {
|
||||
text: qsTr("Connection")
|
||||
}
|
||||
TabButtonType {
|
||||
text: qsTr("Settings")
|
||||
}
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
anchors.top: mainTabBar.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
currentIndex: mainTabBar.currentIndex
|
||||
|
||||
Item {
|
||||
FlickableType {
|
||||
id: connectionFlickable
|
||||
|
||||
anchors.top: parent.top
|
||||
|
||||
contentHeight: connectionContent.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: connectionContent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
spacing: 0
|
||||
|
||||
SmallTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Enter these values in WhatsApp: Settings > Storage and data > Proxy")
|
||||
}
|
||||
|
||||
ListGroupType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 12
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
CopyableValueRow {
|
||||
Layout.fillWidth: true
|
||||
|
||||
copiedText: qsTr("Copied")
|
||||
label: qsTr("Proxy address")
|
||||
value: root.effectiveHost()
|
||||
}
|
||||
|
||||
CopyableValueRow {
|
||||
Layout.fillWidth: true
|
||||
|
||||
copiedText: qsTr("Copied")
|
||||
label: qsTr("Chat port (TLS on)")
|
||||
value: root.savedPort
|
||||
}
|
||||
|
||||
CopyableValueRow {
|
||||
Layout.fillWidth: true
|
||||
|
||||
copiedText: qsTr("Copied")
|
||||
label: qsTr("Media port")
|
||||
value: root.savedMediaPort
|
||||
showSeparator: false
|
||||
}
|
||||
}
|
||||
|
||||
ButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Share")
|
||||
|
||||
onClicked: {
|
||||
ExportController.generateQrFromStringRaw(root.shareText())
|
||||
PageController.goToShareConnectionPage(qsTr("WhatsApp proxy"),
|
||||
qsTr("WhatsApp proxy settings"), "", ".txt", "whatsapp_proxy")
|
||||
}
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 12
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Anyone who knows the address and ports can use the proxy. Calls are not proxied.")
|
||||
}
|
||||
|
||||
ButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 16 + PageController.safeAreaBottomMargin
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: ServersUiController.isProcessedServerHasWriteAccess()
|
||||
variant: ButtonType.Destructive
|
||||
text: qsTr("Delete WhatsApp proxy")
|
||||
|
||||
onClicked: {
|
||||
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
|
||||
var yesButtonFunction = function () {
|
||||
PageController.goToPage(PageEnum.PageDeinstalling)
|
||||
InstallController.removeContainer(ServersUiController.processedServerId,
|
||||
ServersUiController.processedContainerIndex)
|
||||
}
|
||||
Dialogs.askQuestion(headerText,
|
||||
qsTr("The proxy will be stopped and all users will lose access."),
|
||||
qsTr("Continue"), qsTr("Cancel"), yesButtonFunction, function () {})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
FlickableType {
|
||||
id: settingsFlickable
|
||||
|
||||
anchors.top: parent.top
|
||||
|
||||
contentHeight: settingsContent.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: settingsContent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
spacing: 12
|
||||
|
||||
SwitchRowType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
text: qsTr("Enable WhatsApp proxy")
|
||||
checked: WhatsAppProxyConfigModel.isEnabled
|
||||
enabled: containerStatus !== 0 && containerStatus !== 3 && !root.pageBusy && !root.networkBlocked
|
||||
onToggled: function () {
|
||||
if (checked !== WhatsAppProxyConfigModel.isEnabled) {
|
||||
previousEnabled = WhatsAppProxyConfigModel.isEnabled
|
||||
previousContainerStatus = containerStatus
|
||||
WhatsAppProxyConfigModel.isEnabled = checked
|
||||
isUpdating = true
|
||||
if (checked) {
|
||||
root.pendingUpdateAfterEnable = true
|
||||
}
|
||||
InstallController.setContainerEnabled(ServersUiController.processedServerId,
|
||||
ServersUiController.processedContainerIndex, checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SmallTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
visible: !root.fieldsEditable && !root.pageBusy
|
||||
text: (containerStatus === 1 || containerStatus === 2)
|
||||
? qsTr("Enable WhatsApp proxy to edit settings")
|
||||
: (statusErrorCode !== 0
|
||||
? qsTr("Settings locked: connection timed out (error code %1). Re-open the page to retry.").arg(statusErrorCode)
|
||||
: qsTr("Cannot reach the server — settings are unavailable"))
|
||||
}
|
||||
|
||||
TextFieldType {
|
||||
id: publicHostTextField
|
||||
Layout.topMargin: 12
|
||||
enabled: root.fieldsEditable
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
headerText: qsTr("Public host / IP")
|
||||
textField.placeholderText: ServersUiController.serverHostName(ServersUiController.processedServerId)
|
||||
textField.text: WhatsAppProxyConfigModel.publicHost
|
||||
textField.maximumLength: 253
|
||||
textField.validator: PublicHostInputValidator {
|
||||
}
|
||||
textField.onEditingFinished: {
|
||||
textField.text = textField.text.trim()
|
||||
if (!WhatsAppProxyConfigModel.isValidPublicHost(textField.text)) {
|
||||
publicHostTextField.errorText = qsTr("Enter a valid IP address or domain name")
|
||||
return
|
||||
}
|
||||
publicHostTextField.errorText = ""
|
||||
}
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
text: qsTr("Leave empty to use server IP automatically")
|
||||
}
|
||||
|
||||
TextFieldType {
|
||||
id: portTextField
|
||||
enabled: root.fieldsEditable
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
headerText: qsTr("Chat port")
|
||||
textField.placeholderText: WhatsAppProxyConfigModel.defaultPort()
|
||||
textField.text: WhatsAppProxyConfigModel.port
|
||||
textField.maximumLength: 5
|
||||
textField.inputMethodHints: Qt.ImhDigitsOnly
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
}
|
||||
|
||||
TextFieldType {
|
||||
id: mediaPortTextField
|
||||
enabled: root.fieldsEditable
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
headerText: qsTr("Media port")
|
||||
textField.placeholderText: WhatsAppProxyConfigModel.defaultMediaPort()
|
||||
textField.text: WhatsAppProxyConfigModel.mediaPort
|
||||
textField.maximumLength: 5
|
||||
textField.inputMethodHints: Qt.ImhDigitsOnly
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
text: qsTr("Changing a port reinstalls the container. WhatsApp uses 443 and 587 by default; with other ports users enter them manually and enable TLS for the chat port.")
|
||||
}
|
||||
|
||||
ButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 12
|
||||
Layout.bottomMargin: 16 + PageController.safeAreaBottomMargin
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
text: qsTr("Save")
|
||||
enabled: root.fieldsEditable && !root.networkBlocked
|
||||
onClicked: {
|
||||
publicHostTextField.errorText = ""
|
||||
portTextField.errorText = ""
|
||||
mediaPortTextField.errorText = ""
|
||||
|
||||
var host = publicHostTextField.textField.text.trim()
|
||||
var chatPort = WhatsAppProxyConfigModel.sanitizePortFieldText(portTextField.textField.text)
|
||||
var mediaPort = WhatsAppProxyConfigModel.sanitizePortFieldText(mediaPortTextField.textField.text)
|
||||
|
||||
var hasError = false
|
||||
if (!WhatsAppProxyConfigModel.isValidPublicHost(host)) {
|
||||
publicHostTextField.errorText = qsTr("Enter a valid IP address or domain name")
|
||||
hasError = true
|
||||
}
|
||||
if (!WhatsAppProxyConfigModel.isValidPort(chatPort)) {
|
||||
portTextField.errorText = qsTr("The port must be in the range of 1 to 65535")
|
||||
hasError = true
|
||||
}
|
||||
if (!WhatsAppProxyConfigModel.isValidPort(mediaPort)) {
|
||||
mediaPortTextField.errorText = qsTr("The port must be in the range of 1 to 65535")
|
||||
hasError = true
|
||||
} else if (mediaPort === chatPort) {
|
||||
mediaPortTextField.errorText = qsTr("The media port must differ from the chat port")
|
||||
hasError = true
|
||||
}
|
||||
if (hasError) {
|
||||
return
|
||||
}
|
||||
|
||||
previousContainerStatus = containerStatus
|
||||
WhatsAppProxyConfigModel.setPublicHost(host)
|
||||
WhatsAppProxyConfigModel.setPort(chatPort)
|
||||
WhatsAppProxyConfigModel.setMediaPort(mediaPort)
|
||||
isUpdating = true
|
||||
root.scheduleUpdate()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@ PageType {
|
||||
required property string detailedDescription
|
||||
required property int dockerContainer
|
||||
required property bool isTProxy
|
||||
required property bool isWhatsAppProxy
|
||||
|
||||
function install() {
|
||||
if (isTProxy) {
|
||||
@@ -96,6 +97,20 @@ PageType {
|
||||
return
|
||||
}
|
||||
|
||||
if (isWhatsAppProxy) {
|
||||
mediaPort.errorText = ""
|
||||
if (!mediaPort.textField.acceptableInput) {
|
||||
mediaPort.errorText = qsTr("The port must be in the range of 1 to 65535")
|
||||
return
|
||||
}
|
||||
if (mediaPort.textField.text === port.textField.text) {
|
||||
mediaPort.errorText = qsTr("The media port must differ from the chat port")
|
||||
return
|
||||
}
|
||||
WhatsAppProxyConfigModel.setPort(port.textField.text)
|
||||
WhatsAppProxyConfigModel.setMediaPort(mediaPort.textField.text)
|
||||
}
|
||||
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.install(dockerContainer, port.textField.text, transportProtoSelector.currentIndex, ServersUiController.processedServerId)
|
||||
}
|
||||
@@ -155,11 +170,33 @@ PageType {
|
||||
|
||||
visible: !delegateRoot.isTProxy
|
||||
|
||||
headerText: qsTr("Port")
|
||||
headerText: delegateRoot.isWhatsAppProxy ? qsTr("Chat port") : qsTr("Port")
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
}
|
||||
|
||||
TextFieldType {
|
||||
id: mediaPort
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
visible: delegateRoot.isWhatsAppProxy
|
||||
|
||||
headerText: qsTr("Media port")
|
||||
textField.text: WhatsAppProxyConfigModel.defaultMediaPort()
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
visible: delegateRoot.isWhatsAppProxy
|
||||
|
||||
text: qsTr("WhatsApp uses chat port 443 and media port 587 by default. With other ports, users must enter them in WhatsApp proxy settings and enable TLS for the chat port. Calls are not proxied.")
|
||||
color: AmneziaStyle.color.textAccent
|
||||
}
|
||||
|
||||
TextFieldType {
|
||||
id: tproxyHostname
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
<file>Pages2/PageServiceMtProxySettings.qml</file>
|
||||
<file>Pages2/PageServiceTelemtSettings.qml</file>
|
||||
<file>Pages2/PageServiceTProxySettings.qml</file>
|
||||
<file>Pages2/PageServiceWhatsAppProxySettings.qml</file>
|
||||
<file>Pages2/PageServiceSftpSettings.qml</file>
|
||||
<file>Pages2/PageServiceSocksProxySettings.qml</file>
|
||||
<file>Pages2/PageServiceTorWebsiteSettings.qml</file>
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace PageLoader
|
||||
PageServiceMtProxySettings,
|
||||
PageServiceTelemtSettings,
|
||||
PageServiceTProxySettings,
|
||||
PageServiceWhatsAppProxySettings,
|
||||
|
||||
PageSetupWizardStart,
|
||||
PageSetupWizardCredentials,
|
||||
|
||||
Reference in new issue
Block a user