Merge branch 'dev' into trans

This commit is contained in:
StrikerRUS 2024-06-19 02:31:04 +03:00
commit f1271da527
62 changed files with 1308 additions and 174 deletions

View file

@ -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<ServerController> serv
int serverIndex = m_serversModel->getProcessedServerIndex();
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getProcessedContainerIndex());
if (ContainerProps::containerService(container) == ServiceType::Other) {
return;
}
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
ServerCredentials serverCredentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));

View file

@ -35,6 +35,7 @@ namespace PageLoader
PageServiceSftpSettings,
PageServiceTorWebsiteSettings,
PageServiceDnsSettings,
PageServiceSocksProxySettings,
PageSetupWizardStart,
PageSetupWizardCredentials,

View file

@ -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();

View file

@ -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;
}
}

View file

@ -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");
}
}
}
@ -615,15 +617,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;
}

View file

@ -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<int, QByteArray> Socks5ProxyConfigModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[PortRole] = "port";
roles[UserNameRole] = "username";
roles[PasswordRole] = "password";
return roles;
}

View file

@ -0,0 +1,40 @@
#ifndef SOCKS5PROXYCONFIGMODEL_H
#define SOCKS5PROXYCONFIGMODEL_H
#include <QAbstractListModel>
#include <QJsonObject>
#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<int, QByteArray> roleNames() const override;
private:
DockerContainer m_container;
QJsonObject m_protocolConfig;
QJsonObject m_fullConfig;
};
#endif // SOCKS5PROXYCONFIGMODEL_H

View file

@ -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()
}
}
}
}
}
}
}

View file

@ -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 {

View file

@ -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)
}