package envoy.client.ui.container; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.logging.Logger; import javax.naming.TimeLimitExceededException; import javax.swing.*; import javax.swing.border.EmptyBorder; import envoy.client.data.*; import envoy.client.event.HandshakeSuccessfulEvent; import envoy.client.net.Client; import envoy.client.ui.Theme; import envoy.client.ui.primary.PrimaryButton; import envoy.data.LoginCredentials; import envoy.data.Message; import envoy.data.User; import envoy.event.EventBus; import envoy.event.HandshakeRejectionEvent; import envoy.exception.EnvoyException; import envoy.util.EnvoyLog; /** * Project: envoy-client
* File: LoginDialog.java
* Created: 01.01.2020
* * @author Kai S. K. Engelbart * @author Maximilian Käfer * @since Envoy Client v0.3-alpha */ public class LoginDialog extends JDialog { private JPanel contentPanel; private JTextField textField; private JPasswordField passwordField; private JPasswordField repeatPasswordField; private JLabel lblUserName; private JLabel lblPassword; private JLabel lblRepeatPassword; private JLabel errorMessage; private GridBagConstraints gbc_lblRepeatPassword; private GridBagConstraints gbc_repeatPasswordField; private GridBagConstraints gbc_errorMessage; private JPanel buttonPane; private JTextPane registerText; private JCheckBox registerCheckBox; private PrimaryButton okButton; private PrimaryButton cancelButton; private LoginCredentials credentials; private final Client client; private final LocalDB localDB; private final Cache receivedMessageCache; private static final ClientConfig config = ClientConfig.getInstance(); private static final Logger logger = EnvoyLog.getLogger(LoginDialog.class); private static final long serialVersionUID = 0L; /** * Displays a dialog enabling the user to enter their user name and password. * * @param client the client used to perform the handshake * @param localDB the local database in which data is persisted * @param receivedMessageCache the cache that stored messages received during * the handshake * @since Envoy Client v0.3-alpha */ public LoginDialog(Client client, LocalDB localDB, Cache receivedMessageCache) { this.client = client; this.localDB = localDB; this.receivedMessageCache = receivedMessageCache; // Prepare handshake localDB.loadIDGenerator(); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { abortLogin(); } }); initUi(); okButton.addActionListener((evt) -> { try { if (registerCheckBox.isSelected()) { // Check password equality if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) { credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), true); performHandshake(); } else { JOptionPane.showMessageDialog(this, "The repeated password is not the original password!"); clearPasswordFields(); } } else { credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); performHandshake(); } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } }); // Listen to handshake rejections EventBus.getInstance() .register(HandshakeRejectionEvent.class, evt -> { clearPasswordFields(); errorMessage.setVisible(true); errorMessage.setText(evt.get()); }); // Exit the application when the dialog is cancelled cancelButton.addActionListener(evt -> abortLogin()); // Log in directly if configured if (config.hasLoginCredentials()) { credentials = config.getLoginCredentials(); performHandshake(); return; } setVisible(true); } private void performHandshake() { try { client.performHandshake(credentials, receivedMessageCache); if (client.isOnline()) { client.initReceiver(localDB, receivedMessageCache); dispose(); } } catch (IOException | InterruptedException | TimeLimitExceededException e) { logger.warning("Could not connect to server. Trying offline mode..."); e.printStackTrace(); try { // Try entering offline mode localDB.loadUsers(); User clientUser = localDB.getUsers().get(credentials.getIdentifier()); if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); client.setSender(clientUser); JOptionPane.showMessageDialog(null, "A connection to the server could not be established. Starting in offline mode.\n" + e, "Connection error", JOptionPane.WARNING_MESSAGE); dispose(); } catch (Exception e1) { JOptionPane.showMessageDialog(null, e1, "Client error", JOptionPane.ERROR_MESSAGE); System.exit(1); return; } } } private void initUi() { setSize(338, 123); setLocationRelativeTo(null); setResizable(false); getContentPane().setLayout(new BorderLayout()); contentPanel = new JPanel(); contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); getContentPane().add(contentPanel, BorderLayout.CENTER); GridBagLayout gbl_contentPanel = new GridBagLayout(); gbl_contentPanel.columnWidths = new int[] { 0, 0, 0 }; gbl_contentPanel.rowHeights = new int[] { 0, 0, 0 }; gbl_contentPanel.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE }; gbl_contentPanel.rowWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE }; contentPanel.setLayout(gbl_contentPanel); lblUserName = new JLabel("Username:"); GridBagConstraints gbc_lblUserName = new GridBagConstraints(); gbc_lblUserName.anchor = GridBagConstraints.EAST; gbc_lblUserName.insets = new Insets(0, 0, 5, 5); gbc_lblUserName.gridx = 0; gbc_lblUserName.gridy = 0; contentPanel.add(lblUserName, gbc_lblUserName); textField = new JTextField(); textField.setBorder(null); GridBagConstraints gbc_textField = new GridBagConstraints(); gbc_textField.insets = new Insets(0, 0, 5, 0); gbc_textField.fill = GridBagConstraints.HORIZONTAL; gbc_textField.gridx = 1; gbc_textField.gridy = 0; contentPanel.add(textField, gbc_textField); textField.setColumns(10); lblPassword = new JLabel("Password:"); GridBagConstraints gbc_lblPassword = new GridBagConstraints(); gbc_lblPassword.anchor = GridBagConstraints.EAST; gbc_lblPassword.insets = new Insets(0, 0, 0, 5); gbc_lblPassword.gridx = 0; gbc_lblPassword.gridy = 1; contentPanel.add(lblPassword, gbc_lblPassword); passwordField = new JPasswordField(); passwordField.setBorder(null); GridBagConstraints gbc_passwordField = new GridBagConstraints(); gbc_passwordField.fill = GridBagConstraints.HORIZONTAL; gbc_passwordField.gridx = 1; gbc_passwordField.gridy = 1; contentPanel.add(passwordField, gbc_passwordField); lblRepeatPassword = new JLabel("Repeat Password:"); gbc_lblRepeatPassword = new GridBagConstraints(); gbc_lblRepeatPassword.anchor = GridBagConstraints.EAST; gbc_lblRepeatPassword.insets = new Insets(0, 0, 0, 5); gbc_lblRepeatPassword.gridx = 0; gbc_lblRepeatPassword.gridy = 2; repeatPasswordField = new JPasswordField(); gbc_repeatPasswordField = new GridBagConstraints(); gbc_repeatPasswordField.fill = GridBagConstraints.HORIZONTAL; gbc_repeatPasswordField.gridx = 1; gbc_repeatPasswordField.gridy = 2; errorMessage = new JLabel(); gbc_errorMessage = new GridBagConstraints(); gbc_errorMessage.gridx = 1; gbc_errorMessage.gridy = 3; gbc_errorMessage.fill = GridBagConstraints.HORIZONTAL; gbc_errorMessage.insets = new Insets(5, 5, 5, 5); errorMessage.setForeground(Color.RED); errorMessage.setVisible(false); contentPanel.add(errorMessage, gbc_errorMessage); buttonPane = new JPanel(); registerText = new JTextPane(); registerText.setEditable(false); registerText.setText("Register?"); registerText.setFont(new Font("Arial", Font.BOLD, 12)); registerText.setAlignmentX(LEFT_ALIGNMENT); buttonPane.add(registerText); registerCheckBox = new JCheckBox(); registerCheckBox.setAlignmentX(LEFT_ALIGNMENT); registerCheckBox.addItemListener(e -> { switch (e.getStateChange()) { case ItemEvent.SELECTED: contentPanel.add(lblRepeatPassword, gbc_lblRepeatPassword); contentPanel.add(repeatPasswordField, gbc_repeatPasswordField); setSize(338, 173); break; case ItemEvent.DESELECTED: if (repeatPasswordField.getParent() == contentPanel) { contentPanel.remove(lblRepeatPassword); contentPanel.remove(repeatPasswordField); setSize(338, 148); } break; } contentPanel.revalidate(); contentPanel.repaint(); }); buttonPane.add(registerCheckBox); buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); getContentPane().add(buttonPane, BorderLayout.SOUTH); okButton = new PrimaryButton("OK"); okButton.setActionCommand("OK"); buttonPane.add(okButton); getRootPane().setDefaultButton(okButton); cancelButton = new PrimaryButton("Cancel"); cancelButton.setActionCommand("Cancel"); buttonPane.add(cancelButton); setTheme(); setModalityType(Dialog.DEFAULT_MODALITY_TYPE); EventBus.getInstance().register(HandshakeSuccessfulEvent.class, evt -> dispose()); } /** * Resets the text stored in the password fields. * * @since Envoy Client v0.3-alpha */ private void clearPasswordFields() { passwordField.setText(null); repeatPasswordField.setText(null); } private void setTheme() { Theme theme = Settings.getInstance().getCurrentTheme(); // Panels contentPanel.setBackground(theme.getBackgroundColor()); contentPanel.setForeground(theme.getBackgroundColor()); buttonPane.setBackground(theme.getBackgroundColor()); buttonPane.setForeground(theme.getBackgroundColor()); // Input Fields textField.setBackground(theme.getCellColor()); textField.setForeground(theme.getUserNameColor()); passwordField.setBackground(theme.getCellColor()); passwordField.setForeground(theme.getUserNameColor()); repeatPasswordField.setBackground(theme.getCellColor()); repeatPasswordField.setForeground(theme.getUserNameColor()); // JLabels lblUserName.setBackground(theme.getCellColor()); lblUserName.setForeground(theme.getUserNameColor()); lblPassword.setBackground(theme.getCellColor()); lblPassword.setForeground(theme.getUserNameColor()); lblRepeatPassword.setBackground(theme.getCellColor()); lblRepeatPassword.setForeground(theme.getUserNameColor()); // Register registerText.setBackground(theme.getCellColor()); registerText.setForeground(theme.getUserNameColor()); registerCheckBox.setBackground(theme.getCellColor()); // Buttons okButton.setBackground(theme.getInteractableBackgroundColor()); okButton.setForeground(theme.getInteractableForegroundColor()); cancelButton.setBackground(theme.getInteractableBackgroundColor()); cancelButton.setForeground(theme.getInteractableForegroundColor()); } /** * Shuts the system down properly if the login was aborted. * * @since Envoy Client v0.1-beta */ private void abortLogin() { logger.info("The login process has been cancelled. Exiting..."); System.exit(0); } }