Skip to content

Commit

Permalink
Oh no, got hit with another big refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
tresf committed May 3, 2024
1 parent 37b2838 commit 753f980
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 109 deletions.
6 changes: 4 additions & 2 deletions src/qz/common/AboutInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import qz.utils.StringUtilities;
import qz.utils.SystemUtilities;
import qz.ws.PrintSocketServer;
import qz.ws.WebsocketPorts;

import java.io.BufferedReader;
import java.io.IOException;
Expand Down Expand Up @@ -68,6 +69,7 @@ private static JSONObject product() throws JSONException {
private static JSONObject socket(CertificateManager certificateManager, String domain) throws JSONException {
JSONObject socket = new JSONObject();
String sanitizeDomain = StringUtilities.escapeHtmlEntities(domain);
WebsocketPorts websocketPorts = PrintSocketServer.getWebsocketPorts();

// Gracefully handle XSS per https://github.com/qzind/tray/issues/1099
if(sanitizeDomain.contains("<") || sanitizeDomain.contains(">")) {
Expand All @@ -78,9 +80,9 @@ private static JSONObject socket(CertificateManager certificateManager, String d
socket
.put("domain", sanitizeDomain)
.put("secureProtocol", "wss")
.put("securePort", certificateManager.isSslActive() ? PrintSocketServer.getSecurePortInUse() : "none")
.put("securePort", certificateManager.isSslActive() ? websocketPorts.getSecurePort() : "none")
.put("insecureProtocol", "ws")
.put("insecurePort", PrintSocketServer.getInsecurePortInUse());
.put("insecurePort", websocketPorts.getInsecurePort());

return socket;
}
Expand Down
19 changes: 11 additions & 8 deletions src/qz/common/TrayManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import qz.utils.*;
import qz.ws.PrintSocketServer;
import qz.ws.SingleInstanceChecker;
import qz.ws.WebsocketPorts;

import javax.swing.*;
import java.awt.*;
Expand Down Expand Up @@ -534,10 +535,9 @@ private void blackList(Certificate cert) {
}
}

public void setServer(Server server, int insecurePortInUse, int securePortInUse) {
public void setServer(Server server, WebsocketPorts websocketPorts) {
if (server != null && server.getConnectors().length > 0) {
singleInstanceCheck(PrintSocketServer.insecurePorts, insecurePortInUse, false);
singleInstanceCheck(PrintSocketServer.securePorts, securePortInUse, true);
singleInstanceCheck(websocketPorts);

displayInfoMessage("Server started on port(s) " + PrintSocketServer.getPorts(server));

Expand Down Expand Up @@ -633,11 +633,14 @@ private void displayMessage(final String caption, final String text, final TrayI
}
}

public void singleInstanceCheck(java.util.List<Integer> ports, Integer portInUse, boolean usingSecure) {
for(int port : ports) {
if (portInUse == -1 || port != ports.get(portInUse)) {
new SingleInstanceChecker(this, port, usingSecure);
}
public void singleInstanceCheck(WebsocketPorts websocketPorts) {
// Secure
for(int port : websocketPorts.getUnusedSecurePorts()) {
new SingleInstanceChecker(this, port, true);
}
// Insecure
for(int port : websocketPorts.getUnusedInsecurePorts()) {
new SingleInstanceChecker(this, port, false);
}
}

Expand Down
22 changes: 3 additions & 19 deletions src/qz/installer/Installer.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import qz.installer.provision.ProvisionInstaller;
import qz.utils.FileUtilities;
import qz.utils.SystemUtilities;
import qz.ws.WebsocketPorts;

import java.io.*;
import java.nio.file.*;
Expand All @@ -42,8 +43,7 @@ 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);
WebsocketPorts websocketPorts;

public enum PrivilegeLevel {
USER,
Expand Down Expand Up @@ -365,7 +365,7 @@ public Installer invokeProvisioning(Phase phase) {

// Special case for custom websocket ports
if(phase == Phase.INSTALL) {
provisionInstaller.setCustomPorts(this);
websocketPorts = WebsocketPorts.parseFromSteps(provisionInstaller.getSteps());
}
} catch(Exception e) {
log.warn("An error occurred invoking provision \"phase\": \"{}\"", phase, e);
Expand All @@ -385,22 +385,6 @@ 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,10 +148,9 @@ public Installer addSystemSettings() {
WindowsUtilities.addNumberedRegValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\Policies\\Google\\Chrome\\URLWhitelist", String.format("%s://*", DATA_DIR));

// Firewall rules
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");
"dir=in", "action=allow", "profile=any", String.format("localport=%s", websocketPorts.allPortsAsString()), "localip=any", "protocol=tcp");
return this;
}

Expand Down
26 changes: 2 additions & 24 deletions src/qz/installer/provision/ProvisionInstaller.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,30 +136,8 @@ 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) {
HashMap<String, String> pairs = PropertyInvoker.parsePropertyPairs(step);
String foundPorts;
if((foundPorts = pairs.get(ArgValue.WEBSOCKET_SECURE_PORTS.getMatch())) != null) {
List<Integer> securePorts = PrefsSearch.parseIntegerArray(foundPorts);
if(!securePorts.isEmpty()) {
installer.setSecurePorts(securePorts);
log.info("Picked up custom secure ports from {}: [{}]", PROVISION_FILE, StringUtils.join(securePorts, ","));
}
}
if((foundPorts = pairs.get(ArgValue.WEBSOCKET_INSECURE_PORTS.getMatch())) != null) {
List<Integer> insecurePorts = PrefsSearch.parseIntegerArray(foundPorts);
if(!insecurePorts.isEmpty()) {
installer.setSecurePorts(insecurePorts);
log.info("Picked up custom insecure ports from {}: [{}]", PROVISION_FILE, StringUtils.join(insecurePorts, ","));
}
}
}
}
public ArrayList<Step> getSteps() {
return steps;
}

private static ArrayList<Step> parse(JSONArray jsonArray, Object relativeObject) throws JSONException {
Expand Down
2 changes: 1 addition & 1 deletion src/qz/ui/AboutDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void initComponents() {
// Some OSs (e.g. FreeBSD) return null for server.getURI(), fallback to sane values
URI uri = server.getURI();
String scheme = uri == null ? "http" : uri.getScheme();
int port = uri == null ? PrintSocketServer.getInsecurePortInUse(): uri.getPort();
int port = uri == null ? PrintSocketServer.getWebsocketPorts().getInsecurePort(): uri.getPort();
linkLibrary.setLinkLocation(String.format("%s://%s:%s", scheme, AboutInfo.getPreferredHostname(), port));
}
Box versionBox = Box.createHorizontalBox();
Expand Down
5 changes: 2 additions & 3 deletions src/qz/utils/PrefsSearch.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,8 @@ public static int getInt(ArgValue argValue, Properties ... propsArray) {
return getInt(argValue, true, 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> getIntegerArray(ArgValue argValue, Properties ... propsArray) {
return parseIntegerArray(getString(argValue, propsArray));
}

public static List<Integer> parseIntegerArray(String commaSeparated) {
Expand Down
65 changes: 15 additions & 50 deletions src/qz/ws/PrintSocketServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter;
import qz.App;
import qz.common.Constants;
import qz.common.TrayManager;
import qz.installer.certificate.CertificateManager;
import qz.utils.ArgValue;
Expand All @@ -33,7 +32,6 @@
import java.time.Duration;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
* Created by robert on 9/9/2014.
Expand All @@ -44,13 +42,9 @@ public class PrintSocketServer {
private static final Logger log = LogManager.getLogger(PrintSocketServer.class);

private static final int MAX_MESSAGE_SIZE = Integer.MAX_VALUE;
public static List<Integer> securePorts;
public static List<Integer> insecurePorts;

private static final AtomicInteger securePortIndex = new AtomicInteger(0);
private static final AtomicInteger insecurePortIndex = new AtomicInteger(0);
private static final AtomicBoolean running = new AtomicBoolean(false);

private static WebsocketPorts websocketPorts;
private static TrayManager trayManager;
private static Server server;
private static boolean httpsOnly;
Expand All @@ -65,7 +59,7 @@ public static void runServer(CertificateManager certManager, boolean headless) t
wssHost = PrefsSearch.getString(ArgValue.SECURITY_WSS_HOST, certManager.getProperties());
httpsOnly = PrefsSearch.getBoolean(ArgValue.SECURITY_WSS_HTTPSONLY, certManager.getProperties());
sniStrict = PrefsSearch.getBoolean(ArgValue.SECURITY_WSS_SNISTRICT, certManager.getProperties());
parseWebSocketPorts();
websocketPorts = WebsocketPorts.parseFromProperties();

server = findAvailableSecurePort(certManager);

Expand All @@ -79,10 +73,10 @@ public static void runServer(CertificateManager certManager, boolean headless) t
return;
}

while(!running.get() && insecurePortIndex.get() < insecurePorts.size()) {
while(!running.get() && websocketPorts.insecureBoundsCheck()) {
try {
ServerConnector connector = new ServerConnector(server);
connector.setPort(getInsecurePortInUse());
connector.setPort(websocketPorts.getInsecurePort());
if(httpsOnly) {
server.setConnectors(new Connector[] {secureConnector});
} else if (secureConnector != null) {
Expand Down Expand Up @@ -117,8 +111,7 @@ public static void runServer(CertificateManager certManager, boolean headless) t
try {
trayManager.setDangerIcon();
running.set(false);
securePortIndex.set(0);
insecurePortIndex.set(0);
websocketPorts.resetIndices();
server.stop();
}
catch(Exception e) {
Expand All @@ -130,15 +123,15 @@ public static void runServer(CertificateManager certManager, boolean headless) t
running.set(true);

log.info("Server started on port(s) " + getPorts(server));
int insecurePort = httpsOnly ? -1 : insecurePortIndex.get();
int securePort = secureConnector == null ? -1 : securePortIndex.get();
trayManager.setServer(server, insecurePort, securePort);
websocketPorts.setHttpsOnly(httpsOnly);
websocketPorts.setHttpOnly(secureConnector == null);
trayManager.setServer(server, websocketPorts);
server.join();
}
catch(IOException | MultiException e) {
//order of getConnectors is the order we added them -> insecure first
if (server.isFailed()) {
insecurePortIndex.incrementAndGet();
websocketPorts.nextInsecureIndex();
}

//explicitly stop the server, because if only 1 port has an exception the other will still be opened
Expand All @@ -157,7 +150,7 @@ private static Server findAvailableSecurePort(CertificateManager certManager) {

if (certManager != null) {
final AtomicBoolean runningSecure = new AtomicBoolean(false);
while(!runningSecure.get() && securePortIndex.get() < securePorts.size()) {
while(!runningSecure.get() && websocketPorts.secureBoundsCheck()) {
try {
// Bind the secure socket on the proper port number (i.e. 8181), add it as an additional connector
SslConnectionFactory sslConnection = new SslConnectionFactory(certManager.configureSslContextFactory(), HttpVersion.HTTP_1_1.asString());
Expand All @@ -172,19 +165,19 @@ private static Server findAvailableSecurePort(CertificateManager certManager) {

ServerConnector secureConnector = new ServerConnector(server, sslConnection, httpConnection);
secureConnector.setHost(wssHost);
secureConnector.setPort(getSecurePortInUse());
secureConnector.setPort(websocketPorts.getSecurePort());
server.setConnectors(new Connector[] {secureConnector});

server.start();
log.trace("Established secure WebSocket on port {}", getSecurePortInUse());
log.trace("Established secure WebSocket on port {}", websocketPorts.getSecurePort());

//only starting to test port availability; insecure port will actually start
server.stop();
runningSecure.set(true);
}
catch(IOException | MultiException e) {
if (server.isFailed()) {
securePortIndex.incrementAndGet();
websocketPorts.nextSecureIndex();
}

try { server.stop(); }catch(Exception stopEx) { stopEx.printStackTrace(); }
Expand Down Expand Up @@ -225,37 +218,9 @@ public static void main(String ... args) {
App.main(args);
}

/**
* Parses WebSocket ports from preferences or fallback to defaults is a problem is found
*/
public static void parseWebSocketPorts() {
Integer[] secure = PrefsSearch.getIntegerArray(ArgValue.WEBSOCKET_SECURE_PORTS);
Integer[] insecure = PrefsSearch.getIntegerArray(ArgValue.WEBSOCKET_INSECURE_PORTS);
boolean fallback = false;
if(secure.length == 0 || insecure.length == 0) {
log.warn("One or more WebSocket ports is empty, falling back to defaults");
fallback = true;
}
if(secure.length != insecure.length) {
log.warn("Secure ({}) and insecure ({}) WebSocket port counts mismatch, falling back to defaults", secure, insecure);
fallback = true;
}
if(fallback) {
log.warn("Falling back to default WebSocket ports: ({}), ({})", secure, insecure);
secure = Constants.DEFAULT_WSS_PORTS;
insecure = Constants.DEFAULT_WS_PORTS;
}

securePorts = Collections.unmodifiableList(Arrays.asList(secure));
insecurePorts = Collections.unmodifiableList(Arrays.asList(insecure));
}

public static int getSecurePortInUse() {
return securePorts.get(securePortIndex.get());
}

public static int getInsecurePortInUse() {
return insecurePorts.get(insecurePortIndex.get());
public static WebsocketPorts getWebsocketPorts() {
return websocketPorts;
}

/**
Expand Down

0 comments on commit 753f980

Please sign in to comment.