From ebe020164872e98ec26e5c62ed3c169782695fa8 Mon Sep 17 00:00:00 2001
From: jkito <belter@riseup.net>
Date: Wed, 10 Jul 2024 00:08:35 +0530
Subject: [PATCH] installer: add wizard page to install for all users on
 windows

this adds a custom installer page with a checkbox to allow users to
choose to install the app for all users, when its enabled installer
will create a group called 'OpenVPN Administrator'

local users except the admin, guest and default account are added to
the group, and upon uninstall the group is removed

this allows non-admin users that are added to the group to use the app
and successfully start a vpn connection
---
 .../templates/qtinstaller/config/config.xml   |  1 +
 .../templates/qtinstaller/config/script.qs    | 23 ++++++++
 .../packages/bitmaskvpn/meta/install.js       | 33 ++++++++++++
 .../bitmaskvpn/meta/installforallcheckbox.ui  | 53 +++++++++++++++++++
 .../packages/bitmaskvpn/meta/package.xml      |  3 ++
 5 files changed, 113 insertions(+)
 create mode 100644 branding/templates/qtinstaller/config/script.qs
 create mode 100644 branding/templates/qtinstaller/packages/bitmaskvpn/meta/installforallcheckbox.ui

diff --git a/branding/templates/qtinstaller/config/config.xml b/branding/templates/qtinstaller/config/config.xml
index 0de8db97..247d5ab0 100644
--- a/branding/templates/qtinstaller/config/config.xml
+++ b/branding/templates/qtinstaller/config/config.xml
@@ -8,6 +8,7 @@
     <AllowNonAsciiCharacters>false</AllowNonAsciiCharacters>
     <Logo>installer-logo.png</Logo>
     <InstallerApplicationIcon>installer-icon</InstallerApplicationIcon>
+    <ControlScript>script.qs</ControlScript>
 
     <!--
     <RemoteRepositories>
diff --git a/branding/templates/qtinstaller/config/script.qs b/branding/templates/qtinstaller/config/script.qs
new file mode 100644
index 00000000..741331c9
--- /dev/null
+++ b/branding/templates/qtinstaller/config/script.qs
@@ -0,0 +1,23 @@
+function Controller()
+{
+    console.log("Controller script called")
+}
+
+Controller.prototype.ComponentSelectionPageCallback = function()
+{
+    gui.clickButton(buttons.NextButton);
+}
+
+Controller.prototype.ReadyForInstallationPageCallback = function() {
+    console.log("Control script being called")
+    try {
+        var page = gui.pageWidgetByObjectName("DynamicInstallForAllUsersCheckBoxForm");
+        if(page) {
+            console.log("Control script being called")
+            var choice = page.installForAllCheckBox.checked ? "true" : "false";
+            installer.setValue("installForAllUsers", choice);
+        } 
+    } catch(e) {
+        console.log(e);
+    }
+}
\ No newline at end of file
diff --git a/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js b/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js
index bf3d05ba..e2fc8ced 100644
--- a/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js
+++ b/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js
@@ -64,6 +64,9 @@ function Component() {
     }
     console.log("CPU Architecture: " +  systemInfo.currentCpuArchitecture);
 
+    if (systemInfo.productType === "windows") {
+        installer.addWizardPage(component, "InstallForAllUsersCheckBoxForm", QInstaller.LicenseCheck);
+    }
 }
 
 Component.prototype.createOperations = function ()
@@ -83,8 +86,12 @@ Component.prototype.createOperations = function ()
     // We can also use this to register different components (different architecture for instance)
     // See https://doc.qt.io/qtinstallerframework/qt-installer-framework-systeminfo-packages-root-meta-installscript-qs.html
 
+    console.log("installForAllUsers value: " + installer.value("installForAllUsers"));
     if (systemInfo.productType === "windows") {
         postInstallWindows();
+        if (installer.value("installForAllUsers") === "true") {
+            installForAllUsersWindows()
+        }
     } else if (systemInfo.productType === "macos") {
         uninstallOSX();
         postInstallOSX();
@@ -124,6 +131,23 @@ function postInstallWindows() {
     );
 }
 
