1
.gitignore
vendored
|
|
@ -8,6 +8,7 @@ deploy/build/*
|
||||||
deploy/build_32/*
|
deploy/build_32/*
|
||||||
deploy/build_64/*
|
deploy/build_64/*
|
||||||
winbuild*.bat
|
winbuild*.bat
|
||||||
|
.cache/
|
||||||
|
|
||||||
|
|
||||||
# Qt-es
|
# Qt-es
|
||||||
|
|
|
||||||
6
.gitmodules
vendored
|
|
@ -1,6 +1,3 @@
|
||||||
[submodule "client/3rd/wireguard-apple"]
|
|
||||||
path = client/3rd/wireguard-apple
|
|
||||||
url = https://github.com/WireGuard/wireguard-apple
|
|
||||||
[submodule "client/3rd/OpenVPNAdapter"]
|
[submodule "client/3rd/OpenVPNAdapter"]
|
||||||
path = client/3rd/OpenVPNAdapter
|
path = client/3rd/OpenVPNAdapter
|
||||||
url = https://github.com/amnezia-vpn/OpenVPNAdapter.git
|
url = https://github.com/amnezia-vpn/OpenVPNAdapter.git
|
||||||
|
|
@ -25,3 +22,6 @@
|
||||||
[submodule "client/3rd-prebuilt"]
|
[submodule "client/3rd-prebuilt"]
|
||||||
path = client/3rd-prebuilt
|
path = client/3rd-prebuilt
|
||||||
url = https://github.com/amnezia-vpn/3rd-prebuilt
|
url = https://github.com/amnezia-vpn/3rd-prebuilt
|
||||||
|
[submodule "client/3rd/awg-apple"]
|
||||||
|
path = client/3rd/awg-apple
|
||||||
|
url = https://github.com/amnezia-vpn/awg-apple
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,14 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||||
|
|
||||||
set(PROJECT AmneziaVPN)
|
set(PROJECT AmneziaVPN)
|
||||||
|
|
||||||
project(${PROJECT} VERSION 3.1.0.1
|
project(${PROJECT} VERSION 4.0.8.6
|
||||||
DESCRIPTION "AmneziaVPN"
|
DESCRIPTION "AmneziaVPN"
|
||||||
HOMEPAGE_URL "https://amnezia.org/"
|
HOMEPAGE_URL "https://amnezia.org/"
|
||||||
)
|
)
|
||||||
set(RELEASE_DATE "2023-09-21")
|
|
||||||
|
string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
||||||
|
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||||
|
|
||||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit e8795854a5cf27004fe78caecc90a961688d1d41
|
Subproject commit ac32d33555bd62f0b0af314b1e5119d6d78a1a4e
|
||||||
1
client/3rd/awg-apple
vendored
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit fab07138dbab06ac0de256021e47e273f4df8e88
|
||||||
2
client/3rd/qtkeychain
vendored
|
|
@ -1 +1 @@
|
||||||
Subproject commit c6f0b66318f8da6917fb4681103f7303b1836194
|
Subproject commit 8bbaa6d8302cf0747d9786ace4dd13c7fb746502
|
||||||
1
client/3rd/wireguard-apple
vendored
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 23618f994f17d8ad8f2f65d79b4a1e8a0830b334
|
|
||||||
|
|
@ -10,30 +10,34 @@ set_property(GLOBAL PROPERTY AUTOMOC_TARGETS_FOLDER "Autogen")
|
||||||
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "Autogen")
|
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "Autogen")
|
||||||
|
|
||||||
set(PACKAGES
|
set(PACKAGES
|
||||||
Widgets Core Gui Network Xml
|
Core Gui Network Xml
|
||||||
RemoteObjects Quick Svg QuickControls2
|
RemoteObjects Quick Svg QuickControls2
|
||||||
Core5Compat Concurrent LinguistTools
|
Core5Compat Concurrent LinguistTools
|
||||||
)
|
)
|
||||||
|
|
||||||
if(IOS)
|
if(IOS)
|
||||||
set(PACKAGES
|
set(PACKAGES ${PACKAGES} Multimedia)
|
||||||
${PACKAGES}
|
endif()
|
||||||
Multimedia
|
|
||||||
)
|
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||||
|
set(PACKAGES ${PACKAGES} Widgets)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS ${PACKAGES})
|
find_package(Qt6 REQUIRED COMPONENTS ${PACKAGES})
|
||||||
|
|
||||||
set(LIBS ${LIBS}
|
set(LIBS ${LIBS}
|
||||||
Qt6::Widgets Qt6::Core Qt6::Gui
|
Qt6::Core Qt6::Gui
|
||||||
Qt6::Network Qt6::Xml Qt6::RemoteObjects
|
Qt6::Network Qt6::Xml Qt6::RemoteObjects
|
||||||
Qt6::Quick Qt6::Svg Qt6::QuickControls2
|
Qt6::Quick Qt6::Svg Qt6::QuickControls2
|
||||||
Qt6::Core5Compat Qt6::Concurrent
|
Qt6::Core5Compat Qt6::Concurrent
|
||||||
)
|
)
|
||||||
|
|
||||||
if(IOS)
|
if(IOS)
|
||||||
set(LIBS
|
set(LIBS ${LIBS} Qt6::Multimedia)
|
||||||
${LIBS}
|
endif()
|
||||||
Qt6::Multimedia
|
|
||||||
)
|
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||||
|
set(LIBS ${LIBS} Qt6::Widgets)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
qt_standard_project_setup()
|
qt_standard_project_setup()
|
||||||
|
|
@ -46,12 +50,30 @@ endif()
|
||||||
|
|
||||||
qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc)
|
qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc)
|
||||||
|
|
||||||
qt6_add_translations(${PROJECT} TS_FILES
|
# -- i18n begin
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
|
set(AMNEZIAVPN_TS_FILES
|
||||||
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru.ts
|
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru.ts
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_zh_CN.ts
|
||||||
)
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE AMNEZIAVPN_TS_SOURCES *.qrc *.cpp *.h *.ui)
|
||||||
|
|
||||||
|
qt_create_translation(AMNEZIAVPN_QM_FILES ${AMNEZIAVPN_TS_SOURCES} ${AMNEZIAVPN_TS_FILES})
|
||||||
|
|
||||||
|
set(QM_FILE_LIST "")
|
||||||
|
foreach(FILE ${AMNEZIAVPN_QM_FILES})
|
||||||
|
get_filename_component(QM_FILE_NAME ${FILE} NAME)
|
||||||
|
list(APPEND QM_FILE_LIST "<file>${QM_FILE_NAME}</file>")
|
||||||
|
endforeach()
|
||||||
|
string(REPLACE ";" "" QM_FILE_LIST ${QM_FILE_LIST})
|
||||||
|
|
||||||
|
configure_file(${CMAKE_CURRENT_LIST_DIR}/translations/translations.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
|
||||||
|
qt6_add_resources(QRC ${I18NQRC} ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
|
||||||
|
# -- i18n end
|
||||||
|
|
||||||
if(IOS)
|
if(IOS)
|
||||||
#execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/scripts/run-build-cloak.sh)
|
|
||||||
execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/ios/scripts/openvpn.sh args
|
execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/ios/scripts/openvpn.sh args
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
|
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -91,7 +113,6 @@ set(HEADERS ${HEADERS}
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.h
|
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ui/pages.h
|
${CMAKE_CURRENT_LIST_DIR}/ui/pages.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ui/property_helper.h
|
${CMAKE_CURRENT_LIST_DIR}/ui/property_helper.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ui/uilogic.h
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.h
|
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.h
|
${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.h
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/version.h
|
${CMAKE_CURRENT_BINARY_DIR}/version.h
|
||||||
|
|
@ -128,7 +149,6 @@ set(SOURCES ${SOURCES}
|
||||||
${CMAKE_CURRENT_LIST_DIR}/core/servercontroller.cpp
|
${CMAKE_CURRENT_LIST_DIR}/core/servercontroller.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.cpp
|
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.cpp
|
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ui/uilogic.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.cpp
|
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.cpp
|
${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/core/sshclient.cpp
|
${CMAKE_CURRENT_LIST_DIR}/core/sshclient.cpp
|
||||||
|
|
@ -162,20 +182,33 @@ file(GLOB_RECURSE PAGE_LOGIC_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/
|
||||||
file(GLOB CONFIGURATORS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/configurators/*.h)
|
file(GLOB CONFIGURATORS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/configurators/*.h)
|
||||||
file(GLOB CONFIGURATORS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/configurators/*.cpp)
|
file(GLOB CONFIGURATORS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/configurators/*.cpp)
|
||||||
|
|
||||||
file(GLOB UI_MODELS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/models/*.h)
|
file(GLOB UI_MODELS_H CONFIGURE_DEPENDS
|
||||||
file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/models/*.cpp)
|
${CMAKE_CURRENT_LIST_DIR}/ui/models/*.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/ui/models/protocols/*.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.h
|
||||||
|
)
|
||||||
|
file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/ui/models/*.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/ui/models/protocols/*.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.h)
|
||||||
|
file(GLOB UI_CONTROLLERS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.cpp)
|
||||||
|
|
||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
${COMMON_FILES_H}
|
${COMMON_FILES_H}
|
||||||
${PAGE_LOGIC_H}
|
${PAGE_LOGIC_H}
|
||||||
${CONFIGURATORS_H}
|
${CONFIGURATORS_H}
|
||||||
${UI_MODELS_H}
|
${UI_MODELS_H}
|
||||||
|
${UI_CONTROLLERS_H}
|
||||||
)
|
)
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${COMMON_FILES_CPP}
|
${COMMON_FILES_CPP}
|
||||||
${PAGE_LOGIC_CPP}
|
${PAGE_LOGIC_CPP}
|
||||||
${CONFIGURATORS_CPP}
|
${CONFIGURATORS_CPP}
|
||||||
${UI_MODELS_CPP}
|
${UI_MODELS_CPP}
|
||||||
|
${UI_CONTROLLERS_CPP}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|
@ -248,6 +281,7 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.h
|
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.h
|
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.h
|
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/protocols/awgprotocol.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
|
|
@ -258,6 +292,7 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.cpp
|
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.cpp
|
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.cpp
|
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/protocols/awgprotocol.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -307,16 +342,5 @@ if(NOT IOS AND NOT ANDROID)
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC})
|
||||||
add_custom_command(
|
|
||||||
TARGET ${PROJECT} POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:Debug>,copy,true>
|
|
||||||
$<TARGET_FILE_DIR:${PROJECT}>/../service/wireguard-service/wireguard-service.exe
|
|
||||||
$<TARGET_FILE_DIR:${PROJECT}>/wireguard/wireguard-service.exe
|
|
||||||
COMMAND_EXPAND_LISTS
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC})
|
|
||||||
qt_finalize_target(${PROJECT})
|
qt_finalize_target(${PROJECT})
|
||||||
|
|
|
||||||
|
|
@ -3,55 +3,35 @@
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
|
#include <QQuickStyle>
|
||||||
|
#include <QResource>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
|
||||||
|
#include <QQuickItem>
|
||||||
|
|
||||||
#include "core/servercontroller.h"
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include <QQuickStyle>
|
|
||||||
|
|
||||||
#include "platforms/ios/QRCodeReaderBase.h"
|
#include "platforms/ios/QRCodeReaderBase.h"
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
#include "ui/pages.h"
|
#include "platforms/android/android_controller.h"
|
||||||
|
#endif
|
||||||
#include "ui/pages_logic/AppSettingsLogic.h"
|
|
||||||
#include "ui/pages_logic/GeneralSettingsLogic.h"
|
|
||||||
#include "ui/pages_logic/NetworkSettingsLogic.h"
|
|
||||||
#include "ui/pages_logic/NewServerProtocolsLogic.h"
|
|
||||||
#include "ui/pages_logic/QrDecoderLogic.h"
|
|
||||||
#include "ui/pages_logic/ServerConfiguringProgressLogic.h"
|
|
||||||
#include "ui/pages_logic/ServerContainersLogic.h"
|
|
||||||
#include "ui/pages_logic/ServerListLogic.h"
|
|
||||||
#include "ui/pages_logic/ServerSettingsLogic.h"
|
|
||||||
#include "ui/pages_logic/ServerContainersLogic.h"
|
|
||||||
#include "ui/pages_logic/ShareConnectionLogic.h"
|
|
||||||
#include "ui/pages_logic/SitesLogic.h"
|
|
||||||
#include "ui/pages_logic/StartPageLogic.h"
|
|
||||||
#include "ui/pages_logic/VpnLogic.h"
|
|
||||||
#include "ui/pages_logic/WizardLogic.h"
|
|
||||||
|
|
||||||
#include "ui/pages_logic/protocols/CloakLogic.h"
|
|
||||||
#include "ui/pages_logic/protocols/OpenVpnLogic.h"
|
|
||||||
#include "ui/pages_logic/protocols/ShadowSocksLogic.h"
|
|
||||||
|
|
||||||
#include "protocols/qml_register_protocols.h"
|
#include "protocols/qml_register_protocols.h"
|
||||||
|
|
||||||
#if defined(Q_OS_IOS)
|
#if defined(Q_OS_IOS)
|
||||||
#include "platforms/ios/QtAppDelegate-C-Interface.h"
|
#include "platforms/ios/ios_controller.h"
|
||||||
#include "platforms/ios/ios_controller.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]):
|
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv)
|
||||||
AMNEZIA_BASE_CLASS(argc, argv)
|
|
||||||
#else
|
#else
|
||||||
AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecondary,
|
AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecondary, SingleApplication::Options options,
|
||||||
SingleApplication::Options options, int timeout, const QString &userData):
|
int timeout, const QString &userData)
|
||||||
SingleApplication(argc, argv, allowSecondary, options, timeout, userData)
|
: SingleApplication(argc, argv, allowSecondary, options, timeout, userData)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
setQuitOnLastWindowClosed(false);
|
setQuitOnLastWindowClosed(false);
|
||||||
|
|
@ -73,49 +53,97 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_settings = std::shared_ptr<Settings>(new Settings);
|
m_settings = std::shared_ptr<Settings>(new Settings);
|
||||||
m_configurator = std::shared_ptr<VpnConfigurator>(new VpnConfigurator(m_settings, this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AmneziaApplication::~AmneziaApplication()
|
AmneziaApplication::~AmneziaApplication()
|
||||||
{
|
{
|
||||||
|
m_vpnConnectionThread.quit();
|
||||||
|
m_vpnConnectionThread.wait(3000);
|
||||||
|
|
||||||
if (m_engine) {
|
if (m_engine) {
|
||||||
QObject::disconnect(m_engine, 0,0,0);
|
QObject::disconnect(m_engine, 0, 0, 0);
|
||||||
delete m_engine;
|
delete m_engine;
|
||||||
}
|
}
|
||||||
if (m_uiLogic) {
|
|
||||||
QObject::disconnect(m_uiLogic, 0,0,0);
|
|
||||||
delete m_uiLogic;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_protocolProps) delete m_protocolProps;
|
|
||||||
if (m_containerProps) delete m_containerProps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmneziaApplication::init()
|
void AmneziaApplication::init()
|
||||||
{
|
{
|
||||||
m_engine = new QQmlApplicationEngine;
|
m_engine = new QQmlApplicationEngine;
|
||||||
m_uiLogic = new UiLogic(m_settings, m_configurator);
|
|
||||||
|
|
||||||
const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml"));
|
const QUrl url(QStringLiteral("qrc:/ui/qml/main2.qml"));
|
||||||
QObject::connect(m_engine, &QQmlApplicationEngine::objectCreated,
|
QObject::connect(
|
||||||
this, [url](QObject *obj, const QUrl &objUrl) {
|
m_engine, &QQmlApplicationEngine::objectCreated, this,
|
||||||
if (!obj && url == objUrl)
|
[url](QObject *obj, const QUrl &objUrl) {
|
||||||
QCoreApplication::exit(-1);
|
if (!obj && url == objUrl)
|
||||||
}, Qt::QueuedConnection);
|
QCoreApplication::exit(-1);
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
m_engine->rootContext()->setContextProperty("Debug", &Logger::Instance());
|
m_engine->rootContext()->setContextProperty("Debug", &Logger::Instance());
|
||||||
m_uiLogic->registerPagesLogic();
|
|
||||||
|
|
||||||
#if defined(Q_OS_IOS)
|
m_configurator = std::shared_ptr<VpnConfigurator>(new VpnConfigurator(m_settings, this));
|
||||||
setStartPageLogic(m_uiLogic->pageLogic<StartPageLogic>());
|
m_vpnConnection.reset(new VpnConnection(m_settings, m_configurator));
|
||||||
IosController::Instance()->initialize();
|
m_vpnConnection->moveToThread(&m_vpnConnectionThread);
|
||||||
|
m_vpnConnectionThread.start();
|
||||||
|
|
||||||
|
initModels();
|
||||||
|
loadTranslator();
|
||||||
|
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, [this](QString data) {
|
||||||
|
m_pageController->replaceStartPage();
|
||||||
|
m_importController->extractConfigFromData(data);
|
||||||
|
m_pageController->goToPageViewConfig();
|
||||||
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_engine->load(url);
|
#ifdef Q_OS_IOS
|
||||||
|
IosController::Instance()->initialize();
|
||||||
|
connect(IosController::Instance(), &IosController::importConfigFromOutside, [this](QString data) {
|
||||||
|
m_pageController->replaceStartPage();
|
||||||
|
m_importController->extractConfigFromData(data);
|
||||||
|
m_pageController->goToPageViewConfig();
|
||||||
|
});
|
||||||
|
|
||||||
if (m_engine->rootObjects().size() > 0) {
|
connect(IosController::Instance(), &IosController::importBackupFromOutside, [this](QString filePath) {
|
||||||
m_uiLogic->setQmlRoot(m_engine->rootObjects().at(0));
|
m_pageController->replaceStartPage();
|
||||||
}
|
m_pageController->goToPageSettingsBackup();
|
||||||
|
m_settingsController->importBackupFromOutside(filePath);
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_notificationHandler.reset(NotificationHandler::create(nullptr));
|
||||||
|
|
||||||
|
connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, m_notificationHandler.get(),
|
||||||
|
&NotificationHandler::setConnectionState);
|
||||||
|
|
||||||
|
connect(m_notificationHandler.get(), &NotificationHandler::raiseRequested, m_pageController.get(),
|
||||||
|
&PageController::raiseMainWindow);
|
||||||
|
connect(m_notificationHandler.get(), &NotificationHandler::connectRequested, m_connectionController.get(),
|
||||||
|
&ConnectionController::openConnection);
|
||||||
|
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
|
||||||
|
&ConnectionController::closeConnection);
|
||||||
|
connect(this, &AmneziaApplication::translationsUpdated, m_notificationHandler.get(),
|
||||||
|
&NotificationHandler::onTranslationsUpdated);
|
||||||
|
|
||||||
|
m_engine->load(url);
|
||||||
|
m_systemController->setQmlRoot(m_engine->rootObjects().value(0));
|
||||||
|
|
||||||
if (m_settings->isSaveLogs()) {
|
if (m_settings->isSaveLogs()) {
|
||||||
if (!Logger::init()) {
|
if (!Logger::init()) {
|
||||||
|
|
@ -124,19 +152,20 @@ void AmneziaApplication::init()
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
if (m_parser.isSet("a")) m_uiLogic->showOnStartup();
|
if (m_parser.isSet("a"))
|
||||||
else emit m_uiLogic->show();
|
m_pageController->showOnStartup();
|
||||||
|
else
|
||||||
|
emit m_pageController->raiseMainWindow();
|
||||||
#else
|
#else
|
||||||
m_uiLogic->showOnStartup();
|
m_pageController->showOnStartup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO - fix
|
// TODO - fix
|
||||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||||
if (isPrimary()) {
|
if (isPrimary()) {
|
||||||
QObject::connect(this, &SingleApplication::instanceStarted, m_uiLogic, [this](){
|
QObject::connect(this, &SingleApplication::instanceStarted, m_pageController.get(), [this]() {
|
||||||
qDebug() << "Secondary instance started, showing this window instead";
|
qDebug() << "Secondary instance started, showing this window instead";
|
||||||
emit m_uiLogic->show();
|
emit m_pageController->raiseMainWindow();
|
||||||
emit m_uiLogic->raise();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -144,7 +173,7 @@ void AmneziaApplication::init()
|
||||||
// Android TextField clipboard workaround
|
// Android TextField clipboard workaround
|
||||||
// https://bugreports.qt.io/browse/QTBUG-113461
|
// https://bugreports.qt.io/browse/QTBUG-113461
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
QObject::connect(qApp, &QApplication::applicationStateChanged, [](Qt::ApplicationState state) {
|
QObject::connect(qApp, &QGuiApplication::applicationStateChanged, [](Qt::ApplicationState state) {
|
||||||
if (state == Qt::ApplicationActive) {
|
if (state == Qt::ApplicationActive) {
|
||||||
if (qApp->clipboard()->mimeData()->formats().contains("text/html")) {
|
if (qApp->clipboard()->mimeData()->formats().contains("text/html")) {
|
||||||
QTextDocument doc;
|
QTextDocument doc;
|
||||||
|
|
@ -158,55 +187,64 @@ void AmneziaApplication::init()
|
||||||
|
|
||||||
void AmneziaApplication::registerTypes()
|
void AmneziaApplication::registerTypes()
|
||||||
{
|
{
|
||||||
qRegisterMetaType<VpnProtocol::VpnConnectionState>("VpnProtocol::VpnConnectionState");
|
|
||||||
qRegisterMetaType<ServerCredentials>("ServerCredentials");
|
qRegisterMetaType<ServerCredentials>("ServerCredentials");
|
||||||
|
|
||||||
qRegisterMetaType<DockerContainer>("DockerContainer");
|
qRegisterMetaType<DockerContainer>("DockerContainer");
|
||||||
qRegisterMetaType<TransportProto>("TransportProto");
|
qRegisterMetaType<TransportProto>("TransportProto");
|
||||||
qRegisterMetaType<Proto>("Proto");
|
qRegisterMetaType<Proto>("Proto");
|
||||||
qRegisterMetaType<ServiceType>("ServiceType");
|
qRegisterMetaType<ServiceType>("ServiceType");
|
||||||
qRegisterMetaType<Page>("Page");
|
|
||||||
qRegisterMetaType<VpnProtocol::VpnConnectionState>("ConnectionState");
|
|
||||||
|
|
||||||
qRegisterMetaType<PageProtocolLogicBase *>("PageProtocolLogicBase *");
|
|
||||||
|
|
||||||
|
|
||||||
declareQmlPageEnum();
|
|
||||||
declareQmlProtocolEnum();
|
declareQmlProtocolEnum();
|
||||||
declareQmlContainerEnum();
|
declareQmlContainerEnum();
|
||||||
|
|
||||||
qmlRegisterType<PageType>("PageType", 1, 0, "PageType");
|
|
||||||
qmlRegisterType<QRCodeReader>("QRCodeReader", 1, 0, "QRCodeReader");
|
qmlRegisterType<QRCodeReader>("QRCodeReader", 1, 0, "QRCodeReader");
|
||||||
|
|
||||||
m_containerProps = new ContainerProps;
|
m_containerProps.reset(new ContainerProps());
|
||||||
qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", m_containerProps);
|
qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", m_containerProps.get());
|
||||||
|
|
||||||
m_protocolProps = new ProtocolProps;
|
m_protocolProps.reset(new ProtocolProps());
|
||||||
qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", m_protocolProps);
|
qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", m_protocolProps.get());
|
||||||
|
|
||||||
|
qmlRegisterSingletonType(QUrl("qrc:/ui/qml/Filters/ContainersModelFilters.qml"), "ContainersModelFilters", 1, 0,
|
||||||
|
"ContainersModelFilters");
|
||||||
|
|
||||||
|
//
|
||||||
|
Vpn::declareQmlVpnConnectionStateEnum();
|
||||||
|
PageLoader::declareQmlPageEnum();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmneziaApplication::loadFonts()
|
void AmneziaApplication::loadFonts()
|
||||||
{
|
{
|
||||||
QQuickStyle::setStyle("Basic");
|
QQuickStyle::setStyle("Basic");
|
||||||
|
|
||||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Black.ttf");
|
QFontDatabase::addApplicationFont(":/fonts/pt-root-ui_vf.ttf");
|
||||||
QFontDatabase::addApplicationFont(":/fonts/Lato-BlackItalic.ttf");
|
|
||||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Bold.ttf");
|
|
||||||
QFontDatabase::addApplicationFont(":/fonts/Lato-BoldItalic.ttf");
|
|
||||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Italic.ttf");
|
|
||||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Light.ttf");
|
|
||||||
QFontDatabase::addApplicationFont(":/fonts/Lato-LightItalic.ttf");
|
|
||||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Regular.ttf");
|
|
||||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Thin.ttf");
|
|
||||||
QFontDatabase::addApplicationFont(":/fonts/Lato-ThinItalic.ttf");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmneziaApplication::loadTranslator()
|
void AmneziaApplication::loadTranslator()
|
||||||
{
|
{
|
||||||
m_translator = new QTranslator;
|
auto locale = m_settings->getAppLanguage();
|
||||||
if (m_translator->load(QLocale(), QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/translations"))) {
|
m_translator.reset(new QTranslator());
|
||||||
installTranslator(m_translator);
|
updateTranslator(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AmneziaApplication::updateTranslator(const QLocale &locale)
|
||||||
|
{
|
||||||
|
if (!m_translator->isEmpty()) {
|
||||||
|
QCoreApplication::removeTranslator(m_translator.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString strFileName = QString(":/translations/amneziavpn") + QLatin1String("_") + locale.name() + ".qm";
|
||||||
|
if (m_translator->load(strFileName)) {
|
||||||
|
if (QCoreApplication::installTranslator(m_translator.get())) {
|
||||||
|
m_settings->setAppLanguage(locale);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_settings->setAppLanguage(QLocale::English);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_engine->retranslate();
|
||||||
|
|
||||||
|
emit translationsUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AmneziaApplication::parseCommands()
|
bool AmneziaApplication::parseCommands()
|
||||||
|
|
@ -215,19 +253,17 @@ bool AmneziaApplication::parseCommands()
|
||||||
m_parser.addHelpOption();
|
m_parser.addHelpOption();
|
||||||
m_parser.addVersionOption();
|
m_parser.addVersionOption();
|
||||||
|
|
||||||
QCommandLineOption c_autostart {{"a", "autostart"}, "System autostart"};
|
QCommandLineOption c_autostart { { "a", "autostart" }, "System autostart" };
|
||||||
m_parser.addOption(c_autostart);
|
m_parser.addOption(c_autostart);
|
||||||
|
|
||||||
QCommandLineOption c_cleanup {{"c", "cleanup"}, "Cleanup logs"};
|
QCommandLineOption c_cleanup { { "c", "cleanup" }, "Cleanup logs" };
|
||||||
m_parser.addOption(c_cleanup);
|
m_parser.addOption(c_cleanup);
|
||||||
|
|
||||||
m_parser.process(*this);
|
m_parser.process(*this);
|
||||||
|
|
||||||
if (m_parser.isSet(c_cleanup)) {
|
if (m_parser.isSet(c_cleanup)) {
|
||||||
Logger::cleanUp();
|
Logger::cleanUp();
|
||||||
QTimer::singleShot(100, this, [this]{
|
QTimer::singleShot(100, this, [this] { quit(); });
|
||||||
quit();
|
|
||||||
});
|
|
||||||
exec();
|
exec();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -239,3 +275,100 @@ QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
|
||||||
return m_engine;
|
return m_engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AmneziaApplication::initModels()
|
||||||
|
{
|
||||||
|
m_containersModel.reset(new ContainersModel(m_settings, this));
|
||||||
|
m_engine->rootContext()->setContextProperty("ContainersModel", m_containersModel.get());
|
||||||
|
connect(m_vpnConnection.get(), &VpnConnection::newVpnConfigurationCreated, m_containersModel.get(),
|
||||||
|
&ContainersModel::updateContainersConfig);
|
||||||
|
|
||||||
|
m_serversModel.reset(new ServersModel(m_settings, this));
|
||||||
|
m_engine->rootContext()->setContextProperty("ServersModel", m_serversModel.get());
|
||||||
|
connect(m_serversModel.get(), &ServersModel::currentlyProcessedServerIndexChanged, m_containersModel.get(),
|
||||||
|
&ContainersModel::setCurrentlyProcessedServerIndex);
|
||||||
|
connect(m_serversModel.get(), &ServersModel::defaultServerIndexChanged, m_containersModel.get(),
|
||||||
|
&ContainersModel::setCurrentlyProcessedServerIndex);
|
||||||
|
|
||||||
|
m_languageModel.reset(new LanguageModel(m_settings, this));
|
||||||
|
m_engine->rootContext()->setContextProperty("LanguageModel", m_languageModel.get());
|
||||||
|
connect(m_languageModel.get(), &LanguageModel::updateTranslations, this, &AmneziaApplication::updateTranslator);
|
||||||
|
connect(this, &AmneziaApplication::translationsUpdated, m_languageModel.get(), &LanguageModel::translationsUpdated);
|
||||||
|
|
||||||
|
m_sitesModel.reset(new SitesModel(m_settings, this));
|
||||||
|
m_engine->rootContext()->setContextProperty("SitesModel", m_sitesModel.get());
|
||||||
|
connect(m_containersModel.get(), &ContainersModel::defaultContainerChanged, this, [this]() {
|
||||||
|
if ((m_containersModel->getDefaultContainer() == DockerContainer::WireGuard
|
||||||
|
|| m_containersModel->getDefaultContainer() == DockerContainer::Awg)
|
||||||
|
&& m_sitesModel->isSplitTunnelingEnabled()) {
|
||||||
|
m_sitesModel->toggleSplitTunneling(false);
|
||||||
|
emit m_pageController->showNotificationMessage(
|
||||||
|
tr("Split tunneling for %1 is not implemented, the option was disabled")
|
||||||
|
.arg(ContainerProps::containerHumanNames().value(m_containersModel->getDefaultContainer())));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
m_protocolsModel.reset(new ProtocolsModel(m_settings, this));
|
||||||
|
m_engine->rootContext()->setContextProperty("ProtocolsModel", m_protocolsModel.get());
|
||||||
|
|
||||||
|
m_openVpnConfigModel.reset(new OpenVpnConfigModel(this));
|
||||||
|
m_engine->rootContext()->setContextProperty("OpenVpnConfigModel", m_openVpnConfigModel.get());
|
||||||
|
|
||||||
|
m_shadowSocksConfigModel.reset(new ShadowSocksConfigModel(this));
|
||||||
|
m_engine->rootContext()->setContextProperty("ShadowSocksConfigModel", m_shadowSocksConfigModel.get());
|
||||||
|
|
||||||
|
m_cloakConfigModel.reset(new CloakConfigModel(this));
|
||||||
|
m_engine->rootContext()->setContextProperty("CloakConfigModel", m_cloakConfigModel.get());
|
||||||
|
|
||||||
|
m_wireGuardConfigModel.reset(new WireGuardConfigModel(this));
|
||||||
|
m_engine->rootContext()->setContextProperty("WireGuardConfigModel", m_wireGuardConfigModel.get());
|
||||||
|
|
||||||
|
m_awgConfigModel.reset(new AwgConfigModel(this));
|
||||||
|
m_engine->rootContext()->setContextProperty("AwgConfigModel", m_awgConfigModel.get());
|
||||||
|
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
m_ikev2ConfigModel.reset(new Ikev2ConfigModel(this));
|
||||||
|
m_engine->rootContext()->setContextProperty("Ikev2ConfigModel", m_ikev2ConfigModel.get());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_sftpConfigModel.reset(new SftpConfigModel(this));
|
||||||
|
m_engine->rootContext()->setContextProperty("SftpConfigModel", m_sftpConfigModel.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AmneziaApplication::initControllers()
|
||||||
|
{
|
||||||
|
m_connectionController.reset(new ConnectionController(m_serversModel, m_containersModel, m_vpnConnection));
|
||||||
|
m_engine->rootContext()->setContextProperty("ConnectionController", m_connectionController.get());
|
||||||
|
|
||||||
|
connect(this, &AmneziaApplication::translationsUpdated, m_connectionController.get(),
|
||||||
|
&ConnectionController::onTranslationsUpdated);
|
||||||
|
|
||||||
|
m_pageController.reset(new PageController(m_serversModel, m_settings));
|
||||||
|
m_engine->rootContext()->setContextProperty("PageController", m_pageController.get());
|
||||||
|
|
||||||
|
m_installController.reset(new InstallController(m_serversModel, m_containersModel, m_protocolsModel, m_settings));
|
||||||
|
m_engine->rootContext()->setContextProperty("InstallController", m_installController.get());
|
||||||
|
connect(m_installController.get(), &InstallController::passphraseRequestStarted, m_pageController.get(),
|
||||||
|
&PageController::showPassphraseRequestDrawer);
|
||||||
|
connect(m_pageController.get(), &PageController::passphraseRequestDrawerClosed, m_installController.get(),
|
||||||
|
&InstallController::setEncryptedPassphrase);
|
||||||
|
connect(m_installController.get(), &InstallController::currentContainerUpdated, m_connectionController.get(),
|
||||||
|
&ConnectionController::onCurrentContainerUpdated);
|
||||||
|
|
||||||
|
m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
|
||||||
|
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
|
||||||
|
|
||||||
|
m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_settings, m_configurator));
|
||||||
|
m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get());
|
||||||
|
|
||||||
|
m_settingsController.reset(new SettingsController(m_serversModel, m_containersModel, m_languageModel, m_settings));
|
||||||
|
m_engine->rootContext()->setContextProperty("SettingsController", m_settingsController.get());
|
||||||
|
if (m_settingsController->isAutoStartEnabled() && m_serversModel->getDefaultServerIndex() >= 0) {
|
||||||
|
QTimer::singleShot(1000, this, [this]() { m_connectionController->openConnection(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sitesController.reset(new SitesController(m_settings, m_vpnConnection, m_sitesModel));
|
||||||
|
m_engine->rootContext()->setContextProperty("SitesController", m_sitesController.get());
|
||||||
|
|
||||||
|
m_systemController.reset(new SystemController(m_settings));
|
||||||
|
m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get());
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,53 @@
|
||||||
#ifndef AMNEZIA_APPLICATION_H
|
#ifndef AMNEZIA_APPLICATION_H
|
||||||
#define AMNEZIA_APPLICATION_H
|
#define AMNEZIA_APPLICATION_H
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QGuiApplication>
|
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
|
#include <QThread>
|
||||||
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#else
|
||||||
|
#include <QApplication>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "vpnconnection.h"
|
||||||
|
|
||||||
#include "ui/uilogic.h"
|
|
||||||
#include "configurators/vpn_configurator.h"
|
#include "configurators/vpn_configurator.h"
|
||||||
|
|
||||||
|
#include "ui/controllers/connectionController.h"
|
||||||
|
#include "ui/controllers/exportController.h"
|
||||||
|
#include "ui/controllers/importController.h"
|
||||||
|
#include "ui/controllers/installController.h"
|
||||||
|
#include "ui/controllers/pageController.h"
|
||||||
|
#include "ui/controllers/settingsController.h"
|
||||||
|
#include "ui/controllers/sitesController.h"
|
||||||
|
#include "ui/controllers/systemController.h"
|
||||||
|
#include "ui/models/containers_model.h"
|
||||||
|
#include "ui/models/languageModel.h"
|
||||||
|
#include "ui/models/protocols/cloakConfigModel.h"
|
||||||
|
#include "ui/notificationhandler.h"
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
#include "ui/models/protocols/ikev2ConfigModel.h"
|
||||||
|
#endif
|
||||||
|
#include "ui/models/protocols/awgConfigModel.h"
|
||||||
|
#include "ui/models/protocols/openvpnConfigModel.h"
|
||||||
|
#include "ui/models/protocols/shadowsocksConfigModel.h"
|
||||||
|
#include "ui/models/protocols/wireguardConfigModel.h"
|
||||||
|
#include "ui/models/protocols_model.h"
|
||||||
|
#include "ui/models/servers_model.h"
|
||||||
|
#include "ui/models/services/sftpConfigModel.h"
|
||||||
|
#include "ui/models/sites_model.h"
|
||||||
|
|
||||||
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
|
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
|
||||||
|
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
#define AMNEZIA_BASE_CLASS QApplication
|
#define AMNEZIA_BASE_CLASS QGuiApplication
|
||||||
#else
|
#else
|
||||||
#define AMNEZIA_BASE_CLASS SingleApplication
|
#define AMNEZIA_BASE_CLASS SingleApplication
|
||||||
#define QAPPLICATION_CLASS QApplication
|
#define QAPPLICATION_CLASS QApplication
|
||||||
#include "singleapplication.h"
|
#include "singleapplication.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class AmneziaApplication : public AMNEZIA_BASE_CLASS
|
class AmneziaApplication : public AMNEZIA_BASE_CLASS
|
||||||
|
|
@ -32,7 +58,8 @@ public:
|
||||||
AmneziaApplication(int &argc, char *argv[]);
|
AmneziaApplication(int &argc, char *argv[]);
|
||||||
#else
|
#else
|
||||||
AmneziaApplication(int &argc, char *argv[], bool allowSecondary = false,
|
AmneziaApplication(int &argc, char *argv[], bool allowSecondary = false,
|
||||||
SingleApplication::Options options = SingleApplication::User, int timeout = 1000, const QString &userData = {} );
|
SingleApplication::Options options = SingleApplication::User, int timeout = 1000,
|
||||||
|
const QString &userData = {});
|
||||||
#endif
|
#endif
|
||||||
virtual ~AmneziaApplication();
|
virtual ~AmneziaApplication();
|
||||||
|
|
||||||
|
|
@ -40,22 +67,57 @@ public:
|
||||||
void registerTypes();
|
void registerTypes();
|
||||||
void loadFonts();
|
void loadFonts();
|
||||||
void loadTranslator();
|
void loadTranslator();
|
||||||
|
void updateTranslator(const QLocale &locale);
|
||||||
bool parseCommands();
|
bool parseCommands();
|
||||||
|
|
||||||
QQmlApplicationEngine *qmlEngine() const;
|
QQmlApplicationEngine *qmlEngine() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void translationsUpdated();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void initModels();
|
||||||
|
void initControllers();
|
||||||
|
|
||||||
QQmlApplicationEngine *m_engine {};
|
QQmlApplicationEngine *m_engine {};
|
||||||
UiLogic *m_uiLogic {};
|
|
||||||
std::shared_ptr<Settings> m_settings;
|
std::shared_ptr<Settings> m_settings;
|
||||||
std::shared_ptr<VpnConfigurator> m_configurator;
|
std::shared_ptr<VpnConfigurator> m_configurator;
|
||||||
|
|
||||||
ContainerProps* m_containerProps {};
|
QSharedPointer<ContainerProps> m_containerProps;
|
||||||
ProtocolProps* m_protocolProps {};
|
QSharedPointer<ProtocolProps> m_protocolProps;
|
||||||
|
|
||||||
QTranslator* m_translator;
|
QSharedPointer<QTranslator> m_translator;
|
||||||
QCommandLineParser m_parser;
|
QCommandLineParser m_parser;
|
||||||
|
|
||||||
|
QSharedPointer<ContainersModel> m_containersModel;
|
||||||
|
QSharedPointer<ServersModel> m_serversModel;
|
||||||
|
QSharedPointer<LanguageModel> m_languageModel;
|
||||||
|
QSharedPointer<ProtocolsModel> m_protocolsModel;
|
||||||
|
QSharedPointer<SitesModel> m_sitesModel;
|
||||||
|
|
||||||
|
QScopedPointer<OpenVpnConfigModel> m_openVpnConfigModel;
|
||||||
|
QScopedPointer<ShadowSocksConfigModel> m_shadowSocksConfigModel;
|
||||||
|
QScopedPointer<CloakConfigModel> m_cloakConfigModel;
|
||||||
|
QScopedPointer<WireGuardConfigModel> m_wireGuardConfigModel;
|
||||||
|
QScopedPointer<AwgConfigModel> m_awgConfigModel;
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
QScopedPointer<Ikev2ConfigModel> m_ikev2ConfigModel;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QScopedPointer<SftpConfigModel> m_sftpConfigModel;
|
||||||
|
|
||||||
|
QSharedPointer<VpnConnection> m_vpnConnection;
|
||||||
|
QThread m_vpnConnectionThread;
|
||||||
|
QScopedPointer<NotificationHandler> m_notificationHandler;
|
||||||
|
|
||||||
|
QScopedPointer<ConnectionController> m_connectionController;
|
||||||
|
QScopedPointer<PageController> m_pageController;
|
||||||
|
QScopedPointer<InstallController> m_installController;
|
||||||
|
QScopedPointer<ImportController> m_importController;
|
||||||
|
QScopedPointer<ExportController> m_exportController;
|
||||||
|
QScopedPointer<SettingsController> m_settingsController;
|
||||||
|
QScopedPointer<SitesController> m_sitesController;
|
||||||
|
QScopedPointer<SystemController> m_systemController;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AMNEZIA_APPLICATION_H
|
#endif // AMNEZIA_APPLICATION_H
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:allowNativeHeapPointerTagging="false"
|
android:allowNativeHeapPointerTagging="false"
|
||||||
android:theme="@style/Theme.AppCompat.NoActionBar"
|
android:theme="@style/Theme.AppCompat.NoActionBar"
|
||||||
android:icon="@drawable/icon">
|
android:icon="@drawable/icon"
|
||||||
|
android:roundIcon="@drawable/icon_round">
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
|
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
|
||||||
|
|
@ -44,6 +45,7 @@
|
||||||
android:label="-- %%INSERT_APP_NAME%% --"
|
android:label="-- %%INSERT_APP_NAME%% --"
|
||||||
android:screenOrientation="unspecified"
|
android:screenOrientation="unspecified"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|
||||||
<!-- android:theme="@style/splashScreenTheme"-->
|
<!-- android:theme="@style/splashScreenTheme"-->
|
||||||
|
|
|
||||||
|
|
@ -138,8 +138,8 @@ android {
|
||||||
resConfig "en"
|
resConfig "en"
|
||||||
minSdkVersion = 24
|
minSdkVersion = 24
|
||||||
targetSdkVersion = 34
|
targetSdkVersion = 34
|
||||||
versionCode 32 // Change to a higher number
|
versionCode 37 // Change to a higher number
|
||||||
versionName "3.0.9" // Change to a higher number
|
versionName "4.0.8" // Change to a higher number
|
||||||
|
|
||||||
javaCompileOptions.annotationProcessorOptions.arguments = [
|
javaCompileOptions.annotationProcessorOptions.arguments = [
|
||||||
"room.schemaLocation": "${qtAndroidDir}/schemas".toString()
|
"room.schemaLocation": "${qtAndroidDir}/schemas".toString()
|
||||||
|
|
|
||||||
BIN
client/android/res/drawable-hdpi/icon_round.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
client/android/res/drawable-ldpi/icon_round.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
client/android/res/drawable-mdpi/icon_round.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
client/android/res/drawable-xhdpi/icon_round.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
client/android/res/drawable-xxhdpi/icon_round.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
client/android/res/drawable-xxxhdpi/icon_round.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
|
|
@ -70,6 +70,15 @@ public class BadConfigException extends Exception {
|
||||||
EXCLUDED_APPLICATIONS("ExcludedApplications"),
|
EXCLUDED_APPLICATIONS("ExcludedApplications"),
|
||||||
INCLUDED_APPLICATIONS("IncludedApplications"),
|
INCLUDED_APPLICATIONS("IncludedApplications"),
|
||||||
LISTEN_PORT("ListenPort"),
|
LISTEN_PORT("ListenPort"),
|
||||||
|
JC("Jc"),
|
||||||
|
JMIN("Jmin"),
|
||||||
|
JMAX("Jmax"),
|
||||||
|
S1("S1"),
|
||||||
|
S2("S2"),
|
||||||
|
H1("H1"),
|
||||||
|
H2("H2"),
|
||||||
|
H3("H3"),
|
||||||
|
H4("H4"),
|
||||||
MTU("MTU"),
|
MTU("MTU"),
|
||||||
PERSISTENT_KEEPALIVE("PersistentKeepalive"),
|
PERSISTENT_KEEPALIVE("PersistentKeepalive"),
|
||||||
PRE_SHARED_KEY("PresharedKey"),
|
PRE_SHARED_KEY("PresharedKey"),
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,15 @@ public final class Interface {
|
||||||
private final KeyPair keyPair;
|
private final KeyPair keyPair;
|
||||||
private final Optional<Integer> listenPort;
|
private final Optional<Integer> listenPort;
|
||||||
private final Optional<Integer> mtu;
|
private final Optional<Integer> mtu;
|
||||||
|
private final Optional<Integer> jc;
|
||||||
|
private final Optional<Integer> jmin;
|
||||||
|
private final Optional<Integer> jmax;
|
||||||
|
private final Optional<Integer> s1;
|
||||||
|
private final Optional<Integer> s2;
|
||||||
|
private final Optional<Long> h1;
|
||||||
|
private final Optional<Long> h2;
|
||||||
|
private final Optional<Long> h3;
|
||||||
|
private final Optional<Long> h4;
|
||||||
|
|
||||||
private Interface(final Builder builder) {
|
private Interface(final Builder builder) {
|
||||||
// Defensively copy to ensure immutability even if the Builder is reused.
|
// Defensively copy to ensure immutability even if the Builder is reused.
|
||||||
|
|
@ -56,6 +65,15 @@ public final class Interface {
|
||||||
keyPair = Objects.requireNonNull(builder.keyPair, "Interfaces must have a private key");
|
keyPair = Objects.requireNonNull(builder.keyPair, "Interfaces must have a private key");
|
||||||
listenPort = builder.listenPort;
|
listenPort = builder.listenPort;
|
||||||
mtu = builder.mtu;
|
mtu = builder.mtu;
|
||||||
|
jc = builder.jc;
|
||||||
|
jmax = builder.jmax;
|
||||||
|
jmin = builder.jmin;
|
||||||
|
s1 = builder.s1;
|
||||||
|
s2 = builder.s2;
|
||||||
|
h1 = builder.h1;
|
||||||
|
h2 = builder.h2;
|
||||||
|
h3 = builder.h3;
|
||||||
|
h4 = builder.h4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -95,6 +113,33 @@ public final class Interface {
|
||||||
case "privatekey":
|
case "privatekey":
|
||||||
builder.parsePrivateKey(attribute.getValue());
|
builder.parsePrivateKey(attribute.getValue());
|
||||||
break;
|
break;
|
||||||
|
case "jc":
|
||||||
|
builder.parseJc(attribute.getValue());
|
||||||
|
break;
|
||||||
|
case "jmin":
|
||||||
|
builder.parseJmin(attribute.getValue());
|
||||||
|
break;
|
||||||
|
case "jmax":
|
||||||
|
builder.parseJmax(attribute.getValue());
|
||||||
|
break;
|
||||||
|
case "s1":
|
||||||
|
builder.parseS1(attribute.getValue());
|
||||||
|
break;
|
||||||
|
case "s2":
|
||||||
|
builder.parseS2(attribute.getValue());
|
||||||
|
break;
|
||||||
|
case "h1":
|
||||||
|
builder.parseH1(attribute.getValue());
|
||||||
|
break;
|
||||||
|
case "h2":
|
||||||
|
builder.parseH2(attribute.getValue());
|
||||||
|
break;
|
||||||
|
case "h3":
|
||||||
|
builder.parseH3(attribute.getValue());
|
||||||
|
break;
|
||||||
|
case "h4":
|
||||||
|
builder.parseH4(attribute.getValue());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new BadConfigException(
|
throw new BadConfigException(
|
||||||
Section.INTERFACE, Location.TOP_LEVEL, Reason.UNKNOWN_ATTRIBUTE, attribute.getKey());
|
Section.INTERFACE, Location.TOP_LEVEL, Reason.UNKNOWN_ATTRIBUTE, attribute.getKey());
|
||||||
|
|
@ -111,7 +156,9 @@ public final class Interface {
|
||||||
return addresses.equals(other.addresses) && dnsServers.equals(other.dnsServers)
|
return addresses.equals(other.addresses) && dnsServers.equals(other.dnsServers)
|
||||||
&& excludedApplications.equals(other.excludedApplications)
|
&& excludedApplications.equals(other.excludedApplications)
|
||||||
&& includedApplications.equals(other.includedApplications) && keyPair.equals(other.keyPair)
|
&& includedApplications.equals(other.includedApplications) && keyPair.equals(other.keyPair)
|
||||||
&& listenPort.equals(other.listenPort) && mtu.equals(other.mtu);
|
&& listenPort.equals(other.listenPort) && mtu.equals(other.mtu) && jc.equals(other.jc) && jmin.equals(other.jmin)
|
||||||
|
&& jmax.equals(other.jmax) && s1.equals(other.s1) && s2.equals(other.s2) && h1.equals(other.h1) && h2.equals(other.h2)
|
||||||
|
&& h3.equals(other.h3) && h4.equals(other.h4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -180,6 +227,42 @@ public final class Interface {
|
||||||
public Optional<Integer> getMtu() {
|
public Optional<Integer> getMtu() {
|
||||||
return mtu;
|
return mtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Integer> getJc() {
|
||||||
|
return jc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Integer> getJmin() {
|
||||||
|
return jmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Integer> getJmax() {
|
||||||
|
return jmax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Integer> getS1() {
|
||||||
|
return s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Integer> getS2() {
|
||||||
|
return s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Long> getH1() {
|
||||||
|
return h1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Long> getH2() {
|
||||||
|
return h2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Long> getH3() {
|
||||||
|
return h3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Long> getH4() {
|
||||||
|
return h4;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
|
@ -191,6 +274,15 @@ public final class Interface {
|
||||||
hash = 31 * hash + keyPair.hashCode();
|
hash = 31 * hash + keyPair.hashCode();
|
||||||
hash = 31 * hash + listenPort.hashCode();
|
hash = 31 * hash + listenPort.hashCode();
|
||||||
hash = 31 * hash + mtu.hashCode();
|
hash = 31 * hash + mtu.hashCode();
|
||||||
|
hash = 31 * hash + jc.hashCode();
|
||||||
|
hash = 31 * hash + jmin.hashCode();
|
||||||
|
hash = 31 * hash + jmax.hashCode();
|
||||||
|
hash = 31 * hash + s1.hashCode();
|
||||||
|
hash = 31 * hash + s2.hashCode();
|
||||||
|
hash = 31 * hash + h1.hashCode();
|
||||||
|
hash = 31 * hash + h2.hashCode();
|
||||||
|
hash = 31 * hash + h3.hashCode();
|
||||||
|
hash = 31 * hash + h4.hashCode();
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,6 +326,19 @@ public final class Interface {
|
||||||
.append('\n');
|
.append('\n');
|
||||||
listenPort.ifPresent(lp -> sb.append("ListenPort = ").append(lp).append('\n'));
|
listenPort.ifPresent(lp -> sb.append("ListenPort = ").append(lp).append('\n'));
|
||||||
mtu.ifPresent(m -> sb.append("MTU = ").append(m).append('\n'));
|
mtu.ifPresent(m -> sb.append("MTU = ").append(m).append('\n'));
|
||||||
|
|
||||||
|
jc.ifPresent(t_jc -> sb.append("Jc = ").append(t_jc).append('\n'));
|
||||||
|
jmin.ifPresent(t_jmin -> sb.append("Jmin = ").append(t_jmin).append('\n'));
|
||||||
|
jmax.ifPresent(t_jmax -> sb.append("Jmax = ").append(t_jmax).append('\n'));
|
||||||
|
|
||||||
|
s1.ifPresent(t_s1 -> sb.append("S1 = ").append(t_s1).append('\n'));
|
||||||
|
s2.ifPresent(t_s2 -> sb.append("S2 = ").append(t_s2).append('\n'));
|
||||||
|
|
||||||
|
h1.ifPresent(t_h1 -> sb.append("H1 = ").append(t_h1).append('\n'));
|
||||||
|
h2.ifPresent(t_h2 -> sb.append("H2 = ").append(t_h2).append('\n'));
|
||||||
|
h3.ifPresent(t_h3 -> sb.append("H3 = ").append(t_h3).append('\n'));
|
||||||
|
h4.ifPresent(t_h4 -> sb.append("H4 = ").append(t_h4).append('\n'));
|
||||||
|
|
||||||
sb.append("PrivateKey = ").append(keyPair.getPrivateKey().toBase64()).append('\n');
|
sb.append("PrivateKey = ").append(keyPair.getPrivateKey().toBase64()).append('\n');
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
@ -248,6 +353,18 @@ public final class Interface {
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
sb.append("private_key=").append(keyPair.getPrivateKey().toHex()).append('\n');
|
sb.append("private_key=").append(keyPair.getPrivateKey().toHex()).append('\n');
|
||||||
listenPort.ifPresent(lp -> sb.append("listen_port=").append(lp).append('\n'));
|
listenPort.ifPresent(lp -> sb.append("listen_port=").append(lp).append('\n'));
|
||||||
|
|
||||||
|
jc.ifPresent(t_jc -> sb.append("jc=").append(t_jc).append('\n'));
|
||||||
|
jmin.ifPresent(t_jmin -> sb.append("jmin=").append(t_jmin).append('\n'));
|
||||||
|
jmax.ifPresent(t_jmax -> sb.append("jmax=").append(t_jmax).append('\n'));
|
||||||
|
|
||||||
|
s1.ifPresent(t_s1 -> sb.append("s1=").append(t_s1).append('\n'));
|
||||||
|
s2.ifPresent(t_s2 -> sb.append("s2=").append(t_s2).append('\n'));
|
||||||
|
|
||||||
|
h1.ifPresent(t_h1 -> sb.append("h1=").append(t_h1).append('\n'));
|
||||||
|
h2.ifPresent(t_h2 -> sb.append("h2=").append(t_h2).append('\n'));
|
||||||
|
h3.ifPresent(t_h3 -> sb.append("h3=").append(t_h3).append('\n'));
|
||||||
|
h4.ifPresent(t_h4 -> sb.append("h4=").append(t_h4).append('\n'));
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,6 +384,17 @@ public final class Interface {
|
||||||
private Optional<Integer> listenPort = Optional.empty();
|
private Optional<Integer> listenPort = Optional.empty();
|
||||||
// Defaults to not present.
|
// Defaults to not present.
|
||||||
private Optional<Integer> mtu = Optional.empty();
|
private Optional<Integer> mtu = Optional.empty();
|
||||||
|
private Optional<Integer> jc = Optional.empty();
|
||||||
|
private Optional<Integer> jmin = Optional.empty();
|
||||||
|
private Optional<Integer> jmax = Optional.empty();
|
||||||
|
|
||||||
|
private Optional<Integer> s1 = Optional.empty();
|
||||||
|
private Optional<Integer> s2 = Optional.empty();
|
||||||
|
|
||||||
|
private Optional<Long> h1 = Optional.empty();
|
||||||
|
private Optional<Long> h2 = Optional.empty();
|
||||||
|
private Optional<Long> h3 = Optional.empty();
|
||||||
|
private Optional<Long> h4 = Optional.empty();
|
||||||
|
|
||||||
public Builder addAddress(final InetNetwork address) {
|
public Builder addAddress(final InetNetwork address) {
|
||||||
addresses.add(address);
|
addresses.add(address);
|
||||||
|
|
@ -362,6 +490,78 @@ public final class Interface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder parseJc(final String jc) throws BadConfigException {
|
||||||
|
try {
|
||||||
|
return setJc(Integer.parseInt(jc));
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
throw new BadConfigException(Section.INTERFACE, Location.JC, jc, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder parseJmax(final String jmax) throws BadConfigException {
|
||||||
|
try {
|
||||||
|
return setJmax(Integer.parseInt(jmax));
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
throw new BadConfigException(Section.INTERFACE, Location.JMAX, jmax, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder parseJmin(final String jmin) throws BadConfigException {
|
||||||
|
try {
|
||||||
|
return setJmin(Integer.parseInt(jmin));
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
throw new BadConfigException(Section.INTERFACE, Location.JMIN, jmin, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder parseS1(final String s1) throws BadConfigException {
|
||||||
|
try {
|
||||||
|
return setS1(Integer.parseInt(s1));
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
throw new BadConfigException(Section.INTERFACE, Location.S1, s1, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder parseS2(final String s2) throws BadConfigException {
|
||||||
|
try {
|
||||||
|
return setS2(Integer.parseInt(s2));
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
throw new BadConfigException(Section.INTERFACE, Location.S2, s2, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder parseH1(final String h1) throws BadConfigException {
|
||||||
|
try {
|
||||||
|
return setH1(Long.parseLong(h1));
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
throw new BadConfigException(Section.INTERFACE, Location.H1, h1, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder parseH2(final String h2) throws BadConfigException {
|
||||||
|
try {
|
||||||
|
return setH2(Long.parseLong(h2));
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
throw new BadConfigException(Section.INTERFACE, Location.H2, h2, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder parseH3(final String h3) throws BadConfigException {
|
||||||
|
try {
|
||||||
|
return setH3(Long.parseLong(h3));
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
throw new BadConfigException(Section.INTERFACE, Location.H3, h3, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder parseH4(final String h4) throws BadConfigException {
|
||||||
|
try {
|
||||||
|
return setH4(Long.parseLong(h4));
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
throw new BadConfigException(Section.INTERFACE, Location.H4, h4, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Builder parsePrivateKey(final String privateKey) throws BadConfigException {
|
public Builder parsePrivateKey(final String privateKey) throws BadConfigException {
|
||||||
try {
|
try {
|
||||||
return setKeyPair(new KeyPair(Key.fromBase64(privateKey)));
|
return setKeyPair(new KeyPair(Key.fromBase64(privateKey)));
|
||||||
|
|
@ -386,9 +586,81 @@ public final class Interface {
|
||||||
public Builder setMtu(final int mtu) throws BadConfigException {
|
public Builder setMtu(final int mtu) throws BadConfigException {
|
||||||
if (mtu < 0)
|
if (mtu < 0)
|
||||||
throw new BadConfigException(
|
throw new BadConfigException(
|
||||||
Section.INTERFACE, Location.LISTEN_PORT, Reason.INVALID_VALUE, String.valueOf(mtu));
|
Section.INTERFACE, Location.MTU, Reason.INVALID_VALUE, String.valueOf(mtu));
|
||||||
this.mtu = mtu == 0 ? Optional.empty() : Optional.of(mtu);
|
this.mtu = mtu == 0 ? Optional.empty() : Optional.of(mtu);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder setJc(final int jc) throws BadConfigException {
|
||||||
|
if (jc < 0)
|
||||||
|
throw new BadConfigException(
|
||||||
|
Section.INTERFACE, Location.JC, Reason.INVALID_VALUE, String.valueOf(jc));
|
||||||
|
this.jc = Optional.of(jc);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setJmin(final int jmin) throws BadConfigException {
|
||||||
|
if (jmin < 0)
|
||||||
|
throw new BadConfigException(
|
||||||
|
Section.INTERFACE, Location.JMIN, Reason.INVALID_VALUE, String.valueOf(jmin));
|
||||||
|
this.jmin = Optional.of(jmin);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setJmax(final int jmax) throws BadConfigException {
|
||||||
|
if (jmax < 0)
|
||||||
|
throw new BadConfigException(
|
||||||
|
Section.INTERFACE, Location.JMAX, Reason.INVALID_VALUE, String.valueOf(jmax));
|
||||||
|
this.jmax = Optional.of(jmax);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setS1(final int s1) throws BadConfigException {
|
||||||
|
if (s1 < 0)
|
||||||
|
throw new BadConfigException(
|
||||||
|
Section.INTERFACE, Location.S1, Reason.INVALID_VALUE, String.valueOf(s1));
|
||||||
|
this.s1 = Optional.of(s1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setS2(final int s2) throws BadConfigException {
|
||||||
|
if (s2 < 0)
|
||||||
|
throw new BadConfigException(
|
||||||
|
Section.INTERFACE, Location.S2, Reason.INVALID_VALUE, String.valueOf(s2));
|
||||||
|
this.s2 = Optional.of(s2);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setH1(final long h1) throws BadConfigException {
|
||||||
|
if (h1 < 0)
|
||||||
|
throw new BadConfigException(
|
||||||
|
Section.INTERFACE, Location.H1, Reason.INVALID_VALUE, String.valueOf(h1));
|
||||||
|
this.h1 = Optional.of(h1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setH2(final long h2) throws BadConfigException {
|
||||||
|
if (h2 < 0)
|
||||||
|
throw new BadConfigException(
|
||||||
|
Section.INTERFACE, Location.H2, Reason.INVALID_VALUE, String.valueOf(h2));
|
||||||
|
this.h2 = Optional.of(h2);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setH3(final long h3) throws BadConfigException {
|
||||||
|
if (h3 < 0)
|
||||||
|
throw new BadConfigException(
|
||||||
|
Section.INTERFACE, Location.H3, Reason.INVALID_VALUE, String.valueOf(h3));
|
||||||
|
this.h3 = Optional.of(h3);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setH4(final long h4) throws BadConfigException {
|
||||||
|
if (h4 < 0)
|
||||||
|
throw new BadConfigException(
|
||||||
|
Section.INTERFACE, Location.H4, Reason.INVALID_VALUE, String.valueOf(h4));
|
||||||
|
this.h4 = Optional.of(h4);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -380,7 +380,10 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
|
||||||
mNetworkState.bindNetworkListener()
|
mNetworkState.bindNetworkListener()
|
||||||
}
|
}
|
||||||
"wireguard" -> {
|
"wireguard" -> {
|
||||||
startWireGuard()
|
startWireGuard("wireguard")
|
||||||
|
}
|
||||||
|
"awg" -> {
|
||||||
|
startWireGuard("awg")
|
||||||
}
|
}
|
||||||
"shadowsocks" -> {
|
"shadowsocks" -> {
|
||||||
startShadowsocks()
|
startShadowsocks()
|
||||||
|
|
@ -457,7 +460,8 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
|
||||||
fun turnOff() {
|
fun turnOff() {
|
||||||
Log.v(tag, "Aman: turnOff....................")
|
Log.v(tag, "Aman: turnOff....................")
|
||||||
when (mProtocol) {
|
when (mProtocol) {
|
||||||
"wireguard" -> {
|
"wireguard",
|
||||||
|
"awg" -> {
|
||||||
GoBackend.wgTurnOff(currentTunnelHandle)
|
GoBackend.wgTurnOff(currentTunnelHandle)
|
||||||
}
|
}
|
||||||
"cloak",
|
"cloak",
|
||||||
|
|
@ -559,14 +563,14 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
|
||||||
}
|
}
|
||||||
return parseData
|
return parseData
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Wireguard [Config] from a [json] string -
|
* Create a Wireguard [Config] from a [json] string -
|
||||||
* The [json] will be created in AndroidVpnProtocol.cpp
|
* The [json] will be created in AndroidVpnProtocol.cpp
|
||||||
*/
|
*/
|
||||||
private fun buildWireguardConfig(obj: JSONObject): Config {
|
private fun buildWireguardConfig(obj: JSONObject, type: String): Config {
|
||||||
val confBuilder = Config.Builder()
|
val confBuilder = Config.Builder()
|
||||||
val wireguardConfigData = obj.getJSONObject("wireguard_config_data")
|
val wireguardConfigData = obj.getJSONObject(type)
|
||||||
val config = parseConfigData(wireguardConfigData.getString("config"))
|
val config = parseConfigData(wireguardConfigData.getString("config"))
|
||||||
val peerBuilder = Peer.Builder()
|
val peerBuilder = Peer.Builder()
|
||||||
val peerConfig = config["Peer"]!!
|
val peerConfig = config["Peer"]!!
|
||||||
|
|
@ -599,6 +603,30 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
|
||||||
ifaceConfig["DNS"]!!.split(",").forEach {
|
ifaceConfig["DNS"]!!.split(",").forEach {
|
||||||
ifaceBuilder.addDnsServer(InetNetwork.parse(it.trim()).address)
|
ifaceBuilder.addDnsServer(InetNetwork.parse(it.trim()).address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ifaceBuilder.parsePrivateKey(ifaceConfig["PrivateKey"])
|
||||||
|
if (type == "awg_config_data") {
|
||||||
|
ifaceBuilder.parseJc(ifaceConfig["Jc"])
|
||||||
|
ifaceBuilder.parseJmin(ifaceConfig["Jmin"])
|
||||||
|
ifaceBuilder.parseJmax(ifaceConfig["Jmax"])
|
||||||
|
ifaceBuilder.parseS1(ifaceConfig["S1"])
|
||||||
|
ifaceBuilder.parseS2(ifaceConfig["S2"])
|
||||||
|
ifaceBuilder.parseH1(ifaceConfig["H1"])
|
||||||
|
ifaceBuilder.parseH2(ifaceConfig["H2"])
|
||||||
|
ifaceBuilder.parseH3(ifaceConfig["H3"])
|
||||||
|
ifaceBuilder.parseH4(ifaceConfig["H4"])
|
||||||
|
} else {
|
||||||
|
ifaceBuilder.parseJc("0")
|
||||||
|
ifaceBuilder.parseJmin("0")
|
||||||
|
ifaceBuilder.parseJmax("0")
|
||||||
|
ifaceBuilder.parseS1("0")
|
||||||
|
ifaceBuilder.parseS2("0")
|
||||||
|
ifaceBuilder.parseH1("0")
|
||||||
|
ifaceBuilder.parseH2("0")
|
||||||
|
ifaceBuilder.parseH3("0")
|
||||||
|
ifaceBuilder.parseH4("0")
|
||||||
|
|
||||||
|
}
|
||||||
/*val jExcludedApplication = obj.getJSONArray("excludedApps")
|
/*val jExcludedApplication = obj.getJSONArray("excludedApps")
|
||||||
(0 until jExcludedApplication.length()).toList().forEach {
|
(0 until jExcludedApplication.length()).toList().forEach {
|
||||||
val appName = jExcludedApplication.get(it).toString()
|
val appName = jExcludedApplication.get(it).toString()
|
||||||
|
|
@ -716,8 +744,8 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
|
||||||
}).start()
|
}).start()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startWireGuard() {
|
private fun startWireGuard(type: String) {
|
||||||
val wireguard_conf = buildWireguardConfig(mConfig!!)
|
val wireguard_conf = buildWireguardConfig(mConfig!!, type + "_config_data")
|
||||||
Log.i(tag, "startWireGuard: wireguard_conf : $wireguard_conf")
|
Log.i(tag, "startWireGuard: wireguard_conf : $wireguard_conf")
|
||||||
if (currentTunnelHandle != -1) {
|
if (currentTunnelHandle != -1) {
|
||||||
Log.e(tag, "Tunnel already up")
|
Log.e(tag, "Tunnel already up")
|
||||||
|
|
@ -728,9 +756,15 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
|
||||||
val builder = Builder()
|
val builder = Builder()
|
||||||
setupBuilder(wireguard_conf, builder)
|
setupBuilder(wireguard_conf, builder)
|
||||||
builder.setSession("Amnezia")
|
builder.setSession("Amnezia")
|
||||||
|
|
||||||
|
|
||||||
builder.establish().use { tun ->
|
builder.establish().use { tun ->
|
||||||
if (tun == null) return
|
if (tun == null) return
|
||||||
currentTunnelHandle = GoBackend.wgTurnOn("Amnezia", tun.detachFd(), wgConfig)
|
if (type == "awg"){
|
||||||
|
currentTunnelHandle = GoBackend.wgTurnOn("awg0", tun.detachFd(), wgConfig)
|
||||||
|
} else {
|
||||||
|
currentTunnelHandle = GoBackend.wgTurnOn("amn0", tun.detachFd(), wgConfig)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (currentTunnelHandle < 0) {
|
if (currentTunnelHandle < 0) {
|
||||||
Log.e(tag, "Activation Error Code -> $currentTunnelHandle")
|
Log.e(tag, "Activation Error Code -> $currentTunnelHandle")
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ set(HEADERS ${HEADERS}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_notificationhandler.h
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_notificationhandler.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidutils.h
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidutils.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidvpnactivity.h
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidvpnactivity.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.h
|
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -18,6 +19,7 @@ set(SOURCES ${SOURCES}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_notificationhandler.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_notificationhandler.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidutils.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidutils.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidvpnactivity.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidvpnactivity.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ target_compile_options(${PROJECT} PRIVATE
|
||||||
-DVPN_NE_BUNDLEID=\"${BUILD_IOS_APP_IDENTIFIER}.network-extension\"
|
-DVPN_NE_BUNDLEID=\"${BUILD_IOS_APP_IDENTIFIER}.network-extension\"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/wireguard-apple/Sources)
|
set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/awg-apple/Sources)
|
||||||
|
|
||||||
target_sources(${PROJECT} PRIVATE
|
target_sources(${PROJECT} PRIVATE
|
||||||
# ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosvpnprotocol.swift
|
# ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosvpnprotocol.swift
|
||||||
|
|
|
||||||
47
client/configurators/awg_configurator.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "awg_configurator.h"
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
#include "core/servercontroller.h"
|
||||||
|
|
||||||
|
AwgConfigurator::AwgConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
|
||||||
|
: WireguardConfigurator(settings, true, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AwgConfigurator::genAwgConfig(const ServerCredentials &credentials,
|
||||||
|
DockerContainer container,
|
||||||
|
const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||||
|
{
|
||||||
|
QString config = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, errorCode);
|
||||||
|
|
||||||
|
QJsonObject jsonConfig = QJsonDocument::fromJson(config.toUtf8()).object();
|
||||||
|
QString awgConfig = jsonConfig.value(config_key::config).toString();
|
||||||
|
|
||||||
|
QMap<QString, QString> configMap;
|
||||||
|
auto configLines = awgConfig.split("\n");
|
||||||
|
for (auto &line : configLines) {
|
||||||
|
auto trimmedLine = line.trimmed();
|
||||||
|
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
QStringList parts = trimmedLine.split(" = ");
|
||||||
|
if (parts.count() == 2) {
|
||||||
|
configMap.insert(parts[0].trimmed(), parts[1].trimmed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonConfig[config_key::junkPacketCount] = configMap.value(config_key::junkPacketCount);
|
||||||
|
jsonConfig[config_key::junkPacketMinSize] = configMap.value(config_key::junkPacketMinSize);
|
||||||
|
jsonConfig[config_key::junkPacketMaxSize] = configMap.value(config_key::junkPacketMaxSize);
|
||||||
|
jsonConfig[config_key::initPacketJunkSize] = configMap.value(config_key::initPacketJunkSize);
|
||||||
|
jsonConfig[config_key::responsePacketJunkSize] = configMap.value(config_key::responsePacketJunkSize);
|
||||||
|
jsonConfig[config_key::initPacketMagicHeader] = configMap.value(config_key::initPacketMagicHeader);
|
||||||
|
jsonConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader);
|
||||||
|
jsonConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader);
|
||||||
|
jsonConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
|
||||||
|
|
||||||
|
return QJsonDocument(jsonConfig).toJson();
|
||||||
|
}
|
||||||
18
client/configurators/awg_configurator.h
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef AWGCONFIGURATOR_H
|
||||||
|
#define AWGCONFIGURATOR_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "wireguard_configurator.h"
|
||||||
|
|
||||||
|
class AwgConfigurator : public WireguardConfigurator
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
AwgConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QString genAwgConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||||
|
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AWGCONFIGURATOR_H
|
||||||
|
|
@ -1,28 +1,26 @@
|
||||||
#include "ikev2_configurator.h"
|
#include "ikev2_configurator.h"
|
||||||
#include <QApplication>
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QJsonDocument>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
#include <QDebug>
|
|
||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
#include "containers/containers_defs.h"
|
#include "containers/containers_defs.h"
|
||||||
#include "core/server_defs.h"
|
|
||||||
#include "core/scripts_registry.h"
|
#include "core/scripts_registry.h"
|
||||||
#include "utilities.h"
|
#include "core/server_defs.h"
|
||||||
#include "core/servercontroller.h"
|
#include "core/servercontroller.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
Ikev2Configurator::Ikev2Configurator(std::shared_ptr<Settings> settings, QObject *parent)
|
||||||
Ikev2Configurator::Ikev2Configurator(std::shared_ptr<Settings> settings, QObject *parent):
|
: ConfiguratorBase(settings, parent)
|
||||||
ConfiguratorBase(settings, parent)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const ServerCredentials &credentials,
|
Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const ServerCredentials &credentials,
|
||||||
DockerContainer container, ErrorCode *errorCode)
|
DockerContainer container, ErrorCode *errorCode)
|
||||||
{
|
{
|
||||||
Ikev2Configurator::ConnectionData connData;
|
Ikev2Configurator::ConnectionData connData;
|
||||||
connData.host = credentials.hostName;
|
connData.host = credentials.hostName;
|
||||||
|
|
@ -32,26 +30,27 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
|
||||||
|
|
||||||
QString certFileName = "/opt/amnezia/ikev2/clients/" + connData.clientId + ".p12";
|
QString certFileName = "/opt/amnezia/ikev2/clients/" + connData.clientId + ".p12";
|
||||||
|
|
||||||
QString scriptCreateCert = QString("certutil -z <(head -c 1024 /dev/urandom) "\
|
QString scriptCreateCert = QString("certutil -z <(head -c 1024 /dev/urandom) "
|
||||||
"-S -c \"IKEv2 VPN CA\" -n \"%1\" "\
|
"-S -c \"IKEv2 VPN CA\" -n \"%1\" "
|
||||||
"-s \"O=IKEv2 VPN,CN=%1\" "\
|
"-s \"O=IKEv2 VPN,CN=%1\" "
|
||||||
"-k rsa -g 3072 -v 120 "\
|
"-k rsa -g 3072 -v 120 "
|
||||||
"-d sql:/etc/ipsec.d -t \",,\" "\
|
"-d sql:/etc/ipsec.d -t \",,\" "
|
||||||
"--keyUsage digitalSignature,keyEncipherment "\
|
"--keyUsage digitalSignature,keyEncipherment "
|
||||||
"--extKeyUsage serverAuth,clientAuth -8 \"%1\"")
|
"--extKeyUsage serverAuth,clientAuth -8 \"%1\"")
|
||||||
.arg(connData.clientId);
|
.arg(connData.clientId);
|
||||||
|
|
||||||
ServerController serverController(m_settings);
|
ServerController serverController(m_settings);
|
||||||
ErrorCode e = serverController.runContainerScript(credentials, container, scriptCreateCert);
|
ErrorCode e = serverController.runContainerScript(credentials, container, scriptCreateCert);
|
||||||
|
|
||||||
QString scriptExportCert = QString("pk12util -W \"%1\" -d sql:/etc/ipsec.d -n \"%2\" -o \"%3\"")
|
QString scriptExportCert = QString("pk12util -W \"%1\" -d sql:/etc/ipsec.d -n \"%2\" -o \"%3\"")
|
||||||
.arg(connData.password)
|
.arg(connData.password)
|
||||||
.arg(connData.clientId)
|
.arg(connData.clientId)
|
||||||
.arg(certFileName);
|
.arg(certFileName);
|
||||||
e = serverController.runContainerScript(credentials, container, scriptExportCert);
|
e = serverController.runContainerScript(credentials, container, scriptExportCert);
|
||||||
|
|
||||||
connData.clientCert = serverController.getTextFileFromContainer(container, credentials, certFileName, &e);
|
connData.clientCert = serverController.getTextFileFromContainer(container, credentials, certFileName, &e);
|
||||||
connData.caCert = serverController.getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e);
|
connData.caCert =
|
||||||
|
serverController.getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e);
|
||||||
|
|
||||||
qDebug() << "Ikev2Configurator::ConnectionData client cert size:" << connData.clientCert.size();
|
qDebug() << "Ikev2Configurator::ConnectionData client cert size:" << connData.clientCert.size();
|
||||||
qDebug() << "Ikev2Configurator::ConnectionData ca cert size:" << connData.caCert.size();
|
qDebug() << "Ikev2Configurator::ConnectionData ca cert size:" << connData.caCert.size();
|
||||||
|
|
@ -59,8 +58,8 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Ikev2Configurator::genIkev2Config(const ServerCredentials &credentials,
|
QString Ikev2Configurator::genIkev2Config(const ServerCredentials &credentials, DockerContainer container,
|
||||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
|
const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||||
{
|
{
|
||||||
Q_UNUSED(containerConfig)
|
Q_UNUSED(containerConfig)
|
||||||
|
|
||||||
|
|
@ -120,4 +119,3 @@ QString Ikev2Configurator::genStrongSwanConfig(const ConnectionData &connData)
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,82 +1,94 @@
|
||||||
#include "openvpn_configurator.h"
|
#include "openvpn_configurator.h"
|
||||||
#include <QApplication>
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
#include <QDebug>
|
|
||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
#include <QJsonObject>
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
#include <QJsonDocument>
|
#include <QGuiApplication>
|
||||||
|
#else
|
||||||
|
#include <QApplication>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "containers/containers_defs.h"
|
#include "containers/containers_defs.h"
|
||||||
|
#include "core/scripts_registry.h"
|
||||||
#include "core/server_defs.h"
|
#include "core/server_defs.h"
|
||||||
#include "core/servercontroller.h"
|
#include "core/servercontroller.h"
|
||||||
#include "core/scripts_registry.h"
|
|
||||||
#include "utilities.h"
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
#include <openssl/pem.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/pem.h>
|
|
||||||
|
|
||||||
OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
|
OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
|
||||||
ConfiguratorBase(settings, parent)
|
: ConfiguratorBase(settings, parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials,
|
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials,
|
||||||
DockerContainer container, ErrorCode *errorCode)
|
DockerContainer container,
|
||||||
|
ErrorCode *errorCode)
|
||||||
{
|
{
|
||||||
OpenVpnConfigurator::ConnectionData connData = OpenVpnConfigurator::createCertRequest();
|
OpenVpnConfigurator::ConnectionData connData = OpenVpnConfigurator::createCertRequest();
|
||||||
connData.host = credentials.hostName;
|
connData.host = credentials.hostName;
|
||||||
|
|
||||||
if (connData.privKey.isEmpty() || connData.request.isEmpty()) {
|
if (connData.privKey.isEmpty() || connData.request.isEmpty()) {
|
||||||
if (errorCode) *errorCode = ErrorCode::OpenSslFailed;
|
if (errorCode)
|
||||||
|
*errorCode = ErrorCode::OpenSslFailed;
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString reqFileName = QString("%1/%2.req").
|
QString reqFileName = QString("%1/%2.req").arg(amnezia::protocols::openvpn::clientsDirPath).arg(connData.clientId);
|
||||||
arg(amnezia::protocols::openvpn::clientsDirPath).
|
|
||||||
arg(connData.clientId);
|
|
||||||
|
|
||||||
ServerController serverController(m_settings);
|
ServerController serverController(m_settings);
|
||||||
ErrorCode e = serverController.uploadTextFileToContainer(container, credentials, connData.request, reqFileName);
|
ErrorCode e = serverController.uploadTextFileToContainer(container, credentials, connData.request, reqFileName);
|
||||||
if (e) {
|
if (e) {
|
||||||
if (errorCode) *errorCode = e;
|
if (errorCode)
|
||||||
|
*errorCode = e;
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = signCert(container, credentials, connData.clientId);
|
e = signCert(container, credentials, connData.clientId);
|
||||||
if (e) {
|
if (e) {
|
||||||
if (errorCode) *errorCode = e;
|
if (errorCode)
|
||||||
|
*errorCode = e;
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
connData.caCert = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::caCertPath, &e);
|
connData.caCert = serverController.getTextFileFromContainer(container, credentials,
|
||||||
connData.clientCert = serverController.getTextFileFromContainer(container, credentials,
|
amnezia::protocols::openvpn::caCertPath, &e);
|
||||||
QString("%1/%2.crt").arg(amnezia::protocols::openvpn::clientCertPath).arg(connData.clientId), &e);
|
connData.clientCert = serverController.getTextFileFromContainer(
|
||||||
|
container, credentials,
|
||||||
|
QString("%1/%2.crt").arg(amnezia::protocols::openvpn::clientCertPath).arg(connData.clientId), &e);
|
||||||
|
|
||||||
if (e) {
|
if (e) {
|
||||||
if (errorCode) *errorCode = e;
|
if (errorCode)
|
||||||
|
*errorCode = e;
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
connData.taKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::taKeyPath, &e);
|
connData.taKey = serverController.getTextFileFromContainer(container, credentials,
|
||||||
|
amnezia::protocols::openvpn::taKeyPath, &e);
|
||||||
|
|
||||||
if (connData.caCert.isEmpty() || connData.clientCert.isEmpty() || connData.taKey.isEmpty()) {
|
if (connData.caCert.isEmpty() || connData.clientCert.isEmpty() || connData.taKey.isEmpty()) {
|
||||||
if (errorCode) *errorCode = ErrorCode::SshSftpFailureError;
|
if (errorCode)
|
||||||
|
*errorCode = ErrorCode::SshSftpFailureError;
|
||||||
}
|
}
|
||||||
|
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials,
|
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
|
const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||||
{
|
{
|
||||||
ServerController serverController(m_settings);
|
ServerController serverController(m_settings);
|
||||||
QString config = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container),
|
QString config =
|
||||||
serverController.genVarsForScript(credentials, container, containerConfig));
|
serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container),
|
||||||
|
serverController.genVarsForScript(credentials, container, containerConfig));
|
||||||
|
|
||||||
ConnectionData connData = prepareOpenVpnConfig(credentials, container, errorCode);
|
ConnectionData connData = prepareOpenVpnConfig(credentials, container, errorCode);
|
||||||
if (errorCode && *errorCode) {
|
if (errorCode && *errorCode) {
|
||||||
|
|
@ -89,8 +101,7 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
|
||||||
|
|
||||||
if (config.contains("$OPENVPN_TA_KEY")) {
|
if (config.contains("$OPENVPN_TA_KEY")) {
|
||||||
config.replace("$OPENVPN_TA_KEY", connData.taKey);
|
config.replace("$OPENVPN_TA_KEY", connData.taKey);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
config.replace("<tls-auth>", "");
|
config.replace("<tls-auth>", "");
|
||||||
config.replace("</tls-auth>", "");
|
config.replace("</tls-auth>", "");
|
||||||
}
|
}
|
||||||
|
|
@ -133,12 +144,11 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig)
|
||||||
config.replace("block-outside-dns", "");
|
config.replace("block-outside-dns", "");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined (MZ_MACOS) || defined(MZ_LINUX))
|
#if (defined(MZ_MACOS) || defined(MZ_LINUX))
|
||||||
QString dnsConf = QString(
|
QString dnsConf = QString("\nscript-security 2\n"
|
||||||
"\nscript-security 2\n"
|
"up %1/update-resolv-conf.sh\n"
|
||||||
"up %1/update-resolv-conf.sh\n"
|
"down %1/update-resolv-conf.sh\n")
|
||||||
"down %1/update-resolv-conf.sh\n").
|
.arg(qApp->applicationDirPath());
|
||||||
arg(qApp->applicationDirPath());
|
|
||||||
|
|
||||||
config.append(dnsConf);
|
config.append(dnsConf);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -168,23 +178,23 @@ QString OpenVpnConfigurator::processConfigWithExportSettings(QString jsonConfig)
|
||||||
return QJsonDocument(json).toJson();
|
return QJsonDocument(json).toJson();
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode OpenVpnConfigurator::signCert(DockerContainer container,
|
ErrorCode OpenVpnConfigurator::signCert(DockerContainer container, const ServerCredentials &credentials, QString clientId)
|
||||||
const ServerCredentials &credentials, QString clientId)
|
|
||||||
{
|
{
|
||||||
QString script_import = QString("sudo docker exec -i %1 bash -c \"cd /opt/amnezia/openvpn && "
|
QString script_import = QString("sudo docker exec -i %1 bash -c \"cd /opt/amnezia/openvpn && "
|
||||||
"easyrsa import-req %2/%3.req %3\"")
|
"easyrsa import-req %2/%3.req %3\"")
|
||||||
.arg(ContainerProps::containerToString(container))
|
.arg(ContainerProps::containerToString(container))
|
||||||
.arg(amnezia::protocols::openvpn::clientsDirPath)
|
.arg(amnezia::protocols::openvpn::clientsDirPath)
|
||||||
.arg(clientId);
|
.arg(clientId);
|
||||||
|
|
||||||
QString script_sign = QString("sudo docker exec -i %1 bash -c \"export EASYRSA_BATCH=1; cd /opt/amnezia/openvpn && "
|
QString script_sign = QString("sudo docker exec -i %1 bash -c \"export EASYRSA_BATCH=1; cd /opt/amnezia/openvpn && "
|
||||||
"easyrsa sign-req client %2\"")
|
"easyrsa sign-req client %2\"")
|
||||||
.arg(ContainerProps::containerToString(container))
|
.arg(ContainerProps::containerToString(container))
|
||||||
.arg(clientId);
|
.arg(clientId);
|
||||||
|
|
||||||
ServerController serverController(m_settings);
|
ServerController serverController(m_settings);
|
||||||
QStringList scriptList {script_import, script_sign};
|
QStringList scriptList { script_import, script_sign };
|
||||||
QString script = serverController.replaceVars(scriptList.join("\n"), serverController.genVarsForScript(credentials, container));
|
QString script = serverController.replaceVars(scriptList.join("\n"),
|
||||||
|
serverController.genVarsForScript(credentials, container));
|
||||||
|
|
||||||
return serverController.runScript(credentials, script);
|
return serverController.runScript(credentials, script);
|
||||||
}
|
}
|
||||||
|
|
@ -194,18 +204,17 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
|
||||||
ConnectionData connData;
|
ConnectionData connData;
|
||||||
connData.clientId = Utils::getRandomString(32);
|
connData.clientId = Utils::getRandomString(32);
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int nVersion = 1;
|
int nVersion = 1;
|
||||||
|
|
||||||
QByteArray clientIdUtf8 = connData.clientId.toUtf8();
|
QByteArray clientIdUtf8 = connData.clientId.toUtf8();
|
||||||
|
|
||||||
EVP_PKEY * pKey = EVP_PKEY_new();
|
EVP_PKEY *pKey = EVP_PKEY_new();
|
||||||
q_check_ptr(pKey);
|
q_check_ptr(pKey);
|
||||||
RSA * rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
|
RSA *rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
|
||||||
q_check_ptr(rsa);
|
q_check_ptr(rsa);
|
||||||
EVP_PKEY_assign_RSA(pKey, rsa);
|
EVP_PKEY_assign_RSA(pKey, rsa);
|
||||||
|
|
||||||
|
|
||||||
// 2. set version of x509 req
|
// 2. set version of x509 req
|
||||||
X509_REQ *x509_req = X509_REQ_new();
|
X509_REQ *x509_req = X509_REQ_new();
|
||||||
ret = X509_REQ_set_version(x509_req, nVersion);
|
ret = X509_REQ_set_version(x509_req, nVersion);
|
||||||
|
|
@ -219,16 +228,14 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
|
||||||
// 3. set subject of x509 req
|
// 3. set subject of x509 req
|
||||||
X509_NAME *x509_name = X509_REQ_get_subject_name(x509_req);
|
X509_NAME *x509_name = X509_REQ_get_subject_name(x509_req);
|
||||||
|
|
||||||
X509_NAME_add_entry_by_txt(x509_name, "C", MBSTRING_ASC,
|
X509_NAME_add_entry_by_txt(x509_name, "C", MBSTRING_ASC, (unsigned char *)"ORG", -1, -1, 0);
|
||||||
(unsigned char *)"ORG", -1, -1, 0);
|
X509_NAME_add_entry_by_txt(x509_name, "O", MBSTRING_ASC, (unsigned char *)"", -1, -1, 0);
|
||||||
X509_NAME_add_entry_by_txt(x509_name, "O", MBSTRING_ASC,
|
|
||||||
(unsigned char *)"", -1, -1, 0);
|
|
||||||
X509_NAME_add_entry_by_txt(x509_name, "CN", MBSTRING_ASC,
|
X509_NAME_add_entry_by_txt(x509_name, "CN", MBSTRING_ASC,
|
||||||
reinterpret_cast<unsigned char const *>(clientIdUtf8.data()), clientIdUtf8.size(), -1, 0);
|
reinterpret_cast<unsigned char const *>(clientIdUtf8.data()), clientIdUtf8.size(), -1, 0);
|
||||||
|
|
||||||
// 4. set public key of x509 req
|
// 4. set public key of x509 req
|
||||||
ret = X509_REQ_set_pubkey(x509_req, pKey);
|
ret = X509_REQ_set_pubkey(x509_req, pKey);
|
||||||
if (ret != 1){
|
if (ret != 1) {
|
||||||
qWarning() << "Could not set pubkey!";
|
qWarning() << "Could not set pubkey!";
|
||||||
X509_REQ_free(x509_req);
|
X509_REQ_free(x509_req);
|
||||||
EVP_PKEY_free(pKey);
|
EVP_PKEY_free(pKey);
|
||||||
|
|
@ -236,8 +243,8 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. set sign key of x509 req
|
// 5. set sign key of x509 req
|
||||||
ret = X509_REQ_sign(x509_req, pKey, EVP_sha256()); // return x509_req->signature->length
|
ret = X509_REQ_sign(x509_req, pKey, EVP_sha256()); // return x509_req->signature->length
|
||||||
if (ret <= 0){
|
if (ret <= 0) {
|
||||||
qWarning() << "Could not sign request!";
|
qWarning() << "Could not sign request!";
|
||||||
X509_REQ_free(x509_req);
|
X509_REQ_free(x509_req);
|
||||||
EVP_PKEY_free(pKey);
|
EVP_PKEY_free(pKey);
|
||||||
|
|
@ -245,10 +252,9 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
// save private key
|
// save private key
|
||||||
BIO * bp_private = BIO_new(BIO_s_mem());
|
BIO *bp_private = BIO_new(BIO_s_mem());
|
||||||
q_check_ptr(bp_private);
|
q_check_ptr(bp_private);
|
||||||
if (PEM_write_bio_PrivateKey(bp_private, pKey, nullptr, nullptr, 0, nullptr, nullptr) != 1)
|
if (PEM_write_bio_PrivateKey(bp_private, pKey, nullptr, nullptr, 0, nullptr, nullptr) != 1) {
|
||||||
{
|
|
||||||
qFatal("PEM_write_bio_PrivateKey");
|
qFatal("PEM_write_bio_PrivateKey");
|
||||||
EVP_PKEY_free(pKey);
|
EVP_PKEY_free(pKey);
|
||||||
BIO_free_all(bp_private);
|
BIO_free_all(bp_private);
|
||||||
|
|
@ -256,7 +262,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * buffer = nullptr;
|
const char *buffer = nullptr;
|
||||||
size_t size = BIO_get_mem_data(bp_private, &buffer);
|
size_t size = BIO_get_mem_data(bp_private, &buffer);
|
||||||
q_check_ptr(buffer);
|
q_check_ptr(buffer);
|
||||||
connData.privKey = QByteArray(buffer, size);
|
connData.privKey = QByteArray(buffer, size);
|
||||||
|
|
@ -270,7 +276,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
|
||||||
BIO_free_all(bp_private);
|
BIO_free_all(bp_private);
|
||||||
|
|
||||||
// save req
|
// save req
|
||||||
BIO * bio_req = BIO_new(BIO_s_mem());
|
BIO *bio_req = BIO_new(BIO_s_mem());
|
||||||
PEM_write_bio_X509_REQ(bio_req, x509_req);
|
PEM_write_bio_X509_REQ(bio_req, x509_req);
|
||||||
|
|
||||||
BUF_MEM *bio_buf;
|
BUF_MEM *bio_buf;
|
||||||
|
|
@ -278,7 +284,6 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
|
||||||
connData.request = QByteArray(bio_buf->data, bio_buf->length);
|
connData.request = QByteArray(bio_buf->data, bio_buf->length);
|
||||||
BIO_free(bio_req);
|
BIO_free(bio_req);
|
||||||
|
|
||||||
|
|
||||||
EVP_PKEY_free(pKey); // this will also free the rsa key
|
EVP_PKEY_free(pKey); // this will also free the rsa key
|
||||||
|
|
||||||
return connData;
|
return connData;
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,25 @@
|
||||||
#include "ssh_configurator.h"
|
#include "ssh_configurator.h"
|
||||||
#include <QApplication>
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QObject>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
#include <QDebug>
|
|
||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QObject>
|
|
||||||
#include <QTextEdit>
|
|
||||||
#include <QPlainTextEdit>
|
|
||||||
#include <qtimer.h>
|
#include <qtimer.h>
|
||||||
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#else
|
||||||
|
#include <QApplication>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "core/server_defs.h"
|
#include "core/server_defs.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
|
SshConfigurator::SshConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
|
||||||
SshConfigurator::SshConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
|
: ConfiguratorBase(settings, parent)
|
||||||
ConfiguratorBase(settings, parent)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SshConfigurator::convertOpenSShKey(const QString &key)
|
QString SshConfigurator::convertOpenSShKey(const QString &key)
|
||||||
|
|
@ -28,23 +29,30 @@ QString SshConfigurator::convertOpenSShKey(const QString &key)
|
||||||
p.setProcessChannelMode(QProcess::MergedChannels);
|
p.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
|
||||||
QTemporaryFile tmp;
|
QTemporaryFile tmp;
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
tmp.setAutoRemove(false);
|
tmp.setAutoRemove(false);
|
||||||
#endif
|
#endif
|
||||||
tmp.open();
|
tmp.open();
|
||||||
tmp.write(key.toUtf8());
|
tmp.write(key.toUtf8());
|
||||||
tmp.close();
|
tmp.close();
|
||||||
|
|
||||||
// ssh-keygen -p -P "" -N "" -m pem -f id_ssh
|
// ssh-keygen -p -P "" -N "" -m pem -f id_ssh
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
p.setProcessEnvironment(prepareEnv());
|
p.setProcessEnvironment(prepareEnv());
|
||||||
p.setProgram("cmd.exe");
|
p.setProgram("cmd.exe");
|
||||||
p.setNativeArguments(QString("/C \"ssh-keygen.exe -p -P \"\" -N \"\" -m pem -f \"%1\"\"").arg(tmp.fileName()));
|
p.setNativeArguments(QString("/C \"ssh-keygen.exe -p -P \"\" -N \"\" -m pem -f \"%1\"\"").arg(tmp.fileName()));
|
||||||
#else
|
#else
|
||||||
p.setProgram("ssh-keygen");
|
p.setProgram("ssh-keygen");
|
||||||
p.setArguments(QStringList() << "-p" << "-P" << "" << "-N" << "" << "-m" << "pem" << "-f" << tmp.fileName());
|
p.setArguments(QStringList() << "-p"
|
||||||
#endif
|
<< "-P"
|
||||||
|
<< ""
|
||||||
|
<< "-N"
|
||||||
|
<< ""
|
||||||
|
<< "-m"
|
||||||
|
<< "pem"
|
||||||
|
<< "-f" << tmp.fileName());
|
||||||
|
#endif
|
||||||
|
|
||||||
p.start();
|
p.start();
|
||||||
p.waitForFinished();
|
p.waitForFinished();
|
||||||
|
|
@ -65,22 +73,21 @@ void SshConfigurator::openSshTerminal(const ServerCredentials &credentials)
|
||||||
QProcess *p = new QProcess();
|
QProcess *p = new QProcess();
|
||||||
p->setProcessChannelMode(QProcess::SeparateChannels);
|
p->setProcessChannelMode(QProcess::SeparateChannels);
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
p->setProcessEnvironment(prepareEnv());
|
p->setProcessEnvironment(prepareEnv());
|
||||||
p->setProgram(qApp->applicationDirPath() + "\\cygwin\\putty.exe");
|
p->setProgram(qApp->applicationDirPath() + "\\cygwin\\putty.exe");
|
||||||
|
|
||||||
if (credentials.password.contains("PRIVATE KEY")) {
|
if (credentials.secretData.contains("PRIVATE KEY")) {
|
||||||
// todo: connect by key
|
// todo: connect by key
|
||||||
// p->setNativeArguments(QString("%1@%2")
|
// p->setNativeArguments(QString("%1@%2")
|
||||||
// .arg(credentials.userName).arg(credentials.hostName).arg(credentials.password));
|
// .arg(credentials.userName).arg(credentials.hostName).arg(credentials.secretData));
|
||||||
|
} else {
|
||||||
|
p->setNativeArguments(
|
||||||
|
QString("%1@%2 -pw %3").arg(credentials.userName).arg(credentials.hostName).arg(credentials.secretData));
|
||||||
}
|
}
|
||||||
else {
|
#else
|
||||||
p->setNativeArguments(QString("%1@%2 -pw %3")
|
|
||||||
.arg(credentials.userName).arg(credentials.hostName).arg(credentials.password));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
p->setProgram("/bin/bash");
|
p->setProgram("/bin/bash");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
p->startDetached();
|
p->startDetached();
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -95,11 +102,11 @@ QProcessEnvironment SshConfigurator::prepareEnv()
|
||||||
pathEnvVar.clear();
|
pathEnvVar.clear();
|
||||||
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\cygwin;");
|
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\cygwin;");
|
||||||
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\openvpn;");
|
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\openvpn;");
|
||||||
#else
|
#elif defined(Q_OS_MACX)
|
||||||
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS");
|
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
env.insert("PATH", pathEnvVar);
|
env.insert("PATH", pathEnvVar);
|
||||||
//qDebug().noquote() << "ENV PATH" << pathEnvVar;
|
// qDebug().noquote() << "ENV PATH" << pathEnvVar;
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,34 @@
|
||||||
#include "vpn_configurator.h"
|
#include "vpn_configurator.h"
|
||||||
#include "openvpn_configurator.h"
|
|
||||||
#include "cloak_configurator.h"
|
#include "cloak_configurator.h"
|
||||||
#include "shadowsocks_configurator.h"
|
|
||||||
#include "wireguard_configurator.h"
|
|
||||||
#include "ikev2_configurator.h"
|
#include "ikev2_configurator.h"
|
||||||
|
#include "openvpn_configurator.h"
|
||||||
|
#include "shadowsocks_configurator.h"
|
||||||
#include "ssh_configurator.h"
|
#include "ssh_configurator.h"
|
||||||
|
#include "wireguard_configurator.h"
|
||||||
|
#include "awg_configurator.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
#include "containers/containers_defs.h"
|
#include "containers/containers_defs.h"
|
||||||
#include "utilities.h"
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
|
VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
|
||||||
ConfiguratorBase(settings, parent)
|
: ConfiguratorBase(settings, parent)
|
||||||
{
|
{
|
||||||
openVpnConfigurator = std::shared_ptr<OpenVpnConfigurator>(new OpenVpnConfigurator(settings, this));
|
openVpnConfigurator = std::shared_ptr<OpenVpnConfigurator>(new OpenVpnConfigurator(settings, this));
|
||||||
shadowSocksConfigurator = std::shared_ptr<ShadowSocksConfigurator>(new ShadowSocksConfigurator(settings, this));
|
shadowSocksConfigurator = std::shared_ptr<ShadowSocksConfigurator>(new ShadowSocksConfigurator(settings, this));
|
||||||
cloakConfigurator = std::shared_ptr<CloakConfigurator>(new CloakConfigurator(settings, this));
|
cloakConfigurator = std::shared_ptr<CloakConfigurator>(new CloakConfigurator(settings, this));
|
||||||
wireguardConfigurator = std::shared_ptr<WireguardConfigurator>(new WireguardConfigurator(settings, this));
|
wireguardConfigurator = std::shared_ptr<WireguardConfigurator>(new WireguardConfigurator(settings, false, this));
|
||||||
ikev2Configurator = std::shared_ptr<Ikev2Configurator>(new Ikev2Configurator(settings, this));
|
ikev2Configurator = std::shared_ptr<Ikev2Configurator>(new Ikev2Configurator(settings, this));
|
||||||
sshConfigurator = std::shared_ptr<SshConfigurator>(new SshConfigurator(settings, this));
|
sshConfigurator = std::shared_ptr<SshConfigurator>(new SshConfigurator(settings, this));
|
||||||
|
awgConfigurator = std::shared_ptr<AwgConfigurator>(new AwgConfigurator(settings, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials,
|
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||||
DockerContainer container, const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode)
|
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode)
|
||||||
{
|
{
|
||||||
switch (proto) {
|
switch (proto) {
|
||||||
case Proto::OpenVpn:
|
case Proto::OpenVpn:
|
||||||
|
|
@ -35,17 +37,17 @@ QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentia
|
||||||
case Proto::ShadowSocks:
|
case Proto::ShadowSocks:
|
||||||
return shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, errorCode);
|
return shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, errorCode);
|
||||||
|
|
||||||
case Proto::Cloak:
|
case Proto::Cloak: return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode);
|
||||||
return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode);
|
|
||||||
|
|
||||||
case Proto::WireGuard:
|
case Proto::WireGuard:
|
||||||
return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, errorCode);
|
return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, errorCode);
|
||||||
|
|
||||||
case Proto::Ikev2:
|
case Proto::Awg:
|
||||||
return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode);
|
return awgConfigurator->genAwgConfig(credentials, container, containerConfig, errorCode);
|
||||||
|
|
||||||
default:
|
case Proto::Ikev2: return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode);
|
||||||
return "";
|
|
||||||
|
default: return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,8 +64,8 @@ QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
|
||||||
if (dns.first.isEmpty() || !Utils::checkIPv4Format(dns.first)) {
|
if (dns.first.isEmpty() || !Utils::checkIPv4Format(dns.first)) {
|
||||||
if (useAmneziaDns && m_settings->containers(serverIndex).contains(DockerContainer::Dns)) {
|
if (useAmneziaDns && m_settings->containers(serverIndex).contains(DockerContainer::Dns)) {
|
||||||
dns.first = protocols::dns::amneziaDnsIp;
|
dns.first = protocols::dns::amneziaDnsIp;
|
||||||
}
|
} else
|
||||||
else dns.first = m_settings->primaryDns();
|
dns.first = m_settings->primaryDns();
|
||||||
}
|
}
|
||||||
if (dns.second.isEmpty() || !Utils::checkIPv4Format(dns.second)) {
|
if (dns.second.isEmpty() || !Utils::checkIPv4Format(dns.second)) {
|
||||||
dns.second = m_settings->secondaryDns();
|
dns.second = m_settings->secondaryDns();
|
||||||
|
|
@ -73,8 +75,8 @@ QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
|
||||||
return dns;
|
return dns;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container,
|
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto,
|
||||||
Proto proto, QString &config)
|
QString &config)
|
||||||
{
|
{
|
||||||
auto dns = getDnsForConfig(serverIndex);
|
auto dns = getDnsForConfig(serverIndex);
|
||||||
|
|
||||||
|
|
@ -84,8 +86,8 @@ QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerCo
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container,
|
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto,
|
||||||
Proto proto, QString &config)
|
QString &config)
|
||||||
{
|
{
|
||||||
processConfigWithDnsSettings(serverIndex, container, proto, config);
|
processConfigWithDnsSettings(serverIndex, container, proto, config);
|
||||||
|
|
||||||
|
|
@ -95,8 +97,8 @@ QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, Docker
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container,
|
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto,
|
||||||
Proto proto, QString &config)
|
QString &config)
|
||||||
{
|
{
|
||||||
processConfigWithDnsSettings(serverIndex, container, proto, config);
|
processConfigWithDnsSettings(serverIndex, container, proto, config);
|
||||||
|
|
||||||
|
|
@ -107,7 +109,7 @@ QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, Docke
|
||||||
}
|
}
|
||||||
|
|
||||||
void VpnConfigurator::updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig,
|
void VpnConfigurator::updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig,
|
||||||
const QString &stdOut)
|
const QString &stdOut)
|
||||||
{
|
{
|
||||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
Proto mainProto = ContainerProps::defaultProtocol(container);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,14 @@ class CloakConfigurator;
|
||||||
class WireguardConfigurator;
|
class WireguardConfigurator;
|
||||||
class Ikev2Configurator;
|
class Ikev2Configurator;
|
||||||
class SshConfigurator;
|
class SshConfigurator;
|
||||||
|
class AwgConfigurator;
|
||||||
|
|
||||||
// Retrieve connection settings from server
|
// Retrieve connection settings from server
|
||||||
class VpnConfigurator : ConfiguratorBase
|
class VpnConfigurator : ConfiguratorBase
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
explicit VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||||
|
|
||||||
QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
|
QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||||
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
|
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
|
||||||
|
|
@ -40,6 +41,7 @@ public:
|
||||||
std::shared_ptr<WireguardConfigurator> wireguardConfigurator;
|
std::shared_ptr<WireguardConfigurator> wireguardConfigurator;
|
||||||
std::shared_ptr<Ikev2Configurator> ikev2Configurator;
|
std::shared_ptr<Ikev2Configurator> ikev2Configurator;
|
||||||
std::shared_ptr<SshConfigurator> sshConfigurator;
|
std::shared_ptr<SshConfigurator> sshConfigurator;
|
||||||
|
std::shared_ptr<AwgConfigurator> awgConfigurator;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VPN_CONFIGURATOR_H
|
#endif // VPN_CONFIGURATOR_H
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,38 @@
|
||||||
#include "wireguard_configurator.h"
|
#include "wireguard_configurator.h"
|
||||||
#include <QApplication>
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QJsonDocument>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
#include <QDebug>
|
|
||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
#include <QJsonDocument>
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <openssl/pem.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/pem.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "containers/containers_defs.h"
|
#include "containers/containers_defs.h"
|
||||||
#include "core/server_defs.h"
|
|
||||||
#include "core/scripts_registry.h"
|
#include "core/scripts_registry.h"
|
||||||
#include "utilities.h"
|
#include "core/server_defs.h"
|
||||||
#include "core/servercontroller.h"
|
#include "core/servercontroller.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
|
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, bool isAwg, QObject *parent)
|
||||||
ConfiguratorBase(settings, parent)
|
: ConfiguratorBase(settings, parent), m_isAwg(isAwg)
|
||||||
{
|
{
|
||||||
|
m_serverConfigPath = m_isAwg ? amnezia::protocols::awg::serverConfigPath
|
||||||
|
: amnezia::protocols::wireguard::serverConfigPath;
|
||||||
|
m_serverPublicKeyPath = m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath
|
||||||
|
: amnezia::protocols::wireguard::serverPublicKeyPath;
|
||||||
|
m_serverPskKeyPath = m_isAwg ? amnezia::protocols::awg::serverPskKeyPath
|
||||||
|
: amnezia::protocols::wireguard::serverPskKeyPath;
|
||||||
|
m_configTemplate = m_isAwg ? ProtocolScriptType::awg_template
|
||||||
|
: ProtocolScriptType::wireguard_template;
|
||||||
|
|
||||||
|
m_protocolName = m_isAwg ? config_key::awg : config_key::wireguard;
|
||||||
|
m_defaultPort = m_isAwg ? protocols::wireguard::defaultPort : protocols::awg::defaultPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
|
WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
|
||||||
|
|
@ -36,37 +44,40 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
|
||||||
|
|
||||||
unsigned char buff[EDDSA_KEY_LENGTH];
|
unsigned char buff[EDDSA_KEY_LENGTH];
|
||||||
int ret = RAND_priv_bytes(buff, EDDSA_KEY_LENGTH);
|
int ret = RAND_priv_bytes(buff, EDDSA_KEY_LENGTH);
|
||||||
if (ret <=0) return connData;
|
if (ret <= 0)
|
||||||
|
return connData;
|
||||||
|
|
||||||
EVP_PKEY * pKey = EVP_PKEY_new();
|
EVP_PKEY *pKey = EVP_PKEY_new();
|
||||||
q_check_ptr(pKey);
|
q_check_ptr(pKey);
|
||||||
pKey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, &buff[0], EDDSA_KEY_LENGTH);
|
pKey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, &buff[0], EDDSA_KEY_LENGTH);
|
||||||
|
|
||||||
|
|
||||||
size_t keySize = EDDSA_KEY_LENGTH;
|
size_t keySize = EDDSA_KEY_LENGTH;
|
||||||
|
|
||||||
// save private key
|
// save private key
|
||||||
unsigned char priv[EDDSA_KEY_LENGTH];
|
unsigned char priv[EDDSA_KEY_LENGTH];
|
||||||
EVP_PKEY_get_raw_private_key(pKey, priv, &keySize);
|
EVP_PKEY_get_raw_private_key(pKey, priv, &keySize);
|
||||||
connData.clientPrivKey = QByteArray::fromRawData((char*)priv, keySize).toBase64();
|
connData.clientPrivKey = QByteArray::fromRawData((char *)priv, keySize).toBase64();
|
||||||
|
|
||||||
// save public key
|
// save public key
|
||||||
unsigned char pub[EDDSA_KEY_LENGTH];
|
unsigned char pub[EDDSA_KEY_LENGTH];
|
||||||
EVP_PKEY_get_raw_public_key(pKey, pub, &keySize);
|
EVP_PKEY_get_raw_public_key(pKey, pub, &keySize);
|
||||||
connData.clientPubKey = QByteArray::fromRawData((char*)pub, keySize).toBase64();
|
connData.clientPubKey = QByteArray::fromRawData((char *)pub, keySize).toBase64();
|
||||||
|
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardConfig(const ServerCredentials &credentials,
|
WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardConfig(const ServerCredentials &credentials,
|
||||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
|
DockerContainer container,
|
||||||
|
const QJsonObject &containerConfig,
|
||||||
|
ErrorCode *errorCode)
|
||||||
{
|
{
|
||||||
WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys();
|
WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys();
|
||||||
connData.host = credentials.hostName;
|
connData.host = credentials.hostName;
|
||||||
connData.port = containerConfig.value(config_key::port).toString(protocols::wireguard::defaultPort);
|
connData.port = containerConfig.value(m_protocolName).toObject().value(config_key::port).toString(m_defaultPort);
|
||||||
|
|
||||||
if (connData.clientPrivKey.isEmpty() || connData.clientPubKey.isEmpty()) {
|
if (connData.clientPrivKey.isEmpty() || connData.clientPubKey.isEmpty()) {
|
||||||
if (errorCode) *errorCode = ErrorCode::InternalError;
|
if (errorCode)
|
||||||
|
*errorCode = ErrorCode::InternalError;
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,7 +87,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
||||||
// Get list of already created clients (only IP addresses)
|
// Get list of already created clients (only IP addresses)
|
||||||
QString nextIpNumber;
|
QString nextIpNumber;
|
||||||
{
|
{
|
||||||
QString script = QString("cat %1 | grep AllowedIPs").arg(amnezia::protocols::wireguard::serverConfigPath);
|
QString script = QString("cat %1 | grep AllowedIPs").arg(m_serverConfigPath);
|
||||||
QString stdOut;
|
QString stdOut;
|
||||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||||
stdOut += data + "\n";
|
stdOut += data + "\n";
|
||||||
|
|
@ -96,22 +107,24 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
||||||
// Calc next IP address
|
// Calc next IP address
|
||||||
if (ips.isEmpty()) {
|
if (ips.isEmpty()) {
|
||||||
nextIpNumber = "2";
|
nextIpNumber = "2";
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
int next = ips.last().split(".").last().toInt() + 1;
|
int next = ips.last().split(".").last().toInt() + 1;
|
||||||
if (next > 254) {
|
if (next > 254) {
|
||||||
if (errorCode) *errorCode = ErrorCode::AddressPoolError;
|
if (errorCode)
|
||||||
|
*errorCode = ErrorCode::AddressPoolError;
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
nextIpNumber = QString::number(next);
|
nextIpNumber = QString::number(next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString subnetIp = containerConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
|
QString subnetIp =
|
||||||
|
containerConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
|
||||||
{
|
{
|
||||||
QStringList l = subnetIp.split(".", Qt::SkipEmptyParts);
|
QStringList l = subnetIp.split(".", Qt::SkipEmptyParts);
|
||||||
if (l.isEmpty()) {
|
if (l.isEmpty()) {
|
||||||
if (errorCode) *errorCode = ErrorCode::AddressPoolError;
|
if (errorCode)
|
||||||
|
*errorCode = ErrorCode::AddressPoolError;
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
l.removeLast();
|
l.removeLast();
|
||||||
|
|
@ -121,52 +134,55 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get keys
|
// Get keys
|
||||||
connData.serverPubKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPublicKeyPath, &e);
|
connData.serverPubKey = serverController.getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, &e);
|
||||||
connData.serverPubKey.replace("\n", "");
|
connData.serverPubKey.replace("\n", "");
|
||||||
if (e) {
|
if (e) {
|
||||||
if (errorCode) *errorCode = e;
|
if (errorCode)
|
||||||
|
*errorCode = e;
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
connData.pskKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPskKeyPath, &e);
|
connData.pskKey = serverController.getTextFileFromContainer(container, credentials, m_serverPskKeyPath, &e);
|
||||||
connData.pskKey.replace("\n", "");
|
connData.pskKey.replace("\n", "");
|
||||||
|
|
||||||
if (e) {
|
if (e) {
|
||||||
if (errorCode) *errorCode = e;
|
if (errorCode)
|
||||||
|
*errorCode = e;
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add client to config
|
// Add client to config
|
||||||
QString configPart = QString(
|
QString configPart = QString("[Peer]\n"
|
||||||
"[Peer]\n"
|
"PublicKey = %1\n"
|
||||||
"PublicKey = %1\n"
|
"PresharedKey = %2\n"
|
||||||
"PresharedKey = %2\n"
|
"AllowedIPs = %3/32\n\n")
|
||||||
"AllowedIPs = %3/32\n\n").
|
.arg(connData.clientPubKey, connData.pskKey, connData.clientIP);
|
||||||
arg(connData.clientPubKey).
|
|
||||||
arg(connData.pskKey).
|
|
||||||
arg(connData.clientIP);
|
|
||||||
|
|
||||||
e = serverController.uploadTextFileToContainer(container, credentials, configPart,
|
e = serverController.uploadTextFileToContainer(container, credentials, configPart, m_serverConfigPath,
|
||||||
protocols::wireguard::serverConfigPath, libssh::SftpOverwriteMode::SftpAppendToExisting);
|
libssh::SftpOverwriteMode::SftpAppendToExisting);
|
||||||
|
|
||||||
if (e) {
|
if (e) {
|
||||||
if (errorCode) *errorCode = e;
|
if (errorCode)
|
||||||
|
*errorCode = e;
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = serverController.runScript(credentials,
|
QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'")
|
||||||
serverController.replaceVars("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip /opt/amnezia/wireguard/wg0.conf)'",
|
.arg(m_serverConfigPath);
|
||||||
serverController.genVarsForScript(credentials, container)));
|
|
||||||
|
e = serverController.runScript(
|
||||||
|
credentials, serverController.replaceVars(script, serverController.genVarsForScript(credentials, container)));
|
||||||
|
|
||||||
return connData;
|
return connData;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials,
|
QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
|
const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||||
{
|
{
|
||||||
ServerController serverController(m_settings);
|
ServerController serverController(m_settings);
|
||||||
QString config = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::wireguard_template, container),
|
QString scriptData = amnezia::scriptData(m_configTemplate, container);
|
||||||
serverController.genVarsForScript(credentials, container, containerConfig));
|
QString config = serverController.replaceVars(
|
||||||
|
scriptData, serverController.genVarsForScript(credentials, container, containerConfig));
|
||||||
|
|
||||||
ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode);
|
ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode);
|
||||||
if (errorCode && *errorCode) {
|
if (errorCode && *errorCode) {
|
||||||
|
|
|
||||||
|
|
@ -6,35 +6,44 @@
|
||||||
|
|
||||||
#include "configurator_base.h"
|
#include "configurator_base.h"
|
||||||
#include "core/defs.h"
|
#include "core/defs.h"
|
||||||
|
#include "core/scripts_registry.h"
|
||||||
|
|
||||||
class WireguardConfigurator : ConfiguratorBase
|
class WireguardConfigurator : public ConfiguratorBase
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
WireguardConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
WireguardConfigurator(std::shared_ptr<Settings> settings, bool isAwg, QObject *parent = nullptr);
|
||||||
|
|
||||||
struct ConnectionData {
|
struct ConnectionData
|
||||||
|
{
|
||||||
QString clientPrivKey; // client private key
|
QString clientPrivKey; // client private key
|
||||||
QString clientPubKey; // client public key
|
QString clientPubKey; // client public key
|
||||||
QString clientIP; // internal client IP address
|
QString clientIP; // internal client IP address
|
||||||
QString serverPubKey; // tls-auth key
|
QString serverPubKey; // tls-auth key
|
||||||
QString pskKey; // preshared key
|
QString pskKey; // preshared key
|
||||||
QString host; // host ip
|
QString host; // host ip
|
||||||
QString port;
|
QString port;
|
||||||
};
|
};
|
||||||
|
|
||||||
QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
|
QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||||
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||||
|
|
||||||
QString processConfigWithLocalSettings(QString config);
|
QString processConfigWithLocalSettings(QString config);
|
||||||
QString processConfigWithExportSettings(QString config);
|
QString processConfigWithExportSettings(QString config);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials,
|
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||||
|
|
||||||
ConnectionData genClientKeys();
|
ConnectionData genClientKeys();
|
||||||
|
|
||||||
|
bool m_isAwg;
|
||||||
|
QString m_serverConfigPath;
|
||||||
|
QString m_serverPublicKeyPath;
|
||||||
|
QString m_serverPskKeyPath;
|
||||||
|
amnezia::ProtocolScriptType m_configTemplate;
|
||||||
|
QString m_protocolName;
|
||||||
|
QString m_defaultPort;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WIREGUARD_CONFIGURATOR_H
|
#endif // WIREGUARD_CONFIGURATOR_H
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,23 @@ QDebug operator<<(QDebug debug, const amnezia::DockerContainer &c)
|
||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
amnezia::DockerContainer ContainerProps::containerFromString(const QString &container){
|
amnezia::DockerContainer ContainerProps::containerFromString(const QString &container)
|
||||||
|
{
|
||||||
QMetaEnum metaEnum = QMetaEnum::fromType<DockerContainer>();
|
QMetaEnum metaEnum = QMetaEnum::fromType<DockerContainer>();
|
||||||
for (int i = 0; i < metaEnum.keyCount(); ++i) {
|
for (int i = 0; i < metaEnum.keyCount(); ++i) {
|
||||||
DockerContainer c = static_cast<DockerContainer>(i);
|
DockerContainer c = static_cast<DockerContainer>(i);
|
||||||
if (container == containerToString(c)) return c;
|
if (container == containerToString(c))
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
return DockerContainer::None;
|
return DockerContainer::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ContainerProps::containerToString(amnezia::DockerContainer c){
|
QString ContainerProps::containerToString(amnezia::DockerContainer c)
|
||||||
if (c == DockerContainer::None) return "none";
|
{
|
||||||
if (c == DockerContainer::Cloak) return "amnezia-openvpn-cloak";
|
if (c == DockerContainer::None)
|
||||||
|
return "none";
|
||||||
|
if (c == DockerContainer::Cloak)
|
||||||
|
return "amnezia-openvpn-cloak";
|
||||||
|
|
||||||
QMetaEnum metaEnum = QMetaEnum::fromType<DockerContainer>();
|
QMetaEnum metaEnum = QMetaEnum::fromType<DockerContainer>();
|
||||||
QString containerKey = metaEnum.valueToKey(static_cast<int>(c));
|
QString containerKey = metaEnum.valueToKey(static_cast<int>(c));
|
||||||
|
|
@ -27,9 +32,12 @@ QString ContainerProps::containerToString(amnezia::DockerContainer c){
|
||||||
return "amnezia-" + containerKey.toLower();
|
return "amnezia-" + containerKey.toLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ContainerProps::containerTypeToString(amnezia::DockerContainer c){
|
QString ContainerProps::containerTypeToString(amnezia::DockerContainer c)
|
||||||
if (c == DockerContainer::None) return "none";
|
{
|
||||||
if (c == DockerContainer::Ipsec) return "ikev2";
|
if (c == DockerContainer::None)
|
||||||
|
return "none";
|
||||||
|
if (c == DockerContainer::Ipsec)
|
||||||
|
return "ikev2";
|
||||||
|
|
||||||
QMetaEnum metaEnum = QMetaEnum::fromType<DockerContainer>();
|
QMetaEnum metaEnum = QMetaEnum::fromType<DockerContainer>();
|
||||||
QString containerKey = metaEnum.valueToKey(static_cast<int>(c));
|
QString containerKey = metaEnum.valueToKey(static_cast<int>(c));
|
||||||
|
|
@ -40,29 +48,21 @@ QString ContainerProps::containerTypeToString(amnezia::DockerContainer c){
|
||||||
QVector<amnezia::Proto> ContainerProps::protocolsForContainer(amnezia::DockerContainer container)
|
QVector<amnezia::Proto> ContainerProps::protocolsForContainer(amnezia::DockerContainer container)
|
||||||
{
|
{
|
||||||
switch (container) {
|
switch (container) {
|
||||||
case DockerContainer::None:
|
case DockerContainer::None: return {};
|
||||||
return { };
|
|
||||||
|
|
||||||
case DockerContainer::OpenVpn:
|
case DockerContainer::OpenVpn: return { Proto::OpenVpn };
|
||||||
return { Proto::OpenVpn };
|
|
||||||
|
|
||||||
case DockerContainer::ShadowSocks:
|
case DockerContainer::ShadowSocks: return { Proto::OpenVpn, Proto::ShadowSocks };
|
||||||
return { Proto::OpenVpn, Proto::ShadowSocks };
|
|
||||||
|
|
||||||
case DockerContainer::Cloak:
|
case DockerContainer::Cloak: return { Proto::OpenVpn, Proto::ShadowSocks, Proto::Cloak };
|
||||||
return { Proto::OpenVpn, Proto::ShadowSocks, Proto::Cloak };
|
|
||||||
|
|
||||||
case DockerContainer::Ipsec:
|
case DockerContainer::Ipsec: return { Proto::Ikev2 /*, Protocol::L2tp */ };
|
||||||
return { Proto::Ikev2 /*, Protocol::L2tp */};
|
|
||||||
|
|
||||||
case DockerContainer::Dns:
|
case DockerContainer::Dns: return {};
|
||||||
return { };
|
|
||||||
|
|
||||||
case DockerContainer::Sftp:
|
case DockerContainer::Sftp: return { Proto::Sftp };
|
||||||
return { Proto::Sftp};
|
|
||||||
|
|
||||||
default:
|
default: return { defaultProtocol(container) };
|
||||||
return { defaultProtocol(container) };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,70 +79,164 @@ QList<DockerContainer> ContainerProps::allContainers()
|
||||||
|
|
||||||
QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
|
QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
|
||||||
{
|
{
|
||||||
return {
|
return { { DockerContainer::None, "Not installed" },
|
||||||
{DockerContainer::None, "Not installed"},
|
{ DockerContainer::OpenVpn, "OpenVPN" },
|
||||||
{DockerContainer::OpenVpn, "OpenVPN"},
|
{ DockerContainer::ShadowSocks, "ShadowSocks" },
|
||||||
{DockerContainer::ShadowSocks, "OpenVpn over ShadowSocks"},
|
{ DockerContainer::Cloak, "OpenVPN over Cloak" },
|
||||||
{DockerContainer::Cloak, "OpenVpn over Cloak"},
|
{ DockerContainer::WireGuard, "WireGuard" },
|
||||||
{DockerContainer::WireGuard, "WireGuard"},
|
{ DockerContainer::Awg, "AmneziaWG" },
|
||||||
{DockerContainer::Ipsec, QObject::tr("IPsec")},
|
{ DockerContainer::Ipsec, QObject::tr("IPsec") },
|
||||||
|
|
||||||
{DockerContainer::TorWebSite, QObject::tr("Web site in Tor network")},
|
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
|
||||||
{DockerContainer::Dns, QObject::tr("DNS Service")},
|
{ DockerContainer::Dns, QObject::tr("Amnezia DNS") },
|
||||||
//{DockerContainer::FileShare, QObject::tr("SMB file sharing service")},
|
{ DockerContainer::Sftp, QObject::tr("Sftp file sharing service") } };
|
||||||
{DockerContainer::Sftp, QObject::tr("Sftp file sharing service")}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
|
QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
|
||||||
{
|
{
|
||||||
return {
|
return { { DockerContainer::OpenVpn,
|
||||||
{DockerContainer::OpenVpn, QObject::tr("OpenVPN container")},
|
QObject::tr("OpenVPN is the most popular VPN protocol, with flexible configuration options. It uses its "
|
||||||
{DockerContainer::ShadowSocks, QObject::tr("Container with OpenVpn and ShadowSocks")},
|
"own security protocol with SSL/TLS for key exchange.") },
|
||||||
{DockerContainer::Cloak, QObject::tr("Container with OpenVpn and ShadowSocks protocols "
|
{ DockerContainer::ShadowSocks,
|
||||||
"configured with traffic masking by Cloak plugin")},
|
QObject::tr("ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but is "
|
||||||
{DockerContainer::WireGuard, QObject::tr("WireGuard container")},
|
"recognised by analysis systems in some highly censored regions.") },
|
||||||
{DockerContainer::Ipsec, QObject::tr("IPsec container")},
|
{ DockerContainer::Cloak,
|
||||||
|
QObject::tr("OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against "
|
||||||
|
"active-probbing detection. Ideal for bypassing blocking in regions with the highest levels "
|
||||||
|
"of censorship.") },
|
||||||
|
{ DockerContainer::WireGuard,
|
||||||
|
QObject::tr("WireGuard - New popular VPN protocol with high performance, high speed and low power "
|
||||||
|
"consumption. Recommended for regions with low levels of censorship.") },
|
||||||
|
{ DockerContainer::Awg,
|
||||||
|
QObject::tr("AmneziaWG - Special protocol from Amnezia, based on WireGuard. It's fast like WireGuard, "
|
||||||
|
"but very resistant to blockages. "
|
||||||
|
"Recommended for regions with high levels of censorship.") },
|
||||||
|
{ DockerContainer::Ipsec,
|
||||||
|
QObject::tr("IKEv2 - Modern stable protocol, a bit faster than others, restores connection after "
|
||||||
|
"signal loss. It has native support on the latest versions of Android and iOS.") },
|
||||||
|
|
||||||
{DockerContainer::TorWebSite, QObject::tr("Web site in Tor network")},
|
{ DockerContainer::TorWebSite, QObject::tr("Deploy a WordPress site on the Tor network in two clicks.") },
|
||||||
{DockerContainer::Dns, QObject::tr("DNS Service")},
|
{ DockerContainer::Dns,
|
||||||
//{DockerContainer::FileShare, QObject::tr("SMB file sharing service - is Window file sharing protocol")},
|
QObject::tr("Replace the current DNS server with your own. This will increase your privacy level.") },
|
||||||
{DockerContainer::Sftp, QObject::tr("Sftp file sharing service - is secure FTP service")}
|
{ DockerContainer::Sftp,
|
||||||
|
QObject::tr("Creates a file vault on your server to securely store and transfer files.") } };
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
{ DockerContainer::OpenVpn,
|
||||||
|
QObject::tr(
|
||||||
|
"OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
|
||||||
|
"It employs its unique security protocol, "
|
||||||
|
"leveraging the strength of SSL/TLS for encryption and key exchange. "
|
||||||
|
"Furthermore, OpenVPN's support for a multitude of authentication methods makes it versatile and adaptable, "
|
||||||
|
"catering to a wide range of devices and operating systems. "
|
||||||
|
"Due to its open-source nature, OpenVPN benefits from extensive scrutiny by the global community, "
|
||||||
|
"which continually reinforces its security. "
|
||||||
|
"With a strong balance of performance, security, and compatibility, "
|
||||||
|
"OpenVPN remains a top choice for privacy-conscious individuals and businesses alike.\n\n"
|
||||||
|
"* Available in the AmneziaVPN across all platforms\n"
|
||||||
|
"* Normal power consumption on mobile devices\n"
|
||||||
|
"* Flexible customisation to suit user needs to work with different operating systems and devices\n"
|
||||||
|
"* Recognised by DPI analysis systems and therefore susceptible to blocking\n"
|
||||||
|
"* Can operate over both TCP and UDP network protocols.") },
|
||||||
|
{ DockerContainer::ShadowSocks,
|
||||||
|
QObject::tr("Shadowsocks, inspired by the SOCKS5 protocol, safeguards the connection using the AEAD cipher. "
|
||||||
|
"Although Shadowsocks is designed to be discreet and challenging to identify, it isn't identical to a standard HTTPS connection."
|
||||||
|
"However, certain traffic analysis systems might still detect a Shadowsocks connection. "
|
||||||
|
"Due to limited support in Amnezia, it's recommended to use AmneziaWG protocol.\n\n"
|
||||||
|
"* Available in the AmneziaVPN only on desktop platforms\n"
|
||||||
|
"* Normal power consumption on mobile devices\n\n"
|
||||||
|
"* Configurable encryption protocol\n"
|
||||||
|
"* Detectable by some DPI systems\n"
|
||||||
|
"* Works over TCP network protocol.") },
|
||||||
|
{ DockerContainer::Cloak,
|
||||||
|
QObject::tr("This is a combination of the OpenVPN protocol and the Cloak plugin designed specifically for "
|
||||||
|
"blocking protection.\n\n"
|
||||||
|
"OpenVPN provides a secure VPN connection by encrypting all Internet traffic between the client "
|
||||||
|
"and the server.\n\n"
|
||||||
|
"Cloak protects OpenVPN from detection and blocking. \n\n"
|
||||||
|
"Cloak can modify packet metadata so that it completely masks VPN traffic as normal web traffic, "
|
||||||
|
"and also protects the VPN from detection by Active Probing. This makes it very resistant to "
|
||||||
|
"being detected\n\n"
|
||||||
|
"Immediately after receiving the first data packet, Cloak authenticates the incoming connection. "
|
||||||
|
"If authentication fails, the plugin masks the server as a fake website and your VPN becomes "
|
||||||
|
"invisible to analysis systems.\n\n"
|
||||||
|
"If there is a extreme level of Internet censorship in your region, we advise you to use only "
|
||||||
|
"OpenVPN over Cloak from the first connection\n\n"
|
||||||
|
"* Available in the AmneziaVPN across all platforms\n"
|
||||||
|
"* High power consumption on mobile devices\n"
|
||||||
|
"* Flexible settings\n"
|
||||||
|
"* Not recognised by DPI analysis systems\n"
|
||||||
|
"* Works over TCP network protocol, 443 port.\n") },
|
||||||
|
{ DockerContainer::WireGuard,
|
||||||
|
QObject::tr("A relatively new popular VPN protocol with a simplified architecture.\n"
|
||||||
|
"Provides stable VPN connection, high performance on all devices. Uses hard-coded encryption "
|
||||||
|
"settings. WireGuard compared to OpenVPN has lower latency and better data transfer throughput.\n"
|
||||||
|
"WireGuard is very susceptible to blocking due to its distinct packet signatures. "
|
||||||
|
"Unlike some other VPN protocols that employ obfuscation techniques, "
|
||||||
|
"the consistent signature patterns of WireGuard packets can be more easily identified and "
|
||||||
|
"thus blocked by advanced Deep Packet Inspection (DPI) systems and other network monitoring tools.\n\n"
|
||||||
|
"* Available in the AmneziaVPN across all platforms\n"
|
||||||
|
"* Low power consumption\n"
|
||||||
|
"* Minimum number of settings\n"
|
||||||
|
"* Easily recognised by DPI analysis systems, susceptible to blocking\n"
|
||||||
|
"* Works over UDP network protocol.") },
|
||||||
|
{ DockerContainer::Awg,
|
||||||
|
QObject::tr("A modern iteration of the popular VPN protocol, "
|
||||||
|
"AmneziaWG builds upon the foundation set by WireGuard, "
|
||||||
|
"retaining its simplified architecture and high-performance capabilities across devices.\n"
|
||||||
|
"While WireGuard is known for its efficiency, "
|
||||||
|
"it had issues with being easily detected due to its distinct packet signatures. "
|
||||||
|
"AmneziaWG solves this problem by using better obfuscation methods, "
|
||||||
|
"making its traffic blend in with regular internet traffic.\n"
|
||||||
|
"This means that AmneziaWG keeps the fast performance of the original "
|
||||||
|
"while adding an extra layer of stealth, "
|
||||||
|
"making it a great choice for those wanting a fast and discreet VPN connection.\n\n"
|
||||||
|
"* Available in the AmneziaVPN across all platforms\n"
|
||||||
|
"* Low power consumption\n"
|
||||||
|
"* Minimum number of settings\n"
|
||||||
|
"* Not recognised by DPI analysis systems, resistant to blocking\n"
|
||||||
|
"* Works over UDP network protocol.") },
|
||||||
|
{ DockerContainer::Ipsec,
|
||||||
|
QObject::tr("IKEv2, paired with the IPSec encryption layer, stands as a modern and stable VPN protocol.\n"
|
||||||
|
"One of its distinguishing features is its ability to swiftly switch between networks and devices, "
|
||||||
|
"making it particularly adaptive in dynamic network environments. \n"
|
||||||
|
"While it offers a blend of security, stability, and speed, "
|
||||||
|
"it's essential to note that IKEv2 can be easily detected and is susceptible to blocking.\n\n"
|
||||||
|
"* Available in the AmneziaVPN only on Windows\n"
|
||||||
|
"* Low power consumption, on mobile devices\n"
|
||||||
|
"* Minimal configuration\n"
|
||||||
|
"* Recognised by DPI analysis systems\n"
|
||||||
|
"* Works over UDP network protocol, ports 500 and 4500.") },
|
||||||
|
|
||||||
|
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
|
||||||
|
{ DockerContainer::Dns, QObject::tr("DNS Service") },
|
||||||
|
{ DockerContainer::Sftp, QObject::tr("Sftp file sharing service - is secure FTP service") }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
amnezia::ServiceType ContainerProps::containerService(DockerContainer c)
|
amnezia::ServiceType ContainerProps::containerService(DockerContainer c)
|
||||||
{
|
{
|
||||||
switch (c) {
|
return ProtocolProps::protocolService(defaultProtocol(c));
|
||||||
case DockerContainer::None : return ServiceType::None;
|
|
||||||
case DockerContainer::OpenVpn : return ServiceType::Vpn;
|
|
||||||
case DockerContainer::Cloak : return ServiceType::Vpn;
|
|
||||||
case DockerContainer::ShadowSocks : return ServiceType::Vpn;
|
|
||||||
case DockerContainer::WireGuard : return ServiceType::Vpn;
|
|
||||||
case DockerContainer::Ipsec : return ServiceType::Vpn;
|
|
||||||
case DockerContainer::TorWebSite : return ServiceType::Other;
|
|
||||||
case DockerContainer::Dns : return ServiceType::Other;
|
|
||||||
//case DockerContainer::FileShare : return ServiceType::Other;
|
|
||||||
case DockerContainer::Sftp : return ServiceType::Other;
|
|
||||||
default: return ServiceType::Other;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Proto ContainerProps::defaultProtocol(DockerContainer c)
|
Proto ContainerProps::defaultProtocol(DockerContainer c)
|
||||||
{
|
{
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case DockerContainer::None : return Proto::Any;
|
case DockerContainer::None: return Proto::Any;
|
||||||
case DockerContainer::OpenVpn : return Proto::OpenVpn;
|
case DockerContainer::OpenVpn: return Proto::OpenVpn;
|
||||||
case DockerContainer::Cloak : return Proto::Cloak;
|
case DockerContainer::Cloak: return Proto::Cloak;
|
||||||
case DockerContainer::ShadowSocks : return Proto::ShadowSocks;
|
case DockerContainer::ShadowSocks: return Proto::ShadowSocks;
|
||||||
case DockerContainer::WireGuard : return Proto::WireGuard;
|
case DockerContainer::WireGuard: return Proto::WireGuard;
|
||||||
case DockerContainer::Ipsec : return Proto::Ikev2;
|
case DockerContainer::Awg: return Proto::Awg;
|
||||||
|
case DockerContainer::Ipsec: return Proto::Ikev2;
|
||||||
|
|
||||||
case DockerContainer::TorWebSite : return Proto::TorWebSite;
|
case DockerContainer::TorWebSite: return Proto::TorWebSite;
|
||||||
case DockerContainer::Dns : return Proto::Dns;
|
case DockerContainer::Dns: return Proto::Dns;
|
||||||
//case DockerContainer::FileShare : return Protocol::FileShare;
|
case DockerContainer::Sftp: return Proto::Sftp;
|
||||||
case DockerContainer::Sftp : return Proto::Sftp;
|
default: return Proto::Any;
|
||||||
default: return Proto::Any;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,31 +245,34 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
#elif defined (Q_OS_IOS)
|
#elif defined(Q_OS_IOS)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case DockerContainer::WireGuard: return true;
|
case DockerContainer::WireGuard: return true;
|
||||||
case DockerContainer::OpenVpn: return true;
|
case DockerContainer::OpenVpn: return true;
|
||||||
case DockerContainer::Cloak: return true;
|
case DockerContainer::Awg: return true;
|
||||||
// case DockerContainer::ShadowSocks: return true;
|
case DockerContainer::Cloak:
|
||||||
|
return true;
|
||||||
|
// case DockerContainer::ShadowSocks: return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
#elif defined (Q_OS_MAC)
|
#elif defined(Q_OS_MAC)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case DockerContainer::WireGuard: return true;
|
case DockerContainer::WireGuard: return true;
|
||||||
case DockerContainer::Ipsec: return false;
|
case DockerContainer::Ipsec: return false;
|
||||||
default: return true;
|
default: return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined (Q_OS_ANDROID)
|
#elif defined(Q_OS_ANDROID)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case DockerContainer::WireGuard: return true;
|
case DockerContainer::WireGuard: return true;
|
||||||
case DockerContainer::OpenVpn: return true;
|
case DockerContainer::OpenVpn: return true;
|
||||||
case DockerContainer::ShadowSocks: return true;
|
case DockerContainer::ShadowSocks: return true;
|
||||||
|
case DockerContainer::Awg: return true;
|
||||||
case DockerContainer::Cloak: return true;
|
case DockerContainer::Cloak: return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined (Q_OS_LINUX)
|
#elif defined(Q_OS_LINUX)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case DockerContainer::WireGuard: return true;
|
case DockerContainer::WireGuard: return true;
|
||||||
case DockerContainer::Ipsec: return false;
|
case DockerContainer::Ipsec: return false;
|
||||||
|
|
@ -183,14 +280,65 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ContainerProps::fixedPortsForContainer(DockerContainer c)
|
QStringList ContainerProps::fixedPortsForContainer(DockerContainer c)
|
||||||
{
|
{
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case DockerContainer::Ipsec : return QStringList{"500", "4500"};
|
case DockerContainer::Ipsec: return QStringList { "500", "4500" };
|
||||||
default: return {};
|
default: return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContainerProps::isEasySetupContainer(DockerContainer container)
|
||||||
|
{
|
||||||
|
switch (container) {
|
||||||
|
case DockerContainer::WireGuard: return true;
|
||||||
|
case DockerContainer::Awg: return true;
|
||||||
|
case DockerContainer::Cloak: return true;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ContainerProps::easySetupHeader(DockerContainer container)
|
||||||
|
{
|
||||||
|
switch (container) {
|
||||||
|
case DockerContainer::WireGuard: return tr("Low");
|
||||||
|
case DockerContainer::Awg: return tr("Medium or High");
|
||||||
|
case DockerContainer::Cloak: return tr("Extreme");
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ContainerProps::easySetupDescription(DockerContainer container)
|
||||||
|
{
|
||||||
|
switch (container) {
|
||||||
|
case DockerContainer::WireGuard: return tr("I just want to increase the level of my privacy.");
|
||||||
|
case DockerContainer::Awg: return tr("I want to bypass censorship. This option recommended in most cases.");
|
||||||
|
case DockerContainer::Cloak:
|
||||||
|
return tr("Most VPN protocols are blocked. Recommended if other options are not working.");
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ContainerProps::easySetupOrder(DockerContainer container)
|
||||||
|
{
|
||||||
|
switch (container) {
|
||||||
|
case DockerContainer::WireGuard: return 3;
|
||||||
|
case DockerContainer::Awg: return 2;
|
||||||
|
case DockerContainer::Cloak: return 1;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContainerProps::isShareable(DockerContainer container)
|
||||||
|
{
|
||||||
|
switch (container) {
|
||||||
|
case DockerContainer::TorWebSite: return false;
|
||||||
|
case DockerContainer::Dns: return false;
|
||||||
|
case DockerContainer::Sftp: return false;
|
||||||
|
default: return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,68 +8,72 @@
|
||||||
|
|
||||||
using namespace amnezia;
|
using namespace amnezia;
|
||||||
|
|
||||||
namespace amnezia {
|
namespace amnezia
|
||||||
|
|
||||||
namespace ContainerEnumNS {
|
|
||||||
Q_NAMESPACE
|
|
||||||
enum DockerContainer {
|
|
||||||
None = 0,
|
|
||||||
OpenVpn,
|
|
||||||
ShadowSocks,
|
|
||||||
Cloak,
|
|
||||||
WireGuard,
|
|
||||||
Ipsec,
|
|
||||||
|
|
||||||
//non-vpn
|
|
||||||
TorWebSite,
|
|
||||||
Dns,
|
|
||||||
//FileShare,
|
|
||||||
Sftp
|
|
||||||
};
|
|
||||||
Q_ENUM_NS(DockerContainer)
|
|
||||||
} // namespace ContainerEnumNS
|
|
||||||
|
|
||||||
using namespace ContainerEnumNS;
|
|
||||||
using namespace ProtocolEnumNS;
|
|
||||||
|
|
||||||
class ContainerProps : public QObject
|
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
namespace ContainerEnumNS
|
||||||
Q_INVOKABLE static amnezia::DockerContainer containerFromString(const QString &container);
|
{
|
||||||
Q_INVOKABLE static QString containerToString(amnezia::DockerContainer container);
|
Q_NAMESPACE
|
||||||
Q_INVOKABLE static QString containerTypeToString(amnezia::DockerContainer c);
|
enum DockerContainer {
|
||||||
|
None = 0,
|
||||||
|
Awg,
|
||||||
|
WireGuard,
|
||||||
|
OpenVpn,
|
||||||
|
Cloak,
|
||||||
|
ShadowSocks,
|
||||||
|
Ipsec,
|
||||||
|
|
||||||
Q_INVOKABLE static QList<amnezia::DockerContainer> allContainers();
|
// non-vpn
|
||||||
|
TorWebSite,
|
||||||
|
Dns,
|
||||||
|
Sftp
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(DockerContainer)
|
||||||
|
} // namespace ContainerEnumNS
|
||||||
|
|
||||||
Q_INVOKABLE static QMap<amnezia::DockerContainer, QString> containerHumanNames();
|
using namespace ContainerEnumNS;
|
||||||
Q_INVOKABLE static QMap<amnezia::DockerContainer, QString> containerDescriptions();
|
using namespace ProtocolEnumNS;
|
||||||
|
|
||||||
// these protocols will be displayed in container settings
|
class ContainerProps : public QObject
|
||||||
Q_INVOKABLE static QVector<amnezia::Proto> protocolsForContainer(amnezia::DockerContainer container);
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
Q_INVOKABLE static amnezia::ServiceType containerService(amnezia::DockerContainer c);
|
public:
|
||||||
|
Q_INVOKABLE static amnezia::DockerContainer containerFromString(const QString &container);
|
||||||
|
Q_INVOKABLE static QString containerToString(amnezia::DockerContainer container);
|
||||||
|
Q_INVOKABLE static QString containerTypeToString(amnezia::DockerContainer c);
|
||||||
|
|
||||||
// binding between Docker container and main protocol of given container
|
Q_INVOKABLE static QList<amnezia::DockerContainer> allContainers();
|
||||||
// it may be changed fot future containers :)
|
|
||||||
Q_INVOKABLE static amnezia::Proto defaultProtocol(amnezia::DockerContainer c);
|
|
||||||
|
|
||||||
Q_INVOKABLE static bool isSupportedByCurrentPlatform(amnezia::DockerContainer c);
|
Q_INVOKABLE static QMap<amnezia::DockerContainer, QString> containerHumanNames();
|
||||||
Q_INVOKABLE static QStringList fixedPortsForContainer(amnezia::DockerContainer c);
|
Q_INVOKABLE static QMap<amnezia::DockerContainer, QString> containerDescriptions();
|
||||||
};
|
Q_INVOKABLE static QMap<amnezia::DockerContainer, QString> containerDetailedDescriptions();
|
||||||
|
|
||||||
|
// these protocols will be displayed in container settings
|
||||||
|
Q_INVOKABLE static QVector<amnezia::Proto> protocolsForContainer(amnezia::DockerContainer container);
|
||||||
|
|
||||||
|
Q_INVOKABLE static amnezia::ServiceType containerService(amnezia::DockerContainer c);
|
||||||
|
|
||||||
static void declareQmlContainerEnum() {
|
// binding between Docker container and main protocol of given container
|
||||||
qmlRegisterUncreatableMetaObject(
|
// it may be changed fot future containers :)
|
||||||
ContainerEnumNS::staticMetaObject,
|
Q_INVOKABLE static amnezia::Proto defaultProtocol(amnezia::DockerContainer c);
|
||||||
"ContainerEnum",
|
|
||||||
1, 0,
|
Q_INVOKABLE static bool isSupportedByCurrentPlatform(amnezia::DockerContainer c);
|
||||||
"ContainerEnum",
|
Q_INVOKABLE static QStringList fixedPortsForContainer(amnezia::DockerContainer c);
|
||||||
"Error: only enums"
|
|
||||||
);
|
static bool isEasySetupContainer(amnezia::DockerContainer container);
|
||||||
}
|
static QString easySetupHeader(amnezia::DockerContainer container);
|
||||||
|
static QString easySetupDescription(amnezia::DockerContainer container);
|
||||||
|
static int easySetupOrder(amnezia::DockerContainer container);
|
||||||
|
|
||||||
|
static bool isShareable(amnezia::DockerContainer container);
|
||||||
|
};
|
||||||
|
|
||||||
|
static void declareQmlContainerEnum()
|
||||||
|
{
|
||||||
|
qmlRegisterUncreatableMetaObject(ContainerEnumNS::staticMetaObject, "ContainerEnum", 1, 0, "ContainerEnum",
|
||||||
|
"Error: only enums");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace amnezia
|
} // namespace amnezia
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@ struct ServerCredentials
|
||||||
{
|
{
|
||||||
QString hostName;
|
QString hostName;
|
||||||
QString userName;
|
QString userName;
|
||||||
QString password;
|
QString secretData;
|
||||||
int port = 22;
|
int port = 22;
|
||||||
|
|
||||||
bool isValid() const { return !hostName.isEmpty() && !userName.isEmpty() && !password.isEmpty() && port > 0; }
|
bool isValid() const { return !hostName.isEmpty() && !userName.isEmpty() && !secretData.isEmpty() && port > 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ErrorCode
|
enum ErrorCode
|
||||||
|
|
@ -37,7 +37,7 @@ enum ErrorCode
|
||||||
|
|
||||||
// Ssh connection errors
|
// Ssh connection errors
|
||||||
SshRequsetDeniedError, SshInterruptedError, SshInternalError,
|
SshRequsetDeniedError, SshInterruptedError, SshInternalError,
|
||||||
SshPrivateKeyError, SshPrivateKeyFormatError,
|
SshPrivateKeyError, SshPrivateKeyFormatError, SshTimeoutError,
|
||||||
|
|
||||||
// Ssh sftp errors
|
// Ssh sftp errors
|
||||||
SshSftpEofError, SshSftpNoSuchFileError, SshSftpPermissionDeniedError,
|
SshSftpEofError, SshSftpNoSuchFileError, SshSftpPermissionDeniedError,
|
||||||
|
|
@ -69,7 +69,10 @@ enum ErrorCode
|
||||||
OpenSslFailed,
|
OpenSslFailed,
|
||||||
OpenVpnExecutableCrashed,
|
OpenVpnExecutableCrashed,
|
||||||
ShadowSocksExecutableCrashed,
|
ShadowSocksExecutableCrashed,
|
||||||
CloakExecutableCrashed
|
CloakExecutableCrashed,
|
||||||
|
|
||||||
|
// import and install errors
|
||||||
|
ImportInvalidConfigError
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace amnezia
|
} // namespace amnezia
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ QString errorString(ErrorCode code){
|
||||||
case(SshInternalError): return QObject::tr("Ssh internal error");
|
case(SshInternalError): return QObject::tr("Ssh internal error");
|
||||||
case(SshPrivateKeyError): return QObject::tr("Invalid private key or invalid passphrase entered");
|
case(SshPrivateKeyError): return QObject::tr("Invalid private key or invalid passphrase entered");
|
||||||
case(SshPrivateKeyFormatError): return QObject::tr("The selected private key format is not supported, use openssh ED25519 key types or PEM key types");
|
case(SshPrivateKeyFormatError): return QObject::tr("The selected private key format is not supported, use openssh ED25519 key types or PEM key types");
|
||||||
|
case(SshTimeoutError): return QObject::tr("Timeout connecting to server");
|
||||||
|
|
||||||
// Libssh sftp errors
|
// Libssh sftp errors
|
||||||
case(SshSftpEofError): return QObject::tr("Sftp error: End-of-file encountered");
|
case(SshSftpEofError): return QObject::tr("Sftp error: End-of-file encountered");
|
||||||
|
|
@ -57,6 +58,8 @@ QString errorString(ErrorCode code){
|
||||||
case (OpenVpnTapAdapterError): return QObject::tr("Can't setup OpenVPN TAP network adapter");
|
case (OpenVpnTapAdapterError): return QObject::tr("Can't setup OpenVPN TAP network adapter");
|
||||||
case (AddressPoolError): return QObject::tr("VPN pool error: no available addresses");
|
case (AddressPoolError): return QObject::tr("VPN pool error: no available addresses");
|
||||||
|
|
||||||
|
case (ImportInvalidConfigError): return QObject::tr("The config does not contain any containers and credentiaks for connecting to the server");
|
||||||
|
|
||||||
case(InternalError):
|
case(InternalError):
|
||||||
default:
|
default:
|
||||||
return QObject::tr("Internal error");
|
return QObject::tr("Internal error");
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#include "scripts_registry.h"
|
#include "scripts_registry.h"
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
QString amnezia::scriptFolder(amnezia::DockerContainer container)
|
QString amnezia::scriptFolder(amnezia::DockerContainer container)
|
||||||
{
|
{
|
||||||
|
|
@ -11,11 +11,11 @@ QString amnezia::scriptFolder(amnezia::DockerContainer container)
|
||||||
case DockerContainer::Cloak: return QLatin1String("openvpn_cloak");
|
case DockerContainer::Cloak: return QLatin1String("openvpn_cloak");
|
||||||
case DockerContainer::ShadowSocks: return QLatin1String("openvpn_shadowsocks");
|
case DockerContainer::ShadowSocks: return QLatin1String("openvpn_shadowsocks");
|
||||||
case DockerContainer::WireGuard: return QLatin1String("wireguard");
|
case DockerContainer::WireGuard: return QLatin1String("wireguard");
|
||||||
|
case DockerContainer::Awg: return QLatin1String("awg");
|
||||||
case DockerContainer::Ipsec: return QLatin1String("ipsec");
|
case DockerContainer::Ipsec: return QLatin1String("ipsec");
|
||||||
|
|
||||||
case DockerContainer::TorWebSite: return QLatin1String("website_tor");
|
case DockerContainer::TorWebSite: return QLatin1String("website_tor");
|
||||||
case DockerContainer::Dns: return QLatin1String("dns");
|
case DockerContainer::Dns: return QLatin1String("dns");
|
||||||
//case DockerContainer::FileShare: return QLatin1String("file_share");
|
|
||||||
case DockerContainer::Sftp: return QLatin1String("sftp");
|
case DockerContainer::Sftp: return QLatin1String("sftp");
|
||||||
default: return "";
|
default: return "";
|
||||||
}
|
}
|
||||||
|
|
@ -45,6 +45,7 @@ QString amnezia::scriptName(ProtocolScriptType type)
|
||||||
case ProtocolScriptType::container_startup: return QLatin1String("start.sh");
|
case ProtocolScriptType::container_startup: return QLatin1String("start.sh");
|
||||||
case ProtocolScriptType::openvpn_template: return QLatin1String("template.ovpn");
|
case ProtocolScriptType::openvpn_template: return QLatin1String("template.ovpn");
|
||||||
case ProtocolScriptType::wireguard_template: return QLatin1String("template.conf");
|
case ProtocolScriptType::wireguard_template: return QLatin1String("template.conf");
|
||||||
|
case ProtocolScriptType::awg_template: return QLatin1String("template.conf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,7 +53,7 @@ QString amnezia::scriptData(amnezia::SharedScriptType type)
|
||||||
{
|
{
|
||||||
QString fileName = QString(":/server_scripts/%1").arg(amnezia::scriptName(type));
|
QString fileName = QString(":/server_scripts/%1").arg(amnezia::scriptName(type));
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
if (! file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
qDebug() << "Warning: script missing" << fileName;
|
qDebug() << "Warning: script missing" << fileName;
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +68,7 @@ QString amnezia::scriptData(amnezia::ProtocolScriptType type, DockerContainer co
|
||||||
{
|
{
|
||||||
QString fileName = QString(":/server_scripts/%1/%2").arg(amnezia::scriptFolder(container), amnezia::scriptName(type));
|
QString fileName = QString(":/server_scripts/%1/%2").arg(amnezia::scriptFolder(container), amnezia::scriptName(type));
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
if (! file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
qDebug() << "Warning: script missing" << fileName;
|
qDebug() << "Warning: script missing" << fileName;
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@ enum ProtocolScriptType {
|
||||||
configure_container,
|
configure_container,
|
||||||
container_startup,
|
container_startup,
|
||||||
openvpn_template,
|
openvpn_template,
|
||||||
wireguard_template
|
wireguard_template,
|
||||||
|
awg_template
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,21 @@
|
||||||
|
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFile>
|
|
||||||
#include <QEventLoop>
|
#include <QEventLoop>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QTimer>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QTimer>
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
@ -25,15 +24,14 @@
|
||||||
|
|
||||||
#include "containers/containers_defs.h"
|
#include "containers/containers_defs.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include "scripts_registry.h"
|
||||||
#include "server_defs.h"
|
#include "server_defs.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "scripts_registry.h"
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#include <configurators/vpn_configurator.h>
|
#include <configurators/vpn_configurator.h>
|
||||||
|
|
||||||
ServerController::ServerController(std::shared_ptr<Settings> settings, QObject *parent) :
|
ServerController::ServerController(std::shared_ptr<Settings> settings, QObject *parent) : m_settings(settings)
|
||||||
m_settings(settings)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,10 +40,10 @@ ServerController::~ServerController()
|
||||||
m_sshClient.disconnectFromHost();
|
m_sshClient.disconnectFromHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ErrorCode ServerController::runScript(const ServerCredentials &credentials, QString script,
|
ErrorCode ServerController::runScript(const ServerCredentials &credentials, QString script,
|
||||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut,
|
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut,
|
||||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr) {
|
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr)
|
||||||
|
{
|
||||||
|
|
||||||
auto error = m_sshClient.connectToHost(credentials);
|
auto error = m_sshClient.connectToHost(credentials);
|
||||||
if (error != ErrorCode::NoError) {
|
if (error != ErrorCode::NoError) {
|
||||||
|
|
@ -92,36 +90,36 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::runContainerScript(const ServerCredentials &credentials,
|
ErrorCode
|
||||||
DockerContainer container, QString script,
|
ServerController::runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
|
||||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut,
|
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut,
|
||||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr)
|
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr)
|
||||||
{
|
{
|
||||||
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
|
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
|
||||||
Logger::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script);
|
Logger::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script);
|
||||||
|
|
||||||
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
|
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
|
|
||||||
QString runner = QString("sudo docker exec -i $CONTAINER_NAME bash %1 ").arg(fileName);
|
QString runner = QString("sudo docker exec -i $CONTAINER_NAME bash %1 ").arg(fileName);
|
||||||
e = runScript(credentials,
|
e = runScript(credentials, replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
||||||
replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
|
||||||
|
|
||||||
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
|
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
|
||||||
runScript(credentials,
|
runScript(credentials, replaceVars(remover, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
||||||
replaceVars(remover, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
|
ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials,
|
||||||
const ServerCredentials &credentials, const QString &file, const QString &path,
|
const QString &file, const QString &path,
|
||||||
libssh::SftpOverwriteMode overwriteMode)
|
libssh::SftpOverwriteMode overwriteMode)
|
||||||
{
|
{
|
||||||
ErrorCode e = ErrorCode::NoError;
|
ErrorCode e = ErrorCode::NoError;
|
||||||
QString tmpFileName = QString("/tmp/%1.tmp").arg(Utils::getRandomString(16));
|
QString tmpFileName = QString("/tmp/%1.tmp").arg(Utils::getRandomString(16));
|
||||||
e = uploadFileToHost(credentials, file.toUtf8(), tmpFileName);
|
e = uploadFileToHost(credentials, file.toUtf8(), tmpFileName);
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
|
|
||||||
QString stdOut;
|
QString stdOut;
|
||||||
auto cbReadStd = [&](const QString &data, libssh::Client &) {
|
auto cbReadStd = [&](const QString &data, libssh::Client &) {
|
||||||
|
|
@ -130,61 +128,63 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
|
||||||
};
|
};
|
||||||
|
|
||||||
// mkdir
|
// mkdir
|
||||||
QString mkdir = QString("sudo docker exec -i $CONTAINER_NAME mkdir -p \"$(dirname %1)\"")
|
QString mkdir = QString("sudo docker exec -i $CONTAINER_NAME mkdir -p \"$(dirname %1)\"").arg(path);
|
||||||
.arg(path);
|
|
||||||
|
|
||||||
e = runScript(credentials,
|
|
||||||
replaceVars(mkdir, genVarsForScript(credentials, container)));
|
|
||||||
if (e) return e;
|
|
||||||
|
|
||||||
|
e = runScript(credentials, replaceVars(mkdir, genVarsForScript(credentials, container)));
|
||||||
|
if (e)
|
||||||
|
return e;
|
||||||
|
|
||||||
if (overwriteMode == libssh::SftpOverwriteMode::SftpOverwriteExisting) {
|
if (overwriteMode == libssh::SftpOverwriteMode::SftpOverwriteExisting) {
|
||||||
e = runScript(credentials,
|
e = runScript(credentials,
|
||||||
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(path),
|
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(path),
|
||||||
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
|
genVarsForScript(credentials, container)),
|
||||||
|
cbReadStd, cbReadStd);
|
||||||
|
|
||||||
if (e) return e;
|
if (e)
|
||||||
}
|
return e;
|
||||||
else if (overwriteMode == libssh::SftpOverwriteMode::SftpAppendToExisting) {
|
} else if (overwriteMode == libssh::SftpOverwriteMode::SftpAppendToExisting) {
|
||||||
e = runScript(credentials,
|
e = runScript(credentials,
|
||||||
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(tmpFileName),
|
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(tmpFileName),
|
||||||
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
|
genVarsForScript(credentials, container)),
|
||||||
|
cbReadStd, cbReadStd);
|
||||||
|
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
|
|
||||||
e = runScript(credentials,
|
e = runScript(
|
||||||
replaceVars(QString("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName).arg(path),
|
credentials,
|
||||||
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
|
replaceVars(
|
||||||
|
QString("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName).arg(path),
|
||||||
if (e) return e;
|
genVarsForScript(credentials, container)),
|
||||||
}
|
cbReadStd, cbReadStd);
|
||||||
else return ErrorCode::NotImplementedError;
|
|
||||||
|
|
||||||
|
if (e)
|
||||||
|
return e;
|
||||||
|
} else
|
||||||
|
return ErrorCode::NotImplementedError;
|
||||||
|
|
||||||
if (stdOut.contains("Error: No such container:")) {
|
if (stdOut.contains("Error: No such container:")) {
|
||||||
return ErrorCode::ServerContainerMissingError;
|
return ErrorCode::ServerContainerMissingError;
|
||||||
}
|
}
|
||||||
|
|
||||||
runScript(credentials,
|
runScript(credentials,
|
||||||
replaceVars(QString("sudo shred %1").arg(tmpFileName),
|
replaceVars(QString("sudo shred %1").arg(tmpFileName), genVarsForScript(credentials, container)));
|
||||||
genVarsForScript(credentials, container)));
|
|
||||||
|
|
||||||
runScript(credentials,
|
runScript(credentials, replaceVars(QString("sudo rm %1").arg(tmpFileName), genVarsForScript(credentials, container)));
|
||||||
replaceVars(QString("sudo rm %1").arg(tmpFileName),
|
|
||||||
genVarsForScript(credentials, container)));
|
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
|
QByteArray ServerController::getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials,
|
||||||
const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode)
|
const QString &path, ErrorCode *errorCode)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (errorCode) *errorCode = ErrorCode::NoError;
|
if (errorCode)
|
||||||
|
*errorCode = ErrorCode::NoError;
|
||||||
QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"").
|
|
||||||
arg(ContainerProps::containerToString(container)).arg(path);
|
|
||||||
|
|
||||||
|
QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"")
|
||||||
|
.arg(ContainerProps::containerToString(container))
|
||||||
|
.arg(path);
|
||||||
|
|
||||||
QString stdOut;
|
QString stdOut;
|
||||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||||
|
|
@ -196,8 +196,8 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
|
||||||
return QByteArray::fromHex(stdOut.toUtf8());
|
return QByteArray::fromHex(stdOut.toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath,
|
ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data,
|
||||||
libssh::SftpOverwriteMode overwriteMode)
|
const QString &remotePath, libssh::SftpOverwriteMode overwriteMode)
|
||||||
{
|
{
|
||||||
auto error = m_sshClient.connectToHost(credentials);
|
auto error = m_sshClient.connectToHost(credentials);
|
||||||
if (error != ErrorCode::NoError) {
|
if (error != ErrorCode::NoError) {
|
||||||
|
|
@ -209,7 +209,8 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
|
||||||
localFile.write(data);
|
localFile.write(data);
|
||||||
localFile.close();
|
localFile.close();
|
||||||
|
|
||||||
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toStdString(), remotePath.toStdString(), "non_desc");
|
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toStdString(), remotePath.toStdString(),
|
||||||
|
"non_desc");
|
||||||
if (error != ErrorCode::NoError) {
|
if (error != ErrorCode::NoError) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
@ -218,15 +219,14 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
|
||||||
|
|
||||||
ErrorCode ServerController::removeAllContainers(const ServerCredentials &credentials)
|
ErrorCode ServerController::removeAllContainers(const ServerCredentials &credentials)
|
||||||
{
|
{
|
||||||
return runScript(credentials,
|
return runScript(credentials, amnezia::scriptData(SharedScriptType::remove_all_containers));
|
||||||
amnezia::scriptData(SharedScriptType::remove_all_containers));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::removeContainer(const ServerCredentials &credentials, DockerContainer container)
|
ErrorCode ServerController::removeContainer(const ServerCredentials &credentials, DockerContainer container)
|
||||||
{
|
{
|
||||||
return runScript(credentials,
|
return runScript(credentials,
|
||||||
replaceVars(amnezia::scriptData(SharedScriptType::remove_container),
|
replaceVars(amnezia::scriptData(SharedScriptType::remove_container),
|
||||||
genVarsForScript(credentials, container)));
|
genVarsForScript(credentials, container)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::setupContainer(const ServerCredentials &credentials, DockerContainer container,
|
ErrorCode ServerController::setupContainer(const ServerCredentials &credentials, DockerContainer container,
|
||||||
|
|
@ -236,22 +236,33 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
|
||||||
ErrorCode e = ErrorCode::NoError;
|
ErrorCode e = ErrorCode::NoError;
|
||||||
|
|
||||||
e = isUserInSudo(credentials, container);
|
e = isUserInSudo(credentials, container);
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
|
|
||||||
e = isServerDpkgBusy(credentials, container);
|
e = isServerDpkgBusy(credentials, container);
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
|
|
||||||
e = installDockerWorker(credentials, container);
|
e = installDockerWorker(credentials, container);
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
qDebug().noquote() << "ServerController::setupContainer installDockerWorker finished";
|
qDebug().noquote() << "ServerController::setupContainer installDockerWorker finished";
|
||||||
|
|
||||||
if (!isUpdate) {
|
if (!isUpdate) {
|
||||||
e = isServerPortBusy(credentials, container, config);
|
e = isServerPortBusy(credentials, container, config);
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isUpdate) {
|
||||||
|
e = isServerPortBusy(credentials, container, config);
|
||||||
|
if (e)
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = prepareHostWorker(credentials, container, config);
|
e = prepareHostWorker(credentials, container, config);
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
qDebug().noquote() << "ServerController::setupContainer prepareHostWorker finished";
|
qDebug().noquote() << "ServerController::setupContainer prepareHostWorker finished";
|
||||||
|
|
||||||
removeContainer(credentials, container);
|
removeContainer(credentials, container);
|
||||||
|
|
@ -259,15 +270,18 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
|
||||||
|
|
||||||
qDebug().noquote() << "buildContainerWorker start";
|
qDebug().noquote() << "buildContainerWorker start";
|
||||||
e = buildContainerWorker(credentials, container, config);
|
e = buildContainerWorker(credentials, container, config);
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
qDebug().noquote() << "ServerController::setupContainer buildContainerWorker finished";
|
qDebug().noquote() << "ServerController::setupContainer buildContainerWorker finished";
|
||||||
|
|
||||||
e = runContainerWorker(credentials, container, config);
|
e = runContainerWorker(credentials, container, config);
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
qDebug().noquote() << "ServerController::setupContainer runContainerWorker finished";
|
qDebug().noquote() << "ServerController::setupContainer runContainerWorker finished";
|
||||||
|
|
||||||
e = configureContainerWorker(credentials, container, config);
|
e = configureContainerWorker(credentials, container, config);
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
qDebug().noquote() << "ServerController::setupContainer configureContainerWorker finished";
|
qDebug().noquote() << "ServerController::setupContainer configureContainerWorker finished";
|
||||||
|
|
||||||
setupServerFirewall(credentials);
|
setupServerFirewall(credentials);
|
||||||
|
|
@ -277,46 +291,25 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::updateContainer(const ServerCredentials &credentials, DockerContainer container,
|
ErrorCode ServerController::updateContainer(const ServerCredentials &credentials, DockerContainer container,
|
||||||
const QJsonObject &oldConfig, QJsonObject &newConfig)
|
const QJsonObject &oldConfig, QJsonObject &newConfig)
|
||||||
{
|
{
|
||||||
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
|
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
|
||||||
qDebug() << "ServerController::updateContainer for container" << container << "reinstall required is" << reinstallRequired;
|
qDebug() << "ServerController::updateContainer for container" << container << "reinstall required is"
|
||||||
|
<< reinstallRequired;
|
||||||
|
|
||||||
if (reinstallRequired) {
|
if (reinstallRequired) {
|
||||||
return setupContainer(credentials, container, newConfig, true);
|
return setupContainer(credentials, container, newConfig, true);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ErrorCode e = configureContainerWorker(credentials, container, newConfig);
|
ErrorCode e = configureContainerWorker(credentials, container, newConfig);
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
|
|
||||||
return startupContainerWorker(credentials, container, newConfig);
|
return startupContainerWorker(credentials, container, newConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject ServerController::createContainerInitialConfig(DockerContainer container, int port, TransportProto tp)
|
bool ServerController::isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig,
|
||||||
{
|
const QJsonObject &newConfig)
|
||||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
|
||||||
|
|
||||||
QJsonObject config {
|
|
||||||
{ config_key::container, ContainerProps::containerToString(container) }
|
|
||||||
};
|
|
||||||
|
|
||||||
QJsonObject protoConfig;
|
|
||||||
protoConfig.insert(config_key::port, QString::number(port));
|
|
||||||
protoConfig.insert(config_key::transport_proto, ProtocolProps::transportProtoToString(tp, mainProto));
|
|
||||||
|
|
||||||
|
|
||||||
if (container == DockerContainer::Sftp) {
|
|
||||||
protoConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
|
|
||||||
protoConfig.insert(config_key::password, Utils::getRandomString(10));
|
|
||||||
}
|
|
||||||
|
|
||||||
config.insert(ProtocolProps::protoToString(mainProto), protoConfig);
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerController::isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig)
|
|
||||||
{
|
{
|
||||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
Proto mainProto = ContainerProps::defaultProtocol(container);
|
||||||
|
|
||||||
|
|
@ -324,25 +317,29 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
|
||||||
const QJsonObject &newProtoConfig = newConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
|
const QJsonObject &newProtoConfig = newConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
|
||||||
|
|
||||||
if (container == DockerContainer::OpenVpn) {
|
if (container == DockerContainer::OpenVpn) {
|
||||||
if (oldProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) !=
|
if (oldProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto)
|
||||||
newProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto))
|
!= newProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (oldProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) !=
|
if (oldProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort)
|
||||||
newProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort))
|
!= newProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container == DockerContainer::Cloak) {
|
if (container == DockerContainer::Cloak) {
|
||||||
if (oldProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort) !=
|
if (oldProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort)
|
||||||
newProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort))
|
!= newProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container == DockerContainer::ShadowSocks) {
|
if (container == DockerContainer::ShadowSocks) {
|
||||||
if (oldProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) !=
|
if (oldProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort)
|
||||||
newProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort))
|
!= newProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort))
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (container == DockerContainer::Awg) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -364,75 +361,86 @@ ErrorCode ServerController::installDockerWorker(const ServerCredentials &credent
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
};
|
};
|
||||||
|
|
||||||
ErrorCode error = runScript(credentials,
|
ErrorCode error =
|
||||||
replaceVars(amnezia::scriptData(SharedScriptType::install_docker),
|
runScript(credentials,
|
||||||
genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
|
replaceVars(amnezia::scriptData(SharedScriptType::install_docker), genVarsForScript(credentials)),
|
||||||
|
cbReadStdOut, cbReadStdErr);
|
||||||
|
|
||||||
qDebug().noquote() << "ServerController::installDockerWorker" << stdOut;
|
qDebug().noquote() << "ServerController::installDockerWorker" << stdOut;
|
||||||
if (stdOut.contains("lock")) return ErrorCode::ServerPacketManagerError;
|
if (stdOut.contains("lock"))
|
||||||
if (stdOut.contains("command not found")) return ErrorCode::ServerDockerFailedError;
|
return ErrorCode::ServerPacketManagerError;
|
||||||
|
if (stdOut.contains("command not found"))
|
||||||
|
return ErrorCode::ServerDockerFailedError;
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
|
ErrorCode ServerController::prepareHostWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||||
|
const QJsonObject &config)
|
||||||
{
|
{
|
||||||
// create folder on host
|
// create folder on host
|
||||||
return runScript(credentials,
|
return runScript(
|
||||||
replaceVars(amnezia::scriptData(SharedScriptType::prepare_host),
|
credentials,
|
||||||
genVarsForScript(credentials, container)));
|
replaceVars(amnezia::scriptData(SharedScriptType::prepare_host), genVarsForScript(credentials, container)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
|
ErrorCode ServerController::buildContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||||
|
const QJsonObject &config)
|
||||||
{
|
{
|
||||||
ErrorCode e = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(),
|
ErrorCode e = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(),
|
||||||
amnezia::server::getDockerfileFolder(container) + "/Dockerfile");
|
amnezia::server::getDockerfileFolder(container) + "/Dockerfile");
|
||||||
|
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
|
|
||||||
QString stdOut;
|
QString stdOut;
|
||||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||||
stdOut += data + "\n";
|
stdOut += data + "\n";
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
};
|
};
|
||||||
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
|
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
|
||||||
// stdOut += data + "\n";
|
// stdOut += data + "\n";
|
||||||
// };
|
// };
|
||||||
|
|
||||||
e = runScript(credentials,
|
e = runScript(credentials,
|
||||||
replaceVars(amnezia::scriptData(SharedScriptType::build_container),
|
replaceVars(amnezia::scriptData(SharedScriptType::build_container),
|
||||||
genVarsForScript(credentials, container, config)), cbReadStdOut);
|
genVarsForScript(credentials, container, config)),
|
||||||
if (e) return e;
|
cbReadStdOut);
|
||||||
|
if (e)
|
||||||
|
return e;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
|
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||||
|
QJsonObject &config)
|
||||||
{
|
{
|
||||||
QString stdOut;
|
QString stdOut;
|
||||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||||
stdOut += data + "\n";
|
stdOut += data + "\n";
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
};
|
};
|
||||||
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
|
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
|
||||||
// stdOut += data + "\n";
|
// stdOut += data + "\n";
|
||||||
// };
|
// };
|
||||||
|
|
||||||
ErrorCode e = runScript(credentials,
|
ErrorCode e = runScript(credentials,
|
||||||
replaceVars(amnezia::scriptData(ProtocolScriptType::run_container, container),
|
replaceVars(amnezia::scriptData(ProtocolScriptType::run_container, container),
|
||||||
genVarsForScript(credentials, container, config)), cbReadStdOut);
|
genVarsForScript(credentials, container, config)),
|
||||||
|
cbReadStdOut);
|
||||||
|
|
||||||
|
if (stdOut.contains("address already in use"))
|
||||||
if (stdOut.contains("docker: Error response from daemon")) return ErrorCode::ServerDockerFailedError;
|
return ErrorCode::ServerPortAlreadyAllocatedError;
|
||||||
|
if (stdOut.contains("is already in use by container"))
|
||||||
if (stdOut.contains("address already in use")) return ErrorCode::ServerPortAlreadyAllocatedError;
|
return ErrorCode::ServerPortAlreadyAllocatedError;
|
||||||
if (stdOut.contains("is already in use by container")) return ErrorCode::ServerPortAlreadyAllocatedError;
|
if (stdOut.contains("invalid publish"))
|
||||||
if (stdOut.contains("invalid publish")) return ErrorCode::ServerDockerFailedError;
|
return ErrorCode::ServerDockerFailedError;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
|
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||||
|
QJsonObject &config)
|
||||||
{
|
{
|
||||||
QString stdOut;
|
QString stdOut;
|
||||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||||
|
|
@ -444,19 +452,18 @@ ErrorCode ServerController::configureContainerWorker(const ServerCredentials &cr
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ErrorCode e = runContainerScript(credentials, container,
|
ErrorCode e = runContainerScript(credentials, container,
|
||||||
replaceVars(amnezia::scriptData(ProtocolScriptType::configure_container, container),
|
replaceVars(amnezia::scriptData(ProtocolScriptType::configure_container, container),
|
||||||
genVarsForScript(credentials, container, config)),
|
genVarsForScript(credentials, container, config)),
|
||||||
cbReadStdOut, cbReadStdErr);
|
cbReadStdOut, cbReadStdErr);
|
||||||
|
|
||||||
|
|
||||||
m_configurator->updateContainerConfigAfterInstallation(container, config, stdOut);
|
m_configurator->updateContainerConfigAfterInstallation(container, config, stdOut);
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
|
ErrorCode ServerController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||||
|
const QJsonObject &config)
|
||||||
{
|
{
|
||||||
QString script = amnezia::scriptData(ProtocolScriptType::container_startup, container);
|
QString script = amnezia::scriptData(ProtocolScriptType::container_startup, container);
|
||||||
|
|
||||||
|
|
@ -465,104 +472,144 @@ ErrorCode ServerController::startupContainerWorker(const ServerCredentials &cred
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode e = uploadTextFileToContainer(container, credentials,
|
ErrorCode e = uploadTextFileToContainer(container, credentials,
|
||||||
replaceVars(script, genVarsForScript(credentials, container, config)),
|
replaceVars(script, genVarsForScript(credentials, container, config)),
|
||||||
"/opt/amnezia/start.sh");
|
"/opt/amnezia/start.sh");
|
||||||
if (e) return e;
|
if (e)
|
||||||
|
return e;
|
||||||
|
|
||||||
return runScript(credentials,
|
return runScript(credentials,
|
||||||
replaceVars("sudo docker exec -d $CONTAINER_NAME sh -c \"chmod a+x /opt/amnezia/start.sh && /opt/amnezia/start.sh\"",
|
replaceVars("sudo docker exec -d $CONTAINER_NAME sh -c \"chmod a+x /opt/amnezia/start.sh && "
|
||||||
genVarsForScript(credentials, container, config)));
|
"/opt/amnezia/start.sh\"",
|
||||||
|
genVarsForScript(credentials, container, config)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
|
ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials,
|
||||||
|
DockerContainer container, const QJsonObject &config)
|
||||||
{
|
{
|
||||||
const QJsonObject &openvpnConfig = config.value(ProtocolProps::protoToString(Proto::OpenVpn)).toObject();
|
const QJsonObject &openvpnConfig = config.value(ProtocolProps::protoToString(Proto::OpenVpn)).toObject();
|
||||||
const QJsonObject &cloakConfig = config.value(ProtocolProps::protoToString(Proto::Cloak)).toObject();
|
const QJsonObject &cloakConfig = config.value(ProtocolProps::protoToString(Proto::Cloak)).toObject();
|
||||||
const QJsonObject &ssConfig = config.value(ProtocolProps::protoToString(Proto::ShadowSocks)).toObject();
|
const QJsonObject &ssConfig = config.value(ProtocolProps::protoToString(Proto::ShadowSocks)).toObject();
|
||||||
const QJsonObject &wireguarConfig = config.value(ProtocolProps::protoToString(Proto::WireGuard)).toObject();
|
const QJsonObject &wireguarConfig = config.value(ProtocolProps::protoToString(Proto::WireGuard)).toObject();
|
||||||
|
const QJsonObject &amneziaWireguarConfig = config.value(ProtocolProps::protoToString(Proto::Awg)).toObject();
|
||||||
const QJsonObject &sftpConfig = config.value(ProtocolProps::protoToString(Proto::Sftp)).toObject();
|
const QJsonObject &sftpConfig = config.value(ProtocolProps::protoToString(Proto::Sftp)).toObject();
|
||||||
|
|
||||||
Vars vars;
|
Vars vars;
|
||||||
|
|
||||||
vars.append({{"$REMOTE_HOST", credentials.hostName}});
|
vars.append({ { "$REMOTE_HOST", credentials.hostName } });
|
||||||
|
|
||||||
// OpenVPN vars
|
// OpenVPN vars
|
||||||
vars.append({{"$OPENVPN_SUBNET_IP", openvpnConfig.value(config_key::subnet_address).toString(protocols::openvpn::defaultSubnetAddress) }});
|
vars.append(
|
||||||
vars.append({{"$OPENVPN_SUBNET_CIDR", openvpnConfig.value(config_key::subnet_cidr).toString(protocols::openvpn::defaultSubnetCidr) }});
|
{ { "$OPENVPN_SUBNET_IP",
|
||||||
vars.append({{"$OPENVPN_SUBNET_MASK", openvpnConfig.value(config_key::subnet_mask).toString(protocols::openvpn::defaultSubnetMask) }});
|
openvpnConfig.value(config_key::subnet_address).toString(protocols::openvpn::defaultSubnetAddress) } });
|
||||||
|
vars.append({ { "$OPENVPN_SUBNET_CIDR",
|
||||||
|
openvpnConfig.value(config_key::subnet_cidr).toString(protocols::openvpn::defaultSubnetCidr) } });
|
||||||
|
vars.append({ { "$OPENVPN_SUBNET_MASK",
|
||||||
|
openvpnConfig.value(config_key::subnet_mask).toString(protocols::openvpn::defaultSubnetMask) } });
|
||||||
|
|
||||||
vars.append({{"$OPENVPN_PORT", openvpnConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) }});
|
vars.append({ { "$OPENVPN_PORT", openvpnConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) } });
|
||||||
vars.append({{"$OPENVPN_TRANSPORT_PROTO", openvpnConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) }});
|
vars.append(
|
||||||
|
{ { "$OPENVPN_TRANSPORT_PROTO",
|
||||||
|
openvpnConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) } });
|
||||||
|
|
||||||
bool isNcpDisabled = openvpnConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable);
|
bool isNcpDisabled = openvpnConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable);
|
||||||
vars.append({{"$OPENVPN_NCP_DISABLE", isNcpDisabled ? protocols::openvpn::ncpDisableString : "" }});
|
vars.append({ { "$OPENVPN_NCP_DISABLE", isNcpDisabled ? protocols::openvpn::ncpDisableString : "" } });
|
||||||
|
|
||||||
vars.append({{"$OPENVPN_CIPHER", openvpnConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher) }});
|
vars.append({ { "$OPENVPN_CIPHER",
|
||||||
vars.append({{"$OPENVPN_HASH", openvpnConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash) }});
|
openvpnConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher) } });
|
||||||
|
vars.append({ { "$OPENVPN_HASH", openvpnConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash) } });
|
||||||
|
|
||||||
bool isTlsAuth = openvpnConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth);
|
bool isTlsAuth = openvpnConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth);
|
||||||
vars.append({{"$OPENVPN_TLS_AUTH", isTlsAuth ? protocols::openvpn::tlsAuthString : "" }});
|
vars.append({ { "$OPENVPN_TLS_AUTH", isTlsAuth ? protocols::openvpn::tlsAuthString : "" } });
|
||||||
if (!isTlsAuth) {
|
if (!isTlsAuth) {
|
||||||
// erase $OPENVPN_TA_KEY, so it will not set in OpenVpnConfigurator::genOpenVpnConfig
|
// erase $OPENVPN_TA_KEY, so it will not set in OpenVpnConfigurator::genOpenVpnConfig
|
||||||
vars.append({{"$OPENVPN_TA_KEY", "" }});
|
vars.append({ { "$OPENVPN_TA_KEY", "" } });
|
||||||
}
|
}
|
||||||
|
|
||||||
vars.append({{"$OPENVPN_ADDITIONAL_CLIENT_CONFIG", openvpnConfig.value(config_key::additional_client_config).
|
vars.append({ { "$OPENVPN_ADDITIONAL_CLIENT_CONFIG",
|
||||||
toString(protocols::openvpn::defaultAdditionalClientConfig) }});
|
openvpnConfig.value(config_key::additional_client_config)
|
||||||
vars.append({{"$OPENVPN_ADDITIONAL_SERVER_CONFIG", openvpnConfig.value(config_key::additional_server_config).
|
.toString(protocols::openvpn::defaultAdditionalClientConfig) } });
|
||||||
toString(protocols::openvpn::defaultAdditionalServerConfig) }});
|
vars.append({ { "$OPENVPN_ADDITIONAL_SERVER_CONFIG",
|
||||||
|
openvpnConfig.value(config_key::additional_server_config)
|
||||||
|
.toString(protocols::openvpn::defaultAdditionalServerConfig) } });
|
||||||
|
|
||||||
// ShadowSocks vars
|
// ShadowSocks vars
|
||||||
vars.append({{"$SHADOWSOCKS_SERVER_PORT", ssConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) }});
|
vars.append({ { "$SHADOWSOCKS_SERVER_PORT",
|
||||||
vars.append({{"$SHADOWSOCKS_LOCAL_PORT", ssConfig.value(config_key::local_port).toString(protocols::shadowsocks::defaultLocalProxyPort) }});
|
ssConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) } });
|
||||||
vars.append({{"$SHADOWSOCKS_CIPHER", ssConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher) }});
|
vars.append({ { "$SHADOWSOCKS_LOCAL_PORT",
|
||||||
|
ssConfig.value(config_key::local_port).toString(protocols::shadowsocks::defaultLocalProxyPort) } });
|
||||||
|
vars.append({ { "$SHADOWSOCKS_CIPHER",
|
||||||
|
ssConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher) } });
|
||||||
|
|
||||||
vars.append({{"$CONTAINER_NAME", ContainerProps::containerToString(container)}});
|
vars.append({ { "$CONTAINER_NAME", ContainerProps::containerToString(container) } });
|
||||||
vars.append({{"$DOCKERFILE_FOLDER", "/opt/amnezia/" + ContainerProps::containerToString(container)}});
|
vars.append({ { "$DOCKERFILE_FOLDER", "/opt/amnezia/" + ContainerProps::containerToString(container) } });
|
||||||
|
|
||||||
// Cloak vars
|
// Cloak vars
|
||||||
vars.append({{"$CLOAK_SERVER_PORT", cloakConfig.value(config_key::port).toString(protocols::cloak::defaultPort) }});
|
vars.append({ { "$CLOAK_SERVER_PORT", cloakConfig.value(config_key::port).toString(protocols::cloak::defaultPort) } });
|
||||||
vars.append({{"$FAKE_WEB_SITE_ADDRESS", cloakConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite) }});
|
vars.append({ { "$FAKE_WEB_SITE_ADDRESS",
|
||||||
|
cloakConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite) } });
|
||||||
|
|
||||||
// Wireguard vars
|
// Wireguard vars
|
||||||
vars.append({{"$WIREGUARD_SUBNET_IP", wireguarConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) }});
|
vars.append(
|
||||||
vars.append({{"$WIREGUARD_SUBNET_CIDR", wireguarConfig.value(config_key::subnet_cidr).toString(protocols::wireguard::defaultSubnetCidr) }});
|
{ { "$WIREGUARD_SUBNET_IP",
|
||||||
vars.append({{"$WIREGUARD_SUBNET_MASK", wireguarConfig.value(config_key::subnet_mask).toString(protocols::wireguard::defaultSubnetMask) }});
|
wireguarConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) } });
|
||||||
|
vars.append({ { "$WIREGUARD_SUBNET_CIDR",
|
||||||
|
wireguarConfig.value(config_key::subnet_cidr).toString(protocols::wireguard::defaultSubnetCidr) } });
|
||||||
|
vars.append({ { "$WIREGUARD_SUBNET_MASK",
|
||||||
|
wireguarConfig.value(config_key::subnet_mask).toString(protocols::wireguard::defaultSubnetMask) } });
|
||||||
|
|
||||||
vars.append({{"$WIREGUARD_SERVER_PORT", wireguarConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) }});
|
vars.append({ { "$WIREGUARD_SERVER_PORT",
|
||||||
|
wireguarConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) } });
|
||||||
|
|
||||||
// IPsec vars
|
// IPsec vars
|
||||||
vars.append({{"$IPSEC_VPN_L2TP_NET", "192.168.42.0/24"}});
|
vars.append({ { "$IPSEC_VPN_L2TP_NET", "192.168.42.0/24" } });
|
||||||
vars.append({{"$IPSEC_VPN_L2TP_POOL", "192.168.42.10-192.168.42.250"}});
|
vars.append({ { "$IPSEC_VPN_L2TP_POOL", "192.168.42.10-192.168.42.250" } });
|
||||||
vars.append({{"$IPSEC_VPN_L2TP_LOCAL", "192.168.42.1"}});
|
vars.append({ { "$IPSEC_VPN_L2TP_LOCAL", "192.168.42.1" } });
|
||||||
|
|
||||||
vars.append({{"$IPSEC_VPN_XAUTH_NET", "192.168.43.0/24"}});
|
vars.append({ { "$IPSEC_VPN_XAUTH_NET", "192.168.43.0/24" } });
|
||||||
vars.append({{"$IPSEC_VPN_XAUTH_POOL", "192.168.43.10-192.168.43.250"}});
|
vars.append({ { "$IPSEC_VPN_XAUTH_POOL", "192.168.43.10-192.168.43.250" } });
|
||||||
|
|
||||||
vars.append({{"$IPSEC_VPN_SHA2_TRUNCBUG", "yes"}});
|
vars.append({ { "$IPSEC_VPN_SHA2_TRUNCBUG", "yes" } });
|
||||||
|
|
||||||
vars.append({{"$IPSEC_VPN_VPN_ANDROID_MTU_FIX", "yes"}});
|
vars.append({ { "$IPSEC_VPN_VPN_ANDROID_MTU_FIX", "yes" } });
|
||||||
vars.append({{"$IPSEC_VPN_DISABLE_IKEV2", "no"}});
|
vars.append({ { "$IPSEC_VPN_DISABLE_IKEV2", "no" } });
|
||||||
vars.append({{"$IPSEC_VPN_DISABLE_L2TP", "no"}});
|
vars.append({ { "$IPSEC_VPN_DISABLE_L2TP", "no" } });
|
||||||
vars.append({{"$IPSEC_VPN_DISABLE_XAUTH", "no"}});
|
vars.append({ { "$IPSEC_VPN_DISABLE_XAUTH", "no" } });
|
||||||
|
|
||||||
vars.append({{"$IPSEC_VPN_C2C_TRAFFIC", "no"}});
|
vars.append({ { "$IPSEC_VPN_C2C_TRAFFIC", "no" } });
|
||||||
|
|
||||||
vars.append({{"$PRIMARY_SERVER_DNS", m_settings->primaryDns()}});
|
|
||||||
vars.append({{"$SECONDARY_SERVER_DNS", m_settings->secondaryDns()}});
|
|
||||||
|
|
||||||
|
vars.append({ { "$PRIMARY_SERVER_DNS", m_settings->primaryDns() } });
|
||||||
|
vars.append({ { "$SECONDARY_SERVER_DNS", m_settings->secondaryDns() } });
|
||||||
|
|
||||||
// Sftp vars
|
// Sftp vars
|
||||||
vars.append({{"$SFTP_PORT", sftpConfig.value(config_key::port).toString(QString::number(ProtocolProps::defaultPort(Proto::Sftp))) }});
|
vars.append(
|
||||||
vars.append({{"$SFTP_USER", sftpConfig.value(config_key::userName).toString() }});
|
{ { "$SFTP_PORT",
|
||||||
vars.append({{"$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() }});
|
sftpConfig.value(config_key::port).toString(QString::number(ProtocolProps::defaultPort(Proto::Sftp))) } });
|
||||||
|
vars.append({ { "$SFTP_USER", sftpConfig.value(config_key::userName).toString() } });
|
||||||
|
vars.append({ { "$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() } });
|
||||||
|
|
||||||
|
// Amnezia wireguard vars
|
||||||
|
vars.append({ { "$AWG_SERVER_PORT",
|
||||||
|
amneziaWireguarConfig.value(config_key::port).toString(protocols::awg::defaultPort) } });
|
||||||
|
|
||||||
|
vars.append({ { "$JUNK_PACKET_COUNT", amneziaWireguarConfig.value(config_key::junkPacketCount).toString() } });
|
||||||
|
vars.append({ { "$JUNK_PACKET_MIN_SIZE", amneziaWireguarConfig.value(config_key::junkPacketMinSize).toString() } });
|
||||||
|
vars.append({ { "$JUNK_PACKET_MAX_SIZE", amneziaWireguarConfig.value(config_key::junkPacketMaxSize).toString() } });
|
||||||
|
vars.append({ { "$INIT_PACKET_JUNK_SIZE", amneziaWireguarConfig.value(config_key::initPacketJunkSize).toString() } });
|
||||||
|
vars.append({ { "$RESPONSE_PACKET_JUNK_SIZE",
|
||||||
|
amneziaWireguarConfig.value(config_key::responsePacketJunkSize).toString() } });
|
||||||
|
vars.append({ { "$INIT_PACKET_MAGIC_HEADER",
|
||||||
|
amneziaWireguarConfig.value(config_key::initPacketMagicHeader).toString() } });
|
||||||
|
vars.append({ { "$RESPONSE_PACKET_MAGIC_HEADER",
|
||||||
|
amneziaWireguarConfig.value(config_key::responsePacketMagicHeader).toString() } });
|
||||||
|
vars.append({ { "$UNDERLOAD_PACKET_MAGIC_HEADER",
|
||||||
|
amneziaWireguarConfig.value(config_key::underloadPacketMagicHeader).toString() } });
|
||||||
|
vars.append({ { "$TRANSPORT_PACKET_MAGIC_HEADER",
|
||||||
|
amneziaWireguarConfig.value(config_key::transportPacketMagicHeader).toString() } });
|
||||||
|
|
||||||
QString serverIp = Utils::getIPAddress(credentials.hostName);
|
QString serverIp = Utils::getIPAddress(credentials.hostName);
|
||||||
if (!serverIp.isEmpty()) {
|
if (!serverIp.isEmpty()) {
|
||||||
vars.append({{"$SERVER_IP_ADDRESS", serverIp}});
|
vars.append({ { "$SERVER_IP_ADDRESS", serverIp } });
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
qWarning() << "ServerController::genVarsForScript unable to resolve address for credentials.hostName";
|
qWarning() << "ServerController::genVarsForScript unable to resolve address for credentials.hostName";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -581,10 +628,11 @@ QString ServerController::checkSshConnection(const ServerCredentials &credential
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
};
|
};
|
||||||
|
|
||||||
ErrorCode e = runScript(credentials,
|
ErrorCode e =
|
||||||
amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
|
runScript(credentials, amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
|
||||||
|
|
||||||
if (errorCode) *errorCode = e;
|
if (errorCode)
|
||||||
|
*errorCode = e;
|
||||||
|
|
||||||
return stdOut;
|
return stdOut;
|
||||||
}
|
}
|
||||||
|
|
@ -596,9 +644,9 @@ void ServerController::setCancelInstallation(const bool cancel)
|
||||||
|
|
||||||
ErrorCode ServerController::setupServerFirewall(const ServerCredentials &credentials)
|
ErrorCode ServerController::setupServerFirewall(const ServerCredentials &credentials)
|
||||||
{
|
{
|
||||||
return runScript(credentials,
|
return runScript(
|
||||||
replaceVars(amnezia::scriptData(SharedScriptType::setup_host_firewall),
|
credentials,
|
||||||
genVarsForScript(credentials)));
|
replaceVars(amnezia::scriptData(SharedScriptType::setup_host_firewall), genVarsForScript(credentials)));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ServerController::replaceVars(const QString &script, const Vars &vars)
|
QString ServerController::replaceVars(const QString &script, const Vars &vars)
|
||||||
|
|
@ -610,7 +658,8 @@ QString ServerController::replaceVars(const QString &script, const Vars &vars)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
|
ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container,
|
||||||
|
const QJsonObject &config)
|
||||||
{
|
{
|
||||||
if (container == DockerContainer::Dns) {
|
if (container == DockerContainer::Dns) {
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
|
|
@ -633,12 +682,15 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
|
||||||
QStringList fixedPorts = ContainerProps::fixedPortsForContainer(container);
|
QStringList fixedPorts = ContainerProps::fixedPortsForContainer(container);
|
||||||
|
|
||||||
QString defaultPort("%1");
|
QString defaultPort("%1");
|
||||||
QString port = containerConfig.value(config_key::port).toString(defaultPort.arg(ProtocolProps::defaultPort(protocol)));
|
QString port =
|
||||||
QString defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(protocol), protocol);
|
containerConfig.value(config_key::port).toString(defaultPort.arg(ProtocolProps::defaultPort(protocol)));
|
||||||
|
QString defaultTransportProto =
|
||||||
|
ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(protocol), protocol);
|
||||||
QString transportProto = containerConfig.value(config_key::transport_proto).toString(defaultTransportProto);
|
QString transportProto = containerConfig.value(config_key::transport_proto).toString(defaultTransportProto);
|
||||||
|
|
||||||
// TODO reimplement with netstat
|
// TODO reimplement with netstat
|
||||||
QString script = QString("which lsof &>/dev/null || true && sudo lsof -i -P -n 2>/dev/null | grep -E ':%1 ").arg(port);
|
QString script =
|
||||||
|
QString("which lsof &>/dev/null || true && sudo lsof -i -P -n 2>/dev/null | grep -E ':%1 ").arg(port);
|
||||||
for (auto &port : fixedPorts) {
|
for (auto &port : fixedPorts) {
|
||||||
script = script.append("|:%1").arg(port);
|
script = script.append("|:%1").arg(port);
|
||||||
}
|
}
|
||||||
|
|
@ -648,8 +700,8 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
|
||||||
script = script.append(" | grep LISTEN");
|
script = script.append(" | grep LISTEN");
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode errorCode = runScript(credentials,
|
ErrorCode errorCode = runScript(credentials, replaceVars(script, genVarsForScript(credentials, container)),
|
||||||
replaceVars(script, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
cbReadStdOut, cbReadStdErr);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
@ -677,9 +729,11 @@ ErrorCode ServerController::isUserInSudo(const ServerCredentials &credentials, D
|
||||||
};
|
};
|
||||||
|
|
||||||
const QString scriptData = amnezia::scriptData(SharedScriptType::check_user_in_sudo);
|
const QString scriptData = amnezia::scriptData(SharedScriptType::check_user_in_sudo);
|
||||||
ErrorCode error = runScript(credentials, replaceVars(scriptData, genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
|
ErrorCode error =
|
||||||
|
runScript(credentials, replaceVars(scriptData, genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
|
||||||
|
|
||||||
if (!stdOut.contains("sudo")) return ErrorCode::ServerUserNotInSudo;
|
if (!stdOut.contains("sudo"))
|
||||||
|
return ErrorCode::ServerUserNotInSudo;
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
@ -707,18 +761,20 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
|
||||||
stdOut.clear();
|
stdOut.clear();
|
||||||
runScript(credentials,
|
runScript(credentials,
|
||||||
replaceVars(amnezia::scriptData(SharedScriptType::check_server_is_busy),
|
replaceVars(amnezia::scriptData(SharedScriptType::check_server_is_busy),
|
||||||
genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
|
genVarsForScript(credentials)),
|
||||||
|
cbReadStdOut, cbReadStdErr);
|
||||||
|
|
||||||
if (stdOut.contains("Packet manager not found")) return ErrorCode::ServerPacketManagerError;
|
if (stdOut.contains("Packet manager not found"))
|
||||||
if (stdOut.contains("fuser not installed")) return ErrorCode::NoError;
|
return ErrorCode::ServerPacketManagerError;
|
||||||
|
if (stdOut.contains("fuser not installed"))
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
|
||||||
if (stdOut.isEmpty()) {
|
if (stdOut.isEmpty()) {
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
} else {
|
||||||
else {
|
#ifdef MZ_DEBUG
|
||||||
#ifdef MZ_DEBUG
|
|
||||||
qDebug().noquote() << stdOut;
|
qDebug().noquote() << stdOut;
|
||||||
#endif
|
#endif
|
||||||
emit serverIsBusy(true);
|
emit serverIsBusy(true);
|
||||||
QThread::msleep(10000);
|
QThread::msleep(10000);
|
||||||
}
|
}
|
||||||
|
|
@ -737,7 +793,8 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
|
||||||
return future.result();
|
return future.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers)
|
ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredentials &credentials,
|
||||||
|
QMap<DockerContainer, QJsonObject> &installedContainers)
|
||||||
{
|
{
|
||||||
QString stdOut;
|
QString stdOut;
|
||||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||||
|
|
@ -768,14 +825,47 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential
|
||||||
QString port = containerAndPortMatch.captured(2);
|
QString port = containerAndPortMatch.captured(2);
|
||||||
QString transportProto = containerAndPortMatch.captured(3);
|
QString transportProto = containerAndPortMatch.captured(3);
|
||||||
DockerContainer container = ContainerProps::containerFromString(name);
|
DockerContainer container = ContainerProps::containerFromString(name);
|
||||||
|
|
||||||
|
QJsonObject config;
|
||||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
Proto mainProto = ContainerProps::defaultProtocol(container);
|
||||||
QJsonObject config {
|
for (auto protocol : ContainerProps::protocolsForContainer(container)) {
|
||||||
{ config_key::container, name },
|
QJsonObject containerConfig;
|
||||||
{ ProtocolProps::protoToString(mainProto), QJsonObject {
|
if (protocol == mainProto) {
|
||||||
{ config_key::port, port },
|
containerConfig.insert(config_key::port, port);
|
||||||
{ config_key::transport_proto, transportProto }}
|
containerConfig.insert(config_key::transport_proto, transportProto);
|
||||||
|
|
||||||
|
if (protocol == Proto::Awg) {
|
||||||
|
QString serverConfig = getTextFileFromContainer(container, credentials, protocols::awg::serverConfigPath, &errorCode);
|
||||||
|
|
||||||
|
QMap<QString, QString> serverConfigMap;
|
||||||
|
auto serverConfigLines = serverConfig.split("\n");
|
||||||
|
for (auto &line : serverConfigLines) {
|
||||||
|
auto trimmedLine = line.trimmed();
|
||||||
|
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
QStringList parts = trimmedLine.split(" = ");
|
||||||
|
if (parts.count() == 2) {
|
||||||
|
serverConfigMap.insert(parts[0].trimmed(), parts[1].trimmed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
containerConfig[config_key::junkPacketCount] = serverConfigMap.value(config_key::junkPacketCount);
|
||||||
|
containerConfig[config_key::junkPacketMinSize] = serverConfigMap.value(config_key::junkPacketMinSize);
|
||||||
|
containerConfig[config_key::junkPacketMaxSize] = serverConfigMap.value(config_key::junkPacketMaxSize);
|
||||||
|
containerConfig[config_key::initPacketJunkSize] = serverConfigMap.value(config_key::initPacketJunkSize);
|
||||||
|
containerConfig[config_key::responsePacketJunkSize] = serverConfigMap.value(config_key::responsePacketJunkSize);
|
||||||
|
containerConfig[config_key::initPacketMagicHeader] = serverConfigMap.value(config_key::initPacketMagicHeader);
|
||||||
|
containerConfig[config_key::responsePacketMagicHeader] = serverConfigMap.value(config_key::responsePacketMagicHeader);
|
||||||
|
containerConfig[config_key::underloadPacketMagicHeader] = serverConfigMap.value(config_key::underloadPacketMagicHeader);
|
||||||
|
containerConfig[config_key::transportPacketMagicHeader] = serverConfigMap.value(config_key::transportPacketMagicHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
config.insert(config_key::container, ContainerProps::containerToString(container));
|
||||||
}
|
}
|
||||||
};
|
config.insert(ProtocolProps::protoToString(protocol), containerConfig);
|
||||||
|
}
|
||||||
installedContainers.insert(container, config);
|
installedContainers.insert(container, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -783,7 +873,8 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &callback)
|
ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey,
|
||||||
|
const std::function<QString()> &callback)
|
||||||
{
|
{
|
||||||
auto error = m_sshClient.getDecryptedPrivateKey(credentials, decryptedPrivateKey, callback);
|
auto error = m_sshClient.getDecryptedPrivateKey(credentials, decryptedPrivateKey, callback);
|
||||||
return error;
|
return error;
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "defs.h"
|
|
||||||
#include "containers/containers_defs.h"
|
#include "containers/containers_defs.h"
|
||||||
|
#include "defs.h"
|
||||||
#include "sshclient.h"
|
#include "sshclient.h"
|
||||||
|
|
||||||
class Settings;
|
class Settings;
|
||||||
|
|
@ -24,52 +24,62 @@ public:
|
||||||
|
|
||||||
ErrorCode removeAllContainers(const ServerCredentials &credentials);
|
ErrorCode removeAllContainers(const ServerCredentials &credentials);
|
||||||
ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container);
|
ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container);
|
||||||
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container,
|
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config,
|
||||||
QJsonObject &config, bool isUpdate = false);
|
bool isUpdate = false);
|
||||||
ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container,
|
ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container,
|
||||||
const QJsonObject &oldConfig, QJsonObject &newConfig);
|
const QJsonObject &oldConfig, QJsonObject &newConfig);
|
||||||
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers);
|
|
||||||
|
|
||||||
// create initial config - generate passwords, etc
|
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials,
|
||||||
QJsonObject createContainerInitialConfig(DockerContainer container, int port, TransportProto tp);
|
QMap<DockerContainer, QJsonObject> &installedContainers);
|
||||||
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
|
||||||
|
|
||||||
ErrorCode uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials,
|
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||||
const QString &file, const QString &path,
|
const QJsonObject &config = QJsonObject());
|
||||||
libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
|
|
||||||
|
ErrorCode uploadTextFileToContainer(
|
||||||
|
DockerContainer container, const ServerCredentials &credentials, const QString &file, const QString &path,
|
||||||
|
libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
|
||||||
QByteArray getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials,
|
QByteArray getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials,
|
||||||
const QString &path, ErrorCode *errorCode = nullptr);
|
const QString &path, ErrorCode *errorCode = nullptr);
|
||||||
|
|
||||||
QString replaceVars(const QString &script, const Vars &vars);
|
QString replaceVars(const QString &script, const Vars &vars);
|
||||||
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject());
|
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None,
|
||||||
|
const QJsonObject &config = QJsonObject());
|
||||||
|
|
||||||
ErrorCode runScript(const ServerCredentials &credentials, QString script,
|
ErrorCode runScript(const ServerCredentials &credentials, QString script,
|
||||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
|
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
|
||||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
|
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
|
||||||
|
|
||||||
ErrorCode runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
|
ErrorCode
|
||||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
|
runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
|
||||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
|
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
|
||||||
|
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
|
||||||
|
|
||||||
QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr);
|
QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr);
|
||||||
|
|
||||||
void setCancelInstallation(const bool cancel);
|
void setCancelInstallation(const bool cancel);
|
||||||
|
|
||||||
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &callback);
|
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey,
|
||||||
|
const std::function<QString()> &callback);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container);
|
ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container);
|
||||||
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||||
ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
const QJsonObject &config = QJsonObject());
|
||||||
|
ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||||
|
const QJsonObject &config = QJsonObject());
|
||||||
ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
|
ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
|
||||||
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
|
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||||
|
QJsonObject &config);
|
||||||
|
|
||||||
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config);
|
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container,
|
||||||
bool isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
|
const QJsonObject &config);
|
||||||
|
bool isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig,
|
||||||
|
const QJsonObject &newConfig);
|
||||||
ErrorCode isUserInSudo(const ServerCredentials &credentials, DockerContainer container);
|
ErrorCode isUserInSudo(const ServerCredentials &credentials, DockerContainer container);
|
||||||
ErrorCode isServerDpkgBusy(const ServerCredentials &credentials, DockerContainer container);
|
ErrorCode isServerDpkgBusy(const ServerCredentials &credentials, DockerContainer container);
|
||||||
|
|
||||||
ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data,
|
ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath,
|
||||||
const QString &remotePath, libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
|
libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
|
||||||
|
|
||||||
ErrorCode setupServerFirewall(const ServerCredentials &credentials);
|
ErrorCode setupServerFirewall(const ServerCredentials &credentials);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ const uint32_t S_IRWXU = 0644;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace libssh {
|
namespace libssh {
|
||||||
|
const QString libsshTimeoutError = "Timeout connecting to";
|
||||||
|
|
||||||
std::function<QString()> Client::m_passphraseCallback;
|
std::function<QString()> Client::m_passphraseCallback;
|
||||||
|
|
||||||
Client::Client(QObject *parent) : QObject(parent)
|
Client::Client(QObject *parent) : QObject(parent)
|
||||||
|
|
@ -45,20 +47,29 @@ namespace libssh {
|
||||||
ssh_options_set(m_session, SSH_OPTIONS_USER, hostUsername.c_str());
|
ssh_options_set(m_session, SSH_OPTIONS_USER, hostUsername.c_str());
|
||||||
ssh_options_set(m_session, SSH_OPTIONS_LOG_VERBOSITY, &logVerbosity);
|
ssh_options_set(m_session, SSH_OPTIONS_LOG_VERBOSITY, &logVerbosity);
|
||||||
|
|
||||||
int connectionResult = ssh_connect(m_session);
|
QFutureWatcher<int> watcher;
|
||||||
|
QFuture<int> future = QtConcurrent::run([this]() {
|
||||||
|
return ssh_connect(m_session);
|
||||||
|
});
|
||||||
|
|
||||||
|
QEventLoop wait;
|
||||||
|
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, &wait, &QEventLoop::quit);
|
||||||
|
watcher.setFuture(future);
|
||||||
|
wait.exec();
|
||||||
|
|
||||||
|
int connectionResult = watcher.result();
|
||||||
|
|
||||||
if (connectionResult != SSH_OK) {
|
if (connectionResult != SSH_OK) {
|
||||||
qDebug() << ssh_get_error(m_session);
|
return fromLibsshErrorCode();
|
||||||
return fromLibsshErrorCode(ssh_get_error_code(m_session));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string authUsername = credentials.userName.toStdString();
|
std::string authUsername = credentials.userName.toStdString();
|
||||||
|
|
||||||
int authResult = SSH_ERROR;
|
int authResult = SSH_ERROR;
|
||||||
if (credentials.password.contains("BEGIN") && credentials.password.contains("PRIVATE KEY")) {
|
if (credentials.secretData.contains("BEGIN") && credentials.secretData.contains("PRIVATE KEY")) {
|
||||||
ssh_key privateKey = nullptr;
|
ssh_key privateKey = nullptr;
|
||||||
ssh_key publicKey = nullptr;
|
ssh_key publicKey = nullptr;
|
||||||
authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
|
authResult = ssh_pki_import_privkey_base64(credentials.secretData.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
|
||||||
if (authResult == SSH_OK) {
|
if (authResult == SSH_OK) {
|
||||||
authResult = ssh_pki_export_privkey_to_pubkey(privateKey, &publicKey);
|
authResult = ssh_pki_export_privkey_to_pubkey(privateKey, &publicKey);
|
||||||
}
|
}
|
||||||
|
|
@ -78,18 +89,17 @@ namespace libssh {
|
||||||
ssh_key_free(privateKey);
|
ssh_key_free(privateKey);
|
||||||
}
|
}
|
||||||
if (authResult != SSH_OK) {
|
if (authResult != SSH_OK) {
|
||||||
qDebug() << ssh_get_error(m_session);
|
qCritical() << ssh_get_error(m_session);
|
||||||
ErrorCode errorCode = fromLibsshErrorCode(ssh_get_error_code(m_session));
|
ErrorCode errorCode = fromLibsshErrorCode();
|
||||||
if (errorCode == ErrorCode::NoError) {
|
if (errorCode == ErrorCode::NoError) {
|
||||||
errorCode = ErrorCode::SshPrivateKeyFormatError;
|
errorCode = ErrorCode::SshPrivateKeyFormatError;
|
||||||
}
|
}
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
authResult = ssh_userauth_password(m_session, authUsername.c_str(), credentials.password.toStdString().c_str());
|
authResult = ssh_userauth_password(m_session, authUsername.c_str(), credentials.secretData.toStdString().c_str());
|
||||||
if (authResult != SSH_OK) {
|
if (authResult != SSH_OK) {
|
||||||
qDebug() << ssh_get_error(m_session);
|
return fromLibsshErrorCode();
|
||||||
return fromLibsshErrorCode(ssh_get_error_code(m_session));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -186,16 +196,15 @@ namespace libssh {
|
||||||
ErrorCode Client::writeResponse(const QString &data)
|
ErrorCode Client::writeResponse(const QString &data)
|
||||||
{
|
{
|
||||||
if (m_channel == nullptr) {
|
if (m_channel == nullptr) {
|
||||||
qDebug() << "ssh channel not initialized";
|
qCritical() << "ssh channel not initialized";
|
||||||
return fromLibsshErrorCode(ssh_get_error_code(m_session));
|
return fromLibsshErrorCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
int bytesWritten = ssh_channel_write(m_channel, data.toUtf8(), (uint32_t)data.size());
|
int bytesWritten = ssh_channel_write(m_channel, data.toUtf8(), (uint32_t)data.size());
|
||||||
if (bytesWritten == data.size() && ssh_channel_write(m_channel, "\n", 1)) {
|
if (bytesWritten == data.size() && ssh_channel_write(m_channel, "\n", 1)) {
|
||||||
return fromLibsshErrorCode(ssh_get_error_code(m_session));
|
return fromLibsshErrorCode();
|
||||||
}
|
}
|
||||||
qDebug() << ssh_get_error(m_session);
|
return fromLibsshErrorCode();
|
||||||
return fromLibsshErrorCode(ssh_get_error_code(m_session));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode Client::closeChannel()
|
ErrorCode Client::closeChannel()
|
||||||
|
|
@ -210,8 +219,7 @@ namespace libssh {
|
||||||
ssh_channel_free(m_channel);
|
ssh_channel_free(m_channel);
|
||||||
m_channel = nullptr;
|
m_channel = nullptr;
|
||||||
}
|
}
|
||||||
qDebug() << ssh_get_error(m_session);
|
return fromLibsshErrorCode();
|
||||||
return fromLibsshErrorCode(ssh_get_error_code(m_session));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const std::string& localPath, const std::string& remotePath, const std::string& fileDesc)
|
ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const std::string& localPath, const std::string& remotePath, const std::string& fileDesc)
|
||||||
|
|
@ -308,12 +316,21 @@ namespace libssh {
|
||||||
sftp_free(m_sftpSession);
|
sftp_free(m_sftpSession);
|
||||||
m_sftpSession = nullptr;
|
m_sftpSession = nullptr;
|
||||||
}
|
}
|
||||||
qDebug() << ssh_get_error(m_session);
|
qCritical() << ssh_get_error(m_session);
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode Client::fromLibsshErrorCode(int errorCode)
|
ErrorCode Client::fromLibsshErrorCode()
|
||||||
{
|
{
|
||||||
|
int errorCode = ssh_get_error_code(m_session);
|
||||||
|
if (errorCode != SSH_NO_ERROR) {
|
||||||
|
QString errorMessage = ssh_get_error(m_session);
|
||||||
|
qCritical() << errorMessage;
|
||||||
|
if (errorMessage.contains(libsshTimeoutError)) {
|
||||||
|
return ErrorCode::SshTimeoutError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (errorCode) {
|
switch (errorCode) {
|
||||||
case(SSH_NO_ERROR): return ErrorCode::NoError;
|
case(SSH_NO_ERROR): return ErrorCode::NoError;
|
||||||
case(SSH_REQUEST_DENIED): return ErrorCode::SshRequsetDeniedError;
|
case(SSH_REQUEST_DENIED): return ErrorCode::SshRequsetDeniedError;
|
||||||
|
|
@ -350,7 +367,7 @@ namespace libssh {
|
||||||
|
|
||||||
ssh_key privateKey = nullptr;
|
ssh_key privateKey = nullptr;
|
||||||
m_passphraseCallback = passphraseCallback;
|
m_passphraseCallback = passphraseCallback;
|
||||||
authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
|
authResult = ssh_pki_import_privkey_base64(credentials.secretData.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
|
||||||
if (authResult == SSH_OK) {
|
if (authResult == SSH_OK) {
|
||||||
char *b64 = nullptr;
|
char *b64 = nullptr;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace libssh {
|
||||||
private:
|
private:
|
||||||
ErrorCode closeChannel();
|
ErrorCode closeChannel();
|
||||||
ErrorCode closeSftpSession();
|
ErrorCode closeSftpSession();
|
||||||
ErrorCode fromLibsshErrorCode(int errorCode);
|
ErrorCode fromLibsshErrorCode();
|
||||||
ErrorCode fromLibsshSftpErrorCode(int errorCode);
|
ErrorCode fromLibsshSftpErrorCode(int errorCode);
|
||||||
static int callback(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata);
|
static int callback(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -359,6 +359,23 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
|
||||||
if (!parseStringList(obj, "vpnDisabledApps", config.m_vpnDisabledApps)) {
|
if (!parseStringList(obj, "vpnDisabledApps", config.m_vpnDisabledApps)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!obj.value("Jc").isNull() && !obj.value("Jmin").isNull()
|
||||||
|
&& !obj.value("Jmax").isNull() && !obj.value("S1").isNull()
|
||||||
|
&& !obj.value("S2").isNull() && !obj.value("H1").isNull()
|
||||||
|
&& !obj.value("H2").isNull() && !obj.value("H3").isNull()
|
||||||
|
&& !obj.value("H4").isNull()) {
|
||||||
|
config.m_junkPacketCount = obj.value("Jc").toString();
|
||||||
|
config.m_junkPacketMinSize = obj.value("Jmin").toString();
|
||||||
|
config.m_junkPacketMaxSize = obj.value("Jmax").toString();
|
||||||
|
config.m_initPacketJunkSize = obj.value("S1").toString();
|
||||||
|
config.m_responsePacketJunkSize = obj.value("S2").toString();
|
||||||
|
config.m_initPacketMagicHeader = obj.value("H1").toString();
|
||||||
|
config.m_responsePacketMagicHeader = obj.value("H2").toString();
|
||||||
|
config.m_underloadPacketMagicHeader = obj.value("H3").toString();
|
||||||
|
config.m_transportPacketMagicHeader = obj.value("H4").toString();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == "deactivate") {
|
if (type == "deactivate") {
|
||||||
Daemon::instance()->deactivate();
|
Daemon::instance()->deactivate(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,34 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
|
||||||
out << "DNS = " << dnsServers.join(", ") << "\n";
|
out << "DNS = " << dnsServers.join(", ") << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_junkPacketCount.isNull()) {
|
||||||
|
out << "Jc = " << m_junkPacketCount << "\n";
|
||||||
|
}
|
||||||
|
if (!m_junkPacketMinSize.isNull()) {
|
||||||
|
out << "JMin = " << m_junkPacketMinSize << "\n";
|
||||||
|
}
|
||||||
|
if (!m_junkPacketMaxSize.isNull()) {
|
||||||
|
out << "JMax = " << m_junkPacketMaxSize << "\n";
|
||||||
|
}
|
||||||
|
if (!m_initPacketJunkSize.isNull()) {
|
||||||
|
out << "S1 = " << m_initPacketJunkSize << "\n";
|
||||||
|
}
|
||||||
|
if (!m_responsePacketJunkSize.isNull()) {
|
||||||
|
out << "S2 = " << m_responsePacketJunkSize << "\n";
|
||||||
|
}
|
||||||
|
if (!m_initPacketMagicHeader.isNull()) {
|
||||||
|
out << "H1 = " << m_initPacketMagicHeader << "\n";
|
||||||
|
}
|
||||||
|
if (!m_responsePacketMagicHeader.isNull()) {
|
||||||
|
out << "H2 = " << m_responsePacketMagicHeader << "\n";
|
||||||
|
}
|
||||||
|
if (!m_underloadPacketMagicHeader.isNull()) {
|
||||||
|
out << "H3 = " << m_underloadPacketMagicHeader << "\n";
|
||||||
|
}
|
||||||
|
if (!m_transportPacketMagicHeader.isNull()) {
|
||||||
|
out << "H4 = " << m_transportPacketMagicHeader << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
// If any extra config was provided, append it now.
|
// If any extra config was provided, append it now.
|
||||||
for (const QString& key : extra.keys()) {
|
for (const QString& key : extra.keys()) {
|
||||||
out << key << " = " << extra[key] << "\n";
|
out << key << " = " << extra[key] << "\n";
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,16 @@ class InterfaceConfig {
|
||||||
QString m_installationId;
|
QString m_installationId;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
QString m_junkPacketCount;
|
||||||
|
QString m_junkPacketMinSize;
|
||||||
|
QString m_junkPacketMaxSize;
|
||||||
|
QString m_initPacketJunkSize;
|
||||||
|
QString m_responsePacketJunkSize;
|
||||||
|
QString m_initPacketMagicHeader;
|
||||||
|
QString m_responsePacketMagicHeader;
|
||||||
|
QString m_underloadPacketMagicHeader;
|
||||||
|
QString m_transportPacketMagicHeader;
|
||||||
|
|
||||||
QJsonObject toJson() const;
|
QJsonObject toJson() const;
|
||||||
QString toWgConf(
|
QString toWgConf(
|
||||||
const QMap<QString, QString>& extra = QMap<QString, QString>()) const;
|
const QMap<QString, QString>& extra = QMap<QString, QString>()) const;
|
||||||
|
|
|
||||||
BIN
client/fonts/pt-root-ui_vf.ttf
Normal file
BIN
client/images/amneziaBigLogo.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
1
client/images/amneziaBigLogo.svg
Normal file
|
After Width: | Height: | Size: 236 KiB |
18
client/images/connectionOff.svg
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<svg width="280" height="280" viewBox="0 0 280 280" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_f_1379_19114)">
|
||||||
|
<circle cx="140" cy="140" r="107.5" stroke="#FBB36A"/>
|
||||||
|
</g>
|
||||||
|
<circle cx="140" cy="140" r="107" stroke="#FBB36A" stroke-width="2"/>
|
||||||
|
<circle cx="140" cy="140" r="107" stroke="url(#paint0_linear_1379_19114)" stroke-width="2"/>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_f_1379_19114" x="2" y="2" width="276" height="276" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="15" result="effect1_foregroundBlur_1379_19114"/>
|
||||||
|
</filter>
|
||||||
|
<linearGradient id="paint0_linear_1379_19114" x1="-2.43527" y1="89.3291" x2="192.652" y2="11.9798" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#E0AA84"/>
|
||||||
|
<stop offset="1" stop-color="#DF7D37"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 969 B |
17
client/images/connectionOn.svg
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<svg width="280" height="280" viewBox="0 0 280 280" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_1379_19118)">
|
||||||
|
<path d="M140 235C127.524 235 115.171 232.543 103.645 227.769C92.1191 222.994 81.6464 215.997 72.8248 207.175C64.0033 198.354 57.0056 187.881 52.2314 176.355C47.4572 164.829 45 152.476 45 140C45 127.524 47.4572 115.171 52.2314 103.645C57.0056 92.1191 64.0033 81.6464 72.8249 72.8248C81.6464 64.0033 92.1191 57.0056 103.645 52.2314C115.171 47.4572 127.524 45 140 45C152.476 45 164.829 47.4572 176.355 52.2314C187.881 57.0056 198.354 64.0033 207.175 72.8249C215.997 81.6464 222.994 92.1192 227.769 103.645C232.543 115.171 235 127.524 235 140C235 152.476 232.543 164.829 227.769 176.355C222.994 187.881 215.997 198.354 207.175 207.175C198.354 215.997 187.881 222.994 176.355 227.769C164.829 232.543 152.476 235 140 235L140 235Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_1379_19118" x="38" y="38" width="204" height="204" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="3"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.2 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1379_19118"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1379_19118" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
30
client/images/connectionProgress.svg
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<svg width="280" height="280" viewBox="0 0 280 280" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g opacity="0.1" filter="url(#filter0_d_1379_19115)">
|
||||||
|
<path d="M235 140C235 152.476 232.543 164.829 227.769 176.355C222.994 187.881 215.997 198.354 207.175 207.175C198.354 215.997 187.881 222.994 176.355 227.769C164.829 232.543 152.476 235 140 235C127.524 235 115.171 232.543 103.645 227.769C92.1191 222.994 81.6464 215.997 72.8249 207.175C64.0033 198.354 57.0056 187.881 52.2314 176.355C47.4572 164.829 45 152.476 45 140C45 127.524 47.4572 115.171 52.2314 103.645C57.0056 92.1191 64.0033 81.6464 72.8249 72.8248C81.6464 64.0033 92.1192 57.0056 103.645 52.2314C115.171 47.4572 127.524 45 140 45C152.476 45 164.829 47.4573 176.355 52.2314C187.881 57.0056 198.354 64.0033 207.175 72.8249C215.997 81.6464 222.994 92.1192 227.769 103.645C232.543 115.171 235 127.524 235 140L235 140Z" stroke="#FBB36A"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter1_d_1379_19115)">
|
||||||
|
<path d="M140 235C126.016 235 112.204 231.913 99.551 225.959C86.8977 220.004 75.7151 211.33 66.8012 200.555C57.8874 189.78 51.4623 177.17 47.9846 163.626C44.5069 150.081 44.0623 135.935 46.6827 122.199C49.3031 108.462 54.9237 95.4738 63.1434 84.1604C71.363 72.847 81.979 63.4878 94.2334 56.7509C106.488 50.014 120.078 46.0655 134.035 45.1875C147.991 44.3094 161.97 46.5233 174.972 51.6712" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_1379_19115" x="38.5" y="38.5" width="203" height="203" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="3"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0.984314 0 0 0 0 0.717647 0 0 0 0 0.317647 0 0 0 1 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1379_19115"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1379_19115" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter1_d_1379_19115" x="38" y="38" width="143.973" height="204" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="3"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0.988235 0 0 0 0 0.301961 0 0 0 0 0.0705883 0 0 0 0.49 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1379_19115"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1379_19115" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.8 KiB |
3
client/images/controls/amnezia.svg
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
6
client/images/controls/app.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17 10C18.6569 10 20 8.65685 20 7C20 5.34315 18.6569 4 17 4C15.3431 4 14 5.34315 14 7C14 8.65685 15.3431 10 17 10Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<rect x="4" y="4" width="6" height="6" rx="1" stroke="#D7D8DB" stroke-width="2"/>
|
||||||
|
<rect x="14" y="14" width="6" height="6" rx="1" stroke="#D7D8DB" stroke-width="2"/>
|
||||||
|
<path d="M7.18963 13.8523L10.8078 20H2.91364L7.18963 13.8523Z" stroke="#D7D8DB" stroke-width="2"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 576 B |
4
client/images/controls/arrow-left.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M19 12H5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 19L5 12L12 5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 315 B |
4
client/images/controls/arrow-right.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M5 12H19" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 5L19 12L12 19" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 316 B |
3
client/images/controls/check.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20 6L9 17L4 12" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 212 B |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 18 KiB |
3
client/images/controls/chevron-down.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6 9L12 15L18 9" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 212 B |
3
client/images/controls/chevron-right.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9 18L15 12L9 6" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 212 B |
3
client/images/controls/chevron-up.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M18 15L12 9L6 15" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 213 B |
4
client/images/controls/copy.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20 9H11C9.89543 9 9 9.89543 9 11V20C9 21.1046 9.89543 22 11 22H20C21.1046 22 22 21.1046 22 20V11C22 9.89543 21.1046 9 20 9Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M5 15H4C3.46957 15 2.96086 14.7893 2.58579 14.4142C2.21071 14.0391 2 13.5304 2 13V4C2 3.46957 2.21071 2.96086 2.58579 2.58579C2.96086 2.21071 3.46957 2 4 2H13C13.5304 2 14.0391 2.21071 14.4142 2.58579C14.7893 2.96086 15 3.46957 15 4V5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 649 B |
5
client/images/controls/delete.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20.332 5H9.33203L2.33203 12L9.33203 19H20.332C20.8625 19 21.3712 18.7893 21.7462 18.4142C22.1213 18.0391 22.332 17.5304 22.332 17V7C22.332 6.46957 22.1213 5.96086 21.7462 5.58579C21.3712 5.21071 20.8625 5 20.332 5V5Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M18.332 9L12.332 15" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12.332 9L18.332 15" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 640 B |
5
client/images/controls/download.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M21 15V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V15" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7 10L12 15L17 10" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 15V3" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 574 B |
4
client/images/controls/edit-3.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12 20H21" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M16.5 3.49998C16.8978 3.10216 17.4374 2.87866 18 2.87866C18.2786 2.87866 18.5544 2.93353 18.8118 3.04014C19.0692 3.14674 19.303 3.303 19.5 3.49998C19.697 3.69697 19.8532 3.93082 19.9598 4.18819C20.0665 4.44556 20.1213 4.72141 20.1213 4.99998C20.1213 5.27856 20.0665 5.55441 19.9598 5.81178C19.8532 6.06915 19.697 6.303 19.5 6.49998L7 19L3 20L4 16L16.5 3.49998Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 660 B |
6
client/images/controls/eye-off.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.88 9.87988C9.58526 10.1545 9.34885 10.4857 9.18488 10.8537C9.02091 11.2217 8.93274 11.619 8.92564 12.0218C8.91853 12.4246 8.99263 12.8247 9.14351 13.1983C9.2944 13.5718 9.51898 13.9112 9.80385 14.196C10.0887 14.4809 10.4281 14.7055 10.8016 14.8564C11.1752 15.0073 11.5753 15.0814 11.9781 15.0742C12.3809 15.0671 12.7782 14.979 13.1462 14.815C13.5142 14.651 13.8454 14.4146 14.12 14.1199" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.73 5.08C11.1513 5.02751 11.5754 5.00079 12 5C19 5 22 12 22 12C21.5529 12.9571 20.9922 13.8569 20.33 14.68" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M6.61 6.61011C4.62125 7.96473 3.02987 9.82537 2 12.0001C2 12.0001 5 19.0001 12 19.0001C13.9159 19.0052 15.7908 18.4452 17.39 17.3901" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M2 2L22 22" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
4
client/images/controls/eye.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M2 12C2 12 5 5 12 5C19 5 22 12 22 12C22 12 19 19 12 19C5 19 2 12 2 12Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 474 B |
11
client/images/controls/file-cog-2.svg
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.5 2H6C5.46957 2 4.96086 2.21071 4.58579 2.58579C4.21071 2.96086 4 3.46957 4 4V20C4 20.5304 4.21071 21.0391 4.58579 21.4142C4.96086 21.7893 5.46957 22 6 22H18C18.5304 22 19.0391 21.7893 19.4142 21.4142C19.7893 21.0391 20 20.5304 20 20V7.5L14.5 2Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M14 2V8H20" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 17C13.1046 17 14 16.1046 14 15C14 13.8954 13.1046 13 12 13C10.8954 13 10 13.8954 10 15C10 16.1046 10.8954 17 12 17Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 12V13" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 17V18" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M14.6 13.5L13.73 14" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.27 16L9.40002 16.5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M14.6 16.5L13.73 16" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.27 14L9.40002 13.5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
3
client/images/controls/folder-open.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6 14L7.45 11.1C7.61696 10.7687 7.87281 10.4903 8.18893 10.296C8.50504 10.1018 8.86897 9.99927 9.24 10H20C20.3055 9.99946 20.6071 10.0689 20.8816 10.2031C21.1561 10.3372 21.3963 10.5325 21.5836 10.7739C21.7709 11.0152 21.9004 11.2963 21.9622 11.5956C22.024 11.8948 22.0164 12.2042 21.94 12.5L20.39 18.5C20.279 18.9299 20.0281 19.3106 19.6769 19.5822C19.3256 19.8538 18.894 20.0008 18.45 20H4C3.46957 20 2.96086 19.7893 2.58579 19.4142C2.21071 19.0391 2 18.5304 2 18V5C2 3.9 2.9 3 4 3H7.93C8.25941 3.0017 8.58331 3.08475 8.8729 3.24176C9.1625 3.39877 9.40882 3.62488 9.59 3.9L10.41 5.1C10.5912 5.37512 10.8375 5.60123 11.1271 5.75824C11.4167 5.91525 11.7406 5.9983 12.07 6H18C18.5304 6 19.0391 6.21071 19.4142 6.58579C19.7893 6.96086 20 7.46957 20 8V10" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 948 B |
4
client/images/controls/github.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M15 22V18C15.1392 16.7473 14.78 15.4901 14 14.5C17 14.5 20 12.5 20 9C20.08 7.75 19.73 6.52 19 5.5C19.28 4.35 19.28 3.15 19 2C19 2 18 2 16 3.5C13.36 3 10.64 3 8.00004 3.5C6.00004 2 5.00004 2 5.00004 2C4.70004 3.15 4.70004 4.35 5.00004 5.5C4.27191 6.51588 3.91851 7.75279 4.00004 9C4.00004 12.5 7.00004 14.5 10 14.5C9.61004 14.99 9.32004 15.55 9.15004 16.15C8.98004 16.75 8.93004 17.38 9.00004 18V22" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M9 18C4.49 20 4 16 2 16" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 711 B |
4
client/images/controls/home.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M3 9L12 2L21 9V20C21 20.5304 20.7893 21.0391 20.4142 21.4142C20.0391 21.7893 19.5304 22 19 22H5C4.46957 22 3.96086 21.7893 3.58579 21.4142C3.21071 21.0391 3 20.5304 3 20V9Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M9 22V12H15V22" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 477 B |
4
client/images/controls/mail.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20 4H4C2.89543 4 2 4.89543 2 6V18C2 19.1046 2.89543 20 4 20H20C21.1046 20 22 19.1046 22 18V6C22 4.89543 21.1046 4 20 4Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M22 7L13.03 12.7C12.7213 12.8934 12.3643 12.996 12 12.996C11.6357 12.996 11.2787 12.8934 10.97 12.7L2 7" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 514 B |
5
client/images/controls/more-vertical.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 6C12.5523 6 13 5.55228 13 5C13 4.44772 12.5523 4 12 4C11.4477 4 11 4.44772 11 5C11 5.55228 11.4477 6 12 6Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 20C12.5523 20 13 19.5523 13 19C13 18.4477 12.5523 18 12 18C11.4477 18 11 18.4477 11 19C11 19.5523 11.4477 20 12 20Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 733 B |
4
client/images/controls/plus.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12 5V19" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M5 12H19" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 307 B |
14
client/images/controls/qr-code.svg
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7 3H4C3.44772 3 3 3.44772 3 4V7C3 7.55228 3.44772 8 4 8H7C7.55228 8 8 7.55228 8 7V4C8 3.44772 7.55228 3 7 3Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M20 3H17C16.4477 3 16 3.44772 16 4V7C16 7.55228 16.4477 8 17 8H20C20.5523 8 21 7.55228 21 7V4C21 3.44772 20.5523 3 20 3Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7 16H4C3.44772 16 3 16.4477 3 17V20C3 20.5523 3.44772 21 4 21H7C7.55228 21 8 20.5523 8 20V17C8 16.4477 7.55228 16 7 16Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M21 16H18C17.4696 16 16.9609 16.2107 16.5858 16.5858C16.2107 16.9609 16 17.4696 16 18V21" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M21 21V21.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 7V10C12 10.5304 11.7893 11.0391 11.4142 11.4142C11.0391 11.7893 10.5304 12 10 12H7" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M3 12H3.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 3H12.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 16V16.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M16 12H17" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M21 12V12.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 21V20" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
BIN
client/images/controls/radio-button-inner-circle-pressed.png
Normal file
|
After Width: | Height: | Size: 5 KiB |
BIN
client/images/controls/radio-button-inner-circle.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
3
client/images/controls/radio-button-pressed.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="0.5" y="0.5" width="23" height="23" rx="11.5" stroke="#A85809"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 177 B |
3
client/images/controls/radio-button.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="0.5" y="0.5" width="23" height="23" rx="11.5" stroke="#878B91"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 177 B |
7
client/images/controls/radio.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M4.93006 19.0702C3.05535 17.1949 2.0022 14.6518 2.0022 12.0002C2.0022 9.34853 3.05535 6.80545 4.93006 4.93018" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.75993 16.24C7.20263 15.6818 6.76087 15.0191 6.45993 14.29C5.85157 12.8205 5.85157 11.1695 6.45993 9.7C6.76087 8.97087 7.20263 8.30823 7.75993 7.75" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M16.24 7.75977C16.8028 8.33271 17.2449 9.01281 17.54 9.75977C18.1483 11.2293 18.1483 12.8802 17.54 14.3498C17.2391 15.0789 16.7973 15.7415 16.24 16.2998" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M19.0701 4.93018C20.9448 6.80545 21.9979 9.34853 21.9979 12.0002C21.9979 14.6518 20.9448 17.1949 19.0701 19.0702" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 491 B |
|
Before Width: | Height: | Size: 624 B |
5
client/images/controls/save.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V5C3 4.46957 3.21071 3.96086 3.58579 3.58579C3.96086 3.21071 4.46957 3 5 3H16L21 8V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M17 21V13H7V21" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7 3V8H15" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 652 B |
6
client/images/controls/server.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20 2H4C2.89543 2 2 2.89543 2 4V8C2 9.10457 2.89543 10 4 10H20C21.1046 10 22 9.10457 22 8V4C22 2.89543 21.1046 2 20 2Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M20 14H4C2.89543 14 2 14.8954 2 16V20C2 21.1046 2.89543 22 4 22H20C21.1046 22 22 21.1046 22 20V16C22 14.8954 21.1046 14 20 14Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M6 6H6.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M6 18H6.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 742 B |
6
client/images/controls/settings-2.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20 7H11" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M14 17H5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M17 20C18.6569 20 20 18.6569 20 17C20 15.3431 18.6569 14 17 14C15.3431 14 14 15.3431 14 17C14 18.6569 15.3431 20 17 20Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7 10C8.65685 10 10 8.65685 10 7C10 5.34315 8.65685 4 7 4C5.34315 4 4 5.34315 4 7C4 8.65685 5.34315 10 7 10Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 722 B |
4
client/images/controls/settings.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12.22 2H11.78C11.2496 2 10.7409 2.21071 10.3658 2.58579C9.99072 2.96086 9.78 3.46957 9.78 4V4.18C9.77964 4.53073 9.68706 4.87519 9.51154 5.17884C9.33602 5.48248 9.08374 5.73464 8.78 5.91L8.35 6.16C8.04596 6.33554 7.70108 6.42795 7.35 6.42795C6.99893 6.42795 6.65404 6.33554 6.35 6.16L6.2 6.08C5.74107 5.81526 5.19584 5.74344 4.684 5.88031C4.17217 6.01717 3.73555 6.35154 3.47 6.81L3.25 7.19C2.98526 7.64893 2.91345 8.19416 3.05031 8.706C3.18717 9.21783 3.52154 9.65445 3.98 9.92L4.13 10.02C4.43228 10.1945 4.68362 10.4451 4.85905 10.7468C5.03448 11.0486 5.1279 11.391 5.13 11.74V12.25C5.1314 12.6024 5.03965 12.949 4.86405 13.2545C4.68844 13.5601 4.43521 13.8138 4.13 13.99L3.98 14.08C3.52154 14.3456 3.18717 14.7822 3.05031 15.294C2.91345 15.8058 2.98526 16.3511 3.25 16.81L3.47 17.19C3.73555 17.6485 4.17217 17.9828 4.684 18.1197C5.19584 18.2566 5.74107 18.1847 6.2 17.92L6.35 17.84C6.65404 17.6645 6.99893 17.5721 7.35 17.5721C7.70108 17.5721 8.04596 17.6645 8.35 17.84L8.78 18.09C9.08374 18.2654 9.33602 18.5175 9.51154 18.8212C9.68706 19.1248 9.77964 19.4693 9.78 19.82V20C9.78 20.5304 9.99072 21.0391 10.3658 21.4142C10.7409 21.7893 11.2496 22 11.78 22H12.22C12.7504 22 13.2591 21.7893 13.6342 21.4142C14.0093 21.0391 14.22 20.5304 14.22 20V19.82C14.2204 19.4693 14.3129 19.1248 14.4885 18.8212C14.664 18.5175 14.9163 18.2654 15.22 18.09L15.65 17.84C15.954 17.6645 16.2989 17.5721 16.65 17.5721C17.0011 17.5721 17.346 17.6645 17.65 17.84L17.8 17.92C18.2589 18.1847 18.8042 18.2566 19.316 18.1197C19.8278 17.9828 20.2645 17.6485 20.53 17.19L20.75 16.8C21.0147 16.3411 21.0866 15.7958 20.9497 15.284C20.8128 14.7722 20.4785 14.3356 20.02 14.07L19.87 13.99C19.5648 13.8138 19.3116 13.5601 19.136 13.2545C18.9604 12.949 18.8686 12.6024 18.87 12.25V11.75C18.8686 11.3976 18.9604 11.051 19.136 10.7455C19.3116 10.4399 19.5648 10.1862 19.87 10.01L20.02 9.92C20.4785 9.65445 20.8128 9.21783 20.9497 8.706C21.0866 8.19416 21.0147 7.64893 20.75 7.19L20.53 6.81C20.2645 6.35154 19.8278 6.01717 19.316 5.88031C18.8042 5.74344 18.2589 5.81526 17.8 6.08L17.65 6.16C17.346 6.33554 17.0011 6.42795 16.65 6.42795C16.2989 6.42795 15.954 6.33554 15.65 6.16L15.22 5.91C14.9163 5.73464 14.664 5.48248 14.4885 5.17884C14.3129 4.87519 14.2204 4.53073 14.22 4.18V4C14.22 3.46957 14.0093 2.96086 13.6342 2.58579C13.2591 2.21071 12.7504 2 12.22 2V2Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
7
client/images/controls/share-2.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M18 8C19.6569 8 21 6.65685 21 5C21 3.34315 19.6569 2 18 2C16.3431 2 15 3.34315 15 5C15 6.65685 16.3431 8 18 8Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M6 15C7.65685 15 9 13.6569 9 12C9 10.3431 7.65685 9 6 9C4.34315 9 3 10.3431 3 12C3 13.6569 4.34315 15 6 15Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M18 22C19.6569 22 21 20.6569 21 19C21 17.3431 19.6569 16 18 16C16.3431 16 15 17.3431 15 19C15 20.6569 16.3431 22 18 22Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M8.58997 13.5098L15.42 17.4898" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M15.41 6.50977L8.58997 10.4898" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 969 B |
3
client/images/controls/telegram.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.44009 10.8882C8.78796 8.6139 12.3627 7.1439 14.1358 6.42277C19.2263 4.37033 20.2844 4.00977 20.9708 4.00977C21.1138 4.00977 21.457 4.0375 21.6857 4.20392C21.8573 4.34259 21.9145 4.53674 21.9431 4.67542C21.9717 4.8141 22.0003 5.11919 21.9717 5.36882C21.6857 8.17012 20.5132 15.0208 19.8841 18.155C19.6267 19.4863 19.1119 19.9301 18.6257 19.9855C17.5676 20.0687 16.7383 19.2921 15.7087 18.6542C14.1072 17.628 13.408 17.1299 11.8351 16.1314C10.0334 14.9665 11.2059 14.3286 12.2355 13.3024C12.4929 13.025 16.9956 8.75257 17.0814 8.36427C17.0814 8.3088 17.11 8.14239 16.9956 8.05918C16.8812 7.97597 16.7383 8.00371 16.6239 8.03145C16.4523 8.05918 13.8784 9.72332 8.87375 12.9961C8.1302 13.4954 7.47244 13.7173 6.87188 13.7173C6.21412 13.7173 4.9558 13.3567 4.01206 13.0516C2.86813 12.691 1.95299 12.4969 2.03878 11.8867C2.12458 11.5539 2.58215 11.2211 3.44009 10.8882Z" stroke="#D7D8DB" stroke-width="2"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1 KiB |
5
client/images/controls/text-cursor.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17 22H16C14.9391 22 13.9217 21.5786 13.1716 20.8284C12.4214 20.0783 12 19.0609 12 18V6C12 4.93913 12.4214 3.92172 13.1716 3.17157C13.9217 2.42143 14.9391 2 16 2H17" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7 22H8C9.06087 22 10.0783 21.5786 10.8284 20.8284C11.5786 20.0783 12 19.0609 12 18V17" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7 2H8C9.06087 2 10.0783 2.42143 10.8284 3.17157C11.5786 3.92172 12 4.93913 12 6V7" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 717 B |
5
client/images/controls/trash.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M3 6H21" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M19 6V20C19 21 18 22 17 22H7C6 22 5 21 5 20V6" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M8 6V4C8 3 9 2 10 2H14C15 2 16 3 16 4V6" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 476 B |
5
client/images/controls/x-circle.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M15 9L9 15" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M9 9L15 15" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 518 B |
|
|
@ -58,7 +58,7 @@ target_link_libraries(networkextension PRIVATE ${FW_UI_KIT})
|
||||||
target_compile_options(networkextension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\")
|
target_compile_options(networkextension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\")
|
||||||
target_compile_options(networkextension PRIVATE -DNETWORK_EXTENSION=1)
|
target_compile_options(networkextension PRIVATE -DNETWORK_EXTENSION=1)
|
||||||
|
|
||||||
set(WG_APPLE_SOURCE_DIR ${CLIENT_ROOT_DIR}/3rd/wireguard-apple/Sources)
|
set(WG_APPLE_SOURCE_DIR ${CLIENT_ROOT_DIR}/3rd/awg-apple/Sources)
|
||||||
|
|
||||||
target_sources(networkextension PRIVATE
|
target_sources(networkextension PRIVATE
|
||||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/WireGuardAdapter.swift
|
${WG_APPLE_SOURCE_DIR}/WireGuardKit/WireGuardAdapter.swift
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "wireguard-go-version.h"
|
#include "wireguard-go-version.h"
|
||||||
#include "3rd/wireguard-apple/Sources/WireGuardKitGo/wireguard.h"
|
#include "3rd/awg-apple/Sources/WireGuardKitGo/wireguard.h"
|
||||||
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
|
#include "3rd/awg-apple/Sources/WireGuardKitC/WireGuardKitC.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "wireguard-go-version.h"
|
#include "wireguard-go-version.h"
|
||||||
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
|
#include "3rd/awg-apple/Sources/WireGuardKitC/WireGuardKitC.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#include "macos/gobridge/wireguard.h"
|
#include "macos/gobridge/wireguard.h"
|
||||||
#include "wireguard-go-version.h"
|
#include "wireguard-go-version.h"
|
||||||
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
|
#include "3rd/awg-apple/Sources/WireGuardKitC/WireGuardKitC.h"
|
||||||
#include "3rd/ShadowSocks/ShadowSocks/ShadowSocks.h"
|
#include "3rd/ShadowSocks/ShadowSocks/ShadowSocks.h"
|
||||||
#include "platforms/ios/ssconnectivity.h"
|
#include "platforms/ios/ssconnectivity.h"
|
||||||
#include "platforms/ios/iosopenvpn2ssadapter.h"
|
#include "platforms/ios/iosopenvpn2ssadapter.h"
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,19 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "amnezia_application.h"
|
#include "amnezia_application.h"
|
||||||
#include "version.h"
|
|
||||||
#include "migrations.h"
|
#include "migrations.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include "Windows.h"
|
#include "Windows.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_IOS)
|
#if defined(Q_OS_IOS)
|
||||||
#include "platforms/ios/QtAppDelegate-C-Interface.h"
|
#include "platforms/ios/QtAppDelegate-C-Interface.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
Migrations migrationsManager;
|
Migrations migrationsManager;
|
||||||
|
|
@ -27,16 +26,19 @@ int main(int argc, char *argv[])
|
||||||
AllowSetForegroundWindow(ASFW_ANY);
|
AllowSetForegroundWindow(ASFW_ANY);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// QTBUG-95974 QTBUG-95764 QTBUG-102168
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
qputenv("QT_ANDROID_DISABLE_ACCESSIBILITY", "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
AmneziaApplication app(argc, argv);
|
AmneziaApplication app(argc, argv);
|
||||||
#else
|
#else
|
||||||
AmneziaApplication app(argc, argv, true, SingleApplication::Mode::User | SingleApplication::Mode::SecondaryNotification);
|
AmneziaApplication app(argc, argv, true,
|
||||||
|
SingleApplication::Mode::User | SingleApplication::Mode::SecondaryNotification);
|
||||||
|
|
||||||
if (!app.isPrimary()) {
|
if (!app.isPrimary()) {
|
||||||
QTimer::singleShot(1000, &app, [&](){
|
QTimer::singleShot(1000, &app, [&]() { app.quit(); });
|
||||||
app.quit();
|
|
||||||
});
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -56,13 +58,16 @@ int main(int argc, char *argv[])
|
||||||
app.setOrganizationName(ORGANIZATION_NAME);
|
app.setOrganizationName(ORGANIZATION_NAME);
|
||||||
app.setApplicationDisplayName(APPLICATION_NAME);
|
app.setApplicationDisplayName(APPLICATION_NAME);
|
||||||
|
|
||||||
app.loadTranslator();
|
|
||||||
app.loadFonts();
|
app.loadFonts();
|
||||||
|
|
||||||
bool doExec = app.parseCommands();
|
bool doExec = app.parseCommands();
|
||||||
|
|
||||||
if (doExec) {
|
if (doExec) {
|
||||||
app.init();
|
app.init();
|
||||||
|
|
||||||
|
qInfo().noquote() << QString("Started %1 version %2").arg(APPLICATION_NAME, APP_VERSION);
|
||||||
|
qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture());
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,9 @@ void LocalSocketController::daemonConnected() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||||
QJsonObject wgConfig = rawConfig.value("wireguard_config_data").toObject();
|
QString protocolName = rawConfig.value("protocol").toString();
|
||||||
|
|
||||||
|
QJsonObject wgConfig = rawConfig.value(protocolName + "_config_data").toObject();
|
||||||
|
|
||||||
QJsonObject json;
|
QJsonObject json;
|
||||||
json.insert("type", "activate");
|
json.insert("type", "activate");
|
||||||
|
|
@ -160,6 +162,19 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||||
// splitTunnelApps.append(QJsonValue(uri));
|
// splitTunnelApps.append(QJsonValue(uri));
|
||||||
// }
|
// }
|
||||||
// json.insert("vpnDisabledApps", splitTunnelApps);
|
// json.insert("vpnDisabledApps", splitTunnelApps);
|
||||||
|
|
||||||
|
if (protocolName == amnezia::config_key::awg) {
|
||||||
|
json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount));
|
||||||
|
json.insert(amnezia::config_key::junkPacketMinSize, wgConfig.value(amnezia::config_key::junkPacketMinSize));
|
||||||
|
json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize));
|
||||||
|
json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize));
|
||||||
|
json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize));
|
||||||
|
json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader));
|
||||||
|
json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
|
||||||
|
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
|
||||||
|
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
|
||||||
|
}
|
||||||
|
|
||||||
write(json);
|
write(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,6 +190,7 @@ void LocalSocketController::deactivate() {
|
||||||
QJsonObject json;
|
QJsonObject json;
|
||||||
json.insert("type", "deactivate");
|
json.insert("type", "deactivate");
|
||||||
write(json);
|
write(json);
|
||||||
|
emit disconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalSocketController::checkStatus() {
|
void LocalSocketController::checkStatus() {
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,16 @@
|
||||||
|
|
||||||
#include "android_controller.h"
|
#include "android_controller.h"
|
||||||
#include "private/qandroidextras_p.h"
|
#include "private/qandroidextras_p.h"
|
||||||
#include "ui/pages_logic/StartPageLogic.h"
|
|
||||||
|
|
||||||
#include "androidvpnactivity.h"
|
|
||||||
#include "androidutils.h"
|
#include "androidutils.h"
|
||||||
|
#include "androidvpnactivity.h"
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
AndroidController* s_instance = nullptr;
|
{
|
||||||
|
AndroidController *s_instance = nullptr;
|
||||||
|
|
||||||
constexpr auto PERMISSIONHELPER_CLASS =
|
constexpr auto PERMISSIONHELPER_CLASS = "org/amnezia/vpn/qt/VPNPermissionHelper";
|
||||||
"org/amnezia/vpn/qt/VPNPermissionHelper";
|
} // namespace
|
||||||
} // namespace
|
|
||||||
|
|
||||||
AndroidController::AndroidController() : QObject()
|
AndroidController::AndroidController() : QObject()
|
||||||
{
|
{
|
||||||
|
|
@ -33,109 +32,127 @@ AndroidController::AndroidController() : QObject()
|
||||||
|
|
||||||
auto activity = AndroidVPNActivity::instance();
|
auto activity = AndroidVPNActivity::instance();
|
||||||
|
|
||||||
connect(activity, &AndroidVPNActivity::serviceConnected, this, []() {
|
connect(
|
||||||
qDebug() << "Transact: service connected";
|
activity, &AndroidVPNActivity::serviceConnected, this,
|
||||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_STATISTIC, "");
|
[]() {
|
||||||
}, Qt::QueuedConnection);
|
qDebug() << "Transact: service connected";
|
||||||
|
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_STATISTIC, "");
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(activity, &AndroidVPNActivity::eventInitialized, this,
|
connect(
|
||||||
[this](const QString& parcelBody) {
|
activity, &AndroidVPNActivity::eventInitialized, this,
|
||||||
// We might get multiple Init events as widgets, or fragments
|
[this](const QString &parcelBody) {
|
||||||
// might query this.
|
// We might get multiple Init events as widgets, or fragments
|
||||||
if (m_init) {
|
// might query this.
|
||||||
return;
|
if (m_init) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << "Transact: init";
|
qDebug() << "Transact: init";
|
||||||
|
|
||||||
m_init = true;
|
m_init = true;
|
||||||
|
|
||||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||||
qlonglong time = doc.object()["time"].toVariant().toLongLong();
|
qlonglong time = doc.object()["time"].toVariant().toLongLong();
|
||||||
|
|
||||||
isConnected = doc.object()["connected"].toBool();
|
isConnected = doc.object()["connected"].toBool();
|
||||||
|
|
||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
emit scheduleStatusCheckSignal();
|
emit scheduleStatusCheckSignal();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit initialized(
|
emit initialized(true, isConnected, time > 0 ? QDateTime::fromMSecsSinceEpoch(time) : QDateTime());
|
||||||
true, isConnected,
|
|
||||||
time > 0 ? QDateTime::fromMSecsSinceEpoch(time) : QDateTime());
|
|
||||||
|
|
||||||
setFallbackConnectedNotification();
|
setFallbackConnectedNotification();
|
||||||
}, Qt::QueuedConnection);
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(activity, &AndroidVPNActivity::eventConnected, this,
|
connect(
|
||||||
[this](const QString& parcelBody) {
|
activity, &AndroidVPNActivity::eventConnected, this,
|
||||||
Q_UNUSED(parcelBody);
|
[this](const QString &parcelBody) {
|
||||||
qDebug() << "Transact: connected";
|
Q_UNUSED(parcelBody);
|
||||||
|
qDebug() << "Transact: connected";
|
||||||
|
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
emit scheduleStatusCheckSignal();
|
emit scheduleStatusCheckSignal();
|
||||||
}
|
}
|
||||||
|
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
|
|
||||||
emit connectionStateChanged(VpnProtocol::Connected);
|
emit connectionStateChanged(Vpn::ConnectionState::Connected);
|
||||||
}, Qt::QueuedConnection);
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(activity, &AndroidVPNActivity::eventDisconnected, this,
|
connect(
|
||||||
[this]() {
|
activity, &AndroidVPNActivity::eventDisconnected, this,
|
||||||
qDebug() << "Transact: disconnected";
|
[this]() {
|
||||||
|
qDebug() << "Transact: disconnected";
|
||||||
|
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
|
|
||||||
emit connectionStateChanged(VpnProtocol::Disconnected);
|
emit connectionStateChanged(Vpn::ConnectionState::Disconnected);
|
||||||
}, Qt::QueuedConnection);
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(activity, &AndroidVPNActivity::eventStatisticUpdate, this,
|
connect(
|
||||||
[this](const QString& parcelBody) {
|
activity, &AndroidVPNActivity::eventStatisticUpdate, this,
|
||||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
[this](const QString &parcelBody) {
|
||||||
|
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||||
|
|
||||||
QString rx = doc.object()["rx_bytes"].toString();
|
QString rx = doc.object()["rx_bytes"].toString();
|
||||||
QString tx = doc.object()["tx_bytes"].toString();
|
QString tx = doc.object()["tx_bytes"].toString();
|
||||||
QString endpoint = doc.object()["endpoint"].toString();
|
QString endpoint = doc.object()["endpoint"].toString();
|
||||||
QString deviceIPv4 = doc.object()["deviceIpv4"].toString();
|
QString deviceIPv4 = doc.object()["deviceIpv4"].toString();
|
||||||
|
|
||||||
emit statusUpdated(rx, tx, endpoint, deviceIPv4);
|
emit statusUpdated(rx, tx, endpoint, deviceIPv4);
|
||||||
}, Qt::QueuedConnection);
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(activity, &AndroidVPNActivity::eventBackendLogs, this,
|
connect(
|
||||||
[this](const QString& parcelBody) {
|
activity, &AndroidVPNActivity::eventBackendLogs, this,
|
||||||
qDebug() << "Transact: backend logs";
|
[this](const QString &parcelBody) {
|
||||||
|
qDebug() << "Transact: backend logs";
|
||||||
|
|
||||||
QString buffer = parcelBody.toUtf8();
|
QString buffer = parcelBody.toUtf8();
|
||||||
if (m_logCallback) {
|
if (m_logCallback) {
|
||||||
m_logCallback(buffer);
|
m_logCallback(buffer);
|
||||||
}
|
}
|
||||||
}, Qt::QueuedConnection);
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(activity, &AndroidVPNActivity::eventActivationError, this,
|
connect(
|
||||||
[this](const QString& parcelBody) {
|
activity, &AndroidVPNActivity::eventActivationError, this,
|
||||||
Q_UNUSED(parcelBody)
|
[this](const QString &parcelBody) {
|
||||||
qDebug() << "Transact: error";
|
Q_UNUSED(parcelBody)
|
||||||
emit connectionStateChanged(VpnProtocol::Error);
|
qDebug() << "Transact: error";
|
||||||
}, Qt::QueuedConnection);
|
emit connectionStateChanged(Vpn::ConnectionState::Error);
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(activity, &AndroidVPNActivity::eventConfigImport, this,
|
connect(
|
||||||
[this](const QString& parcelBody) {
|
activity, &AndroidVPNActivity::eventConfigImport, this,
|
||||||
qDebug() << "Transact: config import";
|
[this](const QString &parcelBody) {
|
||||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
qDebug() << "Transact: config import";
|
||||||
|
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||||
|
|
||||||
QString buffer = doc.object()["config"].toString();
|
QString buffer = doc.object()["config"].toString();
|
||||||
qDebug() << "Transact: config string" << buffer;
|
qDebug() << "Transact: config string" << buffer;
|
||||||
importConfig(buffer);
|
importConfigFromOutside(buffer);
|
||||||
}, Qt::QueuedConnection);
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(activity, &AndroidVPNActivity::serviceDisconnected, this,
|
connect(
|
||||||
[this]() {
|
activity, &AndroidVPNActivity::serviceDisconnected, this,
|
||||||
qDebug() << "Transact: service disconnected";
|
[this]() {
|
||||||
m_serviceConnected = false;
|
qDebug() << "Transact: service disconnected";
|
||||||
}, Qt::QueuedConnection);
|
m_serviceConnected = false;
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidController* AndroidController::instance() {
|
AndroidController *AndroidController::instance()
|
||||||
|
{
|
||||||
if (!s_instance) {
|
if (!s_instance) {
|
||||||
s_instance = new AndroidController();
|
s_instance = new AndroidController();
|
||||||
}
|
}
|
||||||
|
|
@ -143,16 +160,13 @@ AndroidController* AndroidController::instance() {
|
||||||
return s_instance;
|
return s_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidController::initialize(StartPageLogic *startPageLogic)
|
bool AndroidController::initialize()
|
||||||
{
|
{
|
||||||
qDebug() << "Initializing";
|
qDebug() << "Initializing";
|
||||||
|
|
||||||
m_startPageLogic = startPageLogic;
|
|
||||||
|
|
||||||
// Hook in the native implementation for startActivityForResult into the JNI
|
// Hook in the native implementation for startActivityForResult into the JNI
|
||||||
JNINativeMethod methods[]{{"startActivityForResult",
|
JNINativeMethod methods[] { { "startActivityForResult", "(Landroid/content/Intent;)V",
|
||||||
"(Landroid/content/Intent;)V",
|
reinterpret_cast<void *>(startActivityForResult) } };
|
||||||
reinterpret_cast<void*>(startActivityForResult)}};
|
|
||||||
QJniObject javaClass(PERMISSIONHELPER_CLASS);
|
QJniObject javaClass(PERMISSIONHELPER_CLASS);
|
||||||
QJniEnvironment env;
|
QJniEnvironment env;
|
||||||
jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
|
jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
|
||||||
|
|
@ -168,11 +182,9 @@ ErrorCode AndroidController::start()
|
||||||
{
|
{
|
||||||
qDebug() << "Prompting for VPN permission";
|
qDebug() << "Prompting for VPN permission";
|
||||||
QJniObject activity = AndroidUtils::getActivity();
|
QJniObject activity = AndroidUtils::getActivity();
|
||||||
auto appContext = activity.callObjectMethod(
|
auto appContext = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
|
||||||
"getApplicationContext", "()Landroid/content/Context;");
|
QJniObject::callStaticMethod<void>(PERMISSIONHELPER_CLASS, "startService", "(Landroid/content/Context;)V",
|
||||||
QJniObject::callStaticMethod<void>(
|
appContext.object());
|
||||||
PERMISSIONHELPER_CLASS, "startService", "(Landroid/content/Context;)V",
|
|
||||||
appContext.object());
|
|
||||||
|
|
||||||
QJsonDocument doc(m_vpnConfig);
|
QJsonDocument doc(m_vpnConfig);
|
||||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_ACTIVATE, doc.toJson());
|
AndroidVPNActivity::sendToService(ServiceAction::ACTION_ACTIVATE, doc.toJson());
|
||||||
|
|
@ -180,7 +192,8 @@ ErrorCode AndroidController::start()
|
||||||
return NoError;
|
return NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidController::stop() {
|
void AndroidController::stop()
|
||||||
|
{
|
||||||
qDebug() << "AndroidController::stop";
|
qDebug() << "AndroidController::stop";
|
||||||
|
|
||||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_DEACTIVATE, QString());
|
AndroidVPNActivity::sendToService(ServiceAction::ACTION_DEACTIVATE, QString());
|
||||||
|
|
@ -188,16 +201,16 @@ void AndroidController::stop() {
|
||||||
|
|
||||||
// Activates the tunnel that is currently set
|
// Activates the tunnel that is currently set
|
||||||
// in the VPN Service
|
// in the VPN Service
|
||||||
void AndroidController::resumeStart() {
|
void AndroidController::resumeStart()
|
||||||
|
{
|
||||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_RESUME_ACTIVATE, QString());
|
AndroidVPNActivity::sendToService(ServiceAction::ACTION_RESUME_ACTIVATE, QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sets the current notification text that is shown
|
* Sets the current notification text that is shown
|
||||||
*/
|
*/
|
||||||
void AndroidController::setNotificationText(const QString& title,
|
void AndroidController::setNotificationText(const QString &title, const QString &message, int timerSec)
|
||||||
const QString& message,
|
{
|
||||||
int timerSec) {
|
|
||||||
QJsonObject args;
|
QJsonObject args;
|
||||||
args["title"] = title;
|
args["title"] = title;
|
||||||
args["message"] = message;
|
args["message"] = message;
|
||||||
|
|
@ -207,7 +220,8 @@ void AndroidController::setNotificationText(const QString& title,
|
||||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_SET_NOTIFICATION_TEXT, doc.toJson());
|
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);
|
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
|
* switches into the Connected state without the app open
|
||||||
* e.g via always-on vpn
|
* e.g via always-on vpn
|
||||||
*/
|
*/
|
||||||
void AndroidController::setFallbackConnectedNotification() {
|
void AndroidController::setFallbackConnectedNotification()
|
||||||
|
{
|
||||||
QJsonObject args;
|
QJsonObject args;
|
||||||
args["title"] = tr("AmneziaVPN");
|
args["title"] = tr("AmneziaVPN");
|
||||||
//% "Ready for you to connect"
|
//% "Ready for you to connect"
|
||||||
|
|
@ -227,11 +242,13 @@ void AndroidController::setFallbackConnectedNotification() {
|
||||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_SET_NOTIFICATION_FALLBACK, doc.toJson());
|
AndroidVPNActivity::sendToService(ServiceAction::ACTION_SET_NOTIFICATION_FALLBACK, doc.toJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidController::checkStatus() {
|
void AndroidController::checkStatus()
|
||||||
|
{
|
||||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_STATISTIC, QString());
|
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";
|
qDebug() << "get logs";
|
||||||
|
|
||||||
m_logCallback = std::move(a_callback);
|
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());
|
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_GET_LOG, QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidController::cleanupBackendLogs() {
|
void AndroidController::cleanupBackendLogs()
|
||||||
|
{
|
||||||
qDebug() << "cleanup logs";
|
qDebug() << "cleanup logs";
|
||||||
|
|
||||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_CLEANUP_LOG, QString());
|
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_CLEANUP_LOG, QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidController::importConfig(const QString& data){
|
|
||||||
m_startPageLogic->importAnyFile(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QJsonObject &AndroidController::vpnConfig() const
|
const QJsonObject &AndroidController::vpnConfig() const
|
||||||
{
|
{
|
||||||
return m_vpnConfig;
|
return m_vpnConfig;
|
||||||
|
|
@ -285,31 +299,29 @@ void AndroidController::startActivityForResult(JNIEnv *env, jobject, jobject int
|
||||||
qDebug() << "start vpnPermissionHelper";
|
qDebug() << "start vpnPermissionHelper";
|
||||||
Q_UNUSED(env);
|
Q_UNUSED(env);
|
||||||
|
|
||||||
QtAndroidPrivate::startActivity(intent, 1337,
|
QtAndroidPrivate::startActivity(intent, 1337, [](int receiverRequestCode, int resultCode, const QJniObject &data) {
|
||||||
[](int receiverRequestCode, int resultCode,
|
// Currently this function just used in
|
||||||
const QJniObject& data) {
|
// VPNService.kt::checkPermissions. So the result
|
||||||
// Currently this function just used in
|
// we're getting is if the User gave us the
|
||||||
// VPNService.kt::checkPermissions. So the result
|
// Vpn.bind permission. In case of NO we should
|
||||||
// we're getting is if the User gave us the
|
// abort.
|
||||||
// Vpn.bind permission. In case of NO we should
|
Q_UNUSED(receiverRequestCode);
|
||||||
// abort.
|
Q_UNUSED(data);
|
||||||
Q_UNUSED(receiverRequestCode);
|
|
||||||
Q_UNUSED(data);
|
|
||||||
|
|
||||||
AndroidController* controller = AndroidController::instance();
|
AndroidController *controller = AndroidController::instance();
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultCode == ACTIVITY_RESULT_OK) {
|
if (resultCode == ACTIVITY_RESULT_OK) {
|
||||||
qDebug() << "VPN PROMPT RESULT - Accepted";
|
qDebug() << "VPN PROMPT RESULT - Accepted";
|
||||||
controller->resumeStart();
|
controller->resumeStart();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// If the request got rejected abort the current
|
// If the request got rejected abort the current
|
||||||
// connection.
|
// connection.
|
||||||
qWarning() << "VPN PROMPT RESULT - Rejected";
|
qWarning() << "VPN PROMPT RESULT - Rejected";
|
||||||
emit controller->connectionStateChanged(VpnProtocol::Disconnected);
|
emit controller->connectionStateChanged(Vpn::ConnectionState::Disconnected);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,36 +8,32 @@
|
||||||
#include <QJniEnvironment>
|
#include <QJniEnvironment>
|
||||||
#include <QJniObject>
|
#include <QJniObject>
|
||||||
|
|
||||||
#include "ui/pages_logic/StartPageLogic.h"
|
|
||||||
|
|
||||||
#include "protocols/vpnprotocol.h"
|
#include "protocols/vpnprotocol.h"
|
||||||
|
|
||||||
using namespace amnezia;
|
using namespace amnezia;
|
||||||
|
|
||||||
|
|
||||||
class AndroidController : public QObject
|
class AndroidController : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AndroidController();
|
explicit AndroidController();
|
||||||
static AndroidController* instance();
|
static AndroidController *instance();
|
||||||
|
|
||||||
virtual ~AndroidController() override = default;
|
virtual ~AndroidController() override = default;
|
||||||
|
|
||||||
bool initialize(StartPageLogic *startPageLogic);
|
bool initialize();
|
||||||
|
|
||||||
ErrorCode start();
|
ErrorCode start();
|
||||||
void stop();
|
void stop();
|
||||||
void resumeStart();
|
void resumeStart();
|
||||||
|
|
||||||
void checkStatus();
|
void checkStatus();
|
||||||
void setNotificationText(const QString& title, const QString& message, int timerSec);
|
void setNotificationText(const QString &title, const QString &message, int timerSec);
|
||||||
void shareConfig(const QString& data, const QString& suggestedName);
|
void shareConfig(const QString &data, const QString &suggestedName);
|
||||||
void setFallbackConnectedNotification();
|
void setFallbackConnectedNotification();
|
||||||
void getBackendLogs(std::function<void(const QString&)>&& callback);
|
void getBackendLogs(std::function<void(const QString &)> &&callback);
|
||||||
void cleanupBackendLogs();
|
void cleanupBackendLogs();
|
||||||
void importConfig(const QString& data);
|
|
||||||
|
|
||||||
const QJsonObject &vpnConfig() const;
|
const QJsonObject &vpnConfig() const;
|
||||||
void setVpnConfig(const QJsonObject &newVpnConfig);
|
void setVpnConfig(const QJsonObject &newVpnConfig);
|
||||||
|
|
@ -45,18 +41,20 @@ public:
|
||||||
void startQrReaderActivity();
|
void startQrReaderActivity();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void connectionStateChanged(VpnProtocol::VpnConnectionState state);
|
void connectionStateChanged(Vpn::ConnectionState state);
|
||||||
|
|
||||||
// This signal is emitted when the controller is initialized. Note that the
|
// 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
|
// 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
|
// to true and the "connectionDate" should be set to the activation date if
|
||||||
// known.
|
// known.
|
||||||
// If "status" is set to false, the backend service is considered unavailable.
|
// 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 statusUpdated(QString totalRx, QString totalTx, QString endpoint, QString deviceIPv4);
|
||||||
void scheduleStatusCheckSignal();
|
void scheduleStatusCheckSignal();
|
||||||
|
|
||||||
|
void importConfigFromOutside(QString &data);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void scheduleStatusCheckSlot();
|
void scheduleStatusCheckSlot();
|
||||||
|
|
||||||
|
|
@ -65,12 +63,10 @@ private:
|
||||||
|
|
||||||
QJsonObject m_vpnConfig;
|
QJsonObject m_vpnConfig;
|
||||||
|
|
||||||
StartPageLogic *m_startPageLogic;
|
|
||||||
|
|
||||||
bool m_serviceConnected = false;
|
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;
|
bool isConnected = false;
|
||||||
|
|
||||||
|
|
|
||||||