diff --git a/client/client_scripts/mac_installer.sh b/client/client_scripts/mac_installer.sh
new file mode 100644
index 00000000..a572be8e
--- /dev/null
+++ b/client/client_scripts/mac_installer.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+EXTRACT_DIR="$1"
+INSTALLER_PATH="$2"
+
+# Create and clean extract directory
+rm -rf "$EXTRACT_DIR"
+mkdir -p "$EXTRACT_DIR"
+
+# Mount the DMG
+hdiutil attach "$INSTALLER_PATH" -mountpoint "$EXTRACT_DIR/mounted_dmg" -nobrowse -quiet
+if [ $? -ne 0 ]; then
+ echo "Failed to mount DMG"
+ exit 1
+fi
+
+# Copy the app to /Applications
+cp -R "$EXTRACT_DIR/mounted_dmg/AmneziaVPN.app" /Applications/
+if [ $? -ne 0 ]; then
+ echo "Failed to copy AmneziaVPN.app to /Applications"
+ hdiutil detach "$EXTRACT_DIR/mounted_dmg" -quiet
+ exit 1
+fi
+
+# Unmount the DMG
+hdiutil detach "$EXTRACT_DIR/mounted_dmg" -quiet
+if [ $? -ne 0 ]; then
+ echo "Failed to unmount DMG"
+ exit 1
+fi
+
+# Optional: Remove the DMG file
+rm "$INSTALLER_PATH"
+
+echo "Installation completed successfully"
+exit 0
\ No newline at end of file
diff --git a/client/core/scripts_registry.cpp b/client/core/scripts_registry.cpp
index 9b02fba9..d2b17cb9 100644
--- a/client/core/scripts_registry.cpp
+++ b/client/core/scripts_registry.cpp
@@ -58,6 +58,7 @@ QString amnezia::scriptName(ClientScriptType type)
{
switch (type) {
case ClientScriptType::linux_installer: return QLatin1String("linux_installer.sh");
+ case ClientScriptType::mac_installer: return QLatin1String("mac_installer.sh");
default: return QString();
}
}
diff --git a/client/core/scripts_registry.h b/client/core/scripts_registry.h
index 2b4bf087..87fddbb5 100644
--- a/client/core/scripts_registry.h
+++ b/client/core/scripts_registry.h
@@ -35,7 +35,8 @@ namespace amnezia
enum ClientScriptType {
// Client-side scripts
- linux_installer
+ linux_installer,
+ mac_installer
};
QString scriptFolder(DockerContainer container);
diff --git a/client/resources.qrc b/client/resources.qrc
index ae015b9f..4b6689e5 100644
--- a/client/resources.qrc
+++ b/client/resources.qrc
@@ -4,6 +4,7 @@
images/tray/default.png
images/tray/error.png
client_scripts/linux_installer.sh
+ client_scripts/mac_installer.sh
images/AmneziaVPN.png
server_scripts/remove_container.sh
server_scripts/setup_host_firewall.sh
diff --git a/client/ui/controllers/updateController.cpp b/client/ui/controllers/updateController.cpp
index 7eb5c63f..e62ee02f 100644
--- a/client/ui/controllers/updateController.cpp
+++ b/client/ui/controllers/updateController.cpp
@@ -193,9 +193,51 @@ int UpdateController::runWindowsInstaller(const QString &installerPath)
#if defined(Q_OS_MACOS)
int UpdateController::runMacInstaller(const QString &installerPath)
{
- logger.info() << "macOS installer path:" << installerPath;
- // TODO: Implement macOS installation logic
- return -1;
+ // Create temporary directory for extraction
+ QTemporaryDir extractDir;
+ extractDir.setAutoRemove(false);
+ if (!extractDir.isValid()) {
+ logger.error() << "Failed to create temporary directory";
+ return -1;
+ }
+ logger.info() << "Temporary directory created:" << extractDir.path();
+
+ // Create script file in the temporary directory
+ QString scriptPath = extractDir.path() + "/mac_installer.sh";
+ QFile scriptFile(scriptPath);
+ if (!scriptFile.open(QIODevice::WriteOnly)) {
+ logger.error() << "Failed to create script file";
+ return -1;
+ }
+
+ // Get script content from registry
+ QString scriptContent = amnezia::scriptData(amnezia::ClientScriptType::mac_installer);
+ if (scriptContent.isEmpty()) {
+ logger.error() << "macOS installer script content is empty";
+ scriptFile.close();
+ return -1;
+ }
+
+ scriptFile.write(scriptContent.toUtf8());
+ scriptFile.close();
+ logger.info() << "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) {
+ logger.info() << "Installation process started with PID:" << pid;
+ } else {
+ logger.error() << "Failed to start installation process";
+ return -1;
+ }
+
+ return 0;
}
#endif