Custom sites reimplemented

This commit is contained in:
pokamest 2021-05-27 22:18:36 +03:00
parent 97e918ae72
commit 6c74f30d79
23 changed files with 833 additions and 312 deletions

View file

@ -34,6 +34,7 @@ HEADERS += \
ui/mainwindow.h \
ui/qautostart.h \
ui/server_widget.h \
ui/sites_model.h \
utils.h \
vpnconnection.h \
protocols/vpnprotocol.h \
@ -60,6 +61,7 @@ SOURCES += \
ui/mainwindow.cpp \
ui/qautostart.cpp \
ui/server_widget.cpp \
ui/sites_model.cpp \
utils.cpp \
vpnconnection.cpp \
protocols/vpnprotocol.cpp \

View file

@ -226,7 +226,7 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString config)
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
if (m_settings().customRouting()) {
if (m_settings().routeMode() == Settings::VpnOnlyForwardSites) {
config.replace("redirect-gateway def1 bypass-dhcp", "");
}
else {

BIN
client/images/folder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

View file

@ -61,5 +61,6 @@
<file>server_scripts/openvpn_shadowsocks/run_container.sh</file>
<file>server_scripts/openvpn_shadowsocks/start.sh</file>
<file>server_scripts/openvpn_shadowsocks/template.ovpn</file>
<file>images/folder.png</file>
</qresource>
</RCC>

View file

@ -1,5 +1,6 @@
#include "defines.h"
#include "settings.h"
#include "utils.h"
#include <QDebug>
#include "protocols/protocols_defs.h"
@ -205,6 +206,127 @@ QString Settings::nextAvailableServerName() const
return tr("Server") + " " + QString::number(i);
}
QString Settings::routeModeString(RouteMode mode) const
{
switch (mode) {
case VpnAllSites:
return "AllSites";
case VpnOnlyForwardSites:
return "ForwardSites";
case VpnAllExceptSites:
return "ExceptSites";
}
}
void Settings::addVpnSite(RouteMode mode, const QString &site, const QString &ip)
{
QVariantMap sites = vpnSites(mode);
if (sites.contains(site) && ip.isEmpty()) return;
sites.insert(site, ip);
setVpnSites(mode, sites);
// QStringList l = sites.value(site).toStringList();
// if (!l.contains(ip)) {
// if (!ip.isEmpty()) l.append(ip);
// //l.append(ip);
// sites.insert(site, l);
// setVpnSites(mode, sites);
// qDebug() << "sites after" << vpnSites(mode);
// }
}
QStringList Settings::getVpnIps(RouteMode mode) const
{
QStringList ips;
const QVariantMap &m = vpnSites(mode);
for (auto i = m.constBegin(); i != m.constEnd(); ++i) {
if (Utils::checkIPFormat(i.key())) {
ips.append(i.key());
}
else if (Utils::checkIPFormat(i.value().toString())) {
ips.append(i.value().toString());
}
}
ips.removeDuplicates();
return ips;
}
void Settings::removeVpnSite(RouteMode mode, const QString &site)
{
QVariantMap sites = vpnSites(mode);
if (!sites.contains(site)) return;
sites.remove(site);
setVpnSites(mode, sites);
}
void Settings::addVpnIps(RouteMode mode, const QStringList &ips)
{
QVariantMap sites = vpnSites(mode);
for (const QString &ip : ips) {
if (ip.isEmpty()) continue;
sites.insert(ip, "");
}
setVpnSites(mode, sites);
}
void Settings::removeVpnSites(RouteMode mode, const QStringList &sites)
{
QVariantMap sitesMap = vpnSites(mode);
for (const QString &site : sites) {
if (site.isEmpty()) continue;
sitesMap.remove(site);
}
setVpnSites(mode, sitesMap);
}
//void Settings::addVpnForwardSite(const QString &site, const QString &ip)
//{
// auto sites = vpnForwardSites();
// QStringList l = sites.value(site).toStringList();
// if (!l.contains(ip)) {
// l.append(ip);
// setVpnForwardSites(sites);
// }
//}
//QStringList Settings::getVpnForwardIps() const
//{
// QStringList ips;
// const QVariantMap &m = vpnForwardSites();
// for (const QVariant &v : m) {
// ips.append(v.toStringList());
// }
// ips.removeDuplicates();
// return ips;
//}
//void Settings::addVpnExceptSite(const QString &site, const QString &ip)
//{
// auto sites = vpnExceptSites();
// QStringList l = sites.value(site).toStringList();
// if (!l.contains(ip)) {
// l.append(ip);
// setVpnExceptSites(sites);
// }
//}
//QStringList Settings::getVpnExceptIps() const
//{
// QStringList ips;
// const QVariantMap &m = vpnExceptSites();
// for (const QVariant &v : m) {
// ips.append(v.toStringList());
// }
// ips.removeDuplicates();
// return ips;
//}
QString Settings::primaryDns() const { return m_settings.value("Conf/primaryDns", cloudFlareNs1).toString(); }
QString Settings::secondaryDns() const { return m_settings.value("Conf/secondaryDns", cloudFlareNs2).toString(); }

View file

@ -67,16 +67,48 @@ public:
bool isStartMinimized() const { return m_settings.value("Conf/startMinimized", false).toBool(); }
void setStartMinimized(bool enabled) { m_settings.setValue("Conf/startMinimized", enabled); }
bool customRouting() const { return m_settings.value("Conf/customRouting", false).toBool(); }
void setCustomRouting(bool customRouting) { m_settings.setValue("Conf/customRouting", customRouting); }
enum RouteMode {
VpnAllSites,
VpnOnlyForwardSites,
VpnAllExceptSites
};
Q_ENUM (RouteMode)
// list of sites to pass blocking added by user
QStringList customSites() { return m_settings.value("Conf/customSites").toStringList(); }
void setCustomSites(const QStringList &customSites) { m_settings.setValue("Conf/customSites", customSites); }
QString routeModeString(RouteMode mode) const;
// list of ips to pass blocking generated from customSites
QStringList customIps() { return m_settings.value("Conf/customIps").toStringList(); }
void setCustomIps(const QStringList &customIps) { m_settings.setValue("Conf/customIps", customIps); }
RouteMode routeMode() const { return static_cast<RouteMode>(m_settings.value("Conf/routeMode", 0).toInt()); }
void setRouteMode(RouteMode mode) { m_settings.setValue("Conf/routeMode", mode); }
// bool customRouting() const { return m_settings.value("Conf/customRouting", false).toBool(); }
// void setCustomRouting(bool customRouting) { m_settings.setValue("Conf/customRouting", customRouting); }
// // list of sites to pass blocking added by user
// QStringList customSites() { return m_settings.value("Conf/customSites").toStringList(); }
// void setCustomSites(const QStringList &customSites) { m_settings.setValue("Conf/customSites", customSites); }
// // list of ips to pass blocking generated from customSites
// QStringList customIps() { return m_settings.value("Conf/customIps").toStringList(); }
// void setCustomIps(const QStringList &customIps) { m_settings.setValue("Conf/customIps", customIps); }
QVariantMap vpnSites(RouteMode mode) const { return m_settings.value("Conf/" + routeModeString(mode)).toMap(); }
void setVpnSites(RouteMode mode, const QVariantMap &sites) { m_settings.setValue("Conf/"+ routeModeString(mode), sites); m_settings.sync(); }
void addVpnSite(RouteMode mode, const QString &site, const QString &ip= "");
QStringList getVpnIps(RouteMode mode) const;
void removeVpnSite(RouteMode mode, const QString &site);
void addVpnIps(RouteMode mode, const QStringList &ip);
void removeVpnSites(RouteMode mode, const QStringList &sites);
// QVariantMap vpnForwardSites() const { return m_settings.value("Conf/vpnForwardSites").toMap(); }
// void setVpnForwardSites(const QVariantMap &sites) { m_settings.setValue("Conf/vpnForwardSites", sites); }
// void addVpnForwardSite(const QString &site, const QString &ip);
// QStringList getVpnForwardIps() const;
// QVariantMap vpnExceptSites() const { return m_settings.value("Conf/vpnExceptSites").toMap(); }
// void setVpnExceptSites(const QVariantMap &sites) { m_settings.setValue("Conf/vpnExceptSites", sites); }
// void addVpnExceptSite(const QString &site, const QString &ip);
// QStringList getVpnExceptIps() const;
QString primaryDns() const;
QString secondaryDns() const;

View file

@ -4,6 +4,8 @@
#include <QDesktopServices>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QHostInfo>
#include <QItemSelectionModel>
#include <QJsonDocument>
#include <QJsonObject>
#include <QKeyEvent>
@ -59,6 +61,8 @@ MainWindow::MainWindow(QWidget *parent) :
setupUiConnections();
setupNewServerConnections();
setupWizardConnections();
setupVpnPageConnections();
setupSitesPageConnections();
setupGeneralSettingsConnections();
setupAppSettingsConnections();
setupNetworkSettingsConnections();
@ -74,6 +78,11 @@ MainWindow::MainWindow(QWidget *parent) :
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;
}
@ -96,10 +105,6 @@ MainWindow::MainWindow(QWidget *parent) :
goToPage(Page::Vpn, true, false);
}
connect(ui->lineEdit_sites_add_custom, &QLineEdit::returnPressed, [&](){
ui->pushButton_sites_add_custom->click();
});
//ui->pushButton_general_settings_exit->hide();
updateSharingPage(selectedServerIndex, m_settings.serverCredentials(selectedServerIndex), selectedDockerContainer);
@ -143,6 +148,10 @@ MainWindow::MainWindow(QWidget *parent) :
//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()
@ -351,7 +360,8 @@ void MainWindow::keyPressEvent(QKeyEvent *event)
#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.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);
@ -369,6 +379,12 @@ void MainWindow::keyPressEvent(QKeyEvent *event)
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();
}
@ -626,6 +642,17 @@ void MainWindow::onPushButtonNewServerImport(bool)
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).
@ -901,8 +928,7 @@ void MainWindow::onConnectionStateChanged(VpnProtocol::ConnectionState state)
}
ui->pushButton_connect->setEnabled(pushButtonConnectEnabled);
ui->radioButton_mode_all_sites->setEnabled(radioButtonsModeEnabled);
ui->radioButton_mode_selected_sites->setEnabled(radioButtonsModeEnabled);
ui->widget_vpn_mode->setEnabled(radioButtonsModeEnabled);
}
void MainWindow::onVpnProtocolError(ErrorCode errorCode)
@ -1013,27 +1039,6 @@ void MainWindow::setupUiConnections()
connect(b, &QPushButton::clicked, this, [this](){ closePage(); });
}
connect(ui->pushButton_sites_add_custom, &QPushButton::clicked, this, [this](){ onPushButtonAddCustomSitesClicked(); });
connect(ui->radioButton_mode_selected_sites, &QRadioButton::toggled, ui->pushButton_vpn_add_site, &QPushButton::setEnabled);
connect(ui->radioButton_mode_selected_sites, &QRadioButton::toggled, this, [this](bool toggled) {
m_settings.setCustomRouting(toggled);
});
connect(ui->pushButton_servers_add_new, &QPushButton::clicked, this, [this](){ goToPage(Page::Start); });
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::setupNewServerConnections()
@ -1080,7 +1085,8 @@ void MainWindow::setupWizardConnections()
connect(ui->pushButton_setup_wizard_vpn_mode_finish, &QPushButton::clicked, this, [this](){
installServer(getInstallConfigsFromWizardPage());
m_settings.setCustomRouting(ui->checkBox_setup_wizard_vpn_mode->isChecked());
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](){
@ -1092,6 +1098,86 @@ void MainWindow::setupWizardConnections()
});
}
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 indexes = selection->selectedRows();
QStringList sites;
for (const QModelIndex &index : indexes) {
sites.append(index.data().toString());
}
m_settings.removeVpnSites(mode, sites);
updateSitesPage();
// if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) {
// if (IpcClient::Interface()) IpcClient::Interface()->routeDelete(ipToDelete, "");
// if (IpcClient::Interface()) IpcClient::Interface()->flushDns();
// }
// if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) {
// if (IpcClient::Interface())
// IpcClient::Interface()->routeDelete(m_vpnConnection->vpnProtocol()->vpnGateway(),
// QStringList() << ip);
// }
});
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);
updateSitesPage();
});
}
void MainWindow::setupAppSettingsConnections()
{
connect(ui->checkBox_app_settings_autostart, &QCheckBox::stateChanged, this, [this](int state){
@ -1413,7 +1499,13 @@ void MainWindow::setupNewServerPageConnections()
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)));
@ -1431,6 +1523,17 @@ void MainWindow::setupServerSettingsPageConnections()
});
});
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()
@ -1683,67 +1786,57 @@ void MainWindow::onTrayActionConnect()
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;
// get domain name if it present
newSite.replace("https://", "");
newSite.replace("http://", "");
newSite.replace("ftp://", "");
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();
newSite = newSite.split("/", QString::SkipEmptyParts).first();
}
qDebug() << "Adding site" << newSite;
QStringList customSites = m_settings.customSites();
if (!customSites.contains(newSite)) {
customSites.append(newSite);
m_settings.setCustomSites(customSites);
//qDebug() << "sites:" << m_settings.vpnSites(mode);
QString newIp = Utils::getIPAddress(newSite);
QStringList customIps = m_settings.customIps();
if (!newIp.isEmpty() && !customIps.contains(newIp)) {
customIps.append(newIp);
m_settings.setCustomIps(customIps);
const auto &cbProcess = [this, mode](const QString &newSite, const QString &ip) {
m_settings.addVpnSite(mode, newSite, ip);
if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) {
if (IpcClient::Interface()) IpcClient::Interface()->routeAddList(m_vpnConnection->vpnProtocol()->vpnGateway(),
QStringList() << newIp);
}
if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) {
if (IpcClient::Interface())
IpcClient::Interface()->routeAddList(m_vpnConnection->vpnProtocol()->vpnGateway(),
QStringList() << ip);
}
updateSitesPage();
ui->lineEdit_sites_add_custom->clear();
}
else {
qDebug() << "customSites already contains" << newSite;
}
}
};
void MainWindow::onPushButtonDeleteCustomSiteClicked(const QString &siteToDelete)
{
if (siteToDelete.isEmpty()) {
const auto &cbResolv = [this, cbProcess](const QHostInfo &hostInfo){
const QList<QHostAddress> &addresses = hostInfo.addresses();
if (!addresses.isEmpty()) {
//qDebug() << "Resolved address for" << hostInfo.hostName() << addresses.first().toString();
cbProcess(hostInfo.hostName(), addresses.first().toString());
}
};
ui->lineEdit_sites_add_custom->clear();
if (Utils::ipAddressWithSubnetRegExp().exactMatch(newSite)) {
cbProcess(newSite, newSite);
return;
}
QString ipToDelete = Utils::getIPAddress(siteToDelete);
QStringList customSites = m_settings.customSites();
customSites.removeAll(siteToDelete);
qDebug() << "Deleted custom site:" << siteToDelete;
m_settings.setCustomSites(customSites);
QStringList customIps = m_settings.customIps();
customIps.removeAll(ipToDelete);
qDebug() << "Deleted custom ip:" << ipToDelete;
m_settings.setCustomIps(customIps);
updateSitesPage();
if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) {
if (IpcClient::Interface()) IpcClient::Interface()->routeDelete(ipToDelete, "");
if (IpcClient::Interface()) IpcClient::Interface()->flushDns();
else {
cbProcess(newSite, "");
updateSitesPage();
int reqId = QHostInfo::lookupHost(newSite, this, cbResolv);
}
}
@ -1769,16 +1862,20 @@ void MainWindow::updateStartPage()
void MainWindow::updateSitesPage()
{
ui->listWidget_sites->clear();
for (const QString &site : m_settings.customSites()) {
makeSitesListItem(ui->listWidget_sites, site);
}
Settings::RouteMode m = m_settings.routeMode();
if (m == Settings::VpnAllSites) return;
ui->tableView_sites->setModel(sitesModels.value(m));
sitesModels.value(m)->resetCache();
}
void MainWindow::updateVpnPage()
{
ui->radioButton_mode_selected_sites->setChecked(m_settings.customRouting());
ui->pushButton_vpn_add_site->setEnabled(m_settings.customRouting());
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()
@ -1868,20 +1965,6 @@ void MainWindow::updateProtocolsPage()
ui->frame_openvpn_settings->setVisible(containers.contains(DockerContainer::OpenVpn));
}
void MainWindow::updateShareCodePage()
{
// QJsonObject o;
// o.insert("h", m_settings.serverName());
// o.insert("p", m_settings.serverPort());
// o.insert("u", m_settings.userName());
// o.insert("w", m_settings.password());
// QByteArray ba = QJsonDocument(o).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
// ui->textEdit_sharing_code->setText(QString("vpn://%1").arg(QString(ba)));
//qDebug() << "Share code" << QJsonDocument(o).toJson();
}
void MainWindow::updateOpenVpnPage(const QJsonObject &openvpnConfig, DockerContainer container, bool haveAuthData)
{
ui->widget_proto_openvpn->setEnabled(haveAuthData);
@ -1968,34 +2051,43 @@ void MainWindow::updateSharingPage(int serverIndex, const ServerCredentials &cre
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
for (QWidget *page : { ui->page_share_openvpn,
ui->page_share_shadowsocks,
ui->page_share_cloak,
ui->page_share_full_access }) {
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"));
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::OpenVpn);
QString cfg = protoConfig.value(config_key::last_config).toString();
if (!cfg.isEmpty()) {
// TODO add redirect-gateway def1 bypass-dhcp here and on click Generate config
ui->textEdit_share_openvpn_code->setPlainText(cfg);
}
else {
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);
}
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);
// QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::OpenVpn);
// QString cfg = protoConfig.value(config_key::last_config).toString();
// if (!cfg.isEmpty()) {
// // TODO add redirect-gateway def1 bypass-dhcp here and on click Generate config
// ui->textEdit_share_openvpn_code->setPlainText(cfg);
// }
// else {
// 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) {
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);
@ -2034,6 +2126,24 @@ void MainWindow::updateSharingPage(int serverIndex, const ServerCredentials &cre
ui->toolBox_share_connection->layout()->update();
}
if (container == DockerContainer::OpenVpnOverCloak) {
ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client"));
}
// 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)) {
@ -2046,38 +2156,6 @@ void MainWindow::updateSharingPage(int serverIndex, const ServerCredentials &cre
// ui->textEdit_share_amnezia_code->setPlainText(QJsonDocument(exportContainer).toJson());
ui->textEdit_share_amnezia_code->setPlainText(tr(""));
repaint();
update();
updateGeometry();
}
void MainWindow::makeSitesListItem(QListWidget *listWidget, const QString &address)
{
QSize size(310, 25);
QWidget* widget = new QWidget;
widget->resize(size);
QLabel *label = new QLabel(address, widget);
label->resize(size);
QPushButton* btn = new QPushButton(widget);
btn->resize(size);
QPushButton* btn1 = new QPushButton(widget);
btn1->resize(30, 25);
btn1->move(280, 0);
btn1->setCursor(QCursor(Qt::PointingHandCursor));
connect(btn1, &QPushButton::clicked, this, [this, label]() {
onPushButtonDeleteCustomSiteClicked(label->text());
return;
});
QListWidgetItem* item = new QListWidgetItem(listWidget);
item->setSizeHint(size);
listWidget->setItemWidget(item, widget);
widget->setStyleSheet(styleSheet());
}
void MainWindow::makeServersListItem(QListWidget *listWidget, const QJsonObject &server, bool isDefault, int index)

