diff --git a/install/FirefoxAction.CA.dll b/install/FirefoxAction.CA.dll
deleted file mode 100644
index e185b9fd..00000000
Binary files a/install/FirefoxAction.CA.dll and /dev/null differ
diff --git a/install/firefox-action/.gitignore b/install/firefox-action/.gitignore
new file mode 100644
index 00000000..6ada809d
--- /dev/null
+++ b/install/firefox-action/.gitignore
@@ -0,0 +1,4 @@
+bin/
+obj/
+packages/
+.vs/
diff --git a/install/firefox-action/CustomAction.config b/install/firefox-action/CustomAction.config
new file mode 100644
index 00000000..acae396c
--- /dev/null
+++ b/install/firefox-action/CustomAction.config
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/install/firefox-action/FirefoxAction.cs b/install/firefox-action/FirefoxAction.cs
new file mode 100644
index 00000000..3e12e415
--- /dev/null
+++ b/install/firefox-action/FirefoxAction.cs
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019-2024 Estonian Information System Authority
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using Microsoft.Win32;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System.Linq;
+using WixToolset.Dtf.WindowsInstaller;
+
+namespace FirefoxAction
+{
+ public class FirefoxActions
+ {
+ const string KEY_NAME = "ExtensionSettings";
+
+ [CustomAction]
+ public static ActionResult ExtensionSettingsInstall(Session session)
+ {
+ // Instead of catching and logging errors and returning ActionResult.Failure,
+ // we simply let all exceptions through. In both cases the installation fails
+ // with error status 1603, but when letting exceptions through the raw exception
+ // stack trace will be logged in installer log which gives more information.
+
+ var extensionSettings = session.GetExtensionSettings();
+ session.Log("Begin ExtensionSettingsInstall " + extensionSettings.UUID);
+ using (RegistryKey firefox = Utils.FirefoxKey())
+ {
+ var json = firefox.GetJSON(KEY_NAME, "{}");
+ json[extensionSettings.UUID] = new JObject
+ {
+ ["installation_mode"] = "normal_installed",
+ ["install_url"] = extensionSettings.URL
+ };
+ firefox.SetValue(KEY_NAME, json.ToString().Split('\n'));
+ return ActionResult.Success;
+ }
+ }
+
+ [CustomAction]
+ public static ActionResult ExtensionSettingsRemove(Session session)
+ {
+ var extensionSettings = session.GetExtensionSettings();
+ session.Log("Begin ExtensionSettingsRemove " + extensionSettings.UUID);
+ using (RegistryKey firefox = Utils.FirefoxKey())
+ {
+ var json = firefox.GetJSON(KEY_NAME);
+ if (json != null)
+ {
+ json[extensionSettings.UUID] = new JObject
+ {
+ ["installation_mode"] = "blocked"
+ };
+ firefox.SetValue(KEY_NAME, json.ToString().Split('\n'));
+ }
+ }
+ return ActionResult.Success;
+ }
+ }
+
+ internal static class Utils
+ {
+ internal static (string UUID, string URL) GetExtensionSettings(this Session session)
+ {
+ // Deferred custom actions cannot directly access installer properties from session,
+ // only the CustomActionData property is available, see README how to populate it.
+ return (
+ session.CustomActionData["EXTENSIONSETTINGS_UUID"],
+ session.CustomActionData["EXTENSIONSETTINGS_URL"]
+ );
+ }
+
+ internal static RegistryKey FirefoxKey()
+ {
+ using (RegistryKey mozilla = Registry.LocalMachine.OpenOrCreateSubKey(@"Software\Policies\Mozilla", true))
+ {
+ return mozilla.OpenOrCreateSubKey(@"Firefox", true);
+ }
+ }
+
+ internal static RegistryKey OpenOrCreateSubKey(this RegistryKey registryKey, string name, bool writable = false)
+ {
+ return registryKey.OpenSubKey(name, writable) ?? registryKey.CreateSubKey(name);
+ }
+
+ internal static string GetStringValue(this RegistryKey registryKey, string name, string defaultValue = null)
+ {
+ if (!registryKey.GetValueNames().Any(name.Equals))
+ return defaultValue;
+ switch (registryKey.GetValueKind(name))
+ {
+ case RegistryValueKind.String:
+ case RegistryValueKind.ExpandString:
+ return (string)registryKey.GetValue(name, defaultValue);
+ case RegistryValueKind.MultiString:
+ return string.Join("\n", (string[])registryKey.GetValue(name));
+ default: return defaultValue;
+ }
+ }
+
+ internal static JObject GetJSON(this RegistryKey registryKey, string name, string defaultValue = null)
+ {
+ string value = registryKey.GetStringValue(name, defaultValue);
+ if (value == null)
+ {
+ return null;
+ }
+ try
+ {
+ return JObject.Parse(value);
+ }
+ catch (JsonReaderException)
+ {
+ return new JObject();
+ }
+ }
+ }
+}
diff --git a/install/firefox-action/FirefoxAction.csproj b/install/firefox-action/FirefoxAction.csproj
new file mode 100644
index 00000000..cdded0dd
--- /dev/null
+++ b/install/firefox-action/FirefoxAction.csproj
@@ -0,0 +1,17 @@
+
+
+ net40
+ Copyright © 2019
+ RIA
+ README.md
+ LICENSE
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/install/firefox-action/LICENSE b/install/firefox-action/LICENSE
new file mode 100644
index 00000000..ebbc5e6a
--- /dev/null
+++ b/install/firefox-action/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021-2023 Estonian Information System Authority
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/install/firefox-action/README.md b/install/firefox-action/README.md
new file mode 100644
index 00000000..6dacc498
--- /dev/null
+++ b/install/firefox-action/README.md
@@ -0,0 +1,36 @@
+# WiX custom action for installing a Firefox extension with enterprise policy
+
+*FirefoxAction* is a custom action for WiX that installs the given Firefox
+extension with the Firefox enterprise policy engine.
+
+The custom action should be added to a WiX project as follows, it must be deferred
+and not use impersonation (i.e. run in privileged mode for registry access):
+
+
+
+
+
+The Firefox extension UUID and AMO URL must be passed in via `CustomSettingsData` properties via
+dedicated custom actions as follows:
+
+
+
+
+The custom actions must be scheduled in `InstallExecuteSequence` as follows:
+
+
+
+
+ NOT REMOVE="ALL"
+
+
+
+ REMOVE="ALL" AND NOT UPGRADINGPRODUCTCODE
+
+
+
+The code has been forked from the [OpenEID Windows installer project](https://github.com/open-eid/windows-installer/blob/master/FirefoxActionWix/).
diff --git a/install/web-eid.wxs b/install/web-eid.wxs
index 8e45aa14..08d59f2c 100644
--- a/install/web-eid.wxs
+++ b/install/web-eid.wxs
@@ -37,10 +37,8 @@
-
-
+
+
_${PROJECT_VERSION}.$ENV{PLATFORM})
+ find_program(MSBUILD msbuild)
+ set(FIREFOX_ACTION_DLL ${CMAKE_CURRENT_BINARY_DIR}/FirefoxAction.CA.dll)
+ add_custom_command(
+ OUTPUT ${FIREFOX_ACTION_DLL}
+ COMMAND ${MSBUILD} ${CMAKE_SOURCE_DIR}/install/firefox-action/FirefoxAction.csproj
+ /restore /t:rebuild /property:Configuration=Release
+ "/property:OutDir=${CMAKE_CURRENT_BINARY_DIR}/"
+ DEPENDS
+ ${CMAKE_SOURCE_DIR}/install/firefox-action/FirefoxAction.cs
+ ${CMAKE_SOURCE_DIR}/install/firefox-action/FirefoxAction.csproj
+ ${CMAKE_SOURCE_DIR}/install/firefox-action/CustomAction.config
+ COMMENT "Building Firefox custom action DLL"
+ )
+ add_custom_target(firefox-action DEPENDS ${FIREFOX_ACTION_DLL})
set(WIX_CMD wix.exe build -nologo
-arch $ENV{PLATFORM}
-ext WixToolset.UI.wixext
@@ -32,12 +46,13 @@ if(WIN32)
-d jsonfirefox=${CMAKE_CURRENT_BINARY_DIR}/eu.webeid.firefox.json
-d FIREFOX_URL="${FIREFOX_URL}"
-d FIREFOX_UUID="${FIREFOX_UUID}"
+ -d FirefoxActionDll=${FIREFOX_ACTION_DLL}
-d app_path=$
${CMAKE_SOURCE_DIR}/install/web-eid.wxs
${CMAKE_SOURCE_DIR}/install/WelcomeDlg.wxs
${CMAKE_SOURCE_DIR}/install/WixUI_Minimal.wxs
)
- add_custom_target(installer DEPENDS web-eid
+ add_custom_target(installer DEPENDS web-eid firefox-action
COMMAND ${WIX_CMD} -o "${BASE_FILE}.msi"
#Build MSI with QT
COMMAND ${WIX_CMD} -d qt_path=${Qt6_DIR}/../../../bin -o "${BASE_FILE}.qt.msi"
@@ -50,6 +65,9 @@ if(WIN32)
COMMAND ${SIGNCMD} "$<$:/ph;/ac;${CROSSSIGNCERT}>" $
COMMAND_EXPAND_LISTS
)
+ add_custom_command(TARGET firefox-action POST_BUILD
+ COMMAND ${SIGNCMD} ${FIREFOX_ACTION_DLL}
+ )
add_custom_command(TARGET installer POST_BUILD
COMMAND ${SIGNCMD} "${BASE_FILE}.msi" "${BASE_FILE}.qt.msi"
WORKING_DIRECTORY $