Skip to content

Commit

Permalink
addSystemSettings: Add lookahead into provision.json for custom ports
Browse files Browse the repository at this point in the history
  • Loading branch information
tresf committed May 3, 2024
1 parent 9e15a3a commit 2ef0790
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 29 deletions.
33 changes: 30 additions & 3 deletions src/qz/installer/Installer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Integer> securePorts = Arrays.asList(DEFAULT_WSS_PORTS);
private List<Integer> insecurePorts = Arrays.asList(DEFAULT_WSS_PORTS);

public enum PrivilegeLevel {
USER,
SYSTEM
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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;
}
Expand All @@ -377,6 +388,22 @@ public Installer removeProvisioning() {
return this;
}

public void setSecurePorts(List<Integer> securePorts) {
this.securePorts = securePorts;
}

public void setInsecurePorts(List<Integer> insecurePorts) {
this.insecurePorts = insecurePorts;
}

public List<Integer> getSecurePorts() {
return securePorts;
}

public List<Integer> getInsecurePorts() {
return insecurePorts;
}

public static Properties persistProperties(File oldFile, Properties newProps) {
if(oldFile.exists()) {
Properties oldProps = new Properties();
Expand Down
3 changes: 1 addition & 2 deletions src/qz/installer/WindowsInstaller.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
32 changes: 32 additions & 0 deletions src/qz/installer/provision/ProvisionInstaller.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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.*;
Expand Down Expand Up @@ -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<String,String> pair : PropertyInvoker.parsePropertyPairs(step)) {
if(pair.getKey().equals(ArgValue.WEBSOCKET_SECURE_PORTS.getMatch())) {
List<Integer> 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<Integer> 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<Step> parse(JSONArray jsonArray, Object relativeObject) throws JSONException {
ArrayList<Step> steps = new ArrayList<>();
for(int i = 0; i < jsonArray.length(); i++) {
Expand Down
43 changes: 24 additions & 19 deletions src/qz/installer/provision/invoker/PropertyInvoker.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<AbstractMap.SimpleEntry<String,String>> pairs = new ArrayList<>();
for(String prop : props) {
AbstractMap.SimpleEntry<String,String> pair = parsePropertyPair(step, prop);
if (pair != null) {
pairs.add(pair);
}
ArrayList<AbstractMap.SimpleEntry<String,String>> pairs = parsePropertyPairs(step);
if (!pairs.isEmpty()) {
for(AbstractMap.SimpleEntry<String,String> pair : pairs) {
properties.setProperty(pair.getKey(), pair.getValue());
}
if (!pairs.isEmpty()) {
for(AbstractMap.SimpleEntry<String,String> 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;
}
Expand All @@ -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<AbstractMap.SimpleEntry<String,String>> parsePropertyPairs(Step step) {
ArrayList<AbstractMap.SimpleEntry<String,String>> pairs = new ArrayList<>();
if(step.getData() != null && !step.getData().trim().isEmpty()) {
String[] props = step.getData().split("\\|");
for(String prop : props) {
AbstractMap.SimpleEntry<String,String> 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<String, String> parsePropertyPair(Step step, String prop) {
if(prop.contains("=")) {
Expand Down
14 changes: 9 additions & 5 deletions src/qz/utils/PrefsSearch.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,23 @@ public static int getInt(ArgValue argValue, Properties ... propsArray) {
}

public static Integer[] getIntegerArray(ArgValue argValue, Properties ... propsArray) {
List<Integer> parsed = parseIntegerArray(getString(argValue, propsArray));
return parsed.toArray(new Integer[parsed.size()]);
}

public static List<Integer> parseIntegerArray(String commaSeparated) {
List<Integer> 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) {
Expand Down
12 changes: 12 additions & 0 deletions test/qz/installer/provision/resources/provision.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 2ef0790

Please sign in to comment.