moved the platform-specific android code for the new ui

This commit is contained in:
vladimir.kuznetsov 2023-07-24 16:31:04 +09:00
parent 5b8a0881b7
commit 0a1359ed16
31 changed files with 854 additions and 764 deletions

View file

@ -293,6 +293,7 @@ if(ANDROID)
${CMAKE_CURRENT_LIST_DIR}/platforms/android/android_notificationhandler.h
${CMAKE_CURRENT_LIST_DIR}/platforms/android/androidutils.h
${CMAKE_CURRENT_LIST_DIR}/platforms/android/androidvpnactivity.h
${CMAKE_CURRENT_LIST_DIR}/platforms/android/authResultReceiver.h
${CMAKE_CURRENT_LIST_DIR}/protocols/android_vpnprotocol.h
)
@ -301,6 +302,7 @@ if(ANDROID)
${CMAKE_CURRENT_LIST_DIR}/platforms/android/android_notificationhandler.cpp
${CMAKE_CURRENT_LIST_DIR}/platforms/android/androidutils.cpp
${CMAKE_CURRENT_LIST_DIR}/platforms/android/androidvpnactivity.cpp
${CMAKE_CURRENT_LIST_DIR}/platforms/android/authResultReceiver.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/android_vpnprotocol.cpp
)
endif()

View file

@ -4,6 +4,7 @@
#include <QFontDatabase>
#include <QMimeData>
#include <QQuickStyle>
#include <QResource>
#include <QStandardPaths>
#include <QTextDocument>
#include <QTimer>
@ -14,9 +15,12 @@
#include "version.h"
#include "platforms/ios/QRCodeReaderBase.h"
#if defined(Q_OS_ANDROID)
#include "platforms/android/android_controller.h"
#endif
#include "ui/pages.h"
#include "protocols/qml_register_protocols.h"
#include "ui/pages.h"
#if defined(Q_OS_IOS)
#include "platforms/ios/QtAppDelegate-C-Interface.h"
@ -33,7 +37,7 @@ AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecond
setQuitOnLastWindowClosed(false);
// Fix config file permissions
#ifdef Q_OS_LINUX && !defined(Q_OS_ANDROID)
#if defined Q_OS_LINUX && !defined(Q_OS_ANDROID)
{
QSettings s(ORGANIZATION_NAME, APPLICATION_NAME);
s.setValue("permFixed", true);
@ -87,16 +91,35 @@ void AmneziaApplication::init()
initModels();
initControllers();
#ifdef Q_OS_ANDROID
connect(AndroidController::instance(), &AndroidController::initialized, this,
[this](bool status, bool connected, const QDateTime &connectionDate) {
if (connected) {
m_connectionController->onConnectionStateChanged(Vpn::ConnectionState::Connected);
if (m_vpnConnection)
m_vpnConnection->restoreConnection();
}
});
if (!AndroidController::instance()->initialize()) {
qCritical() << QString("Init failed");
if (m_vpnConnection)
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Error);
return;
}
connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, m_importController.get(),
&ImportController::extractConfigFromData);
connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, m_pageController.get(),
&PageController::goToPageViewConfig);
#endif
m_notificationHandler.reset(NotificationHandler::create(nullptr));
connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, m_notificationHandler.get(),
&NotificationHandler::setConnectionState);
void openConnection();
void closeConnection();
connect(m_notificationHandler.get(), &NotificationHandler::raiseRequested, m_pageController.get(),
&PageController::raise);
&PageController::raiseMainWindow);
connect(m_notificationHandler.get(), &NotificationHandler::connectRequested, m_connectionController.get(),
&ConnectionController::openConnection);
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),

View file

