diff --git a/client/client_scripts/linux_installer.sh b/client/client_scripts/linux_installer.sh new file mode 100644 index 00000000..82987535 --- /dev/null +++ b/client/client_scripts/linux_installer.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +EXTRACT_DIR="$1" +INSTALLER_PATH="$2" + +# Create and clean extract directory +rm -rf "$EXTRACT_DIR" +mkdir -p "$EXTRACT_DIR" + +# Extract ZIP archive +unzip "$INSTALLER_PATH" -d "$EXTRACT_DIR" +if [ $? -ne 0 ]; then + echo 'Failed to extract ZIP archive' + exit 1 +fi + +# Find and extract TAR archive +TAR_FILE=$(find "$EXTRACT_DIR" -name '*.tar' -type f) +if [ -z "$TAR_FILE" ]; then + echo 'TAR file not found' + exit 1 +fi + +tar -xf "$TAR_FILE" -C "$EXTRACT_DIR" +if [ $? -ne 0 ]; then + echo 'Failed to extract TAR archive' + exit 1 +fi + +rm -f "$TAR_FILE" + +# Find and run installer +INSTALLER=$(find "$EXTRACT_DIR" -type f -executable) +if [ -z "$INSTALLER" ]; then + echo 'Installer not found' + exit 1 +fi + +"$INSTALLER" +EXIT_CODE=$? + +# Cleanup +rm -rf "$EXTRACT_DIR" +exit $EXIT_CODE \ No newline at end of file diff --git a/client/core/scripts_registry.cpp b/client/core/scripts_registry.cpp index 95b5df4a..9b02fba9 100644 --- a/client/core/scripts_registry.cpp +++ b/client/core/scripts_registry.cpp @@ -54,6 +54,14 @@ QString amnezia::scriptName(ProtocolScriptType type) } } +QString amnezia::scriptName(ClientScriptType type) +{ + switch (type) { + case ClientScriptType::linux_installer: return QLatin1String("linux_installer.sh"); + default: return QString(); + } +} + QString amnezia::scriptData(amnezia::SharedScriptType type) { QString fileName = QString(":/server_scripts/%1").arg(amnezia::scriptName(type)); @@ -81,3 +89,19 @@ QString amnezia::scriptData(amnezia::ProtocolScriptType type, DockerContainer co data.replace("\r", ""); return data; } + +QString amnezia::scriptData(ClientScriptType type) +{ + QString fileName = QString(":/client_scripts/%1").arg(amnezia::scriptName(type)); + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + qDebug() << "Warning: script missing" << fileName; + return ""; + } + QByteArray data = file.readAll(); + if (data.isEmpty()) { + qDebug() << "Warning: script is empty" << fileName; + } + data.replace("\r", ""); + return data; +} diff --git a/client/core/scripts_registry.h b/client/core/scripts_registry.h index d952dafb..2b4bf087 100644 --- a/client/core/scripts_registry.h +++ b/client/core/scripts_registry.h @@ -1,44 +1,52 @@ #ifndef SCRIPTS_REGISTRY_H #define SCRIPTS_REGISTRY_H -#include -#include "core/defs.h" #include "containers/containers_defs.h" +#include "core/defs.h" +#include -namespace amnezia { +namespace amnezia +{ -enum SharedScriptType { - // General scripts - prepare_host, - install_docker, - build_container, - remove_container, - remove_all_containers, - setup_host_firewall, - check_connection, - check_server_is_busy, - check_user_in_sudo -}; -enum ProtocolScriptType { - // Protocol scripts - dockerfile, - run_container, - configure_container, - container_startup, - openvpn_template, - wireguard_template, - awg_template, - xray_template -}; + enum SharedScriptType { + // General scripts + prepare_host, + install_docker, + build_container, + remove_container, + remove_all_containers, + setup_host_firewall, + check_connection, + check_server_is_busy, + check_user_in_sudo + }; + enum ProtocolScriptType { + // Protocol scripts + dockerfile, + run_container, + configure_container, + container_startup, + openvpn_template, + wireguard_template, + awg_template, + xray_template + }; -QString scriptFolder(DockerContainer container); + enum ClientScriptType { + // Client-side scripts + linux_installer + }; -QString scriptName(SharedScriptType type); -QString scriptName(ProtocolScriptType type); + QString scriptFolder(DockerContainer container); -QString scriptData(SharedScriptType type); -QString scriptData(ProtocolScriptType type, DockerContainer container); + QString scriptName(SharedScriptType type); + QString scriptName(ProtocolScriptType type); + QString scriptName(ClientScriptType type); + + QString scriptData(SharedScriptType type); + QString scriptData(ProtocolScriptType type, DockerContainer container); + QString scriptData(ClientScriptType type); } #endif // SCRIPTS_REGISTRY_H diff --git a/client/ui/controllers/updateController.cpp b/client/ui/controllers/updateController.cpp index 80d04d6a..2888ec2d 100644 --- a/client/ui/controllers/updateController.cpp +++ b/client/ui/controllers/updateController.cpp @@ -7,6 +7,7 @@ #include "amnezia_application.h" #include "core/errorstrings.h" +#include "core/scripts_registry.h" #include "version.h" namespace @@ -121,10 +122,14 @@ void UpdateController::runInstaller() file.write(reply->readAll()); file.close(); QString t = installerPath; - auto ipcReply = IpcClient::Interface()->installApp(t); - ipcReply.waitForFinished(); - int result = ipcReply.returnValue(); +#if defined(Q_OS_WINDOWS) + runWindowsInstaller(t); +#elif defined(Q_OS_MACOS) + runMacInstaller(t); +#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + runLinuxInstaller(t); +#endif // emit errorOccured(""); } } else { @@ -140,7 +145,69 @@ void UpdateController::runInstaller() qDebug() << errorString(ErrorCode::ApiConfigDownloadError); } } - reply->deleteLater(); }); } + +#if defined(Q_OS_WINDOWS) +int UpdateController::runWindowsInstaller(const QString &installerPath) +{ + qDebug() << "Windows installer path:" << installerPath; + // TODO: Implement Windows installation logic + return -1; +} +#endif + +#if defined(Q_OS_MACOS) +int UpdateController::runMacInstaller(const QString &installerPath) +{ + qDebug() << "macOS installer path:" << installerPath; + // TODO: Implement macOS installation logic + return -1; +} +#endif + +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) +int UpdateController::runLinuxInstaller(const QString &installerPath) +{ + // Create temporary directory for extraction + QTemporaryDir extractDir; + extractDir.setAutoRemove(false); + if (!extractDir.isValid()) { + qDebug() << "Failed to create temporary directory"; + return -1; + } + qDebug() << "Temporary directory created:" << extractDir.path(); + + // Create script file in the temporary directory + QString scriptPath = extractDir.path() + "/installer.sh"; + QFile scriptFile(scriptPath); + if (!scriptFile.open(QIODevice::WriteOnly)) { + qDebug() << "Failed to create script file"; + return -1; + } + + // Get script content from registry + QString scriptContent = amnezia::scriptData(amnezia::ClientScriptType::linux_installer); + scriptFile.write(scriptContent.toUtf8()); + scriptFile.close(); + qDebug() << "Script file created:" << scriptPath; + + // Make script executable + QFile::setPermissions(scriptPath, QFile::permissions(scriptPath) | QFile::ExeUser); + + // Start detached process + qint64 pid; + bool success = QProcess::startDetached( + "/bin/bash", QStringList() << scriptPath << extractDir.path() << installerPath, extractDir.path(), &pid); + + if (success) { + qDebug() << "Installation process started with PID:" << pid; + } else { + qDebug() << "Failed to start installation process"; + return -1; + } + + return 0; +} +#endif diff --git a/client/ui/controllers/updateController.h b/client/ui/controllers/updateController.h index ea5c22fa..85b7c48d 100644 --- a/client/ui/controllers/updateController.h +++ b/client/ui/controllers/updateController.h @@ -30,6 +30,14 @@ private: QString m_version; QString m_releaseDate; QString m_downloadUrl; + +#if defined(Q_OS_WINDOWS) + int runWindowsInstaller(const QString &installerPath); +#elif defined(Q_OS_MACOS) + int runMacInstaller(const QString &installerPath); +#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + int runLinuxInstaller(const QString &installerPath); +#endif }; #endif // UPDATECONTROLLER_H