From 8d27403228b0782e135d5c5d5d97ec54785cfae3 Mon Sep 17 00:00:00 2001
From: kali <kali@leap.se>
Date: Fri, 2 Oct 2020 21:31:04 +0200
Subject: [PATCH] [pkg] osx uninstall, autolaunch

---
 Makefile                                      |  1 +
 bitmask.pro                                   |  1 +
 .../templates/qtinstaller/config/config.xml   | 22 ++++--
 .../templates/qtinstaller/osx/post-install.py |  6 +-
 .../templates/qtinstaller/osx/uninstall.py    | 70 +++++++++++++++++++
 .../packages/bitmaskvpn/meta/install.js       | 39 ++++++++---
 6 files changed, 121 insertions(+), 18 deletions(-)
 create mode 100755 branding/templates/qtinstaller/osx/uninstall.py

diff --git a/Makefile b/Makefile
index 440bb4c6..53b3e8da 100644
--- a/Makefile
+++ b/Makefile
@@ -111,6 +111,7 @@ ifeq (${PLATFORM}, darwin)
 	@cp "${TEMPLATES}/osx/client.up.sh" ${OSX_DATA}/
 	@cp "${TEMPLATES}/osx/client.down.sh" ${OSX_DATA}/
 	@cp "${TEMPLATES}/qtinstaller/osx/post-install.py" ${OSX_DATA}/
+	@cp "${TEMPLATES}/qtinstaller/osx/uninstall.py" ${OSX_DATA}/
 	@cp "${TEMPLATES}/qtinstaller/osx/se.leap.bitmask-helper.plist" ${OSX_DATA}/
 	@cp build/bin/${PLATFORM}/bitmask-helper ${OSX_DATA}/
 	# FIXME our static openvpn build fails with an "Assertion failed at crypto.c". Needs to be fixed!!! - kali
diff --git a/bitmask.pro b/bitmask.pro
index efce9ef9..98860e4c 100644
--- a/bitmask.pro
+++ b/bitmask.pro
@@ -8,6 +8,7 @@ QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.12
 
 macx {
     LIBS += -framework Security
+    # TODO -- pass the vendor icon here from Makefile.
     ICON = branding/assets/riseup/icon.icns
 }
 
diff --git a/branding/templates/qtinstaller/config/config.xml b/branding/templates/qtinstaller/config/config.xml
index 94d76b6f..8b28be6b 100644
--- a/branding/templates/qtinstaller/config/config.xml
+++ b/branding/templates/qtinstaller/config/config.xml
@@ -1,22 +1,32 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Installer>
+
     <Name>DemoLibVPN-0.0.1</Name>
     <Version>0.0.1</Version>
     <Title>DemoLibVPN Installer</Title>
     <Publisher>LEAP Encryption Access Project</Publisher>
     <TargetDir>@ApplicationsDir@/DemoLibVPN.app</TargetDir>
-    <RunProgram>@TargetDir@/DemoLibVPN.app</RunProgram>
-    <RunProgramArguments>
-    </RunProgramArguments>
+
     <StartMenuDir>DemoLibVPN.app</StartMenuDir>
     <AllowNonAsciiCharacters>false</AllowNonAsciiCharacters>
+
     <!--
     <RemoteRepositories>
-        <Repository>
-            <Url>http://localhost/repository/</Url>
-        </Repository>
+      <Repository>
+        <Url>http://localhost/repository/</Url>
+      </Repository>
     </RemoteRepositories>
     -->
+
     <MaintenanceToolName>Uninstall-DemoLibVPN</MaintenanceToolName>
+
+    <!-- osx run -->
+    <RunProgram>open</RunProgram>
+    <RunProgramDescription>Start DemoLibVPN now!</RunProgramDescription>
+      <RunProgramArguments>
+        <Argument>@TargetDir@</Argument>
+      </RunProgramArguments>
     <WizardStyle>mac</WizardStyle>
+    <!-- end osx run -->
+
 </Installer>
diff --git a/branding/templates/qtinstaller/osx/post-install.py b/branding/templates/qtinstaller/osx/post-install.py
index 18059aa1..2c158457 100755
--- a/branding/templates/qtinstaller/osx/post-install.py
+++ b/branding/templates/qtinstaller/osx/post-install.py
@@ -12,6 +12,7 @@ import subprocess
 
 HELPER = "bitmask-helper"
 HELPER_PLIST = "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"
+
 _dir = os.path.dirname(os.path.realpath(__file__))
 
 def main():
@@ -73,13 +74,12 @@ def fixHelperOwner(log):
 def copyLaunchDaemon():
     plist = "se.leap.bitmask-helper.plist"
     path = os.path.join(_dir, plist)
-    dest = os.path.join('/Library/LaunchDaemons', plist)
     _p = _dir.replace("/", "\/")
     subprocess.call(["sed", "-i.back", "s/PATH/%s/" % _p, path])
-    shutil.copy(path, dest)
+    shutil.copy(path, HELPER_PLIST)
 
 def launchHelper():
-    out = subprocess.call(["launchctl", "load", "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"])
+    out = subprocess.call(["launchctl", "load", HELPER_PLIST])
     return out == 0
 
 def grantPermissionsOnLogFolder():
