From d62ade58a511aa76f8944b7cf32bc646a644b68c Mon Sep 17 00:00:00 2001
From: lunardunno <126363523+lunardunno@users.noreply.github.com>
Date: Mon, 27 May 2024 12:05:53 +0400
Subject: [PATCH 1/7] update Hindi translation
Fixed handling of file extensions in Hindi translation.
---
client/translations/amneziavpn_hi_IN.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/client/translations/amneziavpn_hi_IN.ts b/client/translations/amneziavpn_hi_IN.ts
index 802604a6..2c718fb7 100644
--- a/client/translations/amneziavpn_hi_IN.ts
+++ b/client/translations/amneziavpn_hi_IN.ts
@@ -1144,7 +1144,7 @@ Already installed containers were found on the server. All installed containers
Executable file (*.*)
- निष्पादनीय फाइल (*।*)
+ निष्पादनीय फाइल (*.*)
@@ -1276,7 +1276,7 @@ Already installed containers were found on the server. All installed containers
Backup files (*.backup)
- बैकअप फ़ाइलें (*.बैकअप)
+ बैकअप फ़ाइलें (*.backup)
@@ -1480,7 +1480,7 @@ Already installed containers were found on the server. All installed containers
Logs files (*.log)
- लॉग फ़ाइलें (*.लॉग)
+ लॉग फ़ाइलें (*.log)
From aac9bfcea6744e13a3966b069a3a832d1794e9c6 Mon Sep 17 00:00:00 2001
From: Vladyslav Miachkov
Date: Mon, 27 May 2024 18:58:36 +0300
Subject: [PATCH 2/7] Possible wg show crash fix
---
client/ui/models/clientManagementModel.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/client/ui/models/clientManagementModel.cpp b/client/ui/models/clientManagementModel.cpp
index ea5cb23c..f2117f75 100644
--- a/client/ui/models/clientManagementModel.cpp
+++ b/client/ui/models/clientManagementModel.cpp
@@ -281,7 +281,8 @@ ErrorCode ClientManagementModel::wgShow(const DockerContainer container, const S
}
};
- for (int i = 0; i < peerList.size() && i < transferredDataList.size(); ++i) {
+ for (int i = 0; i < peerList.size() && i < transferredDataList.size() && i < latestHandshakeList.size(); ++i) {
+
const auto transferredData = getStrValue(transferredDataList[i]).split(",");
auto latestHandshake = getStrValue(latestHandshakeList[i]);
auto serverBytesReceived = transferredData.front().trimmed();
From 5db0c281ee33bde55d7344cb52e202c25c609a5c Mon Sep 17 00:00:00 2001
From: "vladimir.kuznetsov"
Date: Thu, 30 May 2024 12:42:53 +0200
Subject: [PATCH 3/7] fixed isDefaultServerDefaultContainerHasSplitTunneling()
---
client/ui/models/servers_model.cpp | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp
index 480ff3b4..17535e5a 100644
--- a/client/ui/models/servers_model.cpp
+++ b/client/ui/models/servers_model.cpp
@@ -615,15 +615,18 @@ bool ServersModel::isDefaultServerDefaultContainerHasSplitTunneling()
{
auto server = m_servers.at(m_defaultServerIndex).toObject();
auto defaultContainer = ContainerProps::containerFromString(server.value(config_key::defaultContainer).toString());
- auto containerConfig = server.value(config_key::containers).toArray().at(defaultContainer).toObject();
- auto protocolConfig = containerConfig.value(ContainerProps::containerTypeToString(defaultContainer)).toObject();
- if (defaultContainer == DockerContainer::Awg || defaultContainer == DockerContainer::WireGuard) {
- return !(protocolConfig.value(config_key::last_config).toString().contains("AllowedIPs = 0.0.0.0/0, ::/0"));
- } else if (defaultContainer == DockerContainer::Cloak || defaultContainer == DockerContainer::OpenVpn
- || defaultContainer == DockerContainer::ShadowSocks) {
- return !(protocolConfig.value(config_key::last_config).toString().contains("redirect-gateway"));
+ auto containers = server.value(config_key::containers).toArray();
+ for (auto i = 0; i < containers.size(); i++) {
+ auto container = containers.at(i).toObject();
+ if (defaultContainer == DockerContainer::Awg || defaultContainer == DockerContainer::WireGuard) {
+ auto containerConfig = container.value(ContainerProps::containerTypeToString(defaultContainer)).toObject();
+ return !(containerConfig.value(config_key::last_config).toString().contains("AllowedIPs = 0.0.0.0/0, ::/0"));
+ } else if (defaultContainer == DockerContainer::Cloak || defaultContainer == DockerContainer::OpenVpn
+ || defaultContainer == DockerContainer::ShadowSocks) {
+ auto containerConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::OpenVpn)).toObject();
+ return !(containerConfig.value(config_key::last_config).toString().contains("redirect-gateway"));
+ }
}
-
return false;
}
From 04fb1825d52cd5135e62bcfacf5b323e03688303 Mon Sep 17 00:00:00 2001
From: "vladimir.kuznetsov"
Date: Wed, 5 Jun 2024 22:19:23 +0200
Subject: [PATCH 4/7] fixed display of awg config settings received from api
---
client/core/controllers/apiController.cpp | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/client/core/controllers/apiController.cpp b/client/core/controllers/apiController.cpp
index 1a8dc8eb..35b459be 100644
--- a/client/core/controllers/apiController.cpp
+++ b/client/core/controllers/apiController.cpp
@@ -40,6 +40,28 @@ void ApiController::processApiConfig(const QString &protocol, const ApiControlle
return;
} else if (protocol == configKey::awg) {
config.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
+ auto serverConfig = QJsonDocument::fromJson(config.toUtf8()).object();
+ auto containers = serverConfig.value(config_key::containers).toArray();
+ if (containers.isEmpty()) {
+ return;
+ }
+ auto container = containers.at(0).toObject();
+ QString containerName = ContainerProps::containerTypeToString(DockerContainer::Awg);
+ auto containerConfig = container.value(containerName).toObject();
+ auto protocolConfig = QJsonDocument::fromJson(containerConfig.value(config_key::last_config).toString().toUtf8()).object();
+ containerConfig[config_key::junkPacketCount] = protocolConfig.value(config_key::junkPacketCount);
+ containerConfig[config_key::junkPacketMinSize] = protocolConfig.value(config_key::junkPacketMinSize);
+ containerConfig[config_key::junkPacketMaxSize] = protocolConfig.value(config_key::junkPacketMaxSize);
+ containerConfig[config_key::initPacketJunkSize] = protocolConfig.value(config_key::initPacketJunkSize);
+ containerConfig[config_key::responsePacketJunkSize] = protocolConfig.value(config_key::responsePacketJunkSize);
+ containerConfig[config_key::initPacketMagicHeader] = protocolConfig.value(config_key::initPacketMagicHeader);
+ containerConfig[config_key::responsePacketMagicHeader] = protocolConfig.value(config_key::responsePacketMagicHeader);
+ containerConfig[config_key::underloadPacketMagicHeader] = protocolConfig.value(config_key::underloadPacketMagicHeader);
+ containerConfig[config_key::transportPacketMagicHeader] = protocolConfig.value(config_key::transportPacketMagicHeader);
+ container[containerName] = containerConfig;
+ containers.replace(0, container);
+ serverConfig[config_key::containers] = containers;
+ config = QString(QJsonDocument(serverConfig).toJson());
}
return;
}
From c22f9ff08af880d8d6020c8fe5001215e18228bc Mon Sep 17 00:00:00 2001
From: Nethius
Date: Mon, 10 Jun 2024 18:35:24 +0700
Subject: [PATCH 5/7] added ui for proxy container (#762)
Added proxy container
---
client/amnezia_application.cpp | 3 +
client/amnezia_application.h | 2 +
client/containers/containers_defs.cpp | 14 +-
client/containers/containers_defs.h | 3 +-
client/core/controllers/serverController.cpp | 15 +-
client/core/scripts_registry.cpp | 1 +
client/protocols/protocols_defs.cpp | 9 +-
client/protocols/protocols_defs.h | 12 +-
client/resources.qrc | 7 +-
client/server_scripts/socks5_proxy/Dockerfile | 10 +
.../socks5_proxy/configure_container.sh | 12 +
.../socks5_proxy/run_container.sh | 5 +
client/server_scripts/socks5_proxy/start.sh | 7 +
client/ui/controllers/installController.cpp | 23 +-
client/ui/controllers/pageController.h | 1 +
client/ui/models/protocols_model.cpp | 1 +
client/ui/models/servers_model.cpp | 2 +
.../services/socks5ProxyConfigModel.cpp | 80 ++++
.../models/services/socks5ProxyConfigModel.h | 40 ++
.../Pages2/PageServiceSocksProxySettings.qml | 385 ++++++++++++++++++
.../qml/Pages2/PageSettingsServerProtocol.qml | 7 +-
.../PageSetupWizardProtocolSettings.qml | 5 +
22 files changed, 633 insertions(+), 11 deletions(-)
create mode 100644 client/server_scripts/socks5_proxy/Dockerfile
create mode 100644 client/server_scripts/socks5_proxy/configure_container.sh
create mode 100644 client/server_scripts/socks5_proxy/run_container.sh
create mode 100644 client/server_scripts/socks5_proxy/start.sh
create mode 100644 client/ui/models/services/socks5ProxyConfigModel.cpp
create mode 100644 client/ui/models/services/socks5ProxyConfigModel.h
create mode 100644 client/ui/qml/Pages2/PageServiceSocksProxySettings.qml
diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp
index db4061eb..eb1eab45 100644
--- a/client/amnezia_application.cpp
+++ b/client/amnezia_application.cpp
@@ -351,6 +351,9 @@ void AmneziaApplication::initModels()
m_sftpConfigModel.reset(new SftpConfigModel(this));
m_engine->rootContext()->setContextProperty("SftpConfigModel", m_sftpConfigModel.get());
+ m_socks5ConfigModel.reset(new Socks5ProxyConfigModel(this));
+ m_engine->rootContext()->setContextProperty("Socks5ProxyConfigModel", m_socks5ConfigModel.get());
+
m_clientManagementModel.reset(new ClientManagementModel(m_settings, this));
m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get());
connect(m_clientManagementModel.get(), &ClientManagementModel::adminConfigRevoked, m_serversModel.get(),
diff --git a/client/amnezia_application.h b/client/amnezia_application.h
index 5561d7c7..b15d55d7 100644
--- a/client/amnezia_application.h
+++ b/client/amnezia_application.h
@@ -41,6 +41,7 @@
#include "ui/models/protocols_model.h"
#include "ui/models/servers_model.h"
#include "ui/models/services/sftpConfigModel.h"
+#include "ui/models/services/socks5ProxyConfigModel.h"
#include "ui/models/sites_model.h"
#include "ui/models/clientManagementModel.h"
#include "ui/models/appSplitTunnelingModel.h"
@@ -114,6 +115,7 @@ private:
#endif
QScopedPointer m_sftpConfigModel;
+ QScopedPointer m_socks5ConfigModel;
QSharedPointer m_vpnConnection;
QThread m_vpnConnectionThread;
diff --git a/client/containers/containers_defs.cpp b/client/containers/containers_defs.cpp
index 89633f9e..3c2a3861 100644
--- a/client/containers/containers_defs.cpp
+++ b/client/containers/containers_defs.cpp
@@ -69,6 +69,8 @@ QVector ContainerProps::protocolsForContainer(amnezia::DockerCon
case DockerContainer::Sftp: return { Proto::Sftp };
+ case DockerContainer::Socks5Proxy: return { Proto::Socks5Proxy };
+
default: return { defaultProtocol(container) };
}
}
@@ -98,7 +100,8 @@ QMap ContainerProps::containerHumanNames()
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("Amnezia DNS") },
- { DockerContainer::Sftp, QObject::tr("Sftp file sharing service") } };
+ { DockerContainer::Sftp, QObject::tr("Sftp file sharing service") },
+ { DockerContainer::Socks5Proxy, QObject::tr("SOCKS5 proxy server") } };
}
QMap ContainerProps::containerDescriptions()
@@ -131,7 +134,9 @@ QMap ContainerProps::containerDescriptions()
{ DockerContainer::Dns,
QObject::tr("Replace the current DNS server with your own. This will increase your privacy level.") },
{ DockerContainer::Sftp,
- QObject::tr("Create a file vault on your server to securely store and transfer files.") } };
+ QObject::tr("Create a file vault on your server to securely store and transfer files.") },
+ { DockerContainer::Socks5Proxy,
+ QObject::tr("") } };
}
QMap ContainerProps::containerDetailedDescriptions()
@@ -240,7 +245,8 @@ QMap ContainerProps::containerDetailedDescriptions()
QObject::tr("After installation, Amnezia will create a\n\n file storage on your server. "
"You will be able to access it using\n FileZilla or other SFTP clients, "
"as well as mount the disk on your device to access\n it directly from your device.\n\n"
- "For more detailed information, you can\n find it in the support section under \"Create SFTP file storage.\" ") }
+ "For more detailed information, you can\n find it in the support section under \"Create SFTP file storage.\" ") },
+ { DockerContainer::Socks5Proxy, QObject::tr("SOCKS5 proxy server") }
};
}
@@ -265,6 +271,7 @@ Proto ContainerProps::defaultProtocol(DockerContainer c)
case DockerContainer::TorWebSite: return Proto::TorWebSite;
case DockerContainer::Dns: return Proto::Dns;
case DockerContainer::Sftp: return Proto::Sftp;
+ case DockerContainer::Socks5Proxy: return Proto::Socks5Proxy;
default: return Proto::Any;
}
}
@@ -367,6 +374,7 @@ bool ContainerProps::isShareable(DockerContainer container)
case DockerContainer::TorWebSite: return false;
case DockerContainer::Dns: return false;
case DockerContainer::Sftp: return false;
+ case DockerContainer::Socks5Proxy: return false;
default: return true;
}
}
diff --git a/client/containers/containers_defs.h b/client/containers/containers_defs.h
index f80cc097..a63e217b 100644
--- a/client/containers/containers_defs.h
+++ b/client/containers/containers_defs.h
@@ -28,7 +28,8 @@ namespace amnezia
// non-vpn
TorWebSite,
Dns,
- Sftp
+ Sftp,
+ Socks5Proxy
};
Q_ENUM_NS(DockerContainer)
} // namespace ContainerEnumNS
diff --git a/client/core/controllers/serverController.cpp b/client/core/controllers/serverController.cpp
index 12ede703..081d86d6 100644
--- a/client/core/controllers/serverController.cpp
+++ b/client/core/controllers/serverController.cpp
@@ -106,7 +106,7 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti
if (e)
return e;
- QString runner = QString("sudo docker exec -i $CONTAINER_NAME bash %1 ").arg(fileName);
+ QString runner = QString("sudo docker exec -i $CONTAINER_NAME sh %1 ").arg(fileName);
e = runScript(credentials, replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
@@ -376,6 +376,10 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
return true;
}
+ if (container == DockerContainer::Socks5Proxy) {
+ return true;
+ }
+
return false;
}
@@ -516,6 +520,7 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
const QJsonObject &amneziaWireguarConfig = config.value(ProtocolProps::protoToString(Proto::Awg)).toObject();
const QJsonObject &xrayConfig = config.value(ProtocolProps::protoToString(Proto::Xray)).toObject();
const QJsonObject &sftpConfig = config.value(ProtocolProps::protoToString(Proto::Sftp)).toObject();
+ const QJsonObject &socks5ProxyConfig = config.value(ProtocolProps::protoToString(Proto::Socks5Proxy)).toObject();
Vars vars;
@@ -613,6 +618,14 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
vars.append({ { "$UNDERLOAD_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::underloadPacketMagicHeader).toString() } });
vars.append({ { "$TRANSPORT_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::transportPacketMagicHeader).toString() } });
+ // Socks5 proxy vars
+ vars.append({ { "$SOCKS5_PROXY_PORT", socks5ProxyConfig.value(config_key::port).toString(protocols::socks5Proxy::defaultPort) } });
+ auto username = socks5ProxyConfig.value(config_key:: userName).toString();
+ auto password = socks5ProxyConfig.value(config_key::password).toString();
+ QString socks5user = (!username.isEmpty() && !password.isEmpty()) ? QString("users %1:CL:%2").arg(username, password) : "";
+ vars.append({ { "$SOCKS5_USER", socks5user } });
+ vars.append({ { "$SOCKS5_AUTH_TYPE", socks5user.isEmpty() ? "none" : "strong" } });
+
QString serverIp = NetworkUtilities::getIPAddress(credentials.hostName);
if (!serverIp.isEmpty()) {
vars.append({ { "$SERVER_IP_ADDRESS", serverIp } });
diff --git a/client/core/scripts_registry.cpp b/client/core/scripts_registry.cpp
index 4e720845..95b5df4a 100644
--- a/client/core/scripts_registry.cpp
+++ b/client/core/scripts_registry.cpp
@@ -18,6 +18,7 @@ QString amnezia::scriptFolder(amnezia::DockerContainer container)
case DockerContainer::TorWebSite: return QLatin1String("website_tor");
case DockerContainer::Dns: return QLatin1String("dns");
case DockerContainer::Sftp: return QLatin1String("sftp");
+ case DockerContainer::Socks5Proxy: return QLatin1String("socks5_proxy");
default: return QString();
}
}
diff --git a/client/protocols/protocols_defs.cpp b/client/protocols/protocols_defs.cpp
index 9373c8bb..bcae339c 100644
--- a/client/protocols/protocols_defs.cpp
+++ b/client/protocols/protocols_defs.cpp
@@ -77,7 +77,8 @@ QMap ProtocolProps::protocolHumanNames()
{ Proto::TorWebSite, "Website in Tor network" },
{ Proto::Dns, "DNS Service" },
- { Proto::Sftp, QObject::tr("Sftp service") } };
+ { Proto::Sftp, QObject::tr("Sftp service") },
+ { Proto::Socks5Proxy, QObject::tr("SOCKS5 proxy server") } };
}
QMap ProtocolProps::protocolDescriptions()
@@ -102,6 +103,7 @@ amnezia::ServiceType ProtocolProps::protocolService(Proto p)
case Proto::TorWebSite: return ServiceType::Other;
case Proto::Dns: return ServiceType::Other;
case Proto::Sftp: return ServiceType::Other;
+ case Proto::Socks5Proxy: return ServiceType::Other;
default: return ServiceType::Other;
}
}
@@ -113,6 +115,7 @@ int ProtocolProps::getPortForInstall(Proto p)
case WireGuard:
case ShadowSocks:
case OpenVpn:
+ case Socks5Proxy:
return QRandomGenerator::global()->bounded(30000, 50000);
default:
return defaultPort(p);
@@ -135,6 +138,7 @@ int ProtocolProps::defaultPort(Proto p)
case Proto::TorWebSite: return -1;
case Proto::Dns: return 53;
case Proto::Sftp: return 222;
+ case Proto::Socks5Proxy: return 38080;
default: return -1;
}
}
@@ -154,6 +158,7 @@ bool ProtocolProps::defaultPortChangeable(Proto p)
case Proto::TorWebSite: return false;
case Proto::Dns: return false;
case Proto::Sftp: return true;
+ case Proto::Socks5Proxy: return true;
default: return false;
}
}
@@ -175,6 +180,7 @@ TransportProto ProtocolProps::defaultTransportProto(Proto p)
case Proto::TorWebSite: return TransportProto::Tcp;
case Proto::Dns: return TransportProto::Udp;
case Proto::Sftp: return TransportProto::Tcp;
+ case Proto::Socks5Proxy: return TransportProto::Tcp;
}
}
@@ -195,6 +201,7 @@ bool ProtocolProps::defaultTransportProtoChangeable(Proto p)
case Proto::TorWebSite: return false;
case Proto::Dns: return false;
case Proto::Sftp: return false;
+ case Proto::Socks5Proxy: return false;
default: return false;
}
return false;
diff --git a/client/protocols/protocols_defs.h b/client/protocols/protocols_defs.h
index c98735b0..56be0d7d 100644
--- a/client/protocols/protocols_defs.h
+++ b/client/protocols/protocols_defs.h
@@ -84,6 +84,7 @@ namespace amnezia
constexpr char awg[] = "awg";
constexpr char xray[] = "xray";
constexpr char ssxray[] = "ssxray";
+ constexpr char socks5proxy[] = "socks5proxy";
constexpr char configVersion[] = "config_version";
@@ -216,6 +217,14 @@ namespace amnezia
constexpr char defaultUnderloadPacketMagicHeader[] = "1766607858";
}
+ namespace socks5Proxy
+ {
+ constexpr char defaultUserName[] = "proxy_user";
+ constexpr char defaultPort[] = "38080";
+
+ constexpr char proxyConfigPath[] = "/usr/local/3proxy/conf/3proxy.cfg";
+ }
+
} // namespace protocols
namespace ProtocolEnumNS
@@ -244,7 +253,8 @@ namespace amnezia
// non-vpn
TorWebSite,
Dns,
- Sftp
+ Sftp,
+ Socks5Proxy
};
Q_ENUM_NS(Proto)
diff --git a/client/resources.qrc b/client/resources.qrc
index 49fd66d3..84296462 100644
--- a/client/resources.qrc
+++ b/client/resources.qrc
@@ -198,7 +198,7 @@
ui/qml/Pages2/PageProtocolOpenVpnSettings.qml
ui/qml/Pages2/PageProtocolShadowSocksSettings.qml
ui/qml/Pages2/PageProtocolCloakSettings.qml
- ui/qml/Pages2/PageProtocolXraySettings.qml
+ ui/qml/Pages2/PageProtocolXraySettings.qml
ui/qml/Pages2/PageProtocolRaw.qml
ui/qml/Pages2/PageSettingsLogging.qml
ui/qml/Pages2/PageServiceSftpSettings.qml
@@ -239,5 +239,10 @@
images/controls/alert-circle.svg
images/controls/file-check-2.svg
ui/qml/Controls2/WarningType.qml
+ ui/qml/Pages2/PageServiceSocksProxySettings.qml
+ server_scripts/socks5_proxy/run_container.sh
+ server_scripts/socks5_proxy/Dockerfile
+ server_scripts/socks5_proxy/configure_container.sh
+ server_scripts/socks5_proxy/start.sh
diff --git a/client/server_scripts/socks5_proxy/Dockerfile b/client/server_scripts/socks5_proxy/Dockerfile
new file mode 100644
index 00000000..7a38682f
--- /dev/null
+++ b/client/server_scripts/socks5_proxy/Dockerfile
@@ -0,0 +1,10 @@
+FROM 3proxy/3proxy:latest
+
+LABEL maintainer="AmneziaVPN"
+
+RUN mkdir -p /opt/amnezia
+RUN echo -e "#!/bin/bash\ntail -f /dev/null" > /opt/amnezia/start.sh
+RUN chmod a+x /opt/amnezia/start.sh
+
+ENTRYPOINT [ "/bin/sh", "/opt/amnezia/start.sh" ]
+CMD [ "" ]
\ No newline at end of file
diff --git a/client/server_scripts/socks5_proxy/configure_container.sh b/client/server_scripts/socks5_proxy/configure_container.sh
new file mode 100644
index 00000000..d271b65e
--- /dev/null
+++ b/client/server_scripts/socks5_proxy/configure_container.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+echo -e "#!/bin/3proxy" > /usr/local/3proxy/conf/3proxy.cfg
+echo -e "config /usr/local/3proxy/conf/3proxy.cfg" >> /usr/local/3proxy/conf/3proxy.cfg
+echo -e "timeouts 1 5 30 60 180 1800 15 60" >> /usr/local/3proxy/conf/3proxy.cfg
+
+echo -e "$SOCKS5_USER" >> /usr/local/3proxy/conf/3proxy.cfg
+
+echo -e "log /usr/local/3proxy/logs/3proxy.log" >> /usr/local/3proxy/conf/3proxy.cfg
+echo -e "logformat \"-\\\"\"+_G{\"\"time_unix\"\":%t, \"\"proxy\"\":{\"\"type:\"\":\"\"%N\"\", \"\"port\"\":%p}, \"\"error\"\":{\"\"code\"\":\"\"%E\"\"}, \"\"auth\"\":{\"\"user\"\":\"\"%U\"\"}, \"\"client\"\":{\"\"ip\"\":\"\"%C\"\", \"\"port\"\":%c}, \"\"server\"\":{\"\"ip\"\":\"\"%R\"\", \"\"port\"\":%r}, \"\"bytes\"\":{\"\"sent\"\":%O, \"\"received\"\":%I}, \"\"request\"\":{\"\"hostname\"\":\"\"%n\"\"}, \"\"message\"\":\"\"%T\"\"}\"" >> /usr/local/3proxy/conf/3proxy.cfg
+echo -e "auth $SOCKS5_AUTH_TYPE" >> /usr/local/3proxy/conf/3proxy.cfg
+echo -e "socks -p$SOCKS5_PROXY_PORT" >> /usr/local/3proxy/conf/3proxy.cfg
\ No newline at end of file
diff --git a/client/server_scripts/socks5_proxy/run_container.sh b/client/server_scripts/socks5_proxy/run_container.sh
new file mode 100644
index 00000000..38ff863a
--- /dev/null
+++ b/client/server_scripts/socks5_proxy/run_container.sh
@@ -0,0 +1,5 @@
+sudo docker run -d \
+--restart always \
+-p $SOCKS5_PROXY_PORT:$SOCKS5_PROXY_PORT/tcp \
+--name $CONTAINER_NAME \
+$CONTAINER_NAME
diff --git a/client/server_scripts/socks5_proxy/start.sh b/client/server_scripts/socks5_proxy/start.sh
new file mode 100644
index 00000000..98555d4e
--- /dev/null
+++ b/client/server_scripts/socks5_proxy/start.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# This scripts copied from Amnezia client to Docker container to /opt/amnezia and launched every time container starts
+
+echo "Container startup"
+
+/bin/3proxy /usr/local/3proxy/conf/3proxy.cfg
\ No newline at end of file
diff --git a/client/ui/controllers/installController.cpp b/client/ui/controllers/installController.cpp
index e743d22c..514091d4 100644
--- a/client/ui/controllers/installController.cpp
+++ b/client/ui/controllers/installController.cpp
@@ -123,6 +123,9 @@ void InstallController::install(DockerContainer container, int port, TransportPr
} else if (container == DockerContainer::Sftp) {
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
containerConfig.insert(config_key::password, Utils::getRandomString(10));
+ } else if (container == DockerContainer::Socks5Proxy) {
+ containerConfig.insert(config_key::userName, protocols::socks5Proxy::defaultUserName);
+ containerConfig.insert(config_key::password, Utils::getRandomString(10));
}
config.insert(config_key::container, ContainerProps::containerToString(container));
@@ -362,7 +365,7 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
if (containerInfo.isEmpty()) {
continue;
}
- const static QRegularExpression containerAndPortRegExp("(amnezia[-a-z]*).*?:([0-9]*)->[0-9]*/(udp|tcp).*");
+ const static QRegularExpression containerAndPortRegExp("(amnezia[-a-z0-9]*).*?:([0-9]*)->[0-9]*/(udp|tcp).*");
QRegularExpressionMatch containerAndPortMatch = containerAndPortRegExp.match(containerInfo);
if (containerAndPortMatch.hasMatch()) {
QString name = containerAndPortMatch.captured(1);
@@ -427,6 +430,20 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
containerConfig.insert(config_key::userName, userName);
containerConfig.insert(config_key::password, password);
+ } else if (protocol == Proto::Socks5Proxy) {
+ QString proxyConfig = serverController->getTextFileFromContainer(container, credentials,
+ protocols::socks5Proxy::proxyConfigPath, errorCode);
+
+ const static QRegularExpression usernameAndPasswordRegExp("users (\\w+):CL:(\\w+)");
+ QRegularExpressionMatch usernameAndPasswordMatch = usernameAndPasswordRegExp.match(proxyConfig);
+
+ if (usernameAndPasswordMatch.hasMatch()) {
+ QString userName = usernameAndPasswordMatch.captured(1);
+ QString password = usernameAndPasswordMatch.captured(2);
+
+ containerConfig.insert(config_key::userName, userName);
+ containerConfig.insert(config_key::password, password);
+ }
}
config.insert(config_key::container, ContainerProps::containerToString(container));
@@ -603,6 +620,10 @@ void InstallController::clearCachedProfile(QSharedPointer serv
int serverIndex = m_serversModel->getProcessedServerIndex();
DockerContainer container = static_cast(m_containersModel->getProcessedContainerIndex());
+ if (ContainerProps::containerService(container) == ServiceType::Other) {
+ return;
+ }
+
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
ServerCredentials serverCredentials =
qvariant_cast(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
diff --git a/client/ui/controllers/pageController.h b/client/ui/controllers/pageController.h
index 1fdb1e81..c9d655ba 100644
--- a/client/ui/controllers/pageController.h
+++ b/client/ui/controllers/pageController.h
@@ -35,6 +35,7 @@ namespace PageLoader
PageServiceSftpSettings,
PageServiceTorWebsiteSettings,
PageServiceDnsSettings,
+ PageServiceSocksProxySettings,
PageSetupWizardStart,
PageSetupWizardCredentials,
diff --git a/client/ui/models/protocols_model.cpp b/client/ui/models/protocols_model.cpp
index b2838ce3..32447cd4 100644
--- a/client/ui/models/protocols_model.cpp
+++ b/client/ui/models/protocols_model.cpp
@@ -86,6 +86,7 @@ PageLoader::PageEnum ProtocolsModel::protocolPage(Proto protocol) const
case Proto::TorWebSite: return PageLoader::PageEnum::PageServiceTorWebsiteSettings;
case Proto::Dns: return PageLoader::PageEnum::PageServiceDnsSettings;
case Proto::Sftp: return PageLoader::PageEnum::PageServiceSftpSettings;
+ case Proto::Socks5Proxy: return PageLoader::PageEnum::PageServiceSocksProxySettings;
default: return PageLoader::PageEnum::PageProtocolOpenVpnSettings;
}
}
diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp
index 17535e5a..3f167029 100644
--- a/client/ui/models/servers_model.cpp
+++ b/client/ui/models/servers_model.cpp
@@ -548,6 +548,8 @@ QStringList ServersModel::getAllInstalledServicesName(const int serverIndex)
servicesName.append("SFTP");
} else if (container == DockerContainer::TorWebSite) {
servicesName.append("TOR");
+ } else if (container == DockerContainer::Socks5Proxy) {
+ servicesName.append("SOCKS5");
}
}
}
diff --git a/client/ui/models/services/socks5ProxyConfigModel.cpp b/client/ui/models/services/socks5ProxyConfigModel.cpp
new file mode 100644
index 00000000..f68670df
--- /dev/null
+++ b/client/ui/models/services/socks5ProxyConfigModel.cpp
@@ -0,0 +1,80 @@
+#include "socks5ProxyConfigModel.h"
+
+#include "protocols/protocols_defs.h"
+
+Socks5ProxyConfigModel::Socks5ProxyConfigModel(QObject *parent) : QAbstractListModel(parent)
+{
+}
+
+int Socks5ProxyConfigModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return 1;
+}
+
+bool Socks5ProxyConfigModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!index.isValid() || index.row() < 0 || index.row() >= ContainerProps::allContainers().size()) {
+ return false;
+ }
+
+ switch (role) {
+ case Roles::PortRole: m_protocolConfig.insert(config_key::port, value.toString()); break;
+ case Roles::UserNameRole: m_protocolConfig.insert(config_key::userName, value.toString()); break;
+ case Roles::PasswordRole: m_protocolConfig.insert(config_key::password, value.toString()); break;
+ }
+
+ emit dataChanged(index, index, QList { role });
+ return true;
+}
+
+QVariant Socks5ProxyConfigModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() < 0 || index.row() >= rowCount()) {
+ return false;
+ }
+
+ switch (role) {
+ case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString();
+ case Roles::UserNameRole:
+ return m_protocolConfig.value(config_key::userName).toString();
+ case Roles::PasswordRole: return m_protocolConfig.value(config_key::password).toString();
+ }
+
+ return QVariant();
+}
+
+void Socks5ProxyConfigModel::updateModel(const QJsonObject &config)
+{
+ beginResetModel();
+ m_container = ContainerProps::containerFromString(config.value(config_key::container).toString());
+
+ m_fullConfig = config;
+ QJsonObject protocolConfig = config.value(config_key::socks5proxy).toObject();
+
+ m_protocolConfig.insert(config_key::userName,
+ protocolConfig.value(config_key::userName).toString());
+
+ m_protocolConfig.insert(config_key::password, protocolConfig.value(config_key::password).toString());
+
+ m_protocolConfig.insert(config_key::port, protocolConfig.value(config_key::port).toString());
+
+ endResetModel();
+}
+
+QJsonObject Socks5ProxyConfigModel::getConfig()
+{
+ m_fullConfig.insert(config_key::socks5proxy, m_protocolConfig);
+ return m_fullConfig;
+}
+
+QHash Socks5ProxyConfigModel::roleNames() const
+{
+ QHash roles;
+
+ roles[PortRole] = "port";
+ roles[UserNameRole] = "username";
+ roles[PasswordRole] = "password";
+
+ return roles;
+}
diff --git a/client/ui/models/services/socks5ProxyConfigModel.h b/client/ui/models/services/socks5ProxyConfigModel.h
new file mode 100644
index 00000000..fc6f2fd4
--- /dev/null
+++ b/client/ui/models/services/socks5ProxyConfigModel.h
@@ -0,0 +1,40 @@
+#ifndef SOCKS5PROXYCONFIGMODEL_H
+#define SOCKS5PROXYCONFIGMODEL_H
+
+#include
+#include
+
+#include "containers/containers_defs.h"
+
+class Socks5ProxyConfigModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ enum Roles {
+ PortRole = Qt::UserRole + 1,
+ UserNameRole,
+ PasswordRole
+ };
+
+ explicit Socks5ProxyConfigModel(QObject *parent = nullptr);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ bool setData(const QModelIndex &index, const QVariant &value, int role) override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+public slots:
+ void updateModel(const QJsonObject &config);
+ QJsonObject getConfig();
+
+protected:
+ QHash roleNames() const override;
+
+private:
+ DockerContainer m_container;
+ QJsonObject m_protocolConfig;
+ QJsonObject m_fullConfig;
+};
+
+#endif // SOCKS5PROXYCONFIGMODEL_H
diff --git a/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml b/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml
new file mode 100644
index 00000000..95343f63
--- /dev/null
+++ b/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml
@@ -0,0 +1,385 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import SortFilterProxyModel 0.2
+
+import PageEnum 1.0
+import ContainerProps 1.0
+
+import "./"
+import "../Controls2"
+import "../Controls2/TextTypes"
+import "../Config"
+import "../Components"
+
+PageType {
+ id: root
+
+ defaultActiveFocusItem: listview
+
+ Connections {
+ target: InstallController
+
+ function onUpdateContainerFinished() {
+ PageController.showNotificationMessage(qsTr("Settings updated successfully"))
+ }
+ }
+
+ Item {
+ id: focusItem
+ KeyNavigation.tab: backButton
+ }
+
+ ColumnLayout {
+ id: backButtonLayout
+
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ anchors.topMargin: 20
+
+ BackButtonType {
+ id: backButton
+ KeyNavigation.tab: listview
+ }
+ }
+
+ FlickableType {
+ id: fl
+ anchors.top: backButtonLayout.bottom
+ anchors.bottom: parent.bottom
+ contentHeight: listview.implicitHeight
+
+ ListView {
+ id: listview
+
+ width: parent.width
+ height: listview.contentItem.height
+
+ clip: true
+ interactive: false
+
+ model: Socks5ProxyConfigModel
+
+ onFocusChanged: {
+ if (focus) {
+ listview.currentItem.focusItemId.forceActiveFocus()
+ }
+ }
+
+ delegate: Item {
+ implicitWidth: listview.width
+ implicitHeight: content.implicitHeight
+
+ property alias focusItemId: hostLabel.rightButton
+
+ ColumnLayout {
+ id: content
+
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ spacing: 0
+
+ HeaderType {
+ Layout.fillWidth: true
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
+
+ headerText: qsTr("SOCKS5 settings")
+ }
+
+ LabelWithButtonType {
+ id: hostLabel
+ Layout.fillWidth: true
+ Layout.topMargin: 32
+
+ parentFlickable: fl
+ KeyNavigation.tab: portLabel.rightButton
+
+ text: qsTr("Host")
+ descriptionText: ServersModel.getProcessedServerData("hostName")
+
+ descriptionOnTop: true
+
+ rightImageSource: "qrc:/images/controls/copy.svg"
+ rightImageColor: "#D7D8DB"
+
+ clickedFunction: function() {
+ GC.copyToClipBoard(descriptionText)
+ PageController.showNotificationMessage(qsTr("Copied"))
+ if (!GC.isMobile()) {
+ this.rightButton.forceActiveFocus()
+ }
+ }
+ }
+
+ LabelWithButtonType {
+ id: portLabel
+ Layout.fillWidth: true
+
+ text: qsTr("Port")
+ descriptionText: port
+
+ descriptionOnTop: true
+
+ parentFlickable: fl
+ KeyNavigation.tab: usernameLabel.rightButton
+
+ rightImageSource: "qrc:/images/controls/copy.svg"
+ rightImageColor: "#D7D8DB"
+
+ clickedFunction: function() {
+ GC.copyToClipBoard(descriptionText)
+ PageController.showNotificationMessage(qsTr("Copied"))
+ if (!GC.isMobile()) {
+ this.rightButton.forceActiveFocus()
+ }
+ }
+ }
+
+ LabelWithButtonType {
+ id: usernameLabel
+ Layout.fillWidth: true
+
+ text: qsTr("User name")
+ descriptionText: username
+
+ descriptionOnTop: true
+
+ parentFlickable: fl
+ KeyNavigation.tab: passwordLabel.eyeButton
+
+ rightImageSource: "qrc:/images/controls/copy.svg"
+ rightImageColor: "#D7D8DB"
+
+ clickedFunction: function() {
+ GC.copyToClipBoard(descriptionText)
+ PageController.showNotificationMessage(qsTr("Copied"))
+ if (!GC.isMobile()) {
+ this.rightButton.forceActiveFocus()
+ }
+ }
+ }
+
+ LabelWithButtonType {
+ id: passwordLabel
+ Layout.fillWidth: true
+
+ text: qsTr("Password")
+ descriptionText: password
+
+ descriptionOnTop: true
+
+ parentFlickable: fl
+ eyeButton.KeyNavigation.tab: passwordLabel.rightButton
+ rightButton.KeyNavigation.tab: changeSettingsButton
+
+ rightImageSource: "qrc:/images/controls/copy.svg"
+ rightImageColor: "#D7D8DB"
+
+ buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
+
+ clickedFunction: function() {
+ GC.copyToClipBoard(descriptionText)
+ PageController.showNotificationMessage(qsTr("Copied"))
+ if (!GC.isMobile()) {
+ this.rightButton.forceActiveFocus()
+ }
+ }
+ }
+
+ DrawerType2 {
+ id: changeSettingsDrawer
+ parent: root
+
+ anchors.fill: parent
+ expandedHeight: root.height * 0.9
+
+ onClosed: {
+ if (!GC.isMobile()) {
+ focusItem.forceActiveFocus()
+ }
+ }
+
+ expandedContent: ColumnLayout {
+ property string tempPort: port
+ property string tempUsername: username
+ property string tempPassword: password
+
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.topMargin: 32
+ anchors.leftMargin: 16
+ anchors.rightMargin: 16
+ spacing: 0
+
+ Connections {
+ target: changeSettingsDrawer
+ function onOpened() {
+ if (!GC.isMobile()) {
+ drawerFocusItem.forceActiveFocus()
+ }
+ tempPort = port
+ tempUsername = username
+ tempPassword = password
+ }
+ function onClosed() {
+ port = tempPort
+ username = tempUsername
+ password = tempPassword
+ portTextField.textFieldText = port
+ usernameTextField.textFieldText = username
+ passwordTextField.textFieldText = password
+ }
+ }
+
+ Item {
+ id: drawerFocusItem
+ KeyNavigation.tab: portTextField.textField
+ }
+
+ HeaderType {
+ Layout.fillWidth: true
+
+ headerText: qsTr("SOCKS5 settings")
+ }
+
+ TextFieldWithHeaderType {
+ id: portTextField
+
+ Layout.fillWidth: true
+ Layout.topMargin: 40
+ parentFlickable: fl
+
+ headerText: qsTr("Port")
+ textFieldText: port
+ textField.maximumLength: 5
+ textField.validator: IntValidator { bottom: 1; top: 65535 }
+
+ textField.onEditingFinished: {
+ textFieldText = textField.text.replace(/^\s+|\s+$/g, '')
+ if (textFieldText !== port) {
+ port = textFieldText
+ }
+ }
+
+ KeyNavigation.tab: usernameTextField.textField
+ }
+
+ TextFieldWithHeaderType {
+ id: usernameTextField
+
+ Layout.fillWidth: true
+ Layout.topMargin: 16
+ parentFlickable: fl
+
+ headerText: qsTr("Username")
+ textFieldPlaceholderText: "username"
+ textFieldText: username
+ textField.maximumLength: 32
+
+ textField.onEditingFinished: {
+ textFieldText = textField.text.replace(/^\s+|\s+$/g, '')
+ if (textFieldText !== username) {
+ username = textFieldText
+ }
+ }
+
+ KeyNavigation.tab: passwordTextField.textField
+ }
+
+ TextFieldWithHeaderType {
+ id: passwordTextField
+
+ property bool hidePassword: true
+
+ Layout.fillWidth: true
+ Layout.topMargin: 16
+ parentFlickable: fl
+
+ headerText: qsTr("Password")
+ textFieldPlaceholderText: "password"
+ textFieldText: password
+ textField.maximumLength: 32
+
+ textField.echoMode: hidePassword ? TextInput.Password : TextInput.Normal
+ buttonImageSource: textFieldText !== "" ? (hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg")
+ : ""
+
+ clickedFunc: function() {
+ hidePassword = !hidePassword
+ }
+
+ textField.onFocusChanged: {
+ textFieldText = textField.text.replace(/^\s+|\s+$/g, '')
+ if (textFieldText !== password) {
+ password = textFieldText
+ }
+ }
+
+ KeyNavigation.tab: saveButton
+ }
+
+ BasicButtonType {
+ id: saveButton
+
+ Layout.fillWidth: true
+ Layout.topMargin: 24
+ Layout.bottomMargin: 24
+
+ text: qsTr("Change connection settings")
+ Keys.onTabPressed: lastItemTabClicked(drawerFocusItem)
+
+ clickedFunc: function() {
+ forceActiveFocus()
+
+ if (!portTextField.textField.acceptableInput) {
+ portTextField.errorText = qsTr("The port must be in the range of 1 to 65535")
+ return
+ }
+ if (usernameTextField.textFieldText && passwordTextField.textFieldText === "") {
+ passwordTextField.errorText = qsTr("Password cannot be empty")
+ return
+ } else if (usernameTextField.textFieldText === "" && passwordTextField.textFieldText) {
+ usernameTextField.errorText = qsTr("Username cannot be empty")
+ return
+ }
+
+ PageController.goToPage(PageEnum.PageSetupWizardInstalling)
+ InstallController.updateContainer(Socks5ProxyConfigModel.getConfig())
+ tempPort = portTextField.textFieldText
+ tempUsername = usernameTextField.textFieldText
+ tempPassword = passwordTextField.textFieldText
+ changeSettingsDrawer.close()
+ }
+ }
+ }
+ }
+
+ BasicButtonType {
+ id: changeSettingsButton
+
+ Layout.fillWidth: true
+ Layout.topMargin: 24
+ Layout.bottomMargin: 24
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
+
+ text: qsTr("Change connection settings")
+ Keys.onTabPressed: lastItemTabClicked(focusItem)
+
+ clickedFunc: function() {
+ forceActiveFocus()
+ changeSettingsDrawer.open()
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml
index 97288733..a0c668be 100644
--- a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml
+++ b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml
@@ -18,6 +18,8 @@ import "../Components"
PageType {
id: root
+ property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex())
+
defaultActiveFocusItem: focusItem
Item {
@@ -103,6 +105,7 @@ PageType {
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Xray: XrayConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Ipsec: Ikev2ConfigModel.updateModel(ProtocolsModel.getConfig()); break;
+ case ProtocolEnum.Socks5Proxy: Socks5ProxyConfigModel.updateModel(ProtocolsModel.getConfig()); break;
}
PageController.goToPage(protocolPage);
}
@@ -124,7 +127,7 @@ PageType {
Layout.fillWidth: true
- visible: ServersModel.isProcessedServerHasWriteAccess()
+ visible: root.isClearCacheVisible
KeyNavigation.tab: removeButton
text: qsTr("Clear %1 profile").arg(ContainersModel.getProcessedContainerName())
@@ -167,7 +170,7 @@ PageType {
Layout.leftMargin: 16
Layout.rightMargin: 16
- visible: ServersModel.isProcessedServerHasWriteAccess()
+ visible: root.isClearCacheVisible
}
LabelWithButtonType {
diff --git a/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml b/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml
index b694dda0..f27873c6 100644
--- a/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml
+++ b/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml
@@ -261,6 +261,11 @@ PageType {
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
+ if (!port.textField.acceptableInput) {
+ port.errorText = qsTr("The port must be in the range of 1 to 65535")
+ return
+ }
+
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.install(dockerContainer, port.textFieldText, transportProtoSelector.currentIndex)
}
From afdfbdbc59e1bb5e164378256adf9fbefd900aae Mon Sep 17 00:00:00 2001
From: albexk
Date: Mon, 17 Jun 2024 17:41:59 +0300
Subject: [PATCH 6/7] Update Android icons
---
client/android/res/mipmap-hdpi/icon.png | Bin 3338 -> 6616 bytes
client/android/res/mipmap-hdpi/icon_round.png | Bin 4225 -> 8393 bytes
client/android/res/mipmap-ldpi/icon.png | Bin 1984 -> 2686 bytes
client/android/res/mipmap-ldpi/icon_round.png | Bin 1723 -> 3198 bytes
client/android/res/mipmap-mdpi/icon.png | Bin 3517 -> 3918 bytes
client/android/res/mipmap-mdpi/icon_round.png | Bin 2624 -> 4798 bytes
client/android/res/mipmap-xhdpi/icon.png | Bin 9958 -> 9472 bytes
.../android/res/mipmap-xhdpi/icon_round.png | Bin 5543 -> 12311 bytes
client/android/res/mipmap-xxhdpi/icon.png | Bin 19030 -> 15513 bytes
.../android/res/mipmap-xxhdpi/icon_round.png | Bin 8247 -> 21130 bytes
client/android/res/mipmap-xxxhdpi/icon.png | Bin 30603 -> 22335 bytes
.../android/res/mipmap-xxxhdpi/icon_round.png | Bin 11186 -> 30527 bytes
12 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/client/android/res/mipmap-hdpi/icon.png b/client/android/res/mipmap-hdpi/icon.png
index d0f203630e5ec2ec3b1985288cefe1b86bb047e7..f1bf806b8555b06e9864ecb2c9e114cca0b188d1 100644
GIT binary patch
literal 6616
zcmZ9RWl$Sjv&RDjha!QX#U&I9DFlZ=&;%=1+}+*Xixg>aD-PwswP-2Dp-6!iit|8m
zio4yub7$U}duQkDe`e48=Ko>8oUfZ{k7fMwgcL#@zgoqzbT~`VKP`9Dv5ZZnV%enq3ra!#5rLI0de7bm1+4)1$QIT7Q
z(1OeY-|U->ldQ@h4Km%GJX1h0PSVnnQy@uFEk@)+V?G7LqB*?`{g
z;RrgJ&e@MG%H5AYKds(u%q{P^JcKOwxI}3QuKr{CrswKU_fg)F`1X?LWcN$no_mi0
zJUnLVgoZ1QK*?W1N{QsVUHgPT%41$NqOUMo2n_eT4F(I8at#W(%M^mg8|KpgsFqD4
zi-s<-V=;SzOz}#~UuRz%9Q{ygtiCMFn6RvKY!^O#oZ>q-o}RIBA9-28MkJ9I|DrWe
zYNYa~g2^y~ljWbB;&9z!{|Ww#r-@Le*}?7CAI9zEj=M>W`lRdtmP<|N^?
zEHNj@tH@)m=DgZ~j{D8)HE=fEm270trYi_zxp|P?QR1Dgd#b%SedJ0)y2_S*Spg}z
z_{%k2d|M*MiX;`yQZ{nqLFuNg@Gruxd9wq-b2}3~
zeUSWS9E_b~PWJXU@D)*z&PovHG<4+ZLj468lA+XAt4s>ix~0}qrD|?%ZRH~|*3NMr
z?3DT?BpVw8pABv
z-HlW&wm10UYs8d!*1yo=$laQUTpuCj?@~%;!JI71dcKy#7n1mUZdG9?5a{xL>PpcU
zP3yxFUI*l+@4cl#Nw006-S_p}3#^7*-$4p_^FJIv9EDd`|6EwO{cVs|o1W5eSj@x(
z0iT>?_NJ&tPpvp`&J+8QC;
z+CA_c#0gaesgC9hXR(=o&}*_8PvfyG7JAP}+QDn{0@c?g+FboP>ZfwXjELj2mkUl^
z7U5G@4lK)w6ju`yQwKY8WY%;4R1HZ5#_-)w)}3xPEp8rBK&VgjPlu1)ZlQ)h9<`{e|abz|4i0SR=5nsVk6L8i)O(!$r7
zp||kR3*S`$Q@)C7`a7k`rft=;)bSYZ-mxt`znKf3yJZqfHu5$seWl=s>j9Pkz4o61
z3@XHzHpX2{R#tjRr~VM|b#mzWTZz*eT$C98EiMj6S|H1^g3RZ+%D@9pDN`m%M~<;S
zpFw=NtX|9Ot(f7J2Pl1#G*2=q9l!54N6A5q0XS_3G5a^`z6=%yTA+%Fyuq3VD}D_+
zQIl<@kC&K~^1uOd4eI*K)X=c}k#{T=)gSvw!5uChCIlRUu!o@iX(Et4ds}IDx=Qf#
z;WNh|4GNjpjD)&%TPH^n{Vlq+oasnS2)LqDOBD>G;f}utz=$QY*NPWii-MPFmx3O<
zd`7IWd{|Ulw_z4hA97rn)U7%v&Dha>SKfW4ck`VRx6x8oL&=PT`*1>4V!KM12a$#b
zeaY?Zj$T^|qr|01F5@ziBcFr5sXTD?W`yKA%t#b9}
z-yDyN+ftL+wXCt_IItlac3t|RNcR!T)uKrHgM-q|j#L7&ZGF-WvtoX1Y4sOHX%@YS
zbLM5!atQS#!bm6xA2wrkXDRjX>f>0b^-L|#$QonlHG~fCA-;OMuqsVmEC?$cc}3H*@A0c_-*0Ds^^1_|
z?b*$VcWe$-uoA$K}GzbDC8O
z!qXyfA0Lmd*Oq-7Ll<@I{!tWo=lKU5Q)nM_zD05}pUF_jm0Hxvr%0WS?}jCBimyhs
z=A;oGpPd?~zeH_0{3_vxL;q}}$K@&ZmZ`5`0^ASl^S(?FuVTag{*L7Iz}8()f5Y4g
z)35okDcCnTv}hGCtD7=_y0x!J*tC~>6AI#5S_0I;PoN#YNeT4K`gshyy0+9mtrjalZgb2s)i=eDnHO$iyWjY95Eq
zrmw&hTz^v=W_*P$;i3HHcMWqtLD|G^=t{H3c);LKUlyq^ND-cn3yv-$hOeH3yR&od
zHmevP?oP4Vx`WwrXfcix{1?EcDwc~pOETa}6fpk5&_qsn)SHnr-+Yd6(&OaNcSa(R
z;fx2P5;$k-El47Hi-nHsKMu^Hr5&asxIfvJO4#H^<8*B-m
z%p5&%wsy6XR2>;-OuBp#IpK~yqX_VRJZ0}4ltc$Hjm(=3lgZyz&g#Tqp5+niPK($I
zAsR%!*6@2V?rl`JWoAz7r*WA#}gP?jB0^w0PnrTI9Oxa#?HV
z?G%>mt!c_}Q+eJMD-QP)P~!RurDs>(N|F5d
z2q20a%Y@ZCn6t(V%ZBo;hN2oT%}0D&?IFzeUeZ)07ip>4D~dloO6?oZ`#vQaMCXnG
zqd%C0-2CVnI6NFus+hdM$08cC`QCAnh7(UQ2_(%v2z4fOaRF5B_cDi;~LhS$!NAfcbZW$dxF^YVqH*<@P{W(_(Qgog0i0a
zH`zR*i6^cBJE{nKbW!_@z0nIMv
zeG~_^hH~E~v`G#!&=6sjDgaUulw&+bwgNC{jpSy-MmQ
zpTo@&&Vv3|s=USxQCrwFA=mSBB3%^;gE6p+rUd{l!H|YxYnZN#U0534P*hOT+OjcZ
zH9CeO*=c36{FB-=Tr#?}l|L5VsPU362(cz`v_%*DJhxt3jw+%9*wDK8G|sa%(aaQzV;;lw
z{IV-J%GM+(H*-Z|_)lMjhQ{!O>yiq;Jvkno+VicxnhL$3MAZ_|*^YPwoa!CE8gjR#
z101$}XVmP*Oo)jns(Y&^FR}|;TwRv+^$F|f=y<`VY~xeS1|}$T+<_!@cc!mA^3rn>
zhkt>AW`(`nMjElJ4O$|0XKdDP;E!uOmG&uKL^!7yhASf9mgrJRxkFB8g&2bFb)A+y
z-$CM0B48P%>7?j@1Z`F`Pc!7T!tu4iefmCU5pg72pYc22oJ<
z28_ZY8nM8uBl*!$$|0unVXN{PiJC~{O(8->Wx-`Trs^}YoGUV4$&8lEOS1Q0Y=#&U
z7TqFRbq=Kx=9d@)Lywz*P6779-u7?HZ($ue8NI|59UP=Z3GrB8CqBh4vxqLUfWE$7
z(V*X+Wt~xNgZSIUVD`f>bmmVZoVx#
zq!`WeB7l_BzLBaJdu<-AH;}f3*`B8?+x?~Wz@uD}y15V9e--={&qjD({oKzxkaL`v
z3!NmoS27p|zLUEPL6LG>NCB2vtiQ&=2TZ#@LN7+QnXAaPYqliLCE{hA#N!T|Q^tnm
zkT5T!Irf4hc}A^+cx~x5D)$4Ng&AGwu}e6V+9=5mz)Z%hL3WOg*4i%I7t7&rUxwe_
zdTbK<2d#1@SsEA^Wc`%Dl7D|AU}5*o?W8!{X*G}t2cH%#tYbz)+oA5)0O-CqqCLKH
zg>*DVw0b!QT7uNhWMel{v^($@QKUfjG|aw~O;7)?^-=a2p4re-{1Wn<<{i8Ch%!%C
zc5}h?x7gGIj&{@1bI<=p4}A~M_hMKl(=I1?#pfDJ}O<+K^b>gl%&QvNmQ_@3ZWc`dFGo*M>hY_RCR4mg%LH3eeFyEnbTpqPA;?mQZ+F%uAJ}G0oPmKBRkR=%9)$!)$
zg4Dofd*`|N?(O?Ll{PSUYU<`_!c*+ea_hFoc_LlKfq3Cd_-N4vpN7{RQd~e!Y#Thv
zOy)IibN3ipwsVnEPsc&YrpRJW*X3THsVgKocALRcJA2F;DGugl@WY+}7p-yE9;P5c
z5xoX0Q$Sz-imCoAnLZ%(&;W}OpYn9}pkURLS4tiasVqv=7uBRCPDxzNGu#BC*yWB5V3-mA-JCB
z$6&4IwC~M^4;XS%TxR(P7W?WDO_MRR^C>IO@Vn^wN(s>N$rRO(!~S-~zOmlcVO~HG
z?JO3@fvcK@ECb1td4g-cxM16sD{SOZNUk#|xk%-}{Og8Aj_=8OwK^?h)H>zhOP!h)
zN&`7yy+vNGX9med7#u+l=_!BEU(>dSvK`cw-sEhtYEv|LtSjnwZf-y*X9}bcp_h>E
z_7Xi*LRr;M%bjPRx5@qBO$)kc6(Nlm&&>3>Y*b98*8=e{WR#M84rTD1M{5PiY0Y*c
zo-Q2v--4A@RMn5o0~C(ix!JfEN8S0}jR_QNeCcr^xq17^V((xS)z_$izSbtIa?-N68yLDWQDR3_GPIw2eP@UHct@K5Fi1pFQ
zGqx-Nu}>3v@cxbJ$9iz8rrY&(RhQ@AC$0QWPFxY)jzMsH5y<^|D)(Udj9)p^Sg{By
zU8!yL7{PrrteBgkNe(1K;O&+c7V*A4B4O&EB{52h2Ey>^R^!^N_5F=PRW9H2GaG6L
zo$iKJlO#^`Z)&3}zDmuanEHjP@@J=^M5&o30a4l=*{#`QC*3?UTUnA-Sd&!!4a)n?
zDXke{B5>XF4pLqrpyJ!P~IL!||_i_@Ww@O{t^QbKwj~cgNa~^jAc5
zlibG#<*x2?#-XDz+*=?ZR=-9Z69pbdN3Aq|6tsaS*GVX$_VvrB$|wr}N^&q+nz5wE
zvNs7tmV6X%uM(R>c%BY5=P*vxpHW%6lm8H~mrF0voExPD4`z=e%QZe>Q>^q7**-pG7#Vo%oej@
zbOOdXMbUTgQfT_b72K+^`i&+JLZUp=`YX4hMMwyg!+5bLK$~?6^mi_kgFYnYVv8zN
zhnVSuO>fVh)QpXnk9!FHnC&oKOdY>>F%dHy_?>tQ!5gx-eLoZmRHa@}m`h9~P(%?d
z2t?fdvPBN&r-z?^PkDQuYeZ4CE
zVQ@=`1=C5gyf@9L=^IB08gG>xfe4YQ}HL-mD$eo(E5Vc^8QE#N^xA
zw#_yD0wvB^*hfwR2>e-IujL=I?TNihqfNvgc?bLLAK2weE=wxoQ~#I&LkM87?~KXk
z4X5uXv*=N(#U84k7djW#2&8YjISZG$JcGhlrz|2#qkk~1=McCs)GNlb1GR!7pO~(B
znki!ny$&XOr5w#Q9Jkd}`5bc8A3gIh4!uPV{~B%eWwV#50ce>9zAcFIP7JVmFnwJwgW^X@ib^`RdmMr+Ixz^p3?cb
z=Vu9#WVx3&UYFcNs_0fW=j`wNY{YJ=BfchA?UwEMG7XLL}1f5
zz?xmp+^qDp3B6+(+b@$>H$i5J<6R2jOg0gtr%;E5A0L0ZNnF2Q`^P8ln54%&K_iB?z2PPUf=`@d1;+Lowp>eD
z8cmy}UM}|b{*#E|WE@}K?!WVw&8MR62$q=ji0sPr(9{8@xL;hjyYI_g93n(wqC`W)
z&K4uo-dHtkAOx!7Hd1MRd`jj~!Mc57
z4BA~Riss=m{JYj*_mbE1vNHFw7PIuQ{wn}}C_n5aROsa^VeMBiF@7O2K`1vADh7pK
z<%IwEKY+8VmA#Gs{|7|Gp#1*}D7u3){{oQzI(XSTTYGw$JG=cKMo{b(|9?&LRB`{a
Pw*jE!)#Per%p(2=LxpR&
delta 3334
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
IM6N<$g5_QSWB>pF
diff --git a/client/android/res/mipmap-ldpi/icon.png b/client/android/res/mipmap-ldpi/icon.png
index 00b978f5ec255ca0c3fe63be100c481d11b850eb..354d642d46bda0ee071a33880da86811aeab0e29 100644
GIT binary patch
literal 2686
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
literal 1984
zcmV;x2S50UP)Y%(yV+D6;K=rp0xPGy_=XO+4i{jsUrwEjW+
zwU0lWkhZB68`Zj1EJf-%w8A8W2%=$WlL8^6goeZp`JhRhIA8XAd%xfNnp`D*?|tvb
zIp;agIrqGzwRM|A2m#?gpcJCVx@@32`Y9UgnlXP+z6Ek8|7A_=;nR9f&1~?b@VkP=
zktl7pa6YdDX`xj03A_h*4k{I{-|}@nO1;8uWAz+W%~e#M@U`b&A#xqpLZCtQIeMjl
zgy^&7D{UCx=acCBG+d&tHw~&@_13P%n0+9Sp6^wlp+dBB1uLOO?&~>O>wlPyYVm&
zT#h)7<1tDLmWr@H76sJSkjv0k+dA0HZ`rj6dk%jOiDa{woEaNMav_VM>jUU{?>&@8
zgMk+O9p{Q8#0!+T0#X3Pq$SrAet}4swx;)zrd_+y+_)3LaKwXBDqexEst_h7vpD{f
zmobsedJwd&hf8om9({D1h67S#?K7$rkQ0Z0cLI?_0_8M>7_CBSi~4;y))*80+~Oi$
z{q+gFfAL}o0-D$kw9K-qs_I{Am-lZD
z42r~dg5bI7+39>ngpcH$an1nDdx5O~d#>)fP4
zTGC&^_U{}LdeBIDhFPE?vDU{NJ74
zhfU0iBk5MQ`vDF#`|)hkJQ88x?mWn9L1n@ca+sXJqo?E9Z%N_*Igh?me;0n+{8$H8
z<_j3^y)5R&Zw{g(=rDn4sA$ERf4@tIKkY@JW*TLoDZKQ|myk+^@tZ3Yrw1u=tI|d;
z&Tm=nxnPp1U1U>j0*lkL7&vnl3O2H}eIM4Ainu#))u8tJn}5TPj~~OUue?AeGE+Ey
z^hwfCT>&~bj^bvBC@w`8_v|$ZbgAb!1{C^d%BLH`jL8)+FoIh
z7#hBhk^f)E&wkq@#$Cw@a1YX(pzcgXPsZewZ#~
z=u1y;A%}NVX+LT+Pa7!AAvQ~mefnp`0kx-oM?f4AV#CWk>QZ@01Bl>-J=JCO&Wk@v;bk##Vc{@E&q_D1O
zmj}cpAy*_6jH7qpFT&EzTiTIMe;+$LpGH1Ehd_wsvj?LlS`-M-*+Zjpda%d@`|;;P
z^5~O&4l+5jUd6v#KlpW_!3Q&QccfWtI5B>m-nj8T`Fi(0_9lTyXchhJFjZ2SJ$8}G
zTQ=vK)W^tovaev!(q$XZvQRN!7LUhY<4CIPWY+TW~0e|cn!oSXjk*afWps|R}mBf%tTI=A#og&T-JCrFwQVl-*{+j`~MUAJ>
zHFbgC>rZNxVKOmouUW^)?QyYwVm41EW`UmTFc(TglwfgCI
ziO0oQ7b3}I6Se$qVA74jNN>$@%6%{Zot
zQSZ$cliN1ZO{8Bd_fwB+Z4Q(ajMVed36pG~KTbSQLdCW9DTY$Fs`VRvtWuv|Y+Gif
zSyu+A^^K_4NLkh%SSW3zto^MhOEMe0jmhZ6+G~kiW+CXY&Jv~tszl^yROshHc6VtC
SSG6nv00009nHmD
z0MgPfgvSo0uMGhHf&dWw3II+ntl)J3z(@eVrZoT{E^gS}vYPc2FBUYmS{mxWpMNU1
ztt9cnx#Wg2^#lM0mVX)qWMn}vOj<8ZZ6xhF4HF|+N|QSWcCpjcR97`H`4E&A5N$s0
z*NL5P@_GEk`>|Dx!s)(}D;<$>!aKK7Q!1%&0#@fLurmsAGQ2)stLC!-
zBk~=4ZNomXyBY-IgpRrj8x>k5ml9V_kr^VRq5wI_ETkst-JrMv{3%#ZBOUUF;s^Ja
zr!-=3VIhS@EMSuO@uDTuSI~YGT__I)VF^-7kJA>aqEvluuSkJZm8Usr#BZCzz%Ng93{JMgnSm7vxbg@zrKYziVBG0lVNWyJoe
z>qr4OHxkcBL0+v_zQXEk84m5rght>jLcx)!R2&RdRoYDTzS|tT2aGmDpXHG{5}C6c
z!1t(_Hq`7pBDV4i)%JKxnbCLmV7k48dUioF8QsDEV|F3
zs%+pn^}D1DIzAT`8#-zHraziIQKWL2>>$vV&&ejo+xL|59z-(Y7W>jhCrgthuvI~9|uSl=Zc{3Zn?t^u$HsptP9rStIpOo=eJ`EvVReF{#z
zMmzN1QT+|s$z7l3tJeDHl9=x+imZqqu}Aj`{B1CTSDyX&gzM~zw**Qsy_25G?LlyW
z8Gr3PO2y;lhk=J0${%mZjZLWQP4-|c4A>gHb{3nPA1w@WmH4ahg?0x=Y{}{;Mcl^S
z_m)(h46k#UIj81K^%-Td067VyYNzh!&=8_%nrbRI@OQ7@*@t0&f0pHt$G$!JW)>Ym
zyLf`;g5dpII$xki!VTC$a{Q}$*elZX`vntTJGn`u21!JIi+o6QRzNDKs}d
z7_#jZrTtjfJx@;J2CBVhH<;GU#R#<;GUP#2E1u9j|a0xzlhvIGW5d{}R_joPuP90xK72l5MR%@LmlT9mYdtYr5Rzg$1-N@RtZ
zKKT6k#gEGd)C$l$?paN5q6{X-B<0})3@=9>&QABs?)*`FPp}$}%kfPr!R}(LL8DaW
zh~C|u*vf70xdoDG5gfeGnZWj3u;Le!?Rwqt6fW}z^6kH-C{^givzOP~KS&So%~nx#oX^`Z
zzXM|yc&+*9)sl~ROSYjg6(XufEwtSO_1tGKK-LYL3cg5P`x`W^v!FoE}3$Cf#OXE@!(nG%Otk9ui
zp&Q*S_}X`gs-{Ltj*wSSp5nO{e!Ttgr8Hdq-TNs0OlSy>DeJo8@5i9YsGyaz{+4d<
zOX#rhTgui#f1Mk>X6l2hhOw+joP1qN|kM!}Mg#6alwH^$CapqY!v+pn6
zkH`8g+Q3~}!;?k7rDf~dC|s5C21PIQcj-ad42(xuj*4PF@Xd4F8>S?nA}Da=M|JUyo~A
z;rmkh8yxu1Iw}fY7dxA1UP!6!(U9DbuKS1#b#*M-Rdg0(xtMC)!(5amZ}jxRs5>Q?
zE$pG2hdt~PVW%a=fjll3rU+>0oF&Y+p4_SaN)@`hz44@f<>8dk)Q*AsZ^ZT5qaQd1
zw<7?1^;$_o*JndoF$@K?TD}LiS<;K#aMW|YOS2E)bEzqe;&2;s{J8UfpgDV%gh^l9n0v@b-Nh76vvn^b4&Ii!f4W
zW*l%&Iux|f(U~@9XDqF4pKmg
zr`j$LF&UM+6jaED7x-;%a`qKHhH_*&z&GLtt|gcXq(8h`GhlA!6h$BBN?++0hU^Lp
zzN}z11XJ2!t{P`APNDv;y~-Q1#O&;%q1W2RZgFl&Z`a!D=P>+teA%
zQ9ANxlUhy(ZC1JRB4^8LV6c}wtyGX#LM2s%K>5M;cy`UOadk?CIJ_dlr@l)M!;kd
zk`kg45(o*2EaqjVe*vz~?VTR`{eR$xu6g+dApE}sFDF+APcIu+w|_A*2uT=1M)JQQ
T2n6`-f&ny(KuIZj#`<
delta 1721
zcmV;q21fb*7`qK2iBL{Q4GJ0x0000DNk~Le0000W0000W2nGNE0CReJ^pRf}e*tq+
zM?wIu&K&6g000DMK}|sb0I`n?{9y$E00vM=L_t(|0i{=aY*SSj|FvDWbzQr5FT0hN
zyNx{)J67pu!-NHw{V*NIu&p|Bl2K`p2)9t0Q9!UYZYo${84{4Sme+aZ`1yIB$
z23tZEDWkHe%#ak&YPANUc{RLe925~UIWqH?BLvW6tfsPqDnPZANF>KYAy1f*2631O
znTrY$A~@NTEfH`+dQLvGGt)^bUbhKP7Cno|sA#V57#c(u+XS7p9S05_gxzir_Bl(U
zB-bA$0R^bTA;_7>GJ4D_ene6c3;NSq~
z15&B9JQ(@nO&hpc0x4P=jIa=MQ_wa=7u$$mKl>1)W|r$K6$*UyfAObysi;^;EPS~I
z5{6-Dj2;zQSiHRqNpog%?JJc>aQ@r<9)$7q
zN$9e3pin;nQ@wZhf3-gy=IT{1cz65#(JE}%ybT_Q6H2)pM?NaY#n0E`_~yBU*n@Vv
z$1k2s?O~)*B&0yzn$?KuwW0RMDm=J!i5t_W=D}`upuYMn*KfIf1Fmc5k;Tk{*Zgv<
ze69fD%os*(B8aR;So?bM>K8X*cX}qsr}s)2`N`oUPhl9$f9)Mc|9}}+edH7x^*mVb
zwxj()ePGPmZ6Q&Tf}J})Kw&{DX3vU;&Gry(TO*<@4cPJBai
zybu^utCJBG5rwWE6Ew-Qp^nocb!Hk-b_O>e85xPw=ju?ty9Sr*ZsC*H=VNt-2Zu^L
zc=Naj_j;!&f5A`%crS`1jfShuo&U#kR@P#SIqZm!jz#g(_1xHqvk%Q|Gt??IO=dWC
z`YhL{kf;*j?zw^s&2Bz&3RM^c(8KCTA$89H;#I_~smt($It|V~H=M)6F!lb0J9qws
z%jNJ&BINIHEki+;CZIq<&vkgz4xG3Wp_x?zVv@+jg5rfF4{TVkeKrL?=T`;x-~i3{mt5n$5Kk$()cX
z#k}NxSUTE}XuE}ct(c4ZtoUi)J1kY;#`uw$$@8&n`9{bRBnVT8apTS@G`7_sDo&1$
z-fM#7e-!&q-X!sF$HsgqmZor7o{ReqyPyS(5^@8oNGO*2cOETI#O?d%U^d^wtn?h{
zve|P+f0`b_o|=(hy9a%|N{I6~Vq#*FNPpqv
z1#AoTW)af$aR?tZLzBdyySo#;{kAE>DB=1%DPGG7<91GQ=(;PI0+kkvM5F5v^U|L~GYW%+>3#azgGf4=(
zOQK=R?^8UGCA-gMS$5)+%%=oHl$i1&e~uzn7;*|{Ga=9;nWPvcUqZ-P|G<
zB|>@`KO!jki-g-aevmg+30dMX$tUdG58i)9bRj(_(%gr~$3EYgvwV}&CTpKH%HjQU
z8Y-xR9j4(eL>#gL;}lWR_ajN$MWjn#Q4A*iJtxIT-u!>i?CSUO>F^&X#b>1T54C_B
P00000NkvXXu0mjfSY|XL
diff --git a/client/android/res/mipmap-mdpi/icon.png b/client/android/res/mipmap-mdpi/icon.png
index e23a94a990c8f398f80ef8b89f89b5c83ccacf42..7a47bbfd00952af9374e1262cf5c7f521c625428 100644
GIT binary patch
literal 3918
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
O0N^Ux${0oK(EkCDEkpYN
delta 3515
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
diff --git a/client/android/res/mipmap-mdpi/icon_round.png b/client/android/res/mipmap-mdpi/icon_round.png
index 0ed71d4cc68335cbf2a85260a233b5b2c9806ec1..0278a784e9bfa14ec71c2fea8aaab67230f81b28 100644
GIT binary patch
delta 4785
zcmZ{oS5VUdv&91ziUeiz)1bTH31PYA=f&PI0
z=?@Ud4-5ir*@8fdIUo?r%YqIA<$n!w1YAQMboJj=()Bhym6sKu@YT|VQv4vNr=^zC
z;x2}OK=iR%>Z-;rOZ9m{DV9@yIDpt)Im33O^EtsuAdwF7zA?TZhhU;Jc`U+6CNX;x
zBPoxDCp8;azKAfg)e#Y1uoG1Z?L`dCntE|YNY2uck&|E?ABoM6J83mbs7QUgoKAme
z9iac2hrVD~+zRLl3HTL!a*kIaF8b)T?oqtI{!N2GFZT;d_7qwYGuV!04@(c_59Lci
z=^lj|7za>&C~LeENbajn$9VlIT~Bo{7Ta)=ptba~4-p{Y@;j0!D*Viwv>3K-g!Kx4
za!zr>fHhPEvzDf8dT!Hl47kI?zPh3l!rM&dI3>{4GKX1Q
zZzs|6w}`hFNmonNU4to!j--UsFuqU}L^_aQwVxY6
zu^cb!mGIP)k(D`>L!FHO9xqRLjZGrmpQlL*JEZsjoZ8$bzXKz)r^X5R^sy%7I9QU=
zgW9dtqk)J=o;t^Zyo+-!gew@2(YCJiy`JSajnI^Q=qM+_&z8K#%0BVsghG;O5M(Zk
z)PPa;uTz5UmeMos+EjXax^^>LDedAIkoNOnA~&q0D_D{Ze$yVBDN2u_YAU1YKnIrR
ztD}x;Sq*cQ>kAJyt%Af#cgJ|m1tIx56G?T9fL$lbnyogi$z8FNxm%8OPED}S3lR#N
zj%&P6;_lX^_i1#iO6wD!8m2NdUy3teI;bzK800}}EyxGU!+rOkW=m~BQTDAb%r6x_
zvY6pB^oRo|sXEkScVc7lBuirMQc@lXbQHXO!x!ZpJvA>!x04OdJ>jP-CSibs>^J3|jZFY{Lp9~Q}kJV+bt$POzZ`9x}
z$iw;^e%zkDj{|2vdi(}Tm)gqy)4@96hyosF
zvv7$ew*TyT(?$$l<}dUfa`vglRl9j7wj7(q5*KT?Ahs0PFHf$h!!Y=$TLJuyX6hz*
zP^OupwP3k{x@k??u=D1&Qd;HP!qM2>k2%oS15XNz1SosW^4Qt)A1a|VOI0WUto_4N
zdcbcYkvcia(8aw!W|W+BK!)KaTApp0vaW6y|K$tltL&9#%xg=*2yPQk#?*Z0vr`4K
zgd1gQeocK^dsSK#0s7f@DFSad;
z#q;WRmb+155g(JI%Y+`E8qJj2Na+;1-QOTdC=ML@zO{U94S6Ufx3@L`z=AC}a(xv^
ztSGGc8EdCC`-OZ#{I?`3(6oCkPDXh@Z_%kD?p7OnLD=wTi-KsY>@8rOah6$Jd?$up
zY@ugXHfu+^W2b|9cLD0}BJrN3k@9+9Qw&Ta6bDXT(6jwybLH&=_@mPcIb!{_oBH%jtJK-
z);U^vV4BVcAG-f)Sp%oz0a`?h#sbC&B}~)t<7}@>!3RU%6FExjLo>%1GPP|Nkf$B`
zO%D4A7;YeTEify9lIcRoV3hqmM^n-eudN&8%J;w@E_FJe6qzY