From e4fe9e6faaa81a9900a65dd8538632ace8a8da49 Mon Sep 17 00:00:00 2001 From: Mitch Gaffigan Date: Wed, 3 Sep 2025 09:42:08 -0500 Subject: [PATCH 1/5] Extracted client command line parsing to tested class Signed-off-by: Mitch Gaffigan --- .../connect/client/ui/CommandLineOptions.java | 100 ++++++++++++++++++ .../com/mirth/connect/client/ui/Mirth.java | 57 ++-------- .../client/ui/CommandLineOptionsTest.java | 59 +++++++++++ 3 files changed, 167 insertions(+), 49 deletions(-) create mode 100644 client/src/com/mirth/connect/client/ui/CommandLineOptions.java create mode 100644 client/test/com/mirth/connect/client/ui/CommandLineOptionsTest.java diff --git a/client/src/com/mirth/connect/client/ui/CommandLineOptions.java b/client/src/com/mirth/connect/client/ui/CommandLineOptions.java new file mode 100644 index 0000000000..26aa14b9dc --- /dev/null +++ b/client/src/com/mirth/connect/client/ui/CommandLineOptions.java @@ -0,0 +1,100 @@ +package com.mirth.connect.client.ui; + +import org.apache.commons.lang3.StringUtils; + +/** + * Immutable holder for command line options used by the Mirth client. + */ +public class CommandLineOptions { + private final String server; + private final String version; + private final String username; + private final String password; + private final String protocols; + private final String cipherSuites; + + /** + * Parse command line arguments for Mirth client. + */ + public CommandLineOptions(String[] args) { + String server = "https://localhost:8443"; + String version = ""; + String username = ""; + String password = ""; + String protocols = ""; + String cipherSuites = ""; + + if (args == null) { + args = new String[0]; + } + + if (args.length > 0) { + server = args[0]; + } + if (args.length > 1) { + version = args[1]; + } + if (args.length > 2) { + if (StringUtils.equalsIgnoreCase(args[2], "-ssl")) { + // -ssl [ [ [ []]]] + if (args.length > 3) { + protocols = args[3]; + } + if (args.length > 4) { + cipherSuites = args[4]; + } + if (args.length > 5) { + username = args[5]; + } + if (args.length > 6) { + password = args[6]; + } + } else { + // [ [-ssl [ []]]] + username = args[2]; + if (args.length > 3) { + password = args[3]; + } + if (args.length > 4 && StringUtils.equalsIgnoreCase(args[4], "-ssl")) { + if (args.length > 5) { + protocols = args[5]; + } + if (args.length > 6) { + cipherSuites = args[6]; + } + } + } + } + + this.server = server; + this.version = version; + this.username = username; + this.password = password; + this.protocols = protocols; + this.cipherSuites = cipherSuites; + } + + public String getServer() { + return server; + } + + public String getVersion() { + return version; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getProtocols() { + return protocols; + } + + public String getCipherSuites() { + return cipherSuites; + } +} diff --git a/client/src/com/mirth/connect/client/ui/Mirth.java b/client/src/com/mirth/connect/client/ui/Mirth.java index 4655e72af3..9dcae43060 100644 --- a/client/src/com/mirth/connect/client/ui/Mirth.java +++ b/client/src/com/mirth/connect/client/ui/Mirth.java @@ -259,59 +259,18 @@ public static void initUIManager() { * String[] */ public static void main(String[] args) { - String server = "https://localhost:8443"; - String version = ""; - String username = ""; - String password = ""; - String protocols = ""; - String cipherSuites = ""; - - if (args.length > 0) { - server = args[0]; - } - if (args.length > 1) { - version = args[1]; - } - if (args.length > 2) { - if (StringUtils.equalsIgnoreCase(args[2], "-ssl")) { - // -ssl [ [ [ []]]] - if (args.length > 3) { - protocols = args[3]; - } - if (args.length > 4) { - cipherSuites = args[4]; - } - if (args.length > 5) { - username = args[5]; - } - if (args.length > 6) { - password = args[6]; - } - } else { - // [ [-ssl [ []]]] - username = args[2]; - if (args.length > 3) { - password = args[3]; - } - if (args.length > 4 && StringUtils.equalsIgnoreCase(args[4], "-ssl")) { - if (args.length > 5) { - protocols = args[5]; - } - if (args.length > 6) { - cipherSuites = args[6]; - } - } - } - } + CommandLineOptions opts = new CommandLineOptions(args); - if (StringUtils.isNotBlank(protocols)) { - PlatformUI.HTTPS_PROTOCOLS = StringUtils.split(protocols, ','); + if (StringUtils.isNotBlank(opts.getProtocols())) { + PlatformUI.HTTPS_PROTOCOLS = StringUtils.split(opts.getProtocols(), ','); } - if (StringUtils.isNotBlank(cipherSuites)) { - PlatformUI.HTTPS_CIPHER_SUITES = StringUtils.split(cipherSuites, ','); + if (StringUtils.isNotBlank(opts.getCipherSuites())) { + PlatformUI.HTTPS_CIPHER_SUITES = StringUtils.split(opts.getCipherSuites(), ','); } + PlatformUI.SERVER_URL = opts.getServer(); + PlatformUI.CLIENT_VERSION = opts.getVersion(); - start(server, version, username, password); + start(opts.getServer(), opts.getVersion(), opts.getUsername(), opts.getPassword()); } private static void start(final String server, final String version, final String username, final String password) { diff --git a/client/test/com/mirth/connect/client/ui/CommandLineOptionsTest.java b/client/test/com/mirth/connect/client/ui/CommandLineOptionsTest.java new file mode 100644 index 0000000000..9281fc2375 --- /dev/null +++ b/client/test/com/mirth/connect/client/ui/CommandLineOptionsTest.java @@ -0,0 +1,59 @@ +package com.mirth.connect.client.ui; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class CommandLineOptionsTest { + + @Test + public void testParseSslForm() { + String[] args = new String[] { "https://example:8443", "1.0", "-ssl", "TLSv1.2,TLSv1.3", "TLS_RSA_WITH_AES_128_GCM_SHA256", "alice", "secret" }; + CommandLineOptions opts = new CommandLineOptions(args); + + assertEquals("https://example:8443", opts.getServer()); + assertEquals("1.0", opts.getVersion()); + assertEquals("alice", opts.getUsername()); + assertEquals("secret", opts.getPassword()); + assertEquals("TLSv1.2,TLSv1.3", opts.getProtocols()); + assertEquals("TLS_RSA_WITH_AES_128_GCM_SHA256", opts.getCipherSuites()); + } + + @Test + public void testParseUsernameFormWithSsl() { + String[] args = new String[] { "https://example:8443", "1.0", "bob", "pw", "-ssl", "TLSv1.2", "CIPHER" }; + CommandLineOptions opts = new CommandLineOptions(args); + + assertEquals("https://example:8443", opts.getServer()); + assertEquals("1.0", opts.getVersion()); + assertEquals("bob", opts.getUsername()); + assertEquals("pw", opts.getPassword()); + assertEquals("TLSv1.2", opts.getProtocols()); + assertEquals("CIPHER", opts.getCipherSuites()); + } + + @Test + public void testNullArgsUsesDefaults() { + CommandLineOptions opts = new CommandLineOptions((String[]) null); + + assertEquals("https://localhost:8443", opts.getServer()); + assertEquals("", opts.getVersion()); + assertEquals("", opts.getUsername()); + assertEquals("", opts.getPassword()); + assertEquals("", opts.getProtocols()); + assertEquals("", opts.getCipherSuites()); + } + + @Test + public void testNormal() { + String[] args = new String[] { "https://example:8443", "1.0" }; + CommandLineOptions opts = new CommandLineOptions(args); + + assertEquals("https://example:8443", opts.getServer()); + assertEquals("1.0", opts.getVersion()); + assertEquals("", opts.getUsername()); + assertEquals("", opts.getPassword()); + assertEquals("", opts.getProtocols()); + assertEquals("", opts.getCipherSuites()); + } +} From b5c3de30c441317aeaf525b6420bb74184191c4e Mon Sep 17 00:00:00 2001 From: Mitch Gaffigan Date: Wed, 3 Sep 2025 09:43:36 -0500 Subject: [PATCH 2/5] Simplified checks for login status isSuccess Signed-off-by: Mitch Gaffigan --- client/src/com/mirth/connect/client/ui/LoginPanel.java | 4 ++-- server/src/com/mirth/connect/model/LoginStatus.java | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/client/src/com/mirth/connect/client/ui/LoginPanel.java b/client/src/com/mirth/connect/client/ui/LoginPanel.java index 5a78f8614a..7a32fb6506 100644 --- a/client/src/com/mirth/connect/client/ui/LoginPanel.java +++ b/client/src/com/mirth/connect/client/ui/LoginPanel.java @@ -451,7 +451,7 @@ public Void doInBackground() { } // If SUCCESS or SUCCESS_GRACE_PERIOD - if ((loginStatus != null) && ((loginStatus.getStatus() == LoginStatus.Status.SUCCESS) || (loginStatus.getStatus() == LoginStatus.Status.SUCCESS_GRACE_PERIOD))) { + if (loginStatus != null && loginStatus.isSuccess()) { if (!handleSuccess(loginStatus)) { LoginPanel.getInstance().setVisible(false); LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); @@ -469,7 +469,7 @@ public Void doInBackground() { loginStatus = plugin.authenticate(LoginPanel.this, client, updatedUsername, loginStatus); - if ((loginStatus != null) && ((loginStatus.getStatus() == LoginStatus.Status.SUCCESS) || (loginStatus.getStatus() == LoginStatus.Status.SUCCESS_GRACE_PERIOD))) { + if (loginStatus != null && loginStatus.isSuccess()) { errorOccurred = false; if (!handleSuccess(loginStatus)) { LoginPanel.getInstance().setVisible(false); diff --git a/server/src/com/mirth/connect/model/LoginStatus.java b/server/src/com/mirth/connect/model/LoginStatus.java index 5af8333a4f..b864dcb583 100644 --- a/server/src/com/mirth/connect/model/LoginStatus.java +++ b/server/src/com/mirth/connect/model/LoginStatus.java @@ -43,4 +43,8 @@ public String getMessage() { public String getUpdatedUsername() { return updatedUsername; } + + public boolean isSuccess() { + return status == Status.SUCCESS || status == Status.SUCCESS_GRACE_PERIOD; + } } From 993b6151907764917b89ec9fdd80bebf446456ba Mon Sep 17 00:00:00 2001 From: Mitch Gaffigan Date: Wed, 3 Sep 2025 09:50:26 -0500 Subject: [PATCH 3/5] Moved handleSuccess to Mirth.java - boots app, not related to panel Signed-off-by: Mitch Gaffigan --- .../mirth/connect/client/ui/LoginPanel.java | 152 +----------------- .../com/mirth/connect/client/ui/Mirth.java | 149 +++++++++++++++++ 2 files changed, 151 insertions(+), 150 deletions(-) diff --git a/client/src/com/mirth/connect/client/ui/LoginPanel.java b/client/src/com/mirth/connect/client/ui/LoginPanel.java index 7a32fb6506..532f2a1259 100644 --- a/client/src/com/mirth/connect/client/ui/LoginPanel.java +++ b/client/src/com/mirth/connect/client/ui/LoginPanel.java @@ -9,38 +9,27 @@ package com.mirth.connect.client.ui; -import static com.mirth.connect.client.core.BrandingConstants.CHECK_FOR_NOTIFICATIONS; - import java.awt.Color; import java.awt.Cursor; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Properties; import java.util.Set; -import java.util.prefs.Preferences; import javax.swing.ImageIcon; import javax.swing.SwingWorker; -import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import com.mirth.connect.client.core.Client; import com.mirth.connect.client.core.ClientException; -import com.mirth.connect.client.core.ConnectServiceUtil; import com.mirth.connect.client.core.UnauthorizedException; import com.mirth.connect.client.core.api.servlets.UserServletInterface; import com.mirth.connect.client.ui.util.DisplayUtil; import com.mirth.connect.model.ExtendedLoginStatus; import com.mirth.connect.model.LoginStatus; -import com.mirth.connect.model.PublicServerSettings; -import com.mirth.connect.model.User; -import com.mirth.connect.model.converters.ObjectXMLSerializer; import com.mirth.connect.plugins.MultiFactorAuthenticationClientPlugin; -import com.mirth.connect.util.MirthSSLUtil; public class LoginPanel extends javax.swing.JFrame { @@ -102,8 +91,6 @@ public void initialize(String mirthServer, String version, String user, String p return; } - PlatformUI.CLIENT_VERSION = version; - setTitle(String.format("%s %s - Login", BrandingConstants.PRODUCT_NAME, version)); setIconImage(BrandingConstants.FAVICON.getImage()); @@ -452,7 +439,7 @@ public Void doInBackground() { // If SUCCESS or SUCCESS_GRACE_PERIOD if (loginStatus != null && loginStatus.isSuccess()) { - if (!handleSuccess(loginStatus)) { + if (!Mirth.handleLoginSuccess(client, loginStatus, username.getText())) { LoginPanel.getInstance().setVisible(false); LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); } @@ -471,7 +458,7 @@ public Void doInBackground() { if (loginStatus != null && loginStatus.isSuccess()) { errorOccurred = false; - if (!handleSuccess(loginStatus)) { + if (!Mirth.handleLoginSuccess(client, loginStatus, username.getText())) { LoginPanel.getInstance().setVisible(false); LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); } @@ -504,141 +491,6 @@ public Void doInBackground() { return null; } - private boolean handleSuccess(LoginStatus loginStatus) throws ClientException { - try { - PublicServerSettings publicServerSettings = client.getPublicServerSettings(); - - if (publicServerSettings.getLoginNotificationEnabled() == true) { - CustomBannerPanelDialog customBannerPanelDialog = new CustomBannerPanelDialog(LoginPanel.getInstance(), "Login Notification", publicServerSettings.getLoginNotificationMessage()); - boolean isAccepted = customBannerPanelDialog.isAccepted(); - - if (isAccepted == true) { - client.setUserNotificationAcknowledged(client.getCurrentUser().getId()); - } - else { - return false; - } - } - - String environmentName = publicServerSettings.getEnvironmentName(); - if (!StringUtils.isBlank(environmentName)) { - PlatformUI.ENVIRONMENT_NAME = environmentName; - } - - String serverName = publicServerSettings.getServerName(); - if (!StringUtils.isBlank(serverName)) { - PlatformUI.SERVER_NAME = serverName; - } else { - PlatformUI.SERVER_NAME = null; - } - - Color defaultBackgroundColor = publicServerSettings.getDefaultAdministratorBackgroundColor(); - if (defaultBackgroundColor != null) { - PlatformUI.DEFAULT_BACKGROUND_COLOR = defaultBackgroundColor; - } - } catch (ClientException e) { - PlatformUI.SERVER_NAME = null; - } - - try { - String database = (String) client.getAbout().get("database"); - if (!StringUtils.isBlank(database)) { - PlatformUI.SERVER_DATABASE = database; - } else { - PlatformUI.SERVER_DATABASE = null; - } - } catch (ClientException e) { - PlatformUI.SERVER_DATABASE = null; - } - - try { - Map map = client.getProtocolsAndCipherSuites(); - PlatformUI.SERVER_HTTPS_SUPPORTED_PROTOCOLS = map.get(MirthSSLUtil.KEY_SUPPORTED_PROTOCOLS); - PlatformUI.SERVER_HTTPS_ENABLED_CLIENT_PROTOCOLS = map.get(MirthSSLUtil.KEY_ENABLED_CLIENT_PROTOCOLS); - PlatformUI.SERVER_HTTPS_ENABLED_SERVER_PROTOCOLS = map.get(MirthSSLUtil.KEY_ENABLED_SERVER_PROTOCOLS); - PlatformUI.SERVER_HTTPS_SUPPORTED_CIPHER_SUITES = map.get(MirthSSLUtil.KEY_SUPPORTED_CIPHER_SUITES); - PlatformUI.SERVER_HTTPS_ENABLED_CIPHER_SUITES = map.get(MirthSSLUtil.KEY_ENABLED_CIPHER_SUITES); - } catch (ClientException e) { - } - - PlatformUI.USER_NAME = StringUtils.defaultString(loginStatus.getUpdatedUsername(), username.getText()); - setStatus("Authenticated..."); - new Mirth(client); - LoginPanel.getInstance().setVisible(false); - - User currentUser = PlatformUI.MIRTH_FRAME.getCurrentUser(PlatformUI.MIRTH_FRAME); - Properties userPreferences = new Properties(); - Set preferenceNames = new HashSet(); - preferenceNames.add("firstlogin"); - preferenceNames.add("checkForNotifications"); - preferenceNames.add("showNotificationPopup"); - preferenceNames.add("archivedNotifications"); - try { - userPreferences = client.getUserPreferences(currentUser.getId(), preferenceNames); - - // Display registration dialog if it's the user's first time logging in - String firstlogin = userPreferences.getProperty("firstlogin"); - if (firstlogin == null || BooleanUtils.toBoolean(firstlogin)) { - if (Integer.valueOf(currentUser.getId()) == 1) { - // if current user is user 1: - // 1. check system preferences for user information - // 2. if system preferences exist, populate screen using currentUser - Preferences preferences = Preferences.userNodeForPackage(Mirth.class); - String systemUserInfo = preferences.get("userLoginInfo", null); - if (systemUserInfo != null) { - String info[] = systemUserInfo.split(",", 0); - currentUser.setUsername(info[0]); - currentUser.setFirstName(info[1]); - currentUser.setLastName(info[2]); - currentUser.setEmail(info[3]); - currentUser.setCountry(info[4]); - currentUser.setStateTerritory(info[5]); - currentUser.setPhoneNumber(info[6]); - currentUser.setOrganization(info[7]); - currentUser.setRole(info[8]); - currentUser.setIndustry(info[9]); - currentUser.setDescription(info[10]); - } - } - FirstLoginDialog firstLoginDialog = new FirstLoginDialog(currentUser); - // if leaving the first login dialog without saving - if (!firstLoginDialog.getResult()) { - return false; - } - } else if (loginStatus.getStatus() == LoginStatus.Status.SUCCESS_GRACE_PERIOD) { - new ChangePasswordDialog(currentUser, loginStatus.getMessage()); - } - - // Check for new notifications from update server if enabled - String checkForNotifications = userPreferences.getProperty("checkForNotifications"); - if (CHECK_FOR_NOTIFICATIONS - && (checkForNotifications == null || BooleanUtils.toBoolean(checkForNotifications))) { - Set archivedNotifications = new HashSet(); - String archivedNotificationString = userPreferences.getProperty("archivedNotifications"); - if (archivedNotificationString != null) { - archivedNotifications = ObjectXMLSerializer.getInstance().deserialize(archivedNotificationString, Set.class); - } - // Update the Other Tasks pane with the unarchived notification count - int unarchivedNotifications = ConnectServiceUtil.getNotificationCount(PlatformUI.SERVER_ID, PlatformUI.SERVER_VERSION, LoadedExtensions.getInstance().getExtensionVersions(), archivedNotifications, PlatformUI.HTTPS_PROTOCOLS, PlatformUI.HTTPS_CIPHER_SUITES); - PlatformUI.MIRTH_FRAME.updateNotificationTaskName(unarchivedNotifications); - - // Display notification dialog if enabled and if there are new notifications - String showNotificationPopup = userPreferences.getProperty("showNotificationPopup"); - if (showNotificationPopup == null || BooleanUtils.toBoolean(showNotificationPopup)) { - if (unarchivedNotifications > 0) { - new NotificationDialog(); - } - } - } - } catch (ClientException e) { - PlatformUI.MIRTH_FRAME.alertThrowable(PlatformUI.MIRTH_FRAME, e); - } - - PlatformUI.MIRTH_FRAME.sendUsageStatistics(); - - return true; - } - public void done() {} }; worker.execute(); diff --git a/client/src/com/mirth/connect/client/ui/Mirth.java b/client/src/com/mirth/connect/client/ui/Mirth.java index 9dcae43060..2b96b14ec8 100644 --- a/client/src/com/mirth/connect/client/ui/Mirth.java +++ b/client/src/com/mirth/connect/client/ui/Mirth.java @@ -9,12 +9,18 @@ package com.mirth.connect.client.ui; +import static com.mirth.connect.client.core.BrandingConstants.CHECK_FOR_NOTIFICATIONS; + import java.awt.Color; import java.awt.Toolkit; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.io.IOException; import java.util.prefs.Preferences; +import java.util.Map; +import java.util.Set; +import java.util.Properties; +import java.util.HashSet; import javax.imageio.ImageIO; import javax.swing.ImageIcon; @@ -28,6 +34,7 @@ import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent.KeyBinding; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; import org.apache.logging.log4j.Level; @@ -42,6 +49,12 @@ import com.jgoodies.looks.plastic.PlasticXPLookAndFeel; import com.mirth.connect.client.core.Client; import com.mirth.connect.client.core.ClientException; +import com.mirth.connect.client.core.ConnectServiceUtil; +import com.mirth.connect.model.LoginStatus; +import com.mirth.connect.model.PublicServerSettings; +import com.mirth.connect.model.User; +import com.mirth.connect.model.converters.ObjectXMLSerializer; +import com.mirth.connect.util.MirthSSLUtil; /** * The main mirth class. Sets up the login and then authenticates the login information and sets up @@ -288,4 +301,140 @@ public void run() { } }); } + + public static boolean handleLoginSuccess(Client client, LoginStatus loginStatus, String userName) throws ClientException { + AbstractLoginPanel loginPanel = LoginPanelFactory.getInstance(); + try { + PublicServerSettings publicServerSettings = client.getPublicServerSettings(); + + if (publicServerSettings.getLoginNotificationEnabled() == true) { + CustomBannerPanelDialog customBannerPanelDialog = new CustomBannerPanelDialog(loginPanel, "Login Notification", publicServerSettings.getLoginNotificationMessage()); + boolean isAccepted = customBannerPanelDialog.isAccepted(); + + if (isAccepted == true) { + client.setUserNotificationAcknowledged(client.getCurrentUser().getId()); + } + else { + return false; + } + } + + String environmentName = publicServerSettings.getEnvironmentName(); + if (!StringUtils.isBlank(environmentName)) { + PlatformUI.ENVIRONMENT_NAME = environmentName; + } + + String serverName = publicServerSettings.getServerName(); + if (!StringUtils.isBlank(serverName)) { + PlatformUI.SERVER_NAME = serverName; + } else { + PlatformUI.SERVER_NAME = null; + } + + Color defaultBackgroundColor = publicServerSettings.getDefaultAdministratorBackgroundColor(); + if (defaultBackgroundColor != null) { + PlatformUI.DEFAULT_BACKGROUND_COLOR = defaultBackgroundColor; + } + } catch (ClientException e) { + PlatformUI.SERVER_NAME = null; + } + + try { + String database = (String) client.getAbout().get("database"); + if (!StringUtils.isBlank(database)) { + PlatformUI.SERVER_DATABASE = database; + } else { + PlatformUI.SERVER_DATABASE = null; + } + } catch (ClientException e) { + PlatformUI.SERVER_DATABASE = null; + } + + try { + Map map = client.getProtocolsAndCipherSuites(); + PlatformUI.SERVER_HTTPS_SUPPORTED_PROTOCOLS = map.get(MirthSSLUtil.KEY_SUPPORTED_PROTOCOLS); + PlatformUI.SERVER_HTTPS_ENABLED_CLIENT_PROTOCOLS = map.get(MirthSSLUtil.KEY_ENABLED_CLIENT_PROTOCOLS); + PlatformUI.SERVER_HTTPS_ENABLED_SERVER_PROTOCOLS = map.get(MirthSSLUtil.KEY_ENABLED_SERVER_PROTOCOLS); + PlatformUI.SERVER_HTTPS_SUPPORTED_CIPHER_SUITES = map.get(MirthSSLUtil.KEY_SUPPORTED_CIPHER_SUITES); + PlatformUI.SERVER_HTTPS_ENABLED_CIPHER_SUITES = map.get(MirthSSLUtil.KEY_ENABLED_CIPHER_SUITES); + } catch (ClientException e) { + } + + PlatformUI.USER_NAME = StringUtils.defaultString(loginStatus.getUpdatedUsername(), userName); + loginPanel.setStatus("Authenticated..."); + new Mirth(client); + loginPanel.setVisible(false); + + User currentUser = PlatformUI.MIRTH_FRAME.getCurrentUser(PlatformUI.MIRTH_FRAME); + Properties userPreferences = new Properties(); + Set preferenceNames = new HashSet(); + preferenceNames.add("firstlogin"); + preferenceNames.add("checkForNotifications"); + preferenceNames.add("showNotificationPopup"); + preferenceNames.add("archivedNotifications"); + try { + userPreferences = client.getUserPreferences(currentUser.getId(), preferenceNames); + + // Display registration dialog if it's the user's first time logging in + String firstlogin = userPreferences.getProperty("firstlogin"); + if (firstlogin == null || BooleanUtils.toBoolean(firstlogin)) { + if (Integer.valueOf(currentUser.getId()) == 1) { + // if current user is user 1: + // 1. check system preferences for user information + // 2. if system preferences exist, populate screen using currentUser + Preferences preferences = Preferences.userNodeForPackage(Mirth.class); + String systemUserInfo = preferences.get("userLoginInfo", null); + if (systemUserInfo != null) { + String info[] = systemUserInfo.split(",", 0); + currentUser.setUsername(info[0]); + currentUser.setFirstName(info[1]); + currentUser.setLastName(info[2]); + currentUser.setEmail(info[3]); + currentUser.setCountry(info[4]); + currentUser.setStateTerritory(info[5]); + currentUser.setPhoneNumber(info[6]); + currentUser.setOrganization(info[7]); + currentUser.setRole(info[8]); + currentUser.setIndustry(info[9]); + currentUser.setDescription(info[10]); + } + } + FirstLoginDialog firstLoginDialog = new FirstLoginDialog(currentUser); + // if leaving the first login dialog without saving + if (!firstLoginDialog.getResult()) { + return false; + } + } else if (loginStatus.getStatus() == LoginStatus.Status.SUCCESS_GRACE_PERIOD) { + new ChangePasswordDialog(currentUser, loginStatus.getMessage()); + } + + // Check for new notifications from update server if enabled + String checkForNotifications = userPreferences.getProperty("checkForNotifications"); + if (CHECK_FOR_NOTIFICATIONS + && (checkForNotifications == null || BooleanUtils.toBoolean(checkForNotifications))) { + Set archivedNotifications = new HashSet(); + String archivedNotificationString = userPreferences.getProperty("archivedNotifications"); + if (archivedNotificationString != null) { + archivedNotifications = ObjectXMLSerializer.getInstance().deserialize(archivedNotificationString, Set.class); + } + // Update the Other Tasks pane with the unarchived notification count + int unarchivedNotifications = ConnectServiceUtil.getNotificationCount(PlatformUI.SERVER_ID, PlatformUI.SERVER_VERSION, LoadedExtensions.getInstance().getExtensionVersions(), archivedNotifications, PlatformUI.HTTPS_PROTOCOLS, PlatformUI.HTTPS_CIPHER_SUITES); + PlatformUI.MIRTH_FRAME.updateNotificationTaskName(unarchivedNotifications); + + // Display notification dialog if enabled and if there are new notifications + String showNotificationPopup = userPreferences.getProperty("showNotificationPopup"); + if (showNotificationPopup == null || BooleanUtils.toBoolean(showNotificationPopup)) { + if (unarchivedNotifications > 0) { + new NotificationDialog(); + } + } + } + } catch (ClientException e) { + PlatformUI.MIRTH_FRAME.alertThrowable(PlatformUI.MIRTH_FRAME, e); + } + + PlatformUI.MIRTH_FRAME.sendUsageStatistics(); + + return true; + } } From 7be7ed788c824454638a22ba0e8c4b3050bb67bf Mon Sep 17 00:00:00 2001 From: Mitch Gaffigan Date: Wed, 3 Sep 2025 09:53:28 -0500 Subject: [PATCH 4/5] Removed duplicated error handling logic to separate method, avoid relying on global state Signed-off-by: Mitch Gaffigan --- .../mirth/connect/client/ui/LoginPanel.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/client/src/com/mirth/connect/client/ui/LoginPanel.java b/client/src/com/mirth/connect/client/ui/LoginPanel.java index 532f2a1259..735279b916 100644 --- a/client/src/com/mirth/connect/client/ui/LoginPanel.java +++ b/client/src/com/mirth/connect/client/ui/LoginPanel.java @@ -33,7 +33,6 @@ public class LoginPanel extends javax.swing.JFrame { - private Client client; private static final String ERROR_MESSAGE = "There was an error connecting to the server at the specified address. Please verify that the server is up and running."; private static LoginPanel instance = null; @@ -407,6 +406,7 @@ private void passwordActionPerformed(java.awt.event.ActionEvent evt)// GEN-FIRST private void loginButtonActionPerformed(java.awt.event.ActionEvent evt)// GEN-FIRST:event_loginButtonActionPerformed {// GEN-HEADEREND:event_loginButtonActionPerformed errorPane.setVisible(false); + LoginPanel loginPanel = this; SwingWorker worker = new SwingWorker() { @@ -415,7 +415,7 @@ public Void doInBackground() { try { String server = serverName.getText(); - client = new Client(server, PlatformUI.HTTPS_PROTOCOLS, PlatformUI.HTTPS_CIPHER_SUITES); + Client client = new Client(server, PlatformUI.HTTPS_PROTOCOLS, PlatformUI.HTTPS_CIPHER_SUITES); PlatformUI.SERVER_URL = server; // Attempt to login @@ -440,8 +440,8 @@ public Void doInBackground() { // If SUCCESS or SUCCESS_GRACE_PERIOD if (loginStatus != null && loginStatus.isSuccess()) { if (!Mirth.handleLoginSuccess(client, loginStatus, username.getText())) { - LoginPanel.getInstance().setVisible(false); - LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); + loginPanel.setVisible(false); + loginPanel.initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); } } else { // Assume failure unless overridden by a plugin @@ -459,8 +459,8 @@ public Void doInBackground() { if (loginStatus != null && loginStatus.isSuccess()) { errorOccurred = false; if (!Mirth.handleLoginSuccess(client, loginStatus, username.getText())) { - LoginPanel.getInstance().setVisible(false); - LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); + loginPanel.setVisible(false); + loginPanel.initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); } } } @@ -469,25 +469,16 @@ public Void doInBackground() { if (errorOccurred) { if (loginStatus != null) { - errorTextArea.setText(loginStatus.getMessage()); + setError(loginStatus.getMessage()); } else { - errorTextArea.setText(ERROR_MESSAGE); + setError(ERROR_MESSAGE); } } } catch (Throwable t) { - errorOccurred = true; - errorTextArea.setText(ERROR_MESSAGE); + setError(ERROR_MESSAGE); t.printStackTrace(); } - if (errorOccurred) { - errorPane.setVisible(true); - loggingIn.setVisible(false); - loginMain.setVisible(true); - loginProgress.setIndeterminate(false); - password.grabFocus(); - } - return null; } @@ -514,6 +505,15 @@ public void setStatus(String status) { this.status.setText("Please wait: " + status); } + public void setError(String status) { + errorTextArea.setText(status); + errorPane.setVisible(true); + loggingIn.setVisible(false); + loginMain.setVisible(true); + loginProgress.setIndeterminate(false); + password.grabFocus(); + } + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton closeButton; private javax.swing.JScrollPane errorPane; From 37fe8749ac75c47a6cb1e72a48072bdafde08184 Mon Sep 17 00:00:00 2001 From: Mitch Gaffigan Date: Wed, 3 Sep 2025 09:55:00 -0500 Subject: [PATCH 5/5] Remove LoginPanel singleton to separate class to allow other implementations Signed-off-by: Mitch Gaffigan --- .../connect/client/ui/AbstractLoginPanel.java | 17 ++++++++++++++ .../com/mirth/connect/client/ui/Frame.java | 8 +++---- .../mirth/connect/client/ui/LoginPanel.java | 16 ++++--------- .../connect/client/ui/LoginPanelFactory.java | 23 +++++++++++++++++++ .../com/mirth/connect/client/ui/Mirth.java | 6 ++--- 5 files changed, 51 insertions(+), 19 deletions(-) create mode 100644 client/src/com/mirth/connect/client/ui/AbstractLoginPanel.java create mode 100644 client/src/com/mirth/connect/client/ui/LoginPanelFactory.java diff --git a/client/src/com/mirth/connect/client/ui/AbstractLoginPanel.java b/client/src/com/mirth/connect/client/ui/AbstractLoginPanel.java new file mode 100644 index 0000000000..0670d81ec1 --- /dev/null +++ b/client/src/com/mirth/connect/client/ui/AbstractLoginPanel.java @@ -0,0 +1,17 @@ +package com.mirth.connect.client.ui; + +/** + * Public interface for the login panel so alternative implementations can be provided. + */ +public abstract class AbstractLoginPanel extends javax.swing.JFrame { + + /** + * Initialize and show the login UI. + */ + public abstract void initialize(String mirthServer, String version, String user, String pass); + + /** + * Update the status text shown on the login UI. + */ + public abstract void setStatus(String status); +} diff --git a/client/src/com/mirth/connect/client/ui/Frame.java b/client/src/com/mirth/connect/client/ui/Frame.java index 633a2791aa..8a366eac0d 100644 --- a/client/src/com/mirth/connect/client/ui/Frame.java +++ b/client/src/com/mirth/connect/client/ui/Frame.java @@ -543,7 +543,7 @@ public void eventDispatched(AWTEvent e) */ public void setupFrame(Client mirthClient) throws ClientException { - LoginPanel login = LoginPanel.getInstance(); + AbstractLoginPanel login = LoginPanelFactory.getInstance(); // Initialize the send message dialog editMessageDialog = new EditMessageDialog(); @@ -1524,7 +1524,7 @@ public void alertThrowable(Component parentComponent, Throwable t, String custom } mirthClient.close(); this.dispose(); - LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); + LoginPanelFactory.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); return; } else if (t.getCause() != null && t.getCause() instanceof HttpHostConnectException && (StringUtils.contains(t.getCause().getMessage(), "Connection refused") || StringUtils.contains(t.getCause().getMessage(), "Host is down"))) { connectionError = true; @@ -1542,7 +1542,7 @@ public void alertThrowable(Component parentComponent, Throwable t, String custom } mirthClient.close(); this.dispose(); - LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); + LoginPanelFactory.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); return; } } @@ -2292,7 +2292,7 @@ public boolean logout(boolean quit, boolean confirmFirst) { this.dispose(); if (!quit) { - LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); + LoginPanelFactory.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", ""); } return true; diff --git a/client/src/com/mirth/connect/client/ui/LoginPanel.java b/client/src/com/mirth/connect/client/ui/LoginPanel.java index 735279b916..dbf0fe9dca 100644 --- a/client/src/com/mirth/connect/client/ui/LoginPanel.java +++ b/client/src/com/mirth/connect/client/ui/LoginPanel.java @@ -31,12 +31,11 @@ import com.mirth.connect.model.LoginStatus; import com.mirth.connect.plugins.MultiFactorAuthenticationClientPlugin; -public class LoginPanel extends javax.swing.JFrame { +public class LoginPanel extends AbstractLoginPanel { private static final String ERROR_MESSAGE = "There was an error connecting to the server at the specified address. Please verify that the server is up and running."; - private static LoginPanel instance = null; - private LoginPanel() { + public LoginPanel() { initComponents(); DisplayUtil.setResizable(this, false); jLabel2.setForeground(UIConstants.HEADER_TITLE_TEXT_COLOR); @@ -74,15 +73,7 @@ public void mouseClicked(java.awt.event.MouseEvent evt) { errorTextArea.setDisabledTextColor(Color.RED); } - public static LoginPanel getInstance() { - synchronized (LoginPanel.class) { - if (instance == null) { - instance = new LoginPanel(); - } - return instance; - } - } - + @Override public void initialize(String mirthServer, String version, String user, String pass) { synchronized (this) { // Do not initialize another login window if one is already visible @@ -501,6 +492,7 @@ private void closeButtonActionPerformed(java.awt.event.ActionEvent evt)// GEN-FI System.exit(0); }// GEN-LAST:event_closeButtonActionPerformed + @Override public void setStatus(String status) { this.status.setText("Please wait: " + status); } diff --git a/client/src/com/mirth/connect/client/ui/LoginPanelFactory.java b/client/src/com/mirth/connect/client/ui/LoginPanelFactory.java new file mode 100644 index 0000000000..a8fd67de2b --- /dev/null +++ b/client/src/com/mirth/connect/client/ui/LoginPanelFactory.java @@ -0,0 +1,23 @@ +package com.mirth.connect.client.ui; + +/** + * Factory for obtaining the application's LoginPanel implementation. + */ +public class LoginPanelFactory { + + private static AbstractLoginPanel provider = null; + + public static synchronized AbstractLoginPanel getInstance() { + if (provider == null) { + provider = new LoginPanel(); + } + return provider; + } + + /** + * Replace the current provider. This is used to switch between login implementations at runtime. + */ + public static synchronized void setProvider(AbstractLoginPanel newProvider) { + provider = newProvider; + } +} diff --git a/client/src/com/mirth/connect/client/ui/Mirth.java b/client/src/com/mirth/connect/client/ui/Mirth.java index 2b96b14ec8..dc6cb709e9 100644 --- a/client/src/com/mirth/connect/client/ui/Mirth.java +++ b/client/src/com/mirth/connect/client/ui/Mirth.java @@ -75,7 +75,7 @@ public Mirth(Client mirthClient) throws ClientException { UIManager.put("Tree.closedIcon", UIConstants.CLOSED_ICON); userPreferences = Preferences.userNodeForPackage(Mirth.class); - LoginPanel.getInstance().setStatus("Loading components..."); + LoginPanelFactory.getInstance().setStatus("Loading components..."); PlatformUI.MIRTH_FRAME.setupFrame(mirthClient); boolean maximized; @@ -135,7 +135,7 @@ public static void aboutMac() { * @return quit */ public static boolean quitMac() { - return (LoginPanel.getInstance().isVisible() || (PlatformUI.MIRTH_FRAME != null && PlatformUI.MIRTH_FRAME.logout(true))); + return PlatformUI.MIRTH_FRAME == null || PlatformUI.MIRTH_FRAME.logout(true); } /** @@ -297,7 +297,7 @@ private static void start(final String server, final String version, final Strin public void run() { initUIManager(); PlatformUI.BACKGROUND_IMAGE = new ImageIcon(com.mirth.connect.client.ui.Frame.class.getResource("images/header_nologo.png")); - LoginPanel.getInstance().initialize(server, version, username, password); + LoginPanelFactory.getInstance().initialize(server, version, username, password); } }); }