@ -13,17 +13,16 @@
#include "android_controller.h"
#include "private/qandroidextras_p.h"
#include "ui/pages_logic/StartPageLogic.h"
#include "androidvpnactivity.h"
#include "androidutils.h"
#include "androidvpnactivity.h"
namespace {
AndroidController* s_instance = nullptr;
namespace
{
AndroidController *s_instance = nullptr;
constexpr auto PERMISSIONHELPER_CLASS =
"org/amnezia/vpn/qt/VPNPermissionHelper";
} // namespace
constexpr auto PERMISSIONHELPER_CLASS = "org/amnezia/vpn/qt/VPNPermissionHelper";
} // namespace
AndroidController::AndroidController() : QObject()
{
@ -33,109 +32,127 @@ AndroidController::AndroidController() : QObject()
auto activity = AndroidVPNActivity::instance();
connect(activity, &AndroidVPNActivity::serviceConnected, this, []() {
qDebug() << "Transact: service connected";
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_STATISTIC, "");
}, Qt::QueuedConnection);
connect(
activity, &AndroidVPNActivity::serviceConnected, this,
[]() {
qDebug() << "Transact: service connected";
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_STATISTIC, "");
},
Qt::QueuedConnection);
connect(activity, &AndroidVPNActivity::eventInitialized, this,
[this](const QString& parcelBody) {
// We might get multiple Init events as widgets, or fragments
// might query this.
if (m_init) {
return;
}
connect(
activity, &AndroidVPNActivity::eventInitialized, this,
[this](const QString &parcelBody) {
// We might get multiple Init events as widgets, or fragments
// might query this.
if (m_init) {
return;
}
qDebug() << "Transact: init";
qDebug() << "Transact: init";
m_init = true;
m_init = true;
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
qlonglong time = doc.object()["time"].toVariant().toLongLong();
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
qlonglong time = doc.object()["time"].toVariant().toLongLong();
isConnected = doc.object()["connected"].toBool();
isConnected = doc.object()["connected"].toBool();
if (isConnected) {
emit scheduleStatusCheckSignal();
}
if (isConnected) {
emit scheduleStatusCheckSignal();
}
emit initialized(
true, isConnected,
time > 0 ? QDateTime::fromMSecsSinceEpoch(time) : QDateTime());
emit initialized(true, isConnected, time > 0 ? QDateTime::fromMSecsSinceEpoch(time) : QDateTime());
setFallbackConnectedNotification();
}, Qt::QueuedConnection);
setFallbackConnectedNotification();
},
Qt::QueuedConnection);
connect(activity, &AndroidVPNActivity::eventConnected, this,
[this](const QString& parcelBody) {
Q_UNUSED(parcelBody);
qDebug() << "Transact: connected";
connect(
activity, &AndroidVPNActivity::eventConnected, this,
[this](const QString &parcelBody) {
Q_UNUSED(parcelBody);
qDebug() << "Transact: connected";
if (!isConnected) {
emit scheduleStatusCheckSignal();
}
if (!isConnected) {
emit scheduleStatusCheckSignal();
}
isConnected = true;
isConnected = true;
emit connectionStateChanged(VpnProtocol::Connected);
}, Qt::QueuedConnection);
emit connectionStateChanged(Vpn::ConnectionState::Connected);
},
Qt::QueuedConnection);
connect(activity, &AndroidVPNActivity::eventDisconnected, this,
[this]() {
qDebug() << "Transact: disconnected";
connect(
activity, &AndroidVPNActivity::eventDisconnected, this,
[this]() {
qDebug() << "Transact: disconnected";
isConnected = false;
isConnected = false;
emit connectionStateChanged(VpnProtocol::Disconnected);
}, Qt::QueuedConnection);
emit connectionStateChanged(Vpn::ConnectionState::Disconnected);
},
Qt::QueuedConnection);
connect(activity, &AndroidVPNActivity::eventStatisticUpdate, this,
[this](const QString& parcelBody) {
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
connect(
activity, &AndroidVPNActivity::eventStatisticUpdate, this,
[this](const QString &parcelBody) {
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
QString rx = doc.object()["rx_bytes"].toString();
QString tx = doc.object()["tx_bytes"].toString();
QString endpoint = doc.object()["endpoint"].toString();
QString deviceIPv4 = doc.object()["deviceIpv4"].toString();
QString rx = doc.object()["rx_bytes"].toString();
QString tx = doc.object()["tx_bytes"].toString();
QString endpoint = doc.object()["endpoint"].toString();
QString deviceIPv4 = doc.object()["deviceIpv4"].toString();
emit statusUpdated(rx, tx, endpoint, deviceIPv4);
}, Qt::QueuedConnection);
emit statusUpdated(rx, tx, endpoint, deviceIPv4);
},
Qt::QueuedConnection);
connect(activity, &AndroidVPNActivity::eventBackendLogs, this,
[this](const QString& parcelBody) {
qDebug() << "Transact: backend logs";
connect(
activity, &AndroidVPNActivity::eventBackendLogs, this,
[this](const QString &parcelBody) {
qDebug() << "Transact: backend logs";
QString buffer = parcelBody.toUtf8();
if (m_logCallback) {
m_logCallback(buffer);
}
}, Qt::QueuedConnection);
QString buffer = parcelBody.toUtf8();
if (m_logCallback) {
m_logCallback(buffer);
}
},
Qt::QueuedConnection);
connect(activity, &AndroidVPNActivity::eventActivationError, this,
[this](const QString& parcelBody) {
Q_UNUSED(parcelBody)
qDebug() << "Transact: error";
emit connectionStateChanged(VpnProtocol::Error);
}, Qt::QueuedConnection);
connect(
activity, &AndroidVPNActivity::eventActivationError, this,
[this](const QString &parcelBody) {
Q_UNUSED(parcelBody)
qDebug() << "Transact: error";
emit connectionStateChanged(Vpn::ConnectionState::Error);
},
Qt::QueuedConnection);
connect(activity, &AndroidVPNActivity::eventConfigImport, this,
[this](const QString& parcelBody) {
qDebug() << "Transact: config import";
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
connect(
activity, &AndroidVPNActivity::eventConfigImport, this,
[this](const QString &parcelBody) {
qDebug() << "Transact: config import";
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
QString buffer = doc.object()["config"].toString();
qDebug() << "Transact: config string" << buffer;
importConfig(buffer);
}, Qt::QueuedConnection);
QString buffer = doc.object()["config"].toString();
qDebug() << "Transact: config string" << buffer;
importConfigFromOutside(buffer);
},
Qt::QueuedConnection);
connect(activity, &AndroidVPNActivity::serviceDisconnected, this,
[this]() {
qDebug() << "Transact: service disconnected";
m_serviceConnected = false;
}, Qt::QueuedConnection);
connect(
activity, &AndroidVPNActivity::serviceDisconnected, this,
[this]() {
qDebug() << "Transact: service disconnected";
m_serviceConnected = false;
},
Qt::QueuedConnection);
}
AndroidController* AndroidController::instance() {
AndroidController *AndroidController::instance()
{
if (!s_instance) {
s_instance = new AndroidController();
}
@ -143,16 +160,13 @@ AndroidController* AndroidController::instance() {
return s_instance;
}
bool AndroidController::initialize(StartPageLogic *startPageLogic)
bool AndroidController::initialize()
{
qDebug() << "Initializing";
m_startPageLogic = startPageLogic;
// Hook in the native implementation for startActivityForResult into the JNI
JNINativeMethod methods[]{{"startActivityForResult",
"(Landroid/content/Intent;)V",
reinterpret_cast<void*>(startActivityForResult)}};
JNINativeMethod methods[] { { "startActivityForResult", "(Landroid/content/Intent;)V",
reinterpret_cast<void *>(startActivityForResult) } };
QJniObject javaClass(PERMISSIONHELPER_CLASS);
QJniEnvironment env;
jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
@ -168,11 +182,9 @@ ErrorCode AndroidController::start()
{
qDebug() << "Prompting for VPN permission";
QJniObject activity = AndroidUtils::getActivity();
auto appContext = activity.callObjectMethod(
"getApplicationContext", "()Landroid/content/Context;");
QJniObject::callStaticMethod<void>(
PERMISSIONHELPER_CLASS, "startService", "(Landroid/content/Context;)V",
appContext.object());
auto appContext = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
QJniObject::callStaticMethod<void>(PERMISSIONHELPER_CLASS, "startService", "(Landroid/content/Context;)V",
appContext.object());
QJsonDocument doc(m_vpnConfig);
AndroidVPNActivity::sendToService(ServiceAction::ACTION_ACTIVATE, doc.toJson());
@ -180,7 +192,8 @@ ErrorCode AndroidController::start()
return NoError;
}
void AndroidController::stop() {
void AndroidController::stop()
{
qDebug() << "AndroidController::stop";
AndroidVPNActivity::sendToService(ServiceAction::ACTION_DEACTIVATE, QString());
@ -188,16 +201,16 @@ void AndroidController::stop() {
// Activates the tunnel that is currently set
// in the VPN Service
void AndroidController::resumeStart() {
void AndroidController::resumeStart()
{
AndroidVPNActivity::sendToService(ServiceAction::ACTION_RESUME_ACTIVATE, QString());
}
/*
* Sets the current notification text that is shown
*/
void AndroidController::setNotificationText(const QString& title,
const QString& message,
int timerSec) {
void AndroidController::setNotificationText(const QString &title, const QString &message, int timerSec)
{
QJsonObject args;
args["title"] = title;
args["message"] = message;
@ -207,7 +220,8 @@ void AndroidController::setNotificationText(const QString& title,
AndroidVPNActivity::sendToService(ServiceAction::ACTION_SET_NOTIFICATION_TEXT, doc.toJson());
}
void AndroidController::shareConfig(const QString& configContent, const QString& suggestedName) {
void AndroidController::shareConfig(const QString &configContent, const QString &suggestedName)
{
AndroidVPNActivity::saveFileAs(configContent, suggestedName);
}
@ -216,7 +230,8 @@ void AndroidController::shareConfig(const QString& configContent, const QString&
* switches into the Connected state without the app open
* e.g via always-on vpn
*/
void AndroidController::setFallbackConnectedNotification() {
void AndroidController::setFallbackConnectedNotification()
{
QJsonObject args;
args["title"] = tr("AmneziaVPN");
//% "Ready for you to connect"
@ -227,11 +242,13 @@ void AndroidController::setFallbackConnectedNotification() {
AndroidVPNActivity::sendToService(ServiceAction::ACTION_SET_NOTIFICATION_FALLBACK, doc.toJson());
}
void AndroidController::checkStatus() {
void AndroidController::checkStatus()
{
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_STATISTIC, QString());
}
void AndroidController::getBackendLogs(std::function<void(const QString&)>&& a_callback) {
void AndroidController::getBackendLogs(std::function<void(const QString &)> &&a_callback)
{
qDebug() << "get logs";
m_logCallback = std::move(a_callback);
@ -239,16 +256,13 @@ void AndroidController::getBackendLogs(std::function<void(const QString&)>&& a_c
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_GET_LOG, QString());
}
void AndroidController::cleanupBackendLogs() {
void AndroidController::cleanupBackendLogs()
{
qDebug() << "cleanup logs";
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_CLEANUP_LOG, QString());
}
void AndroidController::importConfig(const QString& data){
m_startPageLogic->importAnyFile(data);
}
const QJsonObject &AndroidController::vpnConfig() const
{
return m_vpnConfig;
@ -285,31 +299,29 @@ void AndroidController::startActivityForResult(JNIEnv *env, jobject, jobject int
qDebug() << "start vpnPermissionHelper";
Q_UNUSED(env);
QtAndroidPrivate::startActivity(intent, 1337,
[](int receiverRequestCode, int resultCode,
const QJniObject& data) {
// Currently this function just used in
// VPNService.kt::checkPermissions. So the result
// we're getting is if the User gave us the
// Vpn.bind permission. In case of NO we should
// abort.
Q_UNUSED(receiverRequestCode);
Q_UNUSED(data);
QtAndroidPrivate::startActivity(intent, 1337, [](int receiverRequestCode, int resultCode, const QJniObject &data) {
// Currently this function just used in
// VPNService.kt::checkPermissions. So the result
// we're getting is if the User gave us the
// Vpn.bind permission. In case of NO we should
// abort.
Q_UNUSED(receiverRequestCode);
Q_UNUSED(data);
AndroidController* controller = AndroidController::instance();
if (!controller) {
return;
}
AndroidController *controller = AndroidController::instance();
if (!controller) {
return;
}
if (resultCode == ACTIVITY_RESULT_OK) {
qDebug() << "VPN PROMPT RESULT - Accepted";
controller->resumeStart();
return;
}
// If the request got rejected abort the current
// connection.
qWarning() << "VPN PROMPT RESULT - Rejected";
emit controller->connectionStateChanged(VpnProtocol::Disconnected);
});
if (resultCode == ACTIVITY_RESULT_OK) {
qDebug() << "VPN PROMPT RESULT - Accepted";
controller->resumeStart();
return;
}
// If the request got rejected abort the current
// connection.
qWarning() << "VPN PROMPT RESULT - Rejected";
emit controller->connectionStateChanged(Vpn::ConnectionState::Disconnected);
});
return;
}

View file

@ -8,36 +8,32 @@
#include <QJniEnvironment>
#include <QJniObject>
#include "ui/pages_logic/StartPageLogic.h"
#include "protocols/vpnprotocol.h"
using namespace amnezia;
class AndroidController : public QObject
{
Q_OBJECT
public:
explicit AndroidController();
static AndroidController* instance();
static AndroidController *instance();
virtual ~AndroidController() override = default;
bool initialize(StartPageLogic *startPageLogic);
bool initialize();
ErrorCode start();
void stop();
void resumeStart();
void checkStatus();
void setNotificationText(const QString& title, const QString& message, int timerSec);
void shareConfig(const QString& data, const QString& suggestedName);
void setNotificationText(const QString &title, const QString &message, int timerSec);
void shareConfig(const QString &data, const QString &suggestedName);
void setFallbackConnectedNotification();
void getBackendLogs(std::function<void(const QString&)>&& callback);
void getBackendLogs(std::function<void(const QString &)> &&callback);
void cleanupBackendLogs();
void importConfig(const QString& data);
const QJsonObject &vpnConfig() const;
void setVpnConfig(const QJsonObject &newVpnConfig);
@ -45,18 +41,20 @@ public:
void startQrReaderActivity();
signals:
void connectionStateChanged(VpnProtocol::VpnConnectionState state);
void connectionStateChanged(Vpn::ConnectionState state);
// This signal is emitted when the controller is initialized. Note that the
// VPN tunnel can be already active. In this case, "connected" should be set
// to true and the "connectionDate" should be set to the activation date if
// known.
// If "status" is set to false, the backend service is considered unavailable.
void initialized(bool status, bool connected, const QDateTime& connectionDate);
void initialized(bool status, bool connected, const QDateTime &connectionDate);
void statusUpdated(QString totalRx, QString totalTx, QString endpoint, QString deviceIPv4);
void scheduleStatusCheckSignal();
void importConfigFromOutside(QString &data);
protected slots:
void scheduleStatusCheckSlot();
@ -65,12 +63,10 @@ private:
QJsonObject m_vpnConfig;
StartPageLogic *m_startPageLogic;
bool m_serviceConnected = false;
std::function<void(const QString&)> m_logCallback;
std::function<void(const QString &)> m_logCallback;
static void startActivityForResult(JNIEnv* env, jobject /*thiz*/, jobject intent);
static void startActivityForResult(JNIEnv *env, jobject /*thiz*/, jobject intent);
bool isConnected = false;

View file

@ -0,0 +1,16 @@
#include "authResultReceiver.h"
AuthResultReceiver::AuthResultReceiver(QSharedPointer<AuthResultNotifier> &notifier) : m_notifier(notifier)
{
}
void AuthResultReceiver::handleActivityResult(int receiverRequestCode, int resultCode, const QJniObject &data)
{
qDebug() << "receiverRequestCode" << receiverRequestCode << "resultCode" << resultCode;
if (resultCode == -1) { // ResultOK
emit m_notifier->authSuccessful();
} else {
emit m_notifier->authFailed();
}
}

View file

@ -0,0 +1,32 @@
#ifndef AUTHRESULTRECEIVER_H
#define AUTHRESULTRECEIVER_H
#include <QJniObject>
#include <private/qandroidextras_p.h>
class AuthResultNotifier : public QObject
{
Q_OBJECT
public:
AuthResultNotifier(QObject *parent = nullptr) : QObject(parent) {};
signals:
void authFailed();
void authSuccessful();
};
/* Auth result handler for Android */
class AuthResultReceiver final : public QAndroidActivityResultReceiver
{
public:
AuthResultReceiver(QSharedPointer<AuthResultNotifier> &notifier);
void handleActivityResult(int receiverRequestCode, int resultCode, const QJniObject &data) override;
private:
QSharedPointer<AuthResultNotifier> m_notifier;
};
#endif // AUTHRESULTRECEIVER_H

View file

@ -5,27 +5,28 @@
#include <QThread>
#include "logger.h"
#include "wireguardprotocol.h"
#include "utilities.h"
#include "wireguardprotocol.h"
#include "mozilla/localsocketcontroller.h"
WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject* parent) : VpnProtocol(configuration, parent)
WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject *parent)
: VpnProtocol(configuration, parent)
{
m_configFile.setFileName(QDir::tempPath() + QDir::separator() + serviceName() + ".conf");
writeWireguardConfiguration(configuration);
// MZ
#if defined(MZ_LINUX)
//m_impl.reset(new LinuxController());
// m_impl.reset(new LinuxController());
#elif defined(MZ_MACOS) // || defined(MZ_WINDOWS)
m_impl.reset(new LocalSocketController());
connect(m_impl.get(), &ControllerImpl::connected, this, [this](const QString& pubkey, const QDateTime& connectionTimestamp) {
emit connectionStateChanged(VpnProtocol::Connected);
});
connect(m_impl.get(), &ControllerImpl::disconnected, this, [this](){
emit connectionStateChanged(VpnProtocol::Disconnected);
});
connect(m_impl.get(), &ControllerImpl::connected, this,
[this](const QString &pubkey, const QDateTime &connectionTimestamp) {
emit connectionStateChanged(Vpn::ConnectionState::Connected);
});
connect(m_impl.get(), &ControllerImpl::disconnected, this,
[this]() { emit connectionStateChanged(Vpn::ConnectionState::Disconnected); });
m_impl->initialize(nullptr, nullptr);
#endif
}
@ -74,9 +75,10 @@ void WireguardProtocol::stop()
setConnectionState(Vpn::ConnectionState::Disconnected);
});
connect(m_wireguardStopProcess.data(), &PrivilegedProcess::stateChanged, this, [this](QProcess::ProcessState newState) {
qDebug() << "WireguardProtocol::WireguardProtocol Stop stateChanged" << newState;
});
connect(m_wireguardStopProcess.data(), &PrivilegedProcess::stateChanged, this,
[this](QProcess::ProcessState newState) {
qDebug() << "WireguardProtocol::WireguardProtocol Stop stateChanged" << newState;
});
#ifdef Q_OS_LINUX
if (IpcClient::Interface()) {
@ -143,8 +145,8 @@ void WireguardProtocol::writeWireguardConfiguration(const QJsonObject &configura
m_isConfigLoaded = true;
qDebug().noquote() << QString("Set config data") << configPath();
qDebug().noquote() << QString("Set config data") << configuration.value(ProtocolProps::key_proto_config_data(Proto::WireGuard)).toString().toUtf8();
qDebug().noquote() << QString("Set config data")
<< configuration.value(ProtocolProps::key_proto_config_data(Proto::WireGuard)).toString().toUtf8();
}
QString WireguardProtocol::configPath() const
@ -156,7 +158,8 @@ void WireguardProtocol::updateRouteGateway(QString line)
{
// TODO: fix for macos
line = line.split("ROUTE_GATEWAY", Qt::SkipEmptyParts).at(1);
if (!line.contains("/")) return;
if (!line.contains("/"))
return;
m_routeGateway = line.split("/", Qt::SkipEmptyParts).first();
m_routeGateway.replace(" ", "");
qDebug() << "Set VPN route gateway" << m_routeGateway;
@ -216,13 +219,13 @@ ErrorCode WireguardProtocol::start()
setConnectionState(Vpn::ConnectionState::Disconnected);
});
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::stateChanged, this, [this](QProcess::ProcessState newState) {
qDebug() << "WireguardProtocol::WireguardProtocol stateChanged" << newState;
});
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::stateChanged, this,
[this](QProcess::ProcessState newState) {
qDebug() << "WireguardProtocol::WireguardProtocol stateChanged" << newState;
});
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::finished, this, [this]() {
setConnectionState(Vpn::ConnectionState::Connected);
});
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::finished, this,
[this]() { setConnectionState(Vpn::ConnectionState::Connected); });
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::readyRead, this, [this]() {
QRemoteObjectPendingReply<QByteArray> reply = m_wireguardStartProcess->readAll();
@ -250,7 +253,6 @@ ErrorCode WireguardProtocol::start()
void WireguardProtocol::updateVpnGateway(const QString &line)
{
}
QString WireguardProtocol::serviceName() const
@ -261,9 +263,9 @@ QString WireguardProtocol::serviceName() const
QStringList WireguardProtocol::stopArgs()
{
#ifdef Q_OS_WIN
return {"--remove", configPath()};
return { "--remove", configPath() };
#elif defined Q_OS_LINUX
return {"down", "wg99"};
return { "down", "wg99" };
#else
return {};
#endif
@ -272,11 +274,10 @@ QStringList WireguardProtocol::stopArgs()
QStringList WireguardProtocol::startArgs()
{
#ifdef Q_OS_WIN
return {"--add", configPath()};
return { "--add", configPath() };
#elif defined Q_OS_LINUX
return {"up", "wg99"};
return { "up", "wg99" };
#else
return {};
#endif
}

View file

@ -194,7 +194,6 @@
<file>ui/qml/Controls2/HorizontalRadioButton.qml</file>
<file>ui/qml/Controls2/VerticalRadioButton.qml</file>
<file>ui/qml/Controls2/SwitcherType.qml</file>
<file>ui/qml/Pages2/PageTest.qml</file>
<file>ui/qml/Controls2/TabButtonType.qml</file>
<file>ui/qml/Pages2/PageSetupWizardProtocolSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardInstalling.qml</file>
@ -278,5 +277,6 @@
<file>ui/qml/Pages2/PageServiceSftpSettings.qml</file>
<file>images/controls/copy.svg</file>
<file>ui/qml/Pages2/PageServiceTorWebsiteSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardQrReader.qml</file>
</qresource>
</RCC>

View file

@ -11,9 +11,12 @@
#include "configurators/openvpn_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "qrcodegen.hpp"
#include "core/errorstrings.h"
#ifdef Q_OS_ANDROID
#include "platforms/android/android_controller.h"
#include "platforms/android/androidutils.h"
#endif
#include "qrcodegen.hpp"
ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
@ -25,6 +28,14 @@ ExportController::ExportController(const QSharedPointer<ServersModel> &serversMo
m_settings(settings),
m_configurator(configurator)
{
#ifdef Q_OS_ANDROID
m_authResultNotifier.reset(new AuthResultNotifier);
m_authResultReceiver.reset(new AuthResultReceiver(m_authResultNotifier));
connect(m_authResultNotifier.get(), &AuthResultNotifier::authFailed, this,
[this]() { emit exportErrorOccurred(tr("Access error!")); });
connect(m_authResultNotifier.get(), &AuthResultNotifier::authSuccessful, this,
&ExportController::generateFullAccessConfig);
#endif
}
void ExportController::generateFullAccessConfig()
@ -44,6 +55,27 @@ void ExportController::generateFullAccessConfig()
emit exportConfigChanged();
}
#if defined(Q_OS_ANDROID)
void ExportController::generateFullAccessConfigAndroid()
{
/* We use builtin keyguard for ssh key export protection on Android */
QJniObject activity = AndroidUtils::getActivity();
auto appContext = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
if (appContext.isValid()) {
auto intent = QJniObject::callStaticObjectMethod("org/amnezia/vpn/AuthHelper", "getAuthIntent",
"(Landroid/content/Context;)Landroid/content/Intent;",
appContext.object());
if (intent.isValid()) {
if (intent.object<jobject>() != nullptr) {
QtAndroidPrivate::startActivity(intent.object<jobject>(), 1, m_authResultReceiver.get());
}
} else {
generateFullAccessConfig();
}
}
}
#endif
void ExportController::generateConnectionConfig()
{
clearPreviousConfig();
@ -194,6 +226,35 @@ void ExportController::saveFile()
QDesktopServices::openUrl(fi.absoluteDir().absolutePath());
}
void ExportController::shareFile()
{
#if defined Q_OS_IOS
ext.replace("*", "");
QString fileName = QDir::tempPath() + "/" + suggestedName;
if (fileName.isEmpty())
return;
if (!fileName.endsWith(ext))
fileName.append(ext);
QFile::remove(fileName);
QFile save(fileName);
save.open(QIODevice::WriteOnly);
save.write(data.toUtf8());
save.close();
QStringList filesToSend;
filesToSend.append(fileName);
MobileUtils::shareText(filesToSend);
return;
#endif
#if defined Q_OS_ANDROID
AndroidController::instance()->shareConfig(m_config, "amnezia_config");
return;
#endif
}
QList<QString> ExportController::generateQrCodeImageSeries(const QByteArray &data)
{
double k = 850;

View file

@ -6,6 +6,9 @@
#include "configurators/vpn_configurator.h"
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
#ifdef Q_OS_ANDROID
#include "platforms/android/authResultReceiver.h"
#endif
class ExportController : public QObject
{
@ -22,6 +25,9 @@ public:
public slots:
void generateFullAccessConfig();
#if defined(Q_OS_ANDROID)
void generateFullAccessConfigAndroid();
#endif
void generateConnectionConfig();
void generateOpenVpnConfig();
void generateWireGuardConfig();
@ -30,6 +36,7 @@ public slots:
QList<QString> getQrCodes();
void saveFile();
void shareFile();
signals:
void generateConfig(int type);
@ -52,6 +59,11 @@ private:
QString m_config;
QList<QString> m_qrCodes;
#ifdef Q_OS_ANDROID
QSharedPointer<AuthResultNotifier> m_authResultNotifier;
QSharedPointer<QAndroidActivityResultReceiver> m_authResultReceiver;
#endif
};
#endif // EXPORTCONTROLLER_H

View file

@ -2,8 +2,15 @@
#include <QFile>
#include <QFileInfo>
#include <QStandardPaths>
#include "core/errorstrings.h"
#ifdef Q_OS_ANDROID
#include "../../platforms/android/android_controller.h"
#include "../../platforms/android/androidutils.h"
#include <QJniObject>
#endif
#include "utilities.h"
namespace
{
@ -41,33 +48,58 @@ ImportController::ImportController(const QSharedPointer<ServersModel> &serversMo
const std::shared_ptr<Settings> &settings, QObject *parent)
: QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel), m_settings(settings)
{
#ifdef Q_OS_ANDROID
// Set security screen for Android app
AndroidUtils::runOnAndroidThreadSync([]() {
QJniObject activity = AndroidUtils::getActivity();
QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
if (window.isValid()) {
const int FLAG_SECURE = 8192;
window.callMethod<void>("addFlags", "(I)V", FLAG_SECURE);
}
});
#endif
}
void ImportController::extractConfigFromFile(const QUrl &fileUrl)
void ImportController::extractConfigFromFile()
{
QFile file(fileUrl.toLocalFile());
QString fileName = Utils::getFileName(Q_NULLPTR, tr("Open config file"),
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),
"*.vpn *.ovpn *.conf");
QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) {
QString data = file.readAll();
auto configFormat = checkConfigFormat(data);
if (configFormat == ConfigTypes::OpenVpn) {
m_config = extractOpenVpnConfig(data);
} else if (configFormat == ConfigTypes::WireGuard) {
m_config = extractWireGuardConfig(data);
} else {
m_config = extractAmneziaConfig(data);
}
extractConfigFromData(data);
m_configFileName = QFileInfo(file.fileName()).fileName();
}
}
void ImportController::extractConfigFromData(QString &data)
{
auto configFormat = checkConfigFormat(data);
if (configFormat == ConfigTypes::OpenVpn) {
m_config = extractOpenVpnConfig(data);
} else if (configFormat == ConfigTypes::WireGuard) {
m_config = extractWireGuardConfig(data);
} else {
m_config = extractAmneziaConfig(data);
}
}
void ImportController::extractConfigFromCode(QString code)
{
m_config = extractAmneziaConfig(code);
m_configFileName = "";
}
void ImportController::extractConfigFromQr()
{
#ifdef Q_OS_ANDROID
AndroidController::instance()->startQrReaderActivity();
#endif
}
QString ImportController::getConfig()
{
return QJsonDocument(m_config).toJson(QJsonDocument::Indented);

View file

@ -3,10 +3,10 @@
#include <QObject>
#include "core/defs.h"
#include "containers/containers_defs.h"
#include "ui/models/servers_model.h"
#include "core/defs.h"
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
class ImportController : public QObject
{
@ -14,13 +14,14 @@ class ImportController : public QObject
public:
explicit ImportController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const std::shared_ptr<Settings> &settings,
QObject *parent = nullptr);
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
public slots:
void importConfig();
void extractConfigFromFile(const QUrl &fileUrl);
void extractConfigFromFile();
void extractConfigFromData(QString &data);
void extractConfigFromCode(QString code);
void extractConfigFromQr();
QString getConfig();
QString getConfigFileName();
@ -39,7 +40,6 @@ private:
QJsonObject m_config;
QString m_configFileName;
};
#endif // IMPORTCONTROLLER_H

View file

@ -8,6 +8,34 @@
#include "core/servercontroller.h"
#include "utilities.h"
namespace
{
#ifdef Q_OS_WINDOWS
QString getNextDriverLetter()
{
QProcess drivesProc;
drivesProc.start("wmic logicaldisk get caption");
drivesProc.waitForFinished();
QString drives = drivesProc.readAll();
qDebug() << drives;
QString letters = "CFGHIJKLMNOPQRSTUVWXYZ";
QString letter;
for (int i = letters.size() - 1; i > 0; i--) {
letter = letters.at(i);
if (!drives.contains(letter + ":"))
break;
}
if (letter == "C:") {
// set err info
qDebug() << "Can't find free drive letter";
return "";
}
return letter;
}
#endif
}
InstallController::InstallController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const std::shared_ptr<Settings> &settings, QObject *parent)
@ -15,6 +43,17 @@ InstallController::InstallController(const QSharedPointer<ServersModel> &servers
{
}
InstallController::~InstallController()
{
#ifdef Q_OS_WINDOWS
for (QSharedPointer<QProcess> process : m_sftpMountProcesses) {
Utils::signalCtrl(process->processId(), CTRL_C_EVENT);
process->kill();
process->waitForFinished();
}
#endif
}
void InstallController::install(DockerContainer container, int port, TransportProto transportProto)
{
Proto mainProto = ContainerProps::defaultProtocol(container);

View file

@ -16,6 +16,7 @@ public:
explicit InstallController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
~InstallController();
public slots:
void install(DockerContainer container, int port, TransportProto transportProto);

View file

@ -1,7 +1,9 @@
#include "pageController.h"
PageController::PageController(const QSharedPointer<ServersModel> &serversModel,
QObject *parent) : QObject(parent), m_serversModel(serversModel)
#include <QApplication>
PageController::PageController(const QSharedPointer<ServersModel> &serversModel, QObject *parent)
: QObject(parent), m_serversModel(serversModel)
{
}
@ -24,3 +26,24 @@ QString PageController::getPagePath(PageLoader::PageEnum page)
QString pageName = metaEnum.valueToKey(static_cast<int>(page));
return "qrc:/ui/qml/Pages2/" + pageName + ".qml";
}
void PageController::closeWindow()
{
#ifdef Q_OS_ANDROID
qApp->quit();
#else
if (m_serversModel->getServersCount() == 0) {
qApp->quit();
} else {
emit hideMainWindow();
}
#endif
}
void PageController::keyPressEvent(Qt::Key key)
{
switch (key) {
case Qt::Key_Back: emit closePage();
default: return;
}
}

View file

@ -41,6 +41,7 @@ namespace PageLoader
PageSetupWizardConfigSource,
PageSetupWizardTextKey,
PageSetupWizardViewConfig,
PageSetupWizardQrReader,
PageProtocolOpenVpnSettings,
PageProtocolShadowSocksSettings,
@ -67,15 +68,25 @@ public slots:
QString getInitialPage();
QString getPagePath(PageLoader::PageEnum page);
void closeWindow();
void keyPressEvent(Qt::Key key);
signals:
void goToPageHome();
void goToPageSettings();
void goToPageViewConfig();
void closePage();
void restorePageHomeState(bool isContainerInstalled = false);
void replaceStartPage();
void showErrorMessage(QString errorMessage);
void showInfoMessage(QString message);
void showBusyIndicator(bool visible);
void raise();
void hideMainWindow();
void raiseMainWindow();
private:
QSharedPointer<ServersModel> m_serversModel;

View file

@ -6,20 +6,21 @@
#include "VpnLogic.h"
#include "core/errorstrings.h"
#include <core/servercontroller.h>
#include <QTimer>
#include <core/servercontroller.h>
#if defined(Q_OS_ANDROID)
#include "../../platforms/android/androidutils.h"
#include "../../platforms/android/androidutils.h"
#endif
ServerSettingsLogic::ServerSettingsLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent),
m_labelWaitInfoVisible{true},
m_pushButtonClearClientCacheVisible{true},
m_pushButtonShareFullVisible{true},
m_pushButtonClearClientCacheText{tr("Clear client cached profile")}
{ }
ServerSettingsLogic::ServerSettingsLogic(UiLogic *logic, QObject *parent)
: PageLogicBase(logic, parent),
m_labelWaitInfoVisible { true },
m_pushButtonClearClientCacheVisible { true },
m_pushButtonShareFullVisible { true },
m_pushButtonClearClientCacheText { tr("Clear client cached profile") }
{
}
void ServerSettingsLogic::onUpdatePage()
{
@ -33,11 +34,11 @@ void ServerSettingsLogic::onUpdatePage()
const QString &userName = server.value(config_key::userName).toString();
const QString &hostName = server.value(config_key::hostName).toString();
QString name = QString("%1%2%3%4%5")
.arg(userName)
.arg(userName.isEmpty() ? "" : "@")
.arg(hostName)
.arg(port.isEmpty() ? "" : ":")
.arg(port);
.arg(userName)
.arg(userName.isEmpty() ? "" : "@")
.arg(hostName)
.arg(port.isEmpty() ? "" : ":")
.arg(port);
set_labelServerText(name);
set_lineEditDescriptionText(server.value(config_key::description).toString());
@ -49,15 +50,15 @@ void ServerSettingsLogic::onUpdatePage()
void ServerSettingsLogic::onPushButtonForgetServer()
{
if (m_settings->defaultServerIndex() == uiLogic()->m_selectedServerIndex && uiLogic()->m_vpnConnection->isConnected()) {
if (m_settings->defaultServerIndex() == uiLogic()->m_selectedServerIndex
&& uiLogic()->m_vpnConnection->isConnected()) {
uiLogic()->pageLogic<VpnLogic>()->onDisconnect();
}
m_settings->removeServer(uiLogic()->m_selectedServerIndex);
if (m_settings->defaultServerIndex() == uiLogic()->m_selectedServerIndex) {
m_settings->setDefaultServer(0);
}
else if (m_settings->defaultServerIndex() > uiLogic()->m_selectedServerIndex) {
} else if (m_settings->defaultServerIndex() > uiLogic()->m_selectedServerIndex) {
m_settings->setDefaultServer(m_settings->defaultServerIndex() - 1);
}
@ -65,14 +66,12 @@ void ServerSettingsLogic::onPushButtonForgetServer()
m_settings->setDefaultServer(-1);
}
uiLogic()->m_selectedServerIndex = -1;
uiLogic()->onUpdateAllPages();
if (m_settings->serversCount() == 0) {
uiLogic()->setStartPage(Page::Start);
}
else {
} else {
uiLogic()->closePage();
}
}
@ -86,9 +85,7 @@ void ServerSettingsLogic::onPushButtonClearClientCacheClicked()
m_settings->clearLastConnectionConfig(uiLogic()->m_selectedServerIndex, container);
}
QTimer::singleShot(3000, this, [this]() {
set_pushButtonClearClientCacheText(tr("Clear client cached profile"));
});
QTimer::singleShot(3000, this, [this]() { set_pushButtonClearClientCacheText(tr("Clear client cached profile")); });
}
void ServerSettingsLogic::onLineEditDescriptionEditingFinished()
@ -111,7 +108,7 @@ void authResultReceiver::handleActivityResult(int receiverRequestCode, int resul
{
qDebug() << "receiverRequestCode" << receiverRequestCode << "resultCode" << resultCode;
if (resultCode == -1) { //ResultOK
if (resultCode == -1) { // ResultOK
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(m_serverIndex, DockerContainer::None);
emit uiLogic()->goToShareProtocolPage(Proto::Any);
}
@ -121,26 +118,27 @@ void authResultReceiver::handleActivityResult(int receiverRequestCode, int resul
void ServerSettingsLogic::onPushButtonShareFullClicked()
{
#if defined(Q_OS_ANDROID)
/* We use builtin keyguard for ssh key export protection on Android */
/* We use builtin keyguard for ssh key export protection on Android */
QJniObject activity = AndroidUtils::getActivity();
auto appContext = activity.callObjectMethod(
"getApplicationContext", "()Landroid/content/Context;");
auto appContext = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
if (appContext.isValid()) {
QAndroidActivityResultReceiver *receiver = new authResultReceiver(uiLogic(), uiLogic()->m_selectedServerIndex);
auto intent = QJniObject::callStaticObjectMethod(
"org/amnezia/vpn/AuthHelper", "getAuthIntent",
"(Landroid/content/Context;)Landroid/content/Intent;", appContext.object());
auto intent = QJniObject::callStaticObjectMethod("org/amnezia/vpn/AuthHelper", "getAuthIntent",
"(Landroid/content/Context;)Landroid/content/Intent;",
appContext.object());
if (intent.isValid()) {
if (intent.object<jobject>() != nullptr) {
QtAndroidPrivate::startActivity(intent.object<jobject>(), 1, receiver);
}
} else {
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->m_selectedServerIndex, DockerContainer::None);
QtAndroidPrivate::startActivity(intent.object<jobject>(), 1, receiver);
}
} else {
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->m_selectedServerIndex,
DockerContainer::None);
emit uiLogic()->goToShareProtocolPage(Proto::Any);
}
}
#else
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->m_selectedServerIndex, DockerContainer::None);
uiLogic()->pageLogic<ShareConnectionLogic>()->updateSharingPage(uiLogic()->m_selectedServerIndex,
DockerContainer::None);
emit uiLogic()->goToShareProtocolPage(Proto::Any);
#endif
}

View file

@ -1,68 +1,69 @@
#include "StartPageLogic.h"
#include "ViewConfigLogic.h"
#include "core/errorstrings.h"
#include "../uilogic.h"
#include "configurators/ssh_configurator.h"
#include "configurators/vpn_configurator.h"
#include "../uilogic.h"
#include "utilities.h"
#include "core/errorstrings.h"
#include "core/servercontroller.h"
#include "utilities.h"
#include <QEventLoop>
#include <QFileDialog>
#include <QStandardPaths>
#include <QEventLoop>
#ifdef Q_OS_ANDROID
#include <QJniObject>
#include "../../platforms/android/androidutils.h"
#include "../../platforms/android/android_controller.h"
#include "../../platforms/android/android_controller.h"
#include "../../platforms/android/androidutils.h"
#include <QJniObject>
#endif
namespace {
enum class ConfigTypes {
Amnezia,
OpenVpn,
WireGuard
};
ConfigTypes checkConfigFormat(const QString &config)
namespace
{
const QString openVpnConfigPatternCli = "client";
const QString openVpnConfigPatternProto1 = "proto tcp";
const QString openVpnConfigPatternProto2 = "proto udp";
const QString openVpnConfigPatternDriver1 = "dev tun";
const QString openVpnConfigPatternDriver2 = "dev tap";
enum class ConfigTypes {
Amnezia,
OpenVpn,
WireGuard
};
const QString wireguardConfigPatternSectionInterface = "[Interface]";
const QString wireguardConfigPatternSectionPeer = "[Peer]";
ConfigTypes checkConfigFormat(const QString &config)
{
const QString openVpnConfigPatternCli = "client";
const QString openVpnConfigPatternProto1 = "proto tcp";
const QString openVpnConfigPatternProto2 = "proto udp";
const QString openVpnConfigPatternDriver1 = "dev tun";
const QString openVpnConfigPatternDriver2 = "dev tap";
if (config.contains(openVpnConfigPatternCli) &&
(config.contains(openVpnConfigPatternProto1) || config.contains(openVpnConfigPatternProto2)) &&
(config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) {
return ConfigTypes::OpenVpn;
} else if (config.contains(wireguardConfigPatternSectionInterface) &&
config.contains(wireguardConfigPatternSectionPeer))
return ConfigTypes::WireGuard;
return ConfigTypes::Amnezia;
}
const QString wireguardConfigPatternSectionInterface = "[Interface]";
const QString wireguardConfigPatternSectionPeer = "[Peer]";
if (config.contains(openVpnConfigPatternCli)
&& (config.contains(openVpnConfigPatternProto1) || config.contains(openVpnConfigPatternProto2))
&& (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) {
return ConfigTypes::OpenVpn;
} else if (config.contains(wireguardConfigPatternSectionInterface)
&& config.contains(wireguardConfigPatternSectionPeer))
return ConfigTypes::WireGuard;
return ConfigTypes::Amnezia;
}
}
StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent),
m_pushButtonConnectEnabled{true},
m_pushButtonConnectText{tr("Connect")},
m_pushButtonConnectKeyChecked{false},
m_labelWaitInfoVisible{true},
m_pushButtonBackFromStartVisible{true},
m_ipAddressPortRegex{Utils::ipAddressPortRegExp()}
StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent)
: PageLogicBase(logic, parent),
m_pushButtonConnectEnabled { true },
m_pushButtonConnectText { tr("Connect") },
m_pushButtonConnectKeyChecked { false },
m_labelWaitInfoVisible { true },
m_pushButtonBackFromStartVisible { true },
m_ipAddressPortRegex { Utils::ipAddressPortRegExp() }
{
#ifdef Q_OS_ANDROID
// Set security screen for Android app
AndroidUtils::runOnAndroidThreadSync([]() {
QJniObject activity = AndroidUtils::getActivity();
QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
if (window.isValid()){
if (window.isValid()) {
const int FLAG_SECURE = 8192;
window.callMethod<void>("addFlags", "(I)V", FLAG_SECURE);
}
@ -89,17 +90,13 @@ void StartPageLogic::onUpdatePage()
void StartPageLogic::onPushButtonConnect()
{
if (pushButtonConnectKeyChecked()){
if (lineEditIpText().isEmpty() ||
lineEditLoginText().isEmpty() ||
textEditSshKeyText().isEmpty() ) {
if (pushButtonConnectKeyChecked()) {
if (lineEditIpText().isEmpty() || lineEditLoginText().isEmpty() || textEditSshKeyText().isEmpty()) {
set_labelWaitInfoText(tr("Please fill in all fields"));
return;
}
} else {
if (lineEditIpText().isEmpty() ||
lineEditLoginText().isEmpty() ||
lineEditPasswordText().isEmpty() ) {
if (lineEditIpText().isEmpty() || lineEditLoginText().isEmpty() || lineEditPasswordText().isEmpty()) {
set_labelWaitInfoText(tr("Please fill in all fields"));
return;
}
@ -174,7 +171,8 @@ void StartPageLogic::onPushButtonConnect()
set_pushButtonConnectText(tr("Connect"));
uiLogic()->m_installCredentials = serverCredentials;
if (ok) emit uiLogic()->goToPage(Page::NewServer);
if (ok)
emit uiLogic()->goToPage(Page::NewServer);
}
void StartPageLogic::onPushButtonImport()
@ -185,8 +183,10 @@ void StartPageLogic::onPushButtonImport()
void StartPageLogic::onPushButtonImportOpenFile()
{
QString fileName = UiLogic::getOpenFileName(Q_NULLPTR, tr("Open config file"),
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.vpn *.ovpn *.conf");
if (fileName.isEmpty()) return;
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),
"*.vpn *.ovpn *.conf");
if (fileName.isEmpty())
return;
QFile file(fileName);
file.open(QIODevice::ReadOnly);
@ -226,8 +226,7 @@ bool StartPageLogic::importConnection(const QJsonObject &profile)
// check config
uiLogic()->pageLogic<ViewConfigLogic>()->set_configJson(profile);
emit uiLogic()->goToPage(Page::ViewConfig);
}
else {
} else {
qDebug() << "Failed to import profile";
qDebug().noquote() << QJsonDocument(profile).toJson();
return false;
@ -298,7 +297,6 @@ bool StartPageLogic::importConnectionFromOpenVpnConfig(const QString &config)
o[config_key::defaultContainer] = "amnezia-openvpn";
o[config_key::description] = m_settings->nextAvailableServerName();
const static QRegularExpression dnsRegExp("dhcp-option DNS (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
QRegularExpressionMatchIterator dnsMatch = dnsRegExp.globalMatch(config);
if (dnsMatch.hasNext()) {
@ -345,7 +343,9 @@ bool StartPageLogic::importConnectionFromWireguardConfig(const QString &config)
o[config_key::defaultContainer] = "amnezia-wireguard";
o[config_key::description] = m_settings->nextAvailableServerName();
const static QRegularExpression dnsRegExp("DNS = (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b).*(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
const static QRegularExpression dnsRegExp(
"DNS = "
"(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b).*(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
QRegularExpressionMatch dnsMatch = dnsRegExp.match(config);
if (dnsMatch.hasMatch()) {
o[config_key::dns1] = dnsMatch.captured(1);

View file

@ -54,10 +54,10 @@ DrawerType {
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Save connection code")
text: Qt.platform.os === "android" ? qsTr("Share") : qsTr("Save connection code")
onClicked: {
ExportController.saveFile()
Qt.platform.os === "android" ? ExportController.shareFile() : ExportController.saveFile()
}
}

View file

@ -26,7 +26,7 @@ CheckBox {
hoverEnabled: true
indicator: Rectangle {
id: checkBoxBackground
id: background
anchors.verticalCenter: parent.verticalCenter
@ -57,7 +57,6 @@ CheckBox {
radius: 4
Image {
id: indicator
anchors.centerIn: parent
source: root.pressed ? imageSource : root.checked ? imageSource : ""
@ -71,31 +70,38 @@ CheckBox {
}
}
contentItem: ColumnLayout {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 8 + checkBoxBackground.width
contentItem: Item {
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
spacing: 4
anchors.fill: parent
anchors.leftMargin: 8 + background.width
ListItemTitleType {
Layout.fillWidth: true
// Layout.topMargin: 16
// Layout.bottomMargin: description.visible ? 0 : 16
ColumnLayout {
id: content
text: root.text
}
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
CaptionTextType {
id: description
spacing: 4
Layout.fillWidth: true
Layout.bottomMargin: 16
ListItemTitleType {
Layout.fillWidth: true
text: root.descriptionText
color: "#878b91"
text: root.text
}
visible: root.descriptionText !== ""
CaptionTextType {
id: description
Layout.fillWidth: true
text: root.descriptionText
color: "#878b91"
visible: root.descriptionText !== ""
}
}
}

View file

@ -20,7 +20,6 @@ Item {
if (root.stackView.depth <= 1) {
return
}
root.stackView.pop()
}

View file

@ -85,44 +85,50 @@ RadioButton {
}
}
contentItem: ColumnLayout {
id: content
anchors.left: parent.left
anchors.right: parent.right
contentItem: Item {
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
anchors.fill: parent
anchors.leftMargin: 8 + background.width
spacing: 4
ColumnLayout {
id: content
ListItemTitleType {
text: root.text
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
color: {
if (root.checked) {
return selectedTextColor
spacing: 4
ListItemTitleType {
text: root.text
color: {
if (root.checked) {
return selectedTextColor
}
return textColor
}
Layout.fillWidth: true
Behavior on color {
PropertyAnimation { duration: 200 }
}
return textColor
}
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: description.visible ? 0 : 16
CaptionTextType {
id: description
Behavior on color {
PropertyAnimation { duration: 200 }
color: "#878B91"
text: root.descriptionText
visible: root.descriptionText !== ""
Layout.fillWidth: true
}
}
CaptionTextType {
id: description
color: "#878B91"
text: root.descriptionText
visible: root.descriptionText !== ""
Layout.fillWidth: true
Layout.bottomMargin: 16
}
}
MouseArea {

View file

@ -43,8 +43,8 @@ PageType {
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.preferredWidth: 344
Layout.preferredHeight: 279
Layout.preferredWidth: 291
Layout.preferredHeight: 224
}
Header2TextType {
@ -100,7 +100,7 @@ And if you don't like the app, all the more support it - the donation will be us
text: qsTr("Show other methods on Github")
onClicked: Qt.openUrlExternally("https://github.com/amnezia-vpn/amnezia-client")
onClicked: Qt.openUrlExternally("https://github.com/amnezia-vpn/amnezia-client#donate")
}
ParagraphTextType {

View file

@ -61,16 +61,18 @@ PageType {
leftImageSource: "qrc:/images/controls/folder-open.svg"
clickedFunction: function() {
onClicked: fileDialog.open()
// onClicked: fileDialog.open()
ImportController.extractConfigFromFile()
goToPage(PageEnum.PageSetupWizardViewConfig)
}
FileDialog {
id: fileDialog
onAccepted: {
ImportController.extractConfigFromFile(selectedFile)
goToPage(PageEnum.PageSetupWizardViewConfig)
}
}
// FileDialog {
// id: fileDialog
// onAccepted: {
// ImportController.extractConfigFromFile(selectedFile)
// goToPage(PageEnum.PageSetupWizardViewConfig)
// }
// }
}
DividerType {}
@ -84,6 +86,8 @@ PageType {
leftImageSource: "qrc:/images/controls/qr-code.svg"
clickedFunction: function() {
ImportController.extractConfigFromQr()
// goToPage(PageEnum.PageSetupWizardQrReader)
}
}

View file

@ -0,0 +1,52 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import PageEnum 1.0
import QRCodeReader 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
PageType {
id: root
ColumnLayout {
anchors.fill: parent
spacing: 0
BackButtonType {
Layout.topMargin: 20
}
ParagraphTextType {
Layout.fillWidth: true
text: qsTr("Point the camera at the QR code and hold for a couple of seconds.")
}
ProgressBarType {
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
QRCodeReader {
id: qrCodeReader
Component.onCompleted: {
qrCodeReader.setCameraSize(Qt.rect(parent.x,
parent.y,
parent.width,
parent.height))
qrCodeReader.startReading()
}
}
}
}
}

View file

@ -20,6 +20,10 @@ PageType {
popupErrorMessage.popupErrorMessageText = errorMessage
popupErrorMessage.open()
}
function onGoToPageViewConfig() {
goToPage(PageEnum.PageSetupWizardViewConfig)
}
}
FlickableType {

View file

@ -18,7 +18,7 @@ PageType {
enum ConfigType {
AmneziaConnection,
AmenziaFullAccess,
AmneziaFullAccess,
OpenVpn,
WireGuard
}
@ -33,7 +33,14 @@ PageType {
switch (type) {
case PageShare.ConfigType.AmneziaConnection: ExportController.generateConnectionConfig(); break;
case PageShare.ConfigType.AmenziaFullAccess: ExportController.generateFullAccessConfig(); break;
case PageShare.ConfigType.AmneziaFullAccess: {
if (Qt.platform.os === "android") {
ExportController.generateFullAccessConfigAndroid();
} else {
ExportController.generateFullAccessConfig();
}
break;
}
case PageShare.ConfigType.OpenVpn: ExportController.generateOpenVpnConfig(); break;
case PageShare.ConfigType.WireGuard: ExportController.generateWireGuardConfig(); break;
}
@ -48,6 +55,8 @@ PageType {
}
}
property string fullConfigServerSelectorText
property string connectionServerSelectorText
property bool showContent: false
property bool shareButtonEnabled: false
property list<QtObject> connectionTypesModel: [
@ -118,6 +127,7 @@ PageType {
onClicked: {
accessTypeSelector.currentIndex = 0
serverSelector.text = root.connectionServerSelectorText
}
}
@ -129,6 +139,7 @@ PageType {
onClicked: {
accessTypeSelector.currentIndex = 1
serverSelector.text = root.fullConfigServerSelectorText
}
}
}
@ -176,14 +187,24 @@ PageType {
currentIndex: 0
clickedFunction: function() {
serverSelector.text = selectedText
ServersModel.currentlyProcessedIndex = currentIndex
protocolSelector.visible = true
root.shareButtonEnabled = false
handler()
if (accessTypeSelector.currentIndex === 0) {
protocolSelector.visible = true
root.shareButtonEnabled = false
} else {
serverSelector.menuVisible = false
}
}
Component.onCompleted: {
handler()
}
function handler() {
serverSelector.text = selectedText
root.fullConfigServerSelectorText = selectedText
root.connectionServerSelectorText = selectedText
ServersModel.currentlyProcessedIndex = currentIndex
}
}
@ -260,7 +281,9 @@ PageType {
}
Component.onCompleted: {
handler()
if (accessTypeSelector.currentIndex === 0) {
handler()
}
}
function handler() {
@ -272,6 +295,8 @@ PageType {
}
serverSelector.text += ", " + selectedText
root.connectionServerSelectorText = serverSelector.text
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
ContainersModel.setCurrentlyProcessedContainerIndex(proxyContainersModel.mapToSource(currentIndex))

View file

@ -25,6 +25,11 @@ PageType {
tabBarStackView.goToTabBarPage(PageController.getPagePath(PageEnum.PageSettings))
}
function onGoToPageViewConfig() {
var pagePath = PageController.getPagePath(PageEnum.PageSetupWizardViewConfig)
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
}
function onShowErrorMessage(errorMessage) {
popupErrorMessage.popupErrorMessageText = errorMessage
popupErrorMessage.open()
@ -35,6 +40,13 @@ PageType {
tabBarStackView.enabled = !visible
tabBar.enabled = !visible
}
function onClosePage() {
if (tabBarStackView.depth <= 1) {
return
}
tabBarStackView.pop()
}
}
StackViewType {

View file

@ -1,282 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import "./"
import "../Controls2"
import "../Config"
import "../Controls2/TextTypes"
Item {
id: root
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
HeaderType {
id: header
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.topMargin: 20
Layout.bottomMargin: 32
Layout.fillWidth: true
backButtonImage: "qrc:/images/controls/arrow-left.svg"
headerText: "Server 1"
descriptionText: "root 192.168.111.111"
}
Item {
Layout.fillWidth: true
TabBar {
id: tabBar
anchors {
top: parent.top
right: parent.right
left: parent.left
}
background: Rectangle {
color: "transparent"
}
TabButtonType {
id: bb
isSelected: tabBar.currentIndex === 0
text: qsTr("Протоколы")
}
TabButtonType {
isSelected: tabBar.currentIndex === 1
text: qsTr("Сервисы")
}
TabButtonType {
isSelected: tabBar.currentIndex === 2
text: qsTr("Данные")
}
}
StackLayout {
id: stackLayout
currentIndex: tabBar.currentIndex
anchors.top: tabBar.bottom
anchors.topMargin: 16
width: parent.width
height: root.height - header.implicitHeight - tabBar.implicitHeight - 100
Item {
id: protocolsTab
FlickableType {
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: protocolsTabContent.height
ColumnLayout {
id: protocolsTabContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
BasicButtonType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Forget this server")
}
BasicButtonType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: "transparent"
hoveredColor: Qt.rgba(255, 255, 255, 0.08)
pressedColor: Qt.rgba(255, 255, 255, 0.12)
disabledColor: "#878B91"
textColor: "#D7D8DB"
borderWidth: 1
text: qsTr("Forget this server")
}
TextFieldWithHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: "Server IP adress [:port]"
}
LabelWithButtonType {
id: ip
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: "IP, логин и пароль от сервера"
rightImageSource: "qrc:/images/controls/chevron-right.svg"
}
Rectangle {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
height: 1
color: "#2C2D30"
}
LabelWithButtonType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: "QR-код, ключ или файл настроек"
rightImageSource: "qrc:/images/controls/chevron-right.svg"
}
Rectangle {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
height: 1
color: "#2C2D30"
}
CardType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: "Высокий"
bodyText: "Многие иностранные сайты и VPN-провайдеры заблокированы"
footerText: "футер"
}
CardType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: "Высокий"
bodyText: "Многие иностранные сайты и VPN-провайдеры заблокированы"
footerText: "футер"
}
DropDownType {
Layout.fillWidth: true
text: "IP, логин и пароль от сервера"
descriptionText: "IP, логин и пароль от сервера"
menuModel: [
qsTr("SHA512"),
qsTr("SHA384"),
qsTr("SHA256"),
qsTr("SHA3-512"),
qsTr("SHA3-384"),
qsTr("SHA3-256"),
qsTr("whirlpool"),
qsTr("BLAKE2b512"),
qsTr("BLAKE2s256"),
qsTr("SHA1")
]
}
}
}
}
Item {
id: servicesTab
FlickableType {
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: servicesTabContent.height
ColumnLayout {
id: servicesTabContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
CheckBoxType {
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.fillWidth: true
text: qsTr("Auto-negotiate encryption")
}
CheckBoxType {
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.fillWidth: true
text: qsTr("Auto-negotiate encryption")
descriptionText: qsTr("Auto-negotiate encryption")
}
Rectangle {
implicitWidth: buttonGroup.implicitWidth
implicitHeight: buttonGroup.implicitHeight
Layout.leftMargin: 16
Layout.rightMargin: 16
color: "#1C1D21"
radius: 16
RowLayout {
id: buttonGroup
spacing: 0
HorizontalRadioButton {
implicitWidth: (root.width - 32) / 2
text: "UDP"
}
HorizontalRadioButton {
implicitWidth: (root.width - 32) / 2
text: "TCP"
}
}
}
VerticalRadioButton {
text: "Раздельное туннелирование"
descriptionText: "Позволяет подключаться к одним сайтам через защищенное соединение, а к другим в обход него"
checked: true
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
}
VerticalRadioButton {
text: "Раздельное туннелирование"
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
}
SwitcherType {
text: "Auto-negotiate encryption"
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
}
}
}
}
}
}
}
}

View file

@ -18,10 +18,9 @@ Window {
color: "#0E0E11"
// todo
onClosing: function() {
console.debug("QML onClosing signal")
UiLogic.onCloseWindow()
PageController.closeWindow()
}
title: "AmneziaVPN"
@ -36,6 +35,11 @@ Window {
var pagePath = PageController.getInitialPage()
rootStackView.push(pagePath, { "objectName" : pagePath })
}
Keys.onPressed: function(event) {
PageController.keyPressEvent(event.key)
event.accepted = true
}
}
Connections {
@ -49,10 +53,14 @@ Window {
rootStackView.replace(pagePath, { "objectName" : pagePath })
}
function onRaise() {
function onRaiseMainWindow() {
root.show()
root.raise()
root.requestActivate()
}
function onHideMainWindow() {
root.hide()
}
}
}

View file

@ -10,79 +10,76 @@
#include <QKeyEvent>
#include <QMenu>
#include <QMetaEnum>
#include <QMetaObject>
#include <QQmlFile>
#include <QStandardPaths>
#include <QSysInfo>
#include <QThread>
#include <QTimer>
#include <QQmlFile>
#include <QMetaObject>
#include <QStandardPaths>
#include "amnezia_application.h"
#include "configurators/cloak_configurator.h"
#include "configurators/vpn_configurator.h"
#include "configurators/openvpn_configurator.h"
#include "configurators/shadowsocks_configurator.h"
#include "configurators/ssh_configurator.h"
#include "configurators/vpn_configurator.h"
#include "core/servercontroller.h"
#include "core/server_defs.h"
#include "core/errorstrings.h"
#include "core/server_defs.h"
#include "core/servercontroller.h"
#include "containers/containers_defs.h"
#include "ui/qautostart.h"
#include "logger.h"
#include "version.h"
#include "uilogic.h"
#include "utilities.h"
#include "version.h"
#include "vpnconnection.h"
#include <functional>
#if defined Q_OS_MAC || defined Q_OS_LINUX
#include "ui/macos_util.h"
#include "ui/macos_util.h"
#endif
#ifdef Q_OS_ANDROID
#include "platforms/android/android_controller.h"
#include "platforms/android/android_controller.h"
#endif
#include "platforms/ios/MobileUtils.h"
#include "pages_logic/AdvancedServerSettingsLogic.h"
#include "pages_logic/AppSettingsLogic.h"
#include "pages_logic/ClientInfoLogic.h"
#include "pages_logic/ClientManagementLogic.h"
#include "pages_logic/GeneralSettingsLogic.h"
#include "pages_logic/NetworkSettingsLogic.h"
#include "pages_logic/NewServerProtocolsLogic.h"
#include "pages_logic/QrDecoderLogic.h"
#include "pages_logic/ServerConfiguringProgressLogic.h"
#include "pages_logic/ServerContainersLogic.h"
#include "pages_logic/ServerListLogic.h"
#include "pages_logic/ServerSettingsLogic.h"
#include "pages_logic/ServerContainersLogic.h"
#include "pages_logic/ShareConnectionLogic.h"
#include "pages_logic/SitesLogic.h"
#include "pages_logic/StartPageLogic.h"
#include "pages_logic/ViewConfigLogic.h"
#include "pages_logic/VpnLogic.h"
#include "pages_logic/WizardLogic.h"
#include "pages_logic/AdvancedServerSettingsLogic.h"
#include "pages_logic/ClientManagementLogic.h"
#include "pages_logic/ClientInfoLogic.h"
#include "pages_logic/protocols/CloakLogic.h"
#include "pages_logic/protocols/OpenVpnLogic.h"
#include "pages_logic/protocols/ShadowSocksLogic.h"
#include "pages_logic/protocols/OtherProtocolsLogic.h"
#include "pages_logic/protocols/ShadowSocksLogic.h"
#include "pages_logic/protocols/WireGuardLogic.h"
using namespace amnezia;
using namespace PageEnumNS;
UiLogic::UiLogic(std::shared_ptr<Settings> settings, std::shared_ptr<VpnConfigurator> configurator,
QObject *parent) :
QObject(parent),
m_settings(settings),
m_configurator(configurator)
UiLogic::UiLogic(std::shared_ptr<Settings> settings, std::shared_ptr<VpnConfigurator> configurator, QObject *parent)
: QObject(parent), m_settings(settings), m_configurator(configurator)
{
m_protocolsModel = new ProtocolsModel(settings, this);
m_clientManagementModel = new ClientManagementModel(this);
@ -90,7 +87,6 @@ UiLogic::UiLogic(std::shared_ptr<Settings> settings, std::shared_ptr<VpnConfigur
m_vpnConnection->moveToThread(&m_vpnConnectionThread);
m_vpnConnectionThread.start();
m_protocolLogicMap.insert(Proto::OpenVpn, new OpenVpnLogic(this));
m_protocolLogicMap.insert(Proto::ShadowSocks, new ShadowSocksLogic(this));
m_protocolLogicMap.insert(Proto::Cloak, new CloakLogic(this));
@ -99,7 +95,6 @@ UiLogic::UiLogic(std::shared_ptr<Settings> settings, std::shared_ptr<VpnConfigur
m_protocolLogicMap.insert(Proto::Dns, new OtherProtocolsLogic(this));
m_protocolLogicMap.insert(Proto::Sftp, new OtherProtocolsLogic(this));
m_protocolLogicMap.insert(Proto::TorWebSite, new OtherProtocolsLogic(this));
}
UiLogic::~UiLogic()
@ -129,33 +124,37 @@ UiLogic::~UiLogic()
void UiLogic::initializeUiLogic()
{
#ifdef Q_OS_ANDROID
connect(AndroidController::instance(), &AndroidController::initialized, [this](bool status, bool connected, const QDateTime& connectionDate) {
if (connected) {
pageLogic<VpnLogic>()->onConnectionStateChanged(Vpn::ConnectionState::Connected);
if (m_vpnConnection) m_vpnConnection->restoreConnection();
}
});
if (!AndroidController::instance()->initialize(pageLogic<StartPageLogic>())) {
qCritical() << QString("Init failed");
if (m_vpnConnection) m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Error);
return;
}
connect(AndroidController::instance(), &AndroidController::initialized,
[this](bool status, bool connected, const QDateTime &connectionDate) {
if (connected) {
pageLogic<VpnLogic>()->onConnectionStateChanged(Vpn::ConnectionState::Connected);
if (m_vpnConnection)
m_vpnConnection->restoreConnection();
}
});
// if (!AndroidController::instance()->initialize(pageLogic<StartPageLogic>())) {
// qCritical() << QString("Init failed");
// if (m_vpnConnection) m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Error);
// return;
// }
#endif
m_notificationHandler = NotificationHandler::create(qmlRoot());
connect(m_vpnConnection, &VpnConnection::connectionStateChanged, m_notificationHandler, &NotificationHandler::setConnectionState);
connect(m_vpnConnection, &VpnConnection::connectionStateChanged, m_notificationHandler,
&NotificationHandler::setConnectionState);
connect(m_notificationHandler, &NotificationHandler::raiseRequested, this, &UiLogic::raise);
connect(m_notificationHandler, &NotificationHandler::connectRequested, pageLogic<VpnLogic>(), &VpnLogic::onConnect);
connect(m_notificationHandler, &NotificationHandler::disconnectRequested, pageLogic<VpnLogic>(), &VpnLogic::onDisconnect);
connect(m_notificationHandler, &NotificationHandler::disconnectRequested, pageLogic<VpnLogic>(),
&VpnLogic::onDisconnect);
// if (m_settings->serversCount() > 0) {
// if (m_settings->defaultServerIndex() < 0) m_settings->setDefaultServer(0);
// emit goToPage(Page::PageStart, true, false);
// }
// else {
// emit goToPage(Page::PageSetupWizardStart, true, false);
// }
// if (m_settings->serversCount() > 0) {
// if (m_settings->defaultServerIndex() < 0) m_settings->setDefaultServer(0);
// emit goToPage(Page::PageStart, true, false);
// }
// else {
// emit goToPage(Page::PageSetupWizardStart, true, false);
// }
m_selectedServerIndex = m_settings->defaultServerIndex();
@ -165,14 +164,13 @@ void UiLogic::initializeUiLogic()
void UiLogic::showOnStartup()
{
if (! m_settings->isStartMinimized()) {
if (!m_settings->isStartMinimized()) {
emit show();
}
else {
} else {
#ifdef Q_OS_WIN
emit hide();
#elif defined Q_OS_MACX
// TODO: fix: setDockIconVisible(false);
// TODO: fix: setDockIconVisible(false);
#endif
}
}
@ -180,7 +178,7 @@ void UiLogic::showOnStartup()
void UiLogic::onUpdateAllPages()
{
for (auto logic : m_logicMap) {
if (dynamic_cast<ClientInfoLogic*>(logic) || dynamic_cast<ClientManagementLogic*>(logic)) {
if (dynamic_cast<ClientInfoLogic *>(logic) || dynamic_cast<ClientManagementLogic *>(logic)) {
continue;
}
logic->onUpdatePage();
@ -191,57 +189,50 @@ void UiLogic::keyPressEvent(Qt::Key key)
{
switch (key) {
case Qt::Key_AsciiTilde:
case Qt::Key_QuoteLeft: emit toggleLogPanel();
break;
case Qt::Key_L: Logger::openLogsFolder();
break;
case Qt::Key_K: Logger::openServiceLogsFolder();
break;
case Qt::Key_QuoteLeft: emit toggleLogPanel(); break;
case Qt::Key_L: Logger::openLogsFolder(); break;
case Qt::Key_K: Logger::openServiceLogsFolder(); break;
#ifdef QT_DEBUG
case Qt::Key_Q:
qApp->quit();
break;
case Qt::Key_Q: qApp->quit(); break;
case Qt::Key_H:
m_selectedServerIndex = m_settings->defaultServerIndex();
m_selectedDockerContainer = m_settings->defaultContainer(m_selectedServerIndex);
//updateSharingPage(selectedServerIndex, m_settings->serverCredentials(selectedServerIndex), selectedDockerContainer);
// updateSharingPage(selectedServerIndex, m_settings->serverCredentials(selectedServerIndex), selectedDockerContainer);
emit goToPage(Page::ShareConnection);
break;
#endif
case Qt::Key_C:
qDebug().noquote() << "Def server" << m_settings->defaultServerIndex() << m_settings->defaultContainerName(m_settings->defaultServerIndex());
qDebug().noquote() << "Def server" << m_settings->defaultServerIndex()
<< m_settings->defaultContainerName(m_settings->defaultServerIndex());
qDebug().noquote() << QJsonDocument(m_settings->defaultServer()).toJson();
break;
case Qt::Key_A:
emit goToPage(Page::Start);
break;
case Qt::Key_A: emit goToPage(Page::Start); break;
case Qt::Key_S:
m_selectedServerIndex = m_settings->defaultServerIndex();
emit goToPage(Page::ServerSettings);
break;
case Qt::Key_P:
onGotoCurrentProtocolsPage();
break;
case Qt::Key_P: onGotoCurrentProtocolsPage(); break;
case Qt::Key_T:
m_configurator->sshConfigurator->openSshTerminal(m_settings->serverCredentials(m_settings->defaultServerIndex()));
break;
case Qt::Key_Escape:
if (currentPage() == Page::Vpn) break;
if (currentPage() == Page::ServerConfiguringProgress) break;
if (currentPage() == Page::Vpn)
break;
if (currentPage() == Page::ServerConfiguringProgress)
break;
case Qt::Key_Back:
// if (currentPage() == Page::Start && pagesStack.size() < 2) break;
// if (currentPage() == Page::Sites &&
// ui->tableView_sites->selectionModel()->selection().indexes().size() > 0) {
// ui->tableView_sites->clearSelection();
// break;
// }
// if (currentPage() == Page::Start && pagesStack.size() < 2) break;
// if (currentPage() == Page::Sites &&
// ui->tableView_sites->selectionModel()->selection().indexes().size() > 0) {
// ui->tableView_sites->clearSelection();
// break;
// }
emit closePage();
emit closePage();
//}
default:
;
default:;
}
}
@ -250,8 +241,7 @@ void UiLogic::onCloseWindow()
#ifdef Q_OS_ANDROID
qApp->quit();
#else
if (m_settings->serversCount() == 0)
{
if (m_settings->serversCount() == 0) {
qApp->quit();
} else {
emit hide();
@ -267,7 +257,6 @@ QString UiLogic::containerName(int container)
QString UiLogic::containerDesc(int container)
{
return ContainerProps::containerDescriptions().value(static_cast<DockerContainer>(container));
}
void UiLogic::onGotoCurrentProtocolsPage()
@ -286,50 +275,50 @@ void UiLogic::installServer(QPair<DockerContainer, QJsonObject> &container)
qApp->processEvents();
ServerConfiguringProgressLogic::PageFunc pageFunc;
pageFunc.setEnabledFunc = [this] (bool enabled) -> void {
pageFunc.setEnabledFunc = [this](bool enabled) -> void {
pageLogic<ServerConfiguringProgressLogic>()->set_pageEnabled(enabled);
};
ServerConfiguringProgressLogic::ButtonFunc noButton;
ServerConfiguringProgressLogic::LabelFunc waitInfoFunc;
waitInfoFunc.setTextFunc = [this] (const QString& text) -> void {
waitInfoFunc.setTextFunc = [this](const QString &text) -> void {
pageLogic<ServerConfiguringProgressLogic>()->set_labelWaitInfoText(text);
};
waitInfoFunc.setVisibleFunc = [this] (bool visible) -> void {
waitInfoFunc.setVisibleFunc = [this](bool visible) -> void {
pageLogic<ServerConfiguringProgressLogic>()->set_labelWaitInfoVisible(visible);
};
ServerConfiguringProgressLogic::ProgressFunc progressBarFunc;
progressBarFunc.setVisibleFunc = [this] (bool visible) -> void {
progressBarFunc.setVisibleFunc = [this](bool visible) -> void {
pageLogic<ServerConfiguringProgressLogic>()->set_progressBarVisible(visible);
};
progressBarFunc.setValueFunc = [this] (int value) -> void {
progressBarFunc.setValueFunc = [this](int value) -> void {
pageLogic<ServerConfiguringProgressLogic>()->set_progressBarValue(value);
};
progressBarFunc.getValueFunc = [this] (void) -> int {
progressBarFunc.getValueFunc = [this](void) -> int {
return pageLogic<ServerConfiguringProgressLogic>()->progressBarValue();
};
progressBarFunc.getMaximumFunc = [this] (void) -> int {
progressBarFunc.getMaximumFunc = [this](void) -> int {
return pageLogic<ServerConfiguringProgressLogic>()->progressBarMaximum();
};
progressBarFunc.setTextVisibleFunc = [this] (bool visible) -> void {
progressBarFunc.setTextVisibleFunc = [this](bool visible) -> void {
pageLogic<ServerConfiguringProgressLogic>()->set_progressBarTextVisible(visible);
};
progressBarFunc.setTextFunc = [this] (const QString& text) -> void {
progressBarFunc.setTextFunc = [this](const QString &text) -> void {
pageLogic<ServerConfiguringProgressLogic>()->set_progressBarText(text);
};
ServerConfiguringProgressLogic::LabelFunc busyInfoFunc;
busyInfoFunc.setTextFunc = [this] (const QString& text) -> void {
busyInfoFunc.setTextFunc = [this](const QString &text) -> void {
pageLogic<ServerConfiguringProgressLogic>()->set_labelServerBusyText(text);
};
busyInfoFunc.setVisibleFunc = [this] (bool visible) -> void {
busyInfoFunc.setVisibleFunc = [this](bool visible) -> void {
pageLogic<ServerConfiguringProgressLogic>()->set_labelServerBusyVisible(visible);
};
ServerConfiguringProgressLogic::ButtonFunc cancelButtonFunc;
cancelButtonFunc.setVisibleFunc = [this] (bool visible) -> void {
cancelButtonFunc.setVisibleFunc = [this](bool visible) -> void {
pageLogic<ServerConfiguringProgressLogic>()->set_pushButtonCancelVisible(visible);
};
@ -338,13 +327,12 @@ void UiLogic::installServer(QPair<DockerContainer, QJsonObject> &container)
if (errorCode == ErrorCode::NoError) {
if (!isContainerAlreadyAddedToGui(container.first)) {
progressBarFunc.setTextFunc(QString("Installing %1").arg(ContainerProps::containerToString(container.first)));
auto installAction = [&] () {
auto installAction = [&]() {
ServerController serverController(m_settings);
return serverController.setupContainer(m_installCredentials, container.first, container.second);
};
errorCode = pageLogic<ServerConfiguringProgressLogic>()->doInstallAction(installAction, pageFunc, progressBarFunc,
noButton, waitInfoFunc,
busyInfoFunc, cancelButtonFunc);
errorCode = pageLogic<ServerConfiguringProgressLogic>()->doInstallAction(
installAction, pageFunc, progressBarFunc, noButton, waitInfoFunc, busyInfoFunc, cancelButtonFunc);
if (errorCode == ErrorCode::NoError) {
if (!isServerCreated) {
QJsonObject server;
@ -354,7 +342,7 @@ void UiLogic::installServer(QPair<DockerContainer, QJsonObject> &container)
server.insert(config_key::port, m_installCredentials.port);
server.insert(config_key::description, m_settings->nextAvailableServerName());
server.insert(config_key::containers, QJsonArray{container.second});
server.insert(config_key::containers, QJsonArray { container.second });
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container.first));
m_settings->addServer(server);
@ -371,22 +359,23 @@ void UiLogic::installServer(QPair<DockerContainer, QJsonObject> &container)
}
} else {
onUpdateAllPages();
emit showWarningMessage("Attention! The container you are trying to install is already installed on the server. "
"All installed containers have been added to the application ");
emit showWarningMessage(
"Attention! The container you are trying to install is already installed on the server. "
"All installed containers have been added to the application ");
emit setStartPage(Page::Vpn);
return;
}
}
emit showWarningMessage(tr("Error occurred while configuring server.") + "\n" +
tr("Error message: ") + errorString(errorCode) + "\n" +
tr("See logs for details."));
emit showWarningMessage(tr("Error occurred while configuring server.") + "\n" + tr("Error message: ")
+ errorString(errorCode) + "\n" + tr("See logs for details."));
emit closePage();
}
PageProtocolLogicBase *UiLogic::protocolLogic(Proto p)
{
PageProtocolLogicBase *logic = m_protocolLogicMap.value(p);
if (logic) return logic;
if (logic)
return logic;
else {
qCritical() << "UiLogic::protocolLogic Warning: logic missing for" << p;
return new PageProtocolLogicBase(this);
@ -418,7 +407,7 @@ PageEnumNS::Page UiLogic::currentPage()
return static_cast<PageEnumNS::Page>(currentPageValue());
}
void UiLogic::saveTextFile(const QString& desc, const QString& suggestedName, QString ext, const QString& data)
void UiLogic::saveTextFile(const QString &desc, const QString &suggestedName, QString ext, const QString &data)
{
#ifdef Q_OS_IOS
shareTempFile(suggestedName, ext, data);
@ -429,17 +418,19 @@ void UiLogic::saveTextFile(const QString& desc, const QString& suggestedName, QS
QString docDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
QUrl fileName;
#ifdef AMNEZIA_DESKTOP
fileName = QFileDialog::getSaveFileUrl(nullptr, desc,
QUrl::fromLocalFile(docDir + "/" + suggestedName), "*" + ext);
if (fileName.isEmpty()) return;
if (!fileName.toString().endsWith(ext)) fileName = QUrl(fileName.toString() + ext);
fileName = QFileDialog::getSaveFileUrl(nullptr, desc, QUrl::fromLocalFile(docDir + "/" + suggestedName), "*" + ext);
if (fileName.isEmpty())
return;
if (!fileName.toString().endsWith(ext))
fileName = QUrl(fileName.toString() + ext);
#elif defined Q_OS_ANDROID
qDebug() << "UiLogic::shareConfig" << data;
AndroidController::instance()->shareConfig(data, suggestedName);
return;
#endif
if (fileName.isEmpty()) return;
if (fileName.isEmpty())
return;
#ifdef AMNEZIA_DESKTOP
QFile save(fileName.toLocalFile());
@ -458,11 +449,13 @@ void UiLogic::saveTextFile(const QString& desc, const QString& suggestedName, QS
void UiLogic::saveBinaryFile(const QString &desc, QString ext, const QString &data)
{
ext.replace("*", "");
QString fileName = QFileDialog::getSaveFileName(nullptr, desc,
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*" + ext);
QString fileName = QFileDialog::getSaveFileName(
nullptr, desc, QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*" + ext);
if (fileName.isEmpty()) return;
if (!fileName.endsWith(ext)) fileName.append(ext);
if (fileName.isEmpty())
return;
if (!fileName.endsWith(ext))
fileName.append(ext);
QFile save(fileName);
save.open(QIODevice::WriteOnly);
@ -478,12 +471,15 @@ void UiLogic::copyToClipboard(const QString &text)
qApp->clipboard()->setText(text);
}
void UiLogic::shareTempFile(const QString &suggestedName, QString ext, const QString& data) {
void UiLogic::shareTempFile(const QString &suggestedName, QString ext, const QString &data)
{
ext.replace("*", "");
QString fileName = QDir::tempPath() + "/" + suggestedName;
if (fileName.isEmpty()) return;
if (!fileName.endsWith(ext)) fileName.append(ext);
if (fileName.isEmpty())
return;
if (!fileName.endsWith(ext))
fileName.append(ext);
QFile::remove(fileName);
@ -497,14 +493,14 @@ void UiLogic::shareTempFile(const QString &suggestedName, QString ext, const QSt
MobileUtils::shareText(filesToSend);
}
QString UiLogic::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir,
const QString &filter, QString *selectedFilter, QFileDialog::Options options)
QString UiLogic::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter,
QString *selectedFilter, QFileDialog::Options options)
{
QString fileName = QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options);
#ifdef Q_OS_ANDROID
// patch for files containing spaces etc
const QString sep {"raw%3A%2F"};
const QString sep { "raw%3A%2F" };
if (fileName.startsWith("content://") && fileName.contains(sep)) {
QString contentUrl = fileName.split(sep).at(0);
QString rawUrl = fileName.split(sep).at(1);
@ -590,7 +586,8 @@ ErrorCode UiLogic::addAlreadyInstalledContainersGui(bool &isServerCreated)
}
if (createNewServer) {
server.insert(config_key::defaultContainer, ContainerProps::containerToString(installedContainers.firstKey()));
server.insert(config_key::defaultContainer,
ContainerProps::containerToString(installedContainers.firstKey()));
m_settings->addServer(server);
m_settings->setDefaultServer(m_settings->serversCount() - 1);
isServerCreated = true;