From 2ef0790ecb4b1fd851937b4c832f84e8e3946862 Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Fri, 3 May 2024 01:21:03 -0400 Subject: [PATCH] addSystemSettings: Add lookahead into provision.json for custom ports --- src/qz/installer/Installer.java | 33 ++++++++++++-- src/qz/installer/WindowsInstaller.java | 3 +- .../provision/ProvisionInstaller.java | 32 ++++++++++++++ .../provision/invoker/PropertyInvoker.java | 43 +++++++++++-------- src/qz/utils/PrefsSearch.java | 14 +++--- .../provision/resources/provision.json | 12 ++++++ 6 files changed, 108 insertions(+), 29 deletions(-) diff --git a/src/qz/installer/Installer.java b/src/qz/installer/Installer.java index 4ae3c8c2a..c1de34374 100644 --- a/src/qz/installer/Installer.java +++ b/src/qz/installer/Installer.java @@ -42,6 +42,9 @@ public abstract class Installer { public static boolean IS_SILENT = "1".equals(System.getenv(DATA_DIR + "_silent")); public static String JRE_LOCATION = SystemUtilities.isMac() ? "Contents/PlugIns/Java.runtime/Contents/Home" : "runtime"; + private List securePorts = Arrays.asList(DEFAULT_WSS_PORTS); + private List insecurePorts = Arrays.asList(DEFAULT_WSS_PORTS); + public enum PrivilegeLevel { USER, SYSTEM @@ -103,8 +106,8 @@ public static void install() throws Exception { .addSharedDirectory() .addAppLauncher() .addStartupEntry() - .addSystemSettings() - .invokeProvisioning(Phase.INSTALL); + .invokeProvisioning(Phase.INSTALL) + .addSystemSettings(); } public static void uninstall() { @@ -359,8 +362,16 @@ public Installer invokeProvisioning(Phase phase) { Paths.get(getDestination()).resolve(PROVISION_DIR); ProvisionInstaller provisionInstaller = new ProvisionInstaller(provisionPath); provisionInstaller.invoke(phase); + + // Special case for custom websocket ports + switch(phase) { + case INSTALL: + case UNINSTALL: + provisionInstaller.setCustomPorts(this); + break; + } } catch(Exception e) { - log.warn("An error occurred deleting provisioning directory \"phase\": \"{}\" entries", phase, e); + log.warn("An error occurred invoking provision \"phase\": \"{}\"", phase, e); } return this; } @@ -377,6 +388,22 @@ public Installer removeProvisioning() { return this; } + public void setSecurePorts(List securePorts) { + this.securePorts = securePorts; + } + + public void setInsecurePorts(List insecurePorts) { + this.insecurePorts = insecurePorts; + } + + public List getSecurePorts() { + return securePorts; + } + + public List getInsecurePorts() { + return insecurePorts; + } + public static Properties persistProperties(File oldFile, Properties newProps) { if(oldFile.exists()) { Properties oldProps = new Properties(); diff --git a/src/qz/installer/WindowsInstaller.java b/src/qz/installer/WindowsInstaller.java index 781f857f0..c027d10da 100644 --- a/src/qz/installer/WindowsInstaller.java +++ b/src/qz/installer/WindowsInstaller.java @@ -148,8 +148,7 @@ public Installer addSystemSettings() { WindowsUtilities.addNumberedRegValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\Policies\\Google\\Chrome\\URLWhitelist", String.format("%s://*", DATA_DIR)); // Firewall rules - // FIXME: This breaks Windows Installers!! - String ports = StringUtils.join(PrintSocketServer.securePorts, ",") + "," + StringUtils.join(PrintSocketServer.insecurePorts, ","); + String ports = StringUtils.join(getSecurePorts(), ",") + "," + StringUtils.join(getInsecurePorts(), ","); ShellUtilities.execute("netsh.exe", "advfirewall", "firewall", "delete", "rule", String.format("name=%s", ABOUT_TITLE)); ShellUtilities.execute("netsh.exe", "advfirewall", "firewall", "add", "rule", String.format("name=%s", ABOUT_TITLE), "dir=in", "action=allow", "profile=any", String.format("localport=%s", ports), "localip=any", "protocol=tcp"); diff --git a/src/qz/installer/provision/ProvisionInstaller.java b/src/qz/installer/provision/ProvisionInstaller.java index 0996b594a..b359993ff 100644 --- a/src/qz/installer/provision/ProvisionInstaller.java +++ b/src/qz/installer/provision/ProvisionInstaller.java @@ -2,6 +2,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.codehaus.jettison.json.JSONArray; @@ -10,10 +11,14 @@ import qz.build.provision.Step; import qz.build.provision.params.Os; import qz.build.provision.params.Phase; +import qz.build.provision.params.Type; import qz.build.provision.params.types.Script; import qz.build.provision.params.types.Software; import qz.common.Constants; +import qz.installer.Installer; import qz.installer.provision.invoker.*; +import qz.utils.ArgValue; +import qz.utils.PrefsSearch; import qz.utils.ShellUtilities; import qz.utils.SystemUtilities; @@ -22,7 +27,9 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Path; +import java.util.AbstractMap; import java.util.ArrayList; +import java.util.List; import static qz.common.Constants.*; import static qz.utils.FileUtilities.*; @@ -129,6 +136,31 @@ private boolean invokeStep(Step step) throws Exception { return invoker.invoke(); } + /** + * Loops through steps searching for a property which sets a custom websocket ports + */ + public void setCustomPorts(Installer installer) { + for(Step step : steps) { + if(step.getType() == Type.PROPERTY) { + for(AbstractMap.SimpleEntry pair : PropertyInvoker.parsePropertyPairs(step)) { + if(pair.getKey().equals(ArgValue.WEBSOCKET_SECURE_PORTS.getMatch())) { + List securePorts = PrefsSearch.parseIntegerArray(pair.getValue()); + if(!securePorts.isEmpty()) { + installer.setSecurePorts(securePorts); + log.info("Picked up custom secure ports from {}: [{}]", PROVISION_FILE, StringUtils.join(securePorts, ",")); + } + } else if(pair.getKey().equals(ArgValue.WEBSOCKET_INSECURE_PORTS.getMatch())) { + List insecurePorts = PrefsSearch.parseIntegerArray(pair.getValue()); + if(!insecurePorts.isEmpty()) { + installer.setInsecurePorts(insecurePorts); + log.info("Picked up custom insecure ports from {}: [{}]", PROVISION_FILE, StringUtils.join(insecurePorts, ",")); + } + } + } + } + } + } + private static ArrayList parse(JSONArray jsonArray, Object relativeObject) throws JSONException { ArrayList steps = new ArrayList<>(); for(int i = 0; i < jsonArray.length(); i++) { diff --git a/src/qz/installer/provision/invoker/PropertyInvoker.java b/src/qz/installer/provision/invoker/PropertyInvoker.java index 75691bdfd..83acfeddf 100644 --- a/src/qz/installer/provision/invoker/PropertyInvoker.java +++ b/src/qz/installer/provision/invoker/PropertyInvoker.java @@ -20,27 +20,16 @@ public PropertyInvoker(Step step, PropertyHelper properties) { } public boolean invoke() { - if(step.getData() != null && !step.getData().trim().isEmpty()) { - String[] props = step.getData().split("\\|"); - ArrayList> pairs = new ArrayList<>(); - for(String prop : props) { - AbstractMap.SimpleEntry pair = parsePropertyPair(step, prop); - if (pair != null) { - pairs.add(pair); - } + ArrayList> pairs = parsePropertyPairs(step); + if (!pairs.isEmpty()) { + for(AbstractMap.SimpleEntry pair : pairs) { + properties.setProperty(pair.getKey(), pair.getValue()); } - if (!pairs.isEmpty()) { - for(AbstractMap.SimpleEntry pair : pairs) { - properties.setProperty(pair.getKey(), pair.getValue()); - } - if (properties.save()) { - log.info("Successfully provisioned '{}' '{}'", pairs.size(), step.getType()); - return true; - } - log.error("An error occurred saving properties '{}' to file", step.getData()); + if (properties.save()) { + log.info("Successfully provisioned '{}' '{}'", pairs.size(), step.getType()); + return true; } - } else { - log.error("Skipping Step '{}', Data is null or empty", step.getType()); + log.error("An error occurred saving properties '{}' to file", step.getData()); } return false; } @@ -63,6 +52,22 @@ public static PropertyHelper getPreferences(Step step) { return new PropertyHelper(FileUtilities.USER_DIR + File.separator + Constants.PREFS_FILE + ".properties"); } + public static ArrayList> parsePropertyPairs(Step step) { + ArrayList> pairs = new ArrayList<>(); + if(step.getData() != null && !step.getData().trim().isEmpty()) { + String[] props = step.getData().split("\\|"); + for(String prop : props) { + AbstractMap.SimpleEntry pair = parsePropertyPair(step, prop); + if (pair != null) { + pairs.add(pair); + } + } + } else { + log.error("Skipping Step '{}', Data is null or empty", step.getType()); + } + return pairs; + } + private static AbstractMap.SimpleEntry parsePropertyPair(Step step, String prop) { if(prop.contains("=")) { diff --git a/src/qz/utils/PrefsSearch.java b/src/qz/utils/PrefsSearch.java index fa264835a..0eb6fa1d7 100644 --- a/src/qz/utils/PrefsSearch.java +++ b/src/qz/utils/PrefsSearch.java @@ -93,19 +93,23 @@ public static int getInt(ArgValue argValue, Properties ... propsArray) { } public static Integer[] getIntegerArray(ArgValue argValue, Properties ... propsArray) { + List parsed = parseIntegerArray(getString(argValue, propsArray)); + return parsed.toArray(new Integer[parsed.size()]); + } + + public static List parseIntegerArray(String commaSeparated) { List parsed = new ArrayList<>(); - String unparsed = getString(argValue, propsArray); try { - if (unparsed != null && !unparsed.isEmpty()) { - String[] split = unparsed.split(","); + if (commaSeparated != null && !commaSeparated.isEmpty()) { + String[] split = commaSeparated.split(","); for(String item : split) { parsed.add(Integer.parseInt(item)); } } } catch(NumberFormatException nfe) { - log.warn("Failed parsing {} as {}", unparsed, argValue, nfe); + log.warn("Failed parsing {} as a valid integer array", commaSeparated, nfe); } - return parsed.toArray(new Integer[parsed.size()]); + return parsed; } public static boolean getBoolean(ArgValue argValue, Properties ... propsArray) { diff --git a/test/qz/installer/provision/resources/provision.json b/test/qz/installer/provision/resources/provision.json index f596df548..374f63cf5 100644 --- a/test/qz/installer/provision/resources/provision.json +++ b/test/qz/installer/provision/resources/provision.json @@ -88,6 +88,18 @@ "os": "*", "data": "cert1.crt" }, + { + "description": "[PROPERTY] at 'certgen' (qz-tray.properties)", + "type": "property", + "os": "*", + "data": "websocket.secure.ports=9191,9292,9393,9494" + }, + { + "description": "[PROPERTY] at 'certgen' (qz-tray.properties)", + "type": "property", + "os": "*", + "data": "websocket.insecure.ports=9192,9293,9394,9495" + }, { "description": "[PROPERTY] at 'certgen' (qz-tray.properties)", "type": "property",