diff --git a/branding/templates/qtinstaller/osx/uninstall.py b/branding/templates/qtinstaller/osx/uninstall.py
new file mode 100755
index 00000000..7aa8a563
--- /dev/null
+++ b/branding/templates/qtinstaller/osx/uninstall.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+
+# Uninstall script for BitmaskVPN.
+
+import os
+import shutil
+import sys
+import subprocess
+
+HELPER = "bitmask-helper"
+HELPER_PLIST = "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"
+
+_dir = os.path.dirname(os.path.realpath(__file__))
+
+def main():
+    log = open(os.path.join('/tmp', 'bitmask-uninstall.log'), 'w')
+    log.write('Checking for admin privileges...\n')
+
+    _id = os.getuid()
+    log.write("UID: %s\n" % str(_id))
+    if int(_id) != 0:
+      err  = "error: need to run as root. UID: %s\n" % str(_id)
+      logErr(log, err)
+    
+    # failure: sys.exit(1)
+
+    log.write('Checking if helper is running')
+    
+    if isHelperRunning():
+        log.write("Trying to stop bitmask-helper...\n")
+	# if this fail, we can check if the HELPER_PLIST is there
+        ok = unloadHelper()
+        log.write("success: %s \n" % str(ok))
+
+    log.write("Removing LaunchDaemon")
+    out = removeLaunchDaemon()
+    log.write("result: %s \n" % str(out))
+    
+    # all done
+    log.write('uninstall script: done\n')
+    sys.exit(0)
+
+
+def logErr(log, msg):
+    log.write(msg)
+    sys.exit(1)
+
+def isHelperRunning():
+    ps = _getProcessList()
+    return HELPER in ps 
+
+def unloadHelper():
+    out = subprocess.call(["launchctl", "unload", HELPER_PLIST])
+    out2 = subprocess.call(["pkill", "-9", "bitmask-helper"])  # just in case
+    return out == 0
+
+def removeLaunchDaemon():
+    return subprocess.call(["rm", "-f", HELPER_PLIST])
+
+def _getProcessList():
+    _out = []
+    output = subprocess.Popen(["ps", "-ceA"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    stdout, stderr = output.communicate()
+    for line  in stdout.split('\n'):
+        cmd = line.split(' ')[-1]
+        _out.append(cmd.strip())
+    return _out
+
+if __name__ == "__main__":
+    main()
diff --git a/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js b/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js
index f9c85f2b..0bcaeef4 100644
--- a/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js
+++ b/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js
@@ -27,23 +27,44 @@ Component.prototype.createOperations = function ()
     }
 }
 
+Component.prototype.installationFinished = function()
+{
+    console.log("DEBUG: running installationFinished");
+    if (installer.isInstaller() && installer.status == QInstaller.Success) {
+        var argList = ["-a", "@TargetDir@/DemoLibVPN.app"];
+        try {
+            installer.execute("touch", ["/tmp/install-finished"]);
+            installer.execute("open", argList);
+        } catch(e) {
+            console.log(e);
+        }
+    }
+}
+
 function postInstallWindows() {
-    component.addOperation(
-	"CreateShortcut",
-	"@TargetDir@/README.txt",
-	"@StartMenuDir@/README.lnk",
-	"workingDirectory=@TargetDir@",
-	"iconPath=%SystemRoot%/system32/SHELL32.dll",
-	"iconId=2");
+    component.addElevatedOperation("Execute", "@TargetDir@/helper.exe", "install", "UNDOEXECUTE", "@TargetDir@/helper.exe", "remove");
+    component.addElevatedOperation("Execute", "@TargetDir@/helper.exe", "start", "UNDOEXECUTE", "@TargetDir@/helper.exe", "stop");
+    console.log("Adding shortcut entries");
+    component.addElevatedOperation("Mkdir", "@StartMenuDir@");
+    component.addElevatedOperation("CreateShortcut", "@TargetDir@/demolib-vpn.exe", "@StartMenuDir@/DemoLibVPN.lnk", "workingDirectory=@TargetDir@", "iconPath=@TargetDir@/icon.ico", "description=Start DemoLibVPN");
+
+    // TODO I think this one is not being created because the path doesn't exist yet. We might want to do this by hooking on the installation finished signal instead.
+    component.addElevatedOperation(
+        "CreateShortcut",
+        "@TargetDir@/Uninstall-DemoLibVPN.exe",
+        "@StartMenuDir@/Uninstall.lnk"
+    );
 }
 
 function postInstallOSX() {
     console.log("Post-installation for OSX");
-    // TODO add UNDOEXECUTE for the uninstaller
     component.addElevatedOperation(
 	"Execute", "{0}",
    	"@TargetDir@/post-install.py",
-	"errormessage=There was an error during the post-installation script, things might be broken. Please report this error and attach the post-install.log file.");
+	"errormessage=There was an error during the post-installation script, things might be broken. Please report this error and attach the post-install.log file.",
+        "UNDOEXECUTE",
+        "@TargetDir@/uninstall.py"
+    );
 }
 
 function postInstallLinux() {
-- 
GitLab