Merge remote-tracking branch 'origin/dev' into ios-wireguard

This commit is contained in:
Alex Kh 2022-02-15 10:55:45 +04:00
commit e1293c2c74
118 changed files with 2135 additions and 981 deletions

View file

@ -24,7 +24,7 @@ enum class Page {Start = 0, NewServer, NewServerProtocols, Vpn,
Wizard, WizardLow, WizardMedium, WizardHigh, WizardVpnMode, ServerConfiguringProgress,
GeneralSettings, AppSettings, NetworkSettings, ServerSettings,
ServerContainers, ServersList, ShareConnection, Sites,
ProtocolSettings, ProtocolShare, QrDecoder};
ProtocolSettings, ProtocolShare, QrDecoder, About};
Q_ENUM_NS(Page)
static void declareQmlPageEnum() {

View file

@ -4,6 +4,10 @@
#include "defines.h"
#include "ui/qautostart.h"
#include <QDesktopServices>
#include <QFileDialog>
#include <QStandardPaths>
using namespace amnezia;
using namespace PageEnumNS;
@ -11,7 +15,8 @@ AppSettingsLogic::AppSettingsLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent),
m_checkBoxAutostartChecked{false},
m_checkBoxAutoConnectChecked{false},
m_checkBoxStartMinimizedChecked{false}
m_checkBoxStartMinimizedChecked{false},
m_checkBoxSaveLogsChecked{false}
{
}
@ -21,6 +26,7 @@ void AppSettingsLogic::onUpdatePage()
set_checkBoxAutostartChecked(Autostart::isAutostart());
set_checkBoxAutoConnectChecked(m_settings.isAutoConnect());
set_checkBoxStartMinimizedChecked(m_settings.isStartMinimized());
set_checkBoxSaveLogsChecked(m_settings.isSaveLogs());
QString ver = QString("%1: %2 (%3)")
.arg(tr("Software version"))
@ -47,7 +53,38 @@ void AppSettingsLogic::onCheckBoxStartMinimizedToggled(bool checked)
m_settings.setStartMinimized(checked);
}
void AppSettingsLogic::onCheckBoxSaveLogsCheckedToggled(bool checked)
{
m_settings.setSaveLogs(checked);
}
void AppSettingsLogic::onPushButtonOpenLogsClicked()
{
Debug::openLogsFolder();
}
void AppSettingsLogic::onPushButtonExportLogsClicked()
{
QString log = Debug::getLogFile();
QString ext = ".log";
QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save log"),
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*" + ext);
if (fileName.isEmpty()) return;
if (!fileName.endsWith(ext)) fileName.append(ext);
QFile save(fileName);
save.open(QIODevice::WriteOnly);
save.write(log.toUtf8());
save.close();
QFileInfo fi(fileName);
QDesktopServices::openUrl(fi.absoluteDir().absolutePath());
}
void AppSettingsLogic::onPushButtonClearLogsClicked()
{
Debug::clearLogs();
Debug::clearServiceLogs();
}

View file

@ -11,6 +11,7 @@ class AppSettingsLogic : public PageLogicBase
AUTO_PROPERTY(bool, checkBoxAutostartChecked)
AUTO_PROPERTY(bool, checkBoxAutoConnectChecked)
AUTO_PROPERTY(bool, checkBoxStartMinimizedChecked)
AUTO_PROPERTY(bool, checkBoxSaveLogsChecked)
AUTO_PROPERTY(QString, labelVersionText)
public:
@ -19,7 +20,10 @@ public:
Q_INVOKABLE void onCheckBoxAutostartToggled(bool checked);
Q_INVOKABLE void onCheckBoxAutoconnectToggled(bool checked);
Q_INVOKABLE void onCheckBoxStartMinimizedToggled(bool checked);
Q_INVOKABLE void onCheckBoxSaveLogsCheckedToggled(bool checked);
Q_INVOKABLE void onPushButtonOpenLogsClicked();
Q_INVOKABLE void onPushButtonExportLogsClicked();
Q_INVOKABLE void onPushButtonClearLogsClicked();
public:
explicit AppSettingsLogic(UiLogic *uiLogic, QObject *parent = nullptr);

View file

@ -5,6 +5,7 @@
NetworkSettingsLogic::NetworkSettingsLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent),
m_checkBoxUseAmneziaDnsChecked{false},
m_ipAddressRegex{Utils::ipAddressRegExp()}
{
@ -12,6 +13,8 @@ NetworkSettingsLogic::NetworkSettingsLogic(UiLogic *logic, QObject *parent):
void NetworkSettingsLogic::onUpdatePage()
{
set_checkBoxUseAmneziaDnsChecked(m_settings.useAmneziaDns());
set_lineEditDns1Text(m_settings.primaryDns());
set_lineEditDns2Text(m_settings.secondaryDns());
}
@ -41,3 +44,8 @@ void NetworkSettingsLogic::onPushButtonResetDns2Clicked()
m_settings.setSecondaryDns(m_settings.cloudFlareNs2);
onUpdatePage();
}
void NetworkSettingsLogic::onCheckBoxUseAmneziaDnsToggled(bool checked)
{
m_settings.setUseAmneziaDns(checked);
}

View file

@ -9,6 +9,8 @@ class NetworkSettingsLogic : public PageLogicBase
{
Q_OBJECT
AUTO_PROPERTY(bool, checkBoxUseAmneziaDnsChecked)
AUTO_PROPERTY(QString, lineEditDns1Text)
AUTO_PROPERTY(QString, lineEditDns2Text)
READONLY_PROPERTY(QRegExp, ipAddressRegex)
@ -21,6 +23,8 @@ public:
Q_INVOKABLE void onPushButtonResetDns1Clicked();
Q_INVOKABLE void onPushButtonResetDns2Clicked();
Q_INVOKABLE void onCheckBoxUseAmneziaDnsToggled(bool checked);
public:
explicit NetworkSettingsLogic(UiLogic *uiLogic, QObject *parent = nullptr);
~NetworkSettingsLogic() = default;

View file

@ -38,8 +38,6 @@ void QrDecoderLogic::onDetectedQrCode(const QString &code)
if (magic == amnezia::qrMagicCode) {
qDebug() << "QrDecoderLogic::onDetectedQrCode magic code detected" << magic << ba.size();
quint8 chunksCount; s >> chunksCount;
if (totalChunksCount() != chunksCount) {
m_chunks.clear();

View file

@ -12,6 +12,9 @@
#include <functional>
#include "../uilogic.h"
#include "../pages_logic/VpnLogic.h"
#include "vpnconnection.h"
ServerContainersLogic::ServerContainersLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent)
@ -42,8 +45,17 @@ void ServerContainersLogic::onPushButtonProtoSettingsClicked(DockerContainer c,
void ServerContainersLogic::onPushButtonDefaultClicked(DockerContainer c)
{
if (m_settings.defaultContainer(uiLogic()->selectedServerIndex) == c) return;
m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c);
uiLogic()->onUpdateAllPages();
if (uiLogic()->selectedServerIndex != m_settings.defaultServerIndex()) return;
if (!uiLogic()->m_vpnConnection) return;
if (!uiLogic()->m_vpnConnection->isConnected()) return;
uiLogic()->vpnLogic()->onDisconnect();
uiLogic()->vpnLogic()->onConnect();
}
void ServerContainersLogic::onPushButtonShareClicked(DockerContainer c)

View file

@ -28,8 +28,8 @@ void ServerSettingsLogic::onUpdatePage()
set_pushButtonClearVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex));
set_pushButtonClearClientCacheVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex));
set_pushButtonShareFullVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex));
QJsonObject server = m_settings.server(uiLogic()->selectedServerIndex);
QString port = server.value(config_key::port).toString();
const QJsonObject &server = m_settings.server(uiLogic()->selectedServerIndex);
const QString &port = server.value(config_key::port).toString();
set_labelServerText(QString("%1@%2%3%4")
.arg(server.value(config_key::userName).toString())
.arg(server.value(config_key::hostName).toString())

View file

@ -1,9 +1,13 @@
#include <QBuffer>
#include <QImage>
#include <QDataStream>
#include <QZXing>
//#include <QZXing>
#include <QMessageBox>
#include "QZXing.h"
#include "QZXingImageProvider.h"
#include "QZXingFilter.h"
#include "ShareConnectionLogic.h"
#include "configurators/cloak_configurator.h"
@ -60,21 +64,24 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked()
set_shareAmneziaQrCodeTextSeriesLength(0);
QJsonObject serverConfig;
int serverIndex = uiLogic()->selectedServerIndex;
DockerContainer container = uiLogic()->selectedDockerContainer;
// Full access
if (shareFullAccess()) {
serverConfig = m_settings.server(uiLogic()->selectedServerIndex);
serverConfig = m_settings.server(serverIndex);
}
// Container share
else {
ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex);
QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
containerConfig.insert(config_key::container, ContainerProps::containerToString(uiLogic()->selectedDockerContainer));
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
QJsonObject containerConfig = m_settings.containerConfig(serverIndex, container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode e = ErrorCode::NoError;
for (Proto p: ContainerProps::protocolsForContainer(uiLogic()->selectedDockerContainer)) {
QJsonObject protoConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, p);
for (Proto p: ContainerProps::protocolsForContainer(container)) {
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, p);
QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, uiLogic()->selectedDockerContainer, containerConfig, p, &e);
QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, container, containerConfig, p, &e);
if (e) {
cfg = "Error generating config";
break;
@ -85,12 +92,17 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked()
QByteArray ba;
if (!e) {
serverConfig = m_settings.server(uiLogic()->selectedServerIndex);
serverConfig = m_settings.server(serverIndex);
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, ContainerProps::containerToString(uiLogic()->selectedDockerContainer));
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
auto dns = VpnConfigurator::getDnsForConfig(serverIndex);
serverConfig.insert(config_key::dns1, dns.first);
serverConfig.insert(config_key::dns2, dns.second);
}
else {
set_textEditShareAmneziaCodeText(tr("Error while generating connection profile"));
@ -111,12 +123,15 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked()
void ShareConnectionLogic::onPushButtonShareOpenVpnGenerateClicked()
{
ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex);
const QJsonObject &containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
int serverIndex = uiLogic()->selectedServerIndex;
DockerContainer container = uiLogic()->selectedDockerContainer;
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
ErrorCode e = ErrorCode::NoError;
QString cfg = OpenVpnConfigurator::genOpenVpnConfig(credentials, uiLogic()->selectedDockerContainer, containerConfig, &e);
cfg = VpnConfigurator::processConfigWithExportSettings(uiLogic()->selectedDockerContainer, Proto::OpenVpn, cfg);
QString cfg = OpenVpnConfigurator::genOpenVpnConfig(credentials, container, containerConfig, &e);
cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, cfg);
set_textEditShareOpenVpnCodeText(QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString());
}
@ -202,7 +217,7 @@ void ShareConnectionLogic::onPushButtonShareWireGuardGenerateClicked()
errorString(e));
return;
}
cfg = VpnConfigurator::processConfigWithExportSettings(container, Proto::WireGuard, cfg);
cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, cfg);
cfg = QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString();
set_textEditShareWireGuardCodeText(cfg);
@ -223,7 +238,7 @@ void ShareConnectionLogic::onPushButtonShareIkev2GenerateClicked()
Ikev2Configurator::ConnectionData connData = Ikev2Configurator::prepareIkev2Config(credentials, container);
QString cfg = Ikev2Configurator::genIkev2Config(connData);
cfg = VpnConfigurator::processConfigWithExportSettings(container, Proto::Ikev2, cfg);
cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::Ikev2, cfg);
cfg = QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::cert].toString();
set_textEditShareIkev2CertText(cfg);