View file

@ -17,6 +17,7 @@
#include "protocols/vpnprotocol.h"
#include "settings.h"
#include "sites_model.h"
class VpnConnection;
@ -63,7 +64,6 @@ private slots:
void onPushButtonForgetServer(bool);
void onPushButtonAddCustomSitesClicked();
void onPushButtonDeleteCustomSiteClicked(const QString &siteToDelete);
void onTrayActionConnect(); // connect from context menu
void setTrayState(VpnProtocol::ConnectionState state);
@ -94,6 +94,8 @@ private:
void setupUiConnections();
void setupNewServerConnections();
void setupWizardConnections();
void setupVpnPageConnections();
void setupSitesPageConnections();
void setupAppSettingsConnections();
void setupGeneralSettingsConnections();
void setupNetworkSettingsConnections();
@ -110,7 +112,6 @@ private:
void updateServerPage();
void updateServersListPage();
void updateProtocolsPage();
void updateShareCodePage();
void updateOpenVpnPage(const QJsonObject &openvpnConfig, DockerContainer container, bool haveAuthData);
void updateShadowSocksPage(const QJsonObject &ssConfig, DockerContainer container, bool haveAuthData);
void updateCloakPage(const QJsonObject &ckConfig, DockerContainer container, bool haveAuthData);
@ -118,7 +119,6 @@ private:
void updateSharingPage(int serverIndex, const ServerCredentials &credentials,
DockerContainer container);
void makeSitesListItem(QListWidget* listWidget, const QString &address);
void makeServersListItem(QListWidget* listWidget, const QJsonObject &server, bool isDefault, int index);
void updateQRCodeImage(const QString &text, QLabel *label);
@ -135,6 +135,8 @@ private:
VpnConnection* m_vpnConnection;
Settings m_settings;
QMap<Settings::RouteMode, SitesModel *> sitesModels;
QAction* m_trayActionConnect;
QAction* m_trayActionDisconnect;

