diff --git a/client/containers/containers_defs.cpp b/client/containers/containers_defs.cpp index e2d14a5c2..d14a1840c 100644 --- a/client/containers/containers_defs.cpp +++ b/client/containers/containers_defs.cpp @@ -60,7 +60,7 @@ QMap ContainerProps::containerHumanNames() {DockerContainer::ShadowSocks, "OpenVpn over ShadowSocks"}, {DockerContainer::Cloak, "OpenVpn over Cloak"}, {DockerContainer::WireGuard, "WireGuard"}, - {DockerContainer::TorSite, QObject::tr("Web site under TOR")}, + {DockerContainer::TorWebSite, QObject::tr("Web site in TOR network")}, {DockerContainer::Dns, QObject::tr("DNS Service")}, {DockerContainer::FileShare, QObject::tr("File Sharing Service")} }; @@ -74,10 +74,9 @@ QMap ContainerProps::containerDescriptions() {DockerContainer::Cloak, QObject::tr("Container with OpenVpn and ShadowSocks protocols " "configured with traffic masking by Cloak plugin")}, {DockerContainer::WireGuard, QObject::tr("WireGuard container")}, - {DockerContainer::TorSite, QObject::tr("Web site under TOR")}, + {DockerContainer::TorWebSite, QObject::tr("Web site in TOR network")}, {DockerContainer::Dns, QObject::tr("DNS Service")}, {DockerContainer::FileShare, QObject::tr("File Sharing Service")} - }; } @@ -89,7 +88,7 @@ amnezia::ServiceType ContainerProps::containerService(DockerContainer c) case DockerContainer::Cloak : return ServiceType::Vpn; case DockerContainer::ShadowSocks : return ServiceType::Vpn; case DockerContainer::WireGuard : return ServiceType::Vpn; - case DockerContainer::TorSite : return ServiceType::Other; + case DockerContainer::TorWebSite : return ServiceType::Other; case DockerContainer::Dns : return ServiceType::Other; case DockerContainer::FileShare : return ServiceType::Other; default: return ServiceType::Other; diff --git a/client/containers/containers_defs.h b/client/containers/containers_defs.h index 38fd369f2..8f5b9ba43 100644 --- a/client/containers/containers_defs.h +++ b/client/containers/containers_defs.h @@ -20,7 +20,7 @@ enum DockerContainer { WireGuard, //non-vpn - TorSite, + TorWebSite, Dns, FileShare }; diff --git a/client/core/scripts_registry.cpp b/client/core/scripts_registry.cpp index 961784552..52350ab4e 100644 --- a/client/core/scripts_registry.cpp +++ b/client/core/scripts_registry.cpp @@ -11,6 +11,7 @@ QString amnezia::scriptFolder(amnezia::DockerContainer container) case DockerContainer::Cloak: return QLatin1String("openvpn_cloak"); case DockerContainer::ShadowSocks: return QLatin1String("openvpn_shadowsocks"); case DockerContainer::WireGuard: return QLatin1String("wireguard"); + case DockerContainer::TorWebSite: return QLatin1String("website_tor"); default: return ""; } } diff --git a/client/images/delete.png b/client/images/delete.png new file mode 100644 index 000000000..59687bd2e Binary files /dev/null and b/client/images/delete.png differ diff --git a/client/protocols/protocols_defs.cpp b/client/protocols/protocols_defs.cpp index 2f5a4e2bf..c21d15964 100644 --- a/client/protocols/protocols_defs.cpp +++ b/client/protocols/protocols_defs.cpp @@ -68,7 +68,7 @@ QMap ProtocolProps::protocolHumanNames() {Protocol::ShadowSocks, "ShadowSocks"}, {Protocol::Cloak, "Cloak"}, {Protocol::WireGuard, "WireGuard"}, - {Protocol::TorSite, "Web site under TOR"}, + {Protocol::TorWebSite, "Web site in TOR network"}, {Protocol::Dns, "DNS Service"}, {Protocol::FileShare, "File Sharing Service"} }; @@ -87,7 +87,7 @@ amnezia::ServiceType ProtocolProps::protocolService(Protocol p) case Protocol::Cloak : return ServiceType::Vpn; case Protocol::ShadowSocks : return ServiceType::Vpn; case Protocol::WireGuard : return ServiceType::Vpn; - case Protocol::TorSite : return ServiceType::Other; + case Protocol::TorWebSite : return ServiceType::Other; case Protocol::Dns : return ServiceType::Other; case Protocol::FileShare : return ServiceType::Other; default: return ServiceType::Other; @@ -102,7 +102,7 @@ int ProtocolProps::defaultPort(Protocol p) case Protocol::Cloak : return 443; case Protocol::ShadowSocks : return 6789; case Protocol::WireGuard : return 51820; - case Protocol::TorSite : return 443; + case Protocol::TorWebSite : return 443; case Protocol::Dns : return 53; case Protocol::FileShare : return 139; default: return -1; @@ -117,7 +117,7 @@ bool ProtocolProps::defaultPortChangeable(Protocol p) case Protocol::Cloak : return true; case Protocol::ShadowSocks : return true; case Protocol::WireGuard : return true; - case Protocol::TorSite : return true; + case Protocol::TorWebSite : return true; case Protocol::Dns : return false; case Protocol::FileShare : return false; default: return -1; @@ -132,7 +132,7 @@ TransportProto ProtocolProps::defaultTransportProto(Protocol p) case Protocol::Cloak : return TransportProto::Tcp; case Protocol::ShadowSocks : return TransportProto::Tcp; case Protocol::WireGuard : return TransportProto::Udp; - case Protocol::TorSite : return TransportProto::Tcp; + case Protocol::TorWebSite : return TransportProto::Tcp; case Protocol::Dns : return TransportProto::Udp; case Protocol::FileShare : return TransportProto::Tcp; default: return TransportProto::Udp; @@ -147,7 +147,7 @@ bool ProtocolProps::defaultTransportProtoChangeable(Protocol p) case Protocol::Cloak : return false; case Protocol::ShadowSocks : return false; case Protocol::WireGuard : return false; - case Protocol::TorSite : return false; + case Protocol::TorWebSite : return false; case Protocol::Dns : return false; case Protocol::FileShare : return false; default: return -1; diff --git a/client/protocols/protocols_defs.h b/client/protocols/protocols_defs.h index 0470247c8..553a28bb8 100644 --- a/client/protocols/protocols_defs.h +++ b/client/protocols/protocols_defs.h @@ -118,7 +118,7 @@ enum Protocol { ShadowSocks, Cloak, WireGuard, - TorSite, + TorWebSite, Dns, FileShare }; diff --git a/client/resources.qrc b/client/resources.qrc index 691c67a3e..9ccd60f70 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -64,6 +64,8 @@ server_scripts/wireguard/run_container.sh server_scripts/wireguard/start.sh server_scripts/wireguard/template.conf + server_scripts/website_tor/configure_container.sh + server_scripts/website_tor/run_container.sh ui/qml/main.qml ui/qml/TitleBar.qml ui/qml/Pages/PageAppSetting.qml @@ -109,5 +111,8 @@ ui/qml/Controls/Logo.qml ui/qml/Pages/InstallSettings/SelectContainer.qml ui/qml/Pages/Protocols/PageProtocolBase.qml + images/delete.png + ui/qml/Controls/FadeBehavior.qml + ui/qml/Controls/VisibleBehavior.qml diff --git a/client/server_scripts/website_tor/configure_container.sh b/client/server_scripts/website_tor/configure_container.sh new file mode 100644 index 000000000..ecb72e6cb --- /dev/null +++ b/client/server_scripts/website_tor/configure_container.sh @@ -0,0 +1,13 @@ +# Wireguard config +sudo docker exec -i $CONTAINER_NAME bash -c '\ +mkdir -p /opt/amnezia/wireguard; \ +cd /opt/amnezia/wireguard || exit 1; \ +WIREGUARD_SERVER_PRIVATE_KEY=$(wg genkey) && echo $WIREGUARD_SERVER_PRIVATE_KEY > /opt/amnezia/wireguard/wireguard_server_private_key.key; \ +WIREGUARD_SERVER_PUBLIC_KEY=$(echo $WIREGUARD_SERVER_PRIVATE_KEY | wg pubkey) && echo $WIREGUARD_SERVER_PUBLIC_KEY > /opt/amnezia/wireguard/wireguard_server_public_key.key; \ +WIREGUARD_PSK=$(wg genpsk) && echo $WIREGUARD_PSK > /opt/amnezia/wireguard/wireguard_psk.key; \ +echo -e "\ +[Interface]\\n\ +PrivateKey = $WIREGUARD_SERVER_PRIVATE_KEY \\n\ +Address = $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR \\n\ +ListenPort = $WIREGUARD_SERVER_PORT \\n\ +" >/opt/amnezia/wireguard/wg0.conf' diff --git a/client/server_scripts/website_tor/run_container.sh b/client/server_scripts/website_tor/run_container.sh new file mode 100644 index 000000000..8be442ea9 --- /dev/null +++ b/client/server_scripts/website_tor/run_container.sh @@ -0,0 +1,3 @@ +# Run container +sudo docker run -d -p 80:80 --restart always --name amnezia-wp-tor tutum/wordpress +sudo docker run -d --link amnezia-wp-tor --name amnezia-tor goldy/tor-hidden-service diff --git a/client/ui/mainwindow.cpp b/client/ui/mainwindow.cpp new file mode 100644 index 000000000..22e6ef7a0 --- /dev/null +++ b/client/ui/mainwindow.cpp @@ -0,0 +1,2383 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "configurators/cloak_configurator.h" +#include "configurators/vpn_configurator.h" +#include "configurators/openvpn_configurator.h" +#include "configurators/shadowsocks_configurator.h" +#include "configurators/ssh_configurator.h" + +#include "core/servercontroller.h" +#include "core/server_defs.h" +#include "core/errorstrings.h" + +#include "protocols/protocols_defs.h" +#include "protocols/shadowsocksvpnprotocol.h" + +#include "ui/qautostart.h" + +#include "debug.h" +#include "defines.h" +#include "mainwindow.h" +#include "utils.h" +#include "vpnconnection.h" +#include "ui_mainwindow.h" +#include "ui/server_widget.h" +#include "ui_server_widget.h" + +#if defined Q_OS_MAC || defined Q_OS_LINUX +#include "ui/macos_util.h" +#endif + +using namespace amnezia; + +MainWindow::MainWindow(QWidget *parent) : + #ifdef Q_OS_WIN + CFramelessWindow(parent), + #else + QMainWindow(parent), + #endif + ui(new Ui::MainWindow), + m_vpnConnection(nullptr) +{ + ui->setupUi(this); + + ui->frame_wireguard_settings->hide(); + ui->frame_wireguard->hide(); + ui->frame_new_server_settings_parent_wireguard->hide(); + + setupTray(); + setupUiConnections(); + setupNewServerConnections(); + setupWizardConnections(); + setupVpnPageConnections(); + setupSitesPageConnections(); + setupGeneralSettingsConnections(); + setupAppSettingsConnections(); + setupNetworkSettingsConnections(); + setupProtocolsPageConnections(); + setupNewServerPageConnections(); + setupSharePageConnections(); + setupServerSettingsPageConnections(); + + ui->label_error_text->clear(); + installEventFilter(this); + ui->widget_tittlebar->installEventFilter(this); + + ui->stackedWidget_main->setSpeed(200); + ui->stackedWidget_main->setAnimation(QEasingCurve::Linear); + + + ui->tableView_sites->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); +// ui->tableView_sites->setColumnWidth(0, 450); +// ui->tableView_sites->setColumnWidth(1, 120); + + if (QOperatingSystemVersion::current() <= QOperatingSystemVersion::Windows7) { + needToHideCustomTitlebar = true; + } + +#if defined Q_OS_MAC + fixWidget(this); + needToHideCustomTitlebar = true; +#endif + + if (needToHideCustomTitlebar) { + ui->widget_tittlebar->hide(); + resize(width(), 640); + ui->stackedWidget_main->move(0,0); + } + + // Post initialization + goToPage(Page::Start, true, false); + + if (m_settings.defaultServerIndex() >= 0 && m_settings.serversCount() > 0) { + goToPage(Page::Vpn, true, false); + } + + //ui->pushButton_general_settings_exit->hide(); + updateSharingPage(selectedServerIndex, m_settings.serverCredentials(selectedServerIndex), selectedDockerContainer); + + setFixedSize(width(),height()); + + qInfo().noquote() << QString("Started %1 version %2").arg(APPLICATION_NAME).arg(APP_VERSION); + qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName()).arg(QSysInfo::currentCpuArchitecture()); + + + m_vpnConnection = new VpnConnection(this); + connect(m_vpnConnection, SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64))); + connect(m_vpnConnection, SIGNAL(connectionStateChanged(VpnProtocol::ConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::ConnectionState))); + connect(m_vpnConnection, SIGNAL(vpnProtocolError(amnezia::ErrorCode)), this, SLOT(onVpnProtocolError(amnezia::ErrorCode))); + + onConnectionStateChanged(VpnProtocol::Disconnected); + + if (m_settings.isAutoConnect() && m_settings.defaultServerIndex() >= 0) { + QTimer::singleShot(1000, this, [this](){ + ui->pushButton_connect->setEnabled(false); + onConnect(); + }); + } + + m_ipAddressValidator.setRegExp(Utils::ipAddressRegExp()); + m_ipAddressPortValidator.setRegExp(Utils::ipAddressPortRegExp()); + m_ipNetwok24Validator.setRegExp(Utils::ipNetwork24RegExp()); + m_ipPortValidator.setRegExp(Utils::ipPortRegExp()); + + ui->lineEdit_new_server_ip->setValidator(&m_ipAddressPortValidator); + ui->lineEdit_network_settings_dns1->setValidator(&m_ipAddressValidator); + ui->lineEdit_network_settings_dns2->setValidator(&m_ipAddressValidator); + + ui->lineEdit_proto_openvpn_subnet->setValidator(&m_ipNetwok24Validator); + + ui->lineEdit_proto_openvpn_port->setValidator(&m_ipPortValidator); + ui->lineEdit_proto_shadowsocks_port->setValidator(&m_ipPortValidator); + ui->lineEdit_proto_cloak_port->setValidator(&m_ipPortValidator); + + //ui->toolBox_share_connection->removeItem(ui->toolBox_share_connection->indexOf(ui->page_share_shadowsocks)); + //ui->page_share_shadowsocks->setVisible(false); + + + sitesModels.insert(Settings::VpnOnlyForwardSites, new SitesModel(Settings::VpnOnlyForwardSites)); + sitesModels.insert(Settings::VpnAllExceptSites, new SitesModel(Settings::VpnAllExceptSites)); +} + +MainWindow::~MainWindow() +{ + hide(); + + m_vpnConnection->disconnectFromVpn(); + for (int i = 0; i < 50; i++) { + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + QThread::msleep(100); + if (m_vpnConnection->isDisconnected()) { + break; + } + } + + delete m_vpnConnection; + delete ui; + + qDebug() << "Application closed"; +} + +void MainWindow::showOnStartup() +{ + if (! m_settings.isStartMinimized()) show(); + else { +#if defined Q_OS_MACX + setDockIconVisible(false); +#endif + } +} + +void MainWindow::goToPage(Page page, bool reset, bool slide) +{ + //qDebug() << "goToPage" << page; + if (ui->stackedWidget_main->nextWidget() == getPageWidget(page)) return; + + if (reset) { + if (page == Page::ServerSettings) { + updateServerPage(); + } + if (page == Page::ShareConnection) { + + } + if (page == Page::Wizard) { + ui->radioButton_setup_wizard_medium->setChecked(true); + } + if (page == Page::WizardHigh) { + ui->lineEdit_setup_wizard_high_website_masking->setText(protocols::cloak::defaultRedirSite); + } + if (page == Page::ServerConfiguring) { + ui->progressBar_new_server_configuring->setValue(0); + } + if (page == Page::GeneralSettings) { + updateGeneralSettingPage(); + } + if (page == Page::ServersList) { + updateServersListPage(); + } + if (page == Page::Start) { + updateStartPage(); + } + if (page == Page::NewServerProtocols) { + ui->pushButton_new_server_settings_cloak->setChecked(true); + ui->pushButton_new_server_settings_cloak->setChecked(false); + ui->pushButton_new_server_settings_ss->setChecked(true); + ui->pushButton_new_server_settings_ss->setChecked(false); + ui->pushButton_new_server_settings_openvpn->setChecked(true); + ui->pushButton_new_server_settings_openvpn->setChecked(false); + + ui->lineEdit_new_server_cloak_port->setText(amnezia::protocols::cloak::defaultPort); + ui->lineEdit_new_server_cloak_site->setText(amnezia::protocols::cloak::defaultRedirSite); + + ui->lineEdit_new_server_ss_port->setText(amnezia::protocols::shadowsocks::defaultPort); + ui->comboBox_new_server_ss_cipher->setCurrentText(amnezia::protocols::shadowsocks::defaultCipher); + + ui->lineEdit_new_server_openvpn_port->setText(amnezia::protocols::openvpn::defaultPort); + ui->comboBox_new_server_openvpn_proto->setCurrentText(amnezia::protocols::openvpn::defaultTransportProto); + } + if (page == Page::ServerVpnProtocols) { + updateProtocolsPage(); + } + if (page == Page::AppSettings) { + updateAppSettingsPage(); + } + if (page == Page::NetworkSettings) { + updateAppSettingsPage(); + } + if (page == Page::Sites) { + updateSitesPage(); + } + if (page == Page::Vpn) { + updateVpnPage(); + } + + ui->pushButton_new_server_connect_key->setChecked(false); + } + + if (slide) + ui->stackedWidget_main->slideInWidget(getPageWidget(page), SlidingStackedWidget::RIGHT2LEFT); + else + ui->stackedWidget_main->setCurrentWidget(getPageWidget(page)); + + pagesStack.push(page); +} + +void MainWindow::setStartPage(MainWindow::Page page, bool slide) +{ + if (slide) + ui->stackedWidget_main->slideInWidget(getPageWidget(page), SlidingStackedWidget::RIGHT2LEFT); + else + ui->stackedWidget_main->setCurrentWidget(getPageWidget(page)); + + pagesStack.clear(); + pagesStack.push(page); + + if (page == Page::Start) updateStartPage(); +} + +void MainWindow::closePage() +{ + if (pagesStack.size() <= 1) return; + + Page prev = pagesStack.pop(); + //qDebug() << "closePage" << prev << "Set page" << pagesStack.top(); + ui->stackedWidget_main->slideInWidget(getPageWidget(pagesStack.top()), SlidingStackedWidget::LEFT2RIGHT); +} + +QWidget *MainWindow::getPageWidget(MainWindow::Page page) +{ + switch (page) { + case(Page::Start): return ui->page_start; + case(Page::NewServer): return ui->page_new_server; + case(Page::NewServerProtocols): return ui->page_new_server_protocols; + case(Page::Wizard): return ui->page_setup_wizard; + case(Page::WizardHigh): return ui->page_setup_wizard_high_level; + case(Page::WizardLow): return ui->page_setup_wizard_low_level; + case(Page::WizardMedium): return ui->page_setup_wizard_medium_level; + case(Page::WizardVpnMode): return ui->page_setup_wizard_vpn_mode; + case(Page::ServerConfiguring): return ui->page_new_server_configuring; + case(Page::Vpn): return ui->page_vpn; + case(Page::GeneralSettings): return ui->page_general_settings; + case(Page::AppSettings): return ui->page_app_settings; + case(Page::NetworkSettings): return ui->page_network_settings; + case(Page::ServerSettings): return ui->page_server_settings; + case(Page::ServerVpnProtocols): return ui->page_server_protocols; + case(Page::ServersList): return ui->page_servers; + case(Page::ShareConnection): return ui->page_share_connection; + case(Page::Sites): return ui->page_sites; + case(Page::OpenVpnSettings): return ui->page_proto_openvpn; + case(Page::ShadowSocksSettings): return ui->page_proto_shadowsocks; + case(Page::CloakSettings): return ui->page_proto_cloak; + } + return nullptr; +} + + +bool MainWindow::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == ui->widget_tittlebar) { + QMouseEvent *mouseEvent = static_cast(event); + + if (!mouseEvent) + return false; + + if(event->type() == QEvent::MouseButtonPress) { + offset = mouseEvent->pos(); + canMove = true; + } + + if(event->type() == QEvent::MouseButtonRelease) { + canMove = false; + } + + if (event->type() == QEvent::MouseMove) { + if(canMove && (mouseEvent->buttons() & Qt::LeftButton)) { + move(mapToParent(mouseEvent->pos() - offset)); + } + + event->ignore(); + return false; + } + } + + return QMainWindow::eventFilter(obj, event); +} + +void MainWindow::keyPressEvent(QKeyEvent *event) +{ + switch (event->key()) { + case Qt::Key_L: + if (!Debug::openLogsFolder()) { + QMessageBox::warning(this, APPLICATION_NAME, tr("Cannot open logs folder!")); + } + break; +#ifdef QT_DEBUG + case Qt::Key_Q: + qApp->quit(); + break; +// case Qt::Key_0: +// *((char*)-1) = 'x'; +// break; + case Qt::Key_H: + selectedServerIndex = m_settings.defaultServerIndex(); + selectedDockerContainer = m_settings.defaultContainer(selectedServerIndex); + + updateSharingPage(selectedServerIndex, m_settings.serverCredentials(selectedServerIndex), selectedDockerContainer); + goToPage(Page::ShareConnection); + break; +#endif + case Qt::Key_C: + qDebug().noquote() << "Def server" << m_settings.defaultServerIndex() << m_settings.defaultContainerName(m_settings.defaultServerIndex()); + //qDebug().noquote() << QJsonDocument(m_settings.containerConfig(m_settings.defaultServerIndex(), m_settings.defaultContainer(m_settings.defaultServerIndex()))).toJson(); + qDebug().noquote() << QJsonDocument(m_settings.defaultServer()).toJson(); + break; + case Qt::Key_A: + goToPage(Page::Start); + break; + case Qt::Key_S: + selectedServerIndex = m_settings.defaultServerIndex(); + goToPage(Page::ServerSettings); + break; + case Qt::Key_P: + selectedServerIndex = m_settings.defaultServerIndex(); + selectedDockerContainer = m_settings.defaultContainer(selectedServerIndex); + goToPage(Page::ServerVpnProtocols); + break; + case Qt::Key_T: + SshConfigurator::openSshTerminal(m_settings.serverCredentials(m_settings.defaultServerIndex())); + break; + case Qt::Key_Escape: + if (currentPage() == Page::Vpn) break; + if (currentPage() == Page::ServerConfiguring) break; + if (currentPage() == Page::Start && pagesStack.size() < 2) break; + if (currentPage() == Page::Sites && + ui->tableView_sites->selectionModel()->selection().indexes().size() > 0) { + ui->tableView_sites->clearSelection(); + break; + } + + if (! ui->stackedWidget_main->isAnimationRunning() && ui->stackedWidget_main->currentWidget()->isEnabled()) { + closePage(); + } + default: + ; + } +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + if (m_settings.serversCount() == 0) qApp->quit(); + else { + hide(); + event->ignore(); + } +} + +void MainWindow::showEvent(QShowEvent *event) +{ +#if defined Q_OS_MACX + if (!event->spontaneous()) { + setDockIconVisible(true); + } + if (needToHideCustomTitlebar) { + ui->widget_tittlebar->hide(); + resize(width(), 640); + ui->stackedWidget_main->move(0,0); + } +#endif +} + +void MainWindow::hideEvent(QHideEvent *event) +{ +#if defined Q_OS_MACX + if (!event->spontaneous()) { + setDockIconVisible(false); + } +#endif +} + +void MainWindow::onPushButtonNewServerConnect(bool) +{ + if (ui->pushButton_new_server_connect_key->isChecked()){ + if (ui->lineEdit_new_server_ip->text().isEmpty() || + ui->lineEdit_new_server_login->text().isEmpty() || + ui->textEdit_new_server_ssh_key->toPlainText().isEmpty() ) { + + ui->label_new_server_wait_info->setText(tr("Please fill in all fields")); + return; + } + } + else { + if (ui->lineEdit_new_server_ip->text().isEmpty() || + ui->lineEdit_new_server_login->text().isEmpty() || + ui->lineEdit_new_server_password->text().isEmpty() ) { + + ui->label_new_server_wait_info->setText(tr("Please fill in all fields")); + return; + } + } + + + qDebug() << "MainWindow::onPushButtonNewServerConnect checking new server"; + + + ServerCredentials serverCredentials; + serverCredentials.hostName = ui->lineEdit_new_server_ip->text(); + if (serverCredentials.hostName.contains(":")) { + serverCredentials.port = serverCredentials.hostName.split(":").at(1).toInt(); + serverCredentials.hostName = serverCredentials.hostName.split(":").at(0); + } + serverCredentials.userName = ui->lineEdit_new_server_login->text(); + if (ui->pushButton_new_server_connect_key->isChecked()){ + QString key = ui->textEdit_new_server_ssh_key->toPlainText(); + if (key.startsWith("ssh-rsa")) { + QMessageBox::warning(this, APPLICATION_NAME, + tr("It's public key. Private key required")); + + return; + } + + if (key.contains("OPENSSH") && key.contains("BEGIN") && key.contains("PRIVATE KEY")) { + key = SshConfigurator::convertOpenSShKey(key); + } + + serverCredentials.password = key; + } + else { + serverCredentials.password = ui->lineEdit_new_server_password->text(); + } + + ui->pushButton_new_server_connect->setEnabled(false); + ui->pushButton_new_server_connect->setText(tr("Connecting...")); + + ErrorCode e = ErrorCode::NoError; +#ifdef Q_DEBUG + //QString output = ServerController::checkSshConnection(serverCredentials, &e); +#else + QString output; +#endif + + bool ok = true; + if (e) { + ui->label_new_server_wait_info->show(); + ui->label_new_server_wait_info->setText(errorString(e)); + ok = false; + } + else { + if (output.contains("Please login as the user")) { + output.replace("\n", ""); + ui->label_new_server_wait_info->show(); + ui->label_new_server_wait_info->setText(output); + ok = false; + } + } + + ui->pushButton_new_server_connect->setEnabled(true); + ui->pushButton_new_server_connect->setText(tr("Connect")); + + installCredentials = serverCredentials; + if (ok) goToPage(Page::NewServer); +} + +QMap MainWindow::getInstallConfigsFromProtocolsPage() const +{ + QJsonObject cloakConfig { + { config_key::container, amnezia::containerToString(DockerContainer::OpenVpnOverCloak) }, + { config_key::cloak, QJsonObject { + { config_key::port, ui->lineEdit_new_server_cloak_port->text() }, + { config_key::site, ui->lineEdit_new_server_cloak_site->text() }} + } + }; + QJsonObject ssConfig { + { config_key::container, amnezia::containerToString(DockerContainer::OpenVpnOverShadowSocks) }, + { config_key::shadowsocks, QJsonObject { + { config_key::port, ui->lineEdit_new_server_ss_port->text() }, + { config_key::cipher, ui->comboBox_new_server_ss_cipher->currentText() }} + } + }; + QJsonObject openVpnConfig { + { config_key::container, amnezia::containerToString(DockerContainer::OpenVpn) }, + { config_key::openvpn, QJsonObject { + { config_key::port, ui->lineEdit_new_server_openvpn_port->text() }, + { config_key::transport_proto, ui->comboBox_new_server_openvpn_proto->currentText() }} + } + }; + + QMap containers; + + if (ui->checkBox_new_server_cloak->isChecked()) { + containers.insert(DockerContainer::OpenVpnOverCloak, cloakConfig); + } + + if (ui->checkBox_new_server_ss->isChecked()) { + containers.insert(DockerContainer::OpenVpnOverShadowSocks, ssConfig); + } + + if (ui->checkBox_new_server_openvpn->isChecked()) { + containers.insert(DockerContainer::OpenVpn, openVpnConfig); + } + + return containers; +} + +QMap MainWindow::getInstallConfigsFromWizardPage() const +{ + QJsonObject cloakConfig { + { config_key::container, amnezia::containerToString(DockerContainer::OpenVpnOverCloak) }, + { config_key::cloak, QJsonObject { + { config_key::site, ui->lineEdit_setup_wizard_high_website_masking->text() }} + } + }; + QJsonObject ssConfig { + { config_key::container, amnezia::containerToString(DockerContainer::OpenVpnOverShadowSocks) } + }; + QJsonObject openVpnConfig { + { config_key::container, amnezia::containerToString(DockerContainer::OpenVpn) } + }; + + QMap containers; + + if (ui->radioButton_setup_wizard_high->isChecked()) { + containers.insert(DockerContainer::OpenVpnOverCloak, cloakConfig); + } + + if (ui->radioButton_setup_wizard_medium->isChecked()) { + containers.insert(DockerContainer::OpenVpnOverShadowSocks, ssConfig); + } + + if (ui->radioButton_setup_wizard_low->isChecked()) { + containers.insert(DockerContainer::OpenVpn, openVpnConfig); + } + + return containers; +} + +void MainWindow::installServer(const QMap &containers) +{ + if (containers.isEmpty()) return; + + goToPage(Page::ServerConfiguring); + QEventLoop loop; + QTimer::singleShot(500, &loop, SLOT(quit())); + loop.exec(); + qApp->processEvents(); + + bool ok = installContainers(installCredentials, containers, + ui->page_new_server_configuring, + ui->progressBar_new_server_configuring, + nullptr, + ui->label_new_server_configuring_wait_info); + + if (ok) { + QJsonObject server; + server.insert(config_key::hostName, installCredentials.hostName); + server.insert(config_key::userName, installCredentials.userName); + server.insert(config_key::password, installCredentials.password); + server.insert(config_key::port, installCredentials.port); + server.insert(config_key::description, m_settings.nextAvailableServerName()); + + QJsonArray containerConfigs; + for (const QJsonObject &cfg : containers) { + containerConfigs.append(cfg); + } + server.insert(config_key::containers, containerConfigs); + server.insert(config_key::defaultContainer, containerToString(containers.firstKey())); + + m_settings.addServer(server); + m_settings.setDefaultServer(m_settings.serversCount() - 1); + + setStartPage(Page::Vpn); + qApp->processEvents(); + } + else { + closePage(); + } +} + +void MainWindow::onPushButtonNewServerImport(bool) +{ + QString s = ui->lineEdit_start_existing_code->text(); + s.replace("vpn://", ""); + QJsonObject o = QJsonDocument::fromJson(QByteArray::fromBase64(s.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)).object(); + + ServerCredentials credentials; + credentials.hostName = o.value("h").toString(); + if (credentials.hostName.isEmpty()) credentials.hostName = o.value(config_key::hostName).toString(); + + credentials.port = o.value("p").toInt(); + if (credentials.port == 0) credentials.port = o.value(config_key::port).toInt(); + + credentials.userName = o.value("u").toString(); + if (credentials.userName.isEmpty()) credentials.userName = o.value(config_key::userName).toString(); + + credentials.password = o.value("w").toString(); + if (credentials.password.isEmpty()) credentials.password = o.value(config_key::password).toString(); + + if (credentials.isValid()) { + o.insert(config_key::hostName, credentials.hostName); + o.insert(config_key::port, credentials.port); + o.insert(config_key::userName, credentials.userName); + o.insert(config_key::password, credentials.password); + + o.remove("h"); + o.remove("p"); + o.remove("u"); + o.remove("w"); + } + qDebug() << QString("Added server %3@%1:%2"). + arg(credentials.hostName). + arg(credentials.port). + arg(credentials.userName); + + //qDebug() << QString("Password") << credentials.password; + + if (credentials.isValid() || o.contains(config_key::containers)) { + m_settings.addServer(o); + m_settings.setDefaultServer(m_settings.serversCount() - 1); + + setStartPage(Page::Vpn); + } + else { + qDebug() << "Failed to import profile"; + qDebug().noquote() << QJsonDocument(o).toJson(); + return; + } + + if (!o.contains(config_key::containers)) { + selectedServerIndex = m_settings.defaultServerIndex(); + selectedDockerContainer = m_settings.defaultContainer(selectedServerIndex); + goToPage(Page::ServerVpnProtocols); + } +} + +bool MainWindow::installContainers(ServerCredentials credentials, + const QMap &containers, + QWidget *page, QProgressBar *progress, QPushButton *button, QLabel *info) +{ + if (!progress) return false; + + if (page) page->setEnabled(false); + if (button) button->setVisible(false); + + if (info) info->setVisible(true); + if (info) info->setText(tr("Please wait, configuring process may take up to 5 minutes")); + + + int cnt = 0; + for (QMap::const_iterator i = containers.constBegin(); i != containers.constEnd(); i++, cnt++) { + QTimer timer; + connect(&timer, &QTimer::timeout, [progress](){ + progress->setValue(progress->value() + 1); + }); + + progress->setValue(0); + timer.start(1000); + + progress->setTextVisible(true); + progress->setFormat(QString("Installing %1 %2 %3").arg(cnt+1).arg(tr("of")).arg(containers.size())); + + ErrorCode e = ServerController::setupContainer(credentials, i.key(), i.value()); + qDebug() << "Setup server finished with code" << e; + ServerController::disconnectFromHost(credentials); + + if (e) { + if (page) page->setEnabled(true); + if (button) button->setVisible(true); + if (info) info->setVisible(false); + + QMessageBox::warning(this, APPLICATION_NAME, + tr("Error occurred while configuring server.") + "\n" + + errorString(e)); + + return false; + } + + // just ui progressbar tweak + timer.stop(); + + int remaining_val = progress->maximum() - progress->value(); + + if (remaining_val > 0) { + QTimer timer1; + QEventLoop loop1; + + connect(&timer1, &QTimer::timeout, [&](){ + progress->setValue(progress->value() + 1); + if (progress->value() >= progress->maximum()) { + loop1.quit(); + } + }); + + timer1.start(5); + loop1.exec(); + } + } + + + if (button) button->show(); + if (page) page->setEnabled(true); + if (info) info->setText(tr("Amnezia server installed")); + + return true; +} + +ErrorCode MainWindow::doInstallAction(const std::function &action, QWidget *page, QProgressBar *progress, QPushButton *button, QLabel *info) +{ + progress->show(); + if (page) page->setEnabled(false); + if (button) button->setVisible(false); + + if (info) info->setVisible(true); + if (info) info->setText(tr("Please wait, configuring process may take up to 5 minutes")); + + + QTimer timer; + connect(&timer, &QTimer::timeout, [progress](){ + progress->setValue(progress->value() + 1); + }); + + progress->setValue(0); + timer.start(1000); + + ErrorCode e = action(); + qDebug() << "doInstallAction finished with code" << e; + +// if (e) { +// if (page) page->setEnabled(true); +// if (button) button->setVisible(true); +// if (info) info->setVisible(false); + +// QMessageBox::warning(this, APPLICATION_NAME, +// tr("Error occurred while configuring server.") + "\n" + +// errorString(e)); + +// progress->hide(); +// return e; +// } + + // just ui progressbar tweak + timer.stop(); + + int remaining_val = progress->maximum() - progress->value(); + + if (remaining_val > 0) { + QTimer timer1; + QEventLoop loop1; + + connect(&timer1, &QTimer::timeout, [&](){ + progress->setValue(progress->value() + 1); + if (progress->value() >= progress->maximum()) { + loop1.quit(); + } + }); + + timer1.start(5); + loop1.exec(); + } + + + progress->hide(); + if (button) button->show(); + if (page) page->setEnabled(true); + if (info) info->setText(tr("Operation finished")); + + return ErrorCode::NoError; +} + +void MainWindow::onPushButtonClearServer(bool) +{ + ui->page_server_settings->setEnabled(false); + ui->pushButton_server_settings_clear->setText(tr("Uninstalling Amnezia software...")); + + if (m_settings.defaultServerIndex() == selectedServerIndex) { + onDisconnect(); + } + + ErrorCode e = ServerController::removeAllContainers(m_settings.serverCredentials(selectedServerIndex)); + ServerController::disconnectFromHost(m_settings.serverCredentials(selectedServerIndex)); + if (e) { + QMessageBox::warning(this, APPLICATION_NAME, + tr("Error occurred while configuring server.") + "\n" + + errorString(e) + "\n" + + tr("See logs for details.")); + + } + else { + ui->label_server_settings_wait_info->show(); + ui->label_server_settings_wait_info->setText(tr("Amnezia server successfully uninstalled")); + } + + m_settings.setContainers(selectedServerIndex, {}); + m_settings.setDefaultContainer(selectedServerIndex, DockerContainer::None); + + ui->page_server_settings->setEnabled(true); + ui->pushButton_server_settings_clear->setText(tr("Clear server from Amnezia software")); +} + +void MainWindow::onPushButtonForgetServer(bool) +{ + if (m_settings.defaultServerIndex() == selectedServerIndex && m_vpnConnection->isConnected()) { + onDisconnect(); + } + m_settings.removeServer(selectedServerIndex); + + if (m_settings.defaultServerIndex() == selectedServerIndex) { + m_settings.setDefaultServer(0); + } + else if (m_settings.defaultServerIndex() > selectedServerIndex) { + m_settings.setDefaultServer(m_settings.defaultServerIndex() - 1); + } + + if (m_settings.serversCount() == 0) { + m_settings.setDefaultServer(-1); + } + + + selectedServerIndex = -1; + + updateServersListPage(); + + if (m_settings.serversCount() == 0) { + setStartPage(Page::Start); + } + else { + closePage(); + } +} + +void MainWindow::onBytesChanged(quint64 receivedData, quint64 sentData) +{ + ui->label_speed_received->setText(VpnConnection::bytesPerSecToText(receivedData)); + ui->label_speed_sent->setText(VpnConnection::bytesPerSecToText(sentData)); +} + +void MainWindow::onConnectionStateChanged(VpnProtocol::ConnectionState state) +{ + qDebug() << "MainWindow::onConnectionStateChanged" << VpnProtocol::textConnectionState(state); + + bool pushButtonConnectEnabled = false; + bool radioButtonsModeEnabled = false; + ui->label_state->setText(VpnProtocol::textConnectionState(state)); + + setTrayState(state); + + switch (state) { + case VpnProtocol::Disconnected: + onBytesChanged(0,0); + ui->pushButton_connect->setChecked(false); + pushButtonConnectEnabled = true; + radioButtonsModeEnabled = true; + break; + case VpnProtocol::Preparing: + pushButtonConnectEnabled = false; + radioButtonsModeEnabled = false; + break; + case VpnProtocol::Connecting: + pushButtonConnectEnabled = false; + radioButtonsModeEnabled = false; + break; + case VpnProtocol::Connected: + pushButtonConnectEnabled = true; + radioButtonsModeEnabled = false; + break; + case VpnProtocol::Disconnecting: + pushButtonConnectEnabled = false; + radioButtonsModeEnabled = false; + break; + case VpnProtocol::Reconnecting: + pushButtonConnectEnabled = true; + radioButtonsModeEnabled = false; + break; + case VpnProtocol::Error: + ui->pushButton_connect->setChecked(false); + pushButtonConnectEnabled = true; + radioButtonsModeEnabled = true; + break; + case VpnProtocol::Unknown: + pushButtonConnectEnabled = true; + radioButtonsModeEnabled = true; + } + + ui->pushButton_connect->setEnabled(pushButtonConnectEnabled); + ui->widget_vpn_mode->setEnabled(radioButtonsModeEnabled); +} + +void MainWindow::onVpnProtocolError(ErrorCode errorCode) +{ + ui->label_error_text->setText(errorString(errorCode)); +} + +void MainWindow::onPushButtonConnectClicked(bool checked) +{ + if (checked) { + onConnect(); + } else { + onDisconnect(); + } +} + +void MainWindow::setupTray() +{ + m_menu = new QMenu(); + + m_menu->addAction(QIcon(":/images/tray/application.png"), tr("Show") + " " + APPLICATION_NAME, this, [this](){ + show(); + raise(); + }); + m_menu->addSeparator(); + m_trayActionConnect = m_menu->addAction(tr("Connect"), this, SLOT(onConnect())); + m_trayActionDisconnect = m_menu->addAction(tr("Disconnect"), this, SLOT(onDisconnect())); + + m_menu->addSeparator(); + + m_menu->addAction(QIcon(":/images/tray/link.png"), tr("Visit Website"), [&](){ + QDesktopServices::openUrl(QUrl("https://amnezia.org")); + }); + + m_menu->addAction(QIcon(":/images/tray/cancel.png"), tr("Quit") + " " + APPLICATION_NAME, this, [&](){ +// QMessageBox::question(this, QMessageBox::question(this, tr("Exit"), tr("Do you really want to quit?"), QMessageBox::Yes | QMessageBox::No, ); + + QMessageBox msgBox(QMessageBox::Question, tr("Exit"), tr("Do you really want to quit?"), + QMessageBox::Yes | QMessageBox::No, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowStaysOnTopHint); + msgBox.setDefaultButton(QMessageBox::Yes); + msgBox.raise(); + if (msgBox.exec() == QMessageBox::Yes) { + qApp->quit(); + } + }); + + m_tray.setContextMenu(m_menu); + setTrayState(VpnProtocol::Disconnected); + + m_tray.show(); + + connect(&m_tray, &QSystemTrayIcon::activated, this, &MainWindow::onTrayActivated); +} + +void MainWindow::setTrayIcon(const QString &iconPath) +{ + m_tray.setIcon(QIcon(QPixmap(iconPath).scaled(128,128))); +} + +MainWindow::Page MainWindow::currentPage() +{ + ui->stackedWidget_main->waitForAnimation(); + + QWidget *currentPage = ui->stackedWidget_main->currentWidget(); + QMetaEnum e = QMetaEnum::fromType(); + + for (int k = 0; k < e.keyCount(); k++) { + Page p = static_cast(e.value(k)); + if (currentPage == getPageWidget(p)) return p; + } + + return Page::Start; +} + +void MainWindow::setupUiConnections() +{ + connect(ui->pushButton_close, &QPushButton::clicked, this, [this](){ + if (currentPage() == Page::Start || currentPage() == Page::NewServer) qApp->quit(); + else hide(); + }); + + connect(ui->pushButton_vpn_add_site, &QPushButton::clicked, this, [this](){ goToPage(Page::Sites); }); + + + QVector backButtons { + ui->pushButton_back_from_sites, + ui->pushButton_back_from_general_settings, + ui->pushButton_back_from_start, + ui->pushButton_back_from_new_server, + ui->pushButton_back_from_new_server_protocols, + ui->pushButton_back_from_setup_wizard, + ui->pushButton_back_from_setup_wizard_high, + ui->pushButton_back_from_setup_wizard_low, + ui->pushButton_back_from_setup_wizard_medium, + ui->pushButton_back_from_setup_wizard_vpn_mode, + ui->pushButton_back_from_app_settings, + ui->pushButton_back_from_network_settings, + ui->pushButton_back_from_server_settings, + ui->pushButton_back_from_servers, + ui->pushButton_back_from_share, + ui->pushButton_back_from_server_vpn_protocols, + ui->pushButton_back_from_openvpn_settings, + ui->pushButton_back_from_cloak_settings, + ui->pushButton_back_from_shadowsocks_settings + }; + + for (QPushButton *b : backButtons) { + connect(b, &QPushButton::clicked, this, [this](){ closePage(); }); + } + +} + +void MainWindow::setupNewServerConnections() +{ + connect(ui->pushButton_new_server_get_info, &QPushButton::clicked, this, [](){ + QDesktopServices::openUrl(QUrl("https://amnezia.org")); + }); + + connect(ui->pushButton_new_server_connect, SIGNAL(clicked(bool)), this, SLOT(onPushButtonNewServerConnect(bool))); + connect(ui->pushButton_new_server_import, SIGNAL(clicked(bool)), this, SLOT(onPushButtonNewServerImport(bool))); + + connect(ui->pushButton_new_server_connect_configure, &QPushButton::clicked, this, [this](){ + installServer(getInstallConfigsFromProtocolsPage()); + }); + +} + +void MainWindow::setupWizardConnections() +{ + connect(ui->pushButton_new_server_wizard, &QPushButton::clicked, this, [this](){ goToPage(Page::Wizard); }); + connect(ui->pushButton_new_server_advanced, &QPushButton::clicked, this, [this](){ goToPage(Page::NewServerProtocols); }); + connect(ui->pushButton_setup_wizard_next, &QPushButton::clicked, this, [this](){ + if (ui->radioButton_setup_wizard_high->isChecked()) goToPage(Page::WizardHigh); + else if (ui->radioButton_setup_wizard_medium->isChecked()) goToPage(Page::WizardMedium); + else if (ui->radioButton_setup_wizard_low->isChecked()) goToPage(Page::WizardLow); + }); + + connect(ui->pushButton_setup_wizard_high_next, &QPushButton::clicked, this, [this](){ + QString domain = ui->lineEdit_setup_wizard_high_website_masking->text(); + if (domain.isEmpty() || !domain.contains(".")) return; + goToPage(Page::WizardVpnMode); + }); + + connect(ui->lineEdit_setup_wizard_high_website_masking, &QLineEdit::textEdited, this, [this](){ + QString text = ui->lineEdit_setup_wizard_high_website_masking->text(); + text.replace("http://", ""); + text.replace("https://", ""); + if (text.isEmpty()) return; + text = text.split("/").first(); + ui->lineEdit_setup_wizard_high_website_masking->setText(text); + }); + + connect(ui->pushButton_setup_wizard_medium_next, &QPushButton::clicked, this, [this](){ goToPage(Page::WizardVpnMode); }); + + connect(ui->pushButton_setup_wizard_vpn_mode_finish, &QPushButton::clicked, this, [this](){ + installServer(getInstallConfigsFromWizardPage()); + if (ui->checkBox_setup_wizard_vpn_mode->isChecked()) m_settings.setRouteMode(Settings::VpnOnlyForwardSites); + else m_settings.setRouteMode(Settings::VpnAllSites); + }); + + connect(ui->pushButton_setup_wizard_low_finish, &QPushButton::clicked, this, [this](){ + installServer(getInstallConfigsFromWizardPage()); + }); + + connect(ui->lineEdit_setup_wizard_high_website_masking, &QLineEdit::returnPressed, this, [this](){ + ui->pushButton_setup_wizard_high_next->click(); + }); +} + +void MainWindow::setupVpnPageConnections() +{ + connect(ui->radioButton_vpn_mode_all_sites, &QRadioButton::toggled, ui->pushButton_vpn_add_site, &QPushButton::setDisabled); + + connect(ui->radioButton_vpn_mode_all_sites, &QRadioButton::toggled, this, [this](bool toggled) { + m_settings.setRouteMode(Settings::VpnAllSites); + }); + + connect(ui->radioButton_vpn_mode_forward_sites, &QRadioButton::toggled, this, [this](bool toggled) { + m_settings.setRouteMode(Settings::VpnOnlyForwardSites); + }); + + connect(ui->radioButton_vpn_mode_except_sites, &QRadioButton::toggled, this, [this](bool toggled) { + m_settings.setRouteMode(Settings::VpnAllExceptSites); + }); +} + +void MainWindow::setupSitesPageConnections() +{ + connect(ui->pushButton_sites_add_custom, &QPushButton::clicked, this, [this](){ onPushButtonAddCustomSitesClicked(); }); + + connect(ui->lineEdit_sites_add_custom, &QLineEdit::returnPressed, [&](){ + ui->pushButton_sites_add_custom->click(); + }); + + connect(ui->pushButton_sites_delete, &QPushButton::clicked, this, [this](){ + Settings::RouteMode mode = m_settings.routeMode(); + + QItemSelectionModel* selection = ui->tableView_sites->selectionModel(); + if (!selection) return; + + { + QModelIndexList indexesSites = selection->selectedRows(0); + + QStringList sites; + for (const QModelIndex &index : indexesSites) { + sites.append(index.data().toString()); + } + + m_settings.removeVpnSites(mode, sites); + } + + if (m_vpnConnection->connectionState() == VpnProtocol::Connected) { + QModelIndexList indexesIps = selection->selectedRows(1); + + QStringList ips; + for (const QModelIndex &index : indexesIps) { + if (index.data().toString().isEmpty()) { + ips.append(index.sibling(index.row(), 0).data().toString()); + } + else { + ips.append(index.data().toString()); + } + } + + m_vpnConnection->deleteRoutes(ips); + m_vpnConnection->flushDns(); + } + + updateSitesPage(); + }); + + connect(ui->pushButton_sites_import, &QPushButton::clicked, this, [this](){ + QString fileName = QFileDialog::getOpenFileName(this, tr("Import IP addresses"), + QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); + + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) return; + + Settings::RouteMode mode = m_settings.routeMode(); + + QStringList ips; + while (!file.atEnd()) { + QString line = file.readLine(); + + int pos = 0; + QRegExp rx = Utils::ipAddressWithSubnetRegExp(); + while ((pos = rx.indexIn(line, pos)) != -1) { + ips << rx.cap(0); + pos += rx.matchedLength(); + } + } + + m_settings.addVpnIps(mode, ips); + + m_vpnConnection->addRoutes(QStringList() << ips); + m_vpnConnection->flushDns(); + + updateSitesPage(); + }); +} + +void MainWindow::setupAppSettingsConnections() +{ + connect(ui->checkBox_app_settings_autostart, &QCheckBox::stateChanged, this, [this](int state){ + if (state == Qt::Unchecked) { + ui->checkBox_app_settings_autoconnect->setChecked(false); + } + Autostart::setAutostart(state == Qt::Checked); + }); + + connect(ui->checkBox_app_settings_autoconnect, &QCheckBox::stateChanged, this, [this](int state){ + m_settings.setAutoConnect(state == Qt::Checked); + }); + + connect(ui->checkBox_app_settings_start_minimized, &QCheckBox::stateChanged, this, [this](int state){ + m_settings.setStartMinimized(state == Qt::Checked); + }); + + connect(ui->pushButton_app_settings_check_for_updates, &QPushButton::clicked, this, [this](){ + QDesktopServices::openUrl(QUrl("https://github.com/amnezia-vpn/desktop-client/releases/latest")); + }); + + connect(ui->pushButton_app_settings_open_logs, &QPushButton::clicked, this, [this](){ + Debug::openLogsFolder(); + //QDesktopServices::openUrl(QUrl::fromLocalFile(Utils::systemLogPath())); + }); +} + +void MainWindow::setupGeneralSettingsConnections() +{ + connect(ui->pushButton_general_settings_exit, &QPushButton::clicked, this, [&](){ qApp->quit(); }); + + connect(ui->pushButton_settings, &QPushButton::clicked, this, [this](){ goToPage(Page::GeneralSettings); }); + connect(ui->pushButton_general_settings_app_settings, &QPushButton::clicked, this, [this](){ goToPage(Page::AppSettings); }); + connect(ui->pushButton_general_settings_network_settings, &QPushButton::clicked, this, [this](){ goToPage(Page::NetworkSettings); }); + connect(ui->pushButton_general_settings_server_settings, &QPushButton::clicked, this, [this](){ + selectedServerIndex = m_settings.defaultServerIndex(); + goToPage(Page::ServerSettings); + }); + connect(ui->pushButton_general_settings_servers_list, &QPushButton::clicked, this, [this](){ goToPage(Page::ServersList); }); + connect(ui->pushButton_general_settings_share_connection, &QPushButton::clicked, this, [this](){ + selectedServerIndex = m_settings.defaultServerIndex(); + selectedDockerContainer = m_settings.defaultContainer(selectedServerIndex); + + updateSharingPage(selectedServerIndex, m_settings.serverCredentials(selectedServerIndex), selectedDockerContainer); + goToPage(Page::ShareConnection); + }); + + connect(ui->pushButton_general_settings_add_server, &QPushButton::clicked, this, [this](){ goToPage(Page::Start); }); + +} + +void MainWindow::setupNetworkSettingsConnections() +{ + connect(ui->lineEdit_network_settings_dns1, &QLineEdit::textEdited, this, [this](const QString &newText){ + if (m_ipAddressValidator.regExp().exactMatch(newText)) { + m_settings.setPrimaryDns(newText); + } + }); + connect(ui->lineEdit_network_settings_dns2, &QLineEdit::textEdited, this, [this](const QString &newText){ + if (m_ipAddressValidator.regExp().exactMatch(newText)) { + m_settings.setSecondaryDns(newText); + } + }); + + connect(ui->pushButton_network_settings_resetdns1, &QPushButton::clicked, this, [this](){ + m_settings.setPrimaryDns(m_settings.cloudFlareNs1); + updateAppSettingsPage(); + }); + + connect(ui->pushButton_network_settings_resetdns2, &QPushButton::clicked, this, [this](){ + m_settings.setSecondaryDns(m_settings.cloudFlareNs2); + updateAppSettingsPage(); + }); +} + +void MainWindow::setupProtocolsPageConnections() +{ + QJsonObject openvpnConfig; + + // all containers + QList containers { + DockerContainer::OpenVpn, + DockerContainer::OpenVpnOverShadowSocks, + DockerContainer::OpenVpnOverCloak, + DockerContainer::WireGuard + }; + + // default buttons + QList defaultButtons { + ui->pushButton_proto_openvpn_cont_default, + ui->pushButton_proto_ss_openvpn_cont_default, + ui->pushButton_proto_cloak_openvpn_cont_default, + ui->pushButton_proto_wireguard_cont_default + }; + + for (int i = 0; i < containers.size(); ++i) { + connect(defaultButtons.at(i), &QPushButton::clicked, this, [this, containers, i](){ + m_settings.setDefaultContainer(selectedServerIndex, containers.at(i)); + updateProtocolsPage(); + }); + } + + // install buttons + QList installButtons { + ui->pushButton_proto_openvpn_cont_install, + ui->pushButton_proto_ss_openvpn_cont_install, + ui->pushButton_proto_cloak_openvpn_cont_install, + ui->pushButton_proto_wireguard_cont_install + }; + + for (int i = 0; i < containers.size(); ++i) { + QPushButton *button = installButtons.at(i); + DockerContainer container = containers.at(i); + + connect(button, &QPushButton::clicked, this, [this, container, button](bool checked){ + if (checked) { + ErrorCode e = doInstallAction([this, container](){ + return ServerController::setupContainer(m_settings.serverCredentials(selectedServerIndex), container); + }, + ui->page_server_protocols, ui->progressBar_protocols_container_reinstall, + nullptr, nullptr); + + if (!e) { + m_settings.setContainerConfig(selectedServerIndex, container, QJsonObject()); + m_settings.setDefaultContainer(selectedServerIndex, container); + } + } + else { + button->setEnabled(false); + ErrorCode e = ServerController::removeContainer(m_settings.serverCredentials(selectedServerIndex), container); + m_settings.removeContainerConfig(selectedServerIndex, container); + button->setEnabled(true); + + if (m_settings.defaultContainer(selectedServerIndex) == container) { + const auto &c = m_settings.containers(selectedServerIndex); + if (c.isEmpty()) m_settings.setDefaultContainer(selectedServerIndex, DockerContainer::None); + else m_settings.setDefaultContainer(selectedServerIndex, c.keys().first()); + } + } + + updateProtocolsPage(); + }); + } + + // share buttons + QList shareButtons { + ui->pushButton_proto_openvpn_cont_share, + ui->pushButton_proto_ss_openvpn_cont_share, + ui->pushButton_proto_cloak_openvpn_cont_share, + ui->pushButton_proto_wireguard_cont_share + }; + + for (int i = 0; i < containers.size(); ++i) { + QPushButton *button = shareButtons.at(i); + DockerContainer container = containers.at(i); + + connect(button, &QPushButton::clicked, this, [this, button, container](){ + updateSharingPage(selectedServerIndex, m_settings.serverCredentials(selectedServerIndex), container); + goToPage(Page::ShareConnection); + }); + } + + // settings buttons + + // settings openvpn container + connect(ui->pushButton_proto_openvpn_cont_openvpn_config, &QPushButton::clicked, this, [this](){ + selectedDockerContainer = DockerContainer::OpenVpn; + updateOpenVpnPage(m_settings.protocolConfig(selectedServerIndex, selectedDockerContainer, Protocol::OpenVpn), + selectedDockerContainer, m_settings.haveAuthData(selectedServerIndex)); + goToPage(Page::OpenVpnSettings); + }); + + // settings shadowsocks container + connect(ui->pushButton_proto_ss_openvpn_cont_openvpn_config, &QPushButton::clicked, this, [this](){ + selectedDockerContainer = DockerContainer::OpenVpnOverShadowSocks; + updateOpenVpnPage(m_settings.protocolConfig(selectedServerIndex, selectedDockerContainer, Protocol::OpenVpn), + selectedDockerContainer, m_settings.haveAuthData(selectedServerIndex)); + goToPage(Page::OpenVpnSettings); + }); + connect(ui->pushButton_proto_ss_openvpn_cont_ss_config, &QPushButton::clicked, this, [this](){ + selectedDockerContainer = DockerContainer::OpenVpnOverShadowSocks; + updateShadowSocksPage(m_settings.protocolConfig(selectedServerIndex, selectedDockerContainer, Protocol::ShadowSocks), + selectedDockerContainer, m_settings.haveAuthData(selectedServerIndex)); + goToPage(Page::ShadowSocksSettings); + }); + + // settings cloak container + connect(ui->pushButton_proto_cloak_openvpn_cont_openvpn_config, &QPushButton::clicked, this, [this](){ + selectedDockerContainer = DockerContainer::OpenVpnOverCloak; + updateOpenVpnPage(m_settings.protocolConfig(selectedServerIndex, selectedDockerContainer, Protocol::OpenVpn), + selectedDockerContainer, m_settings.haveAuthData(selectedServerIndex)); + goToPage(Page::OpenVpnSettings); + }); + connect(ui->pushButton_proto_cloak_openvpn_cont_ss_config, &QPushButton::clicked, this, [this](){ + selectedDockerContainer = DockerContainer::OpenVpnOverCloak; + updateShadowSocksPage(m_settings.protocolConfig(selectedServerIndex, selectedDockerContainer, Protocol::ShadowSocks), + selectedDockerContainer, m_settings.haveAuthData(selectedServerIndex)); + goToPage(Page::ShadowSocksSettings); + }); + connect(ui->pushButton_proto_cloak_openvpn_cont_cloak_config, &QPushButton::clicked, this, [this](){ + selectedDockerContainer = DockerContainer::OpenVpnOverCloak; + updateCloakPage(m_settings.protocolConfig(selectedServerIndex, selectedDockerContainer, Protocol::Cloak), + selectedDockerContainer, m_settings.haveAuthData(selectedServerIndex)); + goToPage(Page::CloakSettings); + }); + + /// + // Protocols pages + connect(ui->checkBox_proto_openvpn_auto_encryption, &QCheckBox::stateChanged, this, [this](){ + ui->comboBox_proto_openvpn_cipher->setDisabled(ui->checkBox_proto_openvpn_auto_encryption->isChecked()); + ui->comboBox_proto_openvpn_hash->setDisabled(ui->checkBox_proto_openvpn_auto_encryption->isChecked()); + }); + + connect(ui->pushButton_proto_openvpn_save, &QPushButton::clicked, this, [this](){ + QJsonObject protocolConfig = m_settings.protocolConfig(selectedServerIndex, selectedDockerContainer, Protocol::OpenVpn); + protocolConfig = getOpenVpnConfigFromPage(protocolConfig); + + QJsonObject containerConfig = m_settings.containerConfig(selectedServerIndex, selectedDockerContainer); + QJsonObject newContainerConfig = containerConfig; + newContainerConfig.insert(config_key::openvpn, protocolConfig); + + ErrorCode e = doInstallAction([this, containerConfig, newContainerConfig](){ + return ServerController::updateContainer(m_settings.serverCredentials(selectedServerIndex), selectedDockerContainer, containerConfig, newContainerConfig); + }, + ui->page_proto_openvpn, ui->progressBar_proto_openvpn_reset, + ui->pushButton_proto_openvpn_save, ui->label_proto_openvpn_info); + + if (!e) { + m_settings.setContainerConfig(selectedServerIndex, selectedDockerContainer, newContainerConfig); + m_settings.clearLastConnectionConfig(selectedServerIndex, selectedDockerContainer); + } + qDebug() << "Protocol saved with code:" << e << "for" << selectedServerIndex << selectedDockerContainer; + }); + + connect(ui->pushButton_proto_shadowsocks_save, &QPushButton::clicked, this, [this](){ + QJsonObject protocolConfig = m_settings.protocolConfig(selectedServerIndex, selectedDockerContainer, Protocol::ShadowSocks); + protocolConfig = getShadowSocksConfigFromPage(protocolConfig); + + QJsonObject containerConfig = m_settings.containerConfig(selectedServerIndex, selectedDockerContainer); + QJsonObject newContainerConfig = containerConfig; + newContainerConfig.insert(config_key::shadowsocks, protocolConfig); + + ErrorCode e = doInstallAction([this, containerConfig, newContainerConfig](){ + return ServerController::updateContainer(m_settings.serverCredentials(selectedServerIndex), selectedDockerContainer, containerConfig, newContainerConfig); + }, + ui->page_proto_shadowsocks, ui->progressBar_proto_shadowsocks_reset, + ui->pushButton_proto_shadowsocks_save, ui->label_proto_shadowsocks_info); + + if (!e) { + m_settings.setContainerConfig(selectedServerIndex, selectedDockerContainer, newContainerConfig); + m_settings.clearLastConnectionConfig(selectedServerIndex, selectedDockerContainer); + } + qDebug() << "Protocol saved with code:" << e << "for" << selectedServerIndex << selectedDockerContainer; + }); + + connect(ui->pushButton_proto_cloak_save, &QPushButton::clicked, this, [this](){ + QJsonObject protocolConfig = m_settings.protocolConfig(selectedServerIndex, selectedDockerContainer, Protocol::Cloak); + protocolConfig = getCloakConfigFromPage(protocolConfig); + + QJsonObject containerConfig = m_settings.containerConfig(selectedServerIndex, selectedDockerContainer); + QJsonObject newContainerConfig = containerConfig; + newContainerConfig.insert(config_key::cloak, protocolConfig); + + ErrorCode e = doInstallAction([this, containerConfig, newContainerConfig](){ + return ServerController::updateContainer(m_settings.serverCredentials(selectedServerIndex), selectedDockerContainer, containerConfig, newContainerConfig); + }, + ui->page_proto_cloak, ui->progressBar_proto_cloak_reset, + ui->pushButton_proto_cloak_save, ui->label_proto_cloak_info); + + if (!e) { + m_settings.setContainerConfig(selectedServerIndex, selectedDockerContainer, newContainerConfig); + m_settings.clearLastConnectionConfig(selectedServerIndex, selectedDockerContainer); + } + + qDebug() << "Protocol saved with code:" << e << "for" << selectedServerIndex << selectedDockerContainer; + }); + + + connect(ui->pushButton_proto_tor_web_site_cont_install, &QPushButton::clicked, this, [this](bool checked){ + DockerContainer container = DockerContainer::WebSiteInTor; + if (checked) { + ErrorCode e; + + e = ServerController::runScript(ServerController::sshParams(m_settings.serverCredentials(selectedServerIndex)), + "sudo docker stop amnezia-tor"); + + e = ServerController::runScript(ServerController::sshParams(m_settings.serverCredentials(selectedServerIndex)), + "sudo docker rm -f amnezia-tor"); + + e = ServerController::runScript(ServerController::sshParams(m_settings.serverCredentials(selectedServerIndex)), + "sudo docker stop amnezia-wp-tor"); + + e = ServerController::runScript(ServerController::sshParams(m_settings.serverCredentials(selectedServerIndex)), + "sudo docker rm -f amnezia-wp-tor"); + + e = doInstallAction([this, container](){ + return ServerController::setupContainer(m_settings.serverCredentials(selectedServerIndex), container); + }, + ui->page_server_protocols, ui->progressBar_protocols_container_reinstall, + nullptr, nullptr); + + + QString stdOut; + auto cbReadStdOut = [&](const QString &data, QSharedPointer proc) { + stdOut += data + "\n"; + }; + auto cbReadStdErr = [&](const QString &data, QSharedPointer proc) { + stdOut += data + "\n"; + }; + + e = ServerController::runScript(ServerController::sshParams(m_settings.serverCredentials(selectedServerIndex)), + "sudo docker exec -i amnezia-tor onions", + cbReadStdOut, cbReadStdErr); + + qDebug() << "amnezia-tor onions" << stdOut; + + QStringList l = stdOut.split(","); + for (QString s : l) { + if (s.contains(":80")) { + ui->label_tor_web_site->setText(s); + } + } + + } + else { + ui->pushButton_proto_tor_web_site_cont_install->setEnabled(false); + ErrorCode e = ServerController::removeContainer(m_settings.serverCredentials(selectedServerIndex), container); + m_settings.removeContainerConfig(selectedServerIndex, container); + ui->pushButton_proto_tor_web_site_cont_install->setEnabled(true); + + } + + //updateProtocolsPage(); + }); +} + +void MainWindow::setupNewServerPageConnections() +{ + connect(ui->pushButton_connect, SIGNAL(clicked(bool)), this, SLOT(onPushButtonConnectClicked(bool))); + connect(ui->pushButton_start_switch_page, &QPushButton::toggled, this, [this](bool toggled){ + if (toggled){ + ui->stackedWidget_start->setCurrentWidget(ui->page_start_new_server); + ui->pushButton_start_switch_page->setText(tr("Import connection")); + } + else { + ui->stackedWidget_start->setCurrentWidget(ui->page_start_import); + ui->pushButton_start_switch_page->setText(tr("Set up your own server")); + } + //goToPage(Page::NewServer); + }); + + connect(ui->pushButton_new_server_connect_key, &QPushButton::toggled, this, [this](bool checked){ + ui->label_new_server_password->setText(checked ? tr("Private key") : tr("Password")); + ui->pushButton_new_server_connect_key->setText(checked ? tr("Connect using SSH password") : tr("Connect using SSH key")); + ui->lineEdit_new_server_password->setVisible(!checked); + ui->textEdit_new_server_ssh_key->setVisible(checked); + }); + + connect(ui->pushButton_new_server_settings_cloak, &QPushButton::toggled, this, [this](bool toggle){ + ui->frame_new_server_settings_cloak->setMaximumHeight(toggle * 200); + if (toggle) + ui->frame_new_server_settings_parent_cloak->layout()->addWidget(ui->frame_new_server_settings_cloak); + else + ui->frame_new_server_settings_parent_cloak->layout()->removeWidget(ui->frame_new_server_settings_cloak); + }); + connect(ui->pushButton_new_server_settings_ss, &QPushButton::toggled, this, [this](bool toggle){ + ui->frame_new_server_settings_ss->setMaximumHeight(toggle * 200); + if (toggle) + ui->frame_new_server_settings_parent_ss->layout()->addWidget(ui->frame_new_server_settings_ss); + else + ui->frame_new_server_settings_parent_ss->layout()->removeWidget(ui->frame_new_server_settings_ss); + }); + connect(ui->pushButton_new_server_settings_openvpn, &QPushButton::toggled, this, [this](bool toggle){ + ui->frame_new_server_settings_openvpn->setMaximumHeight(toggle * 200); + if (toggle) + ui->frame_new_server_settings_parent_openvpn->layout()->addWidget(ui->frame_new_server_settings_openvpn); + else + ui->frame_new_server_settings_parent_openvpn->layout()->removeWidget(ui->frame_new_server_settings_ss); + }); +} + +void MainWindow::setupServerSettingsPageConnections() +{ + connect(ui->pushButton_servers_add_new, &QPushButton::clicked, this, [this](){ goToPage(Page::Start); }); + + connect(ui->pushButton_server_settings_protocols, &QPushButton::clicked, this, [this](){ goToPage(Page::ServerVpnProtocols); }); + connect(ui->pushButton_server_settings_share_full, &QPushButton::clicked, this, [this](){ + updateSharingPage(selectedServerIndex, m_settings.serverCredentials(selectedServerIndex), DockerContainer::None); + goToPage(Page::ShareConnection); + }); + + connect(ui->pushButton_server_settings_clear, SIGNAL(clicked(bool)), this, SLOT(onPushButtonClearServer(bool))); + connect(ui->pushButton_server_settings_forget, SIGNAL(clicked(bool)), this, SLOT(onPushButtonForgetServer(bool))); + + connect(ui->pushButton_server_settings_clear_client_cache, &QPushButton::clicked, this, [this](){ + ui->pushButton_server_settings_clear_client_cache->setText(tr("Cache cleared")); + + const auto &containers = m_settings.containers(selectedServerIndex); + for (DockerContainer container: containers.keys()) { + m_settings.clearLastConnectionConfig(selectedServerIndex, container); + } + + QTimer::singleShot(3000, this, [this]() { + ui->pushButton_server_settings_clear_client_cache->setText(tr("Clear client cached profile")); + }); + }); + + connect(ui->lineEdit_server_settings_description, &QLineEdit::editingFinished, this, [this](){ + const QString &newText = ui->lineEdit_server_settings_description->text(); + QJsonObject server = m_settings.server(selectedServerIndex); + server.insert(config_key::description, newText); + m_settings.editServer(selectedServerIndex, server); + updateServersListPage(); + }); + + connect(ui->lineEdit_server_settings_description, &QLineEdit::returnPressed, this, [this](){ + ui->lineEdit_server_settings_description->clearFocus(); + }); +} + +void MainWindow::setupSharePageConnections() +{ + connect(ui->pushButton_share_full_copy, &QPushButton::clicked, this, [this](){ + QGuiApplication::clipboard()->setText(ui->textEdit_share_full_code->toPlainText()); + ui->pushButton_share_full_copy->setText(tr("Copied")); + + QTimer::singleShot(3000, this, [this]() { + ui->pushButton_share_full_copy->setText(tr("Copy")); + }); + }); + + connect(ui->pushButton_share_full_save, &QPushButton::clicked, this, [this](){ + if (ui->textEdit_share_full_code->toPlainText().isEmpty()) return; + + QString fileName = QFileDialog::getSaveFileName(this, tr("Save AmneziaVPN config"), + QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.amnezia"); + QSaveFile save(fileName); + save.open(QIODevice::WriteOnly); + save.write(ui->textEdit_share_full_code->toPlainText().toUtf8()); + save.commit(); + }); + + connect(ui->pushButton_share_amnezia_copy, &QPushButton::clicked, this, [this](){ + if (ui->textEdit_share_amnezia_code->toPlainText().isEmpty()) return; + + QGuiApplication::clipboard()->setText(ui->textEdit_share_amnezia_code->toPlainText()); + ui->pushButton_share_amnezia_copy->setText(tr("Copied")); + + QTimer::singleShot(3000, this, [this]() { + ui->pushButton_share_amnezia_copy->setText(tr("Copy")); + }); + }); + + connect(ui->pushButton_share_amnezia_save, &QPushButton::clicked, this, [this](){ + if (ui->textEdit_share_amnezia_code->toPlainText().isEmpty()) return; + + QString fileName = QFileDialog::getSaveFileName(this, tr("Save AmneziaVPN config"), + QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.amnezia"); + QSaveFile save(fileName); + save.open(QIODevice::WriteOnly); + save.write(ui->textEdit_share_amnezia_code->toPlainText().toUtf8()); + save.commit(); + }); + + connect(ui->pushButton_share_openvpn_copy, &QPushButton::clicked, this, [this](){ + QGuiApplication::clipboard()->setText(ui->textEdit_share_openvpn_code->toPlainText()); + ui->pushButton_share_openvpn_copy->setText(tr("Copied")); + + QTimer::singleShot(3000, this, [this]() { + ui->pushButton_share_openvpn_copy->setText(tr("Copy")); + }); + }); + + connect(ui->pushButton_share_ss_copy, &QPushButton::clicked, this, [this](){ + QGuiApplication::clipboard()->setText(ui->lineEdit_share_ss_string->text()); + ui->pushButton_share_ss_copy->setText(tr("Copied")); + + QTimer::singleShot(3000, this, [this]() { + ui->pushButton_share_ss_copy->setText(tr("Copy")); + }); + }); + + connect(ui->pushButton_share_cloak_copy, &QPushButton::clicked, this, [this](){ + QGuiApplication::clipboard()->setText(ui->plainTextEdit_share_cloak->toPlainText()); + ui->pushButton_share_cloak_copy->setText(tr("Copied")); + + QTimer::singleShot(3000, this, [this]() { + ui->pushButton_share_cloak_copy->setText(tr("Copy")); + }); + }); + + connect(ui->pushButton_share_amnezia_generate, &QPushButton::clicked, this, [this](){ + ui->pushButton_share_amnezia_generate->setEnabled(false); + ui->pushButton_share_amnezia_copy->setEnabled(false); + ui->pushButton_share_amnezia_generate->setText(tr("Generating...")); + qApp->processEvents(); + + ServerCredentials credentials = m_settings.serverCredentials(selectedServerIndex); + QJsonObject containerConfig = m_settings.containerConfig(selectedServerIndex, selectedDockerContainer); + containerConfig.insert(config_key::container, containerToString(selectedDockerContainer)); + + ErrorCode e = ErrorCode::NoError; + for (Protocol p: amnezia::protocolsForContainer(selectedDockerContainer)) { + QJsonObject protoConfig = m_settings.protocolConfig(selectedServerIndex, selectedDockerContainer, p); + + QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, selectedDockerContainer, containerConfig, p, &e); + if (e) { + cfg = "Error generating config"; + break; + } + protoConfig.insert(config_key::last_config, cfg); + + containerConfig.insert(protoToString(p), protoConfig); + } + + QByteArray ba; + if (!e) { + QJsonObject serverConfig = m_settings.server(selectedServerIndex); + serverConfig.remove(config_key::userName); + serverConfig.remove(config_key::password); + serverConfig.remove(config_key::port); + serverConfig.insert(config_key::containers, QJsonArray {containerConfig}); + serverConfig.insert(config_key::defaultContainer, containerToString(selectedDockerContainer)); + + + ba = QJsonDocument(serverConfig).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); + ui->textEdit_share_amnezia_code->setPlainText(QString("vpn://%1").arg(QString(ba))); + } + else { + ui->textEdit_share_amnezia_code->setPlainText(tr("Error while generating connection profile")); + } + + ui->pushButton_share_amnezia_generate->setEnabled(true); + ui->pushButton_share_amnezia_copy->setEnabled(true); + ui->pushButton_share_amnezia_generate->setText(tr("Generate config")); + }); + + connect(ui->pushButton_share_openvpn_generate, &QPushButton::clicked, this, [this](){ + ui->pushButton_share_openvpn_generate->setEnabled(false); + ui->pushButton_share_openvpn_copy->setEnabled(false); + ui->pushButton_share_openvpn_save->setEnabled(false); + ui->pushButton_share_openvpn_generate->setText(tr("Generating...")); + + ServerCredentials credentials = m_settings.serverCredentials(selectedServerIndex); + const QJsonObject &containerConfig = m_settings.containerConfig(selectedServerIndex, selectedDockerContainer); + + ErrorCode e = ErrorCode::NoError; + QString cfg = OpenVpnConfigurator::genOpenVpnConfig(credentials, selectedDockerContainer, containerConfig, &e); + cfg = OpenVpnConfigurator::processConfigWithExportSettings(cfg); + + ui->textEdit_share_openvpn_code->setPlainText(cfg); + + ui->pushButton_share_openvpn_generate->setEnabled(true); + ui->pushButton_share_openvpn_copy->setEnabled(true); + ui->pushButton_share_openvpn_save->setEnabled(true); + ui->pushButton_share_openvpn_generate->setText(tr("Generate config")); + }); + + connect(ui->pushButton_share_openvpn_save, &QPushButton::clicked, this, [this](){ + QString fileName = QFileDialog::getSaveFileName(this, tr("Save OpenVPN config"), + QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.ovpn"); + + QSaveFile save(fileName); + save.open(QIODevice::WriteOnly); + save.write(ui->textEdit_share_openvpn_code->toPlainText().toUtf8()); + save.commit(); + }); +} + +void MainWindow::setTrayState(VpnProtocol::ConnectionState state) +{ + QString resourcesPath = ":/images/tray/%1"; + + m_trayActionDisconnect->setEnabled(state == VpnProtocol::Connected); + m_trayActionConnect->setEnabled(state == VpnProtocol::Disconnected); + + switch (state) { + case VpnProtocol::Disconnected: + setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName)); + break; + case VpnProtocol::Preparing: + setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName)); + break; + case VpnProtocol::Connecting: + setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName)); + break; + case VpnProtocol::Connected: + setTrayIcon(QString(resourcesPath).arg(ConnectedTrayIconName)); + break; + case VpnProtocol::Disconnecting: + setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName)); + break; + case VpnProtocol::Reconnecting: + setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName)); + break; + case VpnProtocol::Error: + setTrayIcon(QString(resourcesPath).arg(ErrorTrayIconName)); + break; + case VpnProtocol::Unknown: + default: + setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName)); + } + + //#ifdef Q_OS_MAC + // // Get theme from current user (note, this app can be launched as root application and in this case this theme can be different from theme of real current user ) + // bool darkTaskBar = MacOSFunctions::instance().isMenuBarUseDarkTheme(); + // darkTaskBar = forceUseBrightIcons ? true : darkTaskBar; + // resourcesPath = ":/images_mac/tray_icon/%1"; + // useIconName = useIconName.replace(".png", darkTaskBar ? "@2x.png" : " dark@2x.png"); + //#endif + +} + +void MainWindow::onTrayActivated(QSystemTrayIcon::ActivationReason reason) +{ +#if defined Q_OS_MACX || defined Q_OS_LINUX + if(reason == QSystemTrayIcon::DoubleClick || reason == QSystemTrayIcon::Trigger) { + show(); + raise(); + setWindowState(Qt::WindowActive); + } +#endif +} + +void MainWindow::onConnect() +{ + int serverIndex = m_settings.defaultServerIndex(); + ServerCredentials credentials = m_settings.serverCredentials(serverIndex); + DockerContainer container = m_settings.defaultContainer(serverIndex); + + if (m_settings.containers(serverIndex).isEmpty()) { + ui->label_error_text->setText(tr("VPN Protocols is not installed.\n Please install VPN container at first")); + ui->pushButton_connect->setChecked(false); + return; + } + + if (container == DockerContainer::None) { + ui->label_error_text->setText(tr("VPN Protocol not choosen")); + ui->pushButton_connect->setChecked(false); + return; + } + + + const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container); + onConnectWorker(serverIndex, credentials, container, containerConfig); +} + +void MainWindow::onConnectWorker(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig) +{ + ui->label_error_text->clear(); + ui->pushButton_connect->setChecked(true); + qApp->processEvents(); + + ErrorCode errorCode = m_vpnConnection->connectToVpn( + serverIndex, credentials, container, containerConfig + ); + + if (errorCode) { + //ui->pushButton_connect->setChecked(false); + QMessageBox::critical(this, APPLICATION_NAME, errorString(errorCode)); + return; + } + + ui->pushButton_connect->setEnabled(false); +} + +void MainWindow::onDisconnect() +{ + ui->pushButton_connect->setChecked(false); + m_vpnConnection->disconnectFromVpn(); +} + +void MainWindow::onTrayActionConnect() +{ + if(m_trayActionConnect->text() == tr("Connect")) { + onConnect(); + } else if(m_trayActionConnect->text() == tr("Disconnect")) { + onDisconnect(); + } +} + +void MainWindow::onPushButtonAddCustomSitesClicked() +{ + if (ui->radioButton_vpn_mode_all_sites->isChecked()) return; + Settings::RouteMode mode = m_settings.routeMode(); + + QString newSite = ui->lineEdit_sites_add_custom->text(); + + if (newSite.isEmpty()) return; + if (!newSite.contains(".")) return; + + if (!Utils::ipAddressWithSubnetRegExp().exactMatch(newSite)) { + // get domain name if it present + newSite.replace("https://", ""); + newSite.replace("http://", ""); + newSite.replace("ftp://", ""); + + newSite = newSite.split("/", QString::SkipEmptyParts).first(); + } + + const auto &cbProcess = [this, mode](const QString &newSite, const QString &ip) { + m_settings.addVpnSite(mode, newSite, ip); + + if (!ip.isEmpty()) { + m_vpnConnection->addRoutes(QStringList() << ip); + m_vpnConnection->flushDns(); + } + else if (Utils::ipAddressWithSubnetRegExp().exactMatch(newSite)) { + m_vpnConnection->addRoutes(QStringList() << newSite); + m_vpnConnection->flushDns(); + } + + updateSitesPage(); + }; + + const auto &cbResolv = [this, cbProcess](const QHostInfo &hostInfo){ + const QList &addresses = hostInfo.addresses(); + QString ipv4Addr; + for (const QHostAddress &addr: hostInfo.addresses()) { + if (addr.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) { + cbProcess(hostInfo.hostName(), addr.toString()); + break; + } + } + }; + + ui->lineEdit_sites_add_custom->clear(); + + if (Utils::ipAddressWithSubnetRegExp().exactMatch(newSite)) { + cbProcess(newSite, ""); + return; + } + else { + cbProcess(newSite, ""); + updateSitesPage(); + QHostInfo::lookupHost(newSite, this, cbResolv); + } +} + +void MainWindow::updateStartPage() +{ + ui->lineEdit_start_existing_code->clear(); + ui->textEdit_new_server_ssh_key->clear(); + ui->lineEdit_new_server_ip->clear(); + ui->lineEdit_new_server_password->clear(); + ui->textEdit_new_server_ssh_key->clear(); + ui->lineEdit_new_server_login->setText("root"); + + ui->label_new_server_wait_info->hide(); + ui->label_new_server_wait_info->clear(); + + ui->progressBar_new_server_connection->setMinimum(0); + ui->progressBar_new_server_connection->setMaximum(300); + + ui->pushButton_back_from_start->setVisible(!pagesStack.isEmpty()); + + ui->pushButton_new_server_connect->setVisible(true); +} + +void MainWindow::updateSitesPage() +{ + Settings::RouteMode m = m_settings.routeMode(); + if (m == Settings::VpnAllSites) return; + + if (m == Settings::VpnOnlyForwardSites) ui->label_sites_add_custom->setText(tr("These sites will be opened using VPN")); + if (m == Settings::VpnAllExceptSites) ui->label_sites_add_custom->setText(tr("These sites will be excepted from VPN")); + + ui->tableView_sites->setModel(sitesModels.value(m)); + sitesModels.value(m)->resetCache(); +} + +void MainWindow::updateVpnPage() +{ + Settings::RouteMode mode = m_settings.routeMode(); + ui->radioButton_vpn_mode_all_sites->setChecked(mode == Settings::VpnAllSites); + ui->radioButton_vpn_mode_forward_sites->setChecked(mode == Settings::VpnOnlyForwardSites); + ui->radioButton_vpn_mode_except_sites->setChecked(mode == Settings::VpnAllExceptSites); + ui->pushButton_vpn_add_site->setEnabled(mode != Settings::VpnAllSites); +} + +void MainWindow::updateAppSettingsPage() +{ + ui->checkBox_app_settings_autostart->setChecked(Autostart::isAutostart()); + ui->checkBox_app_settings_autoconnect->setChecked(m_settings.isAutoConnect()); + ui->checkBox_app_settings_start_minimized->setChecked(m_settings.isStartMinimized()); + + ui->lineEdit_network_settings_dns1->setText(m_settings.primaryDns()); + ui->lineEdit_network_settings_dns2->setText(m_settings.secondaryDns()); + + QString ver = QString("%1: %2 (%3)") + .arg(tr("Software version")) + .arg(QString(APP_MAJOR_VERSION)) + .arg(__DATE__); + ui->label_app_settings_version->setText(ver); +} + +void MainWindow::updateGeneralSettingPage() +{ + ui->pushButton_general_settings_share_connection->setEnabled(m_settings.haveAuthData(m_settings.defaultServerIndex())); +} + +void MainWindow::updateServerPage() +{ + ui->label_server_settings_wait_info->hide(); + ui->label_server_settings_wait_info->clear(); + + ui->pushButton_server_settings_clear->setVisible(m_settings.haveAuthData(selectedServerIndex)); + ui->pushButton_server_settings_clear_client_cache->setVisible(m_settings.haveAuthData(selectedServerIndex)); + ui->pushButton_server_settings_share_full->setVisible(m_settings.haveAuthData(selectedServerIndex)); + + QJsonObject server = m_settings.server(selectedServerIndex); + QString port = server.value(config_key::port).toString(); + ui->label_server_settings_server->setText(QString("%1@%2%3%4") + .arg(server.value(config_key::userName).toString()) + .arg(server.value(config_key::hostName).toString()) + .arg(port.isEmpty() ? "" : ":") + .arg(port)); + ui->lineEdit_server_settings_description->setText(server.value(config_key::description).toString()); + + QString selectedContainerName = m_settings.defaultContainerName(selectedServerIndex); + + ui->label_server_settings_current_vpn_protocol->setText(tr("Protocol: ") + selectedContainerName); + + //qDebug() << "DefaultContainer(selectedServerIndex)" << selectedServerIndex << containerToString(m_settings.defaultContainer(selectedServerIndex)); + +} + +void MainWindow::updateServersListPage() +{ + ui->listWidget_servers->clear(); + const QJsonArray &servers = m_settings.serversArray(); + int defaultServer = m_settings.defaultServerIndex(); + + ui->listWidget_servers->setUpdatesEnabled(false); + for(int i = 0; i < servers.size(); i++) { + makeServersListItem(ui->listWidget_servers, servers.at(i).toObject(), i == defaultServer, i); + } + ui->listWidget_servers->setUpdatesEnabled(true); +} + +void MainWindow::updateProtocolsPage() +{ + ui->progressBar_protocols_container_reinstall->hide(); + + auto containers = m_settings.containers(selectedServerIndex); + DockerContainer defaultContainer = m_settings.defaultContainer(selectedServerIndex); + bool haveAuthData = m_settings.haveAuthData(selectedServerIndex); + + // all containers + QList allContainers { + DockerContainer::OpenVpn, + DockerContainer::OpenVpnOverShadowSocks, + DockerContainer::OpenVpnOverCloak, + DockerContainer::WireGuard + }; + + // install buttons + QList installButtons { + ui->pushButton_proto_openvpn_cont_install, + ui->pushButton_proto_ss_openvpn_cont_install, + ui->pushButton_proto_cloak_openvpn_cont_install, + ui->pushButton_proto_wireguard_cont_install + }; + + // default buttons + QList defaultButtons { + ui->pushButton_proto_openvpn_cont_default, + ui->pushButton_proto_ss_openvpn_cont_default, + ui->pushButton_proto_cloak_openvpn_cont_default, + ui->pushButton_proto_wireguard_cont_default + }; + + // share buttons + QList shareButtons { + ui->pushButton_proto_openvpn_cont_share, + ui->pushButton_proto_ss_openvpn_cont_share, + ui->pushButton_proto_cloak_openvpn_cont_share, + ui->pushButton_proto_wireguard_cont_share + }; + + // frames + QList frames { + ui->frame_openvpn_settings, + ui->frame_openvpn_ss_settings, + ui->frame_openvpn_ss_cloak_settings, + ui->frame_wireguard_settings + }; + + for (int i = 0; i < allContainers.size(); ++i) { + defaultButtons.at(i)->setChecked(defaultContainer == allContainers.at(i)); + defaultButtons.at(i)->setVisible(haveAuthData && containers.contains(allContainers.at(i))); + shareButtons.at(i)->setVisible(haveAuthData && containers.contains(allContainers.at(i))); + installButtons.at(i)->setChecked(containers.contains(allContainers.at(i))); + installButtons.at(i)->setEnabled(haveAuthData); + frames.at(i)->setVisible(containers.contains(allContainers.at(i))); + + } +} + +void MainWindow::updateOpenVpnPage(const QJsonObject &openvpnConfig, DockerContainer container, bool haveAuthData) +{ + ui->widget_proto_openvpn->setEnabled(haveAuthData); + ui->pushButton_proto_openvpn_save->setVisible(haveAuthData); + ui->progressBar_proto_openvpn_reset->setVisible(haveAuthData); + + ui->radioButton_proto_openvpn_udp->setEnabled(true); + ui->radioButton_proto_openvpn_tcp->setEnabled(true); + + ui->lineEdit_proto_openvpn_subnet->setText(openvpnConfig.value(config_key::subnet_address). + toString(protocols::openvpn::defaultSubnetAddress)); + + QString trasnsport = openvpnConfig.value(config_key::transport_proto). + toString(protocols::openvpn::defaultTransportProto); + + ui->radioButton_proto_openvpn_udp->setChecked(trasnsport == protocols::openvpn::defaultTransportProto); + ui->radioButton_proto_openvpn_tcp->setChecked(trasnsport != protocols::openvpn::defaultTransportProto); + + ui->comboBox_proto_openvpn_cipher->setCurrentText(openvpnConfig.value(config_key::cipher). + toString(protocols::openvpn::defaultCipher)); + + ui->comboBox_proto_openvpn_hash->setCurrentText(openvpnConfig.value(config_key::hash). + toString(protocols::openvpn::defaultHash)); + + bool blockOutsideDns = openvpnConfig.value(config_key::block_outside_dns).toBool(protocols::openvpn::defaultBlockOutsideDns); + ui->checkBox_proto_openvpn_block_dns->setChecked(blockOutsideDns); + + bool isNcpDisabled = openvpnConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable); + ui->checkBox_proto_openvpn_auto_encryption->setChecked(!isNcpDisabled); + + bool isTlsAuth = openvpnConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth); + ui->checkBox_proto_openvpn_tls_auth->setChecked(isTlsAuth); + + if (container == DockerContainer::OpenVpnOverShadowSocks) { + ui->radioButton_proto_openvpn_udp->setEnabled(false); + ui->radioButton_proto_openvpn_tcp->setEnabled(false); + ui->radioButton_proto_openvpn_tcp->setChecked(true); + } + + ui->lineEdit_proto_openvpn_port->setText(openvpnConfig.value(config_key::port). + toString(protocols::openvpn::defaultPort)); + + ui->lineEdit_proto_openvpn_port->setEnabled(container == DockerContainer::OpenVpn); +} + +void MainWindow::updateShadowSocksPage(const QJsonObject &ssConfig, DockerContainer container, bool haveAuthData) +{ + ui->widget_proto_ss->setEnabled(haveAuthData); + ui->pushButton_proto_shadowsocks_save->setVisible(haveAuthData); + ui->progressBar_proto_shadowsocks_reset->setVisible(haveAuthData); + + ui->comboBox_proto_shadowsocks_cipher->setCurrentText(ssConfig.value(config_key::cipher). + toString(protocols::shadowsocks::defaultCipher)); + + ui->lineEdit_proto_shadowsocks_port->setText(ssConfig.value(config_key::port). + toString(protocols::shadowsocks::defaultPort)); + + ui->lineEdit_proto_shadowsocks_port->setEnabled(container == DockerContainer::OpenVpnOverShadowSocks); +} + +void MainWindow::updateCloakPage(const QJsonObject &ckConfig, DockerContainer container, bool haveAuthData) +{ + ui->widget_proto_cloak->setEnabled(haveAuthData); + ui->pushButton_proto_cloak_save->setVisible(haveAuthData); + ui->progressBar_proto_cloak_reset->setVisible(haveAuthData); + + ui->comboBox_proto_cloak_cipher->setCurrentText(ckConfig.value(config_key::cipher). + toString(protocols::cloak::defaultCipher)); + + ui->lineEdit_proto_cloak_site->setText(ckConfig.value(config_key::site). + toString(protocols::cloak::defaultRedirSite)); + + ui->lineEdit_proto_cloak_port->setText(ckConfig.value(config_key::port). + toString(protocols::cloak::defaultPort)); + + ui->lineEdit_proto_cloak_port->setEnabled(container == DockerContainer::OpenVpnOverCloak); +} + +void MainWindow::updateSharingPage(int serverIndex, const ServerCredentials &credentials, + DockerContainer container) +{ + selectedDockerContainer = container; + selectedServerIndex = serverIndex; + + //const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container); + + for (QWidget *page : { + ui->page_share_amnezia, + ui->page_share_openvpn, + ui->page_share_shadowsocks, + ui->page_share_cloak, + ui->page_share_full_access }) { + + ui->toolBox_share_connection->removeItem(ui->toolBox_share_connection->indexOf(page)); + page->hide(); + } + + if (container == DockerContainer::OpenVpn) { + ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client")); + ui->toolBox_share_connection->addItem(ui->page_share_openvpn, tr(" Share for OpenVPN client")); + + QString cfg = tr("Press Generate config"); + ui->textEdit_share_openvpn_code->setPlainText(cfg); + ui->pushButton_share_openvpn_copy->setEnabled(false); + ui->pushButton_share_openvpn_save->setEnabled(false); + + ui->toolBox_share_connection->setCurrentWidget(ui->page_share_openvpn); + } + + if (container == DockerContainer::OpenVpnOverShadowSocks || + container == DockerContainer::OpenVpnOverCloak) { + ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client")); + ui->toolBox_share_connection->addItem(ui->page_share_shadowsocks, tr(" Share for ShadowSocks client")); + + QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::ShadowSocks); + QString cfg = protoConfig.value(config_key::last_config).toString(); + + if (cfg.isEmpty()) { + const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container); + + ErrorCode e = ErrorCode::NoError; + cfg = ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, &e); + + ui->pushButton_share_ss_copy->setEnabled(true); + } + + QJsonObject ssConfig = QJsonDocument::fromJson(cfg.toUtf8()).object(); + + QString ssString = QString("%1:%2@%3:%4") + .arg(ssConfig.value("method").toString()) + .arg(ssConfig.value("password").toString()) + .arg(ssConfig.value("server").toString()) + .arg(ssConfig.value("server_port").toString()); + + ssString = "ss://" + ssString.toUtf8().toBase64(); + ui->lineEdit_share_ss_string->setText(ssString); + updateQRCodeImage(ssString, ui->label_share_ss_qr_code); + + ui->label_share_ss_server->setText(ssConfig.value("server").toString()); + ui->label_share_ss_port->setText(ssConfig.value("server_port").toString()); + ui->label_share_ss_method->setText(ssConfig.value("method").toString()); + ui->label_share_ss_password->setText(ssConfig.value("password").toString()); + + ui->toolBox_share_connection->setCurrentWidget(ui->page_share_shadowsocks); + ui->page_share_shadowsocks->show(); + ui->page_share_shadowsocks->raise(); + qDebug() << ui->page_share_shadowsocks->size(); + ui->toolBox_share_connection->layout()->update(); + } + + if (container == DockerContainer::OpenVpnOverCloak) { + //ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client")); + ui->toolBox_share_connection->addItem(ui->page_share_cloak, tr(" Share for Cloak client")); + ui->plainTextEdit_share_cloak->setPlainText(QString("")); + + QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::Cloak); + QString cfg = protoConfig.value(config_key::last_config).toString(); + + if (cfg.isEmpty()) { + const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container); + + ErrorCode e = ErrorCode::NoError; + cfg = CloakConfigurator::genCloakConfig(credentials, container, containerConfig, &e); + + ui->pushButton_share_cloak_copy->setEnabled(true); + } + + QJsonObject cloakConfig = QJsonDocument::fromJson(cfg.toUtf8()).object(); + cloakConfig.remove(config_key::transport_proto); + cloakConfig.insert("ProxyMethod", "shadowsocks"); + + ui->plainTextEdit_share_cloak->setPlainText(QJsonDocument(cloakConfig).toJson()); + } + + // Full access + if (container == DockerContainer::None) { + ui->toolBox_share_connection->addItem(ui->page_share_full_access, tr(" Share server full access")); + + const QJsonObject &server = m_settings.server(selectedServerIndex); + + QByteArray ba = QJsonDocument(server).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); + + ui->textEdit_share_full_code->setText(QString("vpn://%1").arg(QString(ba))); + ui->toolBox_share_connection->setCurrentWidget(ui->page_share_full_access); + } + + //ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client")); + + // Amnezia sharing +// QJsonObject exportContainer; +// for (Protocol p: protocolsForContainer(container)) { +// QJsonObject protocolConfig = containerConfig.value(protoToString(p)).toObject(); +// protocolConfig.remove(config_key::last_config); +// exportContainer.insert(protoToString(p), protocolConfig); +// } +// exportContainer.insert(config_key::container, containerToString(container)); + +// ui->textEdit_share_amnezia_code->setPlainText(QJsonDocument(exportContainer).toJson()); + + ui->textEdit_share_amnezia_code->setPlainText(tr("")); +} + +void MainWindow::makeServersListItem(QListWidget *listWidget, const QJsonObject &server, bool isDefault, int index) +{ + QSize size(310, 70); + ServerWidget* widget = new ServerWidget(server, isDefault); + + widget->resize(size); + + connect(widget->ui->pushButton_default, &QPushButton::clicked, this, [this, index](){ + m_settings.setDefaultServer(index); + updateServersListPage(); + }); + +// connect(widget->ui->pushButton_share, &QPushButton::clicked, this, [this, index](){ +// goToPage(Page::ShareConnection); +// // update share page +// }); + + connect(widget->ui->pushButton_settings, &QPushButton::clicked, this, [this, index](){ + selectedServerIndex = index; + goToPage(Page::ServerSettings); + }); + + QListWidgetItem* item = new QListWidgetItem(listWidget); + item->setSizeHint(size); + listWidget->setItemWidget(item, widget); + + widget->setStyleSheet(styleSheet()); +} + +void MainWindow::updateQRCodeImage(const QString &text, QLabel *label) +{ + int levelIndex = 1; + int versionIndex = 0; + bool bExtent = true; + int maskIndex = -1; + + m_qrEncode.EncodeData( levelIndex, versionIndex, bExtent, maskIndex, text.toUtf8().data() ); + + int qrImageSize = m_qrEncode.m_nSymbleSize; + + int encodeImageSize = qrImageSize + ( QR_MARGIN * 2 ); + QImage encodeImage( encodeImageSize, encodeImageSize, QImage::Format_Mono ); + + encodeImage.fill( 1 ); + + for ( int i = 0; i < qrImageSize; i++ ) + for ( int j = 0; j < qrImageSize; j++ ) + if ( m_qrEncode.m_byModuleData[i][j] ) + encodeImage.setPixel( i + QR_MARGIN, j + QR_MARGIN, 0 ); + + label->setPixmap(QPixmap::fromImage(encodeImage.scaledToWidth(label->width()))); +} + +QJsonObject MainWindow::getOpenVpnConfigFromPage(QJsonObject oldConfig) +{ + oldConfig.insert(config_key::subnet_address, ui->lineEdit_proto_openvpn_subnet->text()); + oldConfig.insert(config_key::transport_proto, ui->radioButton_proto_openvpn_udp->isChecked() ? protocols::UDP : protocols::TCP); + oldConfig.insert(config_key::ncp_disable, ! ui->checkBox_proto_openvpn_auto_encryption->isChecked()); + oldConfig.insert(config_key::cipher, ui->comboBox_proto_openvpn_cipher->currentText()); + oldConfig.insert(config_key::hash, ui->comboBox_proto_openvpn_hash->currentText()); + oldConfig.insert(config_key::block_outside_dns, ui->checkBox_proto_openvpn_block_dns->isChecked()); + oldConfig.insert(config_key::port, ui->lineEdit_proto_openvpn_port->text()); + oldConfig.insert(config_key::tls_auth, ui->checkBox_proto_openvpn_tls_auth->isChecked()); + + return oldConfig; +} + +QJsonObject MainWindow::getShadowSocksConfigFromPage(QJsonObject oldConfig) +{ + oldConfig.insert(config_key::cipher, ui->comboBox_proto_shadowsocks_cipher->currentText()); + oldConfig.insert(config_key::port, ui->lineEdit_proto_shadowsocks_port->text()); + + return oldConfig; +} + +QJsonObject MainWindow::getCloakConfigFromPage(QJsonObject oldConfig) +{ + oldConfig.insert(config_key::cipher, ui->comboBox_proto_cloak_cipher->currentText()); + oldConfig.insert(config_key::site, ui->lineEdit_proto_cloak_site->text()); + oldConfig.insert(config_key::port, ui->lineEdit_proto_cloak_port->text()); + + return oldConfig; +} diff --git a/client/ui/mainwindow.ui b/client/ui/mainwindow.ui new file mode 100644 index 000000000..789131bf3 --- /dev/null +++ b/client/ui/mainwindow.ui @@ -0,0 +1,7838 @@ + + + MainWindow + + + + 0 + 0 + 380 + 670 + + + + AmneziaVPN + + + QMainWindow { + background: white; +} + + +QWidget { +font-family: "Lato"; +} + +/*----------------------*/ + +QPushButton { + font-size: 16px; + outline: none; + font-style: normal; + font-weight: normal; + + border: none; +} +QPushButton:disabled { + border: none; +} + +QLabel { + outline: none; + font-size: 16px; + + font-style: normal; + font-weight: normal; + color: #181922; +} +QLabel:disabled { + color: #A7A7A7; +} + +QMessageBox QLabel { + font: 16px "Lato"; +} + + +/*----------------------*/ + +QTextEdit { +background: #F4F4F4; + +/* grey */ +border: 1px solid #A7A7A7; +color: #333333; + +} + +QComboBox { +font-size: 16px; +} + +QLineEdit { +font-size: 16px; +selection-background-color: darkgray; + +background: #F4F4F4; + +border: 1px solid #A7A7A7; +color: #333333; +} + +QLineEdit:focus { + border-bottom:2px solid rgb(200, 200, 200); +} +QLineEdit[error] { + border-bottom:2px solid rgb(213, 40, 60); + color: rgb(213, 40, 60); +} +QLineEdit:disabled { + border-bottom:2px solid rgb(127, 127, 127); + color: rgb(127, 127, 127); +} + +QRadioButton { + color: #181922; + font-size: 16px; + background: transparent; +} + +QCheckBox { + color: #181922; + font-size: 16px; + background: transparent; +} + +QCheckBox::indicator { +min-height: 20px; +min-width: 20px; + +border-image: url(:/images/controls/check_off.png) 0 0 0 0 stretch stretch; +} + +QCheckBox::indicator:unchecked { +border-image: url(:/images/controls/check_off.png) 0 0 0 0 stretch stretch; +} + +QCheckBox::indicator:checked { +border-image: url(:/images/controls/check_on.png); + +} + + +QScrollBar:vertical { /* The area behind the scrollbar covering entire height. */ + background-color: rgba(0, 0, 0,0); + opacity: 100; + width: 10px; /* set width to zero to hide scrollbar entirely. Can look quite clean and scrolling still works with mousewheel. */ + margin: 10px px; /* Takes the height of the buttons + 3 extra pixels to leave some free space between handle and buttons */ + +} + +QScrollBar::handle:vertical { /* The handle you scroll with */ + image-position: center; /* image is used as a small gripper in the center of the scrollbar.. You can also use background-image to use two images */ + background-color: rgb(200, 200, 200); + border: 2px solid rgb(240,240,240); + border-radius: 1px; + min-height: 10px; +} +QScrollBar::handle:vertical:hover { /* state when you hover over the handle */ + background-color: rgb(160, 160, 160); +} +QScrollBar::handle:vertical:pressed { /* state when you hover over the handle */ + background-color: rgb(120, 120, 120); +} +QScrollBar::sub-line:vertical { /* button to scroll up */ + background-color: rgb(240,240,240); + height: 10px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover { /* hover state of button to scroll up */ + background-color: rgb(200, 200, 200); +} + +QScrollBar::up-arrow:vertical { /* arrow to scroll up with */ + top: 2px; +} + +QScrollBar::add-line:vertical { /* Button to scroll down */ + background-color: rgb(240,240,240); + height: 10px; + padding-top: 2px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} +QScrollBar::add-line:vertical:hover { /* hover state of button to scroll down */ + background-color: rgb(200, 200, 200); +} + +QScrollBar::down-arrow:vertical { /* arrow to scroll down with */ + bottom: 3px; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background-color: rgb(240,240,240); + +} + + + + + + + + + 0 + 0 + 380 + 670 + + + + QWidget #widget_main { + background: white; +} + + + + + + 0 + 0 + 380 + 30 + + + + true + + + background: #F5F5F5; + + + + + + 330 + 10 + 16 + 16 + + + + PointingHandCursor + + + image: url(:/images/listitembg.png); +image-position: right; + + + + + + + + + + 360 + 8 + 13 + 13 + + + + PointingHandCursor + + + QPushButton { +image-position: right; +image: url(:/images/close.png); + + padding:1px; +} +QPushButton:hover { + padding:0px; +} + + + + + + + + + + + 0 + 30 + 380 + 640 + + + + + + + 16 + + + + + + 110 + 590 + 150 + 22 + + + + image: url(:/images/AmneziaVPN.png); + + + + + + + + + 40 + 530 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; + +color: #100A44; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +border: 1px solid #211C4A; +border-radius: 4px; +} + + + + Set up your own server + + + true + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 0 + 35 + 380 + 481 + + + + + + + 40 + 210 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + +QPushButton:hover { +background: #211966; +} + + + + Connect + + + + + + 40 + 140 + 300 + 40 + + + + + + + + + + vpn://... + + + + + + 0 + 20 + 381 + 71 + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +color: #100A44; +} + + + + Connect to the already created VPN server + + + Qt::AlignCenter + + + true + + + + + + 40 + 110 + 301 + 21 + + + + + + + Connection code + + + + + + + + 40 + 260 + 300 + 71 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Lato'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + + 50 + 40 + 281 + 21 + + + + PointingHandCursor + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 20px; +text-align: center; + +/* акцент */ +color: #15CDCB; + + + Where to get connection data → + + + + + + 10 + 0 + 361 + 31 + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +color: #100A44; +} + + + + Setup your server to use VPN + + + Qt::AlignCenter + + + true + + + + + + 40 + 100 + 300 + 40 + + + + + + + + + + + + + 40 + 350 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Connect + + + + + + 40 + 180 + 300 + 40 + + + + + + + root + + + + + + 40 + 450 + 281 + 21 + + + + PointingHandCursor + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 20px; +text-align: center; + +/* акцент */ +color: #15CDCB; + + + Connect using SSH key + + + true + + + true + + + + + + 40 + 260 + 300 + 40 + + + + QLineEdit { + background: #F4F4F4; + border: 1px solid #A7A7A7; + color: #333333; +} + + + + + + QLineEdit::Password + + + + + + 40 + 70 + 171 + 21 + + + + + + + Server IP address + + + + + + 40 + 150 + 261 + 21 + + + + + + + Login to connect via SSH + + + + + + 40 + 230 + 171 + 21 + + + + + + + Password + + + + + true + + + + 40 + 390 + 301 + 41 + + + + Please wait, configuring process may take up to 5 minutes + + + true + + + textEdit_new_server_ssh_key + pushButton_new_server_get_info + lineEdit_new_server_ip + pushButton_new_server_connect + lineEdit_new_server_login + pushButton_new_server_connect_key + lineEdit_new_server_password + label_4 + label_5 + label_new_server_password + label_2 + label_new_server_wait_info + + + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +color: #211C4A; +} + +QLineEdit { +padding-left: 10px; +border: 1px solid #A7A7A7; +} + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 110 + 590 + 150 + 22 + + + + image: url(:/images/AmneziaVPN.png); + + + + + + + + + 40 + 310 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Configure VPN protocols manually + + + + + + 10 + 35 + 361 + 31 + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +color: #100A44; +} + + + + Setup your server to use VPN + + + Qt::AlignCenter + + + true + + + + + + 40 + 150 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Run Setup Wizard + + + + + + 40 + 100 + 301 + 41 + + + + + + + If you want easily configure your server just run Wizard + + + Qt::AlignBottom|Qt::AlignHCenter + + + true + + + + + + 40 + 260 + 301 + 41 + + + + + + + Press configure manually to choose VPN protocols you want to install + + + Qt::AlignBottom|Qt::AlignHCenter + + + true + + + + + + + + 0 + 35 + 381 + 31 + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +color: #100A44; +} + + + + Setup Wizard + + + Qt::AlignCenter + + + true + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 10 + 70 + 361 + 561 + + + + + + 10 + 10 + 331 + 25 + + + + High censorship level + + + + + + 10 + 180 + 331 + 30 + + + + Medium censorship level + + + true + + + + + + 10 + 330 + 331 + 30 + + + + Low censorship level + + + + + + 30 + 40 + 321 + 121 + + + + I'm living in country with high censorship level. Many of foreign web sites and VPNs blocked by my government. I want to setup reliable VPN, which is invisible for government. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 30 + 210 + 321 + 101 + + + + I'm living in country with medium censorship level. Some web sites blocked by my government, but VPNs are not blocked at all. I want to setup flexible solution. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 30 + 360 + 321 + 51 + + + + I just want to improve my privacy in internet. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 30 + 490 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Next + + + + + + + + + 0 + 35 + 381 + 31 + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +color: #100A44; +} + + + + Setup Wizard + + + Qt::AlignCenter + + + true + + + + + + 10 + 70 + 361 + 561 + + + + QLabel { + font-size: 16px; +} + + + + + 30 + 10 + 321 + 321 + + + + AmneziaVPN will install VPN protocol which is not visible for your internet provider and government firewall. Your VPN connection will be detected by your provider as regular web traffic to particular web site. + +You SHOULD set this web site address to some foreign web site which is not blocked by your internet provider. Other words you need to type below some foreign web site address which is accessible without VPN. + +Please note, this protocol still does not support export connection profile to mobile devices. Keep for updates. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 30 + 400 + 321 + 71 + + + + OpenVPN over Cloak (VPN obfuscation) profile will be installed + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + true + + + + + + 30 + 490 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Next + + + + + + 30 + 360 + 301 + 41 + + + + + + + 30 + 330 + 291 + 21 + + + + Type web site address for mask + + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + + + 10 + 70 + 361 + 561 + + + + QLabel { + font-size: 16px; +} + + + + + 30 + 10 + 321 + 341 + + + + Optional. + +We recommend to enable VPN mode "For selected sites" and add blocked sites you need to visit manually. If you will choose this option, you will need add every bloked site you want to visit to the access list. You may switch between modes later. + +Please note, you should add addresses to the list after VPN connection established. You may add any domain, URL or IP address, it will be resolved to IP address. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 30 + 490 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Start configuring + + + + + + 30 + 350 + 301 + 71 + + + + Turn on mode "VPN for selected sites" + + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 0 + 35 + 381 + 31 + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +color: #100A44; +} + + + + Setup Wizard + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 35 + 381 + 31 + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +color: #100A44; +} + + + + Setup Wizard + + + Qt::AlignCenter + + + true + + + + + + 10 + 70 + 361 + 561 + + + + QLabel { + font-size: 16px; +} + + + + + 30 + 10 + 321 + 341 + + + + AmneziaVPN will install VPN protocol which is difficult to detect by your internet provider and government firewall (but possible). In most cases, this is the most suitable protocol. This protocol is faster compared to the VPN protocols with "web traffic masking". + +This protocol support export connection profile to mobile devices using QR code (you should launch 3rd party opensource VPN client - ShadowSocks VPN). + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 30 + 400 + 321 + 71 + + + + OpenVPN over ShadowSocks profile will be installed + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + true + + + + + + 30 + 490 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Next + + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + + + 0 + 35 + 381 + 31 + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +color: #100A44; +} + + + + Setup Wizard + + + Qt::AlignCenter + + + true + + + + + + 10 + 70 + 361 + 561 + + + + QLabel { + font-size: 16px; +} + + + + + 30 + 10 + 321 + 341 + + + + AmneziaVPN will install OpenVPN protocol with public/private key pairs generated on server and client sides. You can also configure connection on your mobile device by copying exported ".ovpn" file to your device and setting up official OpenVPN client. We recommend do not use messengers for sending connection profile - it contains VPN private keys. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 30 + 400 + 321 + 71 + + + + OpenVPN profile will be installed + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + true + + + + + + 30 + 490 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Start configuring + + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + + + 40 + 510 + 301 + 40 + + + + QProgressBar{ +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + +QProgressBar::chunk { +background: rgba(255, 255, 255, 0.15); +border-radius: 4px 0px 0px 4px; + +} + + + + 0 + + + Qt::AlignCenter + + + true + + + Configuring... + + + + + + 0 + 35 + 381 + 31 + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +color: #100A44; +} + + + + Configuring... + + + Qt::AlignCenter + + + true + + + + + + 30 + 90 + 321 + 31 + + + + Please wait. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + true + + + + 40 + 560 + 301 + 41 + + + + Please wait, configuring process may take up to 5 minutes + + + true + + + + + + + + 10 + 35 + 361 + 31 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +line-height: 25px; +color: #100A44; + + + + Select VPN protocols + + + Qt::AlignCenter + + + true + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 0 + 70 + 380 + 471 + + + + + 380 + 0 + + + + + 380 + 16777215 + + + + QScrollArea { background: transparent; } +QScrollArea > QWidget > QWidget { background: transparent; } +QScrollArea > QWidget > QScrollBar { background: palette(base); } + +QLineEdit { +background: transparent; +} +QPushButton { + text-align: left; + background-repeat:no-repeat; + background-position:left top; + + background-image: url(:/images/settings.png); + padding-left: 30px; + min-height: 24px; +} +QFrame { +background: transparent; +border: 1px solid lightgrey; +border-radius: 2px; +} +QFrame#scrollArea_server_protocols { +border: none; +} +QLabel { +border: none; +} + + + true + + + + + 0 + 0 + 378 + 469 + + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + 0 + 0 + + + + + 0 + 100 + + + + + + + + QLayout::SetMinAndMaxSize + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + + + + + OpenVPN and ShadowSocks + with masking using Cloak plugin + + + true + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + PointingHandCursor + + + + + + true + + + + + + + + + + + + + + 130 + 0 + + + + + 130 + 16777215 + + + + Port (TCP) + + + + + + + + 185 + 0 + + + + + 185 + 16777215 + + + + 443 + + + + + + + + 130 + 0 + + + + + 130 + 16777215 + + + + Fake Web Site + + + + + + + + 185 + 0 + + + + + 185 + 16777215 + + + + tile.openstreetmap.org + + + + + + + + + + + + + + 0 + 100 + + + + + + + + QLayout::SetMinAndMaxSize + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + + + 0 + 24 + + + + ShadowSocks + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + PointingHandCursor + + + + + + true + + + + + + + + + + + + + + 130 + 0 + + + + + 130 + 16777215 + + + + Port(TCP) + + + + + + + + 185 + 0 + + + + + 185 + 16777215 + + + + 6789 + + + + + + + + 130 + 0 + + + + + 130 + 16777215 + + + + Encryption + + + + + + + + 185 + 0 + + + + + 185 + 16777215 + + + + + chacha20-ietf-poly1305 + + + + + xchacha20-ietf-poly1305 + + + + + aes-256-gcm + + + + + aes-192-gcm + + + + + aes-128-gcm + + + + + + + + + + + + + + + 0 + 100 + + + + + + + + QLayout::SetMinAndMaxSize + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + + + 0 + 0 + + + + + 0 + 24 + + + + OpenVPN + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + PointingHandCursor + + + + + + true + + + + + + + + + + + + + + 130 + 0 + + + + + 130 + 16777215 + + + + Port + + + + + + + + 185 + 0 + + + + + 185 + 16777215 + + + + + + + + + 130 + 0 + + + + + 130 + 16777215 + + + + Protocol + + + + + + + + 185 + 0 + + + + + 185 + 16777215 + + + + + udp + + + + + tcp + + + + + + + + + + + + + + + 0 + 100 + + + + + + + + QLayout::SetMinAndMaxSize + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + + + 0 + 0 + + + + + 0 + 24 + + + + WireGuard + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + PointingHandCursor + + + + + + true + + + + + + + + + + + + + + 130 + 0 + + + + + 130 + 16777215 + + + + Port + + + + + + + + 185 + 0 + + + + + 185 + 16777215 + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + + + 40 + 570 + 301 + 40 + + + + QProgressBar{ +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + +QProgressBar::chunk { +background: rgba(255, 255, 255, 0.15); +border-radius: 4px 0px 0px 4px; + +} + + + + 24 + + + Qt::AlignCenter + + + true + + + Configuring... + + + + + + 40 + 570 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Setup server + + + + + + + + + + + 0 + 0 + 380 + 325 + + + + border-image: url(:/images/background_connected.png); + + + + + + true + + + + + + 0 + 360 + 380 + 51 + + + + + + + + + 53 + 10 + 15 + 15 + + + + image: url(:/images/download.png); + + + + + + + + + 311 + 10 + 15 + 15 + + + + image: url(:/images/upload.png); + + + + + + + + + 260 + 20 + 118 + 30 + + + + + Lato + -1 + 50 + false + false + + + + color: rgb(66, 209, 133); +font: 16px "Lato"; + + + 0 Mbps + + + Qt::AlignCenter + + + + + + 0 + 20 + 127 + 30 + + + + + Lato + -1 + 50 + false + false + + + + color: rgb(65, 113, 214); +font: 16px "Lato"; + + + 0 Mbps + + + Qt::AlignCenter + + + + + + true + + + + 20 + 560 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} + +QPushButton:!enabled { +background: #484952; +} + +QPushButton:hover { +background: #282932; +} + + + + Add site + + + + + + 340 + 10 + 31 + 31 + + + + PointingHandCursor + + + image: url(:/images/settings_grey.png); +background: transparent + + + + + + + + + 150 + 200 + 80 + 40 + + + + PointingHandCursor + + + QPushButton:!checked { +image: url(:/images/connect_button_disconnected.png); +} + +QPushButton:checked { +image: url(:/images/connect_button_connected.png); +} + + + + + + true + + + false + + + + + + 0 + 250 + 380 + 31 + + + + font-family: "Lato"; + +font-style: normal; +font-weight: 600; +font-size: 15px; + +color: #181922; + + + + Connected + + + Qt::AlignCenter + + + + + + 20 + 424 + 341 + 1 + + + + background-image: url(:/images/Line.png); + + + + + + + + + 20 + 440 + 281 + 21 + + + + font-family: "Lato"; + +font-style: normal; +font-weight: 600; +font-size: 15px; + +color: #181922; + + + + + How to use VPN + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 0 + 280 + 381 + 61 + + + + Error text + + + false + + + Qt::AlignCenter + + + true + + + + + + 20 + 470 + 351 + 91 + + + + + true + + + + 0 + 60 + 341 + 19 + + + + Except selected sites + + + false + + + + + true + + + + 0 + 30 + 341 + 19 + + + + For selected sites + + + false + + + + + true + + + + 0 + 0 + 341 + 19 + + + + For all connections + + + true + + + + + + + /*QListView { + outline: 0; + background: transparent; + border: none; + gridline-color: darkgray; +} + +QListView::item +{ + padding-left: 5px; + border: none; + color: #181922; +} + +QListView::item:disabled +{ + padding-left: 5px; + border: none; + color: #181922; +} + +QListView::item:selected { + border: none; + background: rgba(167, 167, 167, 0.1); + color: #181922; +} +*/ + + + + + 10 + 10 + 28 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 10 + 0 + 360 + 0 + + + + List of the most popular prohibited sites + + + Qt::AlignCenter + + + true + + + + + true + + + + 20 + 40 + 340 + 60 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +color: #100A44; + + + + These sites will be opened using VPN + + + Qt::AlignHCenter|Qt::AlignTop + + + true + + + + + + 20 + 140 + 231 + 31 + + + + + Lato + -1 + 50 + false + false + + + + QLineEdit { + border: none; + + font-size: 16px; + background:transparent; + + selection-background-color: darkgray; + border: 1px solid #A7A7A7; +} + + + + + + Qt::AlignCenter + + + yousite.com or IP address + + + + + true + + + + 260 + 140 + 51 + 31 + + + + PointingHandCursor + + + QPushButton { +background: #100A44; +border-radius: 4px; +font-size: 24px; +color: white +} +QPushButton:hover { +background: #211966; +} + + + + + + + + + + 20 + 110 + 311 + 21 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +/* identical to box height, or 24px */ + +/* text */ +color: #333333; + + + Web site/Hostname/IP address/Subnet + + + + + + 20 + 200 + 341 + 371 + + + + QTableView { + background: transparent; + gridline-color: transparent; + + border: none; + outline: none; + show-decoration-selected: 1; +} + +QTableView::item +{ + padding-left: 5px; + border-top: 1px solid lightgray; + color: #181922; +} + +QTableView::item::selected +{ + border: 0px; + padding-left: 5px; + background-color: rgb(99, 180, 251); + border: : rgb(99, 180, 251); +} + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + false + + + Qt::NoPen + + + false + + + false + + + false + + + + + + 80 + 589 + 231 + 31 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Delete selected + + + + + true + + + + 320 + 140 + 51 + 31 + + + + PointingHandCursor + + + QPushButton { +background: #100A44; +border-radius: 4px; +padding: 5px; +image: url(:/images/folder.png); +} +QPushButton:hover { +background: #211966; +} + + + + + + + + + QPushButton { +font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +Text-align:left; +padding-left: 30px; + + +/* black */ +color: #100A44; + +background-repeat: no-repeat; + background-position: left center; +} + +QPushButton:!enabled { +color: #AAAAAA; +} + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 10 + 40 + 360 + 10 + + + + image: url(:/images/line.png); + + + + + + + + + 30 + 180 + 330 + 30 + + + + PointingHandCursor + + + Reinstall server, clear server + + + background-image: url(:/images/server_settings.png); + + + Server management + + + + + + 10 + 160 + 360 + 10 + + + + image: url(:/images/line.png); + + + + + + + + true + + + + 30 + 240 + 330 + 30 + + + + PointingHandCursor + + + background-image: url(:/images/share.png); + + + Share connection + + + + + + 10 + 220 + 360 + 10 + + + + image: url(:/images/line.png); + + + + + + + + + 10 + 620 + 360 + 10 + + + + image: url(:/images/line.png); + + + + + + + + true + + + + 30 + 580 + 330 + 30 + + + + PointingHandCursor + + + + + + Exit + + + + + + 10 + 560 + 360 + 10 + + + + image: url(:/images/line.png); + + + + + + + + + 30 + 60 + 330 + 30 + + + + PointingHandCursor + + + Auto start, Auto connect + + + background-image: url(:/images/settings.png); + + + + App settings + + + + + + 10 + 280 + 360 + 10 + + + + image: url(:/images/line.png); + + + + + + + + + 10 + 100 + 360 + 10 + + + + image: url(:/images/line.png); + + + + + + + + + 30 + 120 + 330 + 30 + + + + PointingHandCursor + + + DNS settings + + + background-image: url(:/images/settings.png); + + + + Network settings + + + + + + 30 + 300 + 330 + 30 + + + + PointingHandCursor + + + Reinstall server, clear server + + + background-image: url(:/images/server_settings.png); + + + Servers + + + + + + 10 + 340 + 360 + 10 + + + + image: url(:/images/line.png); + + + + + + + + + 10 + 400 + 360 + 10 + + + + image: url(:/images/line.png); + + + + + + + + + 30 + 360 + 330 + 30 + + + + PointingHandCursor + + + Add or import new server + + + background-image: url(:/images/plus.png); + + + + Add server + + + + + + + + + + + 20 + 90 + 340 + 501 + + + + QWidget { + margin: 0px; + padding: 0px; +} + +QPushButton:hover { + image: url(:/images/close.png); + image-position: right center; +} + +QListView { + outline: 0; + background: transparent; + border: none; + gridline-color: darkgray; + show-decoration-selected: 1; +} + +QListView::item +{ + padding-left: 5px; + color: #181922; + border: none; + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #FAFBFE, stop: 1 #ECEEFF); +} + +QListView::item:disabled +{ + padding-left: 5px; + border: none; + color: #181922; +} + +QListView::item:selected { + border: none; + background: rgba(167, 167, 167, 0.1); + color: #181922; +} + +QListView::item:selected:!active { + background: transparent; + border: none; +} + +QListView::item:selected:active { + background: transparent; + border: none; +} + +QListView::item:hover { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #FAFBFE, stop: 1 #DCDEDF); +} + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::NoSelection + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 50 + 30 + 171 + 40 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +color: #100A44; + + + + Servers list + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 240 + 39 + 24 + 24 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/plus.png); + padding:1px; +} +QPushButton:hover { + padding:0px; +} + + + + + + + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 110 + 590 + 150 + 22 + + + + image: url(:/images/AmneziaVPN.png); + + + + + + + + + 30 + 100 + 211 + 31 + + + + Auto start + + + + + + 20 + 30 + 340 + 40 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +color: #100A44; + + + + Application Settings + + + Qt::AlignCenter + + + + + + 30 + 140 + 211 + 31 + + + + Auto connect + + + + + + 30 + 280 + 321 + 41 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + +QPushButton:hover { +background: #211966; +} + + + Check for updates + + + + + + 30 + 240 + 281 + 21 + + + + Software version: X.X.X (01.06.2021) + + + + + + 30 + 180 + 211 + 31 + + + + Start minimized + + + + + + 30 + 340 + 321 + 41 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + +QPushButton:hover { +background: #211966; +} + + + Open logs folder + + + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 110 + 590 + 150 + 22 + + + + image: url(:/images/AmneziaVPN.png); + + + + + + + + + 40 + 120 + 271 + 40 + + + + + + + + + + + + + 20 + 30 + 340 + 40 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +color: #100A44; + + + + DNS Servers + + + Qt::AlignCenter + + + + + + 40 + 200 + 271 + 40 + + + + + + + + + + + + true + + + + 320 + 130 + 18 + 18 + + + + PointingHandCursor + + + Reset to default value + + + QPushButton { +image: url(:/images/reload.png); +padding:1px; +} +QPushButton:hover { +padding:0px; +} + + + + + + + + + true + + + + 320 + 210 + 18 + 18 + + + + PointingHandCursor + + + Reset to default value + + + QPushButton { +image: url(:/images/reload.png); +padding:1px; +} +QPushButton:hover { +padding:0px; +} + + + + + + + + + true + + + + 40 + 95 + 291 + 21 + + + + Primary DNS server + + + true + + + + + true + + + + 40 + 175 + 291 + 21 + + + + Secondray DNS server + + + true + + + + + + + true + + + + 40 + 530 + 301 + 41 + + + + Please wait, configuring process may take up to 5 minutes + + + true + + + + + + 40 + 350 + 300 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Clear client cached profile + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 20 + 30 + 340 + 40 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +color: #100A44; + + + + Server settings + + + Qt::AlignCenter + + + true + + + + + + 110 + 590 + 150 + 22 + + + + image: url(:/images/AmneziaVPN.png); + + + + + + + + + 40 + 410 + 300 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Clear server from Amnezia software + + + + + + 40 + 470 + 300 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Forget this server + + + + + + 20 + 120 + 341 + 31 + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 20px; +} + + + root@yourserver.org + + + Qt::AlignCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 70 + 80 + 251 + 31 + + + + QLineEdit { +border: none; +outline: none; +border-bottom: 1px solid lightgrey; +font-size: 18px; +font-weight: bold; +} + + + + Qt::AlignCenter + + + false + + + + + + 40 + 210 + 300 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + VPN protocols + + + + + + 20 + 150 + 341 + 31 + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 20px; +} + + + VPN Protocol: + + + Qt::AlignCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 40 + 260 + 300 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Share Server (FULL ACCESS) + + + label_server_settings_wait_info + label_16 + label_17 + pushButton_server_settings_clear_client_cache + pushButton_server_settings_clear + pushButton_server_settings_forget + label_server_settings_server + lineEdit_server_settings_description + pushButton_server_settings_protocols + pushButton_back_from_server_settings + label_server_settings_current_vpn_protocol + pushButton_server_settings_share_full + + + + + + + + + 20 + 440 + 340 + 121 + + + + QWidget { + margin: 0px; + padding: 0px; +} + +QPushButton:hover { + image: url(:/images/close.png); + image-position: right center; +} + +QListView { + outline: 0; + background: transparent; + border: none; + gridline-color: darkgray; + show-decoration-selected: 1; +} + +QListView::item +{ + padding-left: 5px; + color: #181922; + border: none; + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #FAFBFE, stop: 1 #ECEEFF); +} + +QListView::item:disabled +{ + padding-left: 5px; + border: none; + color: #181922; +} + +QListView::item:selected { + border: none; + background: rgba(167, 167, 167, 0.1); + color: #181922; +} + +QListView::item:selected:!active { + background: transparent; + border: none; +} + +QListView::item:selected:active { + background: transparent; + border: none; +} + +QListView::item:hover { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #FAFBFE, stop: 1 #DCDEDF); +} + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::NoSelection + + + + + + 20 + 30 + 340 + 40 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +color: #100A44; + + + + Protocols + + + Qt::AlignCenter + + + true + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 0 + 70 + 381 + 511 + + + + QWidget { +background: transparent; +} +QPushButton { + text-align: left; + background-repeat:no-repeat; + background-position:left top; + + background-image: url(:/images/settings.png); + padding-left: 30px; + min-height: 24px; +} +QFrame { +border: 1px solid lightgrey; +border-radius: 2px; +} +QFrame#scrollArea_server_protocols { +border: none; +} +QLabel { +border: none; +} + + + true + + + + + 0 + -47 + 371 + 558 + + + + + 19 + + + + + + 0 + 100 + + + + + + + + QLayout::SetMinAndMaxSize + + + + + + + Cloak container + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + QPushButton { + background: transparent; + image: url(:/images/check.png); + padding: 0px; + margin: 0px; +} +QPushButton:checked { + image: url(:/images/check.png); +} +QPushButton:!checked { + image: url(:/images/uncheck.png); +} + + + + + + + + true + + + false + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + background: transparent; +image: url(:/images/share.png); +padding: 0px; +margin: 0px; + + + + + + + + + + + 36 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + QPushButton { + background: transparent; + padding: 0px; + margin: 0px; +} +QPushButton:checked { + image: url(:/images/connect_button_connected.png); +} +QPushButton:!checked { + image: url(:/images/connect_button_disconnected.png); +} + + + + + + + true + + + false + + + + + + + + + + + + PointingHandCursor + + + OpenVPN settings + + + + + + + PointingHandCursor + + + ShadowSocks settings + + + + + + + PointingHandCursor + + + Cloak settings + + + + + + + + + + + + + + 0 + 100 + + + + + QLayout::SetMinAndMaxSize + + + + + + + ShadowSocks container + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + QPushButton { + background: transparent; + image: url(:/images/check.png); + padding: 0px; + margin: 0px; +} +QPushButton:checked { + image: url(:/images/check.png); +} +QPushButton:!checked { + image: url(:/images/uncheck.png); +} + + + + + + + true + + + false + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + background: transparent; +image: url(:/images/share.png); +padding: 0px; +margin: 0px; + + + + + + + + + + + 36 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + QPushButton { + background: transparent; + padding: 0px; + margin: 0px; +} +QPushButton:checked { + image: url(:/images/connect_button_connected.png); +} +QPushButton:!checked { + image: url(:/images/connect_button_disconnected.png); +} + + + + + + + true + + + + + + + + + + + + PointingHandCursor + + + OpenVPN settings + + + + + + + PointingHandCursor + + + ShadowSocks settings + + + + + + + + + + + + + + 0 + 100 + + + + + + + + QLayout::SetMinAndMaxSize + + + + + + + OpenVPN container + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + QPushButton { + background: transparent; + image: url(:/images/check.png); + padding: 0px; + margin: 0px; +} +QPushButton:checked { + image: url(:/images/check.png); +} +QPushButton:!checked { + image: url(:/images/uncheck.png); +} + + + + + + + true + + + false + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + background: transparent; +image: url(:/images/share.png); +padding: 0px; +margin: 0px; + + + + + + + + + + + 36 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + QPushButton { + background: transparent; + padding: 0px; + margin: 0px; +} +QPushButton:checked { + image: url(:/images/connect_button_connected.png); +} +QPushButton:!checked { + image: url(:/images/connect_button_disconnected.png); +} + + + + + + + true + + + + + + + + + + + + PointingHandCursor + + + OpenVPN settings + + + + + + + + + + + + + + 0 + 100 + + + + + + + + QLayout::SetMinAndMaxSize + + + + + + + WireGuard container + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + QPushButton { + background: transparent; + image: url(:/images/check.png); + padding: 0px; + margin: 0px; +} +QPushButton:checked { + image: url(:/images/check.png); +} +QPushButton:!checked { + image: url(:/images/uncheck.png); +} + + + + + + + true + + + false + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + background: transparent; +image: url(:/images/share.png); +padding: 0px; +margin: 0px; + + + + + + + + + + + 36 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + QPushButton { + background: transparent; + padding: 0px; + margin: 0px; +} +QPushButton:checked { + image: url(:/images/connect_button_connected.png); +} +QPushButton:!checked { + image: url(:/images/connect_button_disconnected.png); +} + + + + + + + true + + + + + + + + + + + + PointingHandCursor + + + WireGuard settings + + + + + + + + + + + + + + 0 + 100 + + + + + + + + QLayout::SetMinAndMaxSize + + + + + + + TOR Web site + + + + + + + + 36 + 24 + + + + + 24 + 24 + + + + PointingHandCursor + + + QPushButton { + background: transparent; + padding: 0px; + margin: 0px; +} +QPushButton:checked { + image: url(:/images/connect_button_connected.png); +} +QPushButton:!checked { + image: url(:/images/connect_button_disconnected.png); +} + + + + + + + true + + + + + + + + + + + + Not installed + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 40 + 580 + 300 + 40 + + + + QProgressBar{ +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + +QProgressBar::chunk { +background: rgba(255, 255, 255, 0.15); +border-radius: 4px 0px 0px 4px; + +} + + + + 24 + + + Qt::AlignCenter + + + true + + + Configuring... + + + + + + QScrollBar::sub-line:vertical { /* button to scroll up */ + border-top-right-radius: 3px; + background-color: rgb(240,240,240); + height: 10px; + subcontrol-position: top; + subcontrol-origin: margin; + margin-top: 3px; +} + + +QScrollBar::add-line:vertical { /* Button to scroll down */ + border-bottom-right-radius: 3px; + background-color: rgb(240,240,240); + height: 10px; + padding-top: 2px; + subcontrol-position: bottom; + subcontrol-origin: margin; + margin-bottom: 3px; +} + + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background-color: rgb(240,240,240); +} + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 10 + 40 + 360 + 580 + + + + + 0 + 0 + + + + + Lato + 50 + false + false + + + + QToolBox { +margins: 0px; +} + +QToolBox QFrame { +background: transparent; +} + +QToolBox > QWidget { +font: 25px "Lato"; +background: transparent; +border-radius: 5px; + + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #F1F1F1, stop: 0.4 #FFFFFF, + stop: 0.5 #F8F8F8, stop: 1.0 #FFFFFF); + +} + +QToolBox::tab { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #E1E1E1, stop: 0.4 #DDDDDD, + stop: 0.5 #D8D8D8, stop: 1.0 #D3D3D3); +border-radius: 2px; +font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 18px; +color: #100A44; +image: url(:/images/share.png); +image-position: left; +padding-left: 10px; + + border-color: #DDDDDD; + border-bottom: 2px solid #DDDDDD; +} + +QToolBox::tab:hover { + border-color: #148CD2; + border-bottom: 2px solid #148CD2; +} + + + QFrame::NoFrame + + + 0 + + + 3 + + + 6 + + + + + 0 + 0 + 100 + 30 + + + + + + + Full access + + + + + 10 + 10 + 341 + 100 + + + + QTextEdit { + +background: #F5F5F5; +border-radius: 10px; + + +font-family: Consolas; +font-style: normal; +font-weight: bold; +font-size: 20px; + +text-align: center; + +color: #15CDCB; + +} + + + + QTextEdit::FixedColumnWidth + + + 30 + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Consolas'; font-size:20px; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:20pt;">vpn:\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</span></p></body></html> + + + + + + 10 + 260 + 341 + 111 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +color: #181922; + + + + Anyone who logs in with this code will have the same permissions to use VPN and your server as you. +This code includes your server credentials! +Provide this code only to TRUSTED users. + + + Qt::AlignJustify|Qt::AlignTop + + + true + + + + + + 10 + 130 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} +QPushButton:hover { +background: #282932; +} + + + Copy + + + + + + 10 + 180 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} +QPushButton:hover { +background: #282932; +} + + + Save file + + + + + + + 0 + 0 + 100 + 30 + + + + Share for Amnezia client + + + + + 10 + 10 + 341 + 100 + + + + QTextEdit { + +background: #F5F5F5; +border-radius: 10px; + + +font-family: Consolas; +font-style: normal; +font-weight: bold; +font-size: 20px; + +text-align: center; + +color: #15CDCB; + +} + + + + QTextEdit::FixedColumnWidth + + + 30 + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Consolas'; font-size:20px; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:20pt;">vpn:\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</span></p></body></html> + + + + + + 10 + 280 + 341 + 81 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +color: #181922; + + + + Anyone who logs in with this code will be able to connect to this VPN server. +This code does not include server credentials. + + + Qt::AlignJustify|Qt::AlignTop + + + true + + + + + + 10 + 180 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} +QPushButton:hover { +background: #282932; +} + + + Copy + + + + + + 10 + 130 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} +QPushButton:hover { +background: #282932; +} + + + Generate config + + + + + + 10 + 230 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} +QPushButton:hover { +background: #282932; +} + + + Save file + + + + + + + 0 + 0 + 100 + 30 + + + + Share for OpenVPN client + + + + + 10 + 10 + 341 + 100 + + + + QTextEdit { + +background: #F5F5F5; +border-radius: 10px; + + +font-family: Consolas; +font-style: normal; +font-weight: bold; +font-size: 20px; + +text-align: center; + +color: #15CDCB; + +} + + + + QTextEdit::FixedColumnWidth + + + 30 + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Consolas'; font-size:20px; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:20pt;">vpn:\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</span></p></body></html> + + + + + + 10 + 180 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} +QPushButton:hover { +background: #282932; +} + + + Copy + + + + + + 10 + 230 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} +QPushButton:hover { +background: #282932; +} + + + Save file + + + + + + 10 + 130 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} +QPushButton:hover { +background: #282932; +} + + + Generate config + + + + + + + 0 + 0 + 360 + 360 + + + + + + + Share for ShadowSocks client + + + + + 10 + 70 + 100 + 20 + + + + Password + + + + + + 10 + 10 + 100 + 20 + + + + Server: + + + + + + 10 + 50 + 100 + 20 + + + + Encryption: + + + + + + 10 + 30 + 100 + 20 + + + + Port: + + + + + + 130 + 10 + 111 + 20 + + + + Server: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 130 + 50 + 201 + 20 + + + + Encryption: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 130 + 30 + 111 + 20 + + + + Port: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 130 + 70 + 201 + 20 + + + + Password: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 10 + 100 + 191 + 20 + + + + Connection string + + + + + + 10 + 180 + 331 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} +QPushButton:hover { +background: #282932; +} + + + Copy + + + + + + 85 + 235 + 200 + 200 + + + + + + + + + + + + + 10 + 130 + 331 + 40 + + + + QLineEdit { +background: #F5F5F5; +border-radius: 10px; + + +font-family: Consolas; +font-style: normal; +font-weight: bold; +font-size: 20px; + +text-align: center; + +color: #15CDCB; + +} + + + + + + + 0 + 0 + 100 + 30 + + + + Share for Cloak client + + + + + 10 + 290 + 331 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} +QPushButton:hover { +background: #282932; +} + + + Copy + + + + + + 10 + 30 + 331 + 221 + + + + + + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 0 + 40 + 380 + 600 + + + + + + 10 + 0 + 340 + 30 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +color: #100A44; + + + + OpenVPN Settings + + + Qt::AlignCenter + + + true + + + + + true + + + + 200 + 310 + 151 + 21 + + + + Hash + + + true + + + + + true + + + + 30 + 310 + 151 + 21 + + + + Cipher + + + true + + + + + true + + + + 30 + 110 + 151 + 21 + + + + Network protocol + + + true + + + + + + 30 + 65 + 321 + 31 + + + + + + + + + + + + + 30 + 340 + 151 + 31 + + + + + AES-256-GCM + + + + + AES-192-GCM + + + + + AES-128-GCM + + + + + AES-256-CBC + + + + + AES-192-CBC + + + + + AES-128-CBC + + + + + ChaCha20-Poly1305 + + + + + ARIA-256-CBC + + + + + CAMELLIA-256-CBC + + + + + none + + + + + + true + + + + 30 + 40 + 291 + 21 + + + + VPN Addresses Subnet + + + true + + + + + + 30 + 500 + 321 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Save and restart VPN + + + + + + 30 + 140 + 321 + 71 + + + + QFrame{ + border: 1px solid lightgray; + border-radius: 2px; + margin-top: 0px; +} + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 40 + 171 + 19 + + + + TCP + + + + + + 10 + 10 + 171 + 19 + + + + UDP + + + + + + + 200 + 230 + 151 + 31 + + + + + + + + + + + + + 30 + 280 + 321 + 21 + + + + Auto-negotiate encryption + + + false + + + + + + 200 + 340 + 151 + 31 + + + + + SHA512 + + + + + SHA384 + + + + + SHA256 + + + + + SHA3-512 + + + + + SHA3-384 + + + + + SHA3-256 + + + + + whirlpool + + + + + BLAKE2b512 + + + + + BLAKE2s256 + + + + + SHA1 + + + + + + true + + + + 30 + 230 + 151 + 31 + + + + Port + + + true + + + + + + 30 + 430 + 321 + 21 + + + + Block DNS requests outside of VPN + + + false + + + + + + 30 + 500 + 321 + 40 + + + + QProgressBar{ +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + +QProgressBar::chunk { +background: rgba(255, 255, 255, 0.15); +border-radius: 4px 0px 0px 4px; + +} + + + + 24 + + + Qt::AlignCenter + + + true + + + Configuring... + + + + + true + + + + 30 + 550 + 321 + 41 + + + + + + + Qt::AlignCenter + + + true + + + + + + 30 + 390 + 321 + 21 + + + + Enable TLS auth + + + false + + + progressBar_proto_openvpn_reset + label_38 + label_97 + label_99 + label_100 + lineEdit_proto_openvpn_subnet + comboBox_proto_openvpn_cipher + label_98 + pushButton_proto_openvpn_save + frame_3 + lineEdit_proto_openvpn_port + checkBox_proto_openvpn_auto_encryption + comboBox_proto_openvpn_hash + label_103 + checkBox_proto_openvpn_block_dns + label_proto_openvpn_info + checkBox_proto_openvpn_tls_auth + + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 0 + 40 + 380 + 600 + + + + + + 190 + 110 + 151 + 31 + + + + + + + + + + + + + 20 + 0 + 340 + 30 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +color: #100A44; + + + + ShadowSocks Settings + + + Qt::AlignCenter + + + true + + + + + true + + + + 30 + 110 + 151 + 31 + + + + Port + + + true + + + + + + 190 + 60 + 151 + 31 + + + + + chacha20-poly1305 + + + + + aes-256-gcm + + + + + aes-128-gcm + + + + + + true + + + + 30 + 60 + 151 + 31 + + + + Cipher + + + true + + + + + + 30 + 500 + 321 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Save and restart VPN + + + + + + 30 + 500 + 321 + 40 + + + + QProgressBar{ +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + +QProgressBar::chunk { +background: rgba(255, 255, 255, 0.15); +border-radius: 4px 0px 0px 4px; + +} + + + + 24 + + + Qt::AlignCenter + + + true + + + Configuring... + + + + + true + + + + 30 + 550 + 321 + 41 + + + + + + + Qt::AlignCenter + + + true + + + progressBar_proto_shadowsocks_reset + lineEdit_proto_shadowsocks_port + label_43 + label_104 + comboBox_proto_shadowsocks_cipher + label_101 + pushButton_proto_shadowsocks_save + label_proto_shadowsocks_info + + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 0 + 40 + 381 + 600 + + + + + + 190 + 160 + 151 + 31 + + + + + + + + + + + + true + + + + 30 + 160 + 151 + 31 + + + + Port + + + true + + + + + + 20 + 0 + 340 + 30 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +color: #100A44; + + + + Cloak Settings + + + Qt::AlignCenter + + + true + + + + + + 190 + 110 + 151 + 31 + + + + + + + tile.openstreetmap.org + + + + + true + + + + 30 + 60 + 151 + 31 + + + + Cipher + + + true + + + + + + 30 + 110 + 130 + 31 + + + + + 130 + 0 + + + + + 130 + 16777215 + + + + Fake Web Site + + + + + + 190 + 60 + 151 + 31 + + + + + chacha20-poly1305 + + + + + aes-256-gcm + + + + + aes-192-gcm + + + + + aes-128-gcm + + + + + plain + + + + + + + 30 + 500 + 321 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} +QPushButton:hover { +background: #211966; +} + + + Save and restart VPN + + + + + + 30 + 500 + 321 + 40 + + + + QProgressBar{ +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + +QProgressBar::chunk { +background: rgba(255, 255, 255, 0.15); +border-radius: 4px 0px 0px 4px; + +} + + + + 24 + + + Qt::AlignCenter + + + true + + + Configuring... + + + + + true + + + + 30 + 550 + 321 + 41 + + + + + + + Qt::AlignCenter + + + true + + + progressBar_proto_cloak_reset + lineEdit_proto_cloak_port + label_105 + label_44 + lineEdit_proto_cloak_site + label_102 + label_47 + comboBox_proto_cloak_cipher + pushButton_proto_cloak_save + label_proto_cloak_info + + + + + + + + + + SlidingStackedWidget + QStackedWidget +
ui/Controls/SlidingStackedWidget.h
+ 1 +
+
+ + +
diff --git a/client/ui/pages_logic/ServerConfiguringProgressLogic.cpp b/client/ui/pages_logic/ServerConfiguringProgressLogic.cpp index befbb7e25..8909a9f53 100644 --- a/client/ui/pages_logic/ServerConfiguringProgressLogic.cpp +++ b/client/ui/pages_logic/ServerConfiguringProgressLogic.cpp @@ -1,4 +1,9 @@ #include "ServerConfiguringProgressLogic.h" +#include "defines.h" +#include "core/errorstrings.h" +#include +#include +#include ServerConfiguringProgressLogic::ServerConfiguringProgressLogic(UiLogic *logic, QObject *parent): PageLogicBase(logic, parent), @@ -13,3 +18,105 @@ ServerConfiguringProgressLogic::ServerConfiguringProgressLogic(UiLogic *logic, Q } + +ErrorCode ServerConfiguringProgressLogic::doInstallAction(const std::function &action) +{ + PageFunc page; + page.setEnabledFunc = [this] (bool enabled) -> void { + set_pageEnabled(enabled); + }; + ButtonFunc button; + LabelFunc info; + ProgressFunc progress; + progress.setVisibleFunc = [this] (bool visible) ->void { + set_progressBarVisible(visible); + }; + + progress.setValueFunc = [this] (int value) ->void { + set_progressBarValue(value); + }; + progress.getValueFunc = [this] (void) -> int { + return progressBarValue(); + }; + progress.getMaximiumFunc = [this] (void) -> int { + return progressBarMaximium(); + }; + + + + progress.setVisibleFunc(true); + if (page.setEnabledFunc) { + page.setEnabledFunc(false); + } + if (button.setVisibleFunc) { + button.setVisibleFunc(false); + } + if (info.setVisibleFunc) { + info.setVisibleFunc(true); + } + if (info.setTextFunc) { + info.setTextFunc(tr("Please wait, configuring process may take up to 5 minutes")); + } + + QTimer timer; + connect(&timer, &QTimer::timeout, [progress](){ + progress.setValueFunc(progress.getValueFunc() + 1); + }); + + progress.setValueFunc(0); + timer.start(1000); + + ErrorCode e = action(); + qDebug() << "doInstallAction finished with code" << e; + + if (e) { + if (page.setEnabledFunc) { + page.setEnabledFunc(true); + } + if (button.setVisibleFunc) { + button.setVisibleFunc(true); + } + if (info.setVisibleFunc) { + info.setVisibleFunc(false); + } + QMessageBox::warning(nullptr, APPLICATION_NAME, + tr("Error occurred while configuring server.") + "\n" + + errorString(e)); + + progress.setVisibleFunc(false); + return e; + } + + // just ui progressbar tweak + timer.stop(); + + int remaining_val = progress.getMaximiumFunc() - progress.getValueFunc(); + + if (remaining_val > 0) { + QTimer timer1; + QEventLoop loop1; + + connect(&timer1, &QTimer::timeout, [&](){ + progress.setValueFunc(progress.getValueFunc() + 1); + if (progress.getValueFunc() >= progress.getMaximiumFunc()) { + loop1.quit(); + } + }); + + timer1.start(5); + loop1.exec(); + } + + + progress.setVisibleFunc(false); + if (button.setVisibleFunc) { + button.setVisibleFunc(true); + } + if (page.setEnabledFunc) { + page.setEnabledFunc(true); + } + if (info.setTextFunc) { + info.setTextFunc(tr("Operation finished")); + } + return ErrorCode::NoError; +} diff --git a/client/ui/pages_logic/ServerConfiguringProgressLogic.h b/client/ui/pages_logic/ServerConfiguringProgressLogic.h index f6c007a4a..edd2f4e9e 100644 --- a/client/ui/pages_logic/ServerConfiguringProgressLogic.h +++ b/client/ui/pages_logic/ServerConfiguringProgressLogic.h @@ -1,6 +1,7 @@ #ifndef SERVER_CONFIGURING_PROGRESS_LOGIC_H #define SERVER_CONFIGURING_PROGRESS_LOGIC_H +#include #include "PageLogicBase.h" class UiLogic; @@ -21,5 +22,27 @@ public: explicit ServerConfiguringProgressLogic(UiLogic *uiLogic, QObject *parent = nullptr); ~ServerConfiguringProgressLogic() = default; + ErrorCode doInstallAction(const std::function &action); + +private: + struct ProgressFunc { + std::function setVisibleFunc; + std::function setValueFunc; + std::function getValueFunc; + std::function getMaximiumFunc; + std::function setTextVisibleFunc; + std::function setTextFunc; + }; + struct PageFunc { + std::function setEnabledFunc; + }; + struct ButtonFunc { + std::function setVisibleFunc; + }; + struct LabelFunc { + std::function setVisibleFunc; + std::function setTextFunc; + }; + }; #endif // SERVER_CONFIGURING_PROGRESS_LOGIC_H diff --git a/client/ui/pages_logic/ServerContainersLogic.cpp b/client/ui/pages_logic/ServerContainersLogic.cpp index 14352ea3b..5dc4d0ab3 100644 --- a/client/ui/pages_logic/ServerContainersLogic.cpp +++ b/client/ui/pages_logic/ServerContainersLogic.cpp @@ -1,5 +1,9 @@ #include "ServerContainersLogic.h" #include "ShareConnectionLogic.h" +#include "ServerConfiguringProgressLogic.h" + +#include + #include "protocols/CloakLogic.h" #include "protocols/OpenVpnLogic.h" #include "protocols/ShadowSocksLogic.h" @@ -10,105 +14,17 @@ #include "../uilogic.h" ServerContainersLogic::ServerContainersLogic(UiLogic *logic, QObject *parent): - PageLogicBase(logic, parent), - m_progressBarProtocolsContainerReinstallValue{0}, - m_progressBarProtocolsContainerReinstallMaximium{100}, - m_pushButtonOpenVpnContInstallEnabled{false}, - m_pushButtonSsOpenVpnContInstallEnabled{false}, - m_pushButtonCloakOpenVpnContInstallEnabled{false}, - m_pushButtonWireguardContInstallEnabled{false}, - m_pushButtonOpenVpnContDefaultChecked{false}, - m_pushButtonSsOpenVpnContDefaultChecked{false}, - m_pushButtonCloakOpenVpnContDefaultChecked{false}, - m_pushButtonWireguardContDefaultChecked{false}, - m_pushButtonOpenVpnContDefaultVisible{true}, - m_pushButtonSsOpenVpnContDefaultVisible{false}, - m_pushButtonCloakOpenVpnContDefaultVisible{false}, - m_pushButtonWireguardContDefaultVisible{false}, - m_pushButtonOpenVpnContShareVisible{false}, - m_pushButtonSsOpenVpnContShareVisible{false}, - m_pushButtonCloakOpenVpnContShareVisible{false}, - m_pushButtonWireguardContShareVisible{false}, - m_frameOpenvpnSettingsVisible{true}, - m_frameOpenvpnSsSettingsVisible{true}, - m_frameOpenvpnSsCloakSettingsVisible{true}, - m_progressBarProtocolsContainerReinstallVisible{false}, - m_frameWireguardSettingsVisible{false}, - m_frameWireguardVisible{false} + PageLogicBase(logic, parent) { - setupProtocolsPageConnections(); - - set_frameWireguardSettingsVisible(false); - set_frameWireguardVisible(false); } void ServerContainersLogic::updateServerContainersPage() { - set_progressBarProtocolsContainerReinstallVisible(false); - ContainersModel *c_model = qobject_cast(uiLogic()->containersModel()); c_model->setSelectedServerIndex(uiLogic()->selectedServerIndex); ProtocolsModel *p_model = qobject_cast(uiLogic()->protocolsModel()); p_model->setSelectedServerIndex(uiLogic()->selectedServerIndex); - - auto containers = m_settings.containers(uiLogic()->selectedServerIndex); - DockerContainer defaultContainer = m_settings.defaultContainer(uiLogic()->selectedServerIndex); - bool haveAuthData = m_settings.haveAuthData(uiLogic()->selectedServerIndex); - - // all containers - QList allContainers { - DockerContainer::OpenVpn, - DockerContainer::ShadowSocks, - DockerContainer::Cloak, - DockerContainer::WireGuard - }; - - using SetVisibleFunc = std::function; - using SetCheckedFunc = std::function; - using SetEnabledFunc = std::function; - - QList installButtonsEnabledFunc { - [this](bool enabled) ->void {set_pushButtonOpenVpnContInstallEnabled(enabled);}, - [this](bool enabled) ->void {set_pushButtonSsOpenVpnContInstallEnabled(enabled);}, - [this](bool enabled) ->void {set_pushButtonCloakOpenVpnContInstallEnabled(enabled);}, - [this](bool enabled) ->void {set_pushButtonWireguardContInstallEnabled(enabled);}, - }; - - QList defaultButtonsCheckedFunc { - [this](bool checked) ->void {set_pushButtonOpenVpnContDefaultChecked(checked);}, - [this](bool checked) ->void {set_pushButtonSsOpenVpnContDefaultChecked(checked);}, - [this](bool checked) ->void {set_pushButtonCloakOpenVpnContDefaultChecked(checked);}, - [this](bool checked) ->void {set_pushButtonWireguardContDefaultChecked(checked);}, - }; - QList defaultButtonsVisibleFunc { - [this](bool visible) ->void {set_pushButtonOpenVpnContDefaultVisible(visible);}, - [this](bool visible) ->void {set_pushButtonSsOpenVpnContDefaultVisible(visible);}, - [this](bool visible) ->void {set_pushButtonCloakOpenVpnContDefaultVisible(visible);}, - [this](bool visible) ->void {set_pushButtonWireguardContDefaultVisible(visible);}, - }; - - QList shareButtonsVisibleFunc { - [this](bool visible) ->void {set_pushButtonOpenVpnContShareVisible(visible);}, - [this](bool visible) ->void {set_pushButtonSsOpenVpnContShareVisible(visible);}, - [this](bool visible) ->void {set_pushButtonCloakOpenVpnContShareVisible(visible);}, - [this](bool visible) ->void {set_pushButtonWireguardContShareVisible(visible);}, - }; - - QList framesVisibleFunc { - [this](bool visible) ->void {set_frameOpenvpnSettingsVisible(visible);}, - [this](bool visible) ->void {set_frameOpenvpnSsSettingsVisible(visible);}, - [this](bool visible) ->void {set_frameOpenvpnSsCloakSettingsVisible(visible);}, - [this](bool visible) ->void {set_frameWireguardSettingsVisible(visible);}, - }; - - for (int i = 0; i < allContainers.size(); ++i) { - defaultButtonsCheckedFunc.at(i)(defaultContainer == allContainers.at(i)); - defaultButtonsVisibleFunc.at(i)(haveAuthData && containers.contains(allContainers.at(i))); - shareButtonsVisibleFunc.at(i)(haveAuthData && containers.contains(allContainers.at(i))); - installButtonsEnabledFunc.at(i)(haveAuthData); - framesVisibleFunc.at(i)(containers.contains(allContainers.at(i))); - } } void ServerContainersLogic::onPushButtonProtoSettingsClicked(DockerContainer c, Protocol p) @@ -134,114 +50,48 @@ void ServerContainersLogic::onPushButtonShareClicked(DockerContainer c) emit uiLogic()->goToPage(Page::ShareConnection); } -void ServerContainersLogic::setupProtocolsPageConnections() +void ServerContainersLogic::onPushButtonRemoveClicked(DockerContainer container) { - QJsonObject openvpnConfig; + //buttonSetEnabledFunc(false); + ErrorCode e = ServerController::removeContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), container); + m_settings.removeContainerConfig(uiLogic()->selectedServerIndex, container); + //buttonSetEnabledFunc(true); - // all containers - QList containers { - DockerContainer::OpenVpn, - DockerContainer::ShadowSocks, - DockerContainer::Cloak, - DockerContainer::WireGuard - }; - using ButtonClickedFunc = void (ServerContainersLogic::*)(bool); - using ButtonSetEnabledFunc = std::function; - - - // install buttons - QList installButtonsClickedSig { - &ServerContainersLogic::pushButtonOpenVpnContInstallClicked, - &ServerContainersLogic::pushButtonSsOpenVpnContInstallClicked, - &ServerContainersLogic::pushButtonCloakOpenVpnContInstallClicked, - &ServerContainersLogic::pushButtonWireguardContInstallClicked, - }; - QList installButtonsSetEnabledFunc { - [this] (bool enabled) -> void { - set_pushButtonOpenVpnContInstallEnabled(enabled); - }, - [this] (bool enabled) -> void { - set_pushButtonSsOpenVpnContInstallEnabled(enabled); - }, - [this] (bool enabled) -> void { - set_pushButtonCloakOpenVpnContInstallEnabled(enabled); - }, - [this] (bool enabled) -> void { - set_pushButtonWireguardContInstallEnabled(enabled); - }, - }; - - for (int i = 0; i < containers.size(); ++i) { - ButtonClickedFunc buttonClickedFunc = installButtonsClickedSig.at(i); - ButtonSetEnabledFunc buttonSetEnabledFunc = installButtonsSetEnabledFunc.at(i); - DockerContainer container = containers.at(i); - - connect(this, buttonClickedFunc, [this, container, buttonSetEnabledFunc](bool checked){ - if (checked) { - UiLogic::PageFunc page_server_containers; - page_server_containers.setEnabledFunc = [this] (bool enabled) -> void { - set_pageEnabled(enabled); - }; - UiLogic::ButtonFunc no_button; - UiLogic::LabelFunc no_label; - UiLogic::ProgressFunc progressBar_protocols_container_reinstall; - progressBar_protocols_container_reinstall.setVisibleFunc = [this] (bool visible) ->void { - set_progressBarProtocolsContainerReinstallVisible(visible); - }; - progressBar_protocols_container_reinstall.setValueFunc = [this] (int value) ->void { - set_progressBarProtocolsContainerReinstallValue(value); - }; - progressBar_protocols_container_reinstall.getValueFunc = [this] (void) -> int { - return progressBarProtocolsContainerReinstallValue(); - }; - progressBar_protocols_container_reinstall.getMaximiumFunc = [this] (void) -> int { - return progressBarProtocolsContainerReinstallMaximium(); - }; - - ErrorCode e = uiLogic()->doInstallAction([this, container](){ - return ServerController::setupContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), container); - }, - page_server_containers, progressBar_protocols_container_reinstall, - no_button, no_label); - - if (!e) { - m_settings.setContainerConfig(uiLogic()->selectedServerIndex, container, QJsonObject()); - m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, container); - } - } - else { - buttonSetEnabledFunc(false); - ErrorCode e = ServerController::removeContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), container); - m_settings.removeContainerConfig(uiLogic()->selectedServerIndex, container); - buttonSetEnabledFunc(true); - - if (m_settings.defaultContainer(uiLogic()->selectedServerIndex) == container) { - const auto &c = m_settings.containers(uiLogic()->selectedServerIndex); - if (c.isEmpty()) m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None); - else m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c.keys().first()); - } - } - - updateServerContainersPage(); - }); - } - - // share buttons - QList shareButtonsClickedSig { - &ServerContainersLogic::pushButtonOpenVpnContShareClicked, - &ServerContainersLogic::pushButtonSsOpenVpnContShareClicked, - &ServerContainersLogic::pushButtonCloakOpenVpnContShareClicked, - &ServerContainersLogic::pushButtonWireguardContShareClicked, - }; - - for (int i = 0; i < containers.size(); ++i) { - ButtonClickedFunc buttonClickedFunc = shareButtonsClickedSig.at(i); - DockerContainer container = containers.at(i); - - connect(this, buttonClickedFunc, [this, container](bool){ - uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, m_settings.serverCredentials(uiLogic()->selectedServerIndex), container); - emit uiLogic()->goToPage(Page::ShareConnection); - }); + if (m_settings.defaultContainer(uiLogic()->selectedServerIndex) == container) { + const auto &c = m_settings.containers(uiLogic()->selectedServerIndex); + if (c.isEmpty()) m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None); + else m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c.keys().first()); } + updateServerContainersPage(); } +void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int port, TransportProto tp) +{ + QMap containers; + Protocol mainProto = ContainerProps::defaultProtocol(c); + + QJsonObject config { + { config_key::container, ContainerProps::containerToString(c) }, + { ProtocolProps::protoToString(mainProto), QJsonObject { + { config_key::port, QString::number(port) }, + { config_key::transport_proto, ProtocolProps::transportProtoToString(tp, mainProto) }} + } + }; + + containers.insert(c, config); + + emit uiLogic()->goToPage(Page::ServerConfiguringProgress); + qApp->processEvents(); + + ErrorCode e = uiLogic()->serverConfiguringProgressLogic()->doInstallAction([this, c](){ + return ServerController::setupContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), c); + }); + + if (!e) { + m_settings.setContainerConfig(uiLogic()->selectedServerIndex, c, QJsonObject()); + m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c); + } + + updateServerContainersPage(); + emit uiLogic()->closePage(); +} diff --git a/client/ui/pages_logic/ServerContainersLogic.h b/client/ui/pages_logic/ServerContainersLogic.h index 2a66ac2c3..ff60efb5f 100644 --- a/client/ui/pages_logic/ServerContainersLogic.h +++ b/client/ui/pages_logic/ServerContainersLogic.h @@ -9,67 +9,18 @@ class ServerContainersLogic : public PageLogicBase { Q_OBJECT - AUTO_PROPERTY(int, progressBarProtocolsContainerReinstallValue) - AUTO_PROPERTY(int, progressBarProtocolsContainerReinstallMaximium) - -// AUTO_PROPERTY(bool, pushButtonOpenVpnContInstallChecked) -// AUTO_PROPERTY(bool, pushButtonSsOpenVpnContInstallChecked) -// AUTO_PROPERTY(bool, pushButtonCloakOpenVpnContInstallChecked) -// AUTO_PROPERTY(bool, pushButtonWireguardContInstallChecked) - - AUTO_PROPERTY(bool, pushButtonOpenVpnContInstallEnabled) - AUTO_PROPERTY(bool, pushButtonSsOpenVpnContInstallEnabled) - AUTO_PROPERTY(bool, pushButtonCloakOpenVpnContInstallEnabled) - AUTO_PROPERTY(bool, pushButtonWireguardContInstallEnabled) - - AUTO_PROPERTY(bool, pushButtonOpenVpnContDefaultChecked) - AUTO_PROPERTY(bool, pushButtonSsOpenVpnContDefaultChecked) - AUTO_PROPERTY(bool, pushButtonCloakOpenVpnContDefaultChecked) - AUTO_PROPERTY(bool, pushButtonWireguardContDefaultChecked) - - AUTO_PROPERTY(bool, pushButtonOpenVpnContDefaultVisible) - AUTO_PROPERTY(bool, pushButtonSsOpenVpnContDefaultVisible) - AUTO_PROPERTY(bool, pushButtonCloakOpenVpnContDefaultVisible) - AUTO_PROPERTY(bool, pushButtonWireguardContDefaultVisible) - - AUTO_PROPERTY(bool, pushButtonOpenVpnContShareVisible) - AUTO_PROPERTY(bool, pushButtonSsOpenVpnContShareVisible) - AUTO_PROPERTY(bool, pushButtonCloakOpenVpnContShareVisible) - AUTO_PROPERTY(bool, pushButtonWireguardContShareVisible) - - AUTO_PROPERTY(bool, frameOpenvpnSettingsVisible) - AUTO_PROPERTY(bool, frameOpenvpnSsSettingsVisible) - AUTO_PROPERTY(bool, frameOpenvpnSsCloakSettingsVisible) - AUTO_PROPERTY(bool, progressBarProtocolsContainerReinstallVisible) - - AUTO_PROPERTY(bool, frameWireguardSettingsVisible) - AUTO_PROPERTY(bool, frameWireguardVisible) - public: Q_INVOKABLE void updateServerContainersPage(); + Q_INVOKABLE void onPushButtonProtoSettingsClicked(DockerContainer c, Protocol p); Q_INVOKABLE void onPushButtonDefaultClicked(DockerContainer c); Q_INVOKABLE void onPushButtonShareClicked(DockerContainer c); + Q_INVOKABLE void onPushButtonRemoveClicked(DockerContainer c); + Q_INVOKABLE void onPushButtonContinueClicked(DockerContainer c, int port, TransportProto tp); public: explicit ServerContainersLogic(UiLogic *uiLogic, QObject *parent = nullptr); ~ServerContainersLogic() = default; - void setupProtocolsPageConnections(); - -signals: - void pushButtonOpenVpnContDefaultClicked(bool checked); - void pushButtonSsOpenVpnContDefaultClicked(bool checked); - void pushButtonCloakOpenVpnContDefaultClicked(bool checked); - void pushButtonWireguardContDefaultClicked(bool checked); - void pushButtonOpenVpnContInstallClicked(bool checked); - void pushButtonSsOpenVpnContInstallClicked(bool checked); - void pushButtonCloakOpenVpnContInstallClicked(bool checked); - void pushButtonWireguardContInstallClicked(bool checked); - void pushButtonOpenVpnContShareClicked(bool checked); - void pushButtonSsOpenVpnContShareClicked(bool checked); - void pushButtonCloakOpenVpnContShareClicked(bool checked); - void pushButtonWireguardContShareClicked(bool checked); - }; #endif // SERVER_CONTAINERS_LOGIC_H diff --git a/client/ui/qml/Controls/FadeBehavior.qml b/client/ui/qml/Controls/FadeBehavior.qml new file mode 100644 index 000000000..d40a2ddcf --- /dev/null +++ b/client/ui/qml/Controls/FadeBehavior.qml @@ -0,0 +1,35 @@ +import QtQuick 2.15 +import QtQml 2.15 + +Behavior { + id: root + + property QtObject fadeTarget: targetProperty.object + property string fadeProperty: "scale" + property int fadeDuration: 150 + property string easingType: "Quad" + + property alias outAnimation: outAnimation + property alias inAnimation: inAnimation + + SequentialAnimation { + NumberAnimation { + id: outAnimation + target: root.fadeTarget + property: root.fadeProperty + duration: root.fadeDuration + to: 0 + easing.type: Easing["In"+root.easingType] + } + PropertyAction { } + NumberAnimation { + id: inAnimation + target: root.fadeTarget + property: root.fadeProperty + duration: root.fadeDuration + to: target[property] + easing.type: Easing["Out"+root.easingType] + } + } + +} \ No newline at end of file diff --git a/client/ui/qml/Controls/VisibleBehavior.qml b/client/ui/qml/Controls/VisibleBehavior.qml new file mode 100644 index 000000000..9aeb4e858 --- /dev/null +++ b/client/ui/qml/Controls/VisibleBehavior.qml @@ -0,0 +1,6 @@ +FadeBehavior { + fadeProperty: "opacity" + fadeDuration: 200 + outAnimation.duration: targetValue ? 0 : fadeDuration + inAnimation.duration: targetValue ? fadeDuration : 0 +} diff --git a/client/ui/qml/Pages/InstallSettings/SelectContainer.qml b/client/ui/qml/Pages/InstallSettings/SelectContainer.qml index 206483a31..a004ade1e 100644 --- a/client/ui/qml/Pages/InstallSettings/SelectContainer.qml +++ b/client/ui/qml/Pages/InstallSettings/SelectContainer.qml @@ -10,7 +10,6 @@ Drawer { id: root signal containerSelected(int c_index) property int selectedIndex: -1 - property alias modelFilters: proxyModel.filters z: -3 diff --git a/client/ui/qml/Pages/PageServerContainers.qml b/client/ui/qml/Pages/PageServerContainers.qml index 9685b6b1e..bbe17b412 100644 --- a/client/ui/qml/Pages/PageServerContainers.qml +++ b/client/ui/qml/Pages/PageServerContainers.qml @@ -2,6 +2,8 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.15 import SortFilterProxyModel 0.2 +import ContainerProps 1.0 +import ProtocolProps 1.0 import PageEnum 1.0 import "./" import "../Controls" @@ -19,33 +21,149 @@ PageBase { } Caption { id: caption - text: qsTr("Protocols") + text: container_selector.selectedIndex > 0 ? qsTr("Install new service") : qsTr("Installed services") } - BlueButtonType { - id: pb_add_container - anchors.horizontalCenter: parent.horizontalCenter + + SelectContainer { + id: container_selector + + onContainerSelected: { + var containerProto = ContainerProps.defaultProtocol(c_index) + + tf_port_num.text = ProtocolProps.defaultPort(containerProto) + cb_port_proto.currentIndex = ProtocolProps.defaultTransportProto(containerProto) + + tf_port_num.enabled = ProtocolProps.defaultPortChangeable(containerProto) + cb_port_proto.enabled = ProtocolProps.defaultTransportProtoChangeable(containerProto) + } + } + + Column { + id: c1 + visible: container_selector.selectedIndex > 0 + width: parent.width anchors.top: caption.bottom anchors.topMargin: 10 + Caption { + font.pixelSize: 22 + text: UiLogic.containerName(container_selector.selectedIndex) + } + + Text { + width: parent.width + anchors.topMargin: 10 + padding: 10 + + font.family: "Lato" + font.styleName: "normal" + font.pixelSize: 16 + color: "#181922" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + wrapMode: Text.Wrap + + text: UiLogic.containerDesc(container_selector.selectedIndex) + } + } + + Rectangle { + id: frame_settings + visible: container_selector.selectedIndex > 0 + width: parent.width + anchors.top: c1.bottom + anchors.topMargin: 10 + + border.width: 1 + border.color: "lightgray" + anchors.bottomMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + radius: 2 + Grid { + id: grid + visible: container_selector.selectedIndex > 0 + anchors.fill: parent + columns: 2 + horizontalItemAlignment: Grid.AlignHCenter + verticalItemAlignment: Grid.AlignVCenter + topPadding: 5 + leftPadding: 10 + spacing: 5 + + + LabelType { + width: 130 + text: qsTr("Port") + } + TextFieldType { + id: tf_port_num + width: parent.width - 130 - parent.spacing - parent.leftPadding * 2 + } + LabelType { + width: 130 + text: qsTr("Network Protocol") + } + ComboBoxType { + id: cb_port_proto + width: parent.width - 130 - parent.spacing - parent.leftPadding * 2 + model: [ + qsTr("udp"), + qsTr("tcp"), + ] + } + } + } + + BlueButtonType { + id: pb_cancel_add + visible: container_selector.selectedIndex > 0 + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: pb_continue_add.top + anchors.bottomMargin: 20 + width: parent.width - 40 height: 40 - text: qsTr("Add protocols container") + text: qsTr("Cancel") font.pixelSize: 16 - onClicked: container_selector.visible ? container_selector.close() : container_selector.open() + onClicked: container_selector.selectedIndex = -1 } - SelectContainer { - id: container_selector + + BlueButtonType { + id: pb_continue_add + visible: container_selector.selectedIndex > 0 + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + + width: parent.width - 40 + height: 40 + text: qsTr("Continue") + font.pixelSize: 16 + onClicked: { + let cont = container_selector.selectedIndex + let tp = ProtocolProps.transportProtoFromString(cb_port_proto.currentText) + let port = tf_port_num.text + ServerContainersLogic.onPushButtonContinueClicked(cont, port, tp) + } } + + + + Flickable { + visible: container_selector.selectedIndex <= 0 clip: true width: parent.width - anchors.top: pb_add_container.bottom - anchors.bottom: parent.bottom + anchors.top: caption.bottom + anchors.bottom: pb_add_container.top contentHeight: col.height Column { + visible: container_selector.selectedIndex <= 0 id: col anchors { left: parent.left; @@ -116,23 +234,6 @@ PageBase { visible: index === tb_c.currentIndex } -// ImageButtonType { -// id: button_default1 -// z:10 - -// Layout.alignment: Qt.AlignRight -// checkable: true -// img.source: checked ? "qrc:/images/check.png" : "qrc:/images/uncheck.png" -// width: 20 -// img.width: 20 -// height: 20 - -// checked: default_role -// onClicked: { -// ServerContainersLogic.onPushButtonDefaultClicked(proxyContainersModel.mapToSource(index)) -// } -// } - RowLayout { id: row_container //width: parent.width @@ -156,6 +257,7 @@ PageBase { Layout.fillWidth: true MouseArea { + enabled: col.visible anchors.top: lb_container_name.top anchors.bottom: lb_container_name.bottom anchors.left: parent.left @@ -191,6 +293,7 @@ PageBase { ImageButtonType { id: button_share + visible: index === tb_c.currentIndex Layout.alignment: Qt.AlignRight icon.source: "qrc:/images/share.png" implicitWidth: 30 @@ -198,6 +301,25 @@ PageBase { onClicked: { ServerContainersLogic.onPushButtonShareClicked(proxyContainersModel.mapToSource(index)) } + + VisibleBehavior on visible { } + } + + ImageButtonType { + id: button_remove + visible: index === tb_c.currentIndex + Layout.alignment: Qt.AlignRight + checkable: true + icon.source: "qrc:/images/delete.png" + implicitWidth: 30 + implicitHeight: 30 + + checked: default_role + onClicked: { + ServerContainersLogic.onPushButtonRemoveClicked(proxyContainersModel.mapToSource(index)) + } + + VisibleBehavior on visible { } } } @@ -218,6 +340,9 @@ PageBase { interactive: false model: proxyProtocolsModel + VisibleBehavior on visible { } + + delegate: Item { id: dp_item @@ -279,471 +404,29 @@ PageBase { } } } - -// MouseArea { -// anchors.fill: parent -// onClicked: { -// tb_p.currentIndex = index -// } -// } } } } } } } - - } + BlueButtonType { + id: pb_add_container + visible: container_selector.selectedIndex < 0 + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.topMargin: 10 + anchors.bottomMargin: 20 + width: parent.width - 40 + height: 40 + text: qsTr("Install new protocols container") + font.pixelSize: 16 + onClicked: container_selector.visible ? container_selector.close() : container_selector.open() - - - - - - -// ProgressBar { -// id: progress_bar -// anchors.horizontalCenter: parent.horizontalCenter -// y: 570 -// width: 301 -// height: 40 -// from: 0 -// to: ServerContainersLogic.progressBarProtocolsContainerReinstallMaximium -// value: ServerContainersLogic.progressBarProtocolsContainerReinstallValue -// visible: ServerContainersLogic.progressBarProtocolsContainerReinstallVisible -// background: Rectangle { -// implicitWidth: parent.width -// implicitHeight: parent.height -// color: "#100A44" -// radius: 4 -// } - -// contentItem: Item { -// implicitWidth: parent.width -// implicitHeight: parent.height -// Rectangle { -// width: progress_bar.visualPosition * parent.width -// height: parent.height -// radius: 4 -// color: Qt.rgba(255, 255, 255, 0.15); -// } -// } - -// LabelType { -// anchors.fill: parent -// text: qsTr("Configuring...") -// horizontalAlignment: Text.AlignHCenter -// font.family: "Lato" -// font.styleName: "normal" -// font.pixelSize: 16 -// color: "#D4D4D4" -// } -// } -// ScrollView { -// x: 0 -// y: 190 -// width: 380 -// height: 471 -// clip: true -// Column { -// spacing: 5 -// Rectangle { -// id: frame_openvpn_ss_cloak -// x: 9 -// height: 135 -// width: 363 -// border.width: 1 -// border.color: "lightgray" -// radius: 2 -// visible: ServerContainersLogic.frameOpenvpnSsCloakSettingsVisible -// Item { -// x: 5 -// y: 5 -// width: parent.width - 10 -// height: parent.height - 10 -// LabelType { -// anchors.left: parent.left -// width: 239 -// height: 24 -// text: qsTr("Cloak container") -// leftPadding: 5 -// } -// ImageButtonType { -// anchors.right: sr1.left -// anchors.rightMargin: 5 -// checkable: true -// icon.source: checked ? "qrc:/images/check.png" : "qrc:/images/uncheck.png" -// width: 24 -// height: 24 -// checked: ServerContainersLogic.pushButtonCloakOpenVpnContDefaultChecked -// onCheckedChanged: { -// ServerContainersLogic.pushButtonCloakOpenVpnContDefaultChecked = checked -// } -// onClicked: { -// ServerContainersLogic.onPushButtonProtoCloakOpenVpnContDefaultClicked(checked) -// } - -// visible: ServerContainersLogic.pushButtonCloakOpenVpnContDefaultVisible -// } - -// ImageButtonType { -// id: sr1 -// anchors.right: cn1.left -// anchors.rightMargin: 5 -// icon.source: "qrc:/images/share.png" -// width: 24 -// height: 24 -// visible: ServerContainersLogic.pushButtonCloakOpenVpnContShareVisible -// onClicked: { -// ServerContainersLogic.onPushButtonProtoCloakOpenVpnContShareClicked(false) -// } -// } -// ImageButtonType { -// id: cn1 -// anchors.right: parent.right -// checkable: true -// icon.source: checked ? "qrc:/images/connect_button_connected.png" -// : "qrc:/images/connect_button_disconnected.png" -// width: 36 -// height: 24 -// checked: ServerContainersLogic.pushButtonCloakOpenVpnContInstallChecked -// onCheckedChanged: { -// ServerContainersLogic.pushButtonCloakOpenVpnContInstallChecked = checked -// } -// onClicked: { -// ServerContainersLogic.onPushButtonProtoCloakOpenVpnContInstallClicked(checked) -// } -// enabled: ServerContainersLogic.pushButtonCloakOpenVpnContInstallEnabled -// } -// } -// Rectangle { -// x: 10 -// y: 42 -// height: 83 -// width: 343 -// border.width: 1 -// border.color: "lightgray" -// radius: 2 -// SettingButtonType { -// x: 10 -// y: 10 -// width: 323 -// height: 24 -// text: qsTr("OpenVPN settings") -// icon.source: "qrc:/images/settings.png" -// onClicked: { -// ServerContainersLogic.onPushButtonProtoCloakOpenVpnContOpenvpnConfigClicked() -// } -// } -// SettingButtonType { -// x: 10 -// y: 33 -// width: 323 -// height: 24 -// text: qsTr("ShadowSocks settings") -// icon.source: "qrc:/images/settings.png" -// onClicked: { -// ServerContainersLogic.onPushButtonProtoCloakOpenVpnContSsConfigClicked() -// } -// } -// SettingButtonType { -// x: 10 -// y: 56 -// width: 323 -// height: 24 -// text: qsTr("Cloak settings") -// icon.source: "qrc:/images/settings.png" -// onClicked: { -// ServerContainersLogic.onPushButtonProtoCloakOpenVpnContCloakConfigClicked() -// } -// } -// } -// } -// Rectangle { -// id: frame_openvpn_ss -// x: 9 -// height: 105 -// width: 363 -// border.width: 1 -// border.color: "lightgray" -// radius: 2 -// visible: ServerContainersLogic.frameOpenvpnSsSettingsVisible -// Item { -// x: 5 -// y: 5 -// width: parent.width - 10 -// height: parent.height - 10 -// LabelType { -// anchors.left: parent.left -// width: 239 -// height: 24 -// text: qsTr("ShadowSocks container") -// leftPadding: 5 -// } -// ImageButtonType { -// anchors.right: sr2.left -// anchors.rightMargin: 5 -// checkable: true -// icon.source: checked ? "qrc:/images/check.png" : "qrc:/images/uncheck.png" -// width: 24 -// height: 24 -// checked: ServerContainersLogic.pushButtonSsOpenVpnContDefaultChecked -// onCheckedChanged: { -// ServerContainersLogic.pushButtonSsOpenVpnContDefaultChecked = checked -// } -// onClicked: { -// ServerContainersLogic.onPushButtonProtoSsOpenVpnContDefaultClicked(checked) -// } - -// visible: ServerContainersLogic.pushButtonSsOpenVpnContDefaultVisible -// } - -// ImageButtonType { -// id: sr2 -// anchors.right: cn2.left -// anchors.rightMargin: 5 -// icon.source: "qrc:/images/share.png" -// width: 24 -// height: 24 -// visible: ServerContainersLogic.pushButtonSsOpenVpnContShareVisible -// onClicked: { -// ServerContainersLogic.onPushButtonProtoSsOpenVpnContShareClicked(false) -// } -// } -// ImageButtonType { -// id: cn2 -// anchors.right: parent.right -// checkable: true -// icon.source: checked ? "qrc:/images/connect_button_connected.png" -// : "qrc:/images/connect_button_disconnected.png" -// width: 36 -// height: 24 -// checked: ServerContainersLogic.pushButtonSsOpenVpnContInstallChecked -// onCheckedChanged: { -// ServerContainersLogic.pushButtonSsOpenVpnContInstallChecked = checked -// } -// onClicked: { -// ServerContainersLogic.onPushButtonProtoSsOpenVpnContInstallClicked(checked) -// } -// enabled: ServerContainersLogic.pushButtonSsOpenVpnContInstallEnabled -// } -// } -// Rectangle { -// x: 10 -// y: 42 -// height: 53 -// width: 343 -// border.width: 1 -// border.color: "lightgray" -// radius: 2 -// SettingButtonType { -// x: 10 -// y: 5 -// width: 323 -// height: 24 -// text: qsTr("OpenVPN settings") -// icon.source: "qrc:/images/settings.png" -// onClicked: { -// ServerContainersLogic.onPushButtonProtoSsOpenVpnContOpenvpnConfigClicked() -// } -// } -// SettingButtonType { -// x: 10 -// y: 27 -// width: 323 -// height: 24 -// text: qsTr("ShadowSocks settings") -// icon.source: "qrc:/images/settings.png" -// onClicked: { -// ServerContainersLogic.onPushButtonProtoSsOpenVpnContSsConfigClicked() -// } -// } -// } -// } -// Rectangle { -// id: frame_openvpn -// x: 9 -// height: 100 -// width: 363 -// border.width: 1 -// border.color: "lightgray" -// radius: 2 -// visible: ServerContainersLogic.frameOpenvpnSettingsVisible -// Item { -// x: 5 -// y: 5 -// width: parent.width - 10 -// height: parent.height - 10 -// LabelType { -// anchors.left: parent.left -// width: 239 -// height: 24 -// text: qsTr("OpenVPN container") -// leftPadding: 5 -// } -// ImageButtonType { -// anchors.right: sr3.left -// anchors.rightMargin: 5 -// checkable: true -// icon.source: checked ? "qrc:/images/check.png" : "qrc:/images/uncheck.png" -// width: 24 -// height: 24 -// checked: ServerContainersLogic.pushButtonOpenVpnContDefaultChecked -// onCheckedChanged: { -// ServerContainersLogic.pushButtonOpenVpnContDefaultChecked = checked -// } -// onClicked: { -// ServerContainersLogic.onPushButtonProtoOpenVpnContDefaultClicked(checked) -// } - -// visible: ServerContainersLogic.pushButtonOpenVpnContDefaultVisible -// } - -// ImageButtonType { -// id: sr3 -// anchors.right: cn3.left -// anchors.rightMargin: 5 -// icon.source: "qrc:/images/share.png" -// width: 24 -// height: 24 -// visible: ServerContainersLogic.pushButtonOpenVpnContShareVisible -// onClicked: { -// ServerContainersLogic.onPushButtonProtoOpenVpnContShareClicked(false) -// } -// } -// ImageButtonType { -// id: cn3 -// anchors.right: parent.right -// checkable: true -// icon.source: checked ? "qrc:/images/connect_button_connected.png" -// : "qrc:/images/connect_button_disconnected.png" -// width: 36 -// height: 24 -// checked: ServerContainersLogic.pushButtonOpenVpnContInstallChecked -// onCheckedChanged: { -// ServerContainersLogic.pushButtonOpenVpnContInstallChecked = checked -// } -// onClicked: { -// ServerContainersLogic.onPushButtonProtoOpenVpnContInstallClicked(checked) -// } -// enabled: ServerContainersLogic.pushButtonOpenVpnContInstallEnabled -// } -// } -// Rectangle { -// x: 10 -// y: 42 -// height: 44 -// width: 343 -// border.width: 1 -// border.color: "lightgray" -// radius: 2 -// SettingButtonType { -// x: 10 -// y: 10 -// width: 323 -// height: 24 -// text: qsTr("OpenVPN settings") -// icon.source: "qrc:/images/settings.png" -// onClicked: { -// ServerContainersLogic.onPushButtonProtoOpenVpnContOpenvpnConfigClicked() -// } -// } -// } -// } -// Rectangle { -// id: frame_wireguard -// x: 9 -// height: 100 -// width: 363 -// border.width: 1 -// border.color: "lightgray" -// radius: 2 -// visible: ServerContainersLogic.frameWireguardVisible -// Item { -// x: 5 -// y: 5 -// width: parent.width - 10 -// height: parent.height - 10 -// LabelType { -// anchors.left: parent.left -// width: 239 -// height: 24 -// text: qsTr("WireGuard container") -// leftPadding: 5 -// } -// ImageButtonType { -// anchors.right: sr4.left -// anchors.rightMargin: 5 -// checkable: true -// icon.source: checked ? "qrc:/images/check.png" : "qrc:/images/uncheck.png" -// width: 24 -// height: 24 -// checked: ServerContainersLogic.pushButtonWireguardContDefaultChecked -// onCheckedChanged: { -// ServerContainersLogic.pushButtonWireguardContDefaultChecked = checked -// } -// onClicked: { -// ServerContainersLogic.onPushButtonProtoWireguardContDefaultClicked(checked) -// } - -// visible: ServerContainersLogic.pushButtonWireguardContDefaultVisible -// } - -// ImageButtonType { -// id: sr4 -// anchors.right: cn4.left -// anchors.rightMargin: 5 -// icon.source: "qrc:/images/share.png" -// width: 24 -// height: 24 -// visible: ServerContainersLogic.pushButtonWireguardContShareVisible -// onClicked: { -// ServerContainersLogic.onPushButtonProtoWireguardContShareClicked(false) -// } -// } -// ImageButtonType { -// id: cn4 -// anchors.right: parent.right -// checkable: true -// icon.source: checked ? "qrc:/images/connect_button_connected.png" -// : "qrc:/images/connect_button_disconnected.png" -// width: 36 -// height: 24 -// checked: ServerContainersLogic.pushButtonWireguardContInstallChecked -// onCheckedChanged: { -// ServerContainersLogic.pushButtonWireguardContInstallChecked = checked -// } -// onClicked: { -// ServerContainersLogic.onPushButtonProtoWireguardContInstallClicked(checked) -// } -// enabled: ServerContainersLogic.pushButtonWireguardContInstallEnabled -// } -// } -// Rectangle { -// id: frame_wireguard_settings -// visible: ServerContainersLogic.frameWireguardSettingsVisible -// x: 10 -// y: 42 -// height: 44 -// width: 343 -// border.width: 1 -// border.color: "lightgray" -// radius: 2 -// SettingButtonType { -// x: 10 -// y: 10 -// width: 323 -// height: 24 -// text: qsTr("WireGuard settings") -// icon.source: "qrc:/images/settings.png" -// } -// } -// } -// } -// } + } } diff --git a/client/ui/qml/Pages/PageServerSettings.qml b/client/ui/qml/Pages/PageServerSettings.qml index cb2eefa31..7a476e02a 100644 --- a/client/ui/qml/Pages/PageServerSettings.qml +++ b/client/ui/qml/Pages/PageServerSettings.qml @@ -100,7 +100,7 @@ PageBase { y: 210 width: 300 height: 40 - text: qsTr("VPN protocols") + text: qsTr("Protocols and services") onClicked: { UiLogic.goToPage(PageEnum.ServerContainers) } diff --git a/client/ui/qml/Pages/Protocols/PageProtoShadowSocks.qml b/client/ui/qml/Pages/Protocols/PageProtoShadowSocks.qml index d93506678..28d433fab 100644 --- a/client/ui/qml/Pages/Protocols/PageProtoShadowSocks.qml +++ b/client/ui/qml/Pages/Protocols/PageProtoShadowSocks.qml @@ -33,18 +33,13 @@ PageProtocolBase { qsTr("aes-128-gcm") ] currentIndex: { - console.debug("logic.comboBoxProtoShadowSocksCipherText " + logic.comboBoxProtoShadowSocksCipherText) for (let i = 0; i < model.length; ++i) { - console.debug("check " + model[i]) if (logic.comboBoxProtoShadowSocksCipherText === model[i]) { return i } } return -1 } -// onCurrentTextChanged: { -// logic.comboBoxProtoShadowSocksCipherText = currentText -// } } LabelType { x: 30 diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index 1b75bb0ea..fb321ad26 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -83,6 +83,8 @@ public: Q_INVOKABLE QString containerName(int container); Q_INVOKABLE QString containerDesc(int container); + Q_INVOKABLE void onGotoPage(PageEnumNS::Page p, bool reset = true, bool slide = true) { emit goToPage(p, reset, slide); } + Q_INVOKABLE void onGotoProtocolPage(Protocol p, bool reset = true, bool slide = true) { emit goToProtocolPage(p, reset, slide); } int getCurrentPageValue() const;