View file

@ -98,27 +98,32 @@ void SitesLogic::onPushButtonAddCustomSitesClicked()
}
}
void SitesLogic::onPushButtonSitesDeleteClicked(int row)
void SitesLogic::onPushButtonSitesDeleteClicked(QStringList items)
{
Settings::RouteMode mode = m_settings.routeMode();
auto siteModel = qobject_cast<SitesModel*> (tableViewSitesModel());
if (!siteModel) {
return;
}
if (row < 0 || row >= siteModel->rowCount()) {
if (!siteModel || items.isEmpty()) {
return;
}
{
QStringList sites;
QStringList sites;
QStringList ips;
for (const QString &s: items) {
bool ok;
int row = s.toInt(&ok);
if (!ok || row < 0 || row >= siteModel->rowCount()) return;
sites.append(siteModel->data(row, 0).toString());
m_settings.removeVpnSites(mode, sites);
if (uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) {
ips.append(siteModel->data(row, 1).toString());
}
}
m_settings.removeVpnSites(mode, sites);
if (uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) {
QStringList ips;
ips.append(siteModel->data(row, 1).toString());
uiLogic()->m_vpnConnection->deleteRoutes(ips);
uiLogic()->m_vpnConnection->flushDns();
}
@ -137,18 +142,53 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName)
Settings::RouteMode mode = m_settings.routeMode();
QStringList ips;
QMap<QString, QString> sites;
while (!file.atEnd()) {
QString line = file.readLine();
QStringList line_ips;
QStringList line_sites;
int pos = 0;
QRegExp rx = Utils::ipAddressWithSubnetRegExp();
while ((pos = rx.indexIn(line, pos)) != -1) {
ips << rx.cap(0);
pos += rx.matchedLength();
int posDomain = 0;
QRegExp domainRx = Utils::domainRegExp();
while ((posDomain = domainRx.indexIn(line, posDomain)) != -1) {
line_sites.append(domainRx.cap(0));
posDomain += domainRx.matchedLength();
}
int posIp = 0;
QRegExp ipRx = Utils::ipAddressWithSubnetRegExp();
while ((posIp = ipRx.indexIn(line, posIp)) != -1) {
line_ips.append(ipRx.cap(0));
posIp += ipRx.matchedLength();
}
// domain regex cover ip regex, so remove ips from sites
for (const QString& ip: line_ips) {
line_sites.removeAll(ip);
}
if (line_sites.size() == 1 && line_ips.size() == 1) {
sites.insert(line_sites.at(0), line_ips.at(0));
}
else if (line_sites.size() > 0 && line_ips.size() == 0) {
for (const QString& site: line_sites) {
sites.insert(site, "");
}
}
else {
for (const QString& site: line_sites) {
sites.insert(site, "");
}
for (const QString& ip: line_ips) {
ips.append(ip);
}
}
}
m_settings.addVpnIps(mode, ips);
m_settings.addVpnSites(mode, sites);
uiLogic()->m_vpnConnection->addRoutes(QStringList() << ips);
uiLogic()->m_vpnConnection->flushDns();
@ -156,3 +196,16 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName)
onUpdatePage();
}
void SitesLogic::onPushButtonSitesExportClicked()
{
Settings::RouteMode mode = m_settings.routeMode();
QVariantMap sites = m_settings.vpnSites(mode);
QString data;
for (auto s : sites.keys()) {
data += s + "\t" + sites.value(s).toString() + "\n";
}
uiLogic()->saveTextFile("Sites", ".txt", data);
}

View file

@ -18,8 +18,10 @@ public:
Q_INVOKABLE void onUpdatePage() override;
Q_INVOKABLE void onPushButtonAddCustomSitesClicked();
Q_INVOKABLE void onPushButtonSitesDeleteClicked(int row);
Q_INVOKABLE void onPushButtonSitesDeleteClicked(QStringList items);
Q_INVOKABLE void onPushButtonSitesImportClicked(const QString &fileName);
Q_INVOKABLE void onPushButtonSitesExportClicked();
public:
explicit SitesLogic(UiLogic *uiLogic, QObject *parent = nullptr);

View file

@ -5,6 +5,7 @@
#include <functional>
#include "../uilogic.h"
#include "defines.h"
#include <configurators/vpn_configurator.h>
VpnLogic::VpnLogic(UiLogic *logic, QObject *parent):
@ -33,15 +34,24 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent):
onConnect();
});
}
else {
onConnectionStateChanged(VpnProtocol::Disconnected);
}
}
void VpnLogic::onUpdatePage()
{
Settings::RouteMode mode = m_settings.routeMode();
set_radioButtonVpnModeAllSitesChecked(mode == Settings::VpnAllSites);
set_radioButtonVpnModeForwardSitesChecked(mode == Settings::VpnOnlyForwardSites);
set_radioButtonVpnModeExceptSitesChecked(mode == Settings::VpnAllExceptSites);
DockerContainer selectedContainer = m_settings.defaultContainer(m_settings.defaultServerIndex());
set_isCustomRoutesSupported (selectedContainer == DockerContainer::OpenVpn ||
selectedContainer == DockerContainer::ShadowSocks||
selectedContainer == DockerContainer::Cloak);
set_radioButtonVpnModeAllSitesChecked(mode == Settings::VpnAllSites || !isCustomRoutesSupported());
set_radioButtonVpnModeForwardSitesChecked(mode == Settings::VpnOnlyForwardSites && isCustomRoutesSupported());
set_radioButtonVpnModeExceptSitesChecked(mode == Settings::VpnAllExceptSites && isCustomRoutesSupported());
const QJsonObject &server = uiLogic()->m_settings.defaultServer();
QString serverString = QString("%2 (%3)")
@ -49,10 +59,19 @@ void VpnLogic::onUpdatePage()
.arg(server.value(config_key::hostName).toString());
set_labelCurrentServer(serverString);
DockerContainer selectedContainer = m_settings.defaultContainer(m_settings.defaultServerIndex());
QString selectedContainerName = ContainerProps::containerHumanNames().value(selectedContainer);
set_labelCurrentService(selectedContainerName);
auto dns = VpnConfigurator::getDnsForConfig(m_settings.defaultServerIndex());
set_amneziaDnsEnabled(dns.first == protocols::dns::amneziaDnsIp);
if (dns.first == protocols::dns::amneziaDnsIp) {
set_labelCurrentDns("On your server");
}
else {
set_labelCurrentDns(dns.first + ", " + dns.second);
}
set_isContainerWorkingOnPlatform(ContainerProps::isWorkingOnPlatform(selectedContainer));
if (!isContainerWorkingOnPlatform()) {
set_labelErrorText(tr("AmneziaVPN not supporting selected protocol on this device. Select another protocol."));

View file

@ -16,6 +16,9 @@ class VpnLogic : public PageLogicBase
AUTO_PROPERTY(QString, labelStateText)
AUTO_PROPERTY(QString, labelCurrentServer)
AUTO_PROPERTY(QString, labelCurrentService)
AUTO_PROPERTY(QString, labelCurrentDns)
AUTO_PROPERTY(bool, amneziaDnsEnabled)
AUTO_PROPERTY(bool, pushButtonConnectEnabled)
AUTO_PROPERTY(bool, pushButtonConnectVisible)
AUTO_PROPERTY(bool, widgetVpnModeEnabled)
@ -24,6 +27,8 @@ class VpnLogic : public PageLogicBase
AUTO_PROPERTY(QString, labelErrorText)
AUTO_PROPERTY(QString, labelVersionText)
AUTO_PROPERTY(bool, isCustomRoutesSupported)
AUTO_PROPERTY(bool, radioButtonVpnModeAllSitesChecked)
AUTO_PROPERTY(bool, radioButtonVpnModeForwardSitesChecked)
AUTO_PROPERTY(bool, radioButtonVpnModeExceptSitesChecked)

View file

@ -2,6 +2,7 @@
#include <QTimer>
#include <QProcess>
#include <QStorageInfo>
#include <QStandardPaths>
#include "OtherProtocolsLogic.h"
#include "core/servercontroller.h"
@ -17,7 +18,9 @@ using namespace amnezia;
using namespace PageEnumNS;
OtherProtocolsLogic::OtherProtocolsLogic(UiLogic *logic, QObject *parent):
PageProtocolLogicBase(logic, parent)
PageProtocolLogicBase(logic, parent),
m_checkBoxSftpRestoreChecked{false}
{
}
@ -41,17 +44,12 @@ void OtherProtocolsLogic::updateProtocolPage(const QJsonObject &config, DockerCo
set_labelTftpPortText(config.value(config_key::port).toString());
set_labelTorWebSiteAddressText(config.value(config_key::site).toString());
set_pushButtonSftpMountEnabled(true);
}
//QJsonObject OtherProtocolsLogic::getProtocolConfigFromPage(QJsonObject oldConfig)
//{
//}
void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked()
{
#ifdef Q_OS_WINDOWS
QString OtherProtocolsLogic::getNextDriverLetter() const
{
QProcess drivesProc;
drivesProc.start("wmic logicaldisk get caption");
drivesProc.waitForFinished();
@ -68,53 +66,93 @@ void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked()
if (letter == "C:") {
// set err info
qDebug() << "Can't find free drive letter";
return;
return "";
}
return letter;
}
#endif
//QJsonObject OtherProtocolsLogic::getProtocolConfigFromPage(QJsonObject oldConfig)
//{
//}
void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked()
{
QString mountPath;
QString cmd;
QString host = m_settings.serverCredentials(uiLogic()->selectedServerIndex).hostName;
#ifdef Q_OS_WINDOWS
mountPath = getNextDriverLetter() + ":";
// QString cmd = QString("net use \\\\sshfs\\%1@x.x.x.x!%2 /USER:%1 %3")
// .arg(labelTftpUserNameText())
// .arg(labelTftpPortText())
// .arg(labelTftpPasswordText());
cmd = "C:\\Program Files\\SSHFS-Win\\bin\\sshfs.exe";
#elif defined AMNEZIA_DESKTOP
mountPath = QString("%1/sftp:%2:%3")
.arg(QStandardPaths::writableLocation(QStandardPaths::HomeLocation))
.arg(host)
.arg(labelTftpPortText());
QDir dir(mountPath);
if (!dir.exists()){
dir.mkpath(mountPath);
}
cmd = "/usr/local/bin/sshfs";
#endif
#ifdef AMNEZIA_DESKTOP
set_pushButtonSftpMountEnabled(false);
QProcess *p = new QProcess;
m_sftpMountProcesses.append(p);
p->setProcessChannelMode(QProcess::MergedChannels);
connect(p, &QProcess::readyRead, this, [this, p, letter](){
connect(p, &QProcess::readyRead, this, [this, p, mountPath](){
QString s = p->readAll();
if (s.contains("The service sshfs has been started")) {
QDesktopServices::openUrl(QUrl("file:///" + letter + ":"));
QDesktopServices::openUrl(QUrl("file:///" + mountPath));
set_pushButtonSftpMountEnabled(true);
}
qDebug() << s;
});
// QString cmd = QString("net use \\\\sshfs\\%1@51.77.32.168!%2 /USER:%1 %3")
// .arg(labelTftpUserNameText())
// .arg(labelTftpPortText())
// .arg(labelTftpPasswordText());
p->setProgram("C:\\Program Files\\SSHFS-Win\\bin\\sshfs.exe");
QString host = m_settings.serverCredentials(uiLogic()->selectedServerIndex).hostName;
p->setProgram(cmd);
QString args = QString(
"%1@%2:/ %3: "
"%1@%2:/ %3 "
"-o port=%4 "
"-f "
"-o reconnect"
"-orellinks "
"-ofstypename=SSHFS "
"-o reconnect "
"-o rellinks "
"-o fstypename=SSHFS "
"-o ssh_command=/usr/bin/ssh.exe "
"-oUserKnownHostsFile=/dev/null "
"-oStrictHostKeyChecking=no "
"-o UserKnownHostsFile=/dev/null "
"-o StrictHostKeyChecking=no "
"-o password_stdin")
.arg(labelTftpUserNameText())
.arg(host)
.arg(letter)
.arg(mountPath)
.arg(labelTftpPortText());
p->setNativeArguments(args);
// args.replace("\n", " ");
// args.replace("\r", " ");
//#ifndef Q_OS_WIN
// args.replace("reconnect-orellinks", "");
//#endif
p->setArguments(args.split(" ", QString::SkipEmptyParts));
p->start();
p->waitForStarted(50);
if (p->state() != QProcess::Running) {
qDebug() << "onPushButtonSftpMountDriveClicked process not started";
qDebug() << args;
}
else {
p->write((labelTftpPasswordText() + "\n").toUtf8());
@ -123,7 +161,6 @@ void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked()
//qDebug().noquote() << "onPushButtonSftpMountDriveClicked" << args;
set_pushButtonSftpMountEnabled(true);
#endif
}

View file

@ -34,9 +34,13 @@ private:
Settings m_settings;
UiLogic *m_uiLogic;
#ifdef Q_OS_WINDOWS
#ifdef AMNEZIA_DESKTOP
QList <QProcess *> m_sftpMountProcesses;
#endif
#ifdef Q_OS_WINDOWS
QString getNextDriverLetter() const;
#endif
};
#endif // OTHER_PROTOCOLS_LOGIC_H

View file

@ -3,11 +3,13 @@ import QtQuick.Controls 2.12
CheckBox {
id: root
property int imageWidth : 20
property int imageHeight : 20
indicator: Image {
// y: 5
id: indicator
anchors.verticalCenter: root.verticalCenter
height: 20
width: 20
height: imageHeight
width: imageWidth
source: root.checked ? "qrc:/images/controls/check_on.png"
: "qrc:/images/controls/check_off.png"
}

View file

@ -28,7 +28,7 @@ RadioButton {
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
color: "#181922"
color: enabled ? "#181922" : "#686972"
verticalAlignment: Text.AlignVCenter
leftPadding: root.indicator.width + root.spacing
}

View file

@ -0,0 +1,17 @@
import QtQuick 2.12
LabelType {
id: label_connection_code
width: parent.width - 60
x: 30
font.pixelSize: 14
textFormat: Text.RichText
onLinkActivated: Qt.openUrlExternally(link)
MouseArea {
anchors.fill: parent
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.NoButton
}
}

View file

@ -8,10 +8,13 @@ BasicButtonType {
background: Item {}
contentItem: Item {
anchors.fill: parent
Image {
source: root.icon.source
SvgImageType {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
svg.source: root.icon.source
color: "#100A44"
width: 25
height: 25
}
Text {
id: textItem

View file

@ -0,0 +1,16 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import "."
BasicButtonType {
id: root
icon.color: "#181922"
background: Item {}
contentItem: SvgImageType {
svg.source: icon.source
color: icon.color
anchors.fill: parent
anchors.margins: parent.containsMouse ? 0 : 1
}
}

View file

@ -0,0 +1,23 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtGraphicalEffects 1.15
Item {
id: root
property color color: "#181922"
property alias svg: image
Image {
anchors.fill: parent
id: image
sourceSize: Qt.size(root.width, root.height)
antialiasing: true
visible: false
}
ColorOverlay {
anchors.fill: image
source: image
color: root.color
}
}

View file

@ -0,0 +1,90 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import PageEnum 1.0
import "./"
import "../Controls"
import "../Config"
PageBase {
id: root
page: PageEnum.About
BackButton {
id: back_from_start
}
Caption {
id: caption
font.pixelSize: 22
text: qsTr("About Amnezia")
}
RichLabelType {
id: label_about
anchors.top: caption.bottom
text: qsTr("AmneziaVPN is opensource software, it's free forever. Our goal is to make the best VPN client in the world.
<ul>
<li>Sources on <a href=\"https://github.com/amnezia-vpn/desktop-client\">GitHub</a></li>
<li><a href=\"https://amnezia.org/\">Web Site</a></li>
<li><a href=\"https://t.me/amnezia_vpn_en\">Telegram group</a></li>
<li><a href=\"https://signal.group/#CjQKIB2gUf8QH_IXnOJMGQWMDjYz9cNfmRQipGWLFiIgc4MwEhAKBONrSiWHvoUFbbD0xwdh\">Signal group</a></li>
</ul>
")
}
Caption {
id: caption2
anchors.topMargin: 20
font.pixelSize: 22
text: qsTr("Support")
anchors.top: label_about.bottom
}
RichLabelType {
id: label_support
anchors.top: caption2.bottom
text: qsTr("Have questions? You can get support by:
<ul>
<li><a href=\"https://t.me/amnezia_vpn_en\">Telegram group</a> (preferred way)</li>
<li>Create issue on <a href=\"https://github.com/amnezia-vpn/desktop-client/issues\">GitHub</a></li>
<li>Email to: <a href=\"support@amnezia.org\">support@amnezia.org</a></li>
</ul>")
}
Caption {
id: caption3
anchors.topMargin: 20
font.pixelSize: 22
text: qsTr("Donate")
width: undefined
anchors.top: label_support.bottom
}
LabelType {
anchors.bottom: caption3.bottom
anchors.left: caption3.right
anchors.leftMargin: 5
font.pixelSize: 24
text: "♥"
color: "red"
}
RichLabelType {
id: label_donate
anchors.top: caption3.bottom
text: qsTr("Please support Amnezia project by donation, we really need it now more than ever.
<ul>
<li>By credit card on <a href=\"https://www.patreon.com/amneziavpn\">Patreon</a> (starting from $1)</li>
<li>Send some coins to addresses listed <a href=\"https://github.com/amnezia-vpn/desktop-client/blob/master/README.md\">on GitHub page</a></li>
</ul>
")
}
Logo {
id: logo
anchors.bottom: parent.bottom
}
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@ -14,75 +15,127 @@ PageBase {
id: back
}
Caption {
id: caption
text: qsTr("Application Settings")
}
CheckBoxType {
x: 30
y: 140
width: 211
height: 31
text: qsTr("Auto connect")
checked: AppSettingsLogic.checkBoxAutoConnectChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxAutoConnectChecked = checked
AppSettingsLogic.onCheckBoxAutoconnectToggled(checked)
}
}
CheckBoxType {
x: 30
y: 100
width: 211
height: 31
text: qsTr("Auto start")
checked: AppSettingsLogic.checkBoxAutostartChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxAutostartChecked = checked
AppSettingsLogic.onCheckBoxAutostartToggled(checked)
}
}
CheckBoxType {
x: 30
y: 180
width: 211
height: 31
text: qsTr("Start minimized")
checked: AppSettingsLogic.checkBoxStartMinimizedChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxStartMinimizedChecked = checked
AppSettingsLogic.onCheckBoxStartMinimizedToggled(checked)
}
}
LabelType {
x: 30
y: 240
width: 281
height: 21
text: AppSettingsLogic.labelVersionText
}
BlueButtonType {
x: 30
y: 280
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 40
height: 41
text: qsTr("Check for updates")
onClicked: {
Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
BlueButtonType {
x: 30
y: 340
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 40
height: 41
text: qsTr("Open logs folder")
onClicked: {
AppSettingsLogic.onPushButtonOpenLogsClicked()
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: logo.top
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
CheckBoxType {
Layout.fillWidth: true
text: qsTr("Auto connect")
checked: AppSettingsLogic.checkBoxAutoConnectChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxAutoConnectChecked = checked
AppSettingsLogic.onCheckBoxAutoconnectToggled(checked)
}
}
CheckBoxType {
Layout.fillWidth: true
text: qsTr("Auto start")
checked: AppSettingsLogic.checkBoxAutostartChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxAutostartChecked = checked
AppSettingsLogic.onCheckBoxAutostartToggled(checked)
}
}
CheckBoxType {
Layout.fillWidth: true
text: qsTr("Start minimized")
checked: AppSettingsLogic.checkBoxStartMinimizedChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxStartMinimizedChecked = checked
AppSettingsLogic.onCheckBoxStartMinimizedToggled(checked)
}
}
LabelType {
Layout.fillWidth: true
Layout.topMargin: 15
text: AppSettingsLogic.labelVersionText
}
BlueButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 41
text: qsTr("Check for updates")
onClicked: {
Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
CheckBoxType {
Layout.fillWidth: true
Layout.topMargin: 15
text: qsTr("Keep logs")
checked: AppSettingsLogic.checkBoxSaveLogsChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxSaveLogsChecked = checked
AppSettingsLogic.onCheckBoxSaveLogsCheckedToggled(checked)
}
}
BlueButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 41
text: qsTr("Open logs folder")
onClicked: {
AppSettingsLogic.onPushButtonOpenLogsClicked()
}
}
BlueButtonType {
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
text: qsTr("Export logs")
onClicked: {
AppSettingsLogic.onPushButtonExportLogsClicked()
}
}
BlueButtonType {
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
property string start_text: qsTr("Clear logs")
property string end_text: qsTr("Cleared")
text: start_text
Timer {
id: timer
interval: 1000; running: false; repeat: false
onTriggered: parent.text = parent.start_text
}
onClicked: {
text = end_text
timer.running = true
AppSettingsLogic.onPushButtonClearLogsClicked()
}
}
}
}
Logo {
id: logo
anchors.bottom: parent.bottom
}
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtGraphicalEffects 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@ -31,9 +32,9 @@ PageBase {
anchors.top: l1.bottom
anchors.topMargin: GC.isMobile() ? 0: 15
x: 30
width: parent.width - 40
width: parent.width - 80
height: GC.isMobile() ? 0: 30
icon.source: "qrc:/images/settings.png"
icon.source: "qrc:/images/svg/settings_black_24dp.svg"
text: qsTr("App settings")
onClicked: {
UiLogic.goToPage(PageEnum.AppSettings)
@ -57,7 +58,7 @@ PageBase {
anchors.topMargin: 15
width: parent.width - 40
height: 30
icon.source: "qrc:/images/settings.png"
icon.source: "qrc:/images/svg/settings_suggest_black_24dp.svg"
text: qsTr("Network settings")
onClicked: {
UiLogic.goToPage(PageEnum.NetworkSettings)
@ -81,7 +82,7 @@ PageBase {
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/server_settings.png"
icon.source: "qrc:/images/svg/vpn_key_black_24dp.svg"
text: qsTr("Server Settings")
onClicked: {
GeneralSettingsLogic.onPushButtonGeneralSettingsServerSettingsClicked()
@ -105,7 +106,7 @@ PageBase {
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/share.png"
icon.source: "qrc:/images/svg/share_black_24dp.svg"
text: qsTr("Share connection")
enabled: GeneralSettingsLogic.pushButtonGeneralSettingsShareConnectionEnable
onClicked: {
@ -130,7 +131,7 @@ PageBase {
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/server_settings.png"
icon.source: "qrc:/images/svg/format_list_bulleted_black_24dp.svg"
text: qsTr("Servers")
onClicked: {
UiLogic.goToPage(PageEnum.ServersList)
@ -154,7 +155,7 @@ PageBase {
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/plus.png"
icon.source: "qrc:/images/svg/control_point_black_24dp.svg"
text: qsTr("Add server")
onClicked: {
UiLogic.goToPage(PageEnum.Start)
@ -178,7 +179,7 @@ PageBase {
anchors.bottomMargin: 20
width: 330
height: 30
icon.source: "qrc:/images/settings.png"
icon.source: "qrc:/images/svg/logout_black_24dp.svg"
text: qsTr("Exit")
onClicked: {
Qt.quit()

View file

@ -17,17 +17,42 @@ PageBase {
id: caption
text: qsTr("DNS Servers")
}
CheckBoxType {
id: cb_amnezia_dns
anchors.top: caption.bottom
x: 30
width: parent.width - 60
text: qsTr("Use AmneziaDNS service (recommended)")
checked: NetworkSettingsLogic.checkBoxUseAmneziaDnsChecked
onCheckedChanged: {
NetworkSettingsLogic.checkBoxUseAmneziaDnsChecked = checked
NetworkSettingsLogic.onCheckBoxUseAmneziaDnsToggled(checked)
UiLogic.onUpdateAllPages()
}
}
LabelType {
id: lb_amnezia_dns
x: 30
anchors.top: cb_amnezia_dns.bottom
width: parent.width - 60
text: qsTr("Use AmneziaDNS container on your server, when it installed.\n
Your AmneziaDNS server available only when it installed and VPN connected, it has internal IP address 172.29.172.254\n
If AmneziaDNS service is not installed on the same server, or this option is unchecked, the following DNS servers will be used:")
}
LabelType {
id: l1
x: 40
anchors.top: caption.bottom
width: parent.width - 40
x: 30
anchors.top: lb_amnezia_dns.bottom
width: parent.width - 30
height: 21
text: qsTr("Primary DNS server")
}
TextFieldType {
id: dns1
x: 40
x: 30
anchors.top: l1.bottom
width: parent.width - 90
height: 40
@ -35,36 +60,38 @@ PageBase {
onEditingFinished: {
NetworkSettingsLogic.lineEditDns1Text = text
NetworkSettingsLogic.onLineEditDns1EditFinished(text)
UiLogic.onUpdateAllPages()
}
validator: RegExpValidator {
regExp: NetworkSettingsLogic.ipAddressRegex
}
}
ImageButtonType {
SvgButtonType {
id: resetDNS1
anchors. left: dns1.right
anchors.leftMargin: 10
anchors.verticalCenter: dns1.verticalCenter
width: 24
height: 24
icon.source: "qrc:/images/reload.png"
icon.source: "qrc:/images/svg/refresh_black_24dp.svg"
onClicked: {
NetworkSettingsLogic.onPushButtonResetDns1Clicked()
UiLogic.onUpdateAllPages()
}
}
LabelType {
id: l2
x: 40
x: 30
anchors.top: dns1.bottom
anchors.topMargin: 20
width: parent.width - 40
width: parent.width - 60
height: 21
text: qsTr("Secondray DNS server")
}
TextFieldType {
id: dns2
x: 40
x: 30
anchors.top: l2.bottom
width: parent.width - 90
height: 40
@ -72,21 +99,23 @@ PageBase {
onEditingFinished: {
NetworkSettingsLogic.lineEditDns2Text = text
NetworkSettingsLogic.onLineEditDns2EditFinished(text)
UiLogic.onUpdateAllPages()
}
validator: RegExpValidator {
regExp: NetworkSettingsLogic.ipAddressRegex
}
}
ImageButtonType {
SvgButtonType {
id: resetDNS2
anchors. left: dns2.right
anchors.leftMargin: 10
anchors.verticalCenter: dns2.verticalCenter
width: 24
height: 24
icon.source: "qrc:/images/reload.png"
icon.source: "qrc:/images/svg/refresh_black_24dp.svg"
onClicked: {
NetworkSettingsLogic.onPushButtonResetDns2Clicked()
UiLogic.onUpdateAllPages()
}
}

View file

@ -59,6 +59,10 @@ PageBase {
SelectContainer {
id: container_selector
onAboutToHide: {
pageLoader.focus = true
}
onContainerSelected: {
var containerProto = ContainerProps.defaultProtocol(c_index)

View file

@ -41,6 +41,10 @@ PageBase {
SelectContainer {
id: container_selector
onAboutToHide: {
pageLoader.focus = true
}
onContainerSelected: {
var containerProto = ContainerProps.defaultProtocol(c_index)

View file

@ -19,17 +19,20 @@ PageBase {
text: qsTr("Servers list")
width: undefined
}
ImageButtonType {
SvgButtonType {
anchors.bottom: caption.bottom
anchors.leftMargin: 10
anchors.left: caption.right
width: 24
height: 24
icon.source: "qrc:/images/plus.png"
icon.source: "qrc:/images/svg/control_point_black_24dp.svg"
onClicked: {
UiLogic.goToPage(PageEnum.Start);
}
}
ListView {
id: listWidget_servers
x: 20
@ -124,13 +127,13 @@ PageBase {
checked: is_default
enabled: !is_default
}
ImageButtonType {
SvgButtonType {
id: pushButtonSetting
x: parent.width - 70
y: 15
width: 30
height: 30
icon.source: "qrc:/images/settings.png"
icon.source: "qrc:/images/svg/settings_black_24dp.svg"
opacity: 0
OpacityAnimator {

View file

@ -28,7 +28,16 @@ PageBase {
horizontalAlignment: Text.AlignHCenter
text: ServerSettingsLogic.labelCurrentVpnProtocolText
}
LabelType {
// LabelType {
// anchors.horizontalCenter: parent.horizontalCenter
// y: 120
// width: 341
// height: 31
// font.pixelSize: 20
// horizontalAlignment: Text.AlignHCenter
// text: ServerSettingsLogic.labelServerText
// }
TextFieldType {
anchors.horizontalCenter: parent.horizontalCenter
y: 120
width: 341
@ -36,7 +45,10 @@ PageBase {
font.pixelSize: 20
horizontalAlignment: Text.AlignHCenter
text: ServerSettingsLogic.labelServerText
readOnly: true
background: Item {}
}
LabelType {
anchors.horizontalCenter: parent.horizontalCenter
y: 530

View file

@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@ -14,93 +15,99 @@ PageBase {
id: back_from_setup_wizard
}
Caption {
id: caption
text: qsTr("Setup your server to use VPN")
}
Item {
x: 10
y: 70
width: 361
height: 561
LabelType {
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignTop
text: qsTr("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.")
wrapMode: Text.Wrap
x: 30
y: 40
width: 321
height: 121
}
LabelType {
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignTop
text: qsTr("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.")
wrapMode: Text.Wrap
x: 30
y: 210
width: 321
height: 121
}
LabelType {
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignTop
text: qsTr("I just want to improve my privacy in internet.")
wrapMode: Text.Wrap
x: 30
y: 360
width: 321
height: 121
}
BlueButtonType {
anchors.horizontalCenter: parent.horizontalCenter
y: 490
width: 321
height: 40
text: qsTr("Next")
onClicked: {
if (radioButton_setup_wizard_high.checked) {
UiLogic.goToPage(PageEnum.WizardHigh);
} else if (radioButton_setup_wizard_medium.checked) {
UiLogic.goToPage(PageEnum.WizardMedium);
} else if (radioButton_setup_wizard_low.checked) {
UiLogic.goToPage(PageEnum.WizardLow);
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
RadioButtonType {
id: radioButton_setup_wizard_high
Layout.fillWidth: true
text: qsTr("High censorship level")
checked: WizardLogic.radioButtonHighChecked
onCheckedChanged: {
WizardLogic.radioButtonHighChecked = checked
}
}
}
RadioButtonType {
id: radioButton_setup_wizard_high
x: 10
y: 10
width: 331
height: 25
text: qsTr("High censorship level")
checked: WizardLogic.radioButtonHighChecked
onCheckedChanged: {
WizardLogic.radioButtonHighChecked = checked
LabelType {
Layout.fillWidth: true
Layout.leftMargin: 25
verticalAlignment: Text.AlignTop
text: qsTr("I'm living in a country with a high censorship level. Many of the foreign websites and VPNs are blocked by my government. I want to setup a reliable VPN, which can not be detected by my internet provider and my government.
OpenVPN and ShadowSocks over Cloak (VPN obfuscation) profiles will be installed.\n")
}
}
RadioButtonType {
id: radioButton_setup_wizard_medium
x: 10
y: 330
width: 331
height: 25
text: qsTr("Low censorship level")
checked: WizardLogic.radioButtonLowChecked
onCheckedChanged: {
WizardLogic.radioButtonLowChecked = checked
RadioButtonType {
id: radioButton_setup_wizard_medium
Layout.fillWidth: true
text: qsTr("Medium censorship level")
checked: WizardLogic.radioButtonMediumChecked
onCheckedChanged: {
WizardLogic.radioButtonMediumChecked = checked
}
}
}
RadioButtonType {
id: radioButton_setup_wizard_low
x: 10
y: 180
width: 331
height: 25
text: qsTr("Medium censorship level")
checked: WizardLogic.radioButtonMediumChecked
onCheckedChanged: {
WizardLogic.radioButtonMediumChecked = checked
LabelType {
Layout.fillWidth: true
Layout.leftMargin: 25
verticalAlignment: Text.AlignTop
text: qsTr("I'm living in a country with a medium censorship level. Some websites are blocked by my government, but VPNs are not blocked at all. I want to setup a flexible solution.
OpenVPN over ShadowSocks profile will be installed.\n")
}
RadioButtonType {
id: radioButton_setup_wizard_low
Layout.fillWidth: true
text: qsTr("Low censorship level")
checked: WizardLogic.radioButtonLowChecked
onCheckedChanged: {
WizardLogic.radioButtonLowChecked = checked
}
}
LabelType {
Layout.fillWidth: true
Layout.leftMargin: 25
verticalAlignment: Text.AlignTop
text: qsTr("I want to improve my privacy on the internet.
OpenVPN profile will be installed.\n")
}
BlueButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 41
text: qsTr("Next")
onClicked: {
if (radioButton_setup_wizard_high.checked) {
UiLogic.goToPage(PageEnum.WizardHigh, false);
} else if (radioButton_setup_wizard_medium.checked) {
UiLogic.goToPage(PageEnum.WizardMedium, false);
} else if (radioButton_setup_wizard_low.checked) {
UiLogic.goToPage(PageEnum.WizardLow, false);
}
}
}
}
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@ -14,69 +15,90 @@ PageBase {
id: back_from_setup_wizard
}
Caption {
id: caption
text: qsTr("Setup Wizard")
}
Item {
x: 10
y: 70
width: 361
height: 561
LabelType {
x: 30
y: 10
width: 321
height: 321
text: qsTr("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.\n\nYou SHOULD set this web site address to some foreign web site which is updatesnot blocked by your internet provider. Other words you need to type below some foreign web site address which is accessible without VPN.\n\nPlease note, this protocol still does not support export connection profile to mobile devices. Keep for updates.")
}
LabelType {
x: 30
y: 400
width: 321
height: 71
text: qsTr("OpenVPN over Cloak (VPN obfuscation) profile will be installed")
}
LabelType {
x: 30
y: 330
width: 291
height: 21
text: qsTr("Type web site address for mask")
}
TextFieldType {
id: website_masking
x: 30
y: 360
width: 301
height: 41
text: WizardLogic.lineEditHighWebsiteMaskingText
onEditingFinished: {
let _text = website_masking.text
_text.replace("http://", "");
_text.replace("https://", "");
if (!_text) {
return
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelType {
Layout.fillWidth: true
verticalAlignment: Text.AlignTop
text: qsTr("AmneziaVPN will install a VPN protocol which is not visible to your internet provider and government firewall. Your VPN connection will be seen by your internet provider as regular web traffic to a particular website.
You SHOULD set this website address to some foreign website which is not blocked by your internet provider. In other words, you need to type some foreign website address which is accessible to you without a VPN.")
}
LabelType {
Layout.fillWidth: true
Layout.topMargin: 15
verticalAlignment: Text.AlignTop
text: qsTr("Type another web site address for masking or keep it by default. Your internet provider will think you working on this web site when you connected to VPN.")
}
TextFieldType {
id: website_masking
Layout.fillWidth: true
text: WizardLogic.lineEditHighWebsiteMaskingText
onEditingFinished: {
let _text = website_masking.text
_text.replace("http://", "");
_text.replace("https://", "");
if (!_text) {
return
}
_text = _text.split("/").first();
WizardLogic.lineEditHighWebsiteMaskingText = _text
}
_text = _text.split("/").first();
WizardLogic.lineEditHighWebsiteMaskingText = _text
}
onAccepted: {
next_button.clicked()
}
}
BlueButtonType {
id: next_button
x: 30
y: 490
width: 301
height: 40
text: qsTr("Next")
onClicked: {
let domain = website_masking.text;
if (!domain || !domain.includes(".")) {
return
onAccepted: {
next_button.clicked()
}
UiLogic.goToPage(PageEnum.WizardVpnMode)
}
LabelType {
Layout.fillWidth: true
Layout.topMargin: 15
verticalAlignment: Text.AlignTop
text: qsTr("OpenVPN and ShadowSocks over Cloak (VPN obfuscation) profiles will be installed.
This protocol support exporting connection profiles to mobile devices by exporting ShadowSocks and Cloak configs (you should launch the 3rd party open source VPN client - ShadowSocks VPN and install Cloak plugin).")
}
BlueButtonType {
id: next_button
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
text: qsTr("Next")
onClicked: {
let domain = website_masking.text;
if (!domain || !domain.includes(".")) {
return
}
UiLogic.goToPage(PageEnum.WizardVpnMode, false)
}
}
}
}
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@ -14,38 +15,56 @@ PageBase {
id: back_from_setup_wizard
}
Caption {
id: caption
text: qsTr("Setup Wizard")
}
Item {
x: 10
y: 70
width: 361
height: 561
LabelType {
x: 30
y: 10
width: 321
height: 341
verticalAlignment: Text.AlignTop
text: qsTr('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.')
}
LabelType {
x: 30
y: 400
width: 321
height: 71
text: qsTr('OpenVPN profile will be installed')
verticalAlignment: Text.AlignBottom
}
BlueButtonType {
id: next_button
x: 30
y: 490
width: 301
height: 40
text: qsTr("Start configuring")
onClicked: {
WizardLogic.onPushButtonLowFinishClicked()
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelType {
Layout.fillWidth: true
verticalAlignment: Text.AlignTop
text: qsTr('AmneziaVPN will install the OpenVPN protocol with public/private key pairs generated on both server and client sides.
You can also configure the connection on your mobile device by copying the exported ".ovpn" file to your device, and setting up the official OpenVPN client.
We recommend not to use messaging applications for sending the connection profile - it contains VPN private keys.')
}
LabelType {
Layout.fillWidth: true
Layout.topMargin: 15
text: qsTr('OpenVPN profile will be installed')
verticalAlignment: Text.AlignBottom
}
BlueButtonType {
id: next_button
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
text: qsTr("Start configuring")
onClicked: {
WizardLogic.onPushButtonLowFinishClicked()
}
}
}
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@ -14,38 +15,51 @@ PageBase {
id: back_from_setup_wizard
}
Caption {
id: caption
text: qsTr("Setup Wizard")
}
Item {
x: 10
y: 70
width: 361
height: 561
LabelType {
x: 30
y: 10
width: 321
height: 341
verticalAlignment: Text.AlignTop
text: qsTr('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".\n\nThis protocol support export connection profile to mobile devices using QR code (you should launch 3rd party opensource VPN client - ShadowSocks VPN).')
}
LabelType {
x: 30
y: 400
width: 321
height: 71
text: qsTr('OpenVPN over ShadowSocks profile will be installed')
verticalAlignment: Text.AlignBottom
}
BlueButtonType {
id: next_button
x: 30
y: 490
width: 301
height: 40
text: qsTr("Next")
onClicked: {
UiLogic.goToPage(PageEnum.WizardVpnMode)
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelType {
Layout.fillWidth: true
verticalAlignment: Text.AlignTop
text: qsTr('AmneziaVPN will install a 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 "VPN masking".\n\nThis protocol supports exporting connection profiles to mobile devices by using QR codes (you should launch the 3rd party open source VPN client - ShadowSocks VPN).')
}
LabelType {
Layout.fillWidth: true
Layout.topMargin: 15
text: qsTr('OpenVPN over ShadowSocks profile will be installed')
}
BlueButtonType {
id: next_button
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
text: qsTr("Next")
onClicked: {
UiLogic.goToPage(PageEnum.WizardVpnMode, false)
}
}
}
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@ -14,40 +15,57 @@ PageBase {
id: back_from_setup_wizard
}
Caption {
id: caption
text: qsTr("Setup Wizard")
}
Item {
x: 10
y: 70
width: 361
height: 561
CheckBoxType {
x: 30
y: 350
width: 301
height: 71
text: qsTr('Turn on mode "VPN for selected sites"')
checked: WizardLogic.checkBoxVpnModeChecked
onCheckedChanged: {
WizardLogic.checkBoxVpnModeChecked = checked
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelType {
Layout.fillWidth: true
verticalAlignment: Text.AlignTop
text: qsTr('Optional.\n
You can 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.\n\nPlease 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.')
}
}
LabelType {
x: 30
y: 10
width: 321
height: 341
text: qsTr('Optional.\n\nWe 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.\n\nPlease 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.')
}
BlueButtonType {
id: vpn_mode_finish
x: 30
y: 490
width: 301
height: 40
text: qsTr("Start configuring")
onClicked: {
WizardLogic.onPushButtonVpnModeFinishClicked()
CheckBoxType {
Layout.fillWidth: true
text: qsTr('Turn on mode "VPN for selected sites"')
checked: WizardLogic.checkBoxVpnModeChecked
onCheckedChanged: {
WizardLogic.checkBoxVpnModeChecked = checked
}
}
BlueButtonType {
id: vpn_mode_finish
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
text: qsTr("Start configuring")
onClicked: {
WizardLogic.onPushButtonVpnModeFinishClicked()
}
}
}
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQml.Models 2.15
import Qt.labs.platform 1.0
import QtQuick.Dialogs 1.0
import PageEnum 1.0
@ -12,6 +13,8 @@ PageBase {
page: PageEnum.Sites
logic: SitesLogic
property int lastIndex: 0
BackButton {
id: back
}
@ -104,20 +107,32 @@ PageBase {
}
}
ListView {
id: tb
x: 20
anchors.top: sites_add.bottom
anchors.topMargin: 10
width: parent.width - 40
anchors.bottom: sites_delete.top
anchors.bottomMargin: 10
spacing: 1
clip: true
property int currentRow: -1
DelegateModel {
id: visualModel
model: SitesLogic.tableViewSitesModel
delegate: Item {
groups: [
DelegateModelGroup {
id : delegateModelGroup
name: "multiSelect"
function removeAll(){
var count = delegateModelGroup.count;
if (count !== 0){
delegateModelGroup.remove(0,count);
}
}
function selectAll(){
for(var i = 0; i < visualModel.count; i++){
visualModel.items.get(i).inMultiSelect = true
}
}
}
]
delegate: Rectangle {
id: item
focus: true
height: 25
width: root.width
color: item.DelegateModel.inMultiSelect ? '#63b4fb' : 'transparent'
implicitWidth: 170 * 2
implicitHeight: 30
Item {
@ -171,23 +186,130 @@ PageBase {
}
MouseArea {
anchors.fill: parent
onClicked: {
tb.currentRow = index
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked:{
tb.focus = true
if(mouse.button === Qt.RightButton){
//copyPasteMenu.popup()
console.log("RightButton")
}
if(mouse.button === Qt.LeftButton){
switch(mouse.modifiers){
case Qt.ControlModifier :
item.DelegateModel.inMultiSelect = !item.DelegateModel.inMultiSelect
break;
case Qt.ShiftModifier :
delegateModelGroup.removeAll();
var start = lastIndex <= index? lastIndex: index;
var end = lastIndex >= index? lastIndex: index;
for(var i = start;i <= end;i++){
visualModel.items.get(i).inMultiSelect = true
}
break;
default:
delegateModelGroup.removeAll();
item.DelegateModel.inMultiSelect = true
lastIndex = index
break;
}
}
}
}
}
}
ListView {
id: tb
x: 20
anchors.top: sites_add.bottom
anchors.topMargin: 10
width: parent.width - 40
anchors.bottom: sites_delete.top
anchors.bottomMargin: 10
spacing: 1
clip: true
focus: true
activeFocusOnTab: true
keyNavigationEnabled: true
property int currentRow: -1
model: visualModel
Keys.onPressed: {
if (event.key === Qt.Key_PageUp) {
let idx = tb.indexAt(1, tb.contentY)
tb.positionViewAtIndex(idx-20, ListView.Beginning)
event.accepted = true
}
else if (event.key === Qt.Key_PageDown) {
let idx = tb.indexAt(1, tb.contentY)
tb.positionViewAtIndex(idx+20, ListView.Beginning)
event.accepted = true
}
else if (event.key === Qt.Key_Home) {
tb.positionViewAtBeginning()
event.accepted = true
}
else if (event.key === Qt.Key_End) {
tb.positionViewAtEnd()
event.accepted = true
}
else if (event.key === Qt.Key_Delete) {
let items = []
for(let i = 0; i < visualModel.count; i++){
if (visualModel.items.get(i).inMultiSelect) items.push(i)
}
SitesLogic.onPushButtonSitesDeleteClicked(items)
event.accepted = true
}
else if (event.key === Qt.Key_A) {
delegateModelGroup.selectAll()
event.accepted = true
}
}
}
BlueButtonType {
id: sites_delete
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.bottom: select_all.top
anchors.bottomMargin: 10
anchors.horizontalCenter: parent.horizontalCenter
height: 31
font.pixelSize: 16
text: qsTr("Delete selected")
onClicked: {
SitesLogic.onPushButtonSitesDeleteClicked(tb.currentRow)
let items = []
for(let i = 0; i < visualModel.count; i++){
if (visualModel.items.get(i).inMultiSelect) items.push(i)
}
SitesLogic.onPushButtonSitesDeleteClicked(items)
}
}
BlueButtonType {
id: select_all
anchors.bottom: sites_export.top
anchors.bottomMargin: 10
anchors.horizontalCenter: parent.horizontalCenter
height: 31
font.pixelSize: 16
text: qsTr("Select all")
onClicked: {
delegateModelGroup.selectAll()
}
}
BlueButtonType {
id: sites_export
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.horizontalCenter: parent.horizontalCenter
height: 31
font.pixelSize: 16
text: qsTr("Export all")
onClicked: {
SitesLogic.onPushButtonSitesExportClicked()
}
}
}

View file

@ -240,8 +240,7 @@ PageBase {
anchors.horizontalCenter: parent.horizontalCenter
height: 71
echoMode: TextInput.Password
font.pixelSize: 9
font.pixelSize: 10
verticalAlignment: Text.AlignTop
text: StartPageLogic.textEditSshKeyText
onEditingFinished: {
@ -264,6 +263,7 @@ PageBase {
id: new_sever_connect
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: new_server_ssh_key.bottom
anchors.topMargin: 10
text: StartPageLogic.pushButtonConnectText
visible: StartPageLogic.pushButtonConnectVisible

View file

@ -22,7 +22,7 @@ PageBase {
LabelType {
x: 10
y: 5
y: 10
width: 100
height: 21
text: VpnLogic.labelVersionText
@ -30,6 +30,33 @@ PageBase {
font.pixelSize: 12
}
BasicButtonType {
y: 10
anchors.horizontalCenter: parent.horizontalCenter
height: 21
background: Item {}
contentItem: Text {
anchors.fill: parent
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 18
font.underline: true
text: qsTr("Donate")
color: "#D4D4D4"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
onClicked: {
UiLogic.goToPage(PageEnum.About)
}
}
ImageButtonType {
x: parent.width - 40
y: 10
@ -108,7 +135,7 @@ PageBase {
Layout.alignment: Qt.AlignLeft
height: 21
background: Item {}
text: VpnLogic.labelCurrentServer
text: VpnLogic.labelCurrentServer + " →"
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
@ -129,14 +156,14 @@ PageBase {
LabelType {
Layout.alignment: Qt.AlignRight
height: 21
text: qsTr("Service") + ": "
text: qsTr("Proto") + ": "
}
BasicButtonType {
Layout.alignment: Qt.AlignLeft
height: 21
background: Item {}
text: VpnLogic.labelCurrentService
text: VpnLogic.labelCurrentService + " →"
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
@ -146,10 +173,46 @@ PageBase {
}
}
RowLayout {
id: layout3
anchors.top: layout2.bottom
anchors.topMargin: 5
anchors.horizontalCenter: parent.horizontalCenter
height: 21
LabelType {
Layout.alignment: Qt.AlignRight
height: 21
text: qsTr("DNS") + ": "
}
BasicButtonType {
Layout.alignment: Qt.AlignLeft
height: 21
implicitWidth: implicitContentWidth > root.width * 0.6 ? root.width * 0.6 : implicitContentWidth + leftPadding + rightPadding
background: Item {}
text: VpnLogic.labelCurrentDns + " →"
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
onClicked: {
UiLogic.goToPage(PageEnum.NetworkSettings)
}
}
SvgImageType {
svg.source: VpnLogic.amneziaDnsEnabled ? "qrc:/images/svg/gpp_good_black_24dp.svg" : "qrc:/images/svg/gpp_maybe_black_24dp.svg"
color: VpnLogic.amneziaDnsEnabled ? "#22aa33" : "orange"
width: 25
height: 25
}
}
LabelType {
id: error_text
anchors.top: layout2.bottom
anchors.top: layout3.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 20
width: parent.width - 20
@ -259,6 +322,7 @@ PageBase {
onClicked: VpnLogic.onRadioButtonVpnModeAllSitesClicked(true)
}
RadioButtonType {
enabled: VpnLogic.isCustomRoutesSupported
x: 0
y: 60
width: 341
@ -268,6 +332,7 @@ PageBase {
onClicked: VpnLogic.onRadioButtonVpnModeExceptSitesClicked(true)
}
RadioButtonType {
enabled: VpnLogic.isCustomRoutesSupported
x: 0
y: 30
width: 341

View file

@ -16,7 +16,7 @@ PageProtocolBase {
Caption {
id: caption
text: qsTr("SFTF settings")
text: qsTr("SFTP settings")
}
Rectangle {
@ -77,40 +77,42 @@ PageProtocolBase {
}
}
LabelType {
RichLabelType {
anchors.bottom: check_persist.top
anchors.bottomMargin: 10
width: parent.width - 60
x: 30
font.pixelSize: 14
textFormat: Text.RichText
MouseArea {
anchors.fill: parent
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.NoButton
}
// text: "In order to mount remote SFTP folder as local drive, perform following steps:
//- Install the latest version of WinFsp [https://github.com/billziss-gh/winfsp/releases/latest].
//- Install the latest version of SSHFS-Win. Choose the x64 or x86 installer according to your computer's architecture [https://github.com/billziss-gh/sshfs-win/releases]"
onLinkActivated: Qt.openUrlExternally(link)
text:"In order to mount remote SFTP folder as local drive, perform following steps:
readonly property string windows_text: "In order to mount remote SFTP folder as local drive, perform following steps:
<ul>
<li>Install the latest version of <a href=\"https://github.com/billziss-gh/winfsp/releases/latest\">WinFsp</a>.</li>
<li>Install the latest version of <a href=\"https://github.com/billziss-gh/sshfs-win/releases\">SSHFS-Win</a>. Choose the x64 or x86 installer according to your computer's architecture.</li>
</ul>"
readonly property string macos_text: "In order to mount remote SFTP folder as local folder, perform following steps:
<ul>
<li>Install the latest version of <a href=\"https://osxfuse.github.io/\">macFUSE</a>.</li>
<li>Install the latest version of <a href=\"https://osxfuse.github.io/\">SSHFS</a>.</li>
</ul>"
text: {
if (Qt.platform.os == "windows") return windows_text
else if (Qt.platform.os == "osx") return macos_text
else if (Qt.platform.os == "linux") return ""
else return ""
}
}
CheckBoxType {
id: check_persist
visible: false
anchors.bottom: pb_mount.top
anchors.bottomMargin: 10
x: 30
width: parent.width
height: 21
text: qsTr("Restore drive after restart")
text: qsTr("Restore drive when client starts")
checked: logic.checkBoxSftpRestoreChecked
onCheckedChanged: {
logic.checkBoxSftpRestoreChecked = checked
@ -122,6 +124,7 @@ PageProtocolBase {
BlueButtonType {
id: pb_mount
visible: GC.isDesktop()
enabled: logic.pushButtonSftpMountEnabled
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom

View file

@ -11,7 +11,6 @@ PageProtocolBase {
protocol: ProtocolEnum.ShadowSocks
logic: UiLogic.protocolLogic(protocol)
enabled: logic.pageEnabled
BackButton {
id: back
}

View file

@ -1,6 +1,7 @@
import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import QtQuick.Controls.Material 2.12
import PageEnum 1.0
import PageType 1.0
@ -8,6 +9,7 @@ import Qt.labs.platform 1.1
import Qt.labs.folderlistmodel 2.12
import QtQuick.Dialogs 1.1
import "./"
import "Controls"
import "Pages"
import "Pages/Protocols"
import "Pages/Share"
@ -22,6 +24,8 @@ Window {
visible: true
width: GC.screenWidth
height: GC.isDesktop() ? GC.screenHeight + titleBar.height : GC.screenHeight
minimumWidth: 360
minimumHeight: GC.isDesktop() ? 640 : 0
Keys.enabled: true
onClosing: {
console.debug("QML onClosing signal")
@ -38,7 +42,7 @@ Window {
else if (type === PageType.ShareProto) p_obj = sharePages[page]
else return
console.debug("QML gotoPage " + type + " " + page + " " + p_obj)
//console.debug("QML gotoPage " + type + " " + page + " " + p_obj)
if (pageLoader.depth > 0) {
pageLoader.currentItem.deactivated()
@ -118,7 +122,7 @@ Window {
focus: true
onCurrentItemChanged: {
console.debug("QML onCurrentItemChanged " + pageLoader.currentItem)
//console.debug("QML onCurrentItemChanged " + pageLoader.currentItem)
UiLogic.currentPageValue = currentItem.page
}
@ -213,15 +217,15 @@ Window {
Connections {
target: UiLogic
function onGoToPage(page, reset, slide) {
console.debug("Qml Connections onGoToPage " + page);
//console.debug("Qml Connections onGoToPage " + page);
root.gotoPage(PageType.Basic, page, reset, slide)
}
function onGoToProtocolPage(protocol, reset, slide) {
console.debug("Qml Connections onGoToProtocolPage " + protocol);
//console.debug("Qml Connections onGoToProtocolPage " + protocol);
root.gotoPage(PageType.Proto, protocol, reset, slide)
}
function onGoToShareProtocolPage(protocol, reset, slide) {
console.debug("Qml Connections onGoToShareProtocolPage " + protocol);
//console.debug("Qml Connections onGoToShareProtocolPage " + protocol);
root.gotoPage(PageType.ShareProto, protocol, reset, slide)
}
@ -249,6 +253,9 @@ Window {
root.raise()
root.requestActivate()
}
function onToggleLogPanel() {
drawer_log.visible = !drawer_log.visible
}
}
MessageDialog {
@ -275,4 +282,114 @@ Window {
text: UiLogic.dialogConnectErrorText
visible: false
}
Drawer {
id: drawer_log
z: -3
y: 0
x: 0
edge: Qt.BottomEdge
width: parent.width
height: parent.height * 0.85
modal: true
//interactive: activeFocus
onAboutToHide: {
pageLoader.focus = true
}
onAboutToShow: {
tfSshLog.focus = true
}
Item {
id: itemLog
anchors.fill: parent
Keys.onPressed: {
UiLogic.keyPressEvent(event.key)
event.accepted = true
}
RadioButtonType {
id: rbSshLog
focus: false
anchors.left: parent.left
anchors.leftMargin: 10
anchors.bottom: parent.bottom
anchors.bottomMargin: 2
height: 25
text: qsTr("Ssh log")
}
RadioButtonType {
id: rbAllLog
focus: false
checked: true
anchors.left: rbSshLog.right
anchors.bottom: rbSshLog.bottom
anchors.top: rbSshLog.top
height: rbSshLog.height
text: qsTr("App log")
}
CheckBoxType {
id: cbLogWrap
text: qsTr("Wrap words")
checked: true
anchors.right: parent.right
anchors.bottom: rbAllLog.bottom
anchors.top: rbAllLog.top
height: 15
imageHeight: 15
imageWidth: 15
onCheckedChanged: {
tfSshLog
}
}
TextAreaType {
id: tfSshLog
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: rbSshLog.top
flickableDirection: Flickable.AutoFlickIfNeeded
textArea.readOnly: true
textArea.selectByMouse: true
textArea.verticalAlignment: Text.AlignTop
textArea.text: {
if (!drawer_log.visible) return ""
else if (rbSshLog.checked ) return Debug.sshLog
else return Debug.allLog
}
textArea.wrapMode: cbLogWrap.checked ? TextEdit.WordWrap: TextEdit.NoWrap
Keys.onPressed: {
UiLogic.keyPressEvent(event.key)
event.accepted = true
}
textArea.onTextChanged: {
textArea.cursorPosition = textArea.length-1
}
MouseArea {
anchors.fill: parent
enabled: GC.isDesktop()
acceptedButtons: Qt.RightButton
onClicked: contextMenu.open()
}
ContextMenu {
id: contextMenu
textObj: tfSshLog.textArea
}
}
}
}
}

View file

@ -112,6 +112,7 @@ UiLogic::~UiLogic()
{
emit hide();
#ifdef AMNEZIA_DESKTOP
if (m_vpnConnection->connectionState() != VpnProtocol::VpnConnectionState::Disconnected) {
m_vpnConnection->disconnectFromVpn();
for (int i = 0; i < 50; i++) {
@ -122,6 +123,7 @@ UiLogic::~UiLogic()
}
}
}
#endif
m_vpnConnection->deleteLater();
m_vpnConnectionThread.quit();
@ -149,24 +151,6 @@ void UiLogic::initalizeUiLogic()
connect(m_notificationHandler, &NotificationHandler::connectRequested, vpnLogic(), &VpnLogic::onConnect);
connect(m_notificationHandler, &NotificationHandler::disconnectRequested, vpnLogic(), &VpnLogic::onDisconnect);
// 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
//emit goToPage(Page::Start, true, false);
if (m_settings.serversCount() > 0) {
if (m_settings.defaultServerIndex() < 0) m_settings.setDefaultServer(0);
emit goToPage(Page::Vpn, true, false);
@ -176,37 +160,9 @@ void UiLogic::initalizeUiLogic()
}
selectedServerIndex = m_settings.defaultServerIndex();
//goToPage(Page::ServerContainers, true, false);
//goToPage(Page::NewServerProtocols, true, false);
//onGotoProtocolPage(Proto::OpenVpn);
//ui->pushButton_general_settings_exit->hide();
qInfo().noquote() << QString("Started %1 version %2").arg(APPLICATION_NAME).arg(APP_VERSION);
qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName()).arg(QSysInfo::currentCpuArchitecture());
vpnLogic()->onConnectionStateChanged(VpnProtocol::Disconnected);
// 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);
}
QString UiLogic::getDialogConnectErrorText() const
@ -225,10 +181,13 @@ void UiLogic::setDialogConnectErrorText(const QString &dialogConnectErrorText)
void UiLogic::showOnStartup()
{
if (! m_settings.isStartMinimized()) {
show();
} else {
#if defined Q_OS_MACX
setDockIconVisible(false);
emit show();
}
else {
#ifdef Q_OS_WIN
emit hide();
#elif defined Q_OS_MACX
// TODO: fix: setDockIconVisible(false);
#endif
}
}
@ -257,6 +216,9 @@ void UiLogic::onUpdateAllPages()
void UiLogic::keyPressEvent(Qt::Key key)
{
switch (key) {
case Qt::Key_AsciiTilde:
case Qt::Key_QuoteLeft: emit toggleLogPanel();
break;
case Qt::Key_L: Debug::openLogsFolder();
break;
case Qt::Key_K: Debug::openServiceLogsFolder();
@ -302,7 +264,6 @@ void UiLogic::keyPressEvent(Qt::Key key)
// break;
// }
//if (! ui->stackedWidget_main->isAnimationRunning() && ui->stackedWidget_main->currentWidget()->isEnabled()) {
emit closePage();
//}
default:
@ -644,12 +605,14 @@ PageEnumNS::Page UiLogic::currentPage()
return static_cast<PageEnumNS::Page>(currentPageValue());
}
void UiLogic::saveTextFile(const QString& desc, const QString& ext, const QString& data)
void UiLogic::saveTextFile(const QString& desc, QString ext, const QString& data)
{
ext.replace("*", "");
QString fileName = QFileDialog::getSaveFileName(nullptr, desc,
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), ext);
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*" + ext);
if (fileName.isEmpty()) return;
if (!fileName.endsWith(ext)) fileName.append(ext);
QFile save(fileName);
save.open(QIODevice::WriteOnly);
@ -660,12 +623,14 @@ void UiLogic::saveTextFile(const QString& desc, const QString& ext, const QStrin
QDesktopServices::openUrl(fi.absoluteDir().absolutePath());
}
void UiLogic::saveBinaryFile(const QString &desc, const QString &ext, const QString &data)
void UiLogic::saveBinaryFile(const QString &desc, QString ext, const QString &data)
{
ext.replace("*", "");
QString fileName = QFileDialog::getSaveFileName(nullptr, desc,
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), ext);
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*" + ext);
if (fileName.isEmpty()) return;
if (!fileName.endsWith(ext)) fileName.append(ext);
QFile save(fileName);
save.open(QIODevice::WriteOnly);

View file

@ -100,8 +100,8 @@ public:
Q_INVOKABLE void keyPressEvent(Qt::Key key);
Q_INVOKABLE void saveTextFile(const QString& desc, const QString& ext, const QString& data);
Q_INVOKABLE void saveBinaryFile(const QString& desc, const QString& ext, const QString& data);
Q_INVOKABLE void saveTextFile(const QString& desc, QString ext, const QString& data);
Q_INVOKABLE void saveBinaryFile(const QString& desc, QString ext, const QString& data);
Q_INVOKABLE void copyToClipboard(const QString& text);
QString getDialogConnectErrorText() const;
@ -121,6 +121,7 @@ signals:
void show();
void hide();
void raise();
void toggleLogPanel();
private:
QString m_dialogConnectErrorText;
@ -213,20 +214,6 @@ private:
NotificationHandler* m_notificationHandler;
// QRegExpValidator m_ipAddressValidator;
// QRegExpValidator m_ipAddressPortValidator;
// QRegExpValidator m_ipNetwok24Validator;
// QRegExpValidator m_ipPortValidator;
// QPoint offset;
// bool needToHideCustomTitlebar = false;
// void showEvent(QShowEvent *event) override;
// void hideEvent(QHideEvent *event) override;
// QStack<Page> pagesStack;
int selectedServerIndex = -1; // server index to use when proto settings page opened
DockerContainer selectedDockerContainer; // same
ServerCredentials installCredentials; // used to save cred between pages new_server and new_server_protocols and wizard