View file

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string/>
<string>AmneziaVPN</string>
</property>
<property name="styleSheet">
<string notr="true">QMainWindow {
@ -120,18 +120,18 @@ border-image: url(:/images/controls/check_on.png);
}
QScrollBar:vertical { /* The area behind the scrollbar covering entire height. */
background-color: grey;
background-color: rgba(0, 0, 0,0);
opacity: 100;
width: 7px; /* set width to zero to hide scrollbar entirely. Can look quite clean and scrolling still works with mousewheel. */
margin: 0px 0px; /* Takes the height of the buttons + 3 extra pixels to leave some free space between handle and buttons */
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;
}
@ -143,7 +143,7 @@ QScrollBar::handle:vertical:pressed { /* state when you hover over the handle */
}
QScrollBar::sub-line:vertical { /* button to scroll up */
background-color: rgb(240,240,240);
height: 0px;
height: 10px;
subcontrol-position: top;
subcontrol-origin: margin;
}
@ -158,7 +158,8 @@ QScrollBar::up-arrow:vertical { /* arrow to scroll up with */
QScrollBar::add-line:vertical { /* Button to scroll down */
background-color: rgb(240,240,240);
height: 0px;
height: 10px;
padding-top: 2px;
subcontrol-position: bottom;
subcontrol-origin: margin;
}
@ -171,27 +172,9 @@ QScrollBar::down-arrow:vertical { /* arrow to scroll down with */
}
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
background-color: black;
}
background-color: rgb(240,240,240);
/*
QGroupBox {
border: 1px solid lightgray;
border-radius: 2px;
margin-top: 1ex;
}
QGroupBox::title {
font-size: 16px;
font-style: normal;
font-weight: normal;
color: #181922;
subcontrol-origin: margin;
subcontrol-position: top left;
padding: 0 3px;
}
*/</string>
}</string>
</property>
<widget class="QWidget" name="centralWidget">
<property name="styleSheet">
@ -291,7 +274,7 @@ QPushButton:hover {
<string notr="true"/>
</property>
<property name="currentIndex">
<number>1</number>
<number>10</number>
</property>
<widget class="QWidget" name="page_start">
<widget class="QLabel" name="label_25">
@ -2720,7 +2703,7 @@ background: #211966;
<property name="geometry">
<rect>
<x>0</x>
<y>370</y>
<y>360</y>
<width>380</width>
<height>51</height>
</rect>
@ -2826,7 +2809,7 @@ font: 16px &quot;Lato&quot;; </string>
<property name="geometry">
<rect>
<x>20</x>
<y>550</y>
<y>560</y>
<width>341</width>
<height>40</height>
</rect>
@ -2960,9 +2943,9 @@ color: #181922;
<property name="geometry">
<rect>
<x>20</x>
<y>450</y>
<y>440</y>
<width>281</width>
<height>31</height>
<height>21</height>
</rect>
</property>
<property name="styleSheet">
@ -2983,49 +2966,11 @@ color: #181922;
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QRadioButton" name="radioButton_mode_all_sites">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>20</x>
<y>490</y>
<width>341</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>For all connections</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QRadioButton" name="radioButton_mode_selected_sites">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>20</x>
<y>520</y>
<width>341</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>For selected sites</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
<widget class="QLabel" name="label_error_text">
<property name="geometry">
<rect>
<x>0</x>
<y>290</y>
<y>280</y>
<width>381</width>
<height>61</height>
</rect>
@ -3043,10 +2988,77 @@ color: #181922;
<bool>true</bool>
</property>
</widget>
<widget class="QWidget" name="widget_vpn_mode" native="true">
<property name="geometry">
<rect>
<x>20</x>
<y>470</y>
<width>351</width>
<height>91</height>
</rect>
</property>
<widget class="QRadioButton" name="radioButton_vpn_mode_except_sites">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>60</y>
<width>341</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>Except selected sites</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
<widget class="QRadioButton" name="radioButton_vpn_mode_forward_sites">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>30</y>
<width>341</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>For selected sites</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
<widget class="QRadioButton" name="radioButton_vpn_mode_all_sites">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>341</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>For all connections</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</widget>
</widget>
<widget class="QWidget" name="page_sites">
<property name="styleSheet">
<string notr="true">QListView {
<string notr="true">/*QListView {
outline: 0;
background: transparent;
border: none;
@ -3071,7 +3083,8 @@ QListView::item:selected {
border: none;
background: rgba(167, 167, 167, 0.1);
color: #181922;
}</string>
}
*/</string>
</property>
<widget class="QPushButton" name="pushButton_back_from_sites">
<property name="geometry">
@ -3160,7 +3173,7 @@ color: #100A44;
<rect>
<x>20</x>
<y>140</y>
<width>281</width>
<width>231</width>
<height>31</height>
</rect>
</property>
@ -3191,7 +3204,7 @@ color: #100A44;
<set>Qt::AlignCenter</set>
</property>
<property name="placeholderText">
<string>For example, yousite.com or 17.21.111.8</string>
<string>yousite.com or IP address</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_sites_add_custom">
@ -3200,7 +3213,7 @@ color: #100A44;
</property>
<property name="geometry">
<rect>
<x>310</x>
<x>260</x>
<y>140</y>
<width>51</width>
<height>31</height>
@ -3246,50 +3259,127 @@ line-height: 150%;
color: #333333;</string>
</property>
<property name="text">
<string>Web site or hostname or IP address</string>
<string>Web site/Hostname/IP address/Subnet</string>
</property>
</widget>
<widget class="QListWidget" name="listWidget_sites">
<widget class="QTableView" name="tableView_sites">
<property name="geometry">
<rect>
<x>20</x>
<y>200</y>
<width>340</width>
<height>400</height>
<width>341</width>
<height>371</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QWidget {
margin: 0px;
padding: 0px;
}
QPushButton:hover {
image: url(:/images/close.png);
image-position: right center;
}
QListView {
show-decoration-selected: 1; /* make the selection span the entire width of the view */
}
QListView::item:selected:!active {
<string notr="true">QTableView {
background: transparent;
gridline-color: transparent;
border: none;
outline: none;
show-decoration-selected: 1;
}
QListView::item:selected:active {
background: transparent;
border: none;
QTableView::item
{
padding-left: 5px;
border-top: 1px solid lightgray;
color: #181922;
}
QListView::item:hover {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #FAFBFE, stop: 1 #ECEEFF);
QTableView::item::selected
{
border: 0px;
padding-left: 5px;
background-color: rgb(99, 180, 251);
border: : rgb(99, 180, 251);
}</string>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="gridStyle">
<enum>Qt::NoPen</enum>
</property>
<property name="cornerButtonEnabled">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
<widget class="QPushButton" name="pushButton_sites_delete">
<property name="geometry">
<rect>
<x>80</x>
<y>589</y>
<width>231</width>
<height>31</height>
</rect>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="styleSheet">
<string notr="true">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;
}</string>
</property>
<property name="text">
<string>Delete selected</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_sites_import">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>320</x>
<y>140</y>
<width>51</width>
<height>31</height>
</rect>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
background: #100A44;
border-radius: 4px;
padding: 5px;
image: url(:/images/folder.png);
}
QPushButton:hover {
background: #211966;
}</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</widget>
@ -4471,7 +4561,7 @@ font-weight: bold;
<property name="geometry">
<rect>
<x>40</x>
<y>220</y>
<y>210</y>
<width>300</width>
<height>40</height>
</rect>
@ -4528,6 +4618,40 @@ font-size: 20px;
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
<widget class="QPushButton" name="pushButton_server_settings_share_full">
<property name="geometry">
<rect>
<x>40</x>
<y>260</y>
<width>300</width>
<height>40</height>
</rect>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="styleSheet">
<string notr="true">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;
}</string>
</property>
<property name="text">
<string>Share Server (FULL ACCESS)</string>
</property>
</widget>
<zorder>label_server_settings_wait_info</zorder>
<zorder>label_16</zorder>
<zorder>label_17</zorder>
@ -4539,6 +4663,7 @@ font-size: 20px;
<zorder>pushButton_server_settings_protocols</zorder>
<zorder>pushButton_back_from_server_settings</zorder>
<zorder>label_server_settings_current_vpn_protocol</zorder>
<zorder>pushButton_server_settings_share_full</zorder>
</widget>
<widget class="QWidget" name="page_server_protocols">
<property name="styleSheet">
@ -5284,7 +5409,30 @@ border-radius: 4px 0px 0px 4px;
</widget>
<widget class="QWidget" name="page_share_connection">
<property name="styleSheet">
<string notr="true"/>
<string notr="true">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);
}</string>
</property>
<widget class="QPushButton" name="pushButton_back_from_share">
<property name="geometry">
@ -5391,7 +5539,7 @@ QToolBox::tab:hover {
<number>0</number>
</property>
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<property name="tabSpacing">
<number>6</number>
@ -5401,8 +5549,8 @@ QToolBox::tab:hover {
<rect>
<x>0</x>
<y>0</y>
<width>100</width>
<height>30</height>
<width>360</width>
<height>360</height>
</rect>
</property>
<property name="styleSheet">
@ -5725,8 +5873,8 @@ background: #282932;
<rect>
<x>0</x>
<y>0</y>
<width>100</width>
<height>30</height>
<width>360</width>
<height>360</height>
</rect>
</property>
<attribute name="label">
@ -5891,8 +6039,8 @@ background: #282932;
<rect>
<x>0</x>
<y>0</y>
<width>100</width>
<height>30</height>
<width>360</width>
<height>360</height>
</rect>
</property>
<property name="styleSheet">
@ -6115,8 +6263,8 @@ color: #15CDCB;
<rect>
<x>0</x>
<y>0</y>
<width>100</width>
<height>30</height>
<width>360</width>
<height>360</height>
</rect>
</property>
<attribute name="label">

72
client/ui/sites_model.cpp Normal file
View file

@ -0,0 +1,72 @@
#include "sites_model.h"
SitesModel::SitesModel(Settings::RouteMode mode, QObject *parent)
: m_mode(mode),
QAbstractTableModel(parent)
{
}
void SitesModel::resetCache()
{
beginResetModel();
m_ipsCache.clear();
m_cacheReady = false;
endResetModel();
}
QVariant SitesModel::headerData(int section, Qt::Orientation orientation, int role) const
{
// FIXME: Implement me!
return QVariant();
}
int SitesModel::rowCount(const QModelIndex &parent) const
{
if (!m_cacheReady) genCache();
return m_ipsCache.size();
}
int SitesModel::columnCount(const QModelIndex &parent) const
{
return 2;
}
QVariant SitesModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (!m_cacheReady) genCache();
if (role == Qt::DisplayRole){
if (m_ipsCache.isEmpty()) return QVariant();
if (index.column() == 0) {
return m_ipsCache.at(index.row()).first;
}
if (index.column() == 1) {
return m_ipsCache.at(index.row()).second;
}
}
// if (role == Qt::TextAlignmentRole && index.column() == 1) {
// return Qt::AlignRight;
// }
return QVariant();
}
void SitesModel::genCache() const
{
qDebug() << "SitesModel::genCache";
m_ipsCache.clear();
const QVariantMap &sites = m_settings.vpnSites(m_mode);
auto i = sites.constBegin();
while (i != sites.constEnd()) {
m_ipsCache.append(qMakePair(i.key(), i.value().toString()));
++i;
}
m_cacheReady= true;
}

36
client/ui/sites_model.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef SITESMODEL_H
#define SITESMODEL_H
#include <QAbstractTableModel>
#include "settings.h"
class SitesModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit SitesModel(Settings::RouteMode mode, QObject *parent = nullptr);
void resetCache();
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
private:
void genCache() const;
private:
Settings::RouteMode m_mode;
Settings m_settings;
mutable QVector<QPair<QString, QString>> m_ipsCache;
mutable bool m_cacheReady = false;
};
#endif // SITESMODEL_H

