Merge remote-tracking branch 'origin/dev' into ios-wireguard
|
@ -2,5 +2,5 @@ TEMPLATE = subdirs
|
|||
SUBDIRS = client
|
||||
|
||||
!ios:!android {
|
||||
SUBDIRS += service platform
|
||||
SUBDIRS += service
|
||||
}
|
||||
|
|
|
@ -15,27 +15,15 @@
|
|||
<!-- %%INSERT_FEATURES -->
|
||||
|
||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||
<application
|
||||
android:hardwareAccelerated="true"
|
||||
android:name="org.qtproject.qt5.android.bindings.QtApplication"
|
||||
android:label="-- %%INSERT_APP_NAME%% --"
|
||||
android:extractNativeLibs="true"
|
||||
android:icon="@drawable/icon">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
|
||||
android:name="org.qtproject.qt5.android.bindings.QtActivity"
|
||||
|
||||
android:label="-- %%INSERT_APP_NAME%% --"
|
||||
android:screenOrientation="unspecified"
|
||||
android:launchMode="singleTop">
|
||||
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true" android:icon="@drawable/icon">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop" android:theme="@style/splashScreenTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
|
||||
<!-- Application arguments -->
|
||||
<!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
|
||||
<!-- Application arguments -->
|
||||
|
||||
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
|
||||
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
||||
<meta-data android:name="android.app.repository" android:value="default"/>
|
||||
|
@ -43,7 +31,6 @@
|
|||
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
||||
<!-- Deploy Qt libs as part of package -->
|
||||
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
|
||||
|
||||
<!-- Run with local libs -->
|
||||
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
|
||||
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
|
||||
|
@ -58,7 +45,6 @@
|
|||
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
||||
<meta-data android:value="@string/unsupported_android_version" android:name="android.app.unsupported_android_version"/>
|
||||
<!-- Messages maps -->
|
||||
|
||||
<!-- Splash screen -->
|
||||
<!-- Orientation-specific (portrait/landscape) data is checked first. If not available for current orientation,
|
||||
then android.app.splash_screen_drawable. For best results, use together with splash_screen_sticky and
|
||||
|
@ -69,7 +55,6 @@
|
|||
<!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
|
||||
<!-- Splash screen -->
|
||||
|
||||
<!-- Background running -->
|
||||
<!-- Warning: changing this value to true may cause unexpected crashes if the
|
||||
application still try to draw after
|
||||
|
@ -77,11 +62,9 @@
|
|||
signal is sent! -->
|
||||
<meta-data android:name="android.app.background_running" android:value="false"/>
|
||||
<!-- Background running -->
|
||||
|
||||
<!-- auto screen scale factor -->
|
||||
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
|
||||
<!-- auto screen scale factor -->
|
||||
|
||||
<!-- extract android style -->
|
||||
<!-- available android:values :
|
||||
* default - In most cases this will be the same as "full", but it can also be something else if needed, e.g., for compatibility reasons
|
||||
|
@ -95,21 +78,16 @@
|
|||
</activity>
|
||||
|
||||
<service android:name=".VPNService"
|
||||
|
||||
android:process=":QtOnlyProcess"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.VpnService"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service android:name="org.amnezia.vpn.qt.VPNPermissionHelper"
|
||||
|
||||
<service android:name="org.mozilla.firefox.vpn.qt.VPNPermissionHelper"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE">
|
||||
</service>
|
||||
|
||||
|
||||
|
||||
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -102,8 +102,8 @@ android {
|
|||
resConfig "en"
|
||||
minSdkVersion = 24
|
||||
targetSdkVersion = 30
|
||||
versionCode 7 // Change to a higher number
|
||||
versionName "2.0.7" // Change to a higher number
|
||||
versionCode 8 // Change to a higher number
|
||||
versionName "2.0.8" // Change to a higher number
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
|
@ -43,6 +43,7 @@ class VPNService : android.net.VpnService() {
|
|||
}
|
||||
|
||||
override fun onUnbind(intent: Intent?): Boolean {
|
||||
Log.v(tag, "Got Unbind request")
|
||||
if (!isUp) {
|
||||
// If the Qt Client got closed while we were not connected
|
||||
// we do not need to stay as a foreground service.
|
||||
|
@ -128,6 +129,7 @@ class VPNService : android.net.VpnService() {
|
|||
putOpt("deviceIpv4", mConfig?.getJSONObject("device")?.getString("ipv4Address"))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the VPN Permission is given.
|
||||
* If the permission is given, returns true
|
||||
|
@ -163,6 +165,7 @@ class VPNService : android.net.VpnService() {
|
|||
return 0
|
||||
}
|
||||
}
|
||||
NotificationUtil.show(this) // Go foreground
|
||||
return 1
|
||||
}
|
||||
|
||||
|
@ -237,6 +240,7 @@ class VPNService : android.net.VpnService() {
|
|||
mOpenVPNThreadv3 = null
|
||||
Log.e(tag, "mOpenVPNThreadv3 stop!")
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures an Android VPN Service Tunnel
|
||||
* with a given Wireguard Config
|
||||
|
@ -296,7 +300,8 @@ class VPNService : android.net.VpnService() {
|
|||
currentSection?.let {
|
||||
parseData.put(it.first, it.second)
|
||||
}
|
||||
currentSection = line.substring(1, line.indexOfLast { it == ']' }) to mutableMapOf()
|
||||
currentSection =
|
||||
line.substring(1, line.indexOfLast { it == ']' }) to mutableMapOf()
|
||||
} else {
|
||||
val parameter = line.split("=", limit = 2)
|
||||
currentSection!!.second.put(parameter.first().trim(), parameter.last().trim())
|
||||
|
@ -398,9 +403,8 @@ class VPNService : android.net.VpnService() {
|
|||
prefs.edit()
|
||||
.putString("lastConf", mConfig.toString())
|
||||
.apply()
|
||||
|
||||
NotificationUtil.show(this) // Go foreground
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun startService(c: Context) {
|
||||
|
@ -412,14 +416,19 @@ class VPNService : android.net.VpnService() {
|
|||
|
||||
@JvmStatic
|
||||
private external fun wgGetConfig(handle: Int): String?
|
||||
|
||||
@JvmStatic
|
||||
private external fun wgGetSocketV4(handle: Int): Int
|
||||
|
||||
@JvmStatic
|
||||
private external fun wgGetSocketV6(handle: Int): Int
|
||||
|
||||
@JvmStatic
|
||||
private external fun wgTurnOff(handle: Int)
|
||||
|
||||
@JvmStatic
|
||||
private external fun wgTurnOn(ifName: String, tunFd: Int, settings: String): Int
|
||||
|
||||
@JvmStatic
|
||||
private external fun wgVersion(): String?
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
QT += widgets core gui network xml remoteobjects quick
|
||||
QT += widgets core gui network xml remoteobjects quick svg
|
||||
|
||||
TARGET = AmneziaVPN
|
||||
TEMPLATE = app
|
||||
|
@ -200,6 +200,7 @@ linux:!android {
|
|||
}
|
||||
|
||||
win32|macx|linux:!android {
|
||||
DEFINES += AMNEZIA_DESKTOP
|
||||
|
||||
HEADERS += \
|
||||
ui/systemtray_notificationhandler.h \
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <QJsonDocument>
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "utils.h"
|
||||
|
||||
Settings &VpnConfigurator::m_settings()
|
||||
{
|
||||
|
@ -41,24 +42,59 @@ QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentia
|
|||
}
|
||||
}
|
||||
|
||||
QString VpnConfigurator::processConfigWithLocalSettings(DockerContainer container, Proto proto, QString config)
|
||||
QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
|
||||
{
|
||||
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
|
||||
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
|
||||
QPair<QString, QString> dns;
|
||||
|
||||
bool useAmneziaDns = m_settings().useAmneziaDns();
|
||||
const QJsonObject &server = m_settings().server(serverIndex);
|
||||
|
||||
dns.first = server.value(config_key::dns1).toString();
|
||||
dns.second = server.value(config_key::dns2).toString();
|
||||
|
||||
if (dns.first.isEmpty() || !Utils::checkIPv4Format(dns.first)) {
|
||||
if (useAmneziaDns && m_settings().containers(serverIndex).contains(DockerContainer::Dns)) {
|
||||
dns.first = protocols::dns::amneziaDnsIp;
|
||||
}
|
||||
else dns.first = m_settings().primaryDns();
|
||||
}
|
||||
if (dns.second.isEmpty() || !Utils::checkIPv4Format(dns.second)) {
|
||||
dns.second = m_settings().secondaryDns();
|
||||
}
|
||||
|
||||
qDebug() << "VpnConfigurator::getDnsForConfig" << dns.first << dns.second;
|
||||
return dns;
|
||||
}
|
||||
|
||||
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container,
|
||||
Proto proto, QString &config)
|
||||
{
|
||||
auto dns = getDnsForConfig(serverIndex);
|
||||
|
||||
config.replace("$PRIMARY_DNS", dns.first);
|
||||
config.replace("$SECONDARY_DNS", dns.second);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container,
|
||||
Proto proto, QString &config)
|
||||
{
|
||||
processConfigWithDnsSettings(serverIndex, container, proto, config);
|
||||
|
||||
if (proto == Proto::OpenVpn) {
|
||||
return OpenVpnConfigurator::processConfigWithLocalSettings(config);
|
||||
config = OpenVpnConfigurator::processConfigWithLocalSettings(config);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
QString VpnConfigurator::processConfigWithExportSettings(DockerContainer container, Proto proto, QString config)
|
||||
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container,
|
||||
Proto proto, QString &config)
|
||||
{
|
||||
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
|
||||
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
|
||||
processConfigWithDnsSettings(serverIndex, container, proto, config);
|
||||
|
||||
if (proto == Proto::OpenVpn) {
|
||||
return OpenVpnConfigurator::processConfigWithExportSettings(config);
|
||||
config = OpenVpnConfigurator::processConfigWithExportSettings(config);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,11 @@ public:
|
|||
static QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
|
||||
|
||||
static QString processConfigWithLocalSettings(DockerContainer container, Proto proto, QString config);
|
||||
static QString processConfigWithExportSettings(DockerContainer container, Proto proto, QString config);
|
||||
static QPair<QString, QString> getDnsForConfig(int serverIndex);
|
||||
static QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
|
||||
static QString &processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
static QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
|
||||
// workaround for containers which is not support normal configaration
|
||||
static void updateContainerConfigAfterInstallation(DockerContainer container,
|
||||
|
|
|
@ -149,7 +149,11 @@ bool ContainerProps::isWorkingOnPlatform(DockerContainer c)
|
|||
default: return false;
|
||||
}
|
||||
#elif defined (Q_OS_MAC)
|
||||
return false;
|
||||
switch (c) {
|
||||
case DockerContainer::WireGuard: return false;
|
||||
case DockerContainer::Ipsec: return false;
|
||||
default: return true;
|
||||
}
|
||||
|
||||
#elif defined (Q_OS_ANDROID)
|
||||
switch (c) {
|
||||
|
|
|
@ -79,6 +79,8 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
|
|||
}
|
||||
|
||||
qDebug().noquote() << "EXEC" << lineToExec;
|
||||
Debug::appendSshLog("Run command:" + lineToExec);
|
||||
|
||||
QSharedPointer<SshRemoteProcess> proc = client->createRemoteProcess(lineToExec.toUtf8());
|
||||
|
||||
if (!proc) {
|
||||
|
@ -101,7 +103,9 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
|
|||
|
||||
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, &wait, [proc, cbReadStdOut](){
|
||||
QString s = proc->readAllStandardOutput();
|
||||
|
||||
if (s != "." && !s.isEmpty()) {
|
||||
Debug::appendSshLog("Output: " + s);
|
||||
qDebug().noquote() << "stdout" << s;
|
||||
}
|
||||
if (cbReadStdOut) cbReadStdOut(s, proc);
|
||||
|
@ -110,6 +114,7 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
|
|||
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, &wait, [proc, cbReadStdErr](){
|
||||
QString s = proc->readAllStandardError();
|
||||
if (s != "." && !s.isEmpty()) {
|
||||
Debug::appendSshLog("Output: " + s);
|
||||
qDebug().noquote() << "stderr" << s;
|
||||
}
|
||||
if (cbReadStdErr) cbReadStdErr(s, proc);
|
||||
|
@ -135,6 +140,7 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti
|
|||
const std::function<void (const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr)
|
||||
{
|
||||
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
|
||||
Debug::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script);
|
||||
|
||||
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
|
||||
if (e) return e;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <QObject>
|
||||
#include "sshconnection.h"
|
||||
#include "sshremoteprocess.h"
|
||||
#include "debug.h"
|
||||
#include "defs.h"
|
||||
#include "settings.h"
|
||||
|
||||
|
|
|
@ -6,13 +6,15 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include <core/ipcclient.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "defines.h"
|
||||
#include "utils.h"
|
||||
|
||||
QFile Debug::m_file;
|
||||
QTextStream Debug::m_textStream;
|
||||
QString Debug::m_logFileName;
|
||||
QString Debug::m_logFileName = QString("%1.log").arg(APPLICATION_NAME);
|
||||
|
||||
void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
||||
{
|
||||
|
@ -26,10 +28,30 @@ void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
|
|||
}
|
||||
|
||||
Debug::m_textStream << qFormatLogMessage(type, context, msg) << endl << flush;
|
||||
Debug::appendAllLog(qFormatLogMessage(type, context, msg));
|
||||
|
||||
std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush;
|
||||
}
|
||||
|
||||
Debug &Debug::Instance()
|
||||
{
|
||||
static Debug s;
|
||||
return s;
|
||||
}
|
||||
|
||||
void Debug::appendSshLog(const QString &log)
|
||||
{
|
||||
QString dt = QDateTime::currentDateTime().toString();
|
||||
Instance().m_sshLog.append(dt + ": " + log + "\n");
|
||||
emit Instance().sshLogChanged(Instance().sshLog());
|
||||
}
|
||||
|
||||
void Debug::appendAllLog(const QString &log)
|
||||
{
|
||||
Instance().m_allLog.append(log + "\n");
|
||||
emit Instance().allLogChanged(Instance().allLog());
|
||||
}
|
||||
|
||||
bool Debug::init()
|
||||
{
|
||||
qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}");
|
||||
|
@ -40,11 +62,8 @@ bool Debug::init()
|
|||
return false;
|
||||
}
|
||||
|
||||
m_logFileName = QString("%1.log").arg(APPLICATION_NAME);
|
||||
|
||||
|
||||
m_file.setFileName(appDir.filePath(m_logFileName));
|
||||
if (!m_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
if (!m_file.open(QIODevice::Append)) {
|
||||
qWarning() << "Cannot open log file:" << m_logFileName;
|
||||
return false;
|
||||
}
|
||||
|
@ -63,6 +82,20 @@ QString Debug::userLogsDir()
|
|||
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/log";
|
||||
}
|
||||
|
||||
QString Debug::userLogsFilePath()
|
||||
{
|
||||
return userLogsDir() + QDir::separator() + m_logFileName;
|
||||
}
|
||||
|
||||
QString Debug::getLogFile()
|
||||
{
|
||||
m_file.flush();
|
||||
QFile file(userLogsFilePath());
|
||||
|
||||
file.open(QIODevice::ReadOnly);
|
||||
return file.readAll();
|
||||
}
|
||||
|
||||
bool Debug::openLogsFolder()
|
||||
{
|
||||
QString path = userLogsDir();
|
||||
|
@ -88,3 +121,48 @@ QString Debug::appLogFileNamePath()
|
|||
{
|
||||
return m_file.fileName();
|
||||
}
|
||||
|
||||
void Debug::clearLogs()
|
||||
{
|
||||
bool isLogActive = m_file.isOpen();
|
||||
m_file.close();
|
||||
|
||||
QFile file(userLogsFilePath());
|
||||
|
||||
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
||||
file.resize(0);
|
||||
file.close();
|
||||
|
||||
if (isLogActive) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
void Debug::clearServiceLogs()
|
||||
{
|
||||
IpcClient *m_IpcClient = new IpcClient;
|
||||
|
||||
if (!m_IpcClient->isSocketConnected()) {
|
||||
if (!IpcClient::init(m_IpcClient)) {
|
||||
qWarning() << "Error occured when init IPC client";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_IpcClient->Interface()) {
|
||||
m_IpcClient->Interface()->setLogsEnabled(false);
|
||||
m_IpcClient->Interface()->cleanUp();
|
||||
}
|
||||
else {
|
||||
qWarning() << "Error occured cleaning up service logs";
|
||||
}
|
||||
}
|
||||
|
||||
void Debug::cleanUp()
|
||||
{
|
||||
clearLogs();
|
||||
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
||||
dir.removeRecursively();
|
||||
|
||||
clearServiceLogs();
|
||||
}
|
||||
|
|
|
@ -7,15 +7,37 @@
|
|||
#include <QString>
|
||||
#include <QTextStream>
|
||||
|
||||
class Debug
|
||||
#include "ui/property_helper.h"
|
||||
|
||||
class Debug : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
AUTO_PROPERTY(QString, sshLog)
|
||||
AUTO_PROPERTY(QString, allLog)
|
||||
|
||||
public:
|
||||
static Debug& Instance();
|
||||
|
||||
static void appendSshLog(const QString &log);
|
||||
static void appendAllLog(const QString &log);
|
||||
|
||||
|
||||
static bool init();
|
||||
static bool openLogsFolder();
|
||||
static bool openServiceLogsFolder();
|
||||
static QString appLogFileNamePath();
|
||||
static void clearLogs();
|
||||
static void clearServiceLogs();
|
||||
static void cleanUp();
|
||||
|
||||
static QString userLogsFilePath();
|
||||
static QString getLogFile();
|
||||
|
||||
private:
|
||||
Debug() {}
|
||||
Debug(Debug const &) = delete;
|
||||
Debug& operator= (Debug const&) = delete;
|
||||
|
||||
static QString userLogsDir();
|
||||
|
||||
static QFile m_file;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#define APPLICATION_NAME "AmneziaVPN"
|
||||
#define SERVICE_NAME "AmneziaVPN-service"
|
||||
#define ORGANIZATION_NAME "AmneziaVPN.ORG"
|
||||
#define APP_MAJOR_VERSION "2.0.7"
|
||||
#define APP_VERSION "2.0.7.0"
|
||||
#define APP_MAJOR_VERSION "2.0.8"
|
||||
#define APP_VERSION "2.0.8.0"
|
||||
|
||||
#endif // DEFINES_H
|
||||
|
|
Before Width: | Height: | Size: 324 B |
Before Width: | Height: | Size: 690 B |
Before Width: | Height: | Size: 454 B |
1
client/images/svg/close_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>
|
After Width: | Height: | Size: 268 B |
1
client/images/svg/control_point_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.49 2 2 6.49 2 12s4.49 10 10 10 10-4.49 10-10S17.51 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></svg>
|
After Width: | Height: | Size: 317 B |
1
client/images/svg/delete_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z"/></svg>
|
After Width: | Height: | Size: 252 B |
1
client/images/svg/density_small_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><rect height="2" width="18" x="3" y="2"/><rect height="2" width="18" x="3" y="20"/><rect height="2" width="18" x="3" y="14"/><rect height="2" width="18" x="3" y="8"/></g></g></svg>
|
After Width: | Height: | Size: 371 B |
1
client/images/svg/done_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>
|
After Width: | Height: | Size: 209 B |
1
client/images/svg/format_list_bulleted_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z"/></svg>
|
After Width: | Height: | Size: 430 B |
1
client/images/svg/gpp_good_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><path d="M0,0h24v24H0V0z" fill="none"/></g><g><path d="M12,2L4,5v6.09c0,5.05,3.41,9.76,8,10.91c4.59-1.15,8-5.86,8-10.91V5L12,2z M18,11.09c0,4-2.55,7.7-6,8.83 c-3.45-1.13-6-4.82-6-8.83V6.31l6-2.12l6,2.12V11.09z M8.82,10.59L7.4,12l3.54,3.54l5.66-5.66l-1.41-1.41l-4.24,4.24L8.82,10.59z"/></g></svg>
|
After Width: | Height: | Size: 434 B |
1
client/images/svg/gpp_maybe_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><path d="M0,0h24v24H0V0z" fill="none"/></g><g><g><path d="M12,2L4,5v6.09c0,5.05,3.41,9.76,8,10.91c4.59-1.15,8-5.86,8-10.91V5L12,2z M18,11.09c0,4-2.55,7.7-6,8.83 c-3.45-1.13-6-4.82-6-8.83v-4.7l6-2.25l6,2.25V11.09z"/><rect height="2" width="2" x="11" y="14"/><rect height="5" width="2" x="11" y="7"/></g></g></svg>
|
After Width: | Height: | Size: 451 B |
1
client/images/svg/logout_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><path d="M0,0h24v24H0V0z" fill="none"/></g><g><path d="M17,8l-1.41,1.41L17.17,11H9v2h8.17l-1.58,1.58L17,16l4-4L17,8z M5,5h7V3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h7v-2H5V5z"/></g></svg>
|
After Width: | Height: | Size: 324 B |
1
client/images/svg/miscellaneous_services_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><path d="M14.17,13.71l1.4-2.42c0.09-0.15,0.05-0.34-0.08-0.45l-1.48-1.16c0.03-0.22,0.05-0.45,0.05-0.68s-0.02-0.46-0.05-0.69 l1.48-1.16c0.13-0.11,0.17-0.3,0.08-0.45l-1.4-2.42c-0.09-0.15-0.27-0.21-0.43-0.15L12,4.83c-0.36-0.28-0.75-0.51-1.18-0.69 l-0.26-1.85C10.53,2.13,10.38,2,10.21,2h-2.8C7.24,2,7.09,2.13,7.06,2.3L6.8,4.15C6.38,4.33,5.98,4.56,5.62,4.84l-1.74-0.7 c-0.16-0.06-0.34,0-0.43,0.15l-1.4,2.42C1.96,6.86,2,7.05,2.13,7.16l1.48,1.16C3.58,8.54,3.56,8.77,3.56,9s0.02,0.46,0.05,0.69 l-1.48,1.16C2,10.96,1.96,11.15,2.05,11.3l1.4,2.42c0.09,0.15,0.27,0.21,0.43,0.15l1.74-0.7c0.36,0.28,0.75,0.51,1.18,0.69 l0.26,1.85C7.09,15.87,7.24,16,7.41,16h2.8c0.17,0,0.32-0.13,0.35-0.3l0.26-1.85c0.42-0.18,0.82-0.41,1.18-0.69l1.74,0.7 C13.9,13.92,14.08,13.86,14.17,13.71z M8.81,11c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2s2,0.9,2,2C10.81,10.1,9.91,11,8.81,11z"/><path d="M21.92,18.67l-0.96-0.74c0.02-0.14,0.04-0.29,0.04-0.44c0-0.15-0.01-0.3-0.04-0.44l0.95-0.74 c0.08-0.07,0.11-0.19,0.05-0.29l-0.9-1.55c-0.05-0.1-0.17-0.13-0.28-0.1l-1.11,0.45c-0.23-0.18-0.48-0.33-0.76-0.44l-0.17-1.18 C18.73,13.08,18.63,13,18.53,13h-1.79c-0.11,0-0.21,0.08-0.22,0.19l-0.17,1.18c-0.27,0.12-0.53,0.26-0.76,0.44l-1.11-0.45 c-0.1-0.04-0.22,0-0.28,0.1l-0.9,1.55c-0.05,0.1-0.04,0.22,0.05,0.29l0.95,0.74c-0.02,0.14-0.03,0.29-0.03,0.44 c0,0.15,0.01,0.3,0.03,0.44l-0.95,0.74c-0.08,0.07-0.11,0.19-0.05,0.29l0.9,1.55c0.05,0.1,0.17,0.13,0.28,0.1l1.11-0.45 c0.23,0.18,0.48,0.33,0.76,0.44l0.17,1.18c0.02,0.11,0.11,0.19,0.22,0.19h1.79c0.11,0,0.21-0.08,0.22-0.19l0.17-1.18 c0.27-0.12,0.53-0.26,0.75-0.44l1.12,0.45c0.1,0.04,0.22,0,0.28-0.1l0.9-1.55C22.03,18.86,22,18.74,21.92,18.67z M17.63,18.83 c-0.74,0-1.35-0.6-1.35-1.35s0.6-1.35,1.35-1.35s1.35,0.6,1.35,1.35S18.37,18.83,17.63,18.83z"/></g></g></svg>
|
After Width: | Height: | Size: 1.9 KiB |
1
client/images/svg/refresh_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></svg>
|
After Width: | Height: | Size: 361 B |
1
client/images/svg/settings_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19.43 12.98c.04-.32.07-.64.07-.98 0-.34-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.09-.16-.26-.25-.44-.25-.06 0-.12.01-.17.03l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.06-.02-.12-.03-.18-.03-.17 0-.34.09-.43.25l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98 0 .33.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.09.16.26.25.44.25.06 0 .12-.01.17-.03l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.06.02.12.03.18.03.17 0 .34-.09.43-.25l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-1.98-1.71c.04.31.05.52.05.73 0 .21-.02.43-.05.73l-.14 1.13.89.7 1.08.84-.7 1.21-1.27-.51-1.04-.42-.9.68c-.43.32-.84.56-1.25.73l-1.06.43-.16 1.13-.2 1.35h-1.4l-.19-1.35-.16-1.13-1.06-.43c-.43-.18-.83-.41-1.23-.71l-.91-.7-1.06.43-1.27.51-.7-1.21 1.08-.84.89-.7-.14-1.13c-.03-.31-.05-.54-.05-.74s.02-.43.05-.73l.14-1.13-.89-.7-1.08-.84.7-1.21 1.27.51 1.04.42.9-.68c.43-.32.84-.56 1.25-.73l1.06-.43.16-1.13.2-1.35h1.39l.19 1.35.16 1.13 1.06.43c.43.18.83.41 1.23.71l.91.7 1.06-.43 1.27-.51.7 1.21-1.07.85-.89.7.14 1.13zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
client/images/svg/settings_suggest_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><rect fill="none" height="24" width="24"/><path d="M10,13c0.55,0,1,0.45,1,1s-0.45,1-1,1s-1-0.45-1-1S9.45,13,10,13 M10,11c-1.66,0-3,1.34-3,3s1.34,3,3,3s3-1.34,3-3 S11.66,11,10,11L10,11z M18.5,9l1.09-2.41L22,5.5l-2.41-1.09L18.5,2l-1.09,2.41L15,5.5l2.41,1.09L18.5,9z M21.28,12.72L20.5,11 l-0.78,1.72L18,13.5l1.72,0.78L20.5,16l0.78-1.72L23,13.5L21.28,12.72z M16.25,14c0-0.12,0-0.25-0.01-0.37l1.94-1.47l-2.5-4.33 l-2.24,0.94c-0.2-0.13-0.42-0.26-0.64-0.37L12.5,6h-5L7.2,8.41C6.98,8.52,6.77,8.65,6.56,8.78L4.32,7.83l-2.5,4.33l1.94,1.47 C3.75,13.75,3.75,13.88,3.75,14s0,0.25,0.01,0.37l-1.94,1.47l2.5,4.33l2.24-0.94c0.2,0.13,0.42,0.26,0.64,0.37L7.5,22h5l0.3-2.41 c0.22-0.11,0.43-0.23,0.64-0.37l2.24,0.94l2.5-4.33l-1.94-1.47C16.25,14.25,16.25,14.12,16.25,14z M14.83,17.64l-1.73-0.73 c-0.56,0.6-1.3,1.04-2.13,1.23L10.73,20H9.27l-0.23-1.86c-0.83-0.19-1.57-0.63-2.13-1.23l-1.73,0.73l-0.73-1.27l1.49-1.13 c-0.12-0.39-0.18-0.8-0.18-1.23c0-0.43,0.06-0.84,0.18-1.23l-1.49-1.13l0.73-1.27l1.73,0.73c0.56-0.6,1.3-1.04,2.13-1.23L9.27,8 h1.47l0.23,1.86c0.83,0.19,1.57,0.63,2.13,1.23l1.73-0.73l0.73,1.27l-1.49,1.13c0.12,0.39,0.18,0.8,0.18,1.23 c0,0.43-0.06,0.84-0.18,1.23l1.49,1.13L14.83,17.64z"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
client/images/svg/share_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92c0-1.61-1.31-2.92-2.92-2.92zM18 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM6 13c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm12 7.02c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/></svg>
|
After Width: | Height: | Size: 679 B |
1
client/images/svg/vpn_key_black_24dp.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M22 19h-6v-4h-2.68c-1.14 2.42-3.6 4-6.32 4-3.86 0-7-3.14-7-7s3.14-7 7-7c2.72 0 5.17 1.58 6.32 4H24v6h-2v4zm-4-2h2v-4h2v-2H11.94l-.23-.67C11.01 8.34 9.11 7 7 7c-2.76 0-5 2.24-5 5s2.24 5 5 5c2.11 0 4.01-1.34 4.71-3.33l.23-.67H18v4zM7 15c-1.65 0-3-1.35-3-3s1.35-3 3-3 3 1.35 3 3-1.35 3-3 3zm0-4c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z"/></svg>
|
After Width: | Height: | Size: 498 B |
|
@ -86,15 +86,15 @@ int main(int argc, char *argv[])
|
|||
QApplication app(argc, argv);
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
NativeHelpers::registerApplicationInstance(&app);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
AllowSetForegroundWindow(0);
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
NativeHelpers::registerApplicationInstance(&app);
|
||||
#endif
|
||||
|
||||
loadTranslator();
|
||||
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Black.ttf");
|
||||
|
@ -120,11 +120,27 @@ int main(int argc, char *argv[])
|
|||
QCommandLineOption c_autostart {{"a", "autostart"}, "System autostart"};
|
||||
parser.addOption(c_autostart);
|
||||
|
||||
QCommandLineOption c_cleanup {{"c", "cleanup"}, "Cleanup logs"};
|
||||
parser.addOption(c_cleanup);
|
||||
|
||||
parser.process(app);
|
||||
|
||||
if (parser.isSet(c_cleanup)) {
|
||||
Debug::cleanUp();
|
||||
QTimer::singleShot(100,[&app]{
|
||||
app.quit();
|
||||
});
|
||||
app.exec();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Settings settings;
|
||||
|
||||
if (settings.isSaveLogs()) {
|
||||
if (!Debug::init()) {
|
||||
qWarning() << "Initialization of debug subsystem failed";
|
||||
}
|
||||
}
|
||||
|
||||
app.setQuitOnLastWindowClosed(false);
|
||||
|
||||
|
@ -165,6 +181,8 @@ int main(int argc, char *argv[])
|
|||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
engine->rootContext()->setContextProperty("Debug", &Debug::Instance());
|
||||
|
||||
engine->rootContext()->setContextProperty("UiLogic", uiLogic);
|
||||
|
||||
engine->rootContext()->setContextProperty("AppSettingsLogic", uiLogic->appSettingsLogic());
|
||||
|
@ -196,26 +214,23 @@ int main(int argc, char *argv[])
|
|||
uiLogic->setQmlRoot(engine->rootObjects().at(0));
|
||||
}
|
||||
|
||||
// TODO - fix
|
||||
//#ifdef Q_OS_WIN
|
||||
// if (parser.isSet("a")) mainWindow.showOnStartup();
|
||||
// else mainWindow.show();
|
||||
//#else
|
||||
// mainWindow.showOnStartup();
|
||||
//#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (parser.isSet("a")) uiLogic->showOnStartup();
|
||||
else emit uiLogic->show();
|
||||
#else
|
||||
uiLogic->showOnStartup();
|
||||
#endif
|
||||
|
||||
// TODO - fix
|
||||
//#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
// if (app.isPrimary()) {
|
||||
// QObject::connect(&app, &SingleApplication::instanceStarted, &mainWindow, [&](){
|
||||
// qDebug() << "Secondary instance started, showing this window instead";
|
||||
// mainWindow.show();
|
||||
// mainWindow.showNormal();
|
||||
// mainWindow.raise();
|
||||
// });
|
||||
// }
|
||||
//#endif
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
if (app.isPrimary()) {
|
||||
QObject::connect(&app, &SingleApplication::instanceStarted, uiLogic, [&](){
|
||||
qDebug() << "Secondary instance started, showing this window instead";
|
||||
emit uiLogic->show();
|
||||
emit uiLogic->raise();
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
|
|
@ -159,8 +159,8 @@ ErrorCode OpenVpnProtocol::start()
|
|||
return lastError();
|
||||
}
|
||||
|
||||
QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log";
|
||||
Utils::createEmptyFile(vpnLogFileNamePath);
|
||||
// QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log";
|
||||
// Utils::createEmptyFile(vpnLogFileNamePath);
|
||||
|
||||
if (!m_managementServer.start(m_managementHost, m_managementPort)) {
|
||||
setLastError(ErrorCode::OpenVpnManagementServerError);
|
||||
|
@ -186,8 +186,7 @@ ErrorCode OpenVpnProtocol::start()
|
|||
m_openVpnProcess->setProgram(openVpnExecPath());
|
||||
QStringList arguments({"--config" , configPath(),
|
||||
"--management", m_managementHost, QString::number(m_managementPort),
|
||||
"--management-client",
|
||||
"--log", vpnLogFileNamePath
|
||||
"--management-client"/*, "--log", vpnLogFileNamePath */
|
||||
});
|
||||
m_openVpnProcess->setArguments(arguments);
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@ constexpr char password[] = "password";
|
|||
constexpr char port[] = "port";
|
||||
constexpr char local_port[] = "local_port";
|
||||
|
||||
constexpr char dns1[] = "dns1";
|
||||
constexpr char dns2[] = "dns2";
|
||||
|
||||
|
||||
constexpr char description[] = "description";
|
||||
constexpr char cert[] = "cert";
|
||||
constexpr char config[] = "config";
|
||||
|
@ -55,6 +59,9 @@ constexpr char last_config[] = "last_config";
|
|||
|
||||
namespace protocols {
|
||||
|
||||
namespace dns {
|
||||
constexpr char amneziaDnsIp[] = "172.29.172.254";
|
||||
}
|
||||
|
||||
namespace openvpn {
|
||||
constexpr char defaultSubnetAddress[] = "10.8.0.0";
|
||||
|
|
|
@ -103,12 +103,14 @@ QString VpnProtocol::vpnGateway() const
|
|||
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject& configuration)
|
||||
{
|
||||
switch (container) {
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
|
||||
#endif
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
case DockerContainer::OpenVpn: return new OpenVpnProtocol(configuration);
|
||||
case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration);
|
||||
case DockerContainer::ShadowSocks: return new ShadowSocksVpnProtocol(configuration);
|
||||
case DockerContainer::WireGuard: return new WireguardProtocol(configuration);
|
||||
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
|
||||
#endif
|
||||
default: return nullptr;
|
||||
}
|
||||
|
|
|
@ -27,11 +27,9 @@
|
|||
<file>fonts/Lato-Thin.ttf</file>
|
||||
<file>fonts/Lato-ThinItalic.ttf</file>
|
||||
<file>images/AmneziaVPN.png</file>
|
||||
<file>images/server_settings.png</file>
|
||||
<file>images/share.png</file>
|
||||
<file>server_scripts/remove_container.sh</file>
|
||||
<file>server_scripts/setup_host_firewall.sh</file>
|
||||
<file>images/reload.png</file>
|
||||
<file>server_scripts/openvpn_cloak/Dockerfile</file>
|
||||
<file>server_scripts/openvpn_cloak/configure_container.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/start.sh</file>
|
||||
|
@ -42,7 +40,6 @@
|
|||
<file>images/check.png</file>
|
||||
<file>images/uncheck.png</file>
|
||||
<file>images/settings_grey.png</file>
|
||||
<file>images/plus.png</file>
|
||||
<file>server_scripts/check_connection.sh</file>
|
||||
<file>server_scripts/remove_all_containers.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/run_container.sh</file>
|
||||
|
@ -142,5 +139,23 @@
|
|||
<file>images/connected.png</file>
|
||||
<file>images/disconnected.png</file>
|
||||
<file>ui/qml/Pages/PageQrDecoder.qml</file>
|
||||
<file>ui/qml/Pages/PageAbout.qml</file>
|
||||
<file>ui/qml/Controls/RichLabelType.qml</file>
|
||||
<file>images/svg/gpp_good_black_24dp.svg</file>
|
||||
<file>ui/qml/Controls/SvgImageType.qml</file>
|
||||
<file>images/svg/gpp_maybe_black_24dp.svg</file>
|
||||
<file>images/svg/close_black_24dp.svg</file>
|
||||
<file>images/svg/delete_black_24dp.svg</file>
|
||||
<file>images/svg/done_black_24dp.svg</file>
|
||||
<file>images/svg/format_list_bulleted_black_24dp.svg</file>
|
||||
<file>images/svg/logout_black_24dp.svg</file>
|
||||
<file>images/svg/miscellaneous_services_black_24dp.svg</file>
|
||||
<file>images/svg/refresh_black_24dp.svg</file>
|
||||
<file>images/svg/settings_black_24dp.svg</file>
|
||||
<file>images/svg/share_black_24dp.svg</file>
|
||||
<file>images/svg/vpn_key_black_24dp.svg</file>
|
||||
<file>images/svg/control_point_black_24dp.svg</file>
|
||||
<file>images/svg/settings_suggest_black_24dp.svg</file>
|
||||
<file>ui/qml/Controls/SvgButtonType.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
# Run container
|
||||
sudo docker run -d --restart always --cap-add=NET_ADMIN -p 53:53/udp -p 53:53/tcp --name $CONTAINER_NAME $CONTAINER_NAME
|
||||
sudo docker run -d --restart always --network amnezia-dns-net --ip=172.29.172.254 --name $CONTAINER_NAME $CONTAINER_NAME
|
||||
|
|
|
@ -5,3 +5,4 @@ sudo docker run \
|
|||
-d --privileged \
|
||||
--name $CONTAINER_NAME $CONTAINER_NAME
|
||||
|
||||
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
# Run container
|
||||
sudo docker run -d --restart always --cap-add=NET_ADMIN -p $OPENVPN_PORT:$OPENVPN_PORT/$OPENVPN_TRANSPORT_PROTO --name $CONTAINER_NAME $CONTAINER_NAME
|
||||
sudo docker run \
|
||||
-d --restart always \
|
||||
--cap-add=NET_ADMIN \
|
||||
-p $OPENVPN_PORT:$OPENVPN_PORT/$OPENVPN_TRANSPORT_PROTO \
|
||||
--name $CONTAINER_NAME $CONTAINER_NAME
|
||||
|
||||
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
|
||||
|
||||
# Create tun device if not exist
|
||||
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'
|
||||
|
|
|
@ -14,9 +14,12 @@ iptables -A OUTPUT -o tun0 -j ACCEPT
|
|||
|
||||
# Allow forwarding traffic only from the VPN.
|
||||
iptables -A FORWARD -i tun0 -o eth0 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
|
||||
iptables -A FORWARD -i tun0 -o eth1 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
|
||||
|
||||
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
|
||||
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth0 -j MASQUERADE
|
||||
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth1 -j MASQUERADE
|
||||
|
||||
# kill daemons in case of restart
|
||||
killall -KILL openvpn
|
||||
|
|
|
@ -2,6 +2,10 @@ FROM alpine:latest
|
|||
|
||||
LABEL maintainer="AmneziaVPN"
|
||||
|
||||
ARG SS_RELEASE="v1.13.1"
|
||||
ARG CLOAK_RELEASE="v2.5.5"
|
||||
ARG SERVER_ARCH
|
||||
|
||||
#Install required packages
|
||||
RUN apk add --no-cache curl openvpn easy-rsa bash netcat-openbsd dumb-init rng-tools
|
||||
RUN apk --update upgrade --no-cache
|
||||
|
@ -13,10 +17,16 @@ RUN mkdir -p /opt/amnezia
|
|||
RUN echo -e "#!/bin/bash\ntail -f /dev/null" > /opt/amnezia/start.sh
|
||||
RUN chmod a+x /opt/amnezia/start.sh
|
||||
|
||||
RUN curl -L https://github.com/cbeuw/Cloak/releases/download/v2.5.3/ck-server-linux-amd64-v2.5.3 > /usr/bin/ck-server
|
||||
RUN if [ $SERVER_ARCH="x86_64" ]; then CK_ARCH="amd64"; \
|
||||
elif [ $SERVER_ARCH="i686" ]; then CK_ARCH="386"; \
|
||||
elif [ $SERVER_ARCH="aarch64" ]; then CK_ARCH="arm64"; \
|
||||
elif [ $SERVER_ARCH="arm" ]; then CK_ARCH="arm"; \
|
||||
else exit -1; fi && \
|
||||
curl -L https://github.com/cbeuw/Cloak/releases/download/${CLOAK_RELEASE}/ck-server-linux-${CK_ARCH}-${CLOAK_RELEASE} > /usr/bin/ck-server
|
||||
RUN chmod a+x /usr/bin/ck-server
|
||||
|
||||
RUN curl -L https://github.com/shadowsocks/shadowsocks-rust/releases/download/v1.10.9/shadowsocks-v1.10.9.x86_64-unknown-linux-musl.tar.xz > /usr/bin/ss.tar.xz
|
||||
RUN curl -L https://github.com/shadowsocks/shadowsocks-rust/releases/download/${SS_RELEASE}/shadowsocks-${SS_RELEASE}.${SERVER_ARCH}-unknown-linux-musl.tar.xz > /usr/bin/ss.tar.xz
|
||||
|
||||
RUN tar -Jxvf /usr/bin/ss.tar.xz -C /usr/bin/
|
||||
RUN chmod a+x /usr/bin/ssserver
|
||||
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
# Run container
|
||||
sudo docker run -d --restart always --cap-add=NET_ADMIN -p $CLOAK_SERVER_PORT:443/tcp --name $CONTAINER_NAME $CONTAINER_NAME
|
||||
sudo docker run \
|
||||
-d --restart always \
|
||||
--cap-add=NET_ADMIN \
|
||||
-p $CLOAK_SERVER_PORT:443/tcp \
|
||||
--name $CONTAINER_NAME $CONTAINER_NAME
|
||||
|
||||
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
|
||||
|
||||
# Create tun device if not exist
|
||||
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'
|
||||
|
|
|
@ -14,9 +14,12 @@ iptables -A OUTPUT -o tun0 -j ACCEPT
|
|||
|
||||
# Allow forwarding traffic only from the VPN.
|
||||
iptables -A FORWARD -i tun0 -o eth0 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
|
||||
iptables -A FORWARD -i tun0 -o eth1 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
|
||||
|
||||
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
|
||||
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth0 -j MASQUERADE
|
||||
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth1 -j MASQUERADE
|
||||
|
||||
# kill daemons in case of restart
|
||||
killall -KILL openvpn
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
FROM alpine:latest
|
||||
LABEL maintainer="AmneziaVPN"
|
||||
|
||||
ARG SS_RELEASE="v1.11.2"
|
||||
ARG SS_RELEASE="v1.13.1"
|
||||
ARG SERVER_ARCH
|
||||
|
||||
#Install required packages
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
# Run container
|
||||
sudo docker run -d --restart always --cap-add=NET_ADMIN -p $SHADOWSOCKS_SERVER_PORT:$SHADOWSOCKS_SERVER_PORT/tcp --name $CONTAINER_NAME $CONTAINER_NAME
|
||||
sudo docker run \
|
||||
-d --restart always \
|
||||
--cap-add=NET_ADMIN \
|
||||
-p $SHADOWSOCKS_SERVER_PORT:$SHADOWSOCKS_SERVER_PORT/tcp \
|
||||
--name $CONTAINER_NAME $CONTAINER_NAME
|
||||
|
||||
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
|
||||
|
||||
# Create tun device if not exist
|
||||
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'
|
||||
|
|
|
@ -14,9 +14,12 @@ iptables -A OUTPUT -o tun0 -j ACCEPT
|
|||
|
||||
# Allow forwarding traffic only from the VPN.
|
||||
iptables -A FORWARD -i tun0 -o eth0 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
|
||||
iptables -A FORWARD -i tun0 -o eth1 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
|
||||
|
||||
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
|
||||
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth0 -j MASQUERADE
|
||||
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth1 -j MASQUERADE
|
||||
|
||||
# kill daemons in case of restart
|
||||
killall -KILL openvpn
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
CUR_USER=$(whoami);\
|
||||
sudo mkdir -p $DOCKERFILE_FOLDER;\
|
||||
sudo chown $CUR_USER $DOCKERFILE_FOLDER
|
||||
if ! sudo docker network ls | grep -q amnezia-dns-net; then sudo docker network create --driver bridge --subnet=172.29.172.0/24 --opt com.docker.network.bridge.name=amn0 amnezia-dns-net; fi
|
||||
|
|
|
@ -10,6 +10,8 @@ sudo docker run -d \
|
|||
--name $CONTAINER_NAME \
|
||||
$CONTAINER_NAME
|
||||
|
||||
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
|
||||
|
||||
# Prevent to route packets outside of the container in case if server behind of the NAT
|
||||
#sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up"
|
||||
|
||||
|
|
|
@ -18,8 +18,11 @@ iptables -A OUTPUT -o wg0 -j ACCEPT
|
|||
|
||||
# Allow forwarding traffic only from the VPN.
|
||||
iptables -A FORWARD -i wg0 -o eth0 -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
|
||||
iptables -A FORWARD -i wg0 -o eth1 -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
|
||||
|
||||
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
|
||||
iptables -t nat -A POSTROUTING -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -o eth0 -j MASQUERADE
|
||||
iptables -t nat -A POSTROUTING -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -o eth1 -j MASQUERADE
|
||||
|
||||
tail -f /dev/null
|
||||
|
|
|
@ -228,6 +228,21 @@ void Settings::addVpnSite(RouteMode mode, const QString &site, const QString &ip
|
|||
setVpnSites(mode, sites);
|
||||
}
|
||||
|
||||
void Settings::addVpnSites(RouteMode mode, const QMap<QString, QString> &sites)
|
||||
{
|
||||
QVariantMap allSites = vpnSites(mode);
|
||||
for (auto i = sites.constBegin(); i != sites.constEnd(); ++i) {
|
||||
const QString &site = i.key();
|
||||
const QString &ip = i.value();
|
||||
|
||||
if (allSites.contains(site) && allSites.value(site) == ip) continue;
|
||||
|
||||
allSites.insert(site, ip);
|
||||
}
|
||||
|
||||
setVpnSites(mode, allSites);
|
||||
}
|
||||
|
||||
QStringList Settings::getVpnIps(RouteMode mode) const
|
||||
{
|
||||
QStringList ips;
|
||||
|
|
|
@ -67,6 +67,9 @@ public:
|
|||
bool isStartMinimized() const { return m_settings.value("Conf/startMinimized", false).toBool(); }
|
||||
void setStartMinimized(bool enabled) { m_settings.setValue("Conf/startMinimized", enabled); }
|
||||
|
||||
bool isSaveLogs() const { return m_settings.value("Conf/saveLogs", false).toBool(); }
|
||||
void setSaveLogs(bool enabled) { m_settings.setValue("Conf/saveLogs", enabled); }
|
||||
|
||||
enum RouteMode {
|
||||
VpnAllSites,
|
||||
VpnOnlyForwardSites,
|
||||
|
@ -82,12 +85,15 @@ public:
|
|||
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= "");
|
||||
void addVpnSites(RouteMode mode, const QMap<QString, QString> &sites); // map <site, 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);
|
||||
|
||||
bool useAmneziaDns() const { return m_settings.value("Conf/useAmneziaDns", true).toBool(); }
|
||||
void setUseAmneziaDns(bool enabled) { m_settings.setValue("Conf/useAmneziaDns", enabled); }
|
||||
|
||||
QString primaryDns() const;
|
||||
QString secondaryDns() const;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 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) {
|
||||
QStringList ips;
|
||||
ips.append(siteModel->data(row, 1).toString());
|
||||
}
|
||||
}
|
||||
|
||||
m_settings.removeVpnSites(mode, sites);
|
||||
|
||||
if (uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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."));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,33 +66,67 @@ 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 "
|
||||
|
@ -106,15 +138,21 @@ void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked()
|
|||
"-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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
17
client/ui/qml/Controls/RichLabelType.qml
Normal 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
16
client/ui/qml/Controls/SvgButtonType.qml
Normal 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
|
||||
}
|
||||
}
|
23
client/ui/qml/Controls/SvgImageType.qml
Normal 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
|
||||
}
|
||||
}
|
90
client/ui/qml/Pages/PageAbout.qml
Normal 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
|
||||
}
|
||||
}
|
|
@ -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,13 +15,34 @@ PageBase {
|
|||
id: back
|
||||
}
|
||||
Caption {
|
||||
id: caption
|
||||
text: qsTr("Application Settings")
|
||||
}
|
||||
|
||||
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 {
|
||||
x: 30
|
||||
y: 140
|
||||
width: 211
|
||||
height: 31
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Auto connect")
|
||||
checked: AppSettingsLogic.checkBoxAutoConnectChecked
|
||||
onCheckedChanged: {
|
||||
|
@ -29,10 +51,7 @@ PageBase {
|
|||
}
|
||||
}
|
||||
CheckBoxType {
|
||||
x: 30
|
||||
y: 100
|
||||
width: 211
|
||||
height: 31
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Auto start")
|
||||
checked: AppSettingsLogic.checkBoxAutostartChecked
|
||||
onCheckedChanged: {
|
||||
|
@ -41,10 +60,7 @@ PageBase {
|
|||
}
|
||||
}
|
||||
CheckBoxType {
|
||||
x: 30
|
||||
y: 180
|
||||
width: 211
|
||||
height: 31
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Start minimized")
|
||||
checked: AppSettingsLogic.checkBoxStartMinimizedChecked
|
||||
onCheckedChanged: {
|
||||
|
@ -53,36 +69,73 @@ PageBase {
|
|||
}
|
||||
}
|
||||
LabelType {
|
||||
x: 30
|
||||
y: 240
|
||||
width: 281
|
||||
height: 21
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 15
|
||||
text: AppSettingsLogic.labelVersionText
|
||||
}
|
||||
BlueButtonType {
|
||||
x: 30
|
||||
y: 280
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: parent.width - 40
|
||||
height: 41
|
||||
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 {
|
||||
x: 30
|
||||
y: 340
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: parent.width - 40
|
||||
height: 41
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,10 @@ PageBase {
|
|||
|
||||
SelectContainer {
|
||||
id: container_selector
|
||||
onAboutToHide: {
|
||||
pageLoader.focus = true
|
||||
}
|
||||
|
||||
onContainerSelected: {
|
||||
var containerProto = ContainerProps.defaultProtocol(c_index)
|
||||
|
||||
|
|
|
@ -41,6 +41,10 @@ PageBase {
|
|||
SelectContainer {
|
||||
id: container_selector
|
||||
|
||||
onAboutToHide: {
|
||||
pageLoader.focus = true
|
||||
}
|
||||
|
||||
onContainerSelected: {
|
||||
var containerProto = ContainerProps.defaultProtocol(c_index)
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,94 +15,100 @@ 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
|
||||
x: 10
|
||||
y: 10
|
||||
width: 331
|
||||
height: 25
|
||||
Layout.fillWidth: true
|
||||
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_low
|
||||
x: 10
|
||||
y: 180
|
||||
width: 331
|
||||
height: 25
|
||||
Layout.fillWidth: true
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,50 @@ PageBase {
|
|||
id: back_from_setup_wizard
|
||||
}
|
||||
Caption {
|
||||
id: caption
|
||||
text: qsTr("Setup Wizard")
|
||||
}
|
||||
Item {
|
||||
x: 10
|
||||
y: 70
|
||||
width: 361
|
||||
height: 561
|
||||
|
||||
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 {
|
||||
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.")
|
||||
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 {
|
||||
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")
|
||||
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
|
||||
x: 30
|
||||
y: 360
|
||||
width: 301
|
||||
height: 41
|
||||
Layout.fillWidth: true
|
||||
text: WizardLogic.lineEditHighWebsiteMaskingText
|
||||
onEditingFinished: {
|
||||
let _text = website_masking.text
|
||||
|
@ -63,20 +74,31 @@ PageBase {
|
|||
next_button.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
x: 30
|
||||
y: 490
|
||||
width: 301
|
||||
height: 40
|
||||
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)
|
||||
UiLogic.goToPage(PageEnum.WizardVpnMode, false)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,35 +15,52 @@ PageBase {
|
|||
id: back_from_setup_wizard
|
||||
}
|
||||
Caption {
|
||||
id: caption
|
||||
text: qsTr("Setup Wizard")
|
||||
}
|
||||
Item {
|
||||
x: 10
|
||||
y: 70
|
||||
width: 361
|
||||
height: 561
|
||||
|
||||
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 {
|
||||
x: 30
|
||||
y: 10
|
||||
width: 321
|
||||
height: 341
|
||||
Layout.fillWidth: true
|
||||
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.')
|
||||
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 {
|
||||
x: 30
|
||||
y: 400
|
||||
width: 321
|
||||
height: 71
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 15
|
||||
text: qsTr('OpenVPN profile will be installed')
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
BlueButtonType {
|
||||
id: next_button
|
||||
x: 30
|
||||
y: 490
|
||||
width: 301
|
||||
height: 40
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 15
|
||||
Layout.preferredHeight: 41
|
||||
text: qsTr("Start configuring")
|
||||
onClicked: {
|
||||
WizardLogic.onPushButtonLowFinishClicked()
|
||||
|
@ -50,3 +68,4 @@ PageBase {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
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 {
|
||||
x: 30
|
||||
y: 10
|
||||
width: 321
|
||||
height: 341
|
||||
Layout.fillWidth: true
|
||||
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).')
|
||||
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 {
|
||||
x: 30
|
||||
y: 400
|
||||
width: 321
|
||||
height: 71
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 15
|
||||
text: qsTr('OpenVPN over ShadowSocks profile will be installed')
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
BlueButtonType {
|
||||
id: next_button
|
||||
x: 30
|
||||
y: 490
|
||||
width: 301
|
||||
height: 40
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 15
|
||||
Layout.preferredHeight: 41
|
||||
text: qsTr("Next")
|
||||
onClicked: {
|
||||
UiLogic.goToPage(PageEnum.WizardVpnMode)
|
||||
UiLogic.goToPage(PageEnum.WizardVpnMode, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,37 +15,53 @@ PageBase {
|
|||
id: back_from_setup_wizard
|
||||
}
|
||||
Caption {
|
||||
id: caption
|
||||
text: qsTr("Setup Wizard")
|
||||
}
|
||||
Item {
|
||||
x: 10
|
||||
y: 70
|
||||
width: 361
|
||||
height: 561
|
||||
|
||||
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.')
|
||||
}
|
||||
|
||||
CheckBoxType {
|
||||
x: 30
|
||||
y: 350
|
||||
width: 301
|
||||
height: 71
|
||||
Layout.fillWidth: true
|
||||
text: qsTr('Turn on mode "VPN for selected sites"')
|
||||
checked: WizardLogic.checkBoxVpnModeChecked
|
||||
onCheckedChanged: {
|
||||
WizardLogic.checkBoxVpnModeChecked = checked
|
||||
}
|
||||
}
|
||||
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
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 15
|
||||
Layout.preferredHeight: 41
|
||||
text: qsTr("Start configuring")
|
||||
onClicked: {
|
||||
WizardLogic.onPushButtonVpnModeFinishClicked()
|
||||
|
@ -52,3 +69,4 @@ PageBase {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked:{
|
||||
tb.currentRow = index
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -11,7 +11,6 @@ PageProtocolBase {
|
|||
protocol: ProtocolEnum.ShadowSocks
|
||||
logic: UiLogic.protocolLogic(protocol)
|
||||
|
||||
enabled: logic.pageEnabled
|
||||
BackButton {
|
||||
id: back
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
|
||||
static QRegExp ipPortRegExp() { return QRegExp("^()([1-9]|[1-5]?[0-9]{2,4}|6[1-4][0-9]{3}|65[1-4][0-9]{2}|655[1-2][0-9]|6553[1-5])$"); }
|
||||
|
||||
static QRegExp domainRegExp() { return QRegExp("(((?!\\-))(xn\\-\\-)?[a-z0-9\\-_]{0,61}[a-z0-9]{1,1}\\.)*(xn\\-\\-)?([a-z0-9\\-]{1,61}|[a-z0-9\\-]{1,30})\\.[a-z]{2,}"); }
|
||||
static bool processIsRunning(const QString& fileName);
|
||||
static void killProcessByName(const QString &name);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QHostInfo>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <configurators/openvpn_configurator.h>
|
||||
|
@ -56,21 +57,27 @@ void VpnConnection::onConnectionStateChanged(VpnProtocol::VpnConnectionState sta
|
|||
IpcClient::Interface()->routeDeleteList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0");
|
||||
//qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << forwardIps.size();
|
||||
}
|
||||
QString dns1 = m_vpnConfiguration.value(config_key::dns1).toString();
|
||||
QString dns2 = m_vpnConfiguration.value(config_key::dns1).toString();
|
||||
|
||||
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(),
|
||||
QStringList() << m_settings.primaryDns() << m_settings.secondaryDns());
|
||||
QStringList() << dns1 << dns2);
|
||||
|
||||
|
||||
if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) {
|
||||
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), m_settings.getVpnIps(Settings::VpnOnlyForwardSites));
|
||||
QTimer::singleShot(1000, m_vpnProtocol.data(), [this](){
|
||||
addSitesRoutes(m_vpnProtocol->vpnGateway(), m_settings.routeMode());
|
||||
});
|
||||
}
|
||||
else if (m_settings.routeMode() == Settings::VpnAllExceptSites) {
|
||||
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0/1");
|
||||
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "128.0.0.0/1");
|
||||
|
||||
IpcClient::Interface()->routeAddList(m_vpnProtocol->routeGateway(), QStringList() << remoteAddress());
|
||||
IpcClient::Interface()->routeAddList(m_vpnProtocol->routeGateway(), m_settings.getVpnIps(Settings::VpnAllExceptSites));
|
||||
addSitesRoutes(m_vpnProtocol->routeGateway(), m_settings.routeMode());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (state == VpnProtocol::Error) {
|
||||
IpcClient::Interface()->flushDns();
|
||||
|
@ -89,6 +96,49 @@ const QString &VpnConnection::remoteAddress() const
|
|||
return m_remoteAddress;
|
||||
}
|
||||
|
||||
void VpnConnection::addSitesRoutes(const QString &gw, Settings::RouteMode mode)
|
||||
{
|
||||
QStringList ips;
|
||||
QStringList sites;
|
||||
const QVariantMap &m = m_settings.vpnSites(mode);
|
||||
for (auto i = m.constBegin(); i != m.constEnd(); ++i) {
|
||||
if (Utils::checkIpSubnetFormat(i.key())) {
|
||||
ips.append(i.key());
|
||||
}
|
||||
else {
|
||||
if (Utils::checkIpSubnetFormat(i.value().toString())) {
|
||||
ips.append(i.value().toString());
|
||||
}
|
||||
sites.append(i.key());
|
||||
}
|
||||
}
|
||||
ips.removeDuplicates();
|
||||
|
||||
// add all IPs immediately
|
||||
IpcClient::Interface()->routeAddList(gw, ips);
|
||||
|
||||
// re-resolve domains
|
||||
for (const QString &site: sites) {
|
||||
const auto &cbResolv = [this, site, gw, mode, ips](const QHostInfo &hostInfo){
|
||||
const QList<QHostAddress> &addresses = hostInfo.addresses();
|
||||
QString ipv4Addr;
|
||||
for (const QHostAddress &addr: hostInfo.addresses()) {
|
||||
if (addr.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) {
|
||||
const QString &ip = addr.toString();
|
||||
//qDebug() << "VpnConnection::addSitesRoutes updating site" << site << ip;
|
||||
if (!ips.contains(ip)) {
|
||||
IpcClient::Interface()->routeAddList(gw, QStringList() << ip);
|
||||
m_settings.addVpnSite(mode, site, ip);
|
||||
}
|
||||
flushDns();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
QHostInfo::lookupHost(site, this, cbResolv);
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<VpnProtocol> VpnConnection::vpnProtocol() const
|
||||
{
|
||||
return m_vpnProtocol;
|
||||
|
@ -149,12 +199,12 @@ QString VpnConnection::createVpnConfigurationForProto(int serverIndex,
|
|||
ErrorCode *errorCode)
|
||||
{
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
auto lastVpnConfig = getLastVpnConfig(containerConfig);
|
||||
QMap<Proto, QString> lastVpnConfig = getLastVpnConfig(containerConfig);
|
||||
|
||||
QString configData;
|
||||
if (lastVpnConfig.contains(proto)) {
|
||||
configData = lastVpnConfig.value(proto);
|
||||
configData = VpnConfigurator::processConfigWithLocalSettings(container, proto, configData);
|
||||
configData = VpnConfigurator::processConfigWithLocalSettings(serverIndex, container, proto, configData);
|
||||
|
||||
qDebug() << "VpnConnection::createVpnConfiguration: using saved config for" << ProtocolProps::protoToString(proto);
|
||||
}
|
||||
|
@ -165,7 +215,7 @@ QString VpnConnection::createVpnConfigurationForProto(int serverIndex,
|
|||
|
||||
QString configDataBeforeLocalProcessing = configData;
|
||||
|
||||
configData = VpnConfigurator::processConfigWithLocalSettings(container, proto, configData);
|
||||
configData = VpnConfigurator::processConfigWithLocalSettings(serverIndex, container, proto, configData);
|
||||
|
||||
|
||||
if (errorCode && e) {
|
||||
|
@ -211,6 +261,11 @@ QJsonObject VpnConnection::createVpnConfiguration(int serverIndex,
|
|||
Proto proto = ContainerProps::defaultProtocol(container);
|
||||
vpnConfiguration[config_key::vpnproto] = ProtocolProps::protoToString(proto);
|
||||
|
||||
auto dns = VpnConfigurator::getDnsForConfig(serverIndex);
|
||||
|
||||
vpnConfiguration[config_key::dns1] = dns.first;
|
||||
vpnConfiguration[config_key::dns2] = dns.second;
|
||||
|
||||
return vpnConfiguration;
|
||||
}
|
||||
|
||||
|
@ -240,11 +295,8 @@ void VpnConnection::connectToVpn(int serverIndex,
|
|||
|
||||
if (m_vpnProtocol) {
|
||||
disconnect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
|
||||
//qDebug() << "VpnConnection::connectToVpn 1";
|
||||
m_vpnProtocol->stop();
|
||||
//qDebug() << "VpnConnection::connectToVpn 2";
|
||||
m_vpnProtocol.reset();
|
||||
//qDebug() << "VpnConnection::connectToVpn 3";
|
||||
}
|
||||
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
|
|
|
@ -47,6 +47,7 @@ public:
|
|||
void flushDns();
|
||||
|
||||
const QString &remoteAddress() const;
|
||||
void addSitesRoutes(const QString &gw, Settings::RouteMode mode);
|
||||
|
||||
public slots:
|
||||
void connectToVpn(int serverIndex,
|
||||
|
|
|
@ -64,7 +64,7 @@ echo "Packaging ..."
|
|||
|
||||
#cd $DEPLOY_DIR
|
||||
|
||||
$QT_BIN_DIR/macdeployqt $OUT_APP_DIR/$APP_FILENAME -always-overwrite
|
||||
$QT_BIN_DIR/macdeployqt $OUT_APP_DIR/$APP_FILENAME -always-overwrite -qmldir=$PROJECT_DIR
|
||||
cp -av $BUILD_DIR/service/server/$APP_NAME-service.app/Contents/macOS/$APP_NAME-service $BUNDLE_DIR/Contents/macOS
|
||||
cp -Rv $PROJECT_DIR/deploy/data/macos/* $BUNDLE_DIR/Contents/macOS
|
||||
rm -f $BUNDLE_DIR/Contents/macOS/post_install.sh $BUNDLE_DIR/Contents/macOS/post_uninstall.sh
|
||||
|
|
|
@ -70,7 +70,6 @@ rem if not exist "%OUT_APP_DIR:"=%\%APP_FILENAME:"=%" break
|
|||
echo "Deploying..."
|
||||
|
||||
copy "%WORK_DIR:"=%\service\server\release\%APP_NAME:"=%-service.exe" %OUT_APP_DIR%
|
||||
copy "%WORK_DIR:"=%\platform\post-uninstall\release\post-uninstall.exe" %OUT_APP_DIR%
|
||||
|
||||
echo "Signing exe"
|
||||
cd %OUT_APP_DIR%
|
||||
|
@ -84,8 +83,6 @@ echo "Copying deploy data..."
|
|||
xcopy %DEPLOY_DATA_DIR% %OUT_APP_DIR% /s /e /y /i /f
|
||||
copy "%WORK_DIR:"=%\service\wireguard-service\release\wireguard-service.exe" %OUT_APP_DIR%\wireguard\
|
||||
|
||||
del %OUT_APP_DIR%\botand.dll
|
||||
|
||||
cd %SCRIPT_DIR%
|
||||
xcopy %SCRIPT_DIR:"=%\installer %RELEASE_DIR:"=%\installer /s /e /y /i /f
|
||||
mkdir %INSTALLER_DATA_DIR%
|
||||
|
|