+function installForAllUsersWindows() {
+    component.addElevatedOperation(
+        "Execute", "{0}", "powershell", "-NonInteractive", "-NoProfile", "-command",
+        "try {New-LocalGroup -Name 'OpenVPN Administrators' -Description 'Group to allow use of openvpn' -ErrorAction Stop} catch [Microsoft.PowerShell.Commands.GroupExistsException] { exit 0 }",
+        "errormessage=Unable to create the 'OpenVPN Administrators' group.",
+        "UNDOEXECUTE", "{0}", "powershell", "-NonInteractive", "-NoProfile", "-command",
+        "try { Remove-LocalGroup -Name 'OpenVPN Administrators' -ErrorAction Stop } catch [Microsoft.PowerShell.Commands.GroupNotFoundException] { exit 0 }",
+        "errormessage=Unable to remove the 'OpenVPN Administrator' group."
+    );
+
+    component.addElevatedOperation(
+        "Execute", "{0}", "powershell", "-NonInteractive", "-NoProfile", "-command",
+        "$$users=(Get-LocalUser | Select-Object Name | where {$$_.Name -NotMatch 'Administrator' -and $$_.Name -NotMatch 'Guest' -and $$_.Name -NotMatch 'DefaultAccount' -and $$_.Name -NotMatch 'WDAGUtilityAccount'}); try {Add-LocalGroupMember -Group 'OpenVPN Administrators' -Member $$users -ErrorAction Stop} catch [Microsoft.PowerShell.Commands.MemberExistsException] {exit 0}",
+        "errormessage=Unable to add users to the 'OpenVPN Administrators' group."
+    );
+}
+
 function preInstallOSX() {
     console.log("Pre-installation for OSX: check for running bitmask");
     component.addOperation(
@@ -164,3 +188,12 @@ function postInstallLinux() {
     console.log("Maybe you want to use your package manager instead?");
     component.addOperation("AppendFile", "/tmp/bitmask-installer.log", "this is a test - written from the installer");
 }
+
+function uninstallWindows() {
+    console.log("uninstall for windows: remove openvpn administrators group")
+
+    component.addElevatedOperation(
+        "Execute", "{0}", "powershell", "-NonInteractive", "-NoProfile", "-command",
+        "Remove-LocalGroup -Name 'OpenVPN Administrator' -ErrorAction Ignore",
+    );
+}
\ No newline at end of file
diff --git a/branding/templates/qtinstaller/packages/bitmaskvpn/meta/installforallcheckbox.ui b/branding/templates/qtinstaller/packages/bitmaskvpn/meta/installforallcheckbox.ui
new file mode 100644
index 00000000..b988c5de
--- /dev/null
+++ b/branding/templates/qtinstaller/packages/bitmaskvpn/meta/installforallcheckbox.ui
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+    <class>InstallForAllUsersCheckBoxForm</class>
+    <widget class="QWidget" name="InstallForAllUsersCheckBoxForm">
+        <property name="geometry">
+            <rect>
+                <x>0</x>
+                <y>0</y>
+                <width>412</width>
+                <height>179</height>
+            </rect>
+        </property>
+        <property name="windowTitle">
+            <string>Select Installation Mode</string>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout">
+            <property name="margin">
+                <number>10</number>
+            </property>
+            <item>
+                <widget class="QCheckBox" name="installForAllCheckBox">
+                    <property name="font">
+                        <font>
+                            <weight>75</weight>
+                            <bold>true</bold>
+                        </font>
+                    </property>
+                    <property name="text">
+                        <string>Install for All Users on this Computer</string>
+                    </property>
+                    <property name="checked">
+                        <bool>false</bool>
+                    </property>
+                </widget>
+            </item>
+            <item>
+                <widget class="QLabel" name="allUsersLabel">
+                    <property name="text">
+                        <string>The application will be installed for all users on this machine. All users will be added to the OpenVPN Administrators group to enable interaction with OpenVPN.</string>
+                    </property>
+                    <property name="wordWrap">
+                        <bool>true</bool>
+                    </property>
+                    <property name="indent">
+                        <number>25</number>
+                    </property>
+                </widget>
+            </item>
+        </layout>
+    </widget>
+    <resources />
+    <connections />
+</ui>
\ No newline at end of file
diff --git a/branding/templates/qtinstaller/packages/bitmaskvpn/meta/package.xml b/branding/templates/qtinstaller/packages/bitmaskvpn/meta/package.xml
index d54cf567..e7250b70 100644
--- a/branding/templates/qtinstaller/packages/bitmaskvpn/meta/package.xml
+++ b/branding/templates/qtinstaller/packages/bitmaskvpn/meta/package.xml
@@ -8,4 +8,7 @@
     <RequiresAdminRights>true</RequiresAdminRights>
     <Script>install.js</Script>
     <ForcedInstallation>true</ForcedInstallation>
+    <UserInterfaces>
+        <UserInterface>installforallcheckbox.ui</UserInterface>
+    </UserInterfaces>
 </Package>
-- 
GitLab