mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-24 20:06:50 +03:00
Compare commits
32 Commits
bugfix/api
...
feature/gr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12206cdb52 | ||
|
|
93aebf5256 | ||
|
|
502e815a9f | ||
|
|
8bc69bdc62 | ||
|
|
b3ae687feb | ||
|
|
d6d11d6e60 | ||
|
|
b90bf16945 | ||
|
|
b162147a89 | ||
|
|
faaf5973b4 | ||
|
|
aa4bfc70b9 | ||
|
|
ef674d1e4f | ||
|
|
23633e8fa7 | ||
|
|
3cc846678e | ||
|
|
84e8667e57 | ||
|
|
b500a1f09d | ||
|
|
2399d45bab | ||
|
|
77e82fbf40 | ||
|
|
a6467dd0f0 | ||
|
|
2e11cc56ab | ||
|
|
c2d204b362 | ||
|
|
77a83e4fc3 | ||
|
|
8617896c7a | ||
|
|
97c6b217f2 | ||
|
|
efde0c99a3 | ||
|
|
2dccfce468 | ||
|
|
eaa603684c | ||
|
|
7ef41bfe75 | ||
|
|
e5c25e8a0c | ||
|
|
c9af9f34fc | ||
|
|
acfe19b914 | ||
|
|
81242b405f | ||
|
|
61092259ba |
12
.github/workflows/deploy.yml
vendored
12
.github/workflows/deploy.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
host: 'linux'
|
||||
target: 'desktop'
|
||||
arch: 'gcc_64'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools qtcharts'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
tools: 'tools_ifw'
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
host: 'windows'
|
||||
target: 'desktop'
|
||||
arch: 'win64_msvc2019_64'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools qtcharts'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
tools: 'tools_ifw'
|
||||
@@ -150,7 +150,7 @@ jobs:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'mac'
|
||||
target: 'desktop'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools qtmultimedia'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools qtmultimedia qtcharts'
|
||||
arch: 'clang_64'
|
||||
dir: ${{ runner.temp }}
|
||||
set-env: 'true'
|
||||
@@ -162,7 +162,7 @@ jobs:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'mac'
|
||||
target: 'ios'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools qtmultimedia'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools qtmultimedia qtcharts'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
@@ -242,7 +242,7 @@ jobs:
|
||||
host: 'mac'
|
||||
target: 'desktop'
|
||||
arch: 'clang_64'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools qtcharts'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
@@ -292,7 +292,7 @@ jobs:
|
||||
env:
|
||||
ANDROID_BUILD_PLATFORM: android-34
|
||||
QT_VERSION: 6.6.2
|
||||
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
||||
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools qtcharts'
|
||||
|
||||
steps:
|
||||
- name: 'Install desktop Qt'
|
||||
|
||||
@@ -58,6 +58,7 @@ Check deploy folder for build scripts.
|
||||
- Qt 5 Compatibility Module
|
||||
- Qt Shader Tools
|
||||
- Additional Libraries:
|
||||
- Qt Charts
|
||||
- Qt Image Formats
|
||||
- Qt Multimedia
|
||||
- Qt Remote Objects
|
||||
|
||||
@@ -12,7 +12,7 @@ set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "Autogen")
|
||||
set(PACKAGES
|
||||
Core Gui Network Xml
|
||||
RemoteObjects Quick Svg QuickControls2
|
||||
Core5Compat Concurrent LinguistTools
|
||||
Core5Compat Concurrent LinguistTools Charts
|
||||
)
|
||||
|
||||
execute_process(
|
||||
@@ -38,7 +38,7 @@ set(LIBS ${LIBS}
|
||||
Qt6::Core Qt6::Gui
|
||||
Qt6::Network Qt6::Xml Qt6::RemoteObjects
|
||||
Qt6::Quick Qt6::Svg Qt6::QuickControls2
|
||||
Qt6::Core5Compat Qt6::Concurrent
|
||||
Qt6::Core5Compat Qt6::Concurrent Qt6::Charts
|
||||
)
|
||||
|
||||
if(IOS)
|
||||
@@ -151,6 +151,7 @@ include_directories(mozilla/models)
|
||||
|
||||
if(NOT IOS)
|
||||
set(HEADERS ${HEADERS}
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/MobileUtils.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/QRCodeReaderBase.h
|
||||
)
|
||||
endif()
|
||||
@@ -192,6 +193,7 @@ endif()
|
||||
|
||||
if(NOT IOS)
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/MobileUtils.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/QRCodeReaderBase.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -55,7 +55,6 @@ AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecond
|
||||
#endif
|
||||
|
||||
m_settings = std::shared_ptr<Settings>(new Settings);
|
||||
m_nam = new QNetworkAccessManager(this);
|
||||
}
|
||||
|
||||
AmneziaApplication::~AmneziaApplication()
|
||||
@@ -151,7 +150,7 @@ void AmneziaApplication::init()
|
||||
|
||||
connect(m_notificationHandler.get(), &NotificationHandler::raiseRequested, m_pageController.get(), &PageController::raiseMainWindow);
|
||||
connect(m_notificationHandler.get(), &NotificationHandler::connectRequested, m_connectionController.get(),
|
||||
static_cast<void (ConnectionController::*)()>(&ConnectionController::openConnection));
|
||||
&ConnectionController::openConnection);
|
||||
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
|
||||
&ConnectionController::closeConnection);
|
||||
connect(this, &AmneziaApplication::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated);
|
||||
@@ -196,8 +195,8 @@ void AmneziaApplication::init()
|
||||
// /qt/6.6.1/Src/qtbase/src/plugins/platforms/android/androidjniclipboard.cpp:46
|
||||
// So we catch all the copies to the clipboard and clear them from "text/html"
|
||||
#ifdef Q_OS_ANDROID
|
||||
connect(QGuiApplication::clipboard(), &QClipboard::dataChanged, []() {
|
||||
auto clipboard = QGuiApplication::clipboard();
|
||||
connect(QApplication::clipboard(), &QClipboard::dataChanged, []() {
|
||||
auto clipboard = QApplication::clipboard();
|
||||
if (clipboard->mimeData()->hasHtml()) {
|
||||
clipboard->setText(clipboard->text());
|
||||
}
|
||||
|
||||
@@ -2,15 +2,10 @@
|
||||
#define AMNEZIA_APPLICATION_H
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QThread>
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
#include <QGuiApplication>
|
||||
#else
|
||||
#include <QApplication>
|
||||
#endif
|
||||
#include <QApplication>
|
||||
|
||||
#include "settings.h"
|
||||
#include "vpnconnection.h"
|
||||
@@ -48,7 +43,7 @@
|
||||
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
#define AMNEZIA_BASE_CLASS QGuiApplication
|
||||
#define AMNEZIA_BASE_CLASS QApplication
|
||||
#else
|
||||
#define AMNEZIA_BASE_CLASS SingleApplication
|
||||
#define QAPPLICATION_CLASS QApplication
|
||||
@@ -76,7 +71,6 @@ public:
|
||||
bool parseCommands();
|
||||
|
||||
QQmlApplicationEngine *qmlEngine() const;
|
||||
QNetworkAccessManager *manager() { return m_nam; }
|
||||
|
||||
signals:
|
||||
void translationsUpdated();
|
||||
@@ -130,8 +124,6 @@ private:
|
||||
QScopedPointer<SitesController> m_sitesController;
|
||||
QScopedPointer<SystemController> m_systemController;
|
||||
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
|
||||
|
||||
QNetworkAccessManager *m_nam;
|
||||
};
|
||||
|
||||
#endif // AMNEZIA_APPLICATION_H
|
||||
|
||||
@@ -72,7 +72,7 @@ class AmneziaActivity : QtActivity() {
|
||||
object : Handler(Looper.getMainLooper()) {
|
||||
override fun handleMessage(msg: Message) {
|
||||
val event = msg.extractIpcMessage<ServiceEvent>()
|
||||
Log.d(TAG, "Handle event: $event")
|
||||
if (event != ServiceEvent.STATISTICS_UPDATE) Log.d(TAG, "Handle event: $event")
|
||||
when (event) {
|
||||
ServiceEvent.STATUS_CHANGED -> {
|
||||
msg.data?.getStatus()?.let { (state) ->
|
||||
|
||||
@@ -46,6 +46,7 @@ set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/MobileUtils.mm
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
#include <QNetworkReply>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include "amnezia_application.h"
|
||||
#include "configurators/wireguard_configurator.h"
|
||||
#include "core/errorstrings.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -29,7 +27,8 @@ ApiController::ApiController(QObject *parent) : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ApiController::processApiConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData, QString &config)
|
||||
void ApiController::processApiConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData,
|
||||
QString &config)
|
||||
{
|
||||
if (protocol == configKey::cloak) {
|
||||
config.replace("<key>", "<key>\n");
|
||||
@@ -65,45 +64,50 @@ QJsonObject ApiController::fillApiPayload(const QString &protocol, const ApiCont
|
||||
return obj;
|
||||
}
|
||||
|
||||
void ApiController::updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig)
|
||||
ErrorCode ApiController::updateServerConfigFromApi(const QString &installationUuid, QJsonObject &serverConfig)
|
||||
{
|
||||
#ifdef Q_OS_IOS
|
||||
IosController::Instance()->requestInetAccess();
|
||||
QThread::msleep(10);
|
||||
#endif
|
||||
QFutureWatcher<ErrorCode> watcher;
|
||||
|
||||
auto containerConfig = serverConfig.value(config_key::containers).toArray();
|
||||
QFuture<ErrorCode> future = QtConcurrent::run([this, &serverConfig, &installationUuid]() {
|
||||
auto containerConfig = serverConfig.value(config_key::containers).toArray();
|
||||
|
||||
if (serverConfig.value(config_key::configVersion).toInt()) {
|
||||
QNetworkRequest request;
|
||||
request.setTransferTimeout(7000);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Authorization", "Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
|
||||
QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
|
||||
request.setUrl(endpoint);
|
||||
if (serverConfig.value(config_key::configVersion).toInt()) {
|
||||
QNetworkAccessManager manager;
|
||||
|
||||
QString protocol = serverConfig.value(configKey::protocol).toString();
|
||||
QNetworkRequest request;
|
||||
request.setTransferTimeout(7000);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Authorization",
|
||||
"Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
|
||||
QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
|
||||
request.setUrl(endpoint);
|
||||
|
||||
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
|
||||
QString protocol = serverConfig.value(configKey::protocol).toString();
|
||||
|
||||
QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
|
||||
apiPayload[configKey::uuid] = installationUuid;
|
||||
auto apiPayloadData = generateApiPayloadData(protocol);
|
||||
|
||||
QByteArray requestBody = QJsonDocument(apiPayload).toJson();
|
||||
auto apiPayload = fillApiPayload(protocol, apiPayloadData);
|
||||
apiPayload[configKey::uuid] = installationUuid;
|
||||
|
||||
QNetworkReply *reply = amnApp->manager()->post(request, requestBody); // ??
|
||||
QByteArray requestBody = QJsonDocument(apiPayload).toJson();
|
||||
|
||||
QScopedPointer<QNetworkReply> reply;
|
||||
reply.reset(manager.post(request, requestBody));
|
||||
|
||||
QEventLoop wait;
|
||||
QObject::connect(reply.get(), &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||
wait.exec();
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::finished, [this, reply, protocol, apiPayloadData, serverIndex, serverConfig]() mutable {
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QString contents = QString::fromUtf8(reply->readAll());
|
||||
QString data = QJsonDocument::fromJson(contents.toUtf8()).object().value(config_key::config).toString();
|
||||
auto data = QJsonDocument::fromJson(contents.toUtf8()).object().value(config_key::config).toString();
|
||||
|
||||
data.replace("vpn://", "");
|
||||
QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||
QByteArray ba = QByteArray::fromBase64(data.toUtf8(),
|
||||
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||
|
||||
if (ba.isEmpty()) {
|
||||
emit errorOccurred(errorString(ErrorCode::ApiConfigEmptyError));
|
||||
return;
|
||||
return ErrorCode::ApiConfigDownloadError;
|
||||
}
|
||||
|
||||
QByteArray ba_uncompressed = qUncompress(ba);
|
||||
@@ -115,37 +119,30 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
|
||||
processApiConfig(protocol, apiPayloadData, configStr);
|
||||
|
||||
QJsonObject apiConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
|
||||
serverConfig[config_key::dns1] = apiConfig.value(config_key::dns1);
|
||||
serverConfig[config_key::dns2] = apiConfig.value(config_key::dns2);
|
||||
serverConfig[config_key::containers] = apiConfig.value(config_key::containers);
|
||||
serverConfig[config_key::hostName] = apiConfig.value(config_key::hostName);
|
||||
|
||||
serverConfig.insert(config_key::dns1, apiConfig.value(config_key::dns1));
|
||||
serverConfig.insert(config_key::dns2, apiConfig.value(config_key::dns2));
|
||||
serverConfig.insert(config_key::containers, apiConfig.value(config_key::containers));
|
||||
serverConfig.insert(config_key::hostName, apiConfig.value(config_key::hostName));
|
||||
|
||||
auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString();
|
||||
serverConfig[config_key::defaultContainer] = defaultContainer;
|
||||
|
||||
emit configUpdated(true, serverConfig, serverIndex);
|
||||
serverConfig.insert(config_key::defaultContainer, defaultContainer);
|
||||
} else {
|
||||
if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
|
||||
|| reply->error() == QNetworkReply::NetworkError::TimeoutError) {
|
||||
emit errorOccurred(errorString(ErrorCode::ApiConfigTimeoutError));
|
||||
} else {
|
||||
QString err = reply->errorString();
|
||||
qDebug() << QString::fromUtf8(reply->readAll());
|
||||
qDebug() << reply->error();
|
||||
qDebug() << err;
|
||||
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
emit errorOccurred(errorString(ErrorCode::ApiConfigDownloadError));
|
||||
}
|
||||
QString err = reply->errorString();
|
||||
qDebug() << QString::fromUtf8(reply->readAll());
|
||||
qDebug() << reply->error();
|
||||
qDebug() << err;
|
||||
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
return ErrorCode::ApiConfigDownloadError;
|
||||
}
|
||||
}
|
||||
return ErrorCode::NoError;
|
||||
});
|
||||
|
||||
reply->deleteLater();
|
||||
});
|
||||
QEventLoop wait;
|
||||
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, &wait, &QEventLoop::quit);
|
||||
watcher.setFuture(future);
|
||||
wait.exec();
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::errorOccurred,
|
||||
[this, reply](QNetworkReply::NetworkError error) { qDebug() << reply->errorString() << error; });
|
||||
connect(reply, &QNetworkReply::sslErrors, [this, reply](const QList<QSslError> &errors) {
|
||||
qDebug().noquote() << errors;
|
||||
emit errorOccurred(errorString(ErrorCode::ApiConfigSslError));
|
||||
});
|
||||
}
|
||||
return watcher.result();
|
||||
}
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
|
||||
#include "configurators/openvpn_configurator.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "platforms/ios/ios_controller.h"
|
||||
#endif
|
||||
|
||||
class ApiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -17,15 +13,10 @@ public:
|
||||
explicit ApiController(QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig);
|
||||
|
||||
signals:
|
||||
void errorOccurred(const QString &errorMessage);
|
||||
void configUpdated(const bool updateConfig, const QJsonObject &config, const int serverIndex);
|
||||
ErrorCode updateServerConfigFromApi(const QString &installationUuid, QJsonObject &serverConfig);
|
||||
|
||||
private:
|
||||
struct ApiPayloadData
|
||||
{
|
||||
struct ApiPayloadData {
|
||||
OpenVpnConfigurator::ConnectionData certRequest;
|
||||
|
||||
QString wireGuardClientPrivKey;
|
||||
|
||||
@@ -99,9 +99,6 @@ namespace amnezia
|
||||
// Api errors
|
||||
ApiConfigDownloadError = 1100,
|
||||
ApiConfigAlreadyAdded = 1101,
|
||||
ApiConfigEmptyError = 1102,
|
||||
ApiConfigTimeoutError = 1103,
|
||||
ApiConfigSslError = 1104,
|
||||
|
||||
// QFile errors
|
||||
OpenError = 1200,
|
||||
|
||||
@@ -528,7 +528,6 @@ bool Daemon::switchServer(const InterfaceConfig& config) {
|
||||
QJsonObject Daemon::getStatus() {
|
||||
Q_ASSERT(wgutils() != nullptr);
|
||||
QJsonObject json;
|
||||
logger.debug() << "Status request";
|
||||
|
||||
if (!wgutils()->interfaceExists() || m_connections.isEmpty()) {
|
||||
json.insert("connected", QJsonValue(false));
|
||||
|
||||
@@ -46,8 +46,6 @@ DaemonLocalServerConnection::~DaemonLocalServerConnection() {
|
||||
}
|
||||
|
||||
void DaemonLocalServerConnection::readData() {
|
||||
logger.debug() << "Read Data";
|
||||
|
||||
Q_ASSERT(m_socket);
|
||||
|
||||
while (true) {
|
||||
@@ -90,8 +88,6 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
|
||||
}
|
||||
QString type = typeValue.toString();
|
||||
|
||||
logger.debug() << "Command received:" << type;
|
||||
|
||||
if (type == "activate") {
|
||||
InterfaceConfig config;
|
||||
if (!Daemon::parseConfig(obj, config)) {
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
<true/>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Amnezia VPN needs access to the camera for reading QR-codes.</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<false/>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>CFBundleIcons</key>
|
||||
<dict/>
|
||||
<key>CFBundleIcons~ipad</key>
|
||||
|
||||
@@ -64,7 +64,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
qInfo().noquote() << QString("Started %1 version %2 %3").arg(APPLICATION_NAME, APP_VERSION, GIT_COMMIT_HASH);
|
||||
qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture());
|
||||
qInfo().noquote() << QString("SSL backend: %1").arg(QSslSocket::sslLibraryVersionString());
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@@ -273,8 +273,6 @@ void LocalSocketController::deactivate() {
|
||||
}
|
||||
|
||||
void LocalSocketController::checkStatus() {
|
||||
logger.debug() << "Check status";
|
||||
|
||||
if (m_daemonState == eReady || m_daemonState == eInitializing) {
|
||||
Q_ASSERT(m_socket);
|
||||
|
||||
@@ -324,7 +322,6 @@ void LocalSocketController::cleanupBackendLogs() {
|
||||
}
|
||||
|
||||
void LocalSocketController::readData() {
|
||||
logger.debug() << "Reading";
|
||||
|
||||
Q_ASSERT(m_socket);
|
||||
Q_ASSERT(m_daemonState == eInitializing || m_daemonState == eReady);
|
||||
@@ -366,8 +363,6 @@ void LocalSocketController::parseCommand(const QByteArray& command) {
|
||||
}
|
||||
QString type = typeValue.toString();
|
||||
|
||||
logger.debug() << "Parse command:" << type;
|
||||
|
||||
if (m_daemonState == eInitializing && type == "status") {
|
||||
m_daemonState = eReady;
|
||||
|
||||
@@ -393,6 +388,7 @@ void LocalSocketController::parseCommand(const QByteArray& command) {
|
||||
}
|
||||
|
||||
emit initialized(true, connected.toBool(), datetime);
|
||||
checkStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
15
client/platforms/ios/MobileUtils.cpp
Normal file
15
client/platforms/ios/MobileUtils.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "MobileUtils.h"
|
||||
|
||||
MobileUtils::MobileUtils(QObject *parent) : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool MobileUtils::shareText(const QStringList &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QString MobileUtils::openFile()
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
22
client/platforms/ios/MobileUtils.h
Normal file
22
client/platforms/ios/MobileUtils.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef MOBILEUTILS_H
|
||||
#define MOBILEUTILS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
class MobileUtils : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MobileUtils(QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
bool shareText(const QStringList &filesToSend);
|
||||
QString openFile();
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
};
|
||||
|
||||
#endif // MOBILEUTILS_H
|
||||
109
client/platforms/ios/MobileUtils.mm
Normal file
109
client/platforms/ios/MobileUtils.mm
Normal file
@@ -0,0 +1,109 @@
|
||||
#include "MobileUtils.h"
|
||||
|
||||
#include <UIKit/UIKit.h>
|
||||
#include <Security/Security.h>
|
||||
|
||||
#include <QEventLoop>
|
||||
|
||||
static UIViewController* getViewController() {
|
||||
NSArray *windows = [[UIApplication sharedApplication]windows];
|
||||
for (UIWindow *window in windows) {
|
||||
if (window.isKeyWindow) {
|
||||
return window.rootViewController;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
MobileUtils::MobileUtils(QObject *parent) : QObject(parent) {
|
||||
|
||||
}
|
||||
|
||||
bool MobileUtils::shareText(const QStringList& filesToSend) {
|
||||
NSMutableArray *sharingItems = [NSMutableArray new];
|
||||
|
||||
for (int i = 0; i < filesToSend.size(); i++) {
|
||||
NSURL *logFileUrl = [[NSURL alloc] initFileURLWithPath:filesToSend[i].toNSString()];
|
||||
[sharingItems addObject:logFileUrl];
|
||||
}
|
||||
|
||||
UIViewController *qtController = getViewController();
|
||||
if (!qtController) return;
|
||||
|
||||
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
||||
|
||||
__block bool isAccepted = false;
|
||||
|
||||
[activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
|
||||
isAccepted = completed;
|
||||
emit finished();
|
||||
}];
|
||||
|
||||
[qtController presentViewController:activityController animated:YES completion:nil];
|
||||
UIPopoverPresentationController *popController = activityController.popoverPresentationController;
|
||||
if (popController) {
|
||||
popController.sourceView = qtController.view;
|
||||
popController.sourceRect = CGRectMake(100, 100, 100, 100);
|
||||
}
|
||||
|
||||
QEventLoop wait;
|
||||
QObject::connect(this, &MobileUtils::finished, &wait, &QEventLoop::quit);
|
||||
wait.exec();
|
||||
|
||||
return isAccepted;
|
||||
}
|
||||
|
||||
typedef void (^DocumentPickerClosedCallback)(NSString *path);
|
||||
|
||||
@interface DocumentPickerDelegate : NSObject <UIDocumentPickerDelegate>
|
||||
|
||||
@property (nonatomic, copy) DocumentPickerClosedCallback documentPickerClosedCallback;
|
||||
|
||||
@end
|
||||
|
||||
@implementation DocumentPickerDelegate
|
||||
|
||||
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {
|
||||
for (NSURL *url in urls) {
|
||||
if (self.documentPickerClosedCallback) {
|
||||
self.documentPickerClosedCallback([url path]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller {
|
||||
if (self.documentPickerClosedCallback) {
|
||||
self.documentPickerClosedCallback(nil);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
QString MobileUtils::openFile() {
|
||||
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen];
|
||||
|
||||
DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init];
|
||||
documentPicker.delegate = documentPickerDelegate;
|
||||
|
||||
UIViewController *qtController = getViewController();
|
||||
if (!qtController) return;
|
||||
|
||||
[qtController presentViewController:documentPicker animated:YES completion:nil];
|
||||
|
||||
__block QString filePath;
|
||||
|
||||
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
|
||||
if (path) {
|
||||
filePath = QString::fromUtf8(path.UTF8String);
|
||||
} else {
|
||||
filePath = QString();
|
||||
}
|
||||
emit finished();
|
||||
};
|
||||
|
||||
QEventLoop wait;
|
||||
QObject::connect(this, &MobileUtils::finished, &wait, &QEventLoop::quit);
|
||||
wait.exec();
|
||||
|
||||
return filePath;
|
||||
}
|
||||
@@ -50,19 +50,12 @@ public:
|
||||
|
||||
void getBackendLogs(std::function<void(const QString &)> &&callback);
|
||||
void checkStatus();
|
||||
|
||||
bool shareText(const QStringList &filesToSend);
|
||||
QString openFile();
|
||||
|
||||
void requestInetAccess();
|
||||
signals:
|
||||
void connectionStateChanged(Vpn::ConnectionState state);
|
||||
void bytesChanged(quint64 receivedBytes, quint64 sentBytes);
|
||||
void importConfigFromOutside(const QString);
|
||||
void importBackupFromOutside(const QString);
|
||||
|
||||
void finished();
|
||||
|
||||
protected slots:
|
||||
|
||||
private:
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QThread>
|
||||
#include <QEventLoop>
|
||||
|
||||
#include "../protocols/vpnprotocol.h"
|
||||
#import "ios_controller_wrapper.h"
|
||||
@@ -27,15 +26,6 @@ const char* MessageKey::isOnDemand = "is-on-demand";
|
||||
const char* MessageKey::SplitTunnelType = "SplitTunnelType";
|
||||
const char* MessageKey::SplitTunnelSites = "SplitTunnelSites";
|
||||
|
||||
static UIViewController* getViewController() {
|
||||
NSArray *windows = [[UIApplication sharedApplication]windows];
|
||||
for (UIWindow *window in windows) {
|
||||
if (window.isKeyWindow) {
|
||||
return window.rootViewController;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
Vpn::ConnectionState iosStatusToState(NEVPNStatus status) {
|
||||
switch (status) {
|
||||
@@ -713,86 +703,3 @@ void IosController::sendVpnExtensionMessage(NSDictionary* message, std::function
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IosController::shareText(const QStringList& filesToSend) {
|
||||
NSMutableArray *sharingItems = [NSMutableArray new];
|
||||
|
||||
for (int i = 0; i < filesToSend.size(); i++) {
|
||||
NSURL *logFileUrl = [[NSURL alloc] initFileURLWithPath:filesToSend[i].toNSString()];
|
||||
[sharingItems addObject:logFileUrl];
|
||||
}
|
||||
|
||||
UIViewController *qtController = getViewController();
|
||||
if (!qtController) return;
|
||||
|
||||
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
||||
|
||||
__block bool isAccepted = false;
|
||||
|
||||
[activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
|
||||
isAccepted = completed;
|
||||
emit finished();
|
||||
}];
|
||||
|
||||
[qtController presentViewController:activityController animated:YES completion:nil];
|
||||
UIPopoverPresentationController *popController = activityController.popoverPresentationController;
|
||||
if (popController) {
|
||||
popController.sourceView = qtController.view;
|
||||
popController.sourceRect = CGRectMake(100, 100, 100, 100);
|
||||
}
|
||||
|
||||
QEventLoop wait;
|
||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||
wait.exec();
|
||||
|
||||
return isAccepted;
|
||||
}
|
||||
|
||||
QString IosController::openFile() {
|
||||
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen];
|
||||
|
||||
DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init];
|
||||
documentPicker.delegate = documentPickerDelegate;
|
||||
|
||||
UIViewController *qtController = getViewController();
|
||||
if (!qtController) return;
|
||||
|
||||
[qtController presentViewController:documentPicker animated:YES completion:nil];
|
||||
|
||||
__block QString filePath;
|
||||
|
||||
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
|
||||
if (path) {
|
||||
filePath = QString::fromUtf8(path.UTF8String);
|
||||
} else {
|
||||
filePath = QString();
|
||||
}
|
||||
emit finished();
|
||||
};
|
||||
|
||||
QEventLoop wait;
|
||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||
wait.exec();
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
void IosController::requestInetAccess() {
|
||||
NSURL *url = [NSURL URLWithString:@"http://captive.apple.com/generate_204"];
|
||||
if (url) {
|
||||
qDebug() << "IosController::requestInetAccess URL error";
|
||||
return;
|
||||
}
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
if (error) {
|
||||
qDebug() << "IosController::requestInetAccess error:" << error.localizedDescription;
|
||||
} else {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
QString responseBody = QString::fromUtf8((const char*)data.bytes, data.length);
|
||||
qDebug() << "IosController::requestInetAccess server response:" << httpResponse.statusCode << "\n\n" <<responseBody;
|
||||
}
|
||||
}];
|
||||
[task resume];
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#import <NetworkExtension/NetworkExtension.h>
|
||||
#import <NetworkExtension/NETunnelProviderSession.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <UIKit/UIKit.h>
|
||||
#include <Security/Security.h>
|
||||
|
||||
class IosController;
|
||||
|
||||
@@ -15,11 +13,3 @@ class IosController;
|
||||
- (void)vpnConfigurationDidChange:(NSNotification *)notification;
|
||||
|
||||
@end
|
||||
|
||||
typedef void (^DocumentPickerClosedCallback)(NSString *path);
|
||||
|
||||
@interface DocumentPickerDelegate : NSObject <UIDocumentPickerDelegate>
|
||||
|
||||
@property (nonatomic, copy) DocumentPickerClosedCallback documentPickerClosedCallback;
|
||||
|
||||
@end
|
||||
|
||||
@@ -24,22 +24,5 @@
|
||||
// cppController->vpnStatusDidChange(notification);
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation DocumentPickerDelegate
|
||||
|
||||
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {
|
||||
for (NSURL *url in urls) {
|
||||
if (self.documentPickerClosedCallback) {
|
||||
self.documentPickerClosedCallback([url path]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller {
|
||||
if (self.documentPickerClosedCallback) {
|
||||
self.documentPickerClosedCallback(nil);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -20,9 +20,20 @@ WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject *
|
||||
});
|
||||
connect(m_impl.get(), &ControllerImpl::disconnected, this,
|
||||
[this]() { emit connectionStateChanged(Vpn::ConnectionState::Disconnected); });
|
||||
|
||||
connect(m_impl.get(), &ControllerImpl::statusUpdated, this,
|
||||
&WireguardProtocol::statusUpdated);
|
||||
|
||||
m_impl->initialize(nullptr, nullptr);
|
||||
}
|
||||
|
||||
void WireguardProtocol::statusUpdated(const QString& serverIpv4Gateway, const QString& deviceIpv4Address,
|
||||
uint64_t txBytes, uint64_t rxBytes) {
|
||||
setBytesChanged(rxBytes, txBytes);
|
||||
QThread::msleep(1000);
|
||||
m_impl->checkStatus();
|
||||
}
|
||||
|
||||
WireguardProtocol::~WireguardProtocol()
|
||||
{
|
||||
WireguardProtocol::stop();
|
||||
|
||||
@@ -21,7 +21,8 @@ public:
|
||||
|
||||
ErrorCode start() override;
|
||||
void stop() override;
|
||||
|
||||
void statusUpdated(const QString& serverIpv4Gateway, const QString& deviceIpv4Address,
|
||||
uint64_t txBytes, uint64_t rxBytes);
|
||||
ErrorCode startMzImpl();
|
||||
ErrorCode stopMzImpl();
|
||||
|
||||
|
||||
@@ -225,6 +225,7 @@
|
||||
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
|
||||
<file>images/controls/close.svg</file>
|
||||
<file>images/controls/search.svg</file>
|
||||
<file>ui/qml/Controls2/GraphViewType.qml</file>
|
||||
<file>server_scripts/xray/configure_container.sh</file>
|
||||
<file>server_scripts/xray/Dockerfile</file>
|
||||
<file>server_scripts/xray/run_container.sh</file>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "secure_qsettings.h"
|
||||
#include "platforms/ios/MobileUtils.h"
|
||||
|
||||
#include "QAead.h"
|
||||
#include "QBlockCipher.h"
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
#endif
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include "core/controllers/apiController.h"
|
||||
#include "core/controllers/vpnConfigurationController.h"
|
||||
#include "core/errorstrings.h"
|
||||
#include "utilities.h"
|
||||
#include "version.h"
|
||||
|
||||
ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &serversModel,
|
||||
@@ -17,7 +19,6 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
|
||||
const QSharedPointer<VpnConnection> &vpnConnection, const std::shared_ptr<Settings> &settings,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_apiController(this),
|
||||
m_serversModel(serversModel),
|
||||
m_containersModel(containersModel),
|
||||
m_clientManagementModel(clientManagementModel),
|
||||
@@ -28,9 +29,22 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
|
||||
connect(this, &ConnectionController::connectToVpn, m_vpnConnection.get(), &VpnConnection::connectToVpn, Qt::QueuedConnection);
|
||||
connect(this, &ConnectionController::disconnectFromVpn, m_vpnConnection.get(), &VpnConnection::disconnectFromVpn, Qt::QueuedConnection);
|
||||
|
||||
connect(&m_apiController, &ApiController::configUpdated, this,
|
||||
static_cast<void (ConnectionController::*)(const bool, const QJsonObject &, const int)>(&ConnectionController::openConnection));
|
||||
connect(&m_apiController, &ApiController::errorOccurred, this, &ConnectionController::connectionErrorOccurred);
|
||||
connect(m_vpnConnection.get(), &VpnConnection::bytesChanged, this, [this](quint64 rx, quint64 tx) {
|
||||
m_rxBytes = rx;
|
||||
m_txBytes = tx;
|
||||
});
|
||||
connect(&m_tick, &QTimer::timeout, this, [this]() {
|
||||
quint64 time = QDateTime::currentSecsSinceEpoch();
|
||||
if (m_times.length() > viewSize) {
|
||||
m_times.removeFirst();
|
||||
m_rxView.removeFirst();
|
||||
m_txView.removeFirst();
|
||||
}
|
||||
m_times.append(time);
|
||||
m_rxView.append(m_rxBytes);
|
||||
m_txView.append(m_txBytes);
|
||||
emit bytesChanged();
|
||||
});
|
||||
|
||||
m_state = Vpn::ConnectionState::Disconnected;
|
||||
}
|
||||
@@ -38,24 +52,71 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
|
||||
void ConnectionController::openConnection()
|
||||
{
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true))
|
||||
{
|
||||
if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true)) {
|
||||
emit connectionErrorOccurred(errorString(ErrorCode::AmneziaServiceNotRunning));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int serverIndex = m_serversModel->getDefaultServerIndex();
|
||||
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
|
||||
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing);
|
||||
|
||||
if (serverConfig.value(config_key::configVersion).toInt()
|
||||
&& !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
|
||||
m_apiController.updateServerConfigFromApi(m_settings->getInstallationUuid(true), serverIndex, serverConfig);
|
||||
} else {
|
||||
openConnection(false, serverConfig, serverIndex);
|
||||
ApiController apiController;
|
||||
errorCode = apiController.updateServerConfigFromApi(m_settings->getInstallationUuid(true), serverConfig);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit connectionErrorOccurred(errorString(errorCode));
|
||||
return;
|
||||
}
|
||||
m_serversModel->editServer(serverConfig, serverIndex);
|
||||
}
|
||||
|
||||
if (!m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
|
||||
emit noInstalledContainers();
|
||||
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
|
||||
return;
|
||||
}
|
||||
|
||||
DockerContainer container = qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
|
||||
|
||||
if (!m_containersModel->isSupportedByCurrentPlatform(container)) {
|
||||
emit connectionErrorOccurred(tr("The selected protocol is not supported on the current platform"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (container == DockerContainer::None) {
|
||||
emit connectionErrorOccurred(tr("VPN Protocols is not installed.\n Please install VPN container at first"));
|
||||
return;
|
||||
}
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
|
||||
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
|
||||
|
||||
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
|
||||
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
|
||||
errorCode = updateProtocolConfig(container, credentials, containerConfig, serverController);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit connectionErrorOccurred(errorString(errorCode));
|
||||
return;
|
||||
}
|
||||
|
||||
auto dns = m_serversModel->getDnsPair(serverIndex);
|
||||
serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
|
||||
auto vpnConfiguration = vpnConfigurationController.createVpnConfiguration(dns, serverConfig, containerConfig, container, errorCode);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit connectionErrorOccurred(tr("unable to create configuration"));
|
||||
return;
|
||||
}
|
||||
|
||||
emit connectToVpn(serverIndex, credentials, container, vpnConfiguration);
|
||||
}
|
||||
|
||||
void ConnectionController::closeConnection()
|
||||
@@ -79,6 +140,7 @@ void ConnectionController::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
m_isConnectionInProgress = false;
|
||||
m_isConnected = true;
|
||||
m_connectionStateText = tr("Connected");
|
||||
m_tick.start(1000);
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Connecting: {
|
||||
@@ -98,6 +160,7 @@ void ConnectionController::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
case Vpn::ConnectionState::Disconnecting: {
|
||||
m_isConnectionInProgress = true;
|
||||
m_connectionStateText = tr("Disconnecting...");
|
||||
m_tick.stop();
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Preparing: {
|
||||
@@ -147,6 +210,30 @@ QString ConnectionController::connectionStateText() const
|
||||
return m_connectionStateText;
|
||||
}
|
||||
|
||||
quint64 ConnectionController::rxBytes() const
|
||||
{
|
||||
return m_rxBytes;
|
||||
}
|
||||
|
||||
quint64 ConnectionController::txBytes() const
|
||||
{
|
||||
return m_txBytes;
|
||||
}
|
||||
|
||||
QVector<quint64> ConnectionController::getRxView() const
|
||||
{
|
||||
return m_rxView;
|
||||
}
|
||||
|
||||
QVector<quint64> ConnectionController::getTxView() const
|
||||
{
|
||||
return m_txView;
|
||||
}
|
||||
|
||||
QVector<quint64> ConnectionController::getTimes() const
|
||||
{
|
||||
return m_times;
|
||||
}
|
||||
void ConnectionController::toggleConnection()
|
||||
{
|
||||
if (m_state == Vpn::ConnectionState::Preparing) {
|
||||
@@ -186,53 +273,6 @@ bool ConnectionController::isProtocolConfigExists(const QJsonObject &containerCo
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConnectionController::openConnection(const bool updateConfig, const QJsonObject &config, const int serverIndex)
|
||||
{
|
||||
// Update config for this server as it was received from API
|
||||
if (updateConfig) {
|
||||
m_serversModel->editServer(config, serverIndex);
|
||||
}
|
||||
|
||||
if (!m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
|
||||
emit noInstalledContainers();
|
||||
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
|
||||
return;
|
||||
}
|
||||
|
||||
DockerContainer container = qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
|
||||
|
||||
if (!m_containersModel->isSupportedByCurrentPlatform(container)) {
|
||||
emit connectionErrorOccurred(tr("The selected protocol is not supported on the current platform"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (container == DockerContainer::None) {
|
||||
emit connectionErrorOccurred(tr("VPN Protocols is not installed.\n Please install VPN container at first"));
|
||||
return;
|
||||
}
|
||||
|
||||
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
|
||||
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
|
||||
|
||||
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
|
||||
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
|
||||
ErrorCode errorCode = updateProtocolConfig(container, credentials, containerConfig, serverController);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit connectionErrorOccurred(errorString(errorCode));
|
||||
return;
|
||||
}
|
||||
|
||||
auto dns = m_serversModel->getDnsPair(serverIndex);
|
||||
|
||||
auto vpnConfiguration = vpnConfigurationController.createVpnConfiguration(dns, config, containerConfig, container, errorCode);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit connectionErrorOccurred(tr("unable to create configuration"));
|
||||
return;
|
||||
}
|
||||
|
||||
emit connectToVpn(serverIndex, credentials, container, vpnConfiguration);
|
||||
}
|
||||
|
||||
ErrorCode ConnectionController::updateProtocolConfig(const DockerContainer container, const ServerCredentials &credentials,
|
||||
QJsonObject &containerConfig, QSharedPointer<ServerController> serverController)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef CONNECTIONCONTROLLER_H
|
||||
#define CONNECTIONCONTROLLER_H
|
||||
|
||||
#include "core/controllers/apiController.h"
|
||||
#include "protocols/vpnprotocol.h"
|
||||
#include "ui/models/clientManagementModel.h"
|
||||
#include "ui/models/containers_model.h"
|
||||
@@ -16,6 +15,8 @@ public:
|
||||
Q_PROPERTY(bool isConnected READ isConnected NOTIFY connectionStateChanged)
|
||||
Q_PROPERTY(bool isConnectionInProgress READ isConnectionInProgress NOTIFY connectionStateChanged)
|
||||
Q_PROPERTY(QString connectionStateText READ connectionStateText NOTIFY connectionStateChanged)
|
||||
Q_PROPERTY(quint64 rxBytes READ rxBytes NOTIFY bytesChanged)
|
||||
Q_PROPERTY(quint64 txBytes READ txBytes NOTIFY bytesChanged)
|
||||
|
||||
explicit ConnectionController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
|
||||
const QSharedPointer<ClientManagementModel> &clientManagementModel,
|
||||
@@ -27,6 +28,12 @@ public:
|
||||
bool isConnected() const;
|
||||
bool isConnectionInProgress() const;
|
||||
QString connectionStateText() const;
|
||||
quint64 rxBytes() const;
|
||||
quint64 txBytes() const;
|
||||
|
||||
Q_INVOKABLE QVector<quint64> getRxView() const;
|
||||
Q_INVOKABLE QVector<quint64> getTxView() const;
|
||||
Q_INVOKABLE QVector<quint64> getTimes() const;
|
||||
|
||||
public slots:
|
||||
void toggleConnection();
|
||||
@@ -51,6 +58,7 @@ signals:
|
||||
|
||||
void connectionErrorOccurred(const QString &errorMessage);
|
||||
void reconnectWithUpdatedContainer(const QString &message);
|
||||
void bytesChanged();
|
||||
|
||||
void noInstalledContainers();
|
||||
|
||||
@@ -61,10 +69,6 @@ private:
|
||||
Vpn::ConnectionState getCurrentConnectionState();
|
||||
bool isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container);
|
||||
|
||||
void openConnection(const bool updateConfig, const QJsonObject &config, const int serverIndex);
|
||||
|
||||
ApiController m_apiController;
|
||||
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
QSharedPointer<ContainersModel> m_containersModel;
|
||||
QSharedPointer<ClientManagementModel> m_clientManagementModel;
|
||||
@@ -76,8 +80,17 @@ private:
|
||||
bool m_isConnected = false;
|
||||
bool m_isConnectionInProgress = false;
|
||||
QString m_connectionStateText = tr("Connect");
|
||||
quint64 m_rxBytes = 0;
|
||||
quint64 m_txBytes = 0;
|
||||
QVector<quint64> m_rxView{};
|
||||
QVector<quint64> m_txView{};
|
||||
QVector<quint64> m_times{};
|
||||
|
||||
QTimer m_tick{};
|
||||
|
||||
Vpn::ConnectionState m_state;
|
||||
|
||||
const static quint8 viewSize{60};
|
||||
};
|
||||
|
||||
#endif // CONNECTIONCONTROLLER_H
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "platforms/ios/ios_controller.h"
|
||||
#include "platforms/ios/MobileUtils.h"
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,20 @@ SystemController::SystemController(const std::shared_ptr<Settings> &settings, QO
|
||||
{
|
||||
}
|
||||
|
||||
void SystemController::setAppHasFocus(bool appHasFocus)
|
||||
{
|
||||
if (m_appHasFocus != appHasFocus)
|
||||
{
|
||||
m_appHasFocus = appHasFocus;
|
||||
emit appHasFocusChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool SystemController::appHasFocus() const
|
||||
{
|
||||
return m_appHasFocus;
|
||||
}
|
||||
|
||||
void SystemController::saveFile(QString fileName, const QString &data)
|
||||
{
|
||||
#if defined Q_OS_ANDROID
|
||||
@@ -46,8 +60,9 @@ void SystemController::saveFile(QString fileName, const QString &data)
|
||||
#ifdef Q_OS_IOS
|
||||
QStringList filesToSend;
|
||||
filesToSend.append(fileUrl.toString());
|
||||
MobileUtils mobileUtils;
|
||||
// todo check if save successful
|
||||
IosController::Instance()->shareText(filesToSend);
|
||||
mobileUtils.shareText(filesToSend);
|
||||
return;
|
||||
#else
|
||||
QFileInfo fi(fileName);
|
||||
@@ -66,7 +81,8 @@ QString SystemController::getFileName(const QString &acceptLabel, const QString
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
|
||||
fileName = IosController::Instance()->openFile();
|
||||
MobileUtils mobileUtils;
|
||||
fileName = mobileUtils.openFile();
|
||||
if (fileName.isEmpty()) {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,13 @@
|
||||
class SystemController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool appHasFocus READ appHasFocus WRITE setAppHasFocus NOTIFY appHasFocusChanged)
|
||||
public:
|
||||
explicit SystemController(const std::shared_ptr<Settings> &setting, QObject *parent = nullptr);
|
||||
|
||||
void setAppHasFocus(bool isActive);
|
||||
bool appHasFocus() const;
|
||||
|
||||
static void saveFile(QString fileName, const QString &data);
|
||||
|
||||
public slots:
|
||||
@@ -21,11 +25,13 @@ public slots:
|
||||
|
||||
signals:
|
||||
void fileDialogClosed(const bool isAccepted);
|
||||
void appHasFocusChanged();
|
||||
|
||||
private:
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
|
||||
QObject *m_qmlRoot;
|
||||
bool m_appHasFocus{false};
|
||||
};
|
||||
|
||||
#endif // SYSTEMCONTROLLER_H
|
||||
|
||||
125
client/ui/qml/Controls2/GraphViewType.qml
Normal file
125
client/ui/qml/Controls2/GraphViewType.qml
Normal file
@@ -0,0 +1,125 @@
|
||||
import QtQuick
|
||||
import QtCharts
|
||||
|
||||
ChartView {
|
||||
id: chartView
|
||||
legend.visible: false
|
||||
animationOptions: ChartView.AllAnimations
|
||||
animationDuration: 2000.0
|
||||
|
||||
backgroundColor: "#1C1D21"
|
||||
plotAreaColor: "#1C1D21"
|
||||
margins.top: 0
|
||||
margins.bottom: 0
|
||||
margins.left: 0
|
||||
margins.right: 0
|
||||
antialiasing: true
|
||||
enabled: false
|
||||
|
||||
property bool shouldUpdate: SystemController.appHasFocus
|
||||
|
||||
function getUTCSeconds() {
|
||||
return new Date().setMilliseconds(0) / 1000
|
||||
}
|
||||
|
||||
function addValues(rx, tx) {
|
||||
let currentTime = getUTCSeconds()
|
||||
|
||||
xAxis.min = currentTime - 60
|
||||
xAxis.max = currentTime
|
||||
|
||||
if (rx > yAxis.max) yAxis.max = rx * 1.1
|
||||
if (tx > yAxis.max) yAxis.max = tx * 1.1
|
||||
|
||||
rxLine.append(currentTime, rx)
|
||||
txLine.append(currentTime, tx)
|
||||
}
|
||||
|
||||
function printAll() {
|
||||
var rxValues = ConnectionController.getRxView()
|
||||
var txValues = ConnectionController.getTxView()
|
||||
var times = ConnectionController.getTimes()
|
||||
|
||||
let currentTime = getUTCSeconds()
|
||||
xAxis.min = currentTime - 60
|
||||
xAxis.max = currentTime
|
||||
|
||||
|
||||
rxLine.clear()
|
||||
txLine.clear()
|
||||
|
||||
if (times.length === 0) return
|
||||
|
||||
xAxis.min = times[0]
|
||||
xAxis.max = times[times.length - 1]
|
||||
|
||||
for (let i = 0; i < times.length; i++)
|
||||
{
|
||||
if (rxValues[i] > yAxis.max) yAxis.max = rxValues[i]
|
||||
if (txValues[i] > yAxis.max) yAxis.max = txValues[i]
|
||||
|
||||
rxLine.append(times[i], rxValues[i])
|
||||
txLine.append(times[i], txValues[i])
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
printAll()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ConnectionController
|
||||
function onBytesChanged() {
|
||||
if (shouldUpdate) {
|
||||
addValues(ConnectionController.rxBytes, ConnectionController.txBytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SystemController
|
||||
function onAppHasFocusChanged() {
|
||||
if (shouldUpdate) { printAll() }
|
||||
}
|
||||
}
|
||||
|
||||
ValueAxis {
|
||||
id: yAxis
|
||||
min: -100
|
||||
max: 1000
|
||||
visible: false
|
||||
labelsVisible: false
|
||||
gridLineColor: "transparent"
|
||||
}
|
||||
|
||||
ValueAxis {
|
||||
id: xAxis
|
||||
visible: false
|
||||
labelsVisible: false
|
||||
gridLineColor: "transparent"
|
||||
}
|
||||
|
||||
SplineSeries {
|
||||
id: rxLine
|
||||
name: "Received Bytes"
|
||||
//width: 2
|
||||
axisX: xAxis
|
||||
axisY: yAxis
|
||||
capStyle: Qt.RoundCap
|
||||
useOpenGL: true
|
||||
color: "#70553c"
|
||||
XYPoint { x: getUTCSeconds(); y: 0 }
|
||||
}
|
||||
|
||||
SplineSeries {
|
||||
id: txLine
|
||||
name: "Transmitted Bytes"
|
||||
//width: 2
|
||||
axisX: xAxis
|
||||
axisY: yAxis
|
||||
capStyle: Qt.RoundCap
|
||||
useOpenGL: true
|
||||
color: "#737274"
|
||||
XYPoint { x: getUTCSeconds(); y: 0 }
|
||||
}
|
||||
}
|
||||
@@ -261,10 +261,15 @@ PageType {
|
||||
|
||||
LabelTextType {
|
||||
id: collapsedServerMenuDescription
|
||||
Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
|
||||
}
|
||||
|
||||
GraphViewType {
|
||||
Layout.minimumHeight: 50
|
||||
Layout.bottomMargin: drawer.isCollapsed ? 24 : ServersModel.isDefaultServerFromApi ? 69 : 24
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
||||
@@ -28,6 +28,10 @@ Window {
|
||||
PageController.closeWindow()
|
||||
}
|
||||
|
||||
onActiveChanged: {
|
||||
SystemController.appHasFocus = active
|
||||
}
|
||||
|
||||
title: "AmneziaVPN"
|
||||
|
||||
StackViewType {
|
||||
|
||||
Reference in New Issue
Block a user