View file

@ -146,7 +146,7 @@ bool Utils::checkIPFormat(const QString& ip)
return false;
QStringList list = ip.trimmed().split(".");
foreach(QString it, list) {
for (const QString &it : list) {
if(it.toInt() <= 255 && it.toInt() >= 0)
continue;
return false;
@ -154,6 +154,18 @@ bool Utils::checkIPFormat(const QString& ip)
return true;
}
bool Utils::checkIpSubnetFormat(const QString &ip)
{
if (!ip.contains("/")) return checkIPFormat(ip);
QStringList parts = ip.split("/");
if (parts.size() != 2) return false;
bool ok;
if (parts.at(1).toInt(&ok) <= 32 && ok) return checkIPFormat(parts.at(0));
else return false;
}
void Utils::killProcessByName(const QString &name)
{
qDebug().noquote() << "Kill process" << name;
@ -164,6 +176,28 @@ void Utils::killProcessByName(const QString &name)
#endif
}
QString Utils::netMaskFromIpWithSubnet(const QString ip)
{
if (!ip.contains("/")) return "255.255.255.255";
bool ok;
int prefix = ip.split("/").at(1).toInt(&ok);
if (!ok) return "255.255.255.255";
unsigned long mask = (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF;
return QString("%1.%2.%3.%4")
.arg(mask >> 24)
.arg((mask >> 16) & 0xFF)
.arg((mask >> 8) & 0xFF)
.arg( mask & 0xFF);
}
QString Utils::ipAddressFromIpWithSubnet(const QString ip)
{
return ip.split("/").first();
}
#ifdef Q_OS_WIN
// Inspired from http://stackoverflow.com/a/15281070/1529139
// and http://stackoverflow.com/q/40059902/1529139

View file

@ -23,10 +23,14 @@ public:
static QString getIPAddress(const QString& host);
static QString getStringBetween(const QString& s, const QString& a, const QString& b);
static bool checkIPFormat(const QString& ip);
static bool checkIpSubnetFormat(const QString& ip);
static QRegExp ipAddressRegExp() { return QRegExp("^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\\.(?!$)|$)){4}$"); }
static QRegExp ipAddressPortRegExp() { return QRegExp("^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}"
"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(\\:[0-9]{1,5}){0,1}$"); }
static QRegExp ipAddressWithSubnetRegExp() { return QRegExp("(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}"
"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(\\/[0-9]{1,2}){0,1}"); }
static QRegExp ipNetwork24RegExp() { return QRegExp("^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}"
"0$"); }
@ -35,6 +39,9 @@ public:
static bool processIsRunning(const QString& fileName);
static void killProcessByName(const QString &name);
static QString netMaskFromIpWithSubnet(const QString ip);
static QString ipAddressFromIpWithSubnet(const QString ip);
#ifdef Q_OS_WIN
static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent);
#endif

View file

@ -43,22 +43,22 @@ void VpnConnection::onConnectionStateChanged(VpnProtocol::ConnectionState state)
if (state == VpnProtocol::ConnectionState::Connected && IpcClient::Interface()){
IpcClient::Interface()->flushDns();
if (m_settings.customRouting()) {
if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) {
IpcClient::Interface()->routeDelete("0.0.0.0", m_vpnProtocol->vpnGateway());
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(),
QStringList() << m_settings.primaryDns() << m_settings.secondaryDns());
const QStringList &black_custom = m_settings.customIps();
qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << black_custom.size();
const QStringList &forwardIps = m_settings.getVpnIps(Settings::VpnOnlyForwardSites);
qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << forwardIps.size();
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), black_custom);
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), forwardIps);
}
}
else if (state == VpnProtocol::ConnectionState::Error) {
IpcClient::Interface()->flushDns();
if (m_settings.customRouting()) {
if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) {
IpcClient::Interface()->clearSavedRoutes();
}
}
@ -199,7 +199,7 @@ ErrorCode VpnConnection::createVpnConfiguration(int serverIndex,
ErrorCode VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig)
{
qDebug() << "СonnectToVpn, CustomRouting is" << m_settings.customRouting();
qDebug() << "СonnectToVpn, Route mode is" << m_settings.routeMode();
emit connectionStateChanged(VpnProtocol::ConnectionState::Connecting);
@ -276,7 +276,7 @@ void VpnConnection::disconnectFromVpn()
if (IpcClient::Interface()) {
IpcClient::Interface()->flushDns();
if (m_settings.customRouting()) {
if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) {
IpcClient::Interface()->clearSavedRoutes();
}
}

View file

@ -7,7 +7,7 @@ class IpcInterface
//SIGNAL(sendMessage(const QByteArray &message));
// Route functions
SLOT( bool routeAdd(const QString &ip, const QString &gw, const QString &mask) );
SLOT( bool routeAdd(const QString &ip, const QString &gw) );
SLOT( int routeAddList(const QString &gw, const QStringList &ips) );
SLOT( bool clearSavedRoutes() );
SLOT( bool routeDelete(const QString &ip, const QString &gw) );

View file

@ -53,9 +53,9 @@ int IpcServer::createPrivilegedProcess()
return m_localpid;
}
bool IpcServer::routeAdd(const QString &ip, const QString &gw, const QString &mask)
bool IpcServer::routeAdd(const QString &ip, const QString &gw)
{
return Router::routeAdd(ip, gw, mask);
return Router::routeAdd(ip, gw);
}
int IpcServer::routeAddList(const QString &gw, const QStringList &ips)

View file

@ -15,7 +15,7 @@ public:
explicit IpcServer(QObject *parent = nullptr);
virtual int createPrivilegedProcess() override;
virtual bool routeAdd(const QString &ip, const QString &gw, const QString &mask = QString()) override;
virtual bool routeAdd(const QString &ip, const QString &gw) override;
virtual int routeAddList(const QString &gw, const QStringList &ips) override;
virtual bool clearSavedRoutes() override;
virtual bool routeDelete(const QString &ip, const QString &gw) override;

View file

@ -7,12 +7,12 @@
#endif
bool Router::routeAdd(const QString &ip, const QString &gw, QString mask)
bool Router::routeAdd(const QString &ip, const QString &gw)
{
#ifdef Q_OS_WIN
return RouterWin::Instance().routeAdd(ip, gw, mask);
return RouterWin::Instance().routeAdd(ip, gw);
#elif defined (Q_OS_MAC)
return RouterMac::Instance().routeAdd(ip, gw, mask);
return RouterMac::Instance().routeAdd(ip, gw);
#endif
}

View file

@ -15,7 +15,7 @@ class Router : public QObject
{
Q_OBJECT
public:
static bool routeAdd(const QString &ip, const QString &gw, QString mask = QString());
static bool routeAdd(const QString &ip, const QString &gw);
static int routeAddList(const QString &gw, const QStringList &ips);
static bool clearSavedRoutes();
static bool routeDelete(const QString &ip, const QString &gw);

View file

@ -9,7 +9,7 @@ RouterMac &RouterMac::Instance()
return s;
}
bool RouterMac::routeAdd(const QString &ip, const QString &gw, QString mask)
bool RouterMac::routeAdd(const QString &ip, const QString &gw)
{
int argc = 5;
char **argv = new char*[argc];

View file

@ -18,7 +18,7 @@ class RouterMac : public QObject
public:
static RouterMac& Instance();
bool routeAdd(const QString &ip, const QString &gw, QString mask = QString());
bool routeAdd(const QString &ip, const QString &gw);
int routeAddList(const QString &gw, const QStringList &ips);
bool clearSavedRoutes();
bool routeDelete(const QString &ip, const QString &gw);

View file

@ -1,4 +1,5 @@
#include "router_win.h"
#include "../client/utils.h"
#include <QProcess>
@ -8,20 +9,11 @@ RouterWin &RouterWin::Instance()
return s;
}
bool RouterWin::routeAdd(const QString &ip, const QString &gw, QString mask)
bool RouterWin::routeAdd(const QString &ip, const QString &gw)
{
qDebug().noquote() << QString("ROUTE ADD: IP:%1 %2 GW %3")
.arg(ip)
.arg(mask)
.arg(gw);
if (mask == "") {
mask = "255.255.255.255";
if (ip.endsWith(".0")) mask = "255.255.255.0";
if (ip.endsWith(".0.0")) mask = "255.255.0.0";
if (ip.endsWith(".0.0.0")) mask = "255.0.0.0";
}
//qDebug().noquote() << QString("ROUTE ADD: IP:%1 GW %2").arg(ip).arg(gw);
QString mask = Utils::netMaskFromIpWithSubnet(ip);
PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
MIB_IPFORWARDROW ipfrow;
@ -58,7 +50,7 @@ bool RouterWin::routeAdd(const QString &ip, const QString &gw, QString mask)
}
// address
ipfrow.dwForwardDest = inet_addr(ip.toStdString().c_str());
ipfrow.dwForwardDest = inet_addr(Utils::ipAddressFromIpWithSubnet(ip).toStdString().c_str());
// mask
in_addr maskAddr;
@ -109,12 +101,12 @@ bool RouterWin::routeAdd(const QString &ip, const QString &gw, QString mask)
int RouterWin::routeAddList(const QString &gw, const QStringList &ips)
{
qDebug().noquote() << QString("ROUTE ADD List: IPs size:%1, GW: %2")
.arg(ips.size())
.arg(gw);
// qDebug().noquote() << QString("ROUTE ADD List: IPs size:%1, GW: %2")
// .arg(ips.size())
// .arg(gw);
qDebug().noquote() << QString("ROUTE ADD List: IPs:\n%1")
.arg(ips.join("\n"));
// qDebug().noquote() << QString("ROUTE ADD List: IPs:\n%1")
// .arg(ips.join("\n"));
@ -188,15 +180,10 @@ int RouterWin::routeAddList(const QString &gw, const QStringList &ips)
for (int i = 0; i < ips.size(); ++i) {
QString ip = ips.at(i);
if (ip.isEmpty()) continue;
mask = "255.255.255.255";
if (ip.endsWith(".0")) mask = "255.255.255.0";
if (ip.endsWith(".0.0")) mask = "255.255.0.0";
if (ip.endsWith(".0.0.0")) mask = "255.0.0.0";
QString mask = Utils::netMaskFromIpWithSubnet(ip);
// address
ipfrow.dwForwardDest = inet_addr(ip.toStdString().c_str());
ipfrow.dwForwardDest = inet_addr(Utils::ipAddressFromIpWithSubnet(ip).toStdString().c_str());
// mask
in_addr maskAddr;
@ -280,7 +267,7 @@ bool RouterWin::routeDelete(const QString &ip, const QString &gw)
QProcess p;
p.setProcessChannelMode(QProcess::MergedChannels);
QString command = QString("route delete %1 %2").arg(ip).arg(gw);
QString command = QString("route delete %1 %2").arg(Utils::ipAddressFromIpWithSubnet(ip)).arg(gw);
p.start(command);
p.waitForFinished();

View file

@ -38,7 +38,7 @@ class RouterWin : public QObject
public:
static RouterWin& Instance();
bool routeAdd(const QString &ip, const QString &gw, QString mask = QString());
bool routeAdd(const QString &ip, const QString &gw);
int routeAddList(const QString &gw, const QStringList &ips);
bool clearSavedRoutes();
bool routeDelete(const QString &ip, const